diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 3d36f20..0000000 --- a/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.rs] -indent_size = 4 diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml new file mode 100644 index 0000000..4de0076 --- /dev/null +++ b/.github/workflows/artifacts.yml @@ -0,0 +1,35 @@ +name: Artifacts + +on: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + workflow_dispatch: + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + +jobs: + artifacts: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Install cargo make + uses: davidB/rust-cargo-make@v1 + + - name: Compile contracts to wasm + run: cargo make rust-optimizer + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: artifacts + path: artifacts/ diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 512d0a4..0f34ef9 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -14,8 +14,11 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Run cargo check - uses: actions-rs/cargo@v1 - with: - command: check - args: --all-features + - name: Install cargo make + uses: davidB/rust-cargo-make@v1 + + - name: Install stable Rust + run: cargo make install-stable + + - name: Check + run: cargo make check diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..5465d0b --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,33 @@ +name: Coverage + +on: + push: + branches: + - master + pull_request: + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Install cargo make + uses: davidB/rust-cargo-make@v1 + + - name: Install stable Rust + run: cargo make install-stable + + - name: Run test coverage + run: cargo make coverage-lcov + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: target/coverage/lcov.info diff --git a/.github/workflows/licenses.yml b/.github/workflows/licenses.yml index eeac019..6f598bd 100644 --- a/.github/workflows/licenses.yml +++ b/.github/workflows/licenses.yml @@ -22,13 +22,11 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 + - name: Install cargo make + uses: davidB/rust-cargo-make@v1 + - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.59.0 - target: wasm32-unknown-unknown - override: true + run: cargo make install-stable - name: run cargo deny uses: EmbarkStudios/cargo-deny-action@v1 diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index 4d1e9b3..9bcf1ab 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -14,37 +14,20 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 + - name: Install cargo make + uses: davidB/rust-cargo-make@v1 + - name: Install nightly toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - components: rustfmt, clippy - - - name: Install cargo-machete - uses: actions-rs/cargo@v1 - with: - command: install - args: cargo-machete + run: cargo make install-nightly - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - toolchain: nightly - command: clippy - args: --all-features -- -D warnings + run: cargo make clippy-check - name: Run cargo fmt - uses: actions-rs/cargo@v1 - with: - toolchain: nightly - command: fmt - args: --all -- --check --verbose + run: cargo make format-check - name: Run cargo machete - uses: actions-rs/cargo@v1 - with: - command: machete + run: cargo make machete-check - name: Lint todo comments - run: ./scripts/todo-lint.sh + run: cargo make todo-check diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f0b8dd5..ca8cef1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,18 +14,18 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 + - name: Install cargo make + uses: davidB/rust-cargo-make@v1 + - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.65.0 - target: wasm32-unknown-unknown - override: true + run: cargo make install-stable + + - name: Run unit tests + run: cargo make unit-test + env: + RUST_BACKTRACE: 1 - - name: Run tests - uses: actions-rs/cargo@v1 - with: - command: test - args: --locked --lib + - name: Run integration tests + run: cargo make integration-test env: RUST_BACKTRACE: 1 diff --git a/Cargo.lock b/Cargo.lock index ab6ed40..b079c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.69" @@ -33,6 +42,27 @@ dependencies = [ "serde", ] +[[package]] +name = "apollo-cw-multi-test" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1c7e04dcaeab52c3390867822b3019f81e239b8bbd3146fb91a83b10fb1f27b" +dependencies = [ + "anyhow", + "cosmwasm-std", + "cw-storage-plus 1.1.0", + "cw-utils 1.0.1", + "derivative", + "itertools", + "k256 0.11.6", + "osmosis-std 0.16.2", + "prost 0.9.0", + "regex", + "schemars", + "serde", + "thiserror", +] + [[package]] name = "apollo-utils" version = "0.1.1" @@ -45,6 +75,17 @@ dependencies = [ "cw20 1.1.0", ] +[[package]] +name = "astro-satellite-package" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf737cf762c341a9575ee8fc6da47cc0c4ec11725c9fd0fc5fbb2c31ce0d61a" +dependencies = [ + "astroport-governance", + "cosmwasm-schema", + "cosmwasm-std", +] + [[package]] name = "astroport" version = "2.8.0" @@ -61,1007 +102,3571 @@ dependencies = [ ] [[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.21.3" +name = "astroport-factory" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +checksum = "4ecf768e2d3153bebfbe0c502ffa4199a52598e9b6e89fca54339615b2de77eb" +dependencies = [ + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw2 0.15.1", + "itertools", + "protobuf", + "thiserror", +] [[package]] -name = "base64ct" -version = "1.5.3" +name = "astroport-generator" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "6144780ac014665b07616de0cfb35ca6a9411ed821e20c21e02f4f428c8ed51f" +dependencies = [ + "astroport", + "astroport-governance", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw1-whitelist", + "cw2 0.15.1", + "cw20 0.15.1", + "protobuf", + "thiserror", +] [[package]] -name = "block-buffer" -version = "0.9.0" +name = "astroport-governance" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "72806ace350e81c4e1cab7e275ef91f05bad830275d697d67ad1bd4acc6f016d" dependencies = [ - "generic-array", + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw20 0.15.1", ] [[package]] -name = "block-buffer" -version = "0.10.3" +name = "astroport-liquidity-helper" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3217f55114759b6569fd724dca8f3c5b90286059003a3b5377373256e2c03973" dependencies = [ - "generic-array", + "apollo-cw-asset", + "apollo-utils", + "cosmwasm-schema", + "cosmwasm-std", + "cw-bigint", + "cw-dex 0.4.0-rc.2", + "cw-storage-plus 1.1.0", + "cw2 1.1.0", + "cw20 1.1.0", + "liquidity-helper 0.2.0", + "thiserror", ] [[package]] -name = "bnum" -version = "0.8.0" +name = "astroport-maker" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128a44527fc0d6abf05f9eda748b9027536e12dff93f5acc8449f51583309350" +checksum = "92403e5d00e3c77d13d9616661ea9d9308d493fff6bec5e6e5e7bd7b7e0ff6af" +dependencies = [ + "astro-satellite-package", + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw2 0.15.1", + "cw20 0.15.1", + "thiserror", +] [[package]] -name = "byteorder" -version = "1.4.3" +name = "astroport-native-coin-registry" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "648ed6827a8f11012c0377fb60329204e8511fe46c86db3220113e70bdc57826" +dependencies = [ + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-storage", + "cw-storage-plus 0.15.1", + "cw2 0.15.1", + "thiserror", +] [[package]] -name = "bytes" -version = "1.4.0" +name = "astroport-pair" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "4b2287463c922ef2a73f03fe6b16b37123f3f26da5a76998e6ddf828856068f7" +dependencies = [ + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw2 0.15.1", + "cw20 0.15.1", + "integer-sqrt", + "protobuf", + "thiserror", +] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "astroport-pair-stable" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "a3a262f2b6916e2a83808b246ff16cb2306a416e88b15a47ddbea5f8b666b1a4" +dependencies = [ + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw-utils 1.0.1", + "cw2 0.15.1", + "cw20 0.15.1", + "itertools", + "thiserror", +] [[package]] -name = "chrono" -version = "0.4.23" +name = "astroport-router" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "6e3bbb33c00370bd194cf3a166f1e3f4029a2add2bea01a5eb61e886aefbc85b" dependencies = [ - "num-integer", - "num-traits", + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw2 0.15.1", + "cw20 0.15.1", + "integer-sqrt", + "thiserror", ] [[package]] -name = "const-oid" -version = "0.9.5" +name = "astroport-staking" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "67adbc4240794e886ca1edbc7d46bc8a54c7aca7217d73ddcfbc90e1dbb030e7" +dependencies = [ + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw2 0.15.1", + "cw20 0.15.1", + "protobuf", + "thiserror", +] [[package]] -name = "cosmwasm-crypto" -version = "1.4.0" +name = "astroport-token" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca101fbf2f76723711a30ea3771ef312ec3ec254ad021b237871ed802f9f175" +checksum = "3360383a2e585211da9a455ad57eb100578253b5d18a387f025cadd666604d99" dependencies = [ - "digest 0.10.6", - "ed25519-zebra", - "k256", - "rand_core 0.6.4", - "thiserror", + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw2 0.15.1", + "cw20 0.15.1", + "cw20-base", + "snafu", ] [[package]] -name = "cosmwasm-derive" -version = "1.4.0" +name = "astroport-vesting" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c73d2dd292f60e42849d2b07c03d809cf31e128a4299a805abd6d24553bcaaf5" +checksum = "dffce7cf86bf4d4f177ef941145352499e802abc4b898032af7808d16cca6371" dependencies = [ - "syn 1.0.107", + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw-utils 0.15.1", + "cw2 0.15.1", + "cw20 0.15.1", + "thiserror", ] [[package]] -name = "cosmwasm-schema" -version = "1.4.0" +name = "astroport-whitelist" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce34a08020433989af5cc470104f6bd22134320fe0221bd8aeb919fd5ec92d5" +checksum = "44156757bfab3d4bd208d9b86b890d1478f45d07c8f8d3d1c3e3da91081cb54d" dependencies = [ - "cosmwasm-schema-derive", - "schemars", - "serde", - "serde_json", + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw1-whitelist", + "cw2 0.15.1", "thiserror", ] [[package]] -name = "cosmwasm-schema-derive" -version = "1.4.0" +name = "async-trait" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96694ec781a7dd6dea1f968a2529ade009c21ad999c88b5f53d6cc495b3b96f7" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.31", ] [[package]] -name = "cosmwasm-std" -version = "1.4.0" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a44d3f9c25b2f864737c6605a98f2e4675d53fd8bbc7cf4d7c02475661a793d" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "base64", - "bnum", - "cosmwasm-crypto", - "cosmwasm-derive", - "derivative", - "forward_ref", - "hex", - "schemars", - "serde", - "serde-json-wasm", - "sha2 0.10.6", - "thiserror", + "hermit-abi 0.1.19", + "libc", + "winapi", ] [[package]] -name = "cpufeatures" -version = "0.2.5" +name = "autocfg" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "crunchy" -version = "0.2.2" +name = "base16ct" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" [[package]] -name = "crypto-bigint" -version = "0.5.3" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] -name = "crypto-common" -version = "0.1.6" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "curve25519-dalek" -version = "3.2.0" +name = "base64" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[package]] +name = "bindgen" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "bitflags", + "cexpr", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + +[[package]] +name = "bip32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30ed1d6f8437a487a266c8293aeb95b61a23261273e3e02912cdb8b68bf798b" +dependencies = [ + "bs58", + "hmac", + "k256 0.11.6", + "once_cell", + "pbkdf2", + "rand_core 0.6.4", + "ripemd", + "sha2 0.10.6", "subtle", "zeroize", ] [[package]] -name = "cw-controllers" -version = "1.0.1" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91440ce8ec4f0642798bc8c8cb6b9b53c1926c6dadaf0eed267a5145cd529071" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "schemars", - "serde", - "thiserror", + "generic-array", ] [[package]] -name = "cw-dex" -version = "0.1.1" +name = "block-buffer" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8948dc1d7efcbcf2331b26271f30bc22ca68713d273bb9d68d8acad3e05afda4" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "apollo-cw-asset", - "apollo-utils", - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw20 1.1.0", - "thiserror", + "generic-array", ] [[package]] -name = "cw-dex" -version = "0.3.1" +name = "bnum" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128a44527fc0d6abf05f9eda748b9027536e12dff93f5acc8449f51583309350" + +[[package]] +name = "bs58" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b25ff7cf4e15288be9021a797eb1074cfa97ccb2152d1c645ba9b5d6b31a82c" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" dependencies = [ - "apollo-cw-asset", - "apollo-utils", - "astroport", - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw20 1.1.0", - "osmosis-std", - "thiserror", - "uint", + "sha2 0.9.9", ] [[package]] -name = "cw-dex-router" -version = "0.1.0" +name = "bumpalo" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81c676d4d069b16a4d3dd397319d57fcdb9ae2f6db1e6a63329e547c48bffe34" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ - "apollo-cw-asset", - "apollo-utils", - "cosmwasm-schema", - "cosmwasm-std", - "cw-controllers", - "cw-dex 0.1.1", - "cw-storage-plus 1.1.0", - "cw2 1.1.0", - "cw20 1.1.0", - "thiserror", + "libc", ] [[package]] -name = "cw-storage-plus" -version = "0.15.1" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6cf70ef7686e2da9ad7b067c5942cd3e88dd9453f7af42f54557f8af300fb0" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "cosmwasm-std", - "schemars", - "serde", + "nom", ] [[package]] -name = "cw-storage-plus" -version = "1.1.0" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ - "cosmwasm-std", - "schemars", + "num-traits", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags", + "clap_lex", + "indexmap", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "config" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" +dependencies = [ + "async-trait", + "json5", + "lazy_static", + "nom", + "pathdiff", + "ron", + "rust-ini", "serde", + "serde_json", + "toml", + "yaml-rust", ] [[package]] -name = "cw-utils" -version = "0.15.1" +name = "const-oid" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae0b69fa7679de78825b4edeeec045066aa2b2c4b6e063d80042e565bb4da5c" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw2 0.15.1", - "schemars", - "semver", + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cosmos-sdk-proto" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20b42021d8488665b1a0d9748f1f81df7235362d194f44481e2e61bf376b77b4" +dependencies = [ + "prost 0.11.9", + "prost-types", + "tendermint-proto", +] + +[[package]] +name = "cosmrs" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3903590099dcf1ea580d9353034c9ba1dbf55d1389a5bd2ade98535c3445d1f9" +dependencies = [ + "bip32", + "cosmos-sdk-proto", + "ecdsa 0.14.8", + "eyre", + "getrandom", + "k256 0.11.6", + "rand_core 0.6.4", "serde", + "serde_json", + "subtle-encoding", + "tendermint", + "tendermint-rpc", "thiserror", ] [[package]] -name = "cw-utils" -version = "1.0.1" +name = "cosmwasm-crypto" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" +checksum = "1ca101fbf2f76723711a30ea3771ef312ec3ec254ad021b237871ed802f9f175" dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw2 1.1.0", - "schemars", - "semver", - "serde", + "digest 0.10.6", + "ed25519-zebra", + "k256 0.13.1", + "rand_core 0.6.4", "thiserror", ] [[package]] -name = "cw-vault-standard" -version = "0.3.2" +name = "cosmwasm-derive" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc4f7b369e98e059cf5011ca7dfa7489d08e85ae1ab2e02d404afcfa071627d" +checksum = "c73d2dd292f60e42849d2b07c03d809cf31e128a4299a805abd6d24553bcaaf5" dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-utils 1.0.1", - "schemars", - "serde", + "syn 1.0.107", ] [[package]] -name = "cw2" -version = "0.15.1" +name = "cosmwasm-schema" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5abb8ecea72e09afff830252963cb60faf945ce6cef2c20a43814516082653da" +checksum = "6ce34a08020433989af5cc470104f6bd22134320fe0221bd8aeb919fd5ec92d5" dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 0.15.1", + "cosmwasm-schema-derive", "schemars", "serde", + "serde_json", + "thiserror", ] [[package]] -name = "cw2" -version = "1.1.0" +name = "cosmwasm-schema-derive" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ac2dc7a55ad64173ca1e0a46697c31b7a5c51342f55a1e84a724da4eb99908" +checksum = "96694ec781a7dd6dea1f968a2529ade009c21ad999c88b5f53d6cc495b3b96f7" dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 1.1.0", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "cosmwasm-std" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a44d3f9c25b2f864737c6605a98f2e4675d53fd8bbc7cf4d7c02475661a793d" +dependencies = [ + "base64 0.21.3", + "bnum", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", "schemars", "serde", + "serde-json-wasm", + "sha2 0.10.6", "thiserror", ] [[package]] -name = "cw20" -version = "0.15.1" +name = "cosmwasm-storage" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6025276fb6e603e974c21f3e4606982cdc646080e8fba3198816605505e1d9a" +checksum = "ab544dfcad7c9e971933d522d99ec75cc8ddfa338854bb992b092e11bcd7e818" dependencies = [ - "cosmwasm-schema", "cosmwasm-std", - "cw-utils 0.15.1", - "schemars", "serde", ] [[package]] -name = "cw20" -version = "1.1.0" +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ct-logs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" +dependencies = [ + "sct", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cw-address-like" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451a4691083a88a3c0630a8a88799e9d4cd6679b7ce8ff22b8da2873ff31d380" +dependencies = [ + "cosmwasm-std", +] + +[[package]] +name = "cw-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4728ee779cede6a73bf3daf35504960eb3c256cedd40e5e2827207a49dd76027" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "cw-controllers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91440ce8ec4f0642798bc8c8cb6b9b53c1926c6dadaf0eed267a5145cd529071" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 1.1.0", + "cw-utils 1.0.1", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw-dex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8948dc1d7efcbcf2331b26271f30bc22ca68713d273bb9d68d8acad3e05afda4" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 1.1.0", + "cw-utils 1.0.1", + "cw20 1.1.0", + "thiserror", +] + +[[package]] +name = "cw-dex" +version = "0.4.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6754c95d50772679629d18644b5764c715c2adea10b21b4b8b31ccd197a7c66e" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "astroport", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 1.1.0", + "cw-utils 1.0.1", + "cw20 1.1.0", + "osmosis-std 0.16.2", + "thiserror", + "uint", +] + +[[package]] +name = "cw-dex-router" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81c676d4d069b16a4d3dd397319d57fcdb9ae2f6db1e6a63329e547c48bffe34" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "cosmwasm-schema", + "cosmwasm-std", + "cw-controllers", + "cw-dex 0.1.1", + "cw-storage-plus 1.1.0", + "cw2 1.1.0", + "cw20 1.1.0", + "thiserror", +] + +[[package]] +name = "cw-dex-router" +version = "0.2.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4dcc1413a73797fbc909eb606d889350ef0b345dddeda82f904fe7de34e96e6" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "cosmwasm-schema", + "cosmwasm-std", + "cw-controllers", + "cw-dex 0.4.0-rc.2", + "cw-storage-plus 1.1.0", + "cw2 1.1.0", + "cw20 1.1.0", + "thiserror", +] + +[[package]] +name = "cw-it" +version = "0.2.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d773e4f40f344014825f05c735aff5ade2134324e1f59180df7c8a03bfaa65b" +dependencies = [ + "anyhow", + "apollo-cw-multi-test", + "astroport", + "astroport-factory", + "astroport-generator", + "astroport-maker", + "astroport-native-coin-registry", + "astroport-pair", + "astroport-pair-stable", + "astroport-router", + "astroport-staking", + "astroport-token", + "astroport-vesting", + "astroport-whitelist", + "config", + "cosmrs", + "cosmwasm-schema", + "cosmwasm-std", + "cw20 0.15.1", + "osmosis-std 0.19.1", + "osmosis-test-tube", + "paste", + "prost 0.11.9", + "regex", + "serde", + "serde_json", + "strum 0.24.1", + "test-tube", + "thiserror", +] + +[[package]] +name = "cw-item-set" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea5a233bd67babedbe96a514178a64b0c597f1f38bc474fa8d63e3f26bdceb2" +dependencies = [ + "cosmwasm-std", + "cw-storage-plus 1.1.0", +] + +[[package]] +name = "cw-ownable" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093dfb4520c48b5848274dd88ea99e280a04bc08729603341c7fb0d758c74321" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-ownable-derive", + "cw-storage-plus 1.1.0", + "cw-utils 1.0.1", + "thiserror", +] + +[[package]] +name = "cw-ownable-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d3bf2e0f341bb6cc100d7d441d31cf713fbd3ce0c511f91e79f14b40a889af" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "cw-storage-plus" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6cf70ef7686e2da9ad7b067c5942cd3e88dd9453f7af42f54557f8af300fb0" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-storage-plus" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae0b69fa7679de78825b4edeeec045066aa2b2c4b6e063d80042e565bb4da5c" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2 0.15.1", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw-utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2 1.1.0", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw-vault-standard" +version = "0.3.3-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12a9e148a205aebfb2bf069a5c3756617411c0d8a250f29ec800fa5811090e91" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils 1.0.1", + "schemars", + "serde", +] + +[[package]] +name = "cw-vault-standard-test-helpers" +version = "0.3.3-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8ec267767fbf156d6150b071cdfae2a42d6389dbb2d214e9d2b52b3cf13018" +dependencies = [ + "cosmwasm-std", + "cw-it", + "cw-utils 1.0.1", + "cw-vault-standard", +] + +[[package]] +name = "cw1" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe0783ec4210ba4e0cdfed9874802f469c6db0880f742ad427cb950e940b21c" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw1-whitelist" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233dd13f61495f1336da57c8bdca0536fa9f8dd59c12d2bbfc59928ea580e478" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw-utils 0.15.1", + "cw1", + "cw2 0.15.1", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5abb8ecea72e09afff830252963cb60faf945ce6cef2c20a43814516082653da" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "schemars", + "serde", +] + +[[package]] +name = "cw2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ac2dc7a55ad64173ca1e0a46697c31b7a5c51342f55a1e84a724da4eb99908" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 1.1.0", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw20" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6025276fb6e603e974c21f3e4606982cdc646080e8fba3198816605505e1d9a" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils 0.15.1", + "schemars", + "serde", +] + +[[package]] +name = "cw20" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011c45920f8200bd5d32d4fe52502506f64f2f75651ab408054d4cfc75ca3a9b" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils 1.0.1", + "schemars", + "serde", +] + +[[package]] +name = "cw20-base" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0909c56d0c14601fbdc69382189799482799dcad87587926aec1f3aa321abc41" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.15.1", + "cw-utils 0.15.1", + "cw2 0.15.1", + "cw20 0.15.1", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dlv-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dyn-clone" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +dependencies = [ + "der 0.7.8", + "digest 0.10.6", + "elliptic-curve 0.13.5", + "rfc6979 0.4.0", + "signature 2.1.0", + "spki 0.7.2", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek", + "hashbrown", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest 0.10.6", + "ff 0.12.1", + "generic-array", + "group 0.12.1", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.3", + "digest 0.10.6", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1 0.7.1", + "subtle", + "zeroize", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "flex-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" +dependencies = [ + "eyre", + "paste", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.3", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-proxy" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca815a891b24fdfb243fa3239c86154392b0953ee584aa1a2a1f66d20cbe75cc" +dependencies = [ + "bytes", + "futures", + "headers", + "http", + "hyper", + "hyper-rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "tower-service", + "webpki", +] + +[[package]] +name = "hyper-rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "ct-logs", + "futures-util", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "webpki", + "webpki-roots", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.6", + "sha3", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa 0.16.7", + "elliptic-curve 0.13.5", + "once_cell", + "sha2 0.10.6", + "signature 2.1.0", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "liquidity-helper" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fcbaa0b50025e319bec34d39de1af4684252b22b0bdeff260bfb68b8c250d8f" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "cosmwasm-schema", + "cosmwasm-std", + "cw20 1.1.0", + "schemars", + "serde", +] + +[[package]] +name = "liquidity-helper" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db586fec0aa5d95ae9fccba0ee30ea75474709e0dcdb312b5f75302cd25262e9" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "cosmwasm-schema", + "cosmwasm-std", + "cw20 1.1.0", +] + +[[package]] +name = "locked-astroport-vault" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3ebdb74ecc9d95e87fa7764380b42773b1fd6cfe672e1c199a6e115ecfbed0" +dependencies = [ + "apollo-cw-asset", + "apollo-utils", + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-dex 0.4.0-rc.2", + "cw-dex-router 0.2.0-rc.2", + "cw-item-set", + "cw-ownable", + "cw-storage-plus 1.1.0", + "cw-utils 1.0.1", + "cw-vault-standard", + "cw2 1.1.0", + "cw20 1.1.0", + "liquidity-helper 0.1.0", + "optional_struct", + "osmosis-std 0.14.0", + "schemars", + "serde", + "strum 0.25.0", + "thiserror", +] + +[[package]] +name = "locked-astroport-vault-test-helpers" +version = "0.1.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c655bdf3e9e5b99e78a14323f63df00f1674e0ee4da652a643329d9d00e6de10" +dependencies = [ + "apollo-cw-asset", + "astroport-liquidity-helper", + "cosmwasm-schema", + "cosmwasm-std", + "cw-dex 0.4.0-rc.2", + "cw-dex-router 0.2.0-rc.2", + "cw-it", + "cw-ownable", + "cw-utils 1.0.1", + "cw-vault-standard", + "cw-vault-standard-test-helpers", + "cw2 1.1.0", + "cw20 1.1.0", + "liquidity-helper 0.1.0", + "locked-astroport-vault", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.2", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "optional_struct" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e60da57c6a9d057c07f1a90ca7abed9d104fca0d0db1a7d7e3304e4567d977fd" +dependencies = [ + "optional_struct_internal", + "optional_struct_macro_impl", +] + +[[package]] +name = "optional_struct_internal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e389cec0df3c934737dadc7b927a8e05b8c8ef792cd1af06a524bd129e9f4d" + +[[package]] +name = "optional_struct_macro_impl" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "286db11c92049709d5fbbe89eecaa2febc0efe6c18d94d9ebf942e592ac80f9f" +dependencies = [ + "optional_struct_internal", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "ordered-multimap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" +dependencies = [ + "dlv-list", + "hashbrown", +] + +[[package]] +name = "os_str_bytes" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" + +[[package]] +name = "osmosis-std" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc0a9075efd64ed5a8be3bf134cbf1080570d68384f2ad58ffaac6c00d063fd" +dependencies = [ + "chrono", + "cosmwasm-std", + "osmosis-std-derive 0.13.2", + "prost 0.11.9", + "prost-types", + "schemars", + "serde", + "serde-cw-value", +] + +[[package]] +name = "osmosis-std" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75895e4db1a81ca29118e366365744f64314938327e4eedba8e6e462fb15e94f" +dependencies = [ + "chrono", + "cosmwasm-std", + "osmosis-std-derive 0.16.2", + "prost 0.11.9", + "prost-types", + "schemars", + "serde", + "serde-cw-value", +] + +[[package]] +name = "osmosis-std" +version = "0.17.0-rc0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b022b748710ecdf1adc6a124c3bef29f17ef05e7fa1260a08889d1d53f9cc5" +dependencies = [ + "chrono", + "cosmwasm-std", + "osmosis-std-derive 0.16.2", + "prost 0.11.9", + "prost-types", + "schemars", + "serde", + "serde-cw-value", +] + +[[package]] +name = "osmosis-std" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "088997c4da871db9edb9e090a4e164d1cb12498781491ccb8030246287400300" +dependencies = [ + "chrono", + "cosmwasm-std", + "osmosis-std-derive 0.16.2", + "prost 0.11.9", + "prost-types", + "schemars", + "serde", + "serde-cw-value", +] + +[[package]] +name = "osmosis-std-derive" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a455e262a6fdfd3914f3a4e11e6bc0ce491901cb9d507d7856d7ef6e129e90c6" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "osmosis-std-derive" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47f0b2f22adb341bb59e5a3a1b464dde033181954bd055b9ae86d6511ba465b" +dependencies = [ + "itertools", + "proc-macro2", + "prost-types", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "osmosis-test-tube" +version = "17.0.0-rc0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977a2b4f088dd704a47e96b5914e28465cfcdb1cb1145a1f9b45c219a9b145c5" +dependencies = [ + "base64 0.13.1", + "bindgen", + "cosmrs", + "cosmwasm-std", + "osmosis-std 0.17.0-rc0", + "prost 0.11.9", + "serde", + "serde_json", + "test-tube", + "thiserror", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "peg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pest" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "pest_meta" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.6", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.8", + "spki 0.7.2", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.107", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +dependencies = [ + "bytes", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "ripemd160" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "ron" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +dependencies = [ + "base64 0.13.1", + "bitflags", + "serde", +] + +[[package]] +name = "rust-ini" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.1", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" +dependencies = [ + "openssl-probe", + "rustls", + "schannel", + "security-framework", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "schemars" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.107", +] + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct 0.1.1", + "der 0.6.1", + "generic-array", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.8", + "generic-array", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-cw-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75d32da6b8ed758b7d850b6c3c08f1d7df51a4df3cb201296e63e34a78e99d4" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.107", +] + +[[package]] +name = "serde_json" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "snafu" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" +dependencies = [ + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011c45920f8200bd5d32d4fe52502506f64f2f75651ab408054d4cfc75ca3a9b" +checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-utils 1.0.1", - "schemars", - "serde", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] -name = "der" -version = "0.7.8" +name = "socket2" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ - "const-oid", - "zeroize", + "libc", + "winapi", ] [[package]] -name = "derivative" -version = "2.2.0" +name = "spin" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", + "base64ct", + "der 0.6.1", ] [[package]] -name = "digest" -version = "0.9.0" +name = "spki" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ - "generic-array", + "base64ct", + "der 0.7.8", ] [[package]] -name = "digest" -version = "0.10.6" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "block-buffer 0.10.3", - "const-oid", - "crypto-common", - "subtle", + "strum_macros 0.24.3", ] [[package]] -name = "dyn-clone" -version = "1.0.10" +name = "strum" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.2", +] [[package]] -name = "ecdsa" -version = "0.16.7" +name = "strum_macros" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "der", - "digest 0.10.6", - "elliptic-curve", - "rfc6979", - "signature", - "spki", + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.107", ] [[package]] -name = "ed25519-zebra" -version = "3.1.0" +name = "strum_macros" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ - "curve25519-dalek", - "hashbrown", - "hex", - "rand_core 0.6.4", - "serde", - "sha2 0.9.9", - "zeroize", + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.31", ] [[package]] -name = "either" -version = "1.8.1" +name = "subtle" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] -name = "elliptic-curve" -version = "0.13.5" +name = "subtle-encoding" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.6", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", "zeroize", ] [[package]] -name = "ff" -version = "0.13.0" +name = "syn" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ - "rand_core 0.6.4", - "subtle", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "forward_ref" -version = "1.0.0" +name = "syn" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] -name = "generic-array" -version = "0.14.6" +name = "tendermint" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "467f82178deeebcd357e1273a0c0b77b9a8a0313ef7c07074baebe99d87851f4" dependencies = [ - "typenum", - "version_check", + "async-trait", + "bytes", + "ed25519", + "ed25519-dalek", + "flex-error", + "futures", + "k256 0.11.6", + "num-traits", + "once_cell", + "prost 0.11.9", + "prost-types", + "ripemd160", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2 0.9.9", + "signature 1.6.4", + "subtle", + "subtle-encoding", + "tendermint-proto", + "time", "zeroize", ] [[package]] -name = "getrandom" -version = "0.2.8" +name = "tendermint-config" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "2d42ee0abc27ef5fc34080cce8d43c189950d331631546e7dfb983b6274fa327" dependencies = [ - "cfg-if", - "libc", - "wasi", + "flex-error", + "serde", + "serde_json", + "tendermint", + "toml", + "url", ] [[package]] -name = "group" -version = "0.13.0" +name = "tendermint-proto" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +checksum = "68ce80bf536476db81ecc9ebab834dc329c9c1509a694f211a73858814bfe023" dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost 0.11.9", + "prost-types", + "serde", + "serde_bytes", + "subtle-encoding", + "time", ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "tendermint-rpc" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "6f14aafe3528a0f75e9f3f410b525617b2de16c4b7830a21f717eee62882ec60" dependencies = [ - "ahash", + "async-trait", + "bytes", + "flex-error", + "futures", + "getrandom", + "http", + "hyper", + "hyper-proxy", + "hyper-rustls", + "peg", + "pin-project", + "serde", + "serde_bytes", + "serde_json", + "subtle-encoding", + "tendermint", + "tendermint-config", + "tendermint-proto", + "thiserror", + "time", + "tokio", + "tracing", + "url", + "uuid", + "walkdir", ] [[package]] -name = "hex" -version = "0.4.3" +name = "termcolor" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] [[package]] -name = "hmac" -version = "0.12.1" +name = "test-case" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "2a1d6e7bde536b0412f20765b76e921028059adfd1b90d8974d33fd3c91b25df" dependencies = [ - "digest 0.10.6", + "test-case-macros", ] [[package]] -name = "itertools" -version = "0.10.5" +name = "test-case-core" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "d10394d5d1e27794f772b6fc854c7e91a2dc26e2cbf807ad523370c2a59c0cee" dependencies = [ - "either", + "cfg-if", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.107", ] [[package]] -name = "itoa" -version = "1.0.5" +name = "test-case-macros" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "eeb9a44b1c6a54c1ba58b152797739dba2a83ca74e18168a68c980eb142f9404" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.107", + "test-case-core", +] [[package]] -name = "k256" -version = "0.13.1" +name = "test-tube" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "04de0d85f2438f0b64a5c135a1524564f2b89263cfbce011542446b6681d006f" dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2 0.10.6", - "signature", + "base64 0.13.1", + "cosmrs", + "cosmwasm-std", + "osmosis-std 0.19.1", + "prost 0.11.9", + "serde", + "serde_json", + "thiserror", ] [[package]] -name = "libc" -version = "0.2.139" +name = "textwrap" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] -name = "num-integer" -version = "0.1.45" +name = "thiserror" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ - "autocfg", - "num-traits", + "thiserror-impl", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "thiserror-impl" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ - "autocfg", + "proc-macro2", + "quote", + "syn 2.0.31", ] [[package]] -name = "once_cell" -version = "1.17.1" +name = "time" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +dependencies = [ + "libc", + "num_threads", + "time-macros", +] [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "time-macros" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" [[package]] -name = "osmosis-std" -version = "0.16.2" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75895e4db1a81ca29118e366365744f64314938327e4eedba8e6e462fb15e94f" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "chrono", - "cosmwasm-std", - "osmosis-std-derive", - "prost", - "prost-types", - "schemars", - "serde", - "serde-cw-value", + "tinyvec_macros", ] [[package]] -name = "osmosis-std-derive" -version = "0.16.2" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47f0b2f22adb341bb59e5a3a1b464dde033181954bd055b9ae86d6511ba465b" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ - "itertools", - "proc-macro2", - "prost-types", - "quote", - "syn 1.0.107", + "autocfg", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys", ] [[package]] -name = "pkcs8" -version = "0.10.2" +name = "tokio-macros" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "der", - "spki", + "proc-macro2", + "quote", + "syn 2.0.31", ] [[package]] -name = "proc-macro2" -version = "1.0.66" +name = "tokio-rustls" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "unicode-ident", + "rustls", + "tokio", + "webpki", ] [[package]] -name = "prost" -version = "0.11.9" +name = "tokio-util" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", - "prost-derive", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", ] [[package]] -name = "prost-derive" -version = "0.11.9" +name = "toml" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.107", + "serde", ] [[package]] -name = "prost-types" -version = "0.11.9" +name = "tower-service" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "prost", + "cfg-if", + "pin-project-lite", + "tracing-core", ] [[package]] -name = "quote" -version = "1.0.33" +name = "tracing-core" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ - "proc-macro2", + "once_cell", ] [[package]] -name = "rand_core" -version = "0.5.1" +name = "try-lock" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] -name = "rand_core" -version = "0.6.4" +name = "typenum" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] -name = "rfc6979" -version = "0.4.0" +name = "ucd-trie" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ - "hmac", - "subtle", + "byteorder", + "crunchy", + "hex", + "static_assertions", ] [[package]] -name = "ryu" -version = "1.0.12" +name = "unicode-bidi" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] -name = "schemars" -version = "0.8.11" +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", + "tinyvec", ] [[package]] -name = "schemars_derive" -version = "0.8.11" +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 1.0.107", + "form_urlencoded", + "idna", + "percent-encoding", ] [[package]] -name = "sec1" -version = "0.7.1" +name = "uuid" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "vault-zapper" +version = "0.1.0" dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", + "apollo-cw-asset", + "apollo-utils", + "astroport-liquidity-helper", + "cosmwasm-schema", + "cosmwasm-std", + "cw-dex 0.4.0-rc.2", + "cw-dex-router 0.1.0", + "cw-it", + "cw-storage-plus 1.1.0", + "cw-utils 1.0.1", + "cw-vault-standard", + "cw-vault-standard-test-helpers", + "cw2 1.1.0", + "cw20 1.1.0", + "liquidity-helper 0.1.0", + "locked-astroport-vault", + "locked-astroport-vault-test-helpers", + "test-case", + "thiserror", ] [[package]] -name = "semver" -version = "1.0.16" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "serde" -version = "1.0.152" +name = "walkdir" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ - "serde_derive", + "same-file", + "winapi-util", ] [[package]] -name = "serde-cw-value" -version = "0.7.0" +name = "want" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75d32da6b8ed758b7d850b6c3c08f1d7df51a4df3cb201296e63e34a78e99d4" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "serde", + "try-lock", ] [[package]] -name = "serde-json-wasm" -version = "0.5.0" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "serde", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] -name = "serde_derive" -version = "1.0.152" +name = "wasm-bindgen-backend" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ + "bumpalo", + "log", + "once_cell", "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.31", + "wasm-bindgen-shared", ] [[package]] -name = "serde_derive_internals" -version = "0.26.0" +name = "wasm-bindgen-macro" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "proc-macro2", "quote", - "syn 1.0.107", + "wasm-bindgen-macro-support", ] [[package]] -name = "serde_json" -version = "1.0.93" +name = "wasm-bindgen-macro-support" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "itoa", - "ryu", - "serde", + "proc-macro2", + "quote", + "syn 2.0.31", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "sha2" -version = "0.9.9" +name = "wasm-bindgen-shared" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "sha2" -version = "0.10.6" +name = "webpki" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", + "ring", + "untrusted", ] [[package]] -name = "signature" -version = "2.1.0" +name = "webpki-roots" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ - "digest 0.10.6", - "rand_core 0.6.4", + "webpki", ] [[package]] -name = "spki" -version = "0.7.2" +name = "which" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ - "base64ct", - "der", + "either", + "libc", + "once_cell", ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] [[package]] -name = "subtle" -version = "2.4.1" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "syn" -version = "1.0.107" +name = "winapi-util" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "winapi", ] [[package]] -name = "syn" -version = "2.0.31" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "thiserror" -version = "1.0.48" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "thiserror-impl", + "windows-targets", ] [[package]] -name = "thiserror-impl" -version = "1.0.48" +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.31", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] -name = "typenum" -version = "1.16.0" +name = "windows_aarch64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "uint" -version = "0.9.5" +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] -name = "unicode-ident" -version = "1.0.6" +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] -name = "vault-zapper" -version = "0.1.0" -dependencies = [ - "apollo-cw-asset", - "apollo-utils", - "cosmwasm-schema", - "cosmwasm-std", - "cw-dex 0.3.1", - "cw-dex-router", - "cw-storage-plus 1.1.0", - "cw-vault-standard", - "cw2 1.1.0", - "cw20 1.1.0", - "thiserror", -] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] -name = "version_check" -version = "0.9.4" +name = "windows_x86_64_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] [[package]] name = "zeroize" version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] diff --git a/Cargo.toml b/Cargo.toml index 6207e44..5f47963 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "vault-zapper" +name = "vault-zapper" version = "0.1.0" authors = ["Sturdy "] edition = "2021" @@ -32,28 +32,34 @@ default = [] library = [] osmosis = ["cw-dex/osmosis"] astroport = ["cw-dex/astroport"] +osmosis-test-tube = ["cw-it/osmosis-test-tube", "locked-astroport-vault-test-helpers/osmosis-test-tube"] -[package.metadata.scripts] -optimize = """docker run --rm -v "$(pwd)":/code \ - --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 -""" -optimize-arm64 = """docker run --rm -v "$(pwd)":/code \ ---mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ ---mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ -cosmwasm/rust-optimizer-arm64:0.12.11 -""" + +[package.metadata.optimizer] +builds = [ + { name = "astroport", features = ["astroport"] }, + { name = "osmosis", features = ["osmosis"] }, +] [dependencies] -apollo-utils = "0.1.1" -cosmwasm-schema = "1.4.0" -cosmwasm-std = "1.4.0" -cw-storage-plus = "1.1.0" -cw2 = "1.1.0" -cw20 = "1.1.0" -thiserror = { version = "1.0.48" } -cw-vault-standard = { version = "0.3.2", features = ["lockup"] } -cw-dex-router = { version = "0.1.0", features = ["library"] } -apollo-cw-asset = "0.1.2" -cw-dex = "0.3.1" +apollo-utils = "0.1.1" +cosmwasm-schema = "1.4.0" +cosmwasm-std = "1.4.0" +cw-storage-plus = "1.1.0" +cw2 = "1.1.0" +cw20 = "1.1.0" +thiserror = { version = "1.0.48" } +cw-vault-standard = { version = "0.3.3-rc.1", features = ["lockup"] } +cw-dex-router = { version = "0.1.0", features = ["library"] } +apollo-cw-asset = "0.1.2" +cw-dex = "0.4.0-rc.2" +liquidity-helper = "0.1.0" + +[dev-dependencies] +cw-it = { version = "0.2.0-rc.4", features = ["astroport-multi-test"] } +cw-vault-standard-test-helpers = "0.3.3-rc.4" +locked-astroport-vault-test-helpers = "0.1.0-rc.4" +locked-astroport-vault = "0.1.0-rc.2" +astroport-liquidity-helper = "0.2.0" +test-case = "3.1.0" +cw-utils = "1.0.1" diff --git a/Makefile.toml b/Makefile.toml index 0704fc3..6439ffa 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -1,45 +1,83 @@ +extend = [{ path = "coverage_grcov.Makefile.toml" }] + +[config] +default_to_workspace = false +skip_core_tasks = true + [env] -CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true +# If you bump this version, verify RUST_VERSION correctness +RUST_OPTIMIZER_VERSION = "0.15.0" +# Use rust version from rust-optimizer Dockerfile (see https://github.com/CosmWasm/rust-optimizer/blob/main/Dockerfile#L1) +# to be sure that we compile / test against the same version +RUST_VERSION = "1.69.0" +NIGHTLY_VERSION = "nightly-2023-08-29" + +[tasks.install-stable] +script = ''' +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain ${RUST_VERSION} +rustup target add wasm32-unknown-unknown --toolchain ${RUST_VERSION} +rustup component add rustfmt --toolchain ${RUST_VERSION} +rustup component add clippy --toolchain ${RUST_VERSION} +rustup component add llvm-tools-preview --toolchain ${RUST_VERSION} +''' + +[tasks.install-nightly] +script = ''' +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain ${NIGHTLY_VERSION} +rustup target add wasm32-unknown-unknown --toolchain ${NIGHTLY_VERSION} +rustup component add rustfmt --toolchain ${NIGHTLY_VERSION} +rustup component add clippy --toolchain ${NIGHTLY_VERSION} +''' + +[tasks.rust-optimizer] +cwd = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}" +script = """ +if [[ $(arch) == "arm64" ]]; then + image="abstractmoney/rust-optimizer-arm64:${RUST_OPTIMIZER_VERSION}" +else + image="abstractmoney/rust-optimizer:${RUST_OPTIMIZER_VERSION}" +fi +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + ${image} +""" [tasks.format] -toolchain = "nightly" +toolchain = "${NIGHTLY_VERSION}" install_crate = { crate_name = "rustfmt-nightly", rustup_component_name = "rustfmt-preview", binary = "rustfmt", test_arg = "--help" } command = "cargo" args = ["fmt", "--all", "--", "--emit=files","--verbose"] [tasks.format-check] -toolchain = "nightly" +toolchain = "${NIGHTLY_VERSION}" install_crate = { crate_name = "rustfmt-nightly", rustup_component_name = "rustfmt-preview", binary = "rustfmt", test_arg = "--help" } command = "cargo" args = ["fmt", "--all", "--","--verbose", "--check"] -# This task requires the `cargo-udeps` package: https://crates.io/crates/cargo-udeps -[tasks.udeps] -toolchain = "nightly" -command = "cargo" -args = ["udeps"] - [tasks.deny] command = "cargo" args = ["deny", "check"] [tasks.check] +toolchain = "${RUST_VERSION}" command = "cargo" args = ["check"] [tasks.clippy-check] -toolchain = "nightly" +toolchain = "${NIGHTLY_VERSION}" command = "cargo" args = ["clippy","--all-features","--","-D","warnings"] [tasks.clippy-fix] -toolchain = "nightly" +toolchain = "${NIGHTLY_VERSION}" command = "cargo" -args = ["clippy","--fix","--allow-staged","--","-D","warnings"] +args = ["clippy","--all-features", "--fix","--allow-staged", "--allow-dirty", "--","-D","warnings"] [tasks.todo-check] script = { file = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/scripts/todo-lint.sh", absolute_path = true } # This task requires the `cargo-tarpaulin` package: https://crates.io/crates/cargo-tarpaulin [tasks.cov] +toolchain = "${RUST_VERSION}" command = "cargo" args = [ "tarpaulin", @@ -51,6 +89,7 @@ args = [ ] [tasks.docs] +toolchain = "${RUST_VERSION}" command = "cargo" args = [ "doc", @@ -69,34 +108,78 @@ args = [ # This task requires the `cargo-machete` package: https://crates.io/crates/cargo-machete [tasks.machete-check] +toolchain = "${NIGHTLY_VERSION}" command = "cargo" args = ["machete"] [tasks.machete-fix] command = "cargo" args = ["machete", "--fix"] -# Run automatically on "cargo make". This is the default task. We keep all the -# default tasks and add our own "custom" task. -[tasks.dev-test-flow] -run_task = "custom-default" -# Custom tasks to run on "cargo make" -[tasks.custom-default] -dependencies = ["deny", "clippy-fix", "docs", "machete-fix"] - -# Wasm build of test contract +# Unoptimized Wasm build of contract for testing [tasks.wasm] +toolchain = "${RUST_VERSION}" command = "cargo" args = [ "build", + "-p", + "vault-zapper", "--target", "wasm32-unknown-unknown", "--lib", "--release", - "--package", - "osmosis-test-contract" + "--features", + "astroport", ] +# Run all tests +[tasks.test] +toolchain = "${RUST_VERSION}" +command = "cargo" +args = ["test", "--locked", "--features", "osmosis,astroport"] + +# Run unit tests +[tasks.unit-test] +toolchain = "${RUST_VERSION}" +command = "cargo" +args = [ + "test", + "--lib", + "--features", + "astroport" +] + +# Run integration tests +[tasks.integration-test] +env = { TEST_RUNNER = "osmosis-test-app" } +cwd = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}" +dependencies = ["wasm"] +toolchain = "${RUST_VERSION}" +command = "cargo" +args = [ + "test", + "--features", + "osmosis-test-tube,osmosis,astroport", + "--test", + "*", +] + +# Create HTML coverage report +[tasks.coverage-html] +alias = "coverage-grcov-html" + +# Create LCOV coverage report +[tasks.coverage-lcov] +alias = "coverage-grcov-lcov" + +# Run automatically on "cargo make". This is the default task. +[tasks.default] +alias = "custom-default" + +# Custom tasks to run on "cargo make" +[tasks.custom-default] +dependencies = ["format", "clippy-fix", "deny", "machete-fix", "unit-test", "integration-test"] + # Docs and Test coverage are not run by default. Can run all with "cargo make all". [tasks.all] -dependencies = ["dev-test-flow", "custom-default", "cov"] +dependencies = ["custom-default", "coverage-html"] diff --git a/NOTICE b/NOTICE index df0c69c..ca13779 100644 --- a/NOTICE +++ b/NOTICE @@ -1,4 +1,4 @@ -Copyright 2022 Sturdy +Copyright 2022 Apollo Digital Holdings Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cliff.toml b/cliff.toml deleted file mode 100644 index ec1a999..0000000 --- a/cliff.toml +++ /dev/null @@ -1,54 +0,0 @@ -# configuration file for git-cliff (0.1.0) - -[changelog] -# changelog header -header = """ -# Changelog - -All notable changes to this project will be documented in this file.\n -""" -# template for the changelog body -# https://tera.netlify.app/docs/#introduction -body = """ -{% if version %}\ - ## [{{ version | replace(from="v", to="") }}] - {{ timestamp | date(format="%Y-%m-%d") }} -{% else %}\ - ## [unreleased] -{% endif %}\ -{% for group, commits in commits | group_by(attribute="group") %} - ### {{ group | upper_first }} - {% for commit in commits %} - - {{ commit.message | upper_first }}\ - {% endfor %} -{% endfor %}\n -""" -# remove the leading and trailing whitespaces from the template -trim = true -# changelog footer -footer = """""" - -[git] -# allow only conventional commits -# https://www.conventionalcommits.org -conventional_commits = true -# regex for parsing and grouping commits -commit_parsers = [ - { message = "^feat*", group = "Features" }, - { message = "^fix*", group = "Bug Fixes" }, - { message = "^doc*", group = "Documentation" }, - { message = "^perf*", group = "Performance" }, - { message = "^refactor*", group = "Refactor" }, - { message = "^style*", group = "Styling" }, - { message = "^test*", group = "Testing" }, - { message = "^chore\\(release\\): prepare for*", skip = true }, - { message = "^chore*", group = "Miscellaneous Tasks" }, - { message = "^ci*", group = "Continuous Integration/Deployment" }, - { message = "^build*", group = "Building, Automation and Tooling" }, - { body = ".*security", group = "Security" }, -] -# filter out the commits that are not matched by commit parsers -filter_commits = false -# glob pattern for matching git tags -tag_pattern = "v[0-9]*" -# regex for skipping tags -skip_tags = "v0.1.0-beta.1" \ No newline at end of file diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..1590630 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +too-many-arguments-threshold = 10 diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..050ed21 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,14 @@ +comment: + behavior: default + require_changes: true # [true :: only post the comment if coverage changes] + require_base: false # [true :: must have a base report to post] + require_head: true # [true :: must have a head report to post] + +coverage: + status: + project: + default: + threshold: 95% # TODO: Update this before first release + patch: + default: + threshold: 90% diff --git a/coverage_grcov.Makefile.toml b/coverage_grcov.Makefile.toml new file mode 100644 index 0000000..68cf6b7 --- /dev/null +++ b/coverage_grcov.Makefile.toml @@ -0,0 +1,53 @@ +# https://crates.io/crates/grcov + +[env] +COVERAGE_TARGET_DIRECTORY = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/coverage" +COVERAGE_BINARIES = "${COVERAGE_TARGET_DIRECTORY}/debug/deps" +COVERAGE_PROF_OUTPUT = "${COVERAGE_TARGET_DIRECTORY}/profraw" + +[tasks.coverage-grcov-prepare-outdir] +private = true +script=''' +#!/usr/bin/env bash +set -eux + +rm -rf ${COVERAGE_PROF_OUTPUT} +mkdir -p ${COVERAGE_PROF_OUTPUT} +''' + +[tasks.coverage-grcov-run-test] +condition = { rust_version = { min = "1.60.0" } } +private = true +run_task = "test" + +[tasks.coverage-grcov-run-test.env] +CARGO_BUILD_TARGET_DIR = "${COVERAGE_TARGET_DIRECTORY}" +RUSTFLAGS = "-Cinstrument-coverage" +LLVM_PROFILE_FILE = "${COVERAGE_PROF_OUTPUT}/coverage-%p-%m.profraw" + +[tasks.install-grcov] +condition = { env_not_set = ["SKIP_INSTALL_GRCOV"] } +private = true +command = "cargo" +args = ["install", "grcov", "--locked"] + +[tasks.coverage-grcov] +condition = { rust_version = { min = "1.60.0" } } +private = true +script = ''' +#!/usr/bin/env bash +set -eux + +grcov ${COVERAGE_PROF_OUTPUT} \ + -b ${COVERAGE_BINARIES} -s ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY} \ + -t ${GRCOV_OUTPUT_TYPE} --llvm --branch --ignore-not-existing --ignore "/*" --ignore "*/tests/*" --ignore "*/testing/*" --ignore "target/*" --ignore "contracts/swapper/mock/*" --ignore "contracts/swapper/osmosis/*" -o ${GRCOV_OUTPUT_PATH} +''' +dependencies = ["install-grcov", "coverage-grcov-prepare-outdir", "coverage-grcov-run-test"] + +[tasks.coverage-grcov-html] +env = { GRCOV_OUTPUT_TYPE = "html", GRCOV_OUTPUT_PATH = "${COVERAGE_TARGET_DIRECTORY}/html", TEST_RUNNER = "multi-test" } +run_task = "coverage-grcov" + +[tasks.coverage-grcov-lcov] +env = { GRCOV_OUTPUT_TYPE = "lcov", GRCOV_OUTPUT_PATH = "${COVERAGE_TARGET_DIRECTORY}/lcov.info", TEST_RUNNER = "multi-test" } +run_task = "coverage-grcov" diff --git a/deny.toml b/deny.toml index bbc9c7e..3290f10 100644 --- a/deny.toml +++ b/deny.toml @@ -16,6 +16,9 @@ ignore = [ # other crates. See # https://github.com/chronotope/chrono/issues/602#issuecomment-1075915577 "RUSTSEC-2020-0071", # Alias: RUSTSEC-2020-26235 + # Only in dev deps + "RUSTSEC-2022-0093", + "RUSTSEC-2023-0052" ] [bans] @@ -38,7 +41,11 @@ copyleft = "deny" # We want really high confidence when inferring licenses from text confidence-threshold = 0.93 allow = ["Apache-2.0", "MIT", "BSD-3-Clause", "MPL-2.0", "ISC"] -exceptions = [{ allow = ["Unicode-DFS-2016"], name = "unicode-ident" }] +exceptions = [ + { allow = ["Unicode-DFS-2016"], name = "unicode-ident" }, + { allow = ["BUSL-1.1"], name = "locked-astroport-vault" }, + { allow = ["BUSL-1.1"], name = "locked-astroport-vault-test-helpers" } +] [[licenses.clarify]] name = "webpki" diff --git a/src/contract.rs b/src/contract.rs index 1f0a062..6104eed 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -9,15 +9,21 @@ use cw_vault_standard::extensions::lockup::{ UNLOCKING_POSITION_ATTR_KEY, UNLOCKING_POSITION_CREATED_EVENT_TYPE, }; -use crate::deposit::{callback_deposit, callback_provide_liquidity, execute_deposit}; +use crate::deposit::{ + callback_deposit, callback_enforce_min_out, callback_provide_liquidity, execute_deposit, +}; use crate::error::ContractError; use crate::lockup::execute_unlock; use crate::msg::{CallbackMsg, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; use crate::query::{ - query_depositable_assets, query_user_unlocking_positions, query_withdrawable_assets, + query_all_user_unlocking_positions, query_depositable_assets, query_receive_choices, + query_user_unlocking_positions_for_vault, +}; +use crate::state::{LIQUIDITY_HELPER, LOCKUP_IDS, ROUTER, TEMP_LOCK_KEY}; +use crate::withdraw::{ + callback_after_redeem, callback_after_withdraw_liq, execute_redeem, execute_withdraw_unlocked, + execute_zap_base_tokens, }; -use crate::state::{LOCKUP_IDS, ROUTER, TEMP_UNLOCK_CALLER}; -use crate::withdraw::{execute_withdraw, execute_withdraw_unlocked}; // version info for migration info const CONTRACT_NAME: &str = "crates.io:vault-zapper"; @@ -33,6 +39,7 @@ pub fn instantiate( set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; ROUTER.save(deps.storage, &msg.router.check(deps.api)?)?; + LIQUIDITY_HELPER.save(deps.storage, &msg.liquidity_helper.check(deps.api)?)?; Ok(Response::default()) } @@ -50,7 +57,7 @@ pub fn execute( assets, vault_address, recipient, - slippage_tolerance, + min_out, } => { let assets = assets.check(deps.api)?; execute_deposit( @@ -60,21 +67,44 @@ pub fn execute( assets, api.addr_validate(&vault_address)?, recipient, - slippage_tolerance, + min_out, ) } - ExecuteMsg::Withdraw { + ExecuteMsg::Redeem { vault_address, recipient, - zap_to: withdraw_assets, - } => execute_withdraw( - deps, - env, - info, - api.addr_validate(&vault_address)?, + receive_choice, + min_out, + } => { + let min_out = min_out.check(deps.api)?; + execute_redeem( + deps, + env, + info, + api.addr_validate(&vault_address)?, + recipient, + receive_choice, + min_out, + ) + } + ExecuteMsg::ZapBaseTokens { + base_token, recipient, - withdraw_assets, - ), + receive_choice, + min_out, + } => { + let base_token = base_token.check(deps.api)?; + let min_out = min_out.check(deps.api)?; + execute_zap_base_tokens( + deps, + env, + info, + base_token, + recipient, + receive_choice, + min_out, + ) + } ExecuteMsg::Unlock { vault_address } => { execute_unlock(deps, env, info, api.addr_validate(&vault_address)?) } @@ -82,48 +112,80 @@ pub fn execute( vault_address, lockup_id, recipient, - zap_to: withdraw_assets, - } => execute_withdraw_unlocked( - deps, - env, - info, - api.addr_validate(&vault_address)?, - lockup_id, - recipient, - withdraw_assets, - ), - ExecuteMsg::Callback(msg) => match msg { - CallbackMsg::ProvideLiquidity { - vault_address, - recipient, - pool, - coin_balances, - slippage_tolerance, - } => callback_provide_liquidity( - deps, - env, - info, - vault_address, - recipient, - pool, - coin_balances, - slippage_tolerance, - ), - CallbackMsg::Deposit { - vault_address, - recipient, - coin_balances, - deposit_asset_info, - } => callback_deposit( + receive_choice, + min_out, + } => { + let min_out = min_out.check(deps.api)?; + execute_withdraw_unlocked( deps, env, info, - vault_address, + api.addr_validate(&vault_address)?, + lockup_id, recipient, - coin_balances, - deposit_asset_info, - ), - }, + receive_choice, + min_out, + ) + } + ExecuteMsg::Callback(msg) => { + // Can only be called by self + if info.sender != env.contract.address { + return Err(ContractError::Unauthorized {}); + } + + match msg { + CallbackMsg::ProvideLiquidity { + vault_address, + recipient, + pool, + deposit_asset_info, + } => callback_provide_liquidity( + deps, + env, + info, + vault_address, + recipient, + pool, + deposit_asset_info, + ), + CallbackMsg::Deposit { + vault_address, + recipient, + deposit_asset_info, + } => callback_deposit( + deps, + env, + info, + vault_address, + recipient, + deposit_asset_info, + ), + CallbackMsg::EnforceMinOut { + assets, + recipient, + balances_before, + min_out, + } => callback_enforce_min_out(deps, assets, recipient, balances_before, min_out), + CallbackMsg::AfterRedeem { + receive_choice, + vault_base_token, + recipient, + min_out, + } => callback_after_redeem( + deps, + env, + receive_choice, + vault_base_token, + recipient, + min_out, + ), + CallbackMsg::AfterWithdrawLiq { + assets, + receive_choice, + recipient, + } => callback_after_withdraw_liq(deps, env, assets, receive_choice, recipient), + } + } } } @@ -134,23 +196,40 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { deps, deps.api.addr_validate(&vault_address)?, )?), - QueryMsg::WithdrawableAssets { vault_address } => to_binary(&query_withdrawable_assets( + QueryMsg::ReceiveChoices { vault_address } => to_binary(&query_receive_choices( deps, deps.api.addr_validate(&vault_address)?, )?), - QueryMsg::UnlockingPositions { + QueryMsg::UserUnlockingPositionsForVault { vault_address, owner, - } => to_binary(&query_user_unlocking_positions( + start_after_id, + limit, + } => to_binary(&query_user_unlocking_positions_for_vault( deps, env, deps.api.addr_validate(&vault_address)?, + start_after_id, + limit, + deps.api.addr_validate(&owner)?, + )?), + QueryMsg::UserUnlockingPositions { + owner, + start_after_vault_addr, + start_after_id, + limit, + } => to_binary(&query_all_user_unlocking_positions( + deps, + env, deps.api.addr_validate(&owner)?, + start_after_vault_addr, + start_after_id, + limit, )?), } } -pub const UNLOCK_REPLY_ID: u64 = 0u64; +pub const UNLOCK_REPLY_ID: u64 = 143u64; #[cfg_attr(not(feature = "library"), entry_point)] pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result { @@ -167,21 +246,14 @@ pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result, - slippage_tolerance: Option, + min_out: Uint128, ) -> Result { // Unwrap recipient or use sender let recipient = recipient.map_or(Ok(info.sender.clone()), |x| deps.api.addr_validate(&x))?; - let router = ROUTER.load(deps.storage)?; + let receive_assets_res = receive_assets(&info, &env, &assets)?; - let receive_assets_res = receive_assets(&info, &env, &caller_funds)?; + // Query the vault info to get the deposit asset + let vault: VaultContract = VaultContract::new(&deps.querier, &vault_address)?; + let deposit_asset_info = match deps.api.addr_validate(&vault.base_token) { + Ok(addr) => AssetInfo::cw20(addr), + Err(_) => AssetInfo::native(&vault.base_token), + }; - // Query the vault info - let vault_info: VaultInfoResponse = deps.querier.query_wasm_smart( - vault_address.to_string(), - &VaultStandardQueryMsg::::Info {}, - )?; + // Add a message to enforce the minimum amount of vault tokens received + let vault_token = AssetInfo::native(&vault.vault_token); + let balance_before = vault_token.query_balance(&deps.querier, recipient.clone())?; + let enforce_min_out_msg = CallbackMsg::EnforceMinOut { + assets: vec![vault_token.clone()], + recipient: recipient.clone(), + balances_before: vec![Asset::new(vault_token.clone(), balance_before)].into(), + min_out: vec![Asset::new(vault_token.clone(), min_out)].into(), + } + .into_cosmos_msg(&env)?; - let deposit_asset_info = AssetInfo::Native(vault_info.base_token); + let event = Event::new("apollo/vault-zapper/execute_deposit") + .add_attribute("assets", to_binary(&assets)?.to_string()) + .add_attribute("vault_address", &vault_address) + .add_attribute("recipient", &recipient) + .add_attribute("min_out", min_out); // Check if coins sent are already same as the depositable assets // If yes, then just deposit the coins - if caller_funds.len() == 1 && caller_funds.to_vec()[0].info == deposit_asset_info { - let deposit_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: vault_address.to_string(), - funds: caller_funds - .into_iter() - .filter_map(|a| a.try_into().ok()) - .collect(), - msg: to_binary(&VaultStandardExecuteMsg::::Deposit { - amount: caller_funds.to_vec()[0].amount, - recipient: Some(recipient.to_string()), - })?, - }); - return Ok(Response::new().add_message(deposit_msg)); + if assets.len() == 1 && assets.to_vec()[0].info == deposit_asset_info { + let amount = assets.to_vec()[0].amount; + let msgs = vault.increase_allowance_and_deposit( + amount, + &deposit_asset_info, + Some(recipient.to_string()), + )?; + + return Ok(receive_assets_res + .add_messages(msgs) + .add_message(enforce_min_out_msg) + .add_event(event)); } //Check if the depositable asset is an LP token let pool = Pool::get_pool_for_lp_token(deps.as_ref(), &deposit_asset_info).ok(); - //Set the target of the basket liquidation, depending on if depositable asset + // Set the target of the basket liquidation, depending on if depositable asset // is an LP token or not let receive_asset_infos = match &pool { Some(pool) => { @@ -77,13 +86,9 @@ pub fn execute_deposit( } }; - // Get the amount of tokens sent by the caller and how much was already in the - // contract. - let token_balances = TokenBalances::new(deps.as_ref(), &env, &caller_funds)?; - // Basket Liquidate deposited coins // We only liquidate the coins that are not already the target asset - let liquidate_coins = caller_funds + let liquidate_coins = assets .into_iter() .filter_map(|a| { if !receive_asset_infos.contains(&a.info) { @@ -95,6 +100,7 @@ pub fn execute_deposit( .collect::>(); let receive_asset_info = receive_asset_infos[0].clone(); let mut msgs = if !liquidate_coins.is_empty() { + let router = ROUTER.load(deps.storage)?; router.basket_liquidate_msgs(liquidate_coins.into(), &receive_asset_info, None, None)? } else { vec![] @@ -108,8 +114,7 @@ pub fn execute_deposit( vault_address, recipient, pool, - coin_balances: token_balances, - slippage_tolerance, + deposit_asset_info, } .into_cosmos_msg(&env)?, ) @@ -120,86 +125,60 @@ pub fn execute_deposit( CallbackMsg::Deposit { vault_address, recipient, - coin_balances: token_balances, deposit_asset_info, } .into_cosmos_msg(&env)?, ); } - Ok(receive_assets_res.add_messages(msgs)) + Ok(receive_assets_res + .add_messages(msgs) + .add_message(enforce_min_out_msg) + .add_event(event)) } -#[allow(clippy::too_many_arguments)] pub fn callback_provide_liquidity( deps: DepsMut, env: Env, - info: MessageInfo, + _info: MessageInfo, vault_address: Addr, recipient: Addr, pool: Pool, - mut coin_balances: TokenBalances, - slippage_tolerance: Option, + deposit_asset_info: AssetInfo, ) -> Result { - // Can only be called by self - if info.sender != env.contract.address { - return Err(ContractError::Unauthorized {}); - } + let pool_asset_balances = AssetList::query_asset_info_balances( + pool.pool_assets(deps.as_ref())?, + &deps.querier, + &env.contract.address, + )?; - // Update coin balances - coin_balances.update_balances(deps.as_ref(), &env)?; + let liquidity_helper = LIQUIDITY_HELPER.load(deps.storage)?; - // Provide liquidity with all assets returned from the basket liquidation - // and any that the caller sent with the original message. - let provide_liquidity_assets: AssetList = pool - .get_pool_liquidity(deps.as_ref())? - .into_iter() - .filter_map(|a| { - let balance = coin_balances.get_caller_balance(&a.info); - if balance > Uint128::zero() { - Some(Asset::new(a.info.clone(), balance)) - } else { - None - } - }) - .collect::>() - .into(); - - // Simulate providing liquidity - let lp_tokens_received = - pool.simulate_provide_liquidity(deps.as_ref(), &env, provide_liquidity_assets.clone())?; - - // Provide liquidity to the pool - let mut response = pool.provide_liquidity( - deps.as_ref(), - &env, - provide_liquidity_assets, - if let Some(slippage_tolerance) = slippage_tolerance { - lp_tokens_received.amount * (Decimal::one() - slippage_tolerance) - } else { - lp_tokens_received.amount - }, + let pool: Binary = match pool { + #[cfg(feature = "astroport")] + Pool::Astroport(pool) => to_binary(&pool)?, + #[cfg(feature = "osmosis")] + Pool::Osmosis(pool) => to_binary(&pool)?, + _ => panic!("Unsupported pool type"), + }; + + let provide_liquidity_msgs = liquidity_helper.balancing_provide_liquidity( + pool_asset_balances, + Uint128::zero(), + pool, + None, )?; - // Deposit any LP tokens the caller sent with the original message plus those - // received from this liquidity provision. - let amount_to_deposit = coin_balances - .get_caller_balance(&lp_tokens_received.info) - .checked_add(lp_tokens_received.amount)?; - - // Deposit the coins into the vault - let deposit_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: vault_address.to_string(), - funds: vec![Coin { - denom: lp_tokens_received.info.to_string(), - amount: amount_to_deposit, - }], - msg: to_binary(&VaultStandardExecuteMsg::::Deposit { - amount: amount_to_deposit, - recipient: Some(recipient.to_string()), - })?, - }); - response = response.add_message(deposit_msg); + let response = Response::new() + .add_messages(provide_liquidity_msgs) + .add_message( + CallbackMsg::Deposit { + vault_address, + recipient, + deposit_asset_info, + } + .into_cosmos_msg(&env)?, + ); Ok(response) } @@ -207,33 +186,54 @@ pub fn callback_provide_liquidity( pub fn callback_deposit( deps: DepsMut, env: Env, - info: MessageInfo, + _info: MessageInfo, vault_address: Addr, recipient: Addr, - mut coin_balances: TokenBalances, deposit_asset_info: AssetInfo, ) -> Result { - // Can only be called by self - if info.sender != env.contract.address { - return Err(ContractError::Unauthorized {}); + let amount_to_deposit = + deposit_asset_info.query_balance(&deps.querier, env.contract.address)?; + + let vault: VaultContract<_, _> = + VaultContract::::new(&deps.querier, &vault_address)?; + let msgs = vault.increase_allowance_and_deposit( + amount_to_deposit, + &deposit_asset_info, + Some(recipient.to_string()), + )?; + + Ok(Response::new().add_messages(msgs)) +} + +pub fn callback_enforce_min_out( + deps: DepsMut, + assets: Vec, + recipient: Addr, + balances_before: AssetList, + min_out: AssetList, +) -> Result { + let mut new_balances = + AssetList::query_asset_info_balances(assets.clone(), &deps.querier, &recipient)?; + let assets_received = new_balances.deduct_many(&balances_before)?; + + for asset in min_out.iter() { + let received = assets_received + .find(&asset.info) + .map(|x| x.amount) + .unwrap_or_default(); + if received < asset.amount { + return Err(ContractError::MinOutNotMet { + min_out: asset.amount, + actual: received, + }); + } } - // Update the coin balances - coin_balances.update_balances(deps.as_ref(), &env)?; - - // Deposit the coins into the vault - let caller_balance = coin_balances.get_caller_balance(&deposit_asset_info); - let deposit_msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: vault_address.to_string(), - funds: vec![Coin { - denom: deposit_asset_info.to_string(), - amount: caller_balance, - }], - msg: to_binary(&VaultStandardExecuteMsg::::Deposit { - amount: caller_balance, - recipient: Some(recipient.to_string()), - })?, - }); - - Ok(Response::new().add_message(deposit_msg)) + let event = Event::new("apollo/vault-zapper/callback_enforce_min_out") + .add_attribute("recipient", recipient) + .add_attribute("assets", to_binary(&assets)?.to_string()) + .add_attribute("min_out", to_binary(&min_out)?.to_string()) + .add_attribute("assets_received", to_binary(&assets_received)?.to_string()); + + Ok(Response::new().add_event(event)) } diff --git a/src/error.rs b/src/error.rs index f16442d..ecbc9a2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{OverflowError, StdError}; +use cosmwasm_std::{OverflowError, StdError, Uint128}; use cw_dex::CwDexError; use thiserror::Error; @@ -27,4 +27,10 @@ pub enum ContractError { #[error("Invalid vault token sent")] InvalidVaultToken {}, + + #[error("Minimum amount not met. Expected {min_out}, got {actual}")] + MinOutNotMet { min_out: Uint128, actual: Uint128 }, + + #[error("Invalid min_out argument")] + InvalidMinOut {}, } diff --git a/src/helpers.rs b/src/helpers.rs index cd16c7c..50aa20d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,153 +1,51 @@ -use cosmwasm_schema::cw_serde; - -use apollo_cw_asset::{Asset, AssetInfo, AssetList}; -use cosmwasm_std::{to_binary, Addr, CosmosMsg, Deps, Env, Response, StdResult, Uint128, WasmMsg}; - -use crate::msg::ExecuteMsg; - -/// CwTemplateContract is a wrapper around Addr that provides a lot of helpers -/// for working with this. -#[cw_serde] -pub struct CwTemplateContract(pub Addr); - -impl CwTemplateContract { - pub fn addr(&self) -> Addr { - self.0.clone() - } - - pub fn call>(&self, msg: T) -> StdResult { - let msg = to_binary(&msg.into())?; - Ok(WasmMsg::Execute { - contract_addr: self.addr().into(), - msg, - funds: vec![], - } - .into()) - } -} - -/// Merge several Response objects into one. Currently ignores the data fields. -pub(crate) fn merge_responses(responses: Vec) -> Response { - let mut merged = Response::default(); - for response in responses { - merged = merged - .add_attributes(response.attributes) - .add_events(response.events) - .add_messages( - response - .messages - .iter() - .map(|m| m.msg.clone()) - .collect::>(), - ); - } - merged -} - -/// Struct that helps keep track of how much of each coin belongs to the -/// contract and how much was sent by the caller. -#[cw_serde] -pub struct TokenBalances { - /// The coins that belong to this contract - pub contract_balances: AssetList, - /// The coins that were sent by the caller - pub caller_balances: AssetList, +use cosmwasm_schema::schemars::JsonSchema; +use cosmwasm_schema::serde::Serialize; + +use apollo_cw_asset::AssetInfo; +use cosmwasm_std::{to_binary, CosmosMsg, StdResult, Uint128, WasmMsg}; +use cw_vault_standard::VaultContract; + +/// A trait to help with depositing an `Asset` into a vault. +pub trait VaultHelper { + /// Returns a vector of CosmosMsgs that will increase the allowance of the + /// token if it is a CW20 and deposit the token into the vault. + fn increase_allowance_and_deposit( + &self, + amount: Uint128, + deposit_asset_info: &AssetInfo, + recipient: Option, + ) -> StdResult>; } -impl TokenBalances { - pub fn new(deps: Deps, env: &Env, caller_funds: &AssetList) -> StdResult { - let mut contract_balances = - Self::get_contract_balances_helper(deps, env, caller_funds)?.to_vec(); - - // Deduct the received funds from the current balances - for asset in caller_funds { - if let Some(c) = contract_balances.iter_mut().find(|c| c.info == asset.info) { - c.amount -= asset.amount; - }; - } - - Ok(Self { - contract_balances: contract_balances.into(), - caller_balances: caller_funds.clone(), - }) - } - - pub fn get_caller_balance(&self, asset: &AssetInfo) -> Uint128 { - self.caller_balances - .find(asset) - .map(|c| c.amount) - .unwrap_or_default() - } - - /// Update the struct to add any newly received funds to the - /// caller_balances. Should be called in a CallbackMsg handler. - pub fn update_balances(&mut self, deps: Deps, env: &Env) -> StdResult<()> { - let new_balances = Self::get_contract_balances_helper(deps, env, &self.contract_balances)?; - - // For every coin in new_balances: - // Calculate the difference between the new balance and the old balance. - // Add the difference to the caller_balance. - for asset in &new_balances { - let old_balance = self - .caller_balances - .find(&asset.info) - .map(|a| a.amount) - .unwrap_or_default(); - - let difference = asset.amount.checked_sub(old_balance)?; - if difference > Uint128::zero() { - let mut caller_balances = self.caller_balances.to_vec(); - if let Some(a) = caller_balances.iter_mut().find(|a| a.info == asset.info) { - a.amount += difference; - }; - self.caller_balances = caller_balances.into(); - } - } - - Ok(()) - } - - fn get_contract_balances_helper( - deps: Deps, - env: &Env, - assets_to_query: &AssetList, - ) -> StdResult { - // get all native token balances on contract - let mut contract_balances: AssetList = deps - .querier - .query_all_balances(env.contract.address.to_string())? - .into(); - let contract_assets: Vec = contract_balances - .into_iter() - .map(|c| c.info.to_owned()) - .collect(); - // if provided, query balances for assets not included in above queried balances - // should only be cw20s - if assets_to_query.len() > 0 { - let other_contract_balances = assets_to_query - .into_iter() - .filter_map(|a| { - if matches!(a.info, AssetInfo::Cw20(_)) && !contract_assets.contains(&a.info) { - let contract_balance: Uint128 = deps - .querier - .query_wasm_smart( - a.info.to_string(), - &cw20::Cw20QueryMsg::Balance { - address: env.contract.address.to_string(), - }, - ) - .unwrap_or_default(); - Some(Asset { - info: a.info.to_owned(), - amount: contract_balance, - }) - } else { - None - } - }) - .collect::>(); - contract_balances.add_many(&other_contract_balances.into())?; - } - Ok(contract_balances) +impl VaultHelper for VaultContract +where + E: Serialize, + Q: Serialize + JsonSchema, +{ + fn increase_allowance_and_deposit( + &self, + amount: Uint128, + deposit_asset_info: &AssetInfo, + recipient: Option, + ) -> StdResult> { + let mut msgs: Vec = vec![]; + + if deposit_asset_info.is_native() { + msgs.push(self.deposit(amount, recipient)?); + } else { + // If CW20, first increase allowance + msgs.push(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: deposit_asset_info.to_string(), + msg: to_binary(&cw20::Cw20ExecuteMsg::IncreaseAllowance { + spender: self.addr.to_string(), + amount, + expires: None, + })?, + funds: vec![], + })); + msgs.push(self.deposit_cw20(amount, recipient)?); + }; + + Ok(msgs) } } diff --git a/src/lockup.rs b/src/lockup.rs index cf65176..e313d02 100644 --- a/src/lockup.rs +++ b/src/lockup.rs @@ -9,7 +9,7 @@ use cw_vault_standard::{ }; use crate::contract::UNLOCK_REPLY_ID; -use crate::state::TEMP_UNLOCK_CALLER; +use crate::state::TEMP_LOCK_KEY; use crate::ContractError; pub fn execute_unlock( @@ -44,9 +44,9 @@ pub fn execute_unlock( )?, }); - // Temporarily store the caller's address so we can read it in the reply - // entrypoint - TEMP_UNLOCK_CALLER.save(deps.storage, &info.sender)?; + // Temporarily store the caller's address and the vault address so we can read + // it in the reply entrypoint + TEMP_LOCK_KEY.save(deps.storage, &(info.sender, vault_address))?; // We must add the unlock message as a submessage and parse the Lock ID in the // reply entrypoint. diff --git a/src/msg.rs b/src/msg.rs index f097279..14834c9 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -1,43 +1,82 @@ -use apollo_cw_asset::{AssetInfo, AssetListUnchecked}; +use apollo_cw_asset::{AssetInfo, AssetList, AssetListUnchecked, AssetUnchecked}; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{to_binary, Addr, CosmosMsg, Decimal, Env, StdResult, WasmMsg}; +use cosmwasm_std::{to_binary, Addr, CosmosMsg, Env, StdResult, Uint128, WasmMsg}; use cw_dex::Pool; use cw_dex_router::helpers::CwDexRouterUnchecked; - -use crate::helpers::TokenBalances; +use liquidity_helper::LiquidityHelperUnchecked; #[cw_serde] pub struct InstantiateMsg { pub router: CwDexRouterUnchecked, + pub liquidity_helper: LiquidityHelperUnchecked, } #[cw_serde] pub enum ExecuteMsg { + /// Deposit assets into a vault Deposit { + /// The assets to deposit assets: AssetListUnchecked, + /// The address of the vault to deposit into vault_address: String, + /// The recipient of the vault tokens recipient: Option, - slippage_tolerance: Option, + /// The minimum amount of vault tokens to receive. If the amount of + /// vault tokens received is less than this, the transaction will fail. + min_out: Uint128, }, - Withdraw { + /// Redeem vault tokens and optionally swap the redeemed assets to other + /// assets + Redeem { + /// The address of the vault to redeem from vault_address: String, + /// The recipient of the redeemed assets recipient: Option, - zap_to: ZapTo, + /// The choice of which asset(s) to receive + receive_choice: ReceiveChoice, + /// The minimum amount of assets to receive. If the amount of assets + /// received is less than this, the transaction will fail. + min_out: AssetListUnchecked, }, + /// Zap a vault's base token to other assets + ZapBaseTokens { + /// The base token to swap from + base_token: AssetUnchecked, + /// The recipient of the redeemed assets + recipient: Option, + /// The asset to swap to + receive_choice: ReceiveChoice, + /// The minimum amount of assets to receive. If the amount of assets + /// received is less than this, the transaction will fail. + min_out: AssetListUnchecked, + }, + /// Call unlock on the specified vault and burn the sent vault tokens to + /// create an unlocking position. The unlocking position can be withdrawn + /// from after the unlock period has passed by calling WithdrawUnlocked. Unlock { + /// The address of the vault to call unlock on vault_address: String, }, WithdrawUnlocked { + /// The address of the vault to withdraw from vault_address: String, + /// The ID of the unlocking position to withdraw from lockup_id: u64, + /// The recipient of the withdrawn assets recipient: Option, - zap_to: ZapTo, + /// The choice of which asset(s) to receive + receive_choice: ReceiveChoice, + /// The minimum amount of assets to receive. If the amount of assets + /// received is less than this, the transaction will fail. + min_out: AssetListUnchecked, }, + /// Messages that can only be called by the contract itself. Callback(CallbackMsg), } #[cw_serde] pub enum CallbackMsg { + /// Provide liquidity to a pool ProvideLiquidity { /// The vaults address vault_address: Addr, @@ -45,18 +84,42 @@ pub enum CallbackMsg { recipient: Addr, /// The pool to provide liquidity to pool: Pool, - /// The coin balances of the contract and the coins received by the - /// caller - coin_balances: TokenBalances, - /// An optional slippage tolerance to use when providing liquidity - slippage_tolerance: Option, + /// The asset info of the vault's deposit asset + deposit_asset_info: AssetInfo, }, + /// Performs the actual deposit into the vault Deposit { vault_address: Addr, recipient: Addr, - coin_balances: TokenBalances, deposit_asset_info: AssetInfo, }, + /// Enforce that the minimum amount of the specified assets are sent to the + /// recipient after the transaction + EnforceMinOut { + /// The assets to check the balance of + assets: Vec, + /// The address to check the balance of + recipient: Addr, + /// The recipient's balance of each of the assets before the transaction + balances_before: AssetList, + /// The minimum amount of each asset to receive. If the amount received + /// of any of the assets is less than this, the transaction will + /// fail. + min_out: AssetList, + }, + /// Called after redeeming vault tokens + AfterRedeem { + receive_choice: ReceiveChoice, + vault_base_token: AssetInfo, + recipient: Addr, + min_out: AssetList, + }, + /// Called after withdrawing liquidity from a pool + AfterWithdrawLiq { + assets: Vec, + receive_choice: ReceiveChoice, + recipient: Addr, + }, } impl CallbackMsg { @@ -77,18 +140,31 @@ pub enum QueryMsg { #[returns(Vec)] DepositableAssets { vault_address: String }, - /// Returns Vec. The user may chose one of the options in - /// this vec when calling Withdraw or WithdrawUnlocked. - #[returns(Vec)] - WithdrawableAssets { vault_address: String }, + /// Returns Vec. The user may chose one of the options in + /// this vec when calling Redeem or WithdrawUnlocked. + #[returns(Vec)] + ReceiveChoices { vault_address: String }, /// Returns Vec. The user may withdraw from these /// positions if they have finished unlocking by calling /// WithdrawUnlocked. #[returns(Vec)] - UnlockingPositions { + UserUnlockingPositionsForVault { + owner: String, vault_address: String, + start_after_id: Option, + limit: Option, + }, + + /// Returns Vec. The user may withdraw from + /// these positions if they have finished unlocking by calling + /// WithdrawUnlocked. + #[returns(std::collections::HashMap>)] + UserUnlockingPositions { owner: String, + start_after_vault_addr: Option, + start_after_id: Option, + limit: Option, }, } @@ -96,20 +172,15 @@ pub enum QueryMsg { pub struct MigrateMsg {} #[cw_serde] -pub enum ZapTo { - /// Zap to asset - Asset(AssetInfo), - /// Zap to underlying LP assets - Underlying {}, -} - -#[test] -pub fn test_withdrawable_asset() { - //Example response for ATOM-OSMO pool - let _example_response: Vec = vec![ - ZapTo::Asset(AssetInfo::Native("osmo".to_string())), - ZapTo::Asset(AssetInfo::Native("usdc".to_string())), - ZapTo::Asset(AssetInfo::Native("atom".to_string())), - ZapTo::Underlying {}, - ]; +/// An enum to represent the different ways to receive assets when redeeming +/// vault tokens +pub enum ReceiveChoice { + /// Just receive the base token of the vault + BaseToken, + /// If the base token wraps other assets, unwrap them and receive those. + /// E.g. if the base_token is an LP token, withdraw liquidity and + /// receive the underlying assets. + Underlying, + /// Swap the base token to the specified asset + SwapTo(AssetInfo), } diff --git a/src/query.rs b/src/query.rs index 95f9a9a..12c05f5 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,23 +1,26 @@ +use std::collections::HashMap; + use apollo_cw_asset::AssetInfo; -use cosmwasm_std::{Addr, Deps, Env, StdError, StdResult}; +use cosmwasm_std::{Addr, Deps, Empty, Env, Order, StdError, StdResult}; use cw_dex::traits::Pool as PoolTrait; use cw_dex::Pool; +use cw_storage_plus::Bound; -use crate::state::{LOCKUP_IDS, ROUTER}; +use crate::msg::ReceiveChoice; +use crate::state::{self, DEFAULT_LIMIT, LOCKUP_IDS, ROUTER}; use cw_vault_standard::extensions::lockup::{LockupQueryMsg, UnlockingPosition}; -use cw_vault_standard::{ExtensionQueryMsg, VaultInfoResponse, VaultStandardQueryMsg}; +use cw_vault_standard::{ExtensionQueryMsg, VaultContract, VaultStandardQueryMsg}; pub fn query_depositable_assets(deps: Deps, vault_address: Addr) -> StdResult> { let router = ROUTER.load(deps.storage)?; // Query the vault info - let vault_info: VaultInfoResponse = deps.querier.query_wasm_smart( - vault_address.to_string(), - &VaultStandardQueryMsg::::Info {}, - )?; - - let deposit_asset_info = AssetInfo::Native(vault_info.base_token); + let vault: VaultContract = VaultContract::new(&deps.querier, &vault_address)?; + let deposit_asset_info = match deps.api.addr_validate(&vault.base_token) { + Ok(addr) => AssetInfo::cw20(addr), + Err(_) => AssetInfo::native(&vault.base_token), + }; // Check if deposit asset is an LP token let pool = Pool::get_pool_for_lp_token(deps, &deposit_asset_info).ok(); @@ -47,36 +50,29 @@ pub fn query_depositable_assets(deps: Deps, vault_address: Addr) -> StdResult StdResult> { +pub fn query_receive_choices(deps: Deps, vault_address: Addr) -> StdResult> { let router = ROUTER.load(deps.storage)?; // Query the vault info - let vault_info: VaultInfoResponse = deps.querier.query_wasm_smart( - vault_address.to_string(), - &VaultStandardQueryMsg::::Info {}, - )?; - - let withdraw_asset_info = AssetInfo::Native(vault_info.base_token); + let vault: VaultContract = VaultContract::new(&deps.querier, &vault_address)?; + let withdraw_asset_info = match deps.api.addr_validate(&vault.base_token) { + Ok(addr) => AssetInfo::cw20(addr), + Err(_) => AssetInfo::native(&vault.base_token), + }; // Check if the withdrawn asset is an LP token let pool = Pool::get_pool_for_lp_token(deps, &withdraw_asset_info).ok(); - // Create withdrawable assets vec with first one being the withdraw asset - let mut withdrawable_assets = vec![withdraw_asset_info.clone()]; - - let supported_ask_assets: Vec = match pool { + let swap_to_choices: Vec = match pool { Some(pool) => { // Get the assets in the pool let pool_tokens: Vec = pool @@ -101,9 +97,7 @@ pub fn query_withdrawable_assets(deps: Deps, vault_address: Addr) -> StdResult { @@ -112,38 +106,91 @@ pub fn query_withdrawable_assets(deps: Deps, vault_address: Addr) -> StdResult>(); + + let receive_choices = [ + swap_to_choices.as_slice(), + &[ReceiveChoice::BaseToken, ReceiveChoice::Underlying], + ] + .concat(); - Ok(withdrawable_assets) + Ok(receive_choices) } -pub fn query_user_unlocking_positions( +pub fn query_user_unlocking_positions_for_vault( deps: Deps, env: Env, vault_address: Addr, + start_after_id: Option, + limit: Option, user: Addr, ) -> StdResult> { - let mut user_lockup_ids = LOCKUP_IDS.load(deps.storage, user).unwrap_or_default(); - user_lockup_ids.sort(); - let mut unlocking_positions: Vec = deps.querier.query_wasm_smart( - vault_address, - &VaultStandardQueryMsg::::VaultExtension(ExtensionQueryMsg::Lockup( - LockupQueryMsg::UnlockingPositions { - owner: env.contract.address.to_string(), - start_after: if !user_lockup_ids.is_empty() && user_lockup_ids[0] > 0 { - Some(user_lockup_ids[0] - 1) - } else { - None - }, - limit: None, - }, - )), - )?; - unlocking_positions.retain(|p| user_lockup_ids.contains(&p.id)); + let limit = limit.unwrap_or(DEFAULT_LIMIT) as usize; + let start: Option> = start_after_id.map(Bound::exclusive); + + let user_lockup_ids = LOCKUP_IDS + .prefix((user, vault_address.clone())) + .range(deps.storage, start, None, Order::Ascending) + .take(limit); + + let mut unlocking_positions: Vec = vec![]; + + for res in user_lockup_ids { + let (lockup_id, _) = res?; + + let unlocking_position = deps.querier.query_wasm_smart::( + &vault_address, + &VaultStandardQueryMsg::::VaultExtension(ExtensionQueryMsg::Lockup( + LockupQueryMsg::UnlockingPosition { lockup_id }, + )), + )?; + + if unlocking_position.owner == env.contract.address { + unlocking_positions.push(unlocking_position); + } + } Ok(unlocking_positions) } + +pub fn query_all_user_unlocking_positions( + deps: Deps, + env: Env, + user: Addr, + start_after_vault_addr: Option, + start_after_id: Option, + limit: Option, +) -> StdResult>> { + let user_lockup_ids = state::paginate_all_user_unlocking_positions( + deps, + user, + start_after_vault_addr, + start_after_id, + limit, + )?; + + let mut unlocking_positions_per_vault: HashMap> = HashMap::new(); + + for item in user_lockup_ids { + let ((vault_address, lockup_id), _) = item?; + + let unlocking_position = deps.querier.query_wasm_smart::( + &vault_address, + &VaultStandardQueryMsg::::VaultExtension(ExtensionQueryMsg::Lockup( + LockupQueryMsg::UnlockingPosition { lockup_id }, + )), + )?; + + if unlocking_position.owner == env.contract.address { + if let Some(positions) = unlocking_positions_per_vault.get_mut(&vault_address) { + positions.push(unlocking_position); + } else { + unlocking_positions_per_vault.insert(vault_address, vec![unlocking_position]); + } + } + } + + Ok(unlocking_positions_per_vault) +} diff --git a/src/state.rs b/src/state.rs index 0e4cc0c..2b2d37b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,18 +1,312 @@ -use apollo_cw_asset::Asset; -use cosmwasm_std::{Addr, WasmMsg}; +use std::iter::Take; + +use cosmwasm_std::{Addr, Deps, Order, StdError, StdResult}; use cw_dex_router::helpers::CwDexRouter; -use cw_storage_plus::{Item, Map}; +use cw_storage_plus::{Bound, Item, Map}; +use liquidity_helper::LiquidityHelper; pub const ROUTER: Item = Item::new("router"); +pub const LIQUIDITY_HELPER: Item = Item::new("liquidity_helper"); + +/// Stores the lockup ids for unlocking positions. The key is a tuple of +/// (owner_address, vault_address, lockup_id). +pub const LOCKUP_IDS: Map<(Addr, Addr, u64), ()> = Map::new("lockup_ids"); + +pub const TEMP_LOCK_KEY: Item<(Addr, Addr)> = Item::new("temp_lock_key"); + +/// The default limit when paginating and no limit is specified +pub const DEFAULT_LIMIT: u32 = 10; + +pub type LockupIdIterator<'a> = + Take> + 'a>>; + +pub fn paginate_all_user_unlocking_positions( + deps: Deps, + user: Addr, + start_after_vault_addr: Option, + start_after_id: Option, + limit: Option, +) -> StdResult { + let limit = limit.unwrap_or(DEFAULT_LIMIT) as usize; + + let start = match (start_after_vault_addr, start_after_id) { + (Some(vault_addr), Some(id)) => { + Some(Bound::exclusive((deps.api.addr_validate(&vault_addr)?, id))) + } + (Some(vault_addr), None) => Some(Bound::exclusive(( + deps.api.addr_validate(&vault_addr)?, + u64::MAX, + ))), + (None, Some(_)) => { + return Err(StdError::generic_err( + "Need to supply start_after_vault_addr if start_after_id is supplied", + )) + } + (None, None) => None, + }; + + let user_lockup_ids = LOCKUP_IDS + .sub_prefix(user) + .range(deps.storage, start, None, Order::Ascending) + .take(limit); + + Ok(user_lockup_ids) +} + +#[cfg(test)] +mod tests { + use super::*; + + use cosmwasm_std::testing::mock_dependencies; + use cosmwasm_std::Storage; + + fn store_lock_id(storage: &mut dyn Storage, user: Addr, vault_address: Addr, lock_id: u64) { + LOCKUP_IDS + .save(storage, (user, vault_address, lock_id), &()) + .unwrap(); + } + + #[test] + fn test_paginate_all_user_unlocking_positions() { + let mut deps = mock_dependencies(); + let storage = deps.as_mut().storage; + + // Store some lockup ids + store_lock_id( + storage, + Addr::unchecked("addr0001"), + Addr::unchecked("vault0001"), + 0, + ); + + store_lock_id( + storage, + Addr::unchecked("addr0001"), + Addr::unchecked("vault0001"), + 1, + ); + store_lock_id( + storage, + Addr::unchecked("addr0001"), + Addr::unchecked("vault0001"), + 2, + ); + store_lock_id( + storage, + Addr::unchecked("addr0002"), + Addr::unchecked("vault0001"), + 3, + ); + store_lock_id( + storage, + Addr::unchecked("addr0002"), + Addr::unchecked("vault0001"), + 4, + ); + store_lock_id( + storage, + Addr::unchecked("addr0001"), + Addr::unchecked("vault0002"), + 0, + ); + store_lock_id( + storage, + Addr::unchecked("addr0001"), + Addr::unchecked("vault0002"), + 1, + ); + store_lock_id( + storage, + Addr::unchecked("addr0002"), + Addr::unchecked("vault0002"), + 2, + ); + store_lock_id( + storage, + Addr::unchecked("addr0002"), + Addr::unchecked("vault0002"), + 3, + ); + + // Query all unlocking positions for addr0001 + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0001"), + None, + None, + None, + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 5); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0001"), 0), + (Addr::unchecked("vault0001"), 1), + (Addr::unchecked("vault0001"), 2), + (Addr::unchecked("vault0002"), 0), + (Addr::unchecked("vault0002"), 1), + ] + ); + + // Query all unlocking positions for addr0001 with limit + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0001"), + None, + None, + Some(2), + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 2); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0001"), 0), + (Addr::unchecked("vault0001"), 1), + ] + ); + + // Query all unlocking positions for addr0001 with start_after_vault_addr + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0001"), + Some("vault0001".to_string()), + None, + None, + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 2); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0002"), 0), + (Addr::unchecked("vault0002"), 1), + ] + ); + + // Query all unlocking positions for addr0001 with start_after_vault_addr and + // start_after_id + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0001"), + Some("vault0001".to_string()), + Some(0), + None, + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 4); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0001"), 1), + (Addr::unchecked("vault0001"), 2), + (Addr::unchecked("vault0002"), 0), + (Addr::unchecked("vault0002"), 1), + ] + ); + + // Query all unlocking positions for addr0001 with only start_after_id + let res = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0001"), + None, + Some(1), + None, + ) + .is_err(); + assert!(res); + + // Query all unlocking positions for addr0002 + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0002"), + None, + None, + None, + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 4); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0001"), 3), + (Addr::unchecked("vault0001"), 4), + (Addr::unchecked("vault0002"), 2), + (Addr::unchecked("vault0002"), 3), + ] + ); -pub const LOCKUP_IDS: Map> = Map::new("lockup_ids"); + // Query all unlocking positions for addr0002 with limit + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0002"), + None, + None, + Some(2), + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 2); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0001"), 3), + (Addr::unchecked("vault0001"), 4), + ] + ); -// I'm not aware of any way to send data to our own reply entrypoint, so we must -// save the caller of ExecuteMsg::Unlock here to be able to fetch it in the -// reply entrypoint... -pub const TEMP_UNLOCK_CALLER: Item = Item::new("temp_unlock_caller"); + // Query all unlocking positions for addr0002 with start_after_vault_addr + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0002"), + Some("vault0001".to_string()), + None, + Some(2), + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 2); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0002"), 2), + (Addr::unchecked("vault0002"), 3), + ] + ); -pub struct WithdrawMsg { - pub msg: WasmMsg, - pub redeem_asset: Asset, + // Query all unlocking positions for addr0002 with start_after_vault_addr and + // start_after_id + let res: Vec<(Addr, u64)> = paginate_all_user_unlocking_positions( + deps.as_ref(), + Addr::unchecked("addr0002"), + Some("vault0001".to_string()), + Some(3), + None, + ) + .unwrap() + .map(|x| x.unwrap().0) + .collect(); + assert_eq!(res.len(), 3); + assert_eq!( + res, + vec![ + (Addr::unchecked("vault0001"), 4), + (Addr::unchecked("vault0002"), 2), + (Addr::unchecked("vault0002"), 3), + ] + ); + } } diff --git a/src/withdraw.rs b/src/withdraw.rs index 5186068..9104ebf 100644 --- a/src/withdraw.rs +++ b/src/withdraw.rs @@ -1,71 +1,43 @@ use apollo_cw_asset::{Asset, AssetInfo, AssetList}; +use apollo_utils::assets::receive_assets; +use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - wasm_execute, Addr, DepsMut, Env, MessageInfo, Response, StdError, StdResult, Uint128, + to_binary, Addr, CosmosMsg, DepsMut, Empty, Env, Event, MessageInfo, Response, Uint128, WasmMsg, }; use cw_dex::traits::Pool as PoolTrait; use cw_dex::Pool; -use cw_vault_standard::extensions::lockup::{LockupExecuteMsg, LockupQueryMsg, UnlockingPosition}; -use cw_vault_standard::{ - ExtensionExecuteMsg, ExtensionQueryMsg, VaultInfoResponse, VaultStandardExecuteMsg, - VaultStandardQueryMsg, -}; +use cw_vault_standard::extensions::lockup::LockupExecuteMsg; +use cw_vault_standard::msg::{ExtensionExecuteMsg, VaultStandardExecuteMsg as VaultExecuteMsg}; +use cw_vault_standard::VaultContract; -use crate::helpers::merge_responses; -use crate::msg::ZapTo; -use crate::state::{WithdrawMsg, LOCKUP_IDS, ROUTER}; +use crate::msg::{CallbackMsg, ReceiveChoice}; +use crate::state::{LOCKUP_IDS, ROUTER}; use crate::ContractError; -pub fn execute_withdraw( +#[cw_serde] +pub enum RedeemType { + Normal, + Lockup(u64), +} + +pub fn execute_redeem( deps: DepsMut, env: Env, info: MessageInfo, vault_address: Addr, recipient: Option, - withdraw_assets: ZapTo, + receive_choice: ReceiveChoice, + min_out: AssetList, ) -> Result { - // Query the vault info - let vault_info: VaultInfoResponse = deps.querier.query_wasm_smart( - vault_address.to_string(), - &VaultStandardQueryMsg::::Info {}, - )?; - let vault_token_denom = vault_info.vault_token; - let vault_asset = AssetInfo::Native(vault_info.base_token); - - // Make sure vault token was sent - if info.funds.len() != 1 || info.funds[0].denom != vault_token_denom { - return Err(ContractError::InvalidVaultToken {}); - } - let vault_token = info.funds[0].clone(); - - let amount_redeemed_from_vault: Uint128 = deps.querier.query_wasm_smart( - vault_address.clone(), - &VaultStandardQueryMsg::::PreviewRedeem { - amount: vault_token.amount, - }, - )?; - - let get_withdraw_msg = |vault_address: String, recipient: Option| { - Ok::(WithdrawMsg { - msg: wasm_execute( - vault_address, - &VaultStandardExecuteMsg::::Redeem { - recipient, - amount: vault_token.amount, - }, - info.funds.to_vec(), - )?, - redeem_asset: Asset::new(vault_asset.clone(), amount_redeemed_from_vault), - }) - }; - withdraw( deps, env, - &info, + info, vault_address, recipient, - withdraw_assets, - get_withdraw_msg, + receive_choice, + min_out, + RedeemType::Normal, ) } @@ -76,199 +48,280 @@ pub fn execute_withdraw_unlocked( vault_address: Addr, lockup_id: u64, recipient: Option, - withdraw_assets: ZapTo, + receive_choice: ReceiveChoice, + min_out: AssetList, ) -> Result { - // Load users lockup IDs. - let mut lock_ids = LOCKUP_IDS - .load(deps.storage, info.sender.clone()) - .unwrap_or_default(); + let key = LOCKUP_IDS.key((info.sender.clone(), vault_address.clone(), lockup_id)); // Check if lockup ID is valid. - if !lock_ids.contains(&lockup_id) { - return Err(ContractError::Std(StdError::not_found(format!( - "lockup_id {lockup_id}" - )))); + if !key.has(deps.storage) { + return Err(ContractError::Unauthorized {}); } // Remove lockup ID from users lockup IDs. - lock_ids.retain(|x| *x != lockup_id); - LOCKUP_IDS.save(deps.storage, info.sender.clone(), &lock_ids)?; - - // Query the vault info - let vault_info: VaultInfoResponse = deps.querier.query_wasm_smart( - vault_address.to_string(), - &VaultStandardQueryMsg::::Info {}, - )?; - let vault_asset = AssetInfo::Native(vault_info.base_token); - - let unlocking_position: UnlockingPosition = deps.querier.query_wasm_smart( - vault_address.clone(), - &VaultStandardQueryMsg::::VaultExtension(ExtensionQueryMsg::Lockup( - LockupQueryMsg::UnlockingPosition { lockup_id }, - )), - )?; - let amount_redeemed_from_vault = unlocking_position.base_token_amount; + key.remove(deps.storage); // Proceed with normal withdraw - let get_withdraw_msg = |vault_address: String, recipient: Option| { - Ok::(WithdrawMsg { - msg: wasm_execute( - vault_address, - &VaultStandardExecuteMsg::::VaultExtension( - ExtensionExecuteMsg::Lockup(LockupExecuteMsg::WithdrawUnlocked { - recipient, - lockup_id, - }), - ), - vec![], - )?, - redeem_asset: Asset::new(vault_asset.clone(), amount_redeemed_from_vault), - }) - }; - withdraw( deps, env, - &info, + info, vault_address, recipient, - withdraw_assets, - get_withdraw_msg, + receive_choice, + min_out, + RedeemType::Lockup(lockup_id), ) } // Called by execute_withdraw and execute_withdraw_unlocked to withdraw assets // from the vault. -pub fn withdraw( +pub fn withdraw( deps: DepsMut, env: Env, - info: &MessageInfo, + info: MessageInfo, vault_address: Addr, recipient: Option, - withdraw_assets: ZapTo, - get_withdraw_msg: F, -) -> Result -where - F: Fn(String, Option) -> StdResult, -{ - let router = ROUTER.load(deps.storage)?; - + receive_choice: ReceiveChoice, + min_out: AssetList, + withdraw_type: RedeemType, +) -> Result { // Unwrap recipient or use sender - let recipient = recipient.map_or(Ok(info.sender.clone()), |x| deps.api.addr_validate(&x))?; + let recipient = recipient.map_or(Ok(info.sender), |x| deps.api.addr_validate(&x))?; // Query the vault info - let vault_info: VaultInfoResponse = deps.querier.query_wasm_smart( - vault_address.to_string(), - &VaultStandardQueryMsg::::Info {}, - )?; - let vault_asset = AssetInfo::Native(vault_info.base_token); + let vault: VaultContract = VaultContract::new(&deps.querier, &vault_address)?; + let vault_token_denom = &vault.vault_token; + let vault_base_token = match deps.api.addr_validate(&vault.base_token) { + Ok(addr) => AssetInfo::cw20(addr), + Err(_) => AssetInfo::native(&vault.base_token), + }; - // Check if withdrawal asset is an LP token. - let pool = Pool::get_pool_for_lp_token(deps.as_ref(), &vault_asset).ok(); + // Get withdraw msg + let withdraw_msg = match withdraw_type { + RedeemType::Normal => { + // Make sure vault token was sent + if info.funds.len() != 1 || &info.funds[0].denom != vault_token_denom { + return Err(ContractError::InvalidVaultToken {}); + } + let vault_token = info.funds[0].clone(); - // Create list of messages to return - let mut withdraw_msgs = vec![]; + vault.redeem(vault_token.amount, None)? + } + RedeemType::Lockup(lockup_id) => CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: vault_address.to_string(), + funds: vec![], + msg: to_binary(&VaultExecuteMsg::::VaultExtension( + ExtensionExecuteMsg::Lockup(LockupExecuteMsg::WithdrawUnlocked { + recipient: None, + lockup_id, + }), + ))?, + }), + }; - // Check requested withdrawal assets - match withdraw_assets { - ZapTo::Asset(requested_asset) => { - // If the requested denom is the same as the vaults withdrawal asset - // just withdraw directly to the recipient. - if requested_asset == vault_asset { - withdraw_msgs.push( - get_withdraw_msg(vault_address.to_string(), Some(recipient.to_string()))?.msg, - ); - Ok(Response::new().add_messages(withdraw_msgs)) - } else { - // Add message to withdraw from vault, but return assets to this contract. - let withdraw = get_withdraw_msg(vault_address.to_string(), None)?; - withdraw_msgs.push(withdraw.msg); + let event = Event::new("apollo/vault-zapper/withdraw") + .add_attribute("vault_address", &vault_address) + .add_attribute("recipient", &recipient) + .add_attribute("receive_choice", to_binary(&receive_choice)?.to_string()) + .add_attribute("withdraw_type", to_binary(&withdraw_type)?.to_string()) + .add_attribute("min_out", to_binary(&min_out)?.to_string()); - let mut response = Response::new().add_messages(withdraw_msgs); + Ok(Response::new() + .add_message(withdraw_msg) + .add_message( + CallbackMsg::AfterRedeem { + receive_choice, + vault_base_token, + recipient, + min_out, + } + .into_cosmos_msg(&env)?, + ) + .add_event(event)) +} - let asset_withdrawn_from_vault = withdraw.redeem_asset; +pub fn execute_zap_base_tokens( + deps: DepsMut, + env: Env, + info: MessageInfo, + base_token: Asset, + recipient: Option, + receive_choice: ReceiveChoice, + min_out: AssetList, +) -> Result { + // Unwrap recipient or use sender + let recipient = recipient.map_or(Ok(info.sender.clone()), |x| deps.api.addr_validate(&x))?; - // Check if the withdrawable asset is an LP token. If it is, add a message - // to withdraw liquidity first. - if let Some(pool) = pool { - // Simulate withdrawal of liquidity to get the assets that will be returned - let assets_withdrawn_from_lp = pool - .simulate_withdraw_liquidity(deps.as_ref(), &asset_withdrawn_from_vault)?; + let receive_assets_res = receive_assets(&info, &env, &vec![base_token.clone()].into())?; - // Add messages to withdraw liquidity - let withdraw_liq_res = pool.withdraw_liquidity( - deps.as_ref(), - &env, - asset_withdrawn_from_vault, - AssetList::new(), // TODO: Add min amount - )?; - response = merge_responses(vec![response, withdraw_liq_res]); + let event = Event::new("apollo/vault-zapper/execute_zap_base_tokens") + .add_attribute("base_token", to_binary(&base_token.info)?.to_string()) + .add_attribute("recipient", &recipient) + .add_attribute("receive_choice", to_binary(&receive_choice)?.to_string()) + .add_attribute("min_out", to_binary(&min_out)?.to_string()); + + Ok(receive_assets_res + .add_message( + CallbackMsg::AfterRedeem { + receive_choice, + vault_base_token: base_token.info, + recipient, + min_out, + } + .into_cosmos_msg(&env)?, + ) + .add_event(event)) +} - // Add messages to basket liquidate the assets withdrawn from the LP - response = response.add_messages( - router.basket_liquidate_msgs( - assets_withdrawn_from_lp - .into_iter() - .cloned() - .filter(|a| a.info != requested_asset) - .collect::>() - .into(), - &requested_asset, - None, - Some(recipient.to_string()), - )?, - ); +pub fn callback_after_redeem( + deps: DepsMut, + env: Env, + receive_choice: ReceiveChoice, + vault_base_token: AssetInfo, + recipient: Addr, + min_out: AssetList, +) -> Result { + // Check contract's balance of vault's base token + let base_token_balance = + vault_base_token.query_balance(&deps.querier, &env.contract.address)?; + let base_token = Asset::new(vault_base_token.clone(), base_token_balance); - // If one of the underlying LP assets is the requested asset, add a message to - // send it to the recipient - if let Some(asset) = assets_withdrawn_from_lp.find(&requested_asset) { - response = response.add_message(asset.transfer_msg(recipient)?); - } + let pool = Pool::get_pool_for_lp_token(deps.as_ref(), &vault_base_token).ok(); + + // Check requested withdrawal assets + let (res, withdrawal_assets) = match &receive_choice { + ReceiveChoice::SwapTo(requested_asset) => { + // If the requested denom is the same as the vaults withdrawal asset, just send + // it to the recipient. + if requested_asset == &vault_base_token { + Ok(( + Response::new().add_message(base_token.transfer_msg(&recipient)?), + vec![base_token.info], + )) + } else { + // Check if the withdrawable asset is an LP token. + let router = ROUTER.load(deps.storage)?; + + if let Some(pool) = pool { + // Add messages to withdraw liquidity + let withdraw_liq_res = + pool.withdraw_liquidity(deps.as_ref(), &env, base_token, AssetList::new())?; + Ok(( + withdraw_liq_res.add_message( + CallbackMsg::AfterWithdrawLiq { + assets: pool.pool_assets(deps.as_ref())?, + receive_choice: receive_choice.clone(), + recipient: recipient.clone(), + } + .into_cosmos_msg(&env)?, + ), + vec![requested_asset.clone()], + )) } else { - // Basket liquidate the assets withdrawn from the vault - response = response.add_messages(router.basket_liquidate_msgs( - vec![asset_withdrawn_from_vault].into(), - &requested_asset, - None, + // Basket liquidate the asset withdrawn from the vault + let msgs = router.basket_liquidate_msgs( + vec![base_token].into(), + requested_asset, + None, // Not needed as we have our own min_out enforcement Some(recipient.to_string()), - )?); + )?; + Ok(( + Response::new().add_messages(msgs), + vec![requested_asset.clone()], + )) } - - Ok(response) } } - ZapTo::Underlying {} => { - // We currently only support withdrawing multiple assets if this - // vault returns an LP token, in which case we return the underlying - // LP assets from withdrawing liquidity to the user. - // TODO: Support withdrawing multiple assets that are not in the vault. - // To do this we need to add functionality to cw-dex-router. + ReceiveChoice::BaseToken => Ok(( + Response::new().add_message(base_token.transfer_msg(&recipient)?), + vec![base_token.info.clone()], + )), + ReceiveChoice::Underlying => { if let Some(pool) = pool { - // Add message to withdraw asset from vault, withdraw liquidity, - // and return withdrawn assets to recipient. - let withdraw = get_withdraw_msg(vault_address.to_string(), None)?; - withdraw_msgs.push(withdraw.msg); - let assets_withdrawn_from_lp = - pool.simulate_withdraw_liquidity(deps.as_ref(), &withdraw.redeem_asset); - let withdraw_liquidity_res = pool.withdraw_liquidity( - deps.as_ref(), - &env, - withdraw.redeem_asset, - AssetList::new(), // TODO: Add min amount - )?; - let send_to_recipient_msgs = assets_withdrawn_from_lp - .iter() - .map(|a| a.transfer_msgs(recipient.to_string())) - .collect::>>()? - .concat(); - Ok(merge_responses(vec![ - Response::new().add_messages(withdraw_msgs), - withdraw_liquidity_res, - Response::new().add_messages(send_to_recipient_msgs), - ])) + let pool_assets = pool.pool_assets(deps.as_ref())?; + + let res = + pool.withdraw_liquidity(deps.as_ref(), &env, base_token, AssetList::new())?; + Ok(( + res.add_message( + CallbackMsg::AfterWithdrawLiq { + assets: pool_assets.clone(), + receive_choice, + recipient: recipient.clone(), + } + .into_cosmos_msg(&env)?, + ), + pool_assets, + )) } else { Err(ContractError::UnsupportedWithdrawal {}) } } + }?; + + // Add a message to enforce the minimum amount of assets received + let balances_before = + AssetList::query_asset_info_balances(withdrawal_assets.clone(), &deps.querier, &recipient)?; + let enforce_min_out_msg = CallbackMsg::EnforceMinOut { + assets: withdrawal_assets, + recipient: recipient.clone(), + balances_before, + min_out: min_out.clone(), + } + .into_cosmos_msg(&env)?; + + Ok(res.add_message(enforce_min_out_msg)) +} + +pub fn callback_after_withdraw_liq( + deps: DepsMut, + env: Env, + assets: Vec, + receive_choice: ReceiveChoice, + recipient: Addr, +) -> Result { + let router = ROUTER.load(deps.storage)?; + + let asset_balances = + AssetList::query_asset_info_balances(assets, &deps.querier, &env.contract.address)?; + + match receive_choice { + ReceiveChoice::SwapTo(requested_asset) => { + let requested_asset_balance = asset_balances + .find(&requested_asset) + .map_or(Uint128::zero(), |x| x.amount); + + // Add messages to basket liquidate the assets withdrawn from the LP, but filter + // out the requested asset as we can't swap an asset to itself. + let mut msgs = router.basket_liquidate_msgs( + asset_balances + .to_vec() + .into_iter() + .filter(|x| x.info != requested_asset) + .collect::>() + .into(), + &requested_asset, + None, // Not needed as we have our own min_out enforcement + Some(recipient.to_string()), + )?; + + // Add message to send the requested asset to the recipient if the balance is + // greater than 0. + if requested_asset_balance > Uint128::zero() { + msgs.push( + Asset::new(requested_asset, requested_asset_balance).transfer_msg(recipient)?, + ); + } + + Ok(Response::new().add_messages(msgs)) + } + ReceiveChoice::Underlying => { + let msgs = asset_balances.transfer_msgs(recipient)?; + Ok(Response::new().add_messages(msgs)) + } + ReceiveChoice::BaseToken => { + panic!("Should not be possible to receive base token from callback_after_withdraw_liq") + } } } diff --git a/tarpaulin.toml b/tarpaulin.toml deleted file mode 100644 index 9a91b2a..0000000 --- a/tarpaulin.toml +++ /dev/null @@ -1,10 +0,0 @@ -[all] -exclude-files=[ - "bench/*", - "src/lib.rs", - "test/**/*", - "mod.rs" -] -fail-under=0 # TODO: update this -no-fail-fast=true -skip-clean=false \ No newline at end of file diff --git a/tests/common/mod.rs b/tests/common/mod.rs new file mode 100644 index 0000000..ffaaf5a --- /dev/null +++ b/tests/common/mod.rs @@ -0,0 +1,49 @@ +pub mod robot; +use cw_it::cw_multi_test::{StargateKeeper, StargateMessageHandler}; +use cw_it::multi_test::modules::TokenFactory; +use cw_it::multi_test::MultiTestRunner; +use cw_it::test_tube::SigningAccount; +use cw_it::{OwnedTestRunner, TestRunner}; +pub use robot::*; + +#[cfg(feature = "osmosis-test-tube")] +use cw_it::osmosis_test_tube::OsmosisTestApp; + +pub const UNOPTIMIZED_PATH: &str = "target/wasm32-unknown-unknown/release"; +pub const DEPENDENCY_ARTIFACTS_DIR: &str = "tests/test_artifacts"; + +/// The fee you need to pay to create a new denom with Token Factory. +pub const DENOM_CREATION_FEE: &str = "10000000uosmo"; + +pub 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" => { + 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-app" => OwnedTestRunner::OsmosisTestApp(OsmosisTestApp::new()), + _ => panic!("Unsupported test runner type"), + } +} + +pub fn setup<'a>( + runner: &'a TestRunner<'a>, + vault_lock_duration: u64, +) -> (VaultZapperRobot<'a>, SigningAccount) { + let admin = VaultZapperRobot::default_account(runner); + let deps = VaultZapperRobot::instantiate_deps( + runner, + DEPENDENCY_ARTIFACTS_DIR, + vault_lock_duration, + &admin, + ); + let robot = VaultZapperRobot::instantiate(runner, deps, UNOPTIMIZED_PATH, &admin); + + (robot, admin) +} diff --git a/tests/common/robot.rs b/tests/common/robot.rs new file mode 100644 index 0000000..7baaaf4 --- /dev/null +++ b/tests/common/robot.rs @@ -0,0 +1,547 @@ +use std::collections::HashMap; +use std::str::FromStr; + +use super::DENOM_CREATION_FEE; +use apollo_cw_asset::{Asset, AssetInfo, AssetList, AssetListUnchecked}; +use apollo_utils::assets::separate_natives_and_cw20s; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::testing::mock_dependencies; +use cosmwasm_std::{assert_approx_eq, coin, Addr, Api, Coin, Coins, Decimal, Uint128}; +use cw_dex::Pool; +use cw_dex_router::helpers::CwDexRouterUnchecked; +use cw_it::astroport::robot::AstroportTestRobot; +use cw_it::astroport::utils::AstroportContracts; +use cw_it::cw_multi_test::ContractWrapper; +use cw_it::helpers::Unwrap; +use cw_it::robot::TestRobot; +use cw_it::test_tube::{Account, Module, SigningAccount, Wasm}; +use cw_it::traits::CwItRunner; +use cw_it::{ContractType, TestRunner}; +use cw_vault_standard::extensions::lockup::UnlockingPosition; +use cw_vault_standard_test_helpers::traits::CwVaultStandardRobot; +use liquidity_helper::LiquidityHelperUnchecked; +use locked_astroport_vault_test_helpers::robot::LockedAstroportVaultRobot; +use locked_astroport_vault_test_helpers::router::CwDexRouterRobot; +use vault_zapper::msg::{ExecuteMsg, InstantiateMsg, QueryMsg, ReceiveChoice}; + +#[cfg(feature = "osmosis-test-tube")] +use cw_it::Artifact; + +pub const VAULT_ZAPPER_WASM_NAME: &str = "vault_zapper.wasm"; +pub const ASTROPORT_ARTIFACTS_DIR: &str = "astroport-artifacts"; +pub const ASTROPORT_LIQUIDITY_HELPER_WASM_NAME: &str = "astroport_liquidity_helper.wasm"; + +#[cw_serde] +struct AstroportLiquidityHelperInstantiateMsg { + astroport_factory: String, +} + +/// The default coins to fund new accounts with +pub const DEFAULT_COINS: &str = + "1000000000000000000uosmo,1000000000000000000untrn,1000000000000000000uaxl,1000000000000000000uastro,1000000000000000000ueth,1000000000000000000uwsteth,1000000000000000000uusdc"; +pub enum VaultRobot<'a> { + // Osmosis(OsmosisVaultRobot), //TODO: add osmosis vault robot + Astroport(LockedAstroportVaultRobot<'a>), +} + +impl<'a> TestRobot<'a, TestRunner<'a>> for VaultRobot<'a> { + fn runner(&self) -> &'a TestRunner<'a> { + match self { + VaultRobot::Astroport(robot) => robot.runner(), + } + } +} + +impl<'a> CwVaultStandardRobot<'a, TestRunner<'a>> for VaultRobot<'a> { + fn vault_addr(&self) -> String { + match self { + VaultRobot::Astroport(robot) => robot.vault_addr(), + } + } + + fn query_base_token_balance(&self, address: impl Into) -> Uint128 { + match self { + VaultRobot::Astroport(robot) => robot.query_base_token_balance(address), + } + } +} + +pub struct VaultZapperDependencies<'a> { + pub astroport_contracts: AstroportContracts, + pub cw_dex_router_robot: CwDexRouterRobot<'a>, + pub liquidity_helper_addr: String, + pub vault_robot: VaultRobot<'a>, + pub vault_pool: Pool, + pub pool_assets: Vec, +} + +pub struct VaultZapperRobot<'a> { + pub runner: &'a TestRunner<'a>, + pub vault_zapper_addr: String, + pub deps: VaultZapperDependencies<'a>, +} + +impl<'a> TestRobot<'a, TestRunner<'a>> for VaultZapperRobot<'a> { + fn runner(&self) -> &'a TestRunner<'a> { + self.runner + } +} + +impl<'a> AstroportTestRobot<'a, TestRunner<'a>> for VaultZapperRobot<'a> { + fn astroport_contracts(&self) -> &AstroportContracts { + &self.deps.astroport_contracts + } +} + +impl<'a> CwVaultStandardRobot<'a, TestRunner<'a>> for VaultZapperRobot<'a> { + fn vault_addr(&self) -> String { + self.deps.vault_robot.vault_addr() + } + + fn query_base_token_balance(&self, address: impl Into) -> Uint128 { + self.deps.vault_robot.query_base_token_balance(address) + } +} + +impl<'a> VaultZapperRobot<'a> { + /// Returns the contract code to be able to upload the contract + pub fn contract(runner: &TestRunner, _artifacts_dir: &str) -> ContractType { + match runner { + TestRunner::MultiTest(_) => ContractType::MultiTestContract(Box::new( + ContractWrapper::new_with_empty( + vault_zapper::contract::execute, + vault_zapper::contract::instantiate, + vault_zapper::contract::query, + ) + .with_reply(vault_zapper::contract::reply), + )), + #[cfg(feature = "osmosis-test-tube")] + TestRunner::OsmosisTestApp(_) => { + let path = format!("{}/{}", _artifacts_dir, VAULT_ZAPPER_WASM_NAME); + println!("Loading contract from {}", path); + ContractType::Artifact(Artifact::Local(path)) + } + _ => panic!("Unsupported test runner"), + } + } + + /// Creates a new account with default coins + pub fn default_account(runner: &TestRunner) -> SigningAccount { + runner + .init_account(&Coins::from_str(DEFAULT_COINS).unwrap().into_vec()) + .unwrap() + } + + /// Uploads and instantiates the contracts that the vault zapper depends on + pub fn instantiate_deps( + runner: &'a TestRunner, + dependency_artifacts_dir: &str, + vault_lock_duration: u64, + signer: &SigningAccount, + ) -> VaultZapperDependencies<'a> { + // TODO: Support Osmosis vault with osmosis liquidity helper + let vault_dependencies = + LockedAstroportVaultRobot::instantiate_deps(runner, signer, dependency_artifacts_dir); + let vault_treasury_addr = runner.init_account(&[]).unwrap().address(); + let (reward_vault_robot, axl_ntrn_pool, _astro_ntrn_pool) = + LockedAstroportVaultRobot::new_axlr_ntrn_vault( + runner, + LockedAstroportVaultRobot::contract(runner, dependency_artifacts_dir), + Coin::from_str(DENOM_CREATION_FEE).unwrap(), + vault_treasury_addr, + Decimal::percent(5), + vault_lock_duration, + &vault_dependencies, + signer, + ); + + let deps = VaultZapperDependencies { + astroport_contracts: vault_dependencies.astroport_contracts, + cw_dex_router_robot: vault_dependencies.cw_dex_router_robot, + liquidity_helper_addr: vault_dependencies.liquidity_helper_addr, + vault_robot: VaultRobot::Astroport(reward_vault_robot), + pool_assets: axl_ntrn_pool.pool_assets.clone(), + vault_pool: Pool::Astroport(axl_ntrn_pool), + }; + deps + } + + /// Creates a new `VaultZapperRobot` by uploading and instantiating the + /// contract + pub fn instantiate( + runner: &'a TestRunner<'a>, + dependencies: VaultZapperDependencies<'a>, + artifacts_dir: &str, + admin: &SigningAccount, + ) -> Self { + let instantiate_msg = InstantiateMsg { + router: CwDexRouterUnchecked::new( + dependencies + .cw_dex_router_robot + .cw_dex_router + .addr() + .to_string(), + ), + liquidity_helper: LiquidityHelperUnchecked::new( + dependencies.liquidity_helper_addr.clone(), + ), + }; + + // Upload contract + let code = Self::contract(runner, artifacts_dir); + let code_id = runner.store_code(code, admin).unwrap(); + + let contract_addr = Wasm::new(runner) + .instantiate( + code_id, + &instantiate_msg, + Some(&admin.address()), + None, + &[], + admin, + ) + .unwrap() + .data + .address; + + Self { + runner, + vault_zapper_addr: contract_addr.to_string(), + deps: dependencies, + } + } + + /// Deposit assets into the specified vault via the vault zapper + pub fn zapper_deposit_to_vault( + &self, + assets: AssetList, + recipient: Option, + vault_addr: &str, + min_out: Uint128, + unwrap_choice: Unwrap, + signer: &SigningAccount, + ) -> &Self { + // Increase allowance for Cw20s + let (funds, cw20s) = separate_natives_and_cw20s(&assets); + for cw20 in cw20s { + self.increase_cw20_allowance( + &cw20.address, + &self.vault_zapper_addr, + cw20.amount, + signer, + ); + } + + unwrap_choice.unwrap(self.wasm().execute( + &self.vault_zapper_addr, + &ExecuteMsg::Deposit { + assets: assets.into(), + vault_address: vault_addr.to_string(), + recipient, + min_out, + }, + &funds, + signer, + )); + + self + } + + /// Deposit assets into the vault via the vault zapper + pub fn zapper_deposit( + &self, + assets: AssetList, + recipient: Option, + min_out: Uint128, + unwrap_choice: Unwrap, + signer: &SigningAccount, + ) -> &Self { + self.zapper_deposit_to_vault( + assets, + recipient, + &self.deps.vault_robot.vault_addr(), + min_out, + unwrap_choice, + signer, + ) + } + + /// Redeem the specified amount of vault tokens from the vault via the vault + /// zapper + pub fn zapper_redeem( + &self, + amount: impl Into, + recipient: Option, + receive_choice: ReceiveChoice, + min_out: impl Into, + unwrap_choice: Unwrap, + signer: &SigningAccount, + ) -> &Self { + let min_out = min_out.into(); + unwrap_choice.unwrap(self.wasm().execute( + &self.vault_zapper_addr, + &ExecuteMsg::Redeem { + vault_address: self.deps.vault_robot.vault_addr(), + recipient, + receive_choice, + min_out, + }, + &[coin(amount.into(), self.deps.vault_robot.vault_token())], + signer, + )); + self + } + + /// Redeem all of the signer's vault tokens from the vault via the vault + /// zapper + pub fn zapper_redeem_all( + &self, + recipient: Option, + receive_choice: ReceiveChoice, + min_out: impl Into, + unwrap_choice: Unwrap, + signer: &SigningAccount, + ) -> &Self { + let balance = self.query_vault_token_balance(signer.address()); + self.zapper_redeem( + balance, + recipient, + receive_choice, + min_out, + unwrap_choice, + signer, + ) + } + + /// Zap base tokens via the vault zapper + pub fn zap_base_tokens( + &self, + amount: impl Into, + recipient: Option, + receive_choice: ReceiveChoice, + min_out: impl Into, + unwrap_choice: Unwrap, + signer: &SigningAccount, + ) -> &Self { + let min_out = min_out.into(); + + let base_token = self.deps.vault_robot.base_token(); + let deps = mock_dependencies(); + let base_token_asset_info = match deps.api.addr_validate(&base_token) { + Ok(addr) => AssetInfo::cw20(addr), + Err(_) => AssetInfo::native(&base_token), + }; + let base_token = Asset::new(base_token_asset_info, amount.into()); + + // Increase allowance for Cw20s + let (funds, cw20s) = separate_natives_and_cw20s(&vec![base_token.clone()].into()); + for cw20 in cw20s { + self.increase_cw20_allowance( + &cw20.address, + &self.vault_zapper_addr, + cw20.amount, + signer, + ); + } + + println!("Zapping base tokens: {:?}", base_token); + + unwrap_choice.unwrap(self.wasm().execute( + &self.vault_zapper_addr, + &ExecuteMsg::ZapBaseTokens { + base_token: base_token.into(), + recipient, + receive_choice, + min_out, + }, + &funds, + signer, + )); + self + } + + /// Zap all of the signer's base tokens via the vault zapper + pub fn zap_all_base_tokens( + &self, + recipient: Option, + receive_choice: ReceiveChoice, + min_out: impl Into, + unwrap_choice: Unwrap, + signer: &SigningAccount, + ) -> &Self { + let balance = self.query_base_token_balance(signer.address()); + self.zap_base_tokens( + balance, + recipient, + receive_choice, + min_out, + unwrap_choice, + signer, + ) + } + + /// Call unlock on the specified vault via the vault zapper + pub fn zapper_unlock_from_vault( + &self, + vault_addr: &str, + funds: &[Coin], + signer: &SigningAccount, + ) -> &Self { + self.wasm() + .execute( + &self.vault_zapper_addr, + &ExecuteMsg::Unlock { + vault_address: vault_addr.to_string(), + }, + funds, + signer, + ) + .unwrap(); + self + } + + /// Unlock the vault via the vault zapper + pub fn zapper_unlock(&self, amount: impl Into, signer: &SigningAccount) -> &Self { + self.wasm() + .execute( + &self.vault_zapper_addr, + &ExecuteMsg::Unlock { + vault_address: self.deps.vault_robot.vault_addr(), + }, + &[coin(amount.into(), self.deps.vault_robot.vault_token())], + signer, + ) + .unwrap(); + self + } + + /// Unlock all of the signer's vault tokens from the vault via the vault + /// zapper + pub fn zapper_unlock_all(&self, signer: &SigningAccount) -> &Self { + let balance = self.query_vault_token_balance(signer.address()); + self.zapper_unlock(balance, signer) + } + + /// Withdraw unlocked assets from the vault via the vault zapper + pub fn zapper_withdraw_unlocked( + &self, + lockup_id: u64, + recipient: Option, + receive_choice: ReceiveChoice, + min_out: impl Into, + unwrap_choice: Unwrap, + signer: &SigningAccount, + ) -> &Self { + let min_out = min_out.into(); + unwrap_choice.unwrap(self.wasm().execute( + &self.vault_zapper_addr, + &ExecuteMsg::WithdrawUnlocked { + vault_address: self.deps.vault_robot.vault_addr(), + lockup_id, + recipient, + receive_choice, + min_out, + }, + &[], + signer, + )); + self + } + + /// Increases the test runner's block time by the given number of seconds + pub fn increase_time(&self, seconds: u64) -> &Self { + self.runner.increase_time(seconds).unwrap(); + self + } + + /// Queries the depositable assets for the vault zapper + pub fn zapper_query_depositable_assets(&self) -> Vec { + self.wasm() + .query( + &self.vault_zapper_addr, + &QueryMsg::DepositableAssets { + vault_address: self.vault_addr(), + }, + ) + .unwrap() + } + + /// Queries the withdrawable assets for the vault zapper + pub fn zapper_query_receive_choices(&self) -> Vec { + self.wasm() + .query( + &self.vault_zapper_addr, + &QueryMsg::ReceiveChoices { + vault_address: self.vault_addr(), + }, + ) + .unwrap() + } + + /// Queries the unlocking positions for a user and the vault + pub fn zapper_query_user_unlocking_positions_for_vault( + &self, + owner: &str, + start_after_id: Option, + limit: Option, + ) -> Vec { + self.wasm() + .query( + &self.vault_zapper_addr, + &QueryMsg::UserUnlockingPositionsForVault { + vault_address: self.vault_addr(), + owner: owner.to_string(), + start_after_id, + limit, + }, + ) + .unwrap() + } + + /// Queries the unlocking positions for a user across all vaults + pub fn zapper_query_user_unlocking_positions( + &self, + owner: &str, + start_after_vault_addr: Option, + start_after_id: Option, + limit: Option, + ) -> HashMap> { + self.wasm() + .query( + &self.vault_zapper_addr, + &QueryMsg::UserUnlockingPositions { + owner: owner.to_string(), + start_after_vault_addr, + start_after_id, + limit, + }, + ) + .unwrap() + } + + /// Asserts that the balance of an Astroport AssetInfo for the given address + /// is approximately equal to the expected amount, with the given max + /// relative difference as a string percentage. + pub fn assert_asset_balance_approx_eq( + &self, + asset: impl Into, + address: &str, + expected: impl Into, + max_rel_diff: &str, + ) -> &Self { + let actual = self.query_asset_balance(&asset.into(), address); + assert_approx_eq!(actual, expected.into(), max_rel_diff); + self + } + + pub fn assert_zapper_has_unlocking_positions( + &self, + owner: &str, + expected: &[UnlockingPosition], + ) -> &Self { + let unlocking_positions = + self.zapper_query_user_unlocking_positions_for_vault(owner, None, None); + assert_eq!(unlocking_positions, expected); + self + } +} diff --git a/tests/integration_test.rs b/tests/integration_test.rs new file mode 100644 index 0000000..614c874 --- /dev/null +++ b/tests/integration_test.rs @@ -0,0 +1,10 @@ +use common::setup; +use cw_it::OwnedTestRunner; + +pub mod common; + +#[test] +fn instantiate_works() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + setup(&owned_runner.as_ref(), 0); +} diff --git a/tests/test_artifacts/VERSION.md b/tests/test_artifacts/VERSION.md new file mode 100644 index 0000000..f910bd6 --- /dev/null +++ b/tests/test_artifacts/VERSION.md @@ -0,0 +1,6 @@ +- astroport_liquidity_helper.wasm + - Downloaded from [Github Releases v0.2.0](https://github.com/apollodao/liquidity-helpers/releases/tag/v0.2.0) +- cw_dex_router_astroport.wasm + - Built locally with rust-optimizer-arm 0.13.0 from v0.2.0-rc.2. +- locked_astroport_vault.wasm + - Built locally with rust-optimizer-arm 0.13.0 from v0.1.0-rc.2. diff --git a/tests/test_artifacts/astroport-artifacts/VERSION.md b/tests/test_artifacts/astroport-artifacts/VERSION.md new file mode 100644 index 0000000..d0899cf --- /dev/null +++ b/tests/test_artifacts/astroport-artifacts/VERSION.md @@ -0,0 +1 @@ +These artifacts were downloaded from the Github repository `astroport-core` on the [releases page](https://github.com/astroport-fi/astroport-core/releases/tag/v2.8.0). The version of the artifacts is `v2.8.0`. diff --git a/tests/test_artifacts/astroport-artifacts/astroport_factory.wasm b/tests/test_artifacts/astroport-artifacts/astroport_factory.wasm new file mode 100644 index 0000000..3221587 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_factory.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_generator.wasm b/tests/test_artifacts/astroport-artifacts/astroport_generator.wasm new file mode 100644 index 0000000..ac4bd19 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_generator.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_maker.wasm b/tests/test_artifacts/astroport-artifacts/astroport_maker.wasm new file mode 100644 index 0000000..6226aba Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_maker.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_native_coin_registry.wasm b/tests/test_artifacts/astroport-artifacts/astroport_native_coin_registry.wasm new file mode 100644 index 0000000..b3e79d9 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_native_coin_registry.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_native_coin_wrapper.wasm b/tests/test_artifacts/astroport-artifacts/astroport_native_coin_wrapper.wasm new file mode 100644 index 0000000..c359ffc Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_native_coin_wrapper.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_oracle.wasm b/tests/test_artifacts/astroport-artifacts/astroport_oracle.wasm new file mode 100644 index 0000000..55809fe Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_oracle.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_pair.wasm b/tests/test_artifacts/astroport-artifacts/astroport_pair.wasm new file mode 100644 index 0000000..85e2dfb Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_pair.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_pair_astro_xastro.wasm b/tests/test_artifacts/astroport-artifacts/astroport_pair_astro_xastro.wasm new file mode 100644 index 0000000..b30d4cf Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_pair_astro_xastro.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_pair_concentrated.wasm b/tests/test_artifacts/astroport-artifacts/astroport_pair_concentrated.wasm new file mode 100644 index 0000000..711c876 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_pair_concentrated.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_pair_stable.wasm b/tests/test_artifacts/astroport-artifacts/astroport_pair_stable.wasm new file mode 100644 index 0000000..47caf76 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_pair_stable.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_router.wasm b/tests/test_artifacts/astroport-artifacts/astroport_router.wasm new file mode 100644 index 0000000..7cc7de6 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_router.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_staking.wasm b/tests/test_artifacts/astroport-artifacts/astroport_staking.wasm new file mode 100644 index 0000000..1acd65c Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_staking.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_token.wasm b/tests/test_artifacts/astroport-artifacts/astroport_token.wasm new file mode 100644 index 0000000..6663163 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_token.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_vesting.wasm b/tests/test_artifacts/astroport-artifacts/astroport_vesting.wasm new file mode 100644 index 0000000..bfaa830 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_vesting.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_whitelist.wasm b/tests/test_artifacts/astroport-artifacts/astroport_whitelist.wasm new file mode 100644 index 0000000..0d6fadf Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_whitelist.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/astroport_xastro_token.wasm b/tests/test_artifacts/astroport-artifacts/astroport_xastro_token.wasm new file mode 100644 index 0000000..9f79247 Binary files /dev/null and b/tests/test_artifacts/astroport-artifacts/astroport_xastro_token.wasm differ diff --git a/tests/test_artifacts/astroport-artifacts/checksums.txt b/tests/test_artifacts/astroport-artifacts/checksums.txt new file mode 100644 index 0000000..784f97b --- /dev/null +++ b/tests/test_artifacts/astroport-artifacts/checksums.txt @@ -0,0 +1,16 @@ +554ab0ea27ed7d7885c05e17fe9c861909c75dd26dab7b8b1c05fc9e4fc71824 astroport_factory.wasm +3a89d4b34ceaea04d3b267a1b6898c44cfd1548303759eb2d19834c8c98fd0db astroport_generator.wasm +169a3e9880ed8857b3e2923d65a3b17a928d92b837919287f93e6e81c2fd221b astroport_maker.wasm +a9a7433dcf7fc3b1c8083c0700cde747dfab69e6737beea007198c3c2f4342e7 astroport_native_coin_registry.wasm +fa7f8377bc02cecdffc8ac0859e326cd47115babdf8eb56b4c684469205ea284 astroport_native_coin_wrapper.wasm +09ec5b44b2af52e71bdbd38ba41b140df0ffd5fc92f2522c0449fca82765f19e astroport_oracle.wasm +419da41609bc9db64f4949adf30a7a825916bd31f99d972237921c5cf7bca862 astroport_pair.wasm +2775acbcdf4e61edbc7bd9529473b7825a21fb5d1f7abef3750abcfd8a96a28c astroport_pair_astro_xastro.wasm +7c1d8d5617b0b91193365f7d319dbb0a8d28aed4545f8defebabc432e516038c astroport_pair_concentrated.wasm +226d94adaf4c5e80409cae1af833abe8a32d0c47d151049e2880a3bd4db97cbb astroport_pair_stable.wasm +04e4cf04463cf62798faddbe2a30731f83a4a098f91667ef837399818a248f57 astroport_router.wasm +758f60c3fd1dc13d7ee26b314dc7c2629d6268aa19858aeea557de0a86f21e9f astroport_staking.wasm +0fc3850a504a9b379b4bba3a08e33c2dd79a0a097dc69ab9be82a050b30057ec astroport_token.wasm +936ed932d96188178a6a1a13ee0af0a49e17ba72c48c5185922c16003ddaccbc astroport_vesting.wasm +c24adab7ccce236bfbfc1945f9fc0bcc58c10aef606648e56e534733cd16d62f astroport_whitelist.wasm +1b79f716c62a05445b4cc23df6feddd9e91374c5388171f072021a4489e0fa7a astroport_xastro_token.wasm diff --git a/tests/test_artifacts/astroport-artifacts/checksums_intermediate.txt b/tests/test_artifacts/astroport-artifacts/checksums_intermediate.txt new file mode 100644 index 0000000..c949c73 --- /dev/null +++ b/tests/test_artifacts/astroport-artifacts/checksums_intermediate.txt @@ -0,0 +1,16 @@ +1215763021674384852111c6e6a0f776e7b72fc9a419e38f37c617052d2ecd8c target/wasm32-unknown-unknown/release/astroport_factory.wasm +7ed0b1b76b8370d05b99eb3f357fb0338a43e36e7e0890cbd345d208c77f50ca target/wasm32-unknown-unknown/release/astroport_generator.wasm +8baada1b125ab1ae1409efbfa0b2feddb771c1a67e34acf5c00f11fabab35729 target/wasm32-unknown-unknown/release/astroport_maker.wasm +088d0ce87bc2e098c71ce9fc45ff25bb0f184fdcf1d390a5370d1c9aaaab680e target/wasm32-unknown-unknown/release/astroport_native_coin_registry.wasm +acb51c6c0c12845602dcb6f86b6e01488934ee533eba465204bb61eecc813b33 target/wasm32-unknown-unknown/release/astroport_native_coin_wrapper.wasm +7cd7e46092856500da2676dd8718b4d5746abc7aedecbb74ca485a3c732cb272 target/wasm32-unknown-unknown/release/astroport_oracle.wasm +62e6c692bdde2f8cfdfa838b3f2ddbb7056a6dfbdf9f33b55dd21ec140dbb02d target/wasm32-unknown-unknown/release/astroport_pair.wasm +e3afb1f92e4b7113542e63b5c16ce562555b46d3e5491d5e375ff93439f71921 target/wasm32-unknown-unknown/release/astroport_pair_astro_xastro.wasm +7851837e1dbc940ad032469bd5b03533dc43061cfa8c5eb89d6f19e1d23542c6 target/wasm32-unknown-unknown/release/astroport_pair_concentrated.wasm +24d6572c6b1d4d27271c221e292df592fd0fd22d2255d5cc39bd681dfba7ecf6 target/wasm32-unknown-unknown/release/astroport_pair_stable.wasm +7cd469bb007efe889de91be0e2b7a607b874bc9e54644d1ad5108cfd6c005356 target/wasm32-unknown-unknown/release/astroport_router.wasm +baa66f8f99231f73594dc9569ecaf1014c9dffa65db08e969048685c132642b5 target/wasm32-unknown-unknown/release/astroport_staking.wasm +702b98cab9fffb025ae94424c1d0b43f13d528b4d56a4684c2877a2380abfaa7 target/wasm32-unknown-unknown/release/astroport_token.wasm +ba4890f1dc2c49c783425c6b1d87cc19b163d0c7509bc0a68ba31002ac294ab8 target/wasm32-unknown-unknown/release/astroport_vesting.wasm +3267332f58aef7b5a1baae47ff7d9ce2bfd43980f2c057e5f44adce9b012437e target/wasm32-unknown-unknown/release/astroport_whitelist.wasm +5114934a59ecacc4f65d5f5b0667aba71448a7a8eb154f5d0936003c7b85ef47 target/wasm32-unknown-unknown/release/astroport_xastro_token.wasm diff --git a/tests/test_artifacts/astroport_liquidity_helper.wasm b/tests/test_artifacts/astroport_liquidity_helper.wasm new file mode 100644 index 0000000..13dbf7b Binary files /dev/null and b/tests/test_artifacts/astroport_liquidity_helper.wasm differ diff --git a/tests/test_artifacts/checksums.txt b/tests/test_artifacts/checksums.txt new file mode 100644 index 0000000..0373513 --- /dev/null +++ b/tests/test_artifacts/checksums.txt @@ -0,0 +1,3 @@ +579219463d14bf0175889de23ada925b453c96ff806584e3b09b9481b3375ca1 cw_dex_router_astroport.wasm +00e80be98cacf5e289ee5019a0d4da65547dd92f0627bb5624e9243c8a2241ef astroport_liquidity_helper.wasm +d8be8a2311500aa1fc38d177c024eafc4d1f8185b752f5b654f2b367cfab6cc7 locked_astroport_vault.wasm diff --git a/tests/test_artifacts/cw_dex_router_astroport.wasm b/tests/test_artifacts/cw_dex_router_astroport.wasm new file mode 100644 index 0000000..422d675 Binary files /dev/null and b/tests/test_artifacts/cw_dex_router_astroport.wasm differ diff --git a/tests/test_artifacts/locked_astroport_vault.wasm b/tests/test_artifacts/locked_astroport_vault.wasm new file mode 100644 index 0000000..8019984 Binary files /dev/null and b/tests/test_artifacts/locked_astroport_vault.wasm differ diff --git a/tests/test_deposit.rs b/tests/test_deposit.rs new file mode 100644 index 0000000..1aa25f4 --- /dev/null +++ b/tests/test_deposit.rs @@ -0,0 +1,182 @@ +use apollo_cw_asset::{Asset, AssetInfo}; +use common::setup; +use cosmwasm_std::Uint128; +use cw_dex::traits::Pool; +use cw_it::astroport::robot::AstroportTestRobot; +use cw_it::helpers::Unwrap; +use cw_it::test_tube::Account; +use cw_it::OwnedTestRunner; +use cw_vault_standard_test_helpers::traits::CwVaultStandardRobot; + +pub mod common; + +#[test] +fn deposit_lp_token_works() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + // Deposit the LP token of the vault + let balance = robot.query_base_token_balance(admin.address()); + let deposit_amount = Uint128::new(1000000); + let deposit_asset = Asset::new(robot.deps.vault_pool.lp_token(), deposit_amount); + + robot + .zapper_deposit( + vec![deposit_asset].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_base_token_balance_eq(admin.address(), balance - deposit_amount); +} + +#[test] +fn deposit_one_asset_of_pool_works() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + let asset = robot.deps.pool_assets[0].clone(); + let balance = robot.query_asset_balance(&asset.clone().into(), &admin.address()); + let deposit_amount = Uint128::new(1000000); + assert!(balance > deposit_amount); + + robot + .zapper_deposit( + vec![Asset::new(asset.clone(), deposit_amount)].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq(&asset.into(), &admin.address(), balance - deposit_amount); +} + +#[test] +fn deposit_both_assets_of_pool_works() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + let asset1 = robot.deps.pool_assets[0].clone(); + let asset1_balance = robot.query_asset_balance(&asset1.clone().into(), &admin.address()); + let asset1_deposit_amount = Uint128::new(1000000); + assert!(asset1_balance > asset1_deposit_amount); + let asset2 = robot.deps.pool_assets[1].clone(); + let asset2_balance = robot.query_asset_balance(&asset2.clone().into(), &admin.address()); + let asset2_deposit_amount = Uint128::new(3000000); + assert!(asset2_balance > asset2_deposit_amount); + + robot + .zapper_deposit( + vec![ + Asset::new(asset1.clone(), asset1_deposit_amount), + Asset::new(asset2.clone(), asset2_deposit_amount), + ] + .into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq( + &asset1.into(), + &admin.address(), + asset1_balance - asset1_deposit_amount, + ) + .assert_asset_balance_eq( + &asset2.into(), + &admin.address(), + asset2_balance - asset2_deposit_amount, + ); +} + +#[test] +fn deposit_asset_not_in_pool() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + let asset = AssetInfo::native("uastro"); + let pool_assets = &robot.deps.pool_assets; + assert!(!pool_assets.contains(&asset)); + let balance = robot.query_asset_balance(&asset.clone().into(), &admin.address()); + let deposit_amount = Uint128::new(1000000); + assert!(balance > deposit_amount); + + robot + .zapper_deposit( + vec![Asset::new(asset.clone(), deposit_amount)].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq(&asset.into(), &admin.address(), balance - deposit_amount); +} + +#[test] +fn deposit_lp_min_out_respected() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + // Deposit the LP token of the vault + let balance = robot.query_base_token_balance(admin.address()); + let deposit_amount = Uint128::new(1000000); + let deposit_asset = Asset::new(robot.deps.vault_pool.lp_token(), deposit_amount); + + robot + .zapper_deposit( + vec![deposit_asset.clone()].into(), + None, + deposit_amount * Uint128::new(1_000_000_000_000), + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_deposit( + vec![deposit_asset].into(), + None, + deposit_amount * Uint128::new(1_000_000), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_base_token_balance_eq(admin.address(), balance - deposit_amount); +} + +#[test] +fn deposit_one_asset_of_pool_min_out_respected() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + let asset = robot.deps.pool_assets[0].clone(); + let balance = robot.query_asset_balance(&asset.clone().into(), &admin.address()); + let deposit_amount = Uint128::new(1000000); + assert!(balance > deposit_amount); + + robot + .zapper_deposit( + vec![Asset::new(asset.clone(), deposit_amount)].into(), + None, + deposit_amount * Uint128::new(1_000_000_000_000), + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_deposit( + vec![Asset::new(asset.clone(), deposit_amount)].into(), + None, + deposit_amount * Uint128::new(1_000), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq(&asset.into(), &admin.address(), balance - deposit_amount); +} diff --git a/tests/test_query.rs b/tests/test_query.rs new file mode 100644 index 0000000..589339c --- /dev/null +++ b/tests/test_query.rs @@ -0,0 +1,424 @@ +use std::str::FromStr; + +use apollo_cw_asset::{Asset, AssetInfo}; +use common::{ + setup, VaultRobot, VaultZapperDependencies, VaultZapperRobot, DENOM_CREATION_FEE, + DEPENDENCY_ARTIFACTS_DIR, UNOPTIMIZED_PATH, +}; +use cosmwasm_std::{coin, Addr, Coin, Decimal, Timestamp, Uint128}; +use cw_dex::pool::Pool; +use cw_dex::traits::Pool as PoolTrait; +use cw_it::helpers::Unwrap; +use cw_it::robot::TestRobot; +use cw_it::test_tube::Account; +use cw_it::traits::CwItRunner; +use cw_it::OwnedTestRunner; +use cw_vault_standard::extensions::lockup::UnlockingPosition; +use cw_vault_standard_test_helpers::traits::CwVaultStandardRobot; +use liquidity_helper::LiquidityHelperUnchecked; +use locked_astroport_vault::msg::InstantiateMsg as AstroportVaultInstantiateMsg; +use locked_astroport_vault_test_helpers::robot::LockedAstroportVaultRobot; +use locked_astroport_vault_test_helpers::router::CwDexRouterRobot; +use vault_zapper::msg::ReceiveChoice; + +pub mod common; + +#[test] +fn query_depositable_assets() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, _admin) = setup(&runner, 0); + + let pool_assets = robot.deps.pool_assets.clone(); + + let mut depositable_assets = robot.zapper_query_depositable_assets(); + + let mut expected = [ + &[ + robot.deps.vault_pool.lp_token(), + AssetInfo::native("uastro"), /* There is a swap path from uastro to each of the pool + * assets */ + ], + pool_assets.as_slice(), + ] + .concat(); + + // Sort both so we can compare them + depositable_assets.sort_by_key(|a| a.to_string()); + expected.sort_by_key(|a| a.to_string()); + + assert_eq!(depositable_assets, expected); +} + +#[test] +fn query_receive_choices() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, _admin) = setup(&runner, 0); + + let pool_assets = robot.deps.pool_assets.clone(); + + let expected = vec![ + ReceiveChoice::SwapTo(AssetInfo::native("uastro")), + ReceiveChoice::SwapTo(pool_assets[0].clone()), + ReceiveChoice::SwapTo(pool_assets[1].clone()), + ReceiveChoice::BaseToken, + ReceiveChoice::Underlying, + ]; + + let receive_choices = robot.zapper_query_receive_choices(); + + assert_eq!(receive_choices, expected); +} + +#[test] +fn query_unlocking_positions_for_one_vault() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 300); + + // Deposit the LP token of the vault + let deposit_amount = Uint128::new(1000000); + let deposit_asset = Asset::new(robot.deps.vault_pool.lp_token(), deposit_amount); + + // Deposit and unlock half of the deposited amount + let vault_token_balance = robot + .zapper_deposit( + vec![deposit_asset].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .query_vault_token_balance(admin.address()); + robot.zapper_unlock(vault_token_balance.u128() / 2, &admin); + + // Query the unlocking position and unlock second half + let current_time = runner.query_block_time_nanos(); + let unlocking_position_0 = UnlockingPosition { + id: 0, + base_token_amount: deposit_amount / Uint128::new(2), + owner: Addr::unchecked(robot.vault_zapper_addr.clone()), + release_at: cw_utils::Expiration::AtTime(Timestamp::from_nanos( + current_time + 300_000_000_000, + )), + }; + robot + .assert_zapper_has_unlocking_positions(&admin.address(), &[unlocking_position_0.clone()]) + .zapper_unlock(vault_token_balance.u128() / 2, &admin); + + // Query the unlocking positions + let current_time = runner.query_block_time_nanos(); + let unlocking_position_1 = UnlockingPosition { + id: 1, + release_at: cw_utils::Expiration::AtTime(Timestamp::from_nanos( + current_time + 300_000_000_000, + )), + ..unlocking_position_0.clone() + }; + robot.assert_zapper_has_unlocking_positions( + &admin.address(), + &[unlocking_position_0.clone(), unlocking_position_1.clone()], + ); + + // Query with start_after and limit parameters + let res = + robot.zapper_query_user_unlocking_positions_for_vault(&admin.address(), None, Some(1)); + assert_eq!(res.len(), 1); + assert_eq!(res[0], unlocking_position_0); + let res = + robot.zapper_query_user_unlocking_positions_for_vault(&admin.address(), Some(0), None); + assert_eq!(res.len(), 1); + assert_eq!(res[0], unlocking_position_1); + let res = + robot.zapper_query_user_unlocking_positions_for_vault(&admin.address(), Some(0), Some(1)); + assert_eq!(res.len(), 1); + assert_eq!(res[0], unlocking_position_1); + let res = + robot.zapper_query_user_unlocking_positions_for_vault(&admin.address(), Some(1), Some(1)); + assert_eq!(res.len(), 0); + let res = + robot.zapper_query_user_unlocking_positions_for_vault(&admin.address(), Some(0), Some(0)); + assert_eq!(res.len(), 0); + + // Increase time, withdraw and assert that the unlocking positions are removed + robot + .increase_time(300) + .zapper_withdraw_unlocked( + 0, + None, + ReceiveChoice::BaseToken, + vec![], + Unwrap::Ok, + &admin, + ) + .assert_zapper_has_unlocking_positions(&admin.address(), &[unlocking_position_1]) + .zapper_withdraw_unlocked( + 1, + None, + ReceiveChoice::BaseToken, + vec![], + Unwrap::Ok, + &admin, + ) + .assert_zapper_has_unlocking_positions(&admin.address(), &[]); +} + +#[test] +fn query_unlocking_positions_for_two_vaults() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let admin = VaultZapperRobot::default_account(&runner); + let vault_lock_duration = 300; + + let vault_dependencies = + LockedAstroportVaultRobot::instantiate_deps(&runner, &admin, DEPENDENCY_ARTIFACTS_DIR); + let vault_treasury_addr = runner.init_account(&[]).unwrap().address(); + + // Instantiate first vault + let (axl_ntrn_vault, axl_ntrn_pool, astro_ntrn_pool) = + LockedAstroportVaultRobot::new_axlr_ntrn_vault( + &runner, + LockedAstroportVaultRobot::contract(&runner, DEPENDENCY_ARTIFACTS_DIR), + Coin::from_str(DENOM_CREATION_FEE).unwrap(), + vault_treasury_addr.clone(), + Decimal::percent(5), + vault_lock_duration, + &vault_dependencies, + &admin, + ); + let vault_1_addr = Addr::unchecked(axl_ntrn_vault.vault_addr()); + // Instantiate second vault + let init_msg = AstroportVaultInstantiateMsg { + owner: admin.address(), + vault_token_subdenom: "testVaultToken".to_string(), + lock_duration: vault_lock_duration, + reward_tokens: vec![AssetInfo::native("uastro").into()], + deposits_enabled: true, + treasury: vault_treasury_addr.clone(), + performance_fee: Decimal::percent(5), + router: vault_dependencies + .cw_dex_router_robot + .cw_dex_router + .clone() + .into(), + reward_liquidation_target: AssetInfo::native("uastro").into(), + pool_addr: astro_ntrn_pool.pair_addr.to_string(), + astro_token: apollo_cw_asset::AssetInfoUnchecked::native("uastro"), + astroport_generator: vault_dependencies + .astroport_contracts + .generator + .address + .clone(), + liquidity_helper: LiquidityHelperUnchecked::new( + vault_dependencies.liquidity_helper_addr.clone(), + ), + }; + let astro_ntrn_vault_robot = LockedAstroportVaultRobot::new_with_instantiate_msg( + &runner, + LockedAstroportVaultRobot::contract(&runner, DEPENDENCY_ARTIFACTS_DIR), + Coin::from_str(DENOM_CREATION_FEE).unwrap(), + &init_msg, + &vault_dependencies, + &admin, + ); + let vault_2_addr = Addr::unchecked(&astro_ntrn_vault_robot.vault_addr); + + // Instantiate the zapper and create test robot + let deps = VaultZapperDependencies { + astroport_contracts: vault_dependencies.astroport_contracts.clone(), + cw_dex_router_robot: CwDexRouterRobot { + runner: &runner, + cw_dex_router: vault_dependencies.cw_dex_router_robot.cw_dex_router.clone(), + }, + liquidity_helper_addr: vault_dependencies.liquidity_helper_addr.clone(), + vault_robot: VaultRobot::Astroport(axl_ntrn_vault), + pool_assets: axl_ntrn_pool.pool_assets.clone(), + vault_pool: Pool::Astroport(axl_ntrn_pool.clone()), + }; + let robot = VaultZapperRobot::instantiate(&runner, deps, UNOPTIMIZED_PATH, &admin); + + // Deposit the LP token of the vault + let deposit_amount = Uint128::new(1000000); + let vault_1_deposit_asset = Asset::new(axl_ntrn_pool.lp_token(), deposit_amount); + let vault_2_deopsit_asset = Asset::new( + astro_ntrn_pool.lp_token(), + Uint128::new(1000000) * Uint128::new(1000000), + ); + + // Deposit and unlock half of the deposited amount + let vault1_vault_token_balance = robot + .zapper_deposit( + vec![vault_1_deposit_asset].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .query_vault_token_balance(admin.address()); + robot.zapper_unlock(vault1_vault_token_balance.u128() / 2, &admin); + + let current_time = runner.query_block_time_nanos(); + let vault_1_unlocking_pos_0 = UnlockingPosition { + id: 0, + owner: Addr::unchecked(robot.vault_zapper_addr.clone()), + release_at: cw_utils::Expiration::AtTime(Timestamp::from_nanos( + current_time + vault_lock_duration * 1_000_000_000, + )), + base_token_amount: deposit_amount / Uint128::new(2), + }; + + let vault2_vault_token_balance = robot + .zapper_deposit_to_vault( + vec![vault_2_deopsit_asset].into(), + None, + &astro_ntrn_vault_robot.vault_addr, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .query_native_token_balance(admin.address(), astro_ntrn_vault_robot.vault_token()); + robot.zapper_unlock_from_vault( + &astro_ntrn_vault_robot.vault_addr, + &[coin( + vault2_vault_token_balance.u128() / 2, + astro_ntrn_vault_robot.vault_token(), + )], + &admin, + ); + + let current_time = runner.query_block_time_nanos(); + let vault_2_unlocking_pos_0 = UnlockingPosition { + id: 0, + owner: Addr::unchecked(robot.vault_zapper_addr.clone()), + release_at: cw_utils::Expiration::AtTime(Timestamp::from_nanos( + current_time + vault_lock_duration * 1_000_000_000, + )), + base_token_amount: Uint128::new(1000000) * Uint128::new(1000000) / Uint128::new(2), + }; + + // Query the unlocking positions + let res = robot.zapper_query_user_unlocking_positions(&admin.address(), None, None, None); + assert_eq!(res.len(), 2); + let positions_for_vault_one = res.get(&vault_1_addr).unwrap(); + let positions_for_vault_two = res.get(&vault_2_addr).unwrap(); + assert_eq!(positions_for_vault_one.len(), 1); + assert_eq!(positions_for_vault_two.len(), 1); + assert_eq!( + positions_for_vault_one, + &vec![vault_1_unlocking_pos_0.clone()] + ); + assert_eq!( + positions_for_vault_two, + &vec![vault_2_unlocking_pos_0.clone()] + ); + + // Unlock second half for each vault + robot.zapper_unlock(vault1_vault_token_balance.u128() / 2, &admin); + + let vault_1_unlocking_pos_1 = UnlockingPosition { + id: 1, + owner: Addr::unchecked(robot.vault_zapper_addr.clone()), + release_at: cw_utils::Expiration::AtTime(Timestamp::from_nanos( + runner.query_block_time_nanos() + vault_lock_duration * 1_000_000_000, + )), + base_token_amount: deposit_amount / Uint128::new(2), + }; + + robot.zapper_unlock_from_vault( + &astro_ntrn_vault_robot.vault_addr, + &[coin( + vault2_vault_token_balance.u128() / 2, + astro_ntrn_vault_robot.vault_token(), + )], + &admin, + ); + + let vault_2_unlocking_pos_1 = UnlockingPosition { + id: 1, + owner: Addr::unchecked(robot.vault_zapper_addr.clone()), + release_at: cw_utils::Expiration::AtTime(Timestamp::from_nanos( + runner.query_block_time_nanos() + vault_lock_duration * 1_000_000_000, + )), + base_token_amount: Uint128::new(1000000) * Uint128::new(1000000) / Uint128::new(2), + }; + + // Query the unlocking positions + let res = robot.zapper_query_user_unlocking_positions(&admin.address(), None, None, None); + assert_eq!(res.len(), 2); + let positions_for_vault_one = res.get(&vault_1_addr).unwrap(); + let positions_for_vault_two = res.get(&vault_2_addr).unwrap(); + assert_eq!(positions_for_vault_one.len(), 2); + assert_eq!(positions_for_vault_two.len(), 2); + assert_eq!( + positions_for_vault_one, + &vec![ + vault_1_unlocking_pos_0.clone(), + vault_1_unlocking_pos_1.clone() + ] + ); + assert_eq!( + positions_for_vault_two, + &vec![ + vault_2_unlocking_pos_0.clone(), + vault_2_unlocking_pos_1.clone() + ] + ); + + // Query with start_after_vault_addr + let res = robot.zapper_query_user_unlocking_positions( + &admin.address(), + Some(vault_1_addr.to_string()), + None, + None, + ); + assert_eq!(res.len(), 1); + let positions_for_vault_two = res.get(&vault_2_addr).unwrap(); + assert_eq!(positions_for_vault_two.len(), 2); + assert_eq!( + positions_for_vault_two, + &vec![ + vault_2_unlocking_pos_0.clone(), + vault_2_unlocking_pos_1.clone() + ] + ); + + // Query with start_after_vault_addr and start_after_id + let res = robot.zapper_query_user_unlocking_positions( + &admin.address(), + Some(vault_1_addr.to_string()), + Some(0), + None, + ); + assert_eq!(res.len(), 2); + let positions_for_vault_one = res.get(&vault_1_addr).unwrap(); + let positions_for_vault_two = res.get(&vault_2_addr).unwrap(); + assert_eq!(positions_for_vault_one.len(), 1); + assert_eq!(positions_for_vault_two.len(), 2); + assert_eq!( + positions_for_vault_one, + &vec![vault_1_unlocking_pos_1.clone()] + ); + assert_eq!( + positions_for_vault_two, + &vec![ + vault_2_unlocking_pos_0.clone(), + vault_2_unlocking_pos_1.clone() + ] + ); + + // Query with start_after_vault_addr and start_after_id and limit + let res = robot.zapper_query_user_unlocking_positions( + &admin.address(), + Some(vault_1_addr.to_string()), + Some(1), + Some(1), + ); + assert_eq!(res.len(), 1); + let positions_for_vault_two = res.get(&vault_2_addr).unwrap(); + assert_eq!(positions_for_vault_two.len(), 1); + assert_eq!( + positions_for_vault_two, + &vec![vault_2_unlocking_pos_0.clone()] + ); +} diff --git a/tests/test_withdraw.rs b/tests/test_withdraw.rs new file mode 100644 index 0000000..9ec312a --- /dev/null +++ b/tests/test_withdraw.rs @@ -0,0 +1,434 @@ +use apollo_cw_asset::{Asset, AssetInfo, AssetList, AssetUnchecked}; +use common::setup; +use cosmwasm_std::{Decimal, Uint128}; +use cw_dex::traits::Pool; +use cw_it::astroport::robot::AstroportTestRobot; +use cw_it::helpers::Unwrap; +use cw_it::test_tube::Account; +use cw_it::OwnedTestRunner; +use cw_vault_standard_test_helpers::traits::CwVaultStandardRobot; +use test_case::test_case; +use vault_zapper::msg::ReceiveChoice; + +pub mod common; + +#[test_case(0, true; "no lock, via ReceiveChoice::SwapTo")] +#[test_case(0, false; "no lock, via ReceiveChoice::BaseToken")] +#[test_case(300, true; "with lockup, via ReceiveChoice::SwapTo")] +#[test_case(300, false; "with lockup, via ReceiveChoice::BaseToken")] +fn withdraw_base_token(lock_duration: u64, via_swap_to: bool) { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, lock_duration); + + // Deposit the LP token of the vault + let balance = robot.query_base_token_balance(admin.address()); + let deposit_amount = Uint128::new(1000000); + let deposit_asset_info = robot.deps.vault_pool.lp_token(); + let deposit_asset = Asset::new(deposit_asset_info.clone(), deposit_amount); + + robot + .zapper_deposit( + vec![deposit_asset].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_base_token_balance_eq(admin.address(), balance - deposit_amount); + + let receive_choice = if via_swap_to { + ReceiveChoice::SwapTo(deposit_asset_info.clone()) + } else { + ReceiveChoice::BaseToken + }; + if lock_duration == 0 { + robot + .zapper_redeem_all( + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount + Uint128::new(1), + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_redeem_all( + None, + receive_choice, + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount, + )], + Unwrap::Ok, + &admin, + ); + } else { + robot + .zapper_unlock_all(&admin) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + AssetList::new(), + Unwrap::Err("Claim has not yet matured"), + &admin, + ) + .increase_time(lock_duration) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount + Uint128::new(1), + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice, + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount, + )], + Unwrap::Ok, + &admin, + ); + } + + robot + .assert_vault_token_balance_eq(admin.address(), 0u128) + .assert_base_token_balance_eq(admin.address(), balance); +} + +#[test_case(0; "no lock")] +#[test_case(300; "with lockup")] +fn withdraw_one_asset_in_pool(lock_duration: u64) { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, lock_duration); + + let deposit_asset_info = robot.deps.pool_assets[0].clone(); + let balance_before = + robot.query_asset_balance(&deposit_asset_info.clone().into(), &admin.address()); + let deposit_amount = Uint128::new(1000000); + let deposit_asset = Asset::new(deposit_asset_info.clone(), deposit_amount); + assert!(balance_before > deposit_amount); + + // Deposit + robot + .zapper_deposit( + vec![deposit_asset].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq( + &deposit_asset_info.clone().into(), + &admin.address(), + balance_before - deposit_amount, + ); + + let receive_choice = ReceiveChoice::SwapTo(deposit_asset_info.clone()); + if lock_duration == 0 { + robot.zapper_redeem_all( + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount * (Decimal::one() - Decimal::permille(3)), + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ); + robot.zapper_redeem_all( + None, + receive_choice, + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount * (Decimal::one() - Decimal::permille(4)), + )], + Unwrap::Ok, + &admin, + ); + } else { + robot + .zapper_unlock_all(&admin) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + AssetList::new(), + Unwrap::Err("Claim has not yet matured"), + &admin, + ) + .increase_time(lock_duration) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount * (Decimal::one() - Decimal::permille(3)), + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice, + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount * (Decimal::one() - Decimal::permille(4)), + )], + Unwrap::Ok, + &admin, + ); + }; + + let deposit_asset_balance_after = robot + .assert_vault_token_balance_eq(admin.address(), 0u128) + .query_asset_balance(&deposit_asset_info.into(), &admin.address()); + + // Assert that approx 0.3% was lost due to swap fees + let balance_diff = balance_before - deposit_asset_balance_after; + assert!(Decimal::from_ratio(balance_diff, deposit_amount) < Decimal::permille(4)); +} + +#[test_case(0; "no lock")] +#[test_case(300; "with lockup")] +fn redeem_asset_not_in_pool(lock_duration: u64) { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, lock_duration); + + let deposit_asset_info = AssetInfo::native("uastro"); + let pool_assets = &robot.deps.pool_assets; + assert!(!pool_assets.contains(&deposit_asset_info)); + let balance_before = + robot.query_asset_balance(&deposit_asset_info.clone().into(), &admin.address()); + let deposit_amount = Uint128::new(1000000); + assert!(balance_before > deposit_amount); + + robot + .zapper_deposit( + vec![Asset::new(deposit_asset_info.clone(), deposit_amount)].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq( + &deposit_asset_info.clone().into(), + &admin.address(), + balance_before - deposit_amount, + ); + + let receive_choice = ReceiveChoice::SwapTo(deposit_asset_info.clone()); + if lock_duration == 0 { + robot + .zapper_redeem_all(None, receive_choice, AssetList::new(), Unwrap::Ok, &admin) + .assert_vault_token_balance_eq(admin.address(), 0u128); + } else { + robot + .zapper_unlock_all(&admin) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + AssetList::new(), + Unwrap::Err("Claim has not yet matured"), + &admin, + ) + .increase_time(lock_duration) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice, + AssetList::new(), + Unwrap::Ok, + &admin, + ); + }; + + let deposit_asset_balance_after = robot + .assert_vault_token_balance_eq(admin.address(), 0u128) + .query_asset_balance(&deposit_asset_info.into(), &admin.address()); + + // Assert that approx X% was lost due to swap fees + // TODO: Is 12 permille correct? + let balance_diff = balance_before - deposit_asset_balance_after; + assert!(Decimal::from_ratio(balance_diff, deposit_amount) < Decimal::permille(12)); +} + +#[test_case(0; "no lock")] +#[test_case(300; "with lockup")] +fn redeem_both_assets_of_pool(lock_duration: u64) { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, lock_duration); + + let asset1 = robot.deps.pool_assets[0].clone(); + let asset1_balance = robot.query_asset_balance(&asset1.clone().into(), &admin.address()); + let asset1_deposit_amount = Uint128::new(1000000); + assert!(asset1_balance > asset1_deposit_amount); + let asset2 = robot.deps.pool_assets[1].clone(); + let asset2_balance = robot.query_asset_balance(&asset2.clone().into(), &admin.address()); + let asset2_deposit_amount = Uint128::new(1000000); + assert!(asset2_balance > asset2_deposit_amount); + + // Deposit both assets + robot + .zapper_deposit( + vec![ + Asset::new(asset1.clone(), asset1_deposit_amount), + Asset::new(asset2.clone(), asset2_deposit_amount), + ] + .into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq( + &asset1.clone().into(), + &admin.address(), + asset1_balance - asset1_deposit_amount, + ) + .assert_asset_balance_eq( + &asset2.clone().into(), + &admin.address(), + asset2_balance - asset2_deposit_amount, + ); + + // Redeem both assets + let receive_choice = ReceiveChoice::Underlying; + let max_rel_diff = "0.000000001"; // One unit lost due to rounding + if lock_duration == 0 { + robot + .zapper_redeem_all( + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + asset1.clone().into(), + asset1_deposit_amount, + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_redeem_all( + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + asset2.clone().into(), + asset2_deposit_amount, + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_redeem_all( + None, + receive_choice.clone(), + vec![ + AssetUnchecked::new(asset1.clone().into(), asset1_deposit_amount), + AssetUnchecked::new(asset2.clone().into(), asset2_deposit_amount), + ], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_redeem_all( + None, + receive_choice, + vec![ + AssetUnchecked::new( + asset1.clone().into(), + asset1_deposit_amount - Uint128::one(), + ), + AssetUnchecked::new( + asset2.clone().into(), + asset2_deposit_amount - Uint128::one(), + ), + ], + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_eq(admin.address(), 0u128); + } else { + robot + .zapper_unlock_all(&admin) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + AssetList::new(), + Unwrap::Err("Claim has not yet matured"), + &admin, + ) + .increase_time(lock_duration) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + asset1.clone().into(), + asset1_deposit_amount, + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + asset2.clone().into(), + asset2_deposit_amount, + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice.clone(), + vec![ + AssetUnchecked::new(asset1.clone().into(), asset1_deposit_amount), + AssetUnchecked::new(asset2.clone().into(), asset2_deposit_amount), + ], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zapper_withdraw_unlocked( + 0, + None, + receive_choice, + vec![ + AssetUnchecked::new( + asset1.clone().into(), + asset1_deposit_amount - Uint128::one(), + ), + AssetUnchecked::new( + asset2.clone().into(), + asset2_deposit_amount - Uint128::one(), + ), + ], + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_eq(admin.address(), 0u128); + } + + robot + .assert_asset_balance_approx_eq(asset1, &admin.address(), asset1_balance, max_rel_diff) + .assert_asset_balance_approx_eq(asset2, &admin.address(), asset2_balance, max_rel_diff); +} diff --git a/tests/test_zap_base_token.rs b/tests/test_zap_base_token.rs new file mode 100644 index 0000000..1511154 --- /dev/null +++ b/tests/test_zap_base_token.rs @@ -0,0 +1,314 @@ +use apollo_cw_asset::{Asset, AssetInfo, AssetList, AssetUnchecked}; +use common::setup; +use cosmwasm_std::{Decimal, Uint128}; +use cw_dex::traits::Pool; +use cw_it::astroport::robot::AstroportTestRobot; +use cw_it::helpers::Unwrap; +use cw_it::test_tube::Account; +use cw_it::OwnedTestRunner; +use cw_vault_standard_test_helpers::traits::CwVaultStandardRobot; +use test_case::test_case; +use vault_zapper::msg::ReceiveChoice; + +pub mod common; + +#[test_case(true; "no lock, via ReceiveChoice::SwapTo")] +#[test_case(false; "no lock, via ReceiveChoice::BaseToken")] +fn zap_base_token_to_base_token(via_swap_to: bool) { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + // Deposit the LP token of the vault + let balance = robot.query_base_token_balance(admin.address()); + let deposit_amount = Uint128::new(1000000); + let deposit_asset_info = robot.deps.vault_pool.lp_token(); + let deposit_asset = Asset::new(deposit_asset_info.clone(), deposit_amount); + + //Deposit + robot + .zapper_deposit( + vec![deposit_asset].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_base_token_balance_eq(admin.address(), balance - deposit_amount); + let base_token_balance_before_redeem = robot.query_base_token_balance(admin.address()); + // Redeem + let base_token_balance_after_redeem = robot + .redeem_all(None, Unwrap::Ok, &admin) + .query_base_token_balance(admin.address()); + let base_tokens_received = base_token_balance_after_redeem - base_token_balance_before_redeem; + + let receive_choice = if via_swap_to { + ReceiveChoice::SwapTo(deposit_asset_info.clone()) + } else { + ReceiveChoice::BaseToken + }; + robot + .zap_base_tokens( + base_tokens_received, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount + Uint128::new(1), + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zap_base_tokens( + base_tokens_received, + None, + receive_choice, + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount, + )], + Unwrap::Ok, + &admin, + ); + + robot + .assert_vault_token_balance_eq(admin.address(), 0u128) + .assert_base_token_balance_eq(admin.address(), balance); +} + +#[test] +fn zap_base_tokens_to_one_asset_in_pool() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + let deposit_asset_info = robot.deps.pool_assets[0].clone(); + let balance_before = + robot.query_asset_balance(&deposit_asset_info.clone().into(), &admin.address()); + let deposit_amount = Uint128::new(1000000); + let deposit_asset = Asset::new(deposit_asset_info.clone(), deposit_amount); + assert!(balance_before > deposit_amount); + + // Deposit + robot + .zapper_deposit( + vec![deposit_asset].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq( + &deposit_asset_info.clone().into(), + &admin.address(), + balance_before - deposit_amount, + ); + let base_token_balance_before_redeem = robot.query_base_token_balance(admin.address()); + // Redeem + let base_token_balance_after_redeem = robot + .redeem_all(None, Unwrap::Ok, &admin) + .query_base_token_balance(admin.address()); + let base_tokens_received = base_token_balance_after_redeem - base_token_balance_before_redeem; + + let receive_choice = ReceiveChoice::SwapTo(deposit_asset_info.clone()); + robot.zap_base_tokens( + base_tokens_received, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount * (Decimal::one() - Decimal::permille(3)), + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ); + robot.zap_base_tokens( + base_tokens_received, + None, + receive_choice, + vec![AssetUnchecked::new( + deposit_asset_info.clone().into(), + deposit_amount * (Decimal::one() - Decimal::permille(4)), + )], + Unwrap::Ok, + &admin, + ); + + let deposit_asset_balance_after = robot + .assert_vault_token_balance_eq(admin.address(), 0u128) + .query_asset_balance(&deposit_asset_info.into(), &admin.address()); + + // Assert that approx 0.3% was lost due to swap fees + let balance_diff = balance_before - deposit_asset_balance_after; + assert!(Decimal::from_ratio(balance_diff, deposit_amount) < Decimal::permille(4)); +} + +#[test] +fn zap_base_tokens_to_asset_not_in_pool() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + let deposit_asset_info = AssetInfo::native("uastro"); + let pool_assets = &robot.deps.pool_assets; + assert!(!pool_assets.contains(&deposit_asset_info)); + let balance_before = + robot.query_asset_balance(&deposit_asset_info.clone().into(), &admin.address()); + let deposit_amount = Uint128::new(1000000); + assert!(balance_before > deposit_amount); + + //Deposit + robot + .zapper_deposit( + vec![Asset::new(deposit_asset_info.clone(), deposit_amount)].into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq( + &deposit_asset_info.clone().into(), + &admin.address(), + balance_before - deposit_amount, + ); + let base_token_balance_before_redeem = robot.query_base_token_balance(admin.address()); + // Redeem + let base_token_balance_after_redeem = robot + .redeem_all(None, Unwrap::Ok, &admin) + .query_base_token_balance(admin.address()); + let base_tokens_received = base_token_balance_after_redeem - base_token_balance_before_redeem; + + let receive_choice = ReceiveChoice::SwapTo(deposit_asset_info.clone()); + + robot + .zap_base_tokens( + base_tokens_received, + None, + receive_choice, + AssetList::new(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_eq(admin.address(), 0u128); + + let deposit_asset_balance_after = robot + .assert_vault_token_balance_eq(admin.address(), 0u128) + .query_asset_balance(&deposit_asset_info.into(), &admin.address()); + + // Assert that approx X% was lost due to swap fees + // TODO: Is 12 permille correct? + let balance_diff = balance_before - deposit_asset_balance_after; + assert!(Decimal::from_ratio(balance_diff, deposit_amount) < Decimal::permille(12)); +} + +#[test] +fn zap_base_tokens_to_both_assets_of_pool() { + let owned_runner: OwnedTestRunner = common::get_test_runner(); + let runner = owned_runner.as_ref(); + let (robot, admin) = setup(&runner, 0); + + let asset1 = robot.deps.pool_assets[0].clone(); + let asset1_balance = robot.query_asset_balance(&asset1.clone().into(), &admin.address()); + let asset1_deposit_amount = Uint128::new(1000000); + assert!(asset1_balance > asset1_deposit_amount); + let asset2 = robot.deps.pool_assets[1].clone(); + let asset2_balance = robot.query_asset_balance(&asset2.clone().into(), &admin.address()); + let asset2_deposit_amount = Uint128::new(1000000); + assert!(asset2_balance > asset2_deposit_amount); + + // Deposit both assets + robot + .zapper_deposit( + vec![ + Asset::new(asset1.clone(), asset1_deposit_amount), + Asset::new(asset2.clone(), asset2_deposit_amount), + ] + .into(), + None, + Uint128::one(), + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_gt(admin.address(), 0u128) + .assert_asset_balance_eq( + &asset1.clone().into(), + &admin.address(), + asset1_balance - asset1_deposit_amount, + ) + .assert_asset_balance_eq( + &asset2.clone().into(), + &admin.address(), + asset2_balance - asset2_deposit_amount, + ); + + // Redeem both assets + let base_token_balance_before_redeem = robot.query_base_token_balance(admin.address()); + // Redeem + let base_token_balance_after_redeem = robot + .redeem_all(None, Unwrap::Ok, &admin) + .query_base_token_balance(admin.address()); + let base_tokens_received = base_token_balance_after_redeem - base_token_balance_before_redeem; + + let receive_choice = ReceiveChoice::Underlying; + let max_rel_diff = "0.000000001"; // One unit lost due to rounding + + robot + .zap_base_tokens( + base_tokens_received, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + asset1.clone().into(), + asset1_deposit_amount, + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zap_base_tokens( + base_tokens_received, + None, + receive_choice.clone(), + vec![AssetUnchecked::new( + asset2.clone().into(), + asset2_deposit_amount, + )], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zap_base_tokens( + base_tokens_received, + None, + receive_choice.clone(), + vec![ + AssetUnchecked::new(asset1.clone().into(), asset1_deposit_amount), + AssetUnchecked::new(asset2.clone().into(), asset2_deposit_amount), + ], + Unwrap::Err("Minimum amount not met"), + &admin, + ) + .zap_base_tokens( + base_tokens_received, + None, + receive_choice, + vec![ + AssetUnchecked::new( + asset1.clone().into(), + asset1_deposit_amount - Uint128::one(), + ), + AssetUnchecked::new( + asset2.clone().into(), + asset2_deposit_amount - Uint128::one(), + ), + ], + Unwrap::Ok, + &admin, + ) + .assert_vault_token_balance_eq(admin.address(), 0u128); + + robot + .assert_asset_balance_approx_eq(asset1, &admin.address(), asset1_balance, max_rel_diff) + .assert_asset_balance_approx_eq(asset2, &admin.address(), asset2_balance, max_rel_diff); +}