diff --git a/Cargo.lock b/Cargo.lock index 777acdd..95bc708 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,11 +9,14 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", - "schemars 0.8.11", + "multi_test", + "schemars 0.8.10", "secret-multi-test", "serde", "shadeswap-shared", - "snafu 0.7.2", + "snafu 0.7.1", + "snip20-reference-impl", + "staking", ] [[package]] @@ -75,6 +78,22 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b" +[[package]] +name = "better-secret-math" +version = "0.1.0" +source = "git+https://github.com/securesecrets/better-secret-math#78e1a9b770626e2b4df036ba17803a22c9427d63" +dependencies = [ + "btr-macros", + "cosmwasm-schema", + "cosmwasm-std", + "derive-from-ext", + "ethnum", + "paste", + "schemars 0.8.10", + "serde", + "thiserror", +] + [[package]] name = "bincode2" version = "2.0.1" @@ -94,6 +113,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "btr-macros" +version = "0.1.0" +source = "git+https://github.com/securesecrets/better-secret-math#78e1a9b770626e2b4df036ba17803a22c9427d63" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bumpalo" version = "3.11.0" @@ -157,7 +186,7 @@ checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" [[package]] name = "cosmwasm-crypto" version = "1.0.0" -source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e505fbf3e0854fe2d683f94abf38e4d20fd5f807" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#f7e2b1dbf11e113e258d796288752503a5012367" dependencies = [ "digest", "ed25519-zebra", @@ -169,18 +198,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" version = "1.0.0" -source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e505fbf3e0854fe2d683f94abf38e4d20fd5f807" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#f7e2b1dbf11e113e258d796288752503a5012367" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.4" -source = "git+https://github.com/CosmWasm/cosmwasm#f6a0485088f1084379a5655bcc2956526290c09f" +version = "1.1.1" +source = "git+https://github.com/CosmWasm/cosmwasm#c3b02c8b63bc2e8daae1bca539717dc0a41a7d2d" dependencies = [ "cosmwasm-schema-derive", - "schemars 0.8.11", + "schemars 0.8.10", "serde", "serde_json", "thiserror", @@ -188,8 +217,8 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.4" -source = "git+https://github.com/CosmWasm/cosmwasm#f6a0485088f1084379a5655bcc2956526290c09f" +version = "1.1.1" +source = "git+https://github.com/CosmWasm/cosmwasm#c3b02c8b63bc2e8daae1bca539717dc0a41a7d2d" dependencies = [ "proc-macro2", "quote", @@ -199,13 +228,13 @@ dependencies = [ [[package]] name = "cosmwasm-std" version = "1.0.0" -source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e505fbf3e0854fe2d683f94abf38e4d20fd5f807" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#f7e2b1dbf11e113e258d796288752503a5012367" dependencies = [ "base64 0.13.0", "cosmwasm-crypto", "cosmwasm-derive", "forward_ref", - "schemars 0.8.11", + "schemars 0.8.10", "serde", "serde-json-wasm", "thiserror", @@ -215,7 +244,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" version = "1.0.0" -source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e505fbf3e0854fe2d683f94abf38e4d20fd5f807" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#f7e2b1dbf11e113e258d796288752503a5012367" dependencies = [ "cosmwasm-std", "serde", @@ -291,6 +320,18 @@ dependencies = [ "syn", ] +[[package]] +name = "derive-from-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cd05fe6590ff35c134f88e85306845490180476af05159889bf5312e035f547" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "syn-unnamed-struct", +] + [[package]] name = "digest" version = "0.9.0" @@ -363,18 +404,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ethnum" +version = "1.2.1" +source = "git+https://github.com/securesecrets/ethnum-rs#1354c8edfdc50125a4f84ea7e3a02ffa927e3cac" +dependencies = [ + "cosmwasm-std", + "schemars 0.8.10", + "serde", +] + [[package]] name = "factory" version = "0.1.0" dependencies = [ + "amm_pair", "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", - "schemars 0.8.11", + "multi_test", + "query-authentication", + "schemars 0.8.10", "secret-multi-test", "serde", "shadeswap-shared", - "snafu 0.7.2", + "snafu 0.7.1", + "snip20-reference-impl", ] [[package]] @@ -480,9 +535,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "js-sys" @@ -514,9 +569,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.135" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "log" @@ -538,12 +593,37 @@ dependencies = [ "cosmwasm-storage", "rand_chacha 0.2.2", "rand_core 0.5.1", - "schemars 0.8.11", + "schemars 0.8.10", "secret-toolkit", "serde", "sha2", "shadeswap-shared", - "snafu 0.7.2", + "snafu 0.7.1", + "subtle", +] + +[[package]] +name = "multi_test" +version = "0.1.0" +dependencies = [ + "amm_pair", + "chrono", + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-storage", + "factory", + "lp-token", + "query-authentication", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "schemars 0.8.10", + "secret-multi-test", + "serde", + "sha2", + "shadeswap-shared", + "snafu 0.7.1", + "snip20-reference-impl", + "staking", "subtle", ] @@ -567,7 +647,7 @@ dependencies = [ "query-authentication", "rand", "rs_merkle", - "schemars 0.8.11", + "schemars 0.8.10", "secretcli", "serde", "serde_json", @@ -596,9 +676,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.15.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "opaque-debug" @@ -606,6 +686,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + [[package]] name = "pkcs8" version = "0.8.0" @@ -625,9 +711,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.46" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -665,7 +751,7 @@ dependencies = [ "cosmwasm-std", "remain", "ripemd160", - "schemars 0.8.11", + "schemars 0.8.10", "secp256k1", "serde", "sha2", @@ -767,12 +853,16 @@ dependencies = [ name = "router" version = "0.1.0" dependencies = [ + "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", - "schemars 0.8.11", + "multi_test", + "schemars 0.8.10", + "secret-multi-test", "serde", "shadeswap-shared", - "snafu 0.7.2", + "snafu 0.7.1", + "snip20-reference-impl", ] [[package]] @@ -802,12 +892,12 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.11" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307" +checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed" dependencies = [ "dyn-clone", - "schemars_derive 0.8.11", + "schemars_derive 0.8.10", "serde", "serde_json", ] @@ -826,9 +916,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.11" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9" +checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743" dependencies = [ "proc-macro2", "quote", @@ -870,7 +960,7 @@ dependencies = [ [[package]] name = "secret-multi-test" version = "0.13.4" -source = "git+https://github.com/securesecrets/secret-plus-utils#8034b523a7a9842b2369a8bec29b48bd9282a906" +source = "git+https://github.com/securesecrets/secret-plus-utils#19ef9752f0d9dd0e3ff3dac8720ff545c65b831c" dependencies = [ "anyhow", "cosmwasm-std", @@ -879,7 +969,7 @@ dependencies = [ "itertools", "nanoid", "prost", - "schemars 0.8.11", + "schemars 0.8.10", "secret-storage-plus", "secret-utils", "serde", @@ -889,18 +979,19 @@ dependencies = [ [[package]] name = "secret-storage-plus" version = "0.13.4" -source = "git+https://github.com/securesecrets/secret-plus-utils#8034b523a7a9842b2369a8bec29b48bd9282a906" +source = "git+https://github.com/securesecrets/secret-plus-utils#19ef9752f0d9dd0e3ff3dac8720ff545c65b831c" dependencies = [ + "better-secret-math", "bincode2", "cosmwasm-std", - "schemars 0.8.11", + "schemars 0.8.10", "serde", ] [[package]] name = "secret-toolkit" -version = "0.5.0" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +version = "0.4.0" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "secret-toolkit-crypto", "secret-toolkit-permit", @@ -915,7 +1006,7 @@ dependencies = [ [[package]] name = "secret-toolkit-crypto" version = "0.3.0" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "cosmwasm-std", "rand_chacha 0.2.2", @@ -926,13 +1017,13 @@ dependencies = [ [[package]] name = "secret-toolkit-permit" version = "0.3.1" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "bech32", "cosmwasm-std", "remain", "ripemd160", - "schemars 0.8.11", + "schemars 0.8.10", "secret-toolkit-crypto", "serde", ] @@ -940,21 +1031,21 @@ dependencies = [ [[package]] name = "secret-toolkit-serialization" version = "0.3.0" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "bincode2", "cosmwasm-std", - "schemars 0.8.11", + "schemars 0.8.10", "serde", ] [[package]] name = "secret-toolkit-snip20" version = "0.3.0" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "cosmwasm-std", - "schemars 0.8.11", + "schemars 0.8.10", "secret-toolkit-utils", "serde", ] @@ -962,18 +1053,18 @@ dependencies = [ [[package]] name = "secret-toolkit-snip721" version = "0.3.0" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "cosmwasm-std", - "schemars 0.8.11", + "schemars 0.8.10", "secret-toolkit-utils", "serde", ] [[package]] name = "secret-toolkit-storage" -version = "0.5.0" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +version = "0.4.1" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "cosmwasm-std", "cosmwasm-storage", @@ -984,18 +1075,18 @@ dependencies = [ [[package]] name = "secret-toolkit-utils" version = "0.3.1" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "cosmwasm-std", "cosmwasm-storage", - "schemars 0.8.11", + "schemars 0.8.10", "serde", ] [[package]] name = "secret-toolkit-viewing-key" version = "0.3.0" -source = "git+https://github.com/scrtlabs/secret-toolkit?branch=cosmwasm-v1.0#0d0531c83b429b54b01926d2cacbc0ed6e7893fd" +source = "git+https://github.com/scrtlabs/secret-toolkit?rev=8380c00#8380c00d4abb4585e02ba2d2bab8194aff52743e" dependencies = [ "base64 0.11.0", "cosmwasm-std", @@ -1010,10 +1101,10 @@ dependencies = [ [[package]] name = "secret-utils" version = "0.13.4" -source = "git+https://github.com/securesecrets/secret-plus-utils#8034b523a7a9842b2369a8bec29b48bd9282a906" +source = "git+https://github.com/securesecrets/secret-plus-utils#19ef9752f0d9dd0e3ff3dac8720ff545c65b831c" dependencies = [ "cosmwasm-std", - "schemars 0.8.11", + "schemars 0.8.10", "serde", "thiserror", ] @@ -1028,9 +1119,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.145" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" dependencies = [ "serde_derive", ] @@ -1046,9 +1137,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.145" +version = "1.0.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", @@ -1079,9 +1170,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.86" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" dependencies = [ "itoa", "ryu", @@ -1112,11 +1203,11 @@ dependencies = [ "query-authentication", "rand_chacha 0.2.2", "rand_core 0.5.1", - "schemars 0.8.11", + "schemars 0.8.10", "secret-multi-test", "serde", "sha2", - "snafu 0.7.2", + "snafu 0.7.1", "snip20-reference-impl", "subtle", ] @@ -1143,12 +1234,12 @@ dependencies = [ [[package]] name = "snafu" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd726aec4ebad65756394ff89a9b9598793d4e30121cd71690244c1e497b3aee" +checksum = "5177903bf45656592d9eb5c0e22f408fc023aae51dbe2088889b71633ba451f2" dependencies = [ "doc-comment", - "snafu-derive 0.7.2", + "snafu-derive 0.7.1", ] [[package]] @@ -1164,9 +1255,9 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712529e9b0b014eabaa345b38e06032767e3dc393e8b017e853b1d7247094e74" +checksum = "410b26ed97440d90ced3e2488c868d56a86e2064f5d7d6f417909b286afe25e5" dependencies = [ "heck", "proc-macro2", @@ -1185,7 +1276,7 @@ dependencies = [ "cosmwasm-storage", "rand_chacha 0.2.2", "rand_core 0.5.1", - "schemars 0.8.11", + "schemars 0.8.10", "secret-toolkit", "serde", "sha2", @@ -1210,12 +1301,13 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cosmwasm-storage", + "multi_test", "query-authentication", - "schemars 0.8.11", + "schemars 0.8.10", "secret-multi-test", "serde", "shadeswap-shared", - "snafu 0.7.2", + "snafu 0.7.1", "snip20-reference-impl", ] @@ -1233,29 +1325,40 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.102" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn-unnamed-struct" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0794191b3a4553c98f8f5302470618fdd9bd533a8314d06dab0e70a4de0269" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" dependencies = [ "proc-macro2", "quote", @@ -1281,9 +1384,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "uint" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" +checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" dependencies = [ "byteorder", "crunchy", @@ -1293,9 +1396,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" [[package]] name = "version_check" diff --git a/Cargo.toml b/Cargo.toml index 318767b..db6897c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,7 @@ members = [ "contracts/lp_token", "contracts/staking", "packages/network_integration", - # "packages/multi-test" - # "packages/cosmwasm_math_compat", + "packages/multi_test" ] [profile.release] diff --git a/contracts/amm_pair/.editorconfig b/contracts/amm_pair/.editorconfig deleted file mode 100644 index 43cda4c..0000000 --- a/contracts/amm_pair/.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/contracts/amm_pair/.gitignore b/contracts/amm_pair/.gitignore deleted file mode 100644 index 961cca6..0000000 --- a/contracts/amm_pair/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -# Build results -/target -Cargo.lock -contract.wasm* - -# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) -.cargo-ok - -# Text file backups -**/*.rs.bk - -# macOS -.DS_Store - -# IDEs -*.iml -.idea diff --git a/contracts/amm_pair/Cargo.toml b/contracts/amm_pair/Cargo.toml index bda3378..e369f30 100644 --- a/contracts/amm_pair/Cargo.toml +++ b/contracts/amm_pair/Cargo.toml @@ -33,10 +33,11 @@ serde = {version = "1.0.114", default-features = false, features = [ # cw2 = "0.15.0" shadeswap-shared = {path = "../../packages/shadeswap-shared"} -# staking = {path = "../../contracts/staking"} -# snip20-reference-impl = {path ="../../contracts/snip20"} -# lp-token = {path ="../../contracts/lp_token"} snafu = {version = "0.7.1"} -secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } + [dev-dependencies] -cosmwasm-schema = {git = "https://github.com/CosmWasm/cosmwasm"} +cosmwasm-schema = { git = "https://github.com/CosmWasm/cosmwasm"} +snip20-reference-impl = {path ="../../contracts/snip20"} +secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } +multi_test = {path = "../../packages/multi_test"} +staking = {path = "../../contracts/staking"} diff --git a/contracts/amm_pair/NOTICE b/contracts/amm_pair/NOTICE deleted file mode 100644 index 1b2469e..0000000 --- a/contracts/amm_pair/NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2022 Tony - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/contracts/amm_pair/README.md b/contracts/amm_pair/README.md index 5fd3a39..0063cc8 100644 --- a/contracts/amm_pair/README.md +++ b/contracts/amm_pair/README.md @@ -48,7 +48,7 @@ The Contract to hold Pair Between Swap Tokens. |-------------------|----------------------------------|----------------------------------------------------------------------------|----------| | pair | TokenPair | Token Pair to hold two token | no | | lp_token_contract | ContractInstantiationInfo | ContractInstantiationInfo | no | -| factory_info | ContractLink | The token that will be airdropped | no | +| factory_info | Contract | The token that will be airdropped | no | | prng_seed | Binary | seed to use for viewing key | no | | callback | Callback | Callback to AmmPair Contract to register LP Token | yes | | entropy | Binary | Use to calculate viewing key | no | @@ -129,8 +129,8 @@ Get information about the token pair. ##### Response ```json { - "liquidity_token": "LP Token ContractLink", - "factory": "Factory ContractLink", + "liquidity_token": "LP Token Contract", + "factory": "Factory Contract", "pair": "Token Pair with two Token Type", "amount_0": "Balance of Token 0", "amount_1": "Balance of Token 1", @@ -151,8 +151,8 @@ Get Estimated Price for amount. ##### Response ```json { - "liquidity_token": "LP Token ContractLink", - "factory": "Factory ContractLink", + "liquidity_token": "LP Token Contract", + "factory": "Factory Contract", "pair": "Token Pair with two Token Type", "amount_0": "Balance of Token 0", "amount_1": "Balance of Token 1", @@ -324,7 +324,7 @@ Swap Native Token. | offer | TokenAmount | Amount and Token Type | no | | expected_return | Uint128 | slippage, amount willing to accept | yes | | to | HumanAddr | The address to remove from LP | yes | -| router_link | ContractLink | Router Contract Info | yes | +| router_link | Contract | Router Contract Info | yes | | callback_signature | Binary | signature to verify snip20 | yes | ##### Response ```json @@ -368,7 +368,7 @@ Swap Native Token. |-----------|----------------|--------------------------------------|----------| | expected_return | Uint128 | slippage, amount willing to accept | yes | | to | HumanAddr | The address to remove from LP | yes | -| router_link | ContractLink | Router Contract Info | yes | +| router_link | Contract | Router Contract Info | yes | | callback_signature | Binary | signature to verify snip20 | yes | ##### Response ```json diff --git a/contracts/amm_pair/deploy.sh b/contracts/amm_pair/deploy.sh deleted file mode 100644 index 50fa48f..0000000 --- a/contracts/amm_pair/deploy.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# build and start blockchain -# make start-server -CODE_ID=0 -ADDRESS="" -INIT='{"symbol": "ETHU"}' -LABEL="shade_pair_contract" -docker exec -i secretdev bash -c "secretd tx compute store /root/code/contract.wasm.gz --from a --gas=auto --gas-adjustment=1.15 -y --keyring-backend test" > createresult -# # # /root/code/contract.wasm.gz -#docker exec -i secretdev cat < createresult -docker exec -i secretdev secretd query compute list-code > result.json -# get 1 id and creator -ADDRESS=$(jq .[0] -r < result.json | jq ."creator") -CODE_ID=$(jq .[0] -r < result.json | jq ."id") -echo $ADDRESS -echo $CODE_ID -LASTID=$(jq '. | length' < result.json) -echo $LASTID -docker exec -i secretdev secretd tx compute instantiate 1 "$INIT" --from a --label $LABEL -y --keyring-backend test > tx.json -TX=$(jq ."txhash" < tx.json ) -echo $TX -docker exec -i secretdev secretd query compute list-contract-by-code $LASTID -#docker exec -i secretdev bash -c "cd ./code && secretd tx compute store contract.wasm.gz --from a --gas=auto --gas-adjustment=1.15 -y --keyring-backend test /root/code/contract.wasm.gz" -#docker exec secretdev secretd tx compute store ./code/contract.wasm.gz --from a --gas 1000000 -y --keyring-backend test /root/code/contract.wasm.gz \ No newline at end of file diff --git a/contracts/amm_pair/rustfmt.toml b/contracts/amm_pair/rustfmt.toml deleted file mode 100644 index 432ac7a..0000000 --- a/contracts/amm_pair/rustfmt.toml +++ /dev/null @@ -1,15 +0,0 @@ -# stable -newline_style = "unix" -hard_tabs = false -tab_spaces = 4 - -# unstable... should we require `rustup run nightly cargo fmt` ? -# or just update the style guide when they are stable? -#fn_single_line = true -#format_code_in_doc_comments = true -#overflow_delimited_expr = true -#reorder_impl_items = true -#struct_field_align_threshold = 20 -#struct_lit_single_line = true -#report_todo = "Always" - diff --git a/contracts/amm_pair/secretcli b/contracts/amm_pair/secretcli deleted file mode 100644 index 0f488e5..0000000 Binary files a/contracts/amm_pair/secretcli and /dev/null differ diff --git a/contracts/amm_pair/src/contract.rs b/contracts/amm_pair/src/contract.rs index 1dee598..f6fb358 100644 --- a/contracts/amm_pair/src/contract.rs +++ b/contracts/amm_pair/src/contract.rs @@ -10,18 +10,17 @@ use crate::{ }; use cosmwasm_std::{ - entry_point, from_binary, to_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, - Reply, Response, StdError, StdResult, SubMsg, SubMsgResult, Uint128, WasmMsg, BankMsg, Coin, + entry_point, from_binary, to_binary, Addr, BankMsg, Binary, Coin, CosmosMsg, Deps, DepsMut, + Env, MessageInfo, Reply, Response, StdError, StdResult, SubMsg, SubMsgResult, Uint128, WasmMsg, }; use shadeswap_shared::{ - core::{ - admin_r, admin_w, apply_admin_guard, create_viewing_key, set_admin_guard, ContractLink, - TokenAmount, TokenType, - }, + admin::helpers::{validate_admin, AdminPermissions}, + core::{create_viewing_key, TokenAmount, TokenType}, lp_token::{InitConfig, InstantiateMsg}, msg::amm_pair::{ExecuteMsg, InitMsg, InvokeMsg, QueryMsg, QueryMsgResponse}, - utils::{pad_query_result, pad_response_result}, - Contract, snip20::helpers::send_msg, + snip20::helpers::send_msg, + utils::{pad_query_result, pad_response_result, try_addr_validate_option}, + Contract, }; const AMM_PAIR_CONTRACT_VERSION: u32 = 1; @@ -33,7 +32,7 @@ pub const BLOCK_SIZE: usize = 256; pub fn instantiate( deps: DepsMut, env: Env, - _info: MessageInfo, + info: MessageInfo, msg: InitMsg, ) -> StdResult { if msg.pair.0 == msg.pair.1 { @@ -44,7 +43,7 @@ pub fn instantiate( let mut response = Response::new(); let mut messages = vec![]; - let viewing_key = create_viewing_key(&env, &_info, msg.prng_seed.clone(), msg.entropy.clone()); + let viewing_key = create_viewing_key(&env, &info, msg.prng_seed.clone(), msg.entropy.clone()); register_pair_token(&env, &mut messages, &msg.pair.0, &viewing_key)?; register_pair_token(&env, &mut messages, &msg.pair.1, &viewing_key)?; response = response.add_messages(messages); @@ -54,7 +53,7 @@ pub fn instantiate( "SHADESWAP Liquidity Provider (LP) token for {}-{}", &msg.pair.0, &msg.pair.1 ), - admin: Some(env.contract.address.clone()), + admin: Some(env.contract.address.to_string()), symbol: format!( "{}/{} LP", query_token_symbol(deps.querier, &msg.pair.0)?, @@ -86,21 +85,9 @@ pub fn instantiate( INSTANTIATE_LP_TOKEN_REPLY_ID, )); - match msg.callback { - Some(c) => { - response = response.add_message(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: c.contract.address.to_string(), - code_hash: c.contract.code_hash, - msg: c.msg, - funds: vec![], - })) - } - None => (), - } - let config = Config { factory_contract: msg.factory_info.clone(), - lp_token: ContractLink { + lp_token: Contract { code_hash: msg.lp_token_contract.code_hash, address: Addr::unchecked(""), }, @@ -110,14 +97,12 @@ pub fn instantiate( staking_contract: None, staking_contract_init: msg.staking_contract, prng_seed: msg.prng_seed, + admin_auth: msg.admin_auth, }; config_w(deps.storage).save(&config)?; - match msg.admin { - Some(admin) => admin_w(deps.storage).save(&admin)?, - None => (), - } - Ok(response.add_attribute("created_exchange_address", env.contract.address.to_string())) + response.data = Some(env.contract.address.as_bytes().into()); + Ok(response) } #[entry_point] @@ -126,34 +111,55 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S match msg { ExecuteMsg::Receive { from, amount, msg, .. - } => receiver_callback(deps, env, info, from, amount, msg), + } => { + let checked_addr = deps.api.addr_validate(&from)?; + receiver_callback(deps, env, info, checked_addr, amount, msg) + } ExecuteMsg::AddLiquidityToAMMContract { deposit, expected_return, staking, } => add_liquidity(deps, env, &info, deposit, expected_return, staking), ExecuteMsg::SetCustomPairFee { custom_fee } => { - apply_admin_guard(&info.sender, deps.storage)?; let mut config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; config.custom_fee = custom_fee; config_w(deps.storage).save(&config)?; Ok(Response::default()) } - ExecuteMsg::SetAdmin { admin } => set_admin_guard(deps.storage, info, admin), ExecuteMsg::AddWhiteListAddress { address } => { - apply_admin_guard(&info.sender, deps.storage)?; - add_address_to_whitelist(deps.storage, address) + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; + add_address_to_whitelist(deps.storage, deps.api.addr_validate(&address)?) } ExecuteMsg::RemoveWhitelistAddresses { addresses } => { - apply_admin_guard(&info.sender, deps.storage)?; - remove_addresses_from_whitelist(deps.storage, addresses, env) + let config = config_r(deps.storage).load()?; + let checked_addresses = addresses + .iter() + .flat_map(|v| deps.api.addr_validate(&v)) + .collect(); + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; + remove_addresses_from_whitelist(deps.storage, checked_addresses) } ExecuteMsg::SwapTokens { offer, expected_return, to, - router_link, - callback_signature, } => { if !offer.token.is_native_token() { return Err(StdError::generic_err("Use the receive interface")); @@ -161,37 +167,58 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S offer.assert_sent_native_token_balance(&info)?; let config_settings = config_r(deps.storage).load()?; let sender = info.sender.clone(); + let checked_to = try_addr_validate_option(deps.api, to)?; swap( deps, env, config_settings, sender, - to, + checked_to, offer, expected_return, - router_link, - callback_signature, ) } ExecuteMsg::SetViewingKey { viewing_key } => update_viewing_key(env, deps, viewing_key), + ExecuteMsg::SetConfig { admin_auth } => { + let mut config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; + if let Some(admin_auth) = admin_auth { + config.admin_auth = admin_auth; + } + Ok(Response::default()) + } ExecuteMsg::RecoverFunds { token, amount, to, msg, } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; let send_msg = match token { - TokenType::CustomToken { contract_addr, token_code_hash } => vec![send_msg( - to, + TokenType::CustomToken { + contract_addr, + token_code_hash, + } => vec![send_msg( + deps.api.addr_validate(&to)?, amount, msg, None, None, - &Contract{ + &Contract { address: contract_addr, - code_hash: token_code_hash - } + code_hash: token_code_hash, + }, )?], TokenType::NativeToken { denom } => vec![CosmosMsg::Bank(BankMsg::Send { to_address: to.to_string(), @@ -226,8 +253,6 @@ fn receiver_callback( InvokeMsg::SwapTokens { to, expected_return, - router_link, - callback_signature, } => { for token in config.pair.into_iter() { match token { @@ -238,20 +263,21 @@ fn receiver_callback( amount, }; + let checked_to = + Some(deps.api.addr_validate(&to.ok_or_else(|| { + StdError::generic_err( + "No recipient sent with invoke.".to_string(), + ) + })?)?); + return swap( deps, env, config, from, - Some(to.ok_or_else(|| { - StdError::generic_err( - "No recipient sent with invoke.".to_string(), - ) - })?), + checked_to, offer, expected_return, - router_link, - callback_signature, ); } } @@ -269,8 +295,12 @@ fn receiver_callback( "LP Token was not sent to remove liquidity.".to_string(), )); } + match from { - Some(address) => remove_liquidity(deps, env, amount, address), + Some(address) => { + let checked_address = deps.api.addr_validate(&address)?; + remove_liquidity(deps, env, amount, checked_address) + } None => remove_liquidity(deps, env, amount, from_caller), } } @@ -310,12 +340,6 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { let data = load_trade_history_query(deps, pagination)?; to_binary(&QueryMsgResponse::GetTradeHistory { data }) } - QueryMsg::GetAdmin {} => { - let admin_address = admin_r(deps.storage).load()?; - to_binary(&QueryMsgResponse::GetAdmin { - address: admin_address, - }) - } QueryMsg::GetWhiteListAddress {} => { let stored_addr = whitelist_r(deps.storage).load()?; to_binary(&QueryMsgResponse::GetWhiteListAddress { @@ -340,8 +364,8 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { } QueryMsg::SwapSimulation { offer } => swap_simulation(deps, env, offer), QueryMsg::GetShadeDaoInfo {} => get_shade_dao_info(deps), - QueryMsg::GetEstimatedLiquidity { deposit, slippage } => { - get_estimated_lp_token(deps, env, deposit, slippage) + QueryMsg::GetEstimatedLiquidity { deposit } => { + get_estimated_lp_token(deps, env, deposit) } QueryMsg::GetConfig {} => { let config = config_r(deps.storage).load()?; @@ -359,7 +383,7 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { } #[entry_point] -pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { +pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> StdResult { pad_response_result( match (msg.id, msg.result) { (INSTANTIATE_LP_TOKEN_REPLY_ID, SubMsgResult::Ok(s)) => match s.data { @@ -367,14 +391,18 @@ pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { let contract_address = deps.api.addr_validate(&String::from_utf8(x.to_vec())?)?; let config = config_r(deps.storage).load()?; - register_lp_token( + let mut response = register_lp_token( deps, - _env, + &env, Contract { address: contract_address, code_hash: config.lp_token.code_hash, }, - ) + )?; + + response.data = Some(env.contract.address.to_string().as_bytes().into()); + + Ok(response) } None => Err(StdError::generic_err(format!("Unknown reply id"))), }, @@ -382,9 +410,9 @@ pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { Some(x) => { let contract_address = String::from_utf8(x.to_vec())?; let config = config_r(deps.storage).load()?; - set_staking_contract( + let mut response = set_staking_contract( deps.storage, - Some(ContractLink { + Some(Contract { address: deps.api.addr_validate(&contract_address)?, code_hash: config .staking_contract_init @@ -394,7 +422,11 @@ pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { .contract_info .code_hash, }), - ) + )?; + + response.data = Some(env.contract.address.to_string().as_bytes().into()); + + Ok(response) } None => Err(StdError::generic_err(format!("Unknown reply id"))), }, diff --git a/contracts/amm_pair/src/operations.rs b/contracts/amm_pair/src/operations.rs index ecf76b0..c431d2b 100644 --- a/contracts/amm_pair/src/operations.rs +++ b/contracts/amm_pair/src/operations.rs @@ -11,11 +11,10 @@ use cosmwasm_std::{ }; use shadeswap_shared::{ amm_pair::AMMSettings, - core::{admin_r, ContractLink, Fee, TokenAmount, TokenPairAmount, TokenType, ViewingKey}, + core::{Fee, TokenAmount, TokenPairAmount, TokenType, ViewingKey}, msg::{ amm_pair::{QueryMsgResponse, SwapInfo, SwapResult, TradeHistory}, factory::{QueryMsg as FactoryQueryMsg, QueryResponse as FactoryQueryResponse}, - router::ExecuteMsg as RouterExecuteMsg, staking::{InitMsg as StakingInitMsg, InvokeMsg as StakingInvokeMsg}, }, snip20::{ @@ -79,12 +78,12 @@ fn store_trade_history(deps: DepsMut, trade_history: &TradeHistory) -> StdResult pub fn register_lp_token( deps: DepsMut, - env: Env, + env: &Env, lp_token_address: Contract, ) -> StdResult { let mut config = config_r(deps.storage).load()?; - config.lp_token = ContractLink { + config.lp_token = Contract { address: lp_token_address.address.clone(), code_hash: lp_token_address.code_hash.clone(), }; @@ -108,18 +107,19 @@ pub fn register_lp_token( msg: to_binary(&StakingInitMsg { daily_reward_amount: c.daily_reward_amount, reward_token: c.reward_token.clone(), - pair_contract: ContractLink { + pair_contract: Contract { address: env.contract.address.clone(), code_hash: env.contract.code_hash.clone(), }, prng_seed: config.prng_seed.clone(), - lp_token: ContractLink { + lp_token: Contract { address: lp_token_address.address.clone(), code_hash: lp_token_address.code_hash.clone(), }, authenticator: factory_config.authenticator, //default to same admin as amm_pair - admin: admin_r(deps.storage).load()?, + admin_auth: factory_config.admin_auth, + valid_to: c.valid_to, })?, code_hash: c.contract_info.code_hash.clone(), funds: vec![], @@ -181,7 +181,7 @@ pub fn query_calculate_price( &env, &amm_settings, &config_settings, - &offer, + &offer, exclude_fee, )?; Ok(swap_result) @@ -195,19 +195,11 @@ pub fn swap( recipient: Option, offer: TokenAmount, expected_return: Option, - router_link: Option, - callback_signature: Option, ) -> StdResult { let swaper_receiver = recipient.unwrap_or(sender); let amm_settings = query_factory_config(deps.as_ref(), &config.factory_contract)?.amm_settings; - let swap_result = calculate_swap_result( - deps.as_ref(), - &env, - &amm_settings, - &config, - &offer, - None, - )?; + let swap_result = + calculate_swap_result(deps.as_ref(), &env, &amm_settings, &config, &offer, None)?; // check for the slippage expected value compare to actual value if let Some(expected_return) = expected_return { @@ -219,7 +211,7 @@ pub fn swap( } // Send Shade_Dao_Fee back to shade_dao_address which is 0.1% - let mut messages = Vec::with_capacity(3); + let mut messages = Vec::with_capacity(2); if swap_result.shade_dao_fee_amount > Uint128::zero() { match &offer.token { TokenType::CustomToken { @@ -285,41 +277,12 @@ pub fn swap( store_trade_history(deps, &trade_history)?; - match &router_link { - Some(r) => { - if let Some(c) = callback_signature { - messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: r.address.to_string(), - code_hash: r.code_hash.to_string(), - funds: vec![], - msg: to_binary(&RouterExecuteMsg::SwapCallBack { - last_token_out: TokenAmount { - token: token.clone(), - amount: swap_result.result.return_amount, - }, - signature: c - })?, - })); - } else { - return Err(StdError::generic_err("Callback signature needs to be passed with router contract.")) - } - } - None => (), - } - Ok(Response::new().add_messages(messages).add_attributes(vec![ - Attribute::new("action", "swap"), - // Attribute::new("offer_token", offer.token), - Attribute::new("offer_amount", offer.amount), - Attribute::new("return_amount", swap_result.result.return_amount), - Attribute::new("lp_fee", swap_result.lp_fee_amount), - Attribute::new("shade_dao_fee", swap_result.shade_dao_fee_amount), - Attribute::new("shade_total_fee", swap_result.total_fee_amount), - ])) + Ok(Response::new().add_messages(messages)) } pub fn set_staking_contract( storage: &mut dyn Storage, - staking_contract: Option, + staking_contract: Option, ) -> StdResult { let mut config = config_w(storage).load()?; @@ -328,17 +291,16 @@ pub fn set_staking_contract( config_w(storage).save(&config)?; // send lp contractLink to staking contract - Ok(Response::new().add_attribute("action", "set_staking_contract")) + Ok(Response::new()) } pub fn get_shade_dao_info(deps: Deps) -> StdResult { - let config_settings = config_r(deps.storage).load()?; - let admin = admin_r(deps.storage).load()?; - let amm_settings = query_factory_config(deps, &config_settings.factory_contract)?.amm_settings; + let config = config_r(deps.storage).load()?; + let amm_settings = query_factory_config(deps, &config.factory_contract)?.amm_settings; let shade_dao_info = QueryMsgResponse::ShadeDAOInfo { shade_dao_address: amm_settings.shade_dao_address.address.to_string(), shade_dao_fee: amm_settings.shade_dao_fee, - admin_address: admin.to_string(), + admin_auth: config.admin_auth, lp_fee: amm_settings.lp_fee, }; to_binary(&shade_dao_info) @@ -347,14 +309,8 @@ pub fn get_shade_dao_info(deps: Deps) -> StdResult { pub fn swap_simulation(deps: Deps, env: Env, offer: TokenAmount) -> StdResult { let config_settings = config_r(deps.storage).load()?; let amm_settings = query_factory_config(deps, &config_settings.factory_contract)?.amm_settings; - let swap_result = calculate_swap_result( - deps, - &env, - &amm_settings, - &config_settings, - &offer, - None - )?; + let swap_result = + calculate_swap_result(deps, &env, &amm_settings, &config_settings, &offer, None)?; let simulation_result = QueryMsgResponse::SwapSimulation { total_fee_amount: swap_result.total_fee_amount, lp_fee_amount: swap_result.lp_fee_amount, @@ -365,12 +321,7 @@ pub fn swap_simulation(deps: Deps, env: Env, offer: TokenAmount) -> StdResult, -) -> StdResult { +pub fn get_estimated_lp_token(deps: Deps, env: Env, deposit: TokenPairAmount) -> StdResult { let config = config_r(deps.storage).load()?; let Config { pair, @@ -391,11 +342,7 @@ pub fn get_estimated_lp_token( .query_balances(deps, env.contract.address.to_string(), viewing_key.0)?; let pair_contract_pool_liquidity = query_total_supply(deps, &lp_token)?; - let lp_tokens = calculate_lp_tokens( - &deposit, - pool_balances, - pair_contract_pool_liquidity, - )?; + let lp_tokens = calculate_lp_tokens(&deposit, pool_balances, pair_contract_pool_liquidity)?; let response_msg = QueryMsgResponse::EstimatedLiquidity { lp_token: lp_tokens, total_lp_token: pair_contract_pool_liquidity, @@ -452,13 +399,11 @@ pub fn calculate_swap_result( let tokens_pool = get_token_pool_balance(deps, env, config, offer)?; let token0_pool = tokens_pool[0]; let token1_pool = tokens_pool[1]; - // calculate price - // calculate fee let lp_fee = settings.lp_fee; let shade_dao_fee = settings.shade_dao_fee; - let mut lp_fee_amount = Uint128::zero(); - let mut shade_dao_fee_amount = Uint128::zero(); + let lp_fee_amount; + let shade_dao_fee_amount; // calculation fee match &config.custom_fee { Some(f) => { @@ -501,8 +446,7 @@ pub fn add_address_to_whitelist(storage: &mut dyn Storage, address: Addr) -> Std pub fn remove_addresses_from_whitelist( storage: &mut dyn Storage, - addresses_to_remove: Vec, - _env: Env, + addresses_to_remove: Vec ) -> StdResult { let mut addresses = whitelist_r(storage).load()?; for address in addresses_to_remove { @@ -524,17 +468,17 @@ fn get_token_pool_balance( config.viewing_key.0.clone(), )?; if let Some(index) = config.pair.get_token_index(&swap_offer.token) { - let token0_pool = tokens_balances[index]; - let token1_pool = tokens_balances[index ^ 1]; + let token0_pool = tokens_balances[index]; + let token1_pool = tokens_balances[index ^ 1]; - // conver tand get avialble balance - let token0_pool = token0_pool; - let token1_pool = token1_pool; - Ok([token0_pool, token1_pool]) - } - else - { - Err(StdError::generic_err("The offered token is not traded on this contract".to_string())) + // conver tand get avialble balance + let token0_pool = token0_pool; + let token1_pool = token1_pool; + Ok([token0_pool, token1_pool]) + } else { + Err(StdError::generic_err( + "The offered token is not traded on this contract".to_string(), + )) } } @@ -660,19 +604,15 @@ pub fn add_liquidity( } } - let pair_contract_pool_liquidity = - query_total_supply(deps.as_ref(), &lp_token)?; - println!("total pool amount {}", pair_contract_pool_liquidity); - let lp_tokens = calculate_lp_tokens( - &deposit, - pool_balances, - pair_contract_pool_liquidity, - )?; + let pair_contract_pool_liquidity = query_total_supply(deps.as_ref(), &lp_token)?; + let lp_tokens = calculate_lp_tokens(&deposit, pool_balances, pair_contract_pool_liquidity)?; - if let Some(e) = expected_return - { + if let Some(e) = expected_return { if e > lp_tokens { - return Err(StdError::generic_err(format!("Operation returns less then expected ({} < {}).", e, lp_tokens))); + return Err(StdError::generic_err(format!( + "Operation returns less then expected ({} < {}).", + e, lp_tokens + ))); } } @@ -696,7 +636,7 @@ pub fn add_liquidity( }, )?); let invoke_msg = to_binary(&StakingInvokeMsg::Stake { - from: info.sender.clone(), + from: info.sender.to_string(), })?; // SEND LP Token to Staking Contract with Staking Message let msg = to_binary(&SNIP20ExecuteMsg::Send { @@ -767,9 +707,8 @@ fn calculate_lp_tokens( pool_balances: [Uint128; 2], pair_contract_pool_liquidity: Uint128, ) -> Result { - - let mut lp_tokens: Uint128 = Uint128::zero(); - if pair_contract_pool_liquidity == Uint128::zero() { + let lp_tokens: Uint128; + if pair_contract_pool_liquidity.is_zero() { // If user mints new liquidity pool -> liquidity % = sqrt(x * y) where // x and y is amount of token0 and token1 provided let deposit_token0_amount = Uint256::from(deposit.amount_0); @@ -823,16 +762,23 @@ pub fn query_token_symbol(querier: QuerierWrapper, token: &TokenType) -> StdResu )? .symbol); } - TokenType::NativeToken { denom: _ } => Ok("SCRT".to_string()), + TokenType::NativeToken { denom: d } => { + if d == "uscrt" { + Ok("SCRT".to_string()) + } else { + Ok(d.to_string()) + } + } } } struct FactoryConfig { amm_settings: AMMSettings, authenticator: Option, + admin_auth: Contract, } -fn query_factory_config(deps: Deps, factory: &ContractLink) -> StdResult { +fn query_factory_config(deps: Deps, factory: &Contract) -> StdResult { let result: FactoryQueryResponse = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr: factory.address.to_string(), @@ -846,9 +792,11 @@ fn query_factory_config(deps: Deps, factory: &ContractLink) -> StdResult Ok(FactoryConfig { amm_settings, authenticator, + admin_auth, }), _ => Err(StdError::generic_err( "An error occurred while trying to retrieve factory settings.", @@ -858,7 +806,7 @@ fn query_factory_config(deps: Deps, factory: &ContractLink) -> StdResult StdResult { let result: FactoryQueryResponse = @@ -883,7 +831,7 @@ pub fn query_factory_authorize_api_key( } } -pub fn query_total_supply(deps: Deps, lp_token_info: &ContractLink) -> StdResult { +pub fn query_total_supply(deps: Deps, lp_token_info: &Contract) -> StdResult { let result = token_info( &deps.querier, &Contract { @@ -894,9 +842,7 @@ pub fn query_total_supply(deps: Deps, lp_token_info: &ContractLink) -> StdResult if let Some(ts) = result.total_supply { Ok(ts) - } - else - { + } else { return Err(StdError::generic_err("LP token has no available supply.")); } } diff --git a/contracts/amm_pair/src/state.rs b/contracts/amm_pair/src/state.rs index e11f0f5..9ab5b09 100644 --- a/contracts/amm_pair/src/state.rs +++ b/contracts/amm_pair/src/state.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{Storage, Addr, Binary}; use cosmwasm_storage::{singleton, singleton_read, Singleton, ReadonlySingleton, Bucket, ReadonlyBucket, bucket, bucket_read}; use serde::{Deserialize, Serialize}; -use shadeswap_shared::{msg::amm_pair::TradeHistory, core::{ContractLink, TokenPair, CustomFee, ViewingKey}, staking::StakingContractInit}; +use shadeswap_shared::{msg::amm_pair::TradeHistory, core::{TokenPair, CustomFee, ViewingKey}, staking::StakingContractInit, Contract}; pub const PAGINATION_LIMIT: u8 = 30; pub static CONFIG: &[u8] = b"config"; @@ -12,14 +12,15 @@ pub const BLOCK_SIZE: usize = 256; #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] pub struct Config { - pub factory_contract: ContractLink, - pub lp_token: ContractLink, - pub staking_contract: Option, + pub factory_contract: Contract, + pub lp_token: Contract, + pub staking_contract: Option, pub pair: TokenPair, pub viewing_key: ViewingKey, pub custom_fee: Option, pub staking_contract_init: Option, - pub prng_seed: Binary + pub prng_seed: Binary, + pub admin_auth: Contract } #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] diff --git a/contracts/amm_pair/src/test.rs b/contracts/amm_pair/src/test.rs index b7105c1..4ad4eb3 100644 --- a/contracts/amm_pair/src/test.rs +++ b/contracts/amm_pair/src/test.rs @@ -5,7 +5,7 @@ use serde::Deserialize; use serde::Serialize; use shadeswap_shared::amm_pair::AMMSettings; use shadeswap_shared::{ - core::{create_viewing_key, ContractLink, TokenAmount, TokenType}, + core::{create_viewing_key, TokenAmount, TokenType}, msg::amm_pair::InitMsg, }; @@ -23,14 +23,17 @@ use shadeswap_shared::core::ContractInstantiationInfo; #[cfg(test)] pub mod tests { - use super::help_test_lib::{make_init_config, mk_amm_settings, mk_token_pair}; + use shadeswap_shared::Contract; + + + use super::help_test_lib::{make_init_config, mk_amm_settings, mk_token_pair, mk_token_pair_amount, mk_token_pair_custom_addr}; use super::*; use crate::contract::instantiate; use crate::operations::{ add_address_to_whitelist, add_whitelist_address, calculate_hash, is_address_in_whitelist, - swap, + swap, get_estimated_lp_token, calculate_swap_result, }; - use crate::state::trade_count_r; + use crate::state::{trade_count_r, config_w}; use crate::test::help_test_lib::{ mk_custom_token_amount, mk_native_token_pair, mock_custom_env, mock_dependencies, }; @@ -51,16 +54,15 @@ pub mod tests { code_hash: "CODE_HASH".to_string(), id: 0, }, - factory_info: ContractLink { + factory_info: Contract { address: Addr::unchecked("FACTORYADDR"), code_hash: "FACTORYADDR_HASH".to_string(), }, prng_seed: seed.clone(), entropy: entropy.clone(), - admin: Some(mock_info.sender.clone()), + admin_auth: shadeswap_shared::Contract { address: mock_info.sender.clone(), code_hash: "".to_string() }, staking_contract: None, - custom_fee: None, - callback: None, + custom_fee: None }; assert!(instantiate(deps.as_mut(), env.clone(), mock_info.clone(), msg).is_ok()); let test_view_key = @@ -114,16 +116,15 @@ pub mod tests { code_hash: "CODE_HASH".to_string(), id: 0, }, - factory_info: ContractLink { + factory_info: Contract { address: Addr::unchecked("FACTORYADDR"), code_hash: "FACTORYADDR_HASH".to_string(), }, prng_seed: seed.clone(), entropy: entropy.clone(), - admin: Some(mock_info.sender.clone()), + admin_auth: Contract { address: mock_info.sender.clone(), code_hash: "".to_string() }, staking_contract: None, - custom_fee: None, - callback: None, + custom_fee: None }; assert!(instantiate(deps.as_mut(), env.clone(), mock_info.clone(), msg).is_ok()); let address_a = Addr::unchecked("TESTA".to_string()); @@ -178,25 +179,21 @@ pub mod tests { config.factory_contract.address.as_str(), FACTORY_CONTRACT_ADDRESS.clone() ); - let router_contract = ContractLink { + let _router_contract = Contract { address: Addr::unchecked("router".to_string()), code_hash: "".to_string(), }; - let signature = to_binary(&"signature".to_string())?; + let _signature = to_binary(&"signature".to_string())?; let native_swap = swap( deps.as_mut(), env, config, address_a.clone(), None, - mk_custom_token_amount(Uint128::from(1000u128), token_pair.clone()), - None, - Some(router_contract), - Some(signature), + mk_custom_token_amount(Uint128::from(1000u128), &token_pair), + None )?; - let offer_amount = &native_swap.clone().attributes[2]; - assert_eq!(offer_amount.value, 65420.to_string()); - assert_eq!(native_swap.messages.len(), 3); + assert_eq!(native_swap.messages.len(), 2); Ok(()) } @@ -217,46 +214,50 @@ pub mod tests { config, address_a.clone(), None, - mk_custom_token_amount(Uint128::from(1000u128), token_pair.clone()), - None, - None, - None, + mk_custom_token_amount(Uint128::from(1000u128), &token_pair), + None )?; - let offer_amount = &native_swap.clone().attributes[2]; - assert_eq!(offer_amount.value, 65420.to_string()); assert_eq!(native_swap.messages.len(), 2); Ok(()) } #[test] - fn assert_swap_native_snip20_with_router_without_signature_throws_error() -> StdResult<()> { + fn assert_get_estimated_lp_token_with_wrong_token_pair_throws_err() -> StdResult<()> { let mut deps = mock_dependencies(&[]); - let env = mock_custom_env(FACTORY_CONTRACT_ADDRESS); + let env = mock_env(); let token_pair = mk_native_token_pair(); - let config = make_init_config(mk_native_token_pair().clone())?; - let address_a = Addr::unchecked("TESTA".to_string()); - let router_contract = ContractLink { - address: Addr::unchecked("router".to_string()), - code_hash: "".to_string(), - }; - assert_eq!( - config.factory_contract.address.as_str(), - FACTORY_CONTRACT_ADDRESS.clone() - ); - let native_swap = swap( - deps.as_mut(), - env, - config, - address_a.clone(), - None, - mk_custom_token_amount(Uint128::from(1000u128), token_pair.clone()), - None, - Some(router_contract), - None, - ); - match native_swap.unwrap_err() { + let _config = make_init_config(token_pair)?; + config_w(deps.as_mut().storage).save(&_config)?; + let amount = Uint128::new(1000u128); + let result = get_estimated_lp_token(deps.as_ref(), env, + mk_token_pair_amount("TOKEN_A", CUSTOM_TOKEN_2,amount, amount)); + match result.unwrap_err() { + e => assert_eq!(e, StdError::generic_err( + "The provided tokens dont match those managed by the contract.", + )), + } + Ok(()) + } + + #[test] + fn assert_calculate_swap_with_wrong_token_pair_throws_err() -> StdResult<()> { + let deps = mock_dependencies(&[]); + let env = mock_env(); + let _amm_settings = mk_amm_settings(); + let token_pair = mk_token_pair(); + let _config = make_init_config(token_pair.clone())?; + let amount = Uint128::new(1000u128); + let wrong_pair = mk_token_pair_custom_addr("WRONG_TOKEN_A", "WRONG_TOKEN_B"); + let result = calculate_swap_result(deps.as_ref(), + &env, + &_amm_settings, + &_config, + &mk_custom_token_amount(amount, &wrong_pair), + None); + + match result.unwrap_err() { e => assert_eq!(e, StdError::generic_err( - "Callback signature needs to be passed with router contract.", + "The required token WRONG_TOKEN_A, is not presented in this contract.", )), } Ok(()) @@ -287,9 +288,11 @@ pub mod tests { #[cfg(test)] pub mod tests_calculation_price_and_fee { use super::*; + use super::help_test_lib::{mk_token_pair_custom_addr}; use cosmwasm_std::Decimal; + use shadeswap_shared::Contract; use shadeswap_shared::core::{CustomFee, Fee, TokenPairAmount}; use crate::operations::{ @@ -336,6 +339,17 @@ pub mod tests_calculation_price_and_fee { Ok(()) } + #[test] + fn assert_calculate_price_b() -> StdResult<()> { + let price = calculate_price( + Uint128::from(89u128), + Uint128::from(1000000u128), + Uint128::from(1000000u128), + ); + assert_eq!(Uint128::from(88u128), price?); + Ok(()) + } + #[test] fn assert_initial_swap_with_token_success_without_fee() -> StdResult<()> { @@ -394,16 +408,16 @@ pub mod tests_calculation_price_and_fee { #[test] fn assert_calculate_swap_result_without_custom_fee() -> StdResult<()>{ - let custom_fee: Option = None; + let _custom_fee: Option = None; let mut deps = mock_dependencies(&[]); let token_pair = mk_native_token_pair_test_calculation_price_fee(); let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair.clone(), None,Some(LP_TOKEN.to_string()))?; - let address_a = Addr::unchecked("TESTA".to_string()); + let _address_a = Addr::unchecked("TESTA".to_string()); let token_amount = mk_custom_token_amount_test_calculation_price_fee(Uint128::from(2000u128), config.pair.clone()); let amm_settings = shadeswap_shared::amm_pair::AMMSettings { lp_fee: Fee::new(2, 100), shade_dao_fee: Fee::new(3, 100), - shade_dao_address: ContractLink { + shade_dao_address: Contract { address: Addr::unchecked("DAO"), code_hash: "".to_string(), } @@ -427,7 +441,7 @@ pub mod tests_calculation_price_and_fee { let offer_amount: u128 = 2000; let env = mock_custom_env(FACTORY_CONTRACT_ADDRESS); let expected_amount: u128 = 1624; - let expected_lp_fee: u128 = 40; + let _expected_lp_fee: u128 = 40; let address_a = Addr::unchecked("TESTA".to_string()); add_whitelist_address(deps.as_mut().storage, address_a.clone())?; let swap_result = calculate_swap_result(deps.as_mut().as_ref(), &env,&amm_settings, &config, @@ -441,11 +455,11 @@ pub mod tests_calculation_price_and_fee { #[test] fn assert_slippage_swap_result_with_less_return_amount_throw_exception() -> StdResult<()>{ let mut deps = mock_dependencies(&[]); - let amm_settings = mk_amm_settings_a(); + let _amm_settings = mk_amm_settings_a(); let token_pair = mk_token_pair_test_calculation_price_fee(); let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair, None,Some(LP_TOKEN.to_string()))?; let offer_amount: u128 = 2000; - let expected_amount: u128 = 16666; + let _expected_amount: u128 = 16666; let address_a = Addr::unchecked("TESTA".to_string()); let token = config.pair.clone(); let swap_and_test_slippage = swap( @@ -455,9 +469,7 @@ pub mod tests_calculation_price_and_fee { address_a.clone(), Some(address_a.clone()), mk_custom_token_amount_test_calculation_price_fee(Uint128::from(offer_amount), token), - Some(Uint128::from(40000u128)), - None, - None + Some(Uint128::from(40000u128)) ); match swap_and_test_slippage.unwrap_err() { @@ -468,20 +480,49 @@ pub mod tests_calculation_price_and_fee { Ok(()) } - #[test] + #[test] + fn assert_swap_token_wrong_order_throws_exception() -> StdResult<()>{ + let mut deps = mock_dependencies(&[]); + let _amm_settings = mk_amm_settings_a(); + let token_pair = mk_token_pair_test_calculation_price_fee(); + let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair, None,Some(LP_TOKEN.to_string()))?; + let offer_amount: u128 = 2000; + let _expected_amount: u128 = 16666; + let address_a = Addr::unchecked("TESTA".to_string()); + let _token = config.pair.clone(); + let swap_and_test_slippage = swap( + deps.as_mut(), + mock_custom_env(FACTORY_CONTRACT_ADDRESS), + config, + address_a.clone(), + Some(address_a.clone()), + mk_custom_token_amount_test_calculation_price_fee(Uint128::from(offer_amount), + mk_token_pair_custom_addr("CUSTOMER_TOKEN_3", CUSTOM_TOKEN_1)), + Some(Uint128::from(400u128)), + ); + + match swap_and_test_slippage.unwrap_err() { + e => assert_eq!(e, StdError::generic_err( + "The required token CUSTOMER_TOKEN_3, is not presented in this contract.", + )), + } + Ok(()) + } + + #[test] fn assert_slippage_swap_result_with_higher_return_amount_success() -> StdResult<()>{ let mut deps = mock_dependencies(&[]); - let amm_settings = mk_amm_settings_a(); + let _amm_settings = mk_amm_settings_a(); let token_pair = mk_token_pair_test_calculation_price_fee(); let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair, None,Some(LP_TOKEN.to_string()))?; let offer_amount: u128 = 2000; let address_a = "TESTA".to_string(); let token = config.pair.clone(); - let router_contract = ContractLink{ + let _router_contract = Contract{ address: Addr::unchecked("".to_string()), code_hash: "".to_string() }; - let signature = to_binary(&"signature".to_string())?; + let _signature = to_binary(&"signature".to_string())?; let swap_and_test_slippage = swap( deps.as_mut(), mock_custom_env(FACTORY_CONTRACT_ADDRESS), @@ -489,13 +530,11 @@ pub mod tests_calculation_price_and_fee { Addr::unchecked(address_a.clone()), Some(Addr::unchecked(address_a.clone())), mk_custom_token_amount_test_calculation_price_fee(Uint128::from(offer_amount), token), - Some(Uint128::from(400u128)), - Some(router_contract), - Some(signature) + Some(Uint128::from(400u128)) ); assert_eq!( - swap_and_test_slippage.unwrap().attributes[2].value, - 1228.to_string()); + swap_and_test_slippage.unwrap().messages.len(), + 2); Ok(()) } @@ -503,7 +542,7 @@ pub mod tests_calculation_price_and_fee { fn assert_slippage_add_liqudity_with_less_expected_throw_error() -> StdResult<()>{ let mut deps = mock_dependencies(&[]); let token_pair = mk_token_pair_test_calculation_price_fee(); - let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair.clone(), None,Some(LP_TOKEN.to_string()))?; + let _config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair.clone(), None,Some(LP_TOKEN.to_string()))?; let mock_info = mock_info("Sender", &[]); let add_liquidity_with_err = add_liquidity( deps.as_mut(), @@ -530,15 +569,15 @@ pub mod tests_calculation_price_and_fee { #[test] fn assert_slippage_add_liqudity_with_equal_expected_success() -> StdResult<()>{ let mut deps = mock_dependencies(&[]); - let amm_settings = mk_amm_settings_a(); + let _amm_settings = mk_amm_settings_a(); let token_pair = mk_token_pair_test_calculation_price_fee(); let env = mock_env(); let mock_info = mock_info("Sender", &[]); let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair.clone(), None, Some(LP_TOKEN.to_string()))?; - let offer_amount: u128 = 2000; - let address_a = "TESTA".to_string(); - let token = config.pair.clone(); - let add_liquidity_with_err = add_liquidity( + let _offer_amount: u128 = 2000; + let _address_a = "TESTA".to_string(); + let _token = config.pair.clone(); + let _add_liquidity_with_err = add_liquidity( deps.as_mut(), env.clone(), &mock_info, @@ -556,15 +595,15 @@ pub mod tests_calculation_price_and_fee { #[test] fn assert_slippage_add_liqudity_with_more_then_expected_test_success() -> StdResult<()>{ let mut deps = mock_dependencies(&[]); - let amm_settings = mk_amm_settings_a(); + let _amm_settings = mk_amm_settings_a(); let token_pair = mk_token_pair_test_calculation_price_fee(); let env = mock_env(); let mock_info = mock_info("Sender", &[]); let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair.clone(), None, Some(LP_TOKEN.to_string()))?; - let offer_amount: u128 = 2000; - let address_a = "TESTA".to_string(); - let token = config.pair.clone(); - let add_liquidity_with_err = add_liquidity( + let _offer_amount: u128 = 2000; + let _address_a = "TESTA".to_string(); + let _token = config.pair.clone(); + let _add_liquidity_with_err = add_liquidity( deps.as_mut(), env.clone(), &mock_info, @@ -585,8 +624,8 @@ pub mod tests_calculation_price_and_fee { let token_pair = mk_token_pair_test_calculation_price_fee(); let env = mock_env(); let mock_info = mock_info("Sender", &[]); - let config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair.clone(), None, Some(LP_TOKEN.to_string()))?; - let add_liquidity_with_success = add_liquidity( + let _config = make_init_config_test_calculate_price_fee(deps.as_mut(), token_pair.clone(), None, Some(LP_TOKEN.to_string()))?; + let _add_liquidity_with_success = add_liquidity( deps.as_mut(), env.clone(), &mock_info, @@ -610,9 +649,10 @@ pub mod help_test_lib { from_slice, BalanceResponse, BlockInfo, Coin, ContractInfo, Empty, OwnedDeps, Timestamp, TransactionInfo, }; + use shadeswap_shared::Contract; use crate::contract::instantiate; - use shadeswap_shared::core::{CustomFee, Fee, TokenPair}; + use shadeswap_shared::core::{CustomFee, Fee, TokenPair, TokenPairAmount}; use shadeswap_shared::msg::factory::QueryResponse as FactoryQueryResponse; use shadeswap_shared::snip20::manager::Balance; use shadeswap_shared::snip20::QueryAnswer; @@ -633,16 +673,15 @@ pub mod help_test_lib { code_hash: "CODE_HASH".to_string(), id: 0, }, - factory_info: ContractLink { + factory_info: Contract { address: Addr::unchecked(FACTORY_CONTRACT_ADDRESS), code_hash: "".to_string(), }, prng_seed: seed.clone(), entropy: entropy.clone(), - admin: Some(mock_info.sender.clone()), + admin_auth: Contract { address: mock_info.sender.clone(), code_hash: "".to_string() }, staking_contract: None, - custom_fee: None, - callback: None, + custom_fee: None }; assert!(instantiate(deps.as_mut(), env.clone(), mock_info.clone(), msg).is_ok()); let config = config_r(&deps.storage).load()?; @@ -653,13 +692,21 @@ pub mod help_test_lib { AMMSettings { lp_fee: Fee { nom: 2, denom: 100 }, shade_dao_fee: Fee { nom: 1, denom: 100 }, - shade_dao_address: ContractLink { + shade_dao_address: Contract { code_hash: "CODEHAS".to_string(), address: Addr::unchecked("TEST".to_string()), }, } } + pub fn mk_token_pair_amount(addr_0: &str, addr_1: &str, amount_0: Uint128, amount_1: Uint128) -> TokenPairAmount{ + return TokenPairAmount { + pair: mk_token_pair_custom_addr(addr_0, addr_1), + amount_0: amount_0, + amount_1: amount_1, + } + } + pub fn mk_token_pair() -> TokenPair { let pair = TokenPair( TokenType::CustomToken { @@ -674,6 +721,21 @@ pub mod help_test_lib { pair } + + pub fn mk_token_pair_custom_addr(token_addr_0: &str, token_addr_1: &str) -> TokenPair { + let pair = TokenPair( + TokenType::CustomToken { + contract_addr: Addr::unchecked(token_addr_0.to_string().clone()), + token_code_hash: token_addr_0.to_string(), + }, + TokenType::CustomToken { + contract_addr: Addr::unchecked(token_addr_1.to_string().clone()), + token_code_hash: token_addr_1.to_string(), + }, + ); + pair + } + pub fn mk_native_token_pair() -> TokenPair { let pair = TokenPair( TokenType::CustomToken { @@ -687,7 +749,7 @@ pub mod help_test_lib { pair } - pub fn mk_custom_token_amount(amount: Uint128, token_pair: TokenPair) -> TokenAmount { + pub fn mk_custom_token_amount(amount: Uint128, token_pair: &TokenPair) -> TokenAmount { let token = TokenAmount { token: token_pair.0.clone(), amount: amount.clone(), @@ -712,7 +774,7 @@ pub mod help_test_lib { AMMSettings { shade_dao_fee: Fee { nom: 1, denom: 100 }, lp_fee: Fee { nom: 2, denom: 100 }, - shade_dao_address: ContractLink { + shade_dao_address: Contract { code_hash: "CODEHAS".to_string(), address: Addr::unchecked("TEST".to_string()), }, @@ -740,21 +802,23 @@ pub mod help_test_lib { reward_token: TokenType::CustomToken { contract_addr: Addr::unchecked("".to_string()), token_code_hash: "".to_string(), - } + }, + valid_to: Uint128::new(3747905010000u128) }), prng_seed: to_binary(&"to_string".to_string())?, + admin_auth: Contract { address: Addr::unchecked(MOCK_CONTRACT_ADDR), code_hash: "".to_string() } }) } - pub fn mock_contract_link(address: String) -> ContractLink { - ContractLink { + pub fn mock_contract_link(address: String) -> Contract { + Contract { address: Addr::unchecked(address.clone()), - code_hash: "CODEHASH".to_string(), + code_hash: "".to_string(), } } - pub fn mock_contract_info(address: &str) -> ContractLink { - ContractLink { + pub fn mock_contract_info(address: &str) -> Contract { + Contract { address: Addr::unchecked(address.clone()), code_hash: "".to_string(), } @@ -853,7 +917,7 @@ pub mod help_test_lib { let amm_settings = shadeswap_shared::amm_pair::AMMSettings { lp_fee: Fee::new(28, 100), shade_dao_fee: Fee::new(2, 100), - shade_dao_address: ContractLink { + shade_dao_address: Contract { address: Addr::unchecked("DAO"), code_hash: "".to_string(), }, @@ -862,7 +926,8 @@ pub mod help_test_lib { pair_contract: ContractInstantiationInfo { code_hash: "".to_string(), id: 1_u64 }, amm_settings: amm_settings, lp_token_contract: ContractInstantiationInfo { code_hash: "".to_string(), id: 2_u64 }, - authenticator: None + authenticator: None, + admin_auth: Contract { address: Addr::unchecked(MOCK_CONTRACT_ADDR), code_hash: "".to_string() } }; QuerierResult::Ok(cosmwasm_std::ContractResult::Ok( to_binary(&response).unwrap(), @@ -879,7 +944,7 @@ pub mod help_test_lib { }).unwrap(); QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(balance)) }, - QueryMsg::Balance{address, key} =>{ + QueryMsg::Balance{address: _, key: _} =>{ let balance = to_binary(&QueryAnswer::Balance { amount: Uint128::from(10000u128), }) @@ -901,7 +966,7 @@ pub mod help_test_lib { }).unwrap(); QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(balance)) }, - QueryMsg::Balance{address, key} =>{ + QueryMsg::Balance{address: _, key: _} =>{ let balance = to_binary(&QueryAnswer::Balance { amount: Uint128::from(10000u128), }) @@ -957,8 +1022,7 @@ pub mod help_test_lib { let seed = to_binary(&"SEED".to_string())?; let entropy = to_binary(&"ENTROPY".to_string())?; let mut deps_api = mock_dependencies(&[]); - let env = mock_custom_env(FACTORY_CONTRACT_ADDRESS); - /// let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(FACTORY_CONTRACT_ADDRESS); let mock_info = mock_info("CONTRACT_ADDRESS",&[]); let msg = InitMsg { pair: token_pair.clone(), @@ -966,21 +1030,20 @@ pub mod help_test_lib { code_hash: "CODE_HASH".to_string(), id :0 }, - factory_info: ContractLink { + factory_info: Contract { address: Addr::unchecked(FACTORY_CONTRACT_ADDRESS), code_hash: "TEST".to_string() }, prng_seed: seed.clone(), entropy: entropy.clone(), - admin: Some(mock_info.sender.clone()), + admin_auth: Contract { address: mock_info.sender.clone(), code_hash: "".to_string() }, staking_contract: None, - custom_fee: custom_fee, - callback: None, + custom_fee: custom_fee }; let temp_deps = deps.branch(); assert!(instantiate(temp_deps, env.clone(),mock_info, msg).is_ok()); let mut config = config_r(deps.storage).load()?; // set staking contract - config.lp_token = ContractLink{ + config.lp_token = Contract{ address: deps_api.as_mut().api.addr_validate(&lp_token_addr.unwrap()).unwrap(), code_hash: "".to_string(), }; diff --git a/contracts/amm_pair/tests/integration.rs b/contracts/amm_pair/tests/integration.rs index 3b640c9..e80131f 100644 --- a/contracts/amm_pair/tests/integration.rs +++ b/contracts/amm_pair/tests/integration.rs @@ -1,180 +1,646 @@ -// use amm_pair::contract::{execute, instantiate, query, reply}; -// use snip20_reference_impl::contract::{execute as snip20_execute, instantiate as snip20_instantiate, query as snip20_query}; -// use staking::contract::{execute as staking_execute, instantiate as staking_instantiate, query as staking_query}; -// use lp_token::contract::{execute as lp_execute, instantiate as lp_instantiate, query as lp_query}; -// use secret_multi_test::{App, BankKeeper, Contract, ContractWrapper, Executor}; -// use shadeswap_shared::{ -// msg::amm_pair::{{QueryMsg, QueryMsgResponse}}, -// core::{ContractInstantiationInfo, ContractLink}, -// c_std::{QueryRequest, WasmQuery}, -// factory::{InitMsg as FactoryInitMsg, QueryResponse as FactoryQueryResponse, QueryMsg as FactoryQueryMsg}, -// utils::testing::TestingExt -// }; -// use shadeswap_shared::msg::amm_pair::{{InitMsg}}; -// use crate::{integration_help_lib::{mk_contract_link, mk_address}}; -// use cosmwasm_std::{ -// testing::{mock_env, MockApi}, -// to_binary, Addr, Empty, Binary, ContractInfo, -// }; - - -// pub fn amm_pair_contract_store() -> Box> { -// let contract = ContractWrapper::new_with_empty(execute, instantiate, query).with_reply(reply); -// Box::new(contract) -// } - -// pub fn staking_contract_store() -> Box> { -// let contract = ContractWrapper::new_with_empty(staking_execute, staking_instantiate, staking_query).with_reply(reply); -// Box::new(contract) -// } - -// pub fn snip20_contract_store() -> Box> { -// let contract = ContractWrapper::new_with_empty(snip20_execute, snip20_instantiate, snip20_query).with_reply(reply); -// Box::new(contract) -// } - -// pub fn factory_contract_store() -> Box> { -// let contract = ContractWrapper::new(snip20_execute, snip20_instantiate, snip20_query).with_reply(reply); -// Box::new(contract) -// } - -// pub fn lp_token_contract_store() -> Box> { -// let contract = ContractWrapper::new(lp_execute, lp_instantiate, lp_query); //.with_reply(reply); -// Box::new(contract) -// } - -// pub const CONTRACT_ADDRESS: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy6"; -// pub const TOKEN_A: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy2"; -// pub const TOKEN_B: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy4"; -// pub const FACTORY: &str = "secret13q9rgw3ez5mf808vm6k0naye090hh0m5fe2436"; -// pub const OWNER: &str = "secret1pf42ypa2awg0pxkx8lfyyrjvm28vq0qpffa8qx"; - -// #[cfg(not(target_arch = "wasm32"))] -// #[test] -// pub fn amm_pair_integration_tests() { -// use cosmwasm_std::Uint128; -// use shadeswap_shared::{core::{TokenType, TokenPair}, snip20::{InstantiateMsg, InitConfig}, stake_contract::StakingContractInit}; - -// use crate::integration_help_lib::generate_snip20_contract; - -// let mut router = App::default(); - -// let factory_contract_link = ContractLink{ -// address: mk_address(FACTORY), -// code_hash: "".to_string(), -// }; +use secret_multi_test::{App, Contract, ContractWrapper, Executor}; +use shadeswap_shared::{msg::amm_pair::{{InitMsg, ExecuteMsg, QueryMsg, QueryMsgResponse}}}; +use cosmwasm_std::{ + to_binary, Addr, Empty, ContractInfo, +}; +use shadeswap_shared::c_std::BlockInfo; + + +#[cfg(not(target_arch = "wasm32"))] +#[test] +pub fn amm_pair_integration_tests_with_custom_token() { + use amm_pair::contract::{instantiate, query, execute}; + use multi_test::admin::admin_help::init_admin_contract; + use multi_test::help_lib::integration_help_lib::{roll_blockchain, mint_deposit_snip20, increase_allowance, store_init_factory_contract, + create_token_pair, convert_to_contract_link, send_snip20_with_msg, get_snip20_balance, set_viewing_key, get_amm_pair_config, get_pair_liquidity_pool_balance}; + use cosmwasm_std::{Uint128, Coin, Timestamp}; + use multi_test::util_addr::util_addr::{OWNER}; + use shadeswap_shared::core::{ ContractInstantiationInfo, TokenPairAmount, TokenAmount, CustomFee, Fee}; + use shadeswap_shared::msg::amm_pair::InvokeMsg; + use shadeswap_shared::staking::StakingContractInit; + + use shadeswap_shared::utils::testing::TestingExt; + use shadeswap_shared::{core::{TokenType}}; + use multi_test::help_lib::integration_help_lib::{generate_snip20_contract}; + use multi_test::help_lib::integration_help_lib::snip20_lp_token_contract_store; + use shadeswap_shared::Contract as SContract; + use multi_test::amm_pairs::amm_pairs_mock::amm_pairs_mock::reply; + use staking::contract::{execute as staking_execute, instantiate as staking_instantiate, query as staking_query}; + let owner_addr = Addr::unchecked(OWNER); + + let mut router = App::default(); + router.set_block(BlockInfo { + height: 1, + time: Timestamp::from_seconds(1 as u64), + chain_id: "chain_id".to_string(), + }); + + pub fn staking_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(staking_execute, staking_instantiate, staking_query); + Box::new(contract) + } + + pub fn amm_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(execute, instantiate, query) + .with_reply(reply); + Box::new(contract) + } + + router.init_modules(|router, _, storage| { + router + .bank + .init_balance(storage, &owner_addr.clone(), vec![Coin{denom: "uscrt".into(), amount: Uint128::new(100000000000000u128)}]) + .unwrap(); + }); + + roll_blockchain(&mut router, 1).unwrap(); + // GENERATE TOKEN PAIRS + FACTORY + STAKING + let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); + let token_0_contract = generate_snip20_contract(&mut router, "ETH".to_string(),"ETH".to_string(),18).unwrap(); + let token_1_contract = generate_snip20_contract(&mut router, "USDT".to_string(),"USDT".to_string(),18).unwrap(); + let token_2_contract = generate_snip20_contract(&mut router, "USDT".to_string(),"USDT".to_string(),18).unwrap(); + + // MINT AND DEPOSIT FOR LIQUIDITY + mint_deposit_snip20(&mut router,&token_0_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + mint_deposit_snip20(&mut router,&token_1_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + mint_deposit_snip20(&mut router,&token_2_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + + let admin_contract = init_admin_contract(&mut router, &owner_addr).unwrap(); + let lp_contract_info = router.store_code(snip20_lp_token_contract_store()); + let staking_contract_info = router.store_code(staking_contract_store()); + let factory_contract_info = store_init_factory_contract(&mut router, &convert_to_contract_link(&admin_contract)).unwrap(); + let amm_pairs_info = router.store_code(amm_contract_store()); + roll_blockchain(&mut router, 1).unwrap(); + + let pair = create_token_pair( + &convert_to_contract_link(&token_0_contract), + &convert_to_contract_link(&token_1_contract) + ); + + let invalid_pair = create_token_pair( + &convert_to_contract_link(&token_1_contract), + &convert_to_contract_link(&token_2_contract) + ); + + let factory_link = SContract { + address:factory_contract_info.address, + code_hash: factory_contract_info.code_hash + }; + + // INIT AMM PAIR + let init_msg = InitMsg { + pair: pair.clone(), + lp_token_contract: ContractInstantiationInfo { + code_hash: lp_contract_info.code_hash.to_owned(), + id: lp_contract_info.code_id + }, + factory_info: factory_link.to_owned(), + prng_seed: to_binary("seed").unwrap(), + entropy: to_binary("seed").unwrap(), + admin_auth: convert_to_contract_link(&admin_contract), + staking_contract: Some(StakingContractInit{ + contract_info: ContractInstantiationInfo { + code_hash: staking_contract_info.code_hash.to_owned(), + id: staking_contract_info.code_id}, + daily_reward_amount: Uint128::new(30000u128), + reward_token: TokenType::CustomToken { + contract_addr: reward_contract.address.to_owned(), + token_code_hash: reward_contract.code_hash.to_owned() + }, + valid_to: Uint128::new(3747905010000u128) + }), + custom_fee: None + }; + + roll_blockchain(&mut router, 1).unwrap(); + let amm_pair_contract = router + .instantiate_contract( + amm_pairs_info, + owner_addr.to_owned(), + &init_msg, + &[], + "amm_pair", + Some(OWNER.to_string()), + ).unwrap(); + + // Assert AMM PAIR Config + roll_blockchain(&mut router, 2).unwrap(); + let query: QueryMsgResponse = router.query_test( + amm_pair_contract.to_owned(), + to_binary(&QueryMsg::GetConfig { }).unwrap() + ).unwrap(); + match query { + QueryMsgResponse::GetConfig { + factory_contract, + lp_token, + staking_contract, + pair: _, + custom_fee + } => { + assert_eq!(factory_contract.to_owned(),factory_link.to_owned()); + assert_eq!(custom_fee, None); + assert_ne!(lp_token.address.to_string(), "".to_string()); + assert_ne!(staking_contract.unwrap().address.to_string(), "".to_string()); + }, + _ => panic!("Query Responsedoes not match") + } + + mint_deposit_snip20( + &mut router, + &token_0_contract, + &owner_addr, + Uint128::new(100000000000u128), + &owner_addr + ); + roll_blockchain(&mut router, 1).unwrap(); + mint_deposit_snip20( + &mut router, + &token_1_contract, + &owner_addr, + Uint128::new(100000000000u128), + &owner_addr + ); + roll_blockchain(&mut router, 1).unwrap(); + let pair = create_token_pair( + &convert_to_contract_link(&token_0_contract), + &convert_to_contract_link(&token_1_contract) + ); + + increase_allowance(&mut router, &token_0_contract, Uint128::new(10000000000000u128), &amm_pair_contract.address, &owner_addr).unwrap(); + roll_blockchain(&mut router, 1).unwrap(); + increase_allowance(&mut router, &token_1_contract, Uint128::new(10000000000000u128), &amm_pair_contract.address, &owner_addr).unwrap(); + roll_blockchain(&mut router, 1).unwrap(); + + // ADD LIQIDITY WITH STAKING WITH INVALID TOKEN - REJECTED + let add_liqudity_msg = ExecuteMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount{ + pair: invalid_pair.clone(), + amount_0: Uint128::new(100000000u128), + amount_1: Uint128::new(100000000u128), + }, + expected_return: Some(Uint128::new(1000u128)), + staking: Some(true) + }; + + let err_msg = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &add_liqudity_msg, + &[] + ); + + match err_msg{ + Ok(msg) => todo!(), + Err(err) => assert_ne!(err.to_string(), "".to_string()), + } + + // ADD LIQIDITY WITH STAKING + let add_liqudity_msg = ExecuteMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount{ + pair: pair.clone(), + amount_0: Uint128::new(100000000u128), + amount_1: Uint128::new(100000000u128), + }, + expected_return: Some(Uint128::new(1000u128)), + staking: Some(true) + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &add_liqudity_msg, + &vec![Coin{denom: "uscrt".to_string(), amount: Uint128::new(100000000u128)}] + ).unwrap(); + + let query: QueryMsgResponse = router.query_test(amm_pair_contract.to_owned(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + QueryMsgResponse::GetConfig { + factory_contract: _, + lp_token, + staking_contract: _, + pair: _, + custom_fee: _ + } => { + let contract_info =ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }; + let _ = set_viewing_key(&mut router, &contract_info, "seed", &owner_addr).unwrap(); + let balance = get_snip20_balance(&mut router, &ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }, OWNER, "seed"); + assert_eq!(balance, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } + + // ADD LIQIDITY WITHOUT STAKING + let add_liqudity_msg = ExecuteMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount{ + pair: pair.clone(), + amount_0: Uint128::new(100000000u128), + amount_1: Uint128::new(100000000u128), + }, + expected_return: None, + staking: Some(false) + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &add_liqudity_msg, + &[] + ).unwrap(); + + let query: QueryMsgResponse = router.query_test(amm_pair_contract.to_owned(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + QueryMsgResponse::GetConfig { + factory_contract: _, + lp_token, + staking_contract: _, + pair: _, + custom_fee: _ + } => { + let contract_info =ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }; + let _ = set_viewing_key(&mut router, &contract_info, "seed", &owner_addr).unwrap(); + let balance = get_snip20_balance(&mut router, &ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }, OWNER, "seed"); + assert_eq!(balance, Uint128::new(100000000u128)); + + }, + _ => panic!("Query Responsedoes not match") + } + + let total_liquidity: (Uint128, Uint128, Uint128) = get_pair_liquidity_pool_balance(&mut router,&amm_pair_contract); + assert_eq!(total_liquidity.0, Uint128::new(200000000u128)); + assert_eq!(total_liquidity.1, Uint128::new(200000000u128)); + assert_eq!(total_liquidity.2, Uint128::new(200000000u128)); + + // SWAP TOKENS + roll_blockchain(&mut router, 1).unwrap(); + let swap_msg = to_binary(&ExecuteMsg::SwapTokens { + offer: TokenAmount{ + token: TokenType::CustomToken { + contract_addr: token_0_contract.address.clone(), + token_code_hash: token_0_contract.code_hash.clone() + }, + amount: Uint128::new(1000u128), + }, + expected_return: Some(Uint128::new(500u128)), + to: Some(owner_addr.to_string()), + }).unwrap(); + + let _ = send_snip20_with_msg( + &mut router, + &token_0_contract, + &amm_pair_contract, + Uint128::new(1000u128), + &owner_addr, + &swap_msg + ).unwrap(); + + // REMOVE LIQUIDITY + roll_blockchain(&mut router, 1).unwrap(); + let remove_msg = to_binary(&InvokeMsg::RemoveLiquidity { + from: Some(owner_addr.to_string()) + }).unwrap(); + + let config = get_amm_pair_config(&mut router, &amm_pair_contract); + let _ = send_snip20_with_msg( + &mut router, + &ContractInfo { + address: config.1.address, + code_hash: config.1.code_hash }, + &amm_pair_contract, + Uint128::new(1000u128), + &owner_addr, + &remove_msg + ).unwrap(); + + let total_liquidity: (Uint128, Uint128, Uint128) = get_pair_liquidity_pool_balance(&mut router,&amm_pair_contract); + assert_eq!(total_liquidity.0, Uint128::new(199999000u128)); + assert_eq!(total_liquidity.1, Uint128::new(199999970u128)); + assert_eq!(total_liquidity.2, Uint128::new(199998062u128)); + + // SET CUSTOM FEE + roll_blockchain(&mut router, 1).unwrap(); + let set_custom_fee = ExecuteMsg::SetCustomPairFee { + custom_fee: Some(CustomFee{ + shade_dao_fee: Fee::new(5, 100), + lp_fee: Fee::new(3,100), + }) + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &set_custom_fee, + &[] + ).unwrap(); + + let config = get_amm_pair_config(&mut router, &amm_pair_contract); + let custom_fee: CustomFee = config.4.unwrap(); + assert_eq!(custom_fee.shade_dao_fee.to_owned(), Fee::new(5,100)); + assert_eq!(custom_fee.lp_fee.to_owned(), Fee::new(3,100)); +} + +#[cfg(not(target_arch = "wasm32"))] +#[test] +pub fn amm_pair_integration_tests_native_token() { + use amm_pair::contract::{instantiate, query, execute}; + use multi_test::admin::admin_help::init_admin_contract; + use multi_test::help_lib::integration_help_lib::{roll_blockchain, mint_deposit_snip20, increase_allowance, store_init_factory_contract, convert_to_contract_link, send_snip20_with_msg, get_snip20_balance, set_viewing_key, get_amm_pair_config, get_pair_liquidity_pool_balance, create_token_pair_with_native}; + use cosmwasm_std::{Uint128, Coin, Timestamp}; + use multi_test::util_addr::util_addr::{OWNER}; + use shadeswap_shared::core::{ContractInstantiationInfo, TokenPairAmount, TokenAmount, CustomFee, Fee}; + use shadeswap_shared::msg::amm_pair::InvokeMsg; + + use shadeswap_shared::staking::StakingContractInit; + use shadeswap_shared::utils::testing::TestingExt; + use shadeswap_shared::{core::{TokenType}}; + use multi_test::help_lib::integration_help_lib::{generate_snip20_contract}; + use multi_test::help_lib::integration_help_lib::snip20_lp_token_contract_store; + use multi_test::amm_pairs::amm_pairs_mock::amm_pairs_mock::reply; + use shadeswap_shared::Contract as SContract; + use staking::contract::{execute as staking_execute, instantiate as staking_instantiate, query as staking_query}; + let owner_addr = Addr::unchecked(OWNER); + + let mut router = App::default(); + router.set_block(BlockInfo { + height: 1, + time: Timestamp::from_seconds(1 as u64), + chain_id: "chain_id".to_string(), + }); + + pub fn staking_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(staking_execute, staking_instantiate, staking_query); + Box::new(contract) + } + + pub fn amm_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(execute, instantiate, query) + .with_reply_empty(reply); + Box::new(contract) + } + + router.init_modules(|router, _, storage| { + router + .bank + .init_balance(storage, &owner_addr.clone(), vec![Coin{denom: "uscrt".into(), amount: Uint128::new(100000000000000u128)}]) + .unwrap(); + }); + + roll_blockchain(&mut router, 1).unwrap(); + // GENERATE TOKEN PAIRS + FACTORY + STAKING + let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); + let token_0_contract = generate_snip20_contract(&mut router, "ETH".to_string(),"ETH".to_string(),18).unwrap(); -// let amm_pair_contract_code_id = router.store_code(amm_pair_contract_store()); -// let eth_snip20_contract = generate_snip20_contract(&mut router, "ETH".to_string(),"ETH".to_string(),18); -// let btc_snip20_contract = generate_snip20_contract(&mut router, "BTC".to_string(),"BTC".to_string(),18); -// let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18); -// let snip20_contract_code_id = router.store_code(snip20_contract_store()); -// let staking_contract = router.store_code(staking_contract_store()); -// let lptoken_contract_code_id = router.store_code(lp_token_contract_store()); - -// let token_pair = TokenPair( -// TokenType::CustomToken { contract_addr: eth_snip20_contract.address.to_owned(), token_code_hash: eth_snip20_contract.code_hash.to_owned() }, -// TokenType::CustomToken { contract_addr: btc_snip20_contract.address.to_owned(), token_code_hash: btc_snip20_contract.code_hash.to_owned() } -// ); - -// let init_msg = InitMsg { -// pair: token_pair, -// lp_token_contract: ContractInstantiationInfo { code_hash: lptoken_contract_code_id.code_hash.to_owned(), id: lptoken_contract_code_id.code_id }, -// factory_info: factory_contract_link.to_owned(), -// prng_seed: to_binary(&"password").unwrap(), -// entropy: to_binary(&"password").unwrap(), -// admin: Some(mk_address(&OWNER)), -// staking_contract: Some(StakingContractInit{ -// contract_info: ContractInstantiationInfo { code_hash: staking_contract.code_hash.to_owned(), id: staking_contract.code_id}, -// amount: Uint128::new(10000), -// reward_token: TokenType::CustomToken { contract_addr: reward_contract.address.to_owned(), token_code_hash: reward_contract.code_hash } -// }), -// // staking_contract: None, -// custom_fee: None, -// callback: None, -// }; - -// let mocked_contract_addr = router -// .instantiate_contract( -// amm_pair_contract_code_id, -// mk_address(&OWNER).to_owned(), -// &init_msg, -// &[], -// "amm_pair", -// None, -// ) -// .unwrap(); - -// println!("{}", mocked_contract_addr.address.to_string()); -// let query: QueryMsgResponse = router.query_test(mocked_contract_addr,to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); -// match query { -// QueryMsgResponse::GetConfig { factory_contract, lp_token, staking_contract, pair, custom_fee } => { -// assert_eq!(staking_contract, None); -// assert_eq!(factory_contract, mk_contract_link("")); -// }, -// _ => panic!("Query Responsedoes not match") -// } -// } - -// pub mod integration_help_lib{ -// use cosmwasm_std::{Addr, ContractInfo}; -// use secret_multi_test::{App, Executor}; -// use shadeswap_shared::{msg::amm_pair::InitMsg, core::TokenPair, core::{TokenType, ContractLink}, snip20::{InitConfig, InstantiateMsg}}; -// use crate::{{TOKEN_A, TOKEN_B}, OWNER, snip20_contract_store}; -// use cosmwasm_std::to_binary; - -// pub fn mk_token_pair() -> TokenPair{ -// return TokenPair( -// TokenType::CustomToken { contract_addr: mk_address(TOKEN_A), token_code_hash: "".to_string() }, -// TokenType::CustomToken { contract_addr: mk_address(TOKEN_B), token_code_hash: "".to_string() } -// ); -// } - -// pub fn mk_address(address: &str) -> Addr{ -// return Addr::unchecked(address.to_string()) -// } - -// pub fn mk_contract_link(address: &str) -> ContractLink{ -// return ContractLink{ -// address: mk_address(address), -// code_hash: "".to_string(), -// } -// } - -// pub fn generate_snip20_contract( -// router: &mut App, -// name: String, -// symbol: String, -// decimal: u8) -> ContractInfo { - -// let snip20_contract_code_id = router.store_code(snip20_contract_store()); -// let init_snip20_msg = InstantiateMsg { -// name: name.to_owned(), -// admin: Some(OWNER.to_string()), -// symbol: symbol.to_owned(), -// decimals: decimal, -// initial_balances: None, -// prng_seed: to_binary("password").unwrap(), -// config: Some(InitConfig { -// public_total_supply: Some(true), -// enable_deposit: Some(false), -// enable_redeem: Some(false), -// enable_mint: Some(true), -// enable_burn: Some(true), -// enable_transfer: Some(true), -// }), -// query_auth: None, -// }; -// let init_snip20_code_id = router -// .instantiate_contract( -// snip20_contract_code_id, -// mk_address(&OWNER).to_owned(), -// &init_snip20_msg, -// &[], -// "token_a", -// None, -// ) -// .unwrap(); -// init_snip20_code_id -// } -// } \ No newline at end of file + // MINT AND DEPOSIT FOR LIQUIDITY + mint_deposit_snip20(&mut router,&token_0_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + let admin_contract = init_admin_contract(&mut router, &owner_addr).unwrap(); + let lp_contract_info = router.store_code(snip20_lp_token_contract_store()); + let staking_contract_info = router.store_code(staking_contract_store()); + let factory_contract_info = store_init_factory_contract(&mut router, &convert_to_contract_link(&admin_contract)).unwrap(); + let amm_pairs_info = router.store_code(amm_contract_store()); + roll_blockchain(&mut router, 1).unwrap(); + + let pair = create_token_pair_with_native( + &convert_to_contract_link(&token_0_contract) + ); + + let factory_link = SContract { + address:factory_contract_info.address, + code_hash: factory_contract_info.code_hash + }; + + // INIT AMM PAIR + let init_msg = InitMsg { + pair: pair.clone(), + lp_token_contract: ContractInstantiationInfo { + code_hash: lp_contract_info.code_hash.to_owned(), + id: lp_contract_info.code_id + }, + factory_info: factory_link.to_owned(), + prng_seed: to_binary("seed").unwrap(), + entropy: to_binary("seed").unwrap(), + admin_auth: convert_to_contract_link(&admin_contract), + staking_contract: Some(StakingContractInit{ + contract_info: ContractInstantiationInfo { + code_hash: staking_contract_info.code_hash.to_owned(), + id: staking_contract_info.code_id}, + daily_reward_amount: Uint128::new(30000u128), + reward_token: TokenType::CustomToken { + contract_addr: reward_contract.address.to_owned(), + token_code_hash: reward_contract.code_hash.to_owned() + }, + valid_to: Uint128::new(3747905010000u128) + }), + custom_fee: None + }; + + roll_blockchain(&mut router, 1).unwrap(); + let amm_pair_contract = router + .instantiate_contract( + amm_pairs_info, + owner_addr.to_owned(), + &init_msg, + &[], + "amm_pair", + Some(OWNER.to_string()), + ).unwrap(); + + // Assert AMM PAIR Config + roll_blockchain(&mut router, 2).unwrap(); + let query: QueryMsgResponse = router.query_test(amm_pair_contract.to_owned(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + QueryMsgResponse::GetConfig { + factory_contract, + lp_token, + staking_contract, + pair: _, + custom_fee + } => { + assert_eq!(factory_contract.to_owned(),factory_link.to_owned()); + assert_eq!(custom_fee, None); + assert_ne!(lp_token.address.to_string(), "".to_string()); + assert_ne!(staking_contract.unwrap().address.to_string(), "".to_string()); + }, + _ => panic!("Query Responsedoes not match") + } + + mint_deposit_snip20( + &mut router, + &token_0_contract, + &owner_addr, + Uint128::new(100000000000u128), + &owner_addr + ); + roll_blockchain(&mut router, 1).unwrap(); + + let pair = create_token_pair_with_native( + &convert_to_contract_link(&token_0_contract)); + increase_allowance(&mut router, &token_0_contract, Uint128::new(10000000000000u128), &amm_pair_contract.address, &owner_addr).unwrap(); + roll_blockchain(&mut router, 1).unwrap(); + + // ADD LIQIDITY WITH STAKING + let add_liqudity_msg = ExecuteMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount{ + pair: pair.clone(), + amount_0: Uint128::new(100000000u128), + amount_1: Uint128::new(100000000u128), + }, + expected_return: Some(Uint128::new(1000u128)), + staking: Some(true) + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &add_liqudity_msg, + &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(100000000u128) }] + ).unwrap(); + + + let query: QueryMsgResponse = router.query_test(amm_pair_contract.to_owned(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + QueryMsgResponse::GetConfig { + factory_contract: _, + lp_token, + staking_contract: _, + pair: _, + custom_fee: _ + } => { + let contract_info =ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }; + let _ = set_viewing_key(&mut router, &contract_info, "seed", &owner_addr).unwrap(); + let balance = get_snip20_balance(&mut router, &ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }, OWNER, "seed"); + assert_eq!(balance, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } + + // ADD LIQIDITY WITHOUT STAKING + let add_liqudity_msg = ExecuteMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount{ + pair: pair.clone(), + amount_0: Uint128::new(100000000u128), + amount_1: Uint128::new(100000000u128), + }, + expected_return: None, + staking: Some(false) + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &add_liqudity_msg, + &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(100000000u128) }] + ).unwrap(); + + let query: QueryMsgResponse = router.query_test(amm_pair_contract.to_owned(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + QueryMsgResponse::GetConfig { + factory_contract: _, + lp_token, + staking_contract: _, + pair: _, + custom_fee: _ + } => { + let contract_info =ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }; + let _ = set_viewing_key(&mut router, &contract_info, "seed", &owner_addr).unwrap(); + let balance = get_snip20_balance(&mut router, &ContractInfo{ + address: lp_token.address.clone(), + code_hash: lp_token.code_hash.to_string(), + }, OWNER, "seed"); + assert_eq!(balance, Uint128::new(100000000)); + + }, + _ => panic!("Query Responsedoes not match") + } + + let total_liquidity: (Uint128, Uint128, Uint128) = get_pair_liquidity_pool_balance(&mut router,&amm_pair_contract); + assert_eq!(total_liquidity.0, Uint128::new(200000000u128)); + assert_eq!(total_liquidity.1, Uint128::new(200000000u128)); + assert_eq!(total_liquidity.2, Uint128::new(200000000u128)); + + // SWAP TOKENS + roll_blockchain(&mut router, 1).unwrap(); + let swap_msg = ExecuteMsg::SwapTokens { + offer: TokenAmount{ + token: TokenType::NativeToken { denom: "uscrt".to_string()}, + amount: Uint128::new(1000u128), + }, + expected_return: Some(Uint128::new(500u128)), + to: Some(owner_addr.to_string()) + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &swap_msg, + &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(1000u128) }] + ).unwrap(); + + // REMOVE LIQUIDITY + roll_blockchain(&mut router, 1).unwrap(); + let remove_msg = to_binary(&InvokeMsg::RemoveLiquidity { + from: Some(owner_addr.to_string()) + }).unwrap(); + + let config = get_amm_pair_config(&mut router, &amm_pair_contract); + let _ = send_snip20_with_msg( + &mut router, + &ContractInfo { + address: config.1.address, + code_hash: config.1.code_hash }, + &amm_pair_contract, + Uint128::new(1000u128), + &owner_addr, + &remove_msg + ); + + let total_liquidity: (Uint128, Uint128, Uint128) = get_pair_liquidity_pool_balance(&mut router,&amm_pair_contract); + assert_eq!(total_liquidity.0, Uint128::new(199999000u128)); + assert_eq!(total_liquidity.1, Uint128::new(199999970u128)); + assert_eq!(total_liquidity.2, Uint128::new(199998062u128)); + + // SET CUSTOM FEE + roll_blockchain(&mut router, 1).unwrap(); + let set_custom_fee = ExecuteMsg::SetCustomPairFee { + custom_fee: Some(CustomFee{ + shade_dao_fee: Fee::new(5, 100), + lp_fee: Fee::new(3,100), + }) + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &amm_pair_contract, + &set_custom_fee, + &[] + ).unwrap(); + + let config = get_amm_pair_config(&mut router, &amm_pair_contract); + let custom_fee: CustomFee = config.4.unwrap(); + assert_eq!(custom_fee.shade_dao_fee.to_owned(), Fee::new(5,100)); + assert_eq!(custom_fee.lp_fee.to_owned(), Fee::new(3,100)); +} + + + + + diff --git a/contracts/amm_pair/testscript/foo.key b/contracts/amm_pair/testscript/foo.key deleted file mode 100644 index fa7e8f1..0000000 --- a/contracts/amm_pair/testscript/foo.key +++ /dev/null @@ -1 +0,0 @@ -inmate beyond heavy march minor correct apple satoshi master zero ritual cage roof side excite nest digital nature roof clinic divert veteran treat hour \ No newline at end of file diff --git a/contracts/amm_pair/testscript/package-lock.json b/contracts/amm_pair/testscript/package-lock.json deleted file mode 100644 index f0e7cf4..0000000 --- a/contracts/amm_pair/testscript/package-lock.json +++ /dev/null @@ -1,1590 +0,0 @@ -{ - "name": "cosmostest", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "cosmostest", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@cosmjs/launchpad": "^0.27.1", - "secretjs": "^0.17.5" - } - }, - "node_modules/@cosmjs/amino": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.27.1.tgz", - "integrity": "sha512-w56ar/nK9+qlvWDpBPRmD0Blk2wfkkLqRi1COs1x7Ll1LF0AtkIBUjbRKplENLbNovK0T3h+w8bHiFm+GBGQOA==", - "dependencies": { - "@cosmjs/crypto": "0.27.1", - "@cosmjs/encoding": "0.27.1", - "@cosmjs/math": "0.27.1", - "@cosmjs/utils": "0.27.1" - } - }, - "node_modules/@cosmjs/amino/node_modules/@cosmjs/encoding": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.27.1.tgz", - "integrity": "sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==", - "dependencies": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "node_modules/@cosmjs/amino/node_modules/@cosmjs/math": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz", - "integrity": "sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ==", - "dependencies": { - "bn.js": "^5.2.0" - } - }, - "node_modules/@cosmjs/amino/node_modules/@cosmjs/utils": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz", - "integrity": "sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==" - }, - "node_modules/@cosmjs/amino/node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "node_modules/@cosmjs/crypto": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.27.1.tgz", - "integrity": "sha512-vbcxwSt99tIYJg8Spp00wc3zx72qx+pY3ozGuBN8gAvySnagK9dQ/jHwtWQWdammmdD6oW+75WfIHZ+gNa+Ybg==", - "dependencies": { - "@cosmjs/encoding": "0.27.1", - "@cosmjs/math": "0.27.1", - "@cosmjs/utils": "0.27.1", - "bip39": "^3.0.2", - "bn.js": "^5.2.0", - "elliptic": "^6.5.3", - "js-sha3": "^0.8.0", - "libsodium-wrappers": "^0.7.6", - "ripemd160": "^2.0.2", - "sha.js": "^2.4.11" - } - }, - "node_modules/@cosmjs/crypto/node_modules/@cosmjs/encoding": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.27.1.tgz", - "integrity": "sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==", - "dependencies": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "node_modules/@cosmjs/crypto/node_modules/@cosmjs/math": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz", - "integrity": "sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ==", - "dependencies": { - "bn.js": "^5.2.0" - } - }, - "node_modules/@cosmjs/crypto/node_modules/@cosmjs/utils": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz", - "integrity": "sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==" - }, - "node_modules/@cosmjs/crypto/node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "node_modules/@cosmjs/encoding": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.20.1.tgz", - "integrity": "sha512-aBp153iq2LD4GwDGwodDWZk/eyAUZ8J8bbiqZ1uK8rrylzm9Rdw84aa6JxykezJe+uBPtoI4lx9eH7VQXCGDXw==", - "license": "Apache-2.0", - "dependencies": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "node_modules/@cosmjs/launchpad": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/launchpad/-/launchpad-0.27.1.tgz", - "integrity": "sha512-DcFwGD/z5PK8CzO2sojDxa+Be9EIEtRZb2YawgVnw2Ht/p5FlNv+OVo8qlishpBdalXEN7FvQ1dVeDFEe9TuJw==", - "dependencies": { - "@cosmjs/amino": "0.27.1", - "@cosmjs/crypto": "0.27.1", - "@cosmjs/encoding": "0.27.1", - "@cosmjs/math": "0.27.1", - "@cosmjs/utils": "0.27.1", - "axios": "^0.21.2", - "fast-deep-equal": "^3.1.3" - } - }, - "node_modules/@cosmjs/launchpad/node_modules/@cosmjs/encoding": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.27.1.tgz", - "integrity": "sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==", - "dependencies": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "node_modules/@cosmjs/launchpad/node_modules/@cosmjs/math": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz", - "integrity": "sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ==", - "dependencies": { - "bn.js": "^5.2.0" - } - }, - "node_modules/@cosmjs/launchpad/node_modules/@cosmjs/utils": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz", - "integrity": "sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==" - }, - "node_modules/@cosmjs/launchpad/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/@cosmjs/launchpad/node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "node_modules/@cosmjs/launchpad/node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/@cosmjs/math": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.20.1.tgz", - "integrity": "sha512-xt7BmpSw2OVGM2+JhlJvKv9OJs9+3DqgVL6+byUDC355CSISrZhFjJg9GFko1EFssDXz5YgvBZR5FkifC0xazw==", - "license": "Apache-2.0", - "dependencies": { - "bn.js": "^4.11.8" - } - }, - "node_modules/@cosmjs/utils": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.20.1.tgz", - "integrity": "sha512-xl9YnIrAAaBd6nFffwFbyrnKjqjD9zKGP8OBKxzyglxamHfqAS+PcJPEiaEpt+oUt7HAIOyhL3KK75Dh52hGvA==", - "license": "Apache-2.0" - }, - "node_modules/@iov/crypto": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@iov/crypto/-/crypto-2.1.0.tgz", - "integrity": "sha512-jnb4XuK50admolm7fBxOcxfAW2TO+wYrZlhDWiMETItY/Y5gNNa1zaDSO2wNIjjfGng+8nQ1yqnNhqy7busV2Q==", - "license": "Apache-2.0", - "dependencies": { - "@iov/encoding": "^2.1.0", - "bip39": "^3.0.2", - "bn.js": "^4.11.8", - "elliptic": "^6.4.0", - "js-sha3": "^0.8.0", - "libsodium-wrappers": "^0.7.6", - "pbkdf2": "^3.0.16", - "ripemd160": "^2.0.2", - "sha.js": "^2.4.11", - "type-tagger": "^1.0.0", - "unorm": "^1.5.0" - } - }, - "node_modules/@iov/crypto/node_modules/@iov/encoding": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@iov/encoding/-/encoding-2.5.0.tgz", - "integrity": "sha512-HGHLlQEvD23rFjW5PQrxD2B/6LiBHVSxqX6gjOz9KfcmIMIftRA0qROrTITfjjjUr/yZZEeNk4qjuBls9TaYcA==", - "license": "Apache-2.0", - "dependencies": { - "@cosmjs/encoding": "^0.20.0", - "@cosmjs/math": "^0.20.0", - "@cosmjs/utils": "^0.20.0", - "readonly-date": "^1.0.0" - } - }, - "node_modules/@iov/encoding": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@iov/encoding/-/encoding-2.1.0.tgz", - "integrity": "sha512-5IOdLO7Xg/uRykuiCqeMYghQ3IjWDtGxv7NTWXkgpHuna0aewx43mRpT2NPCpOZd1tpuorDtQ7/zbDNRaIIF/w==", - "license": "Apache-2.0", - "dependencies": { - "base64-js": "^1.3.0", - "bech32": "^1.1.3", - "bn.js": "^4.11.8", - "readonly-date": "^1.0.0" - } - }, - "node_modules/@iov/utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@iov/utils/-/utils-2.0.2.tgz", - "integrity": "sha512-4D8MEvTcFc/DVy5q25vHxRItmgJyeX85dixMH+MxdKr+yy71h3sYk+sVBEIn70uqGP7VqAJkGOPNFs08/XYELw==", - "license": "Apache-2.0" - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", - "license": "BSD-3-Clause" - }, - "node_modules/@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "17.0.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", - "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.10.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "license": "MIT" - }, - "node_modules/bip39": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", - "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", - "license": "ISC", - "dependencies": { - "@types/node": "11.11.6", - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1" - } - }, - "node_modules/bip39/node_modules/@types/node": { - "version": "11.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", - "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==", - "license": "MIT" - }, - "node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "license": "MIT" - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "license": "MIT" - }, - "node_modules/buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/curve25519-js": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/curve25519-js/-/curve25519-js-0.0.4.tgz", - "integrity": "sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==", - "license": "MIT" - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", - "license": "MIT" - }, - "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "license": "MIT" - }, - "node_modules/js-crypto-env": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/js-crypto-env/-/js-crypto-env-0.3.2.tgz", - "integrity": "sha512-F1uHiCkSOo36qBuuZABA4sBf+xeFBzhJZ0Sd7af8FAruszIhm1Xxv+Zr5Ne90Zlh7/fnxCsrdkj0N8f0a3lVlQ==", - "license": "MIT" - }, - "node_modules/js-crypto-hash": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/js-crypto-hash/-/js-crypto-hash-0.6.3.tgz", - "integrity": "sha512-SG8c9tM8y3sUb4k7WvpVfu5vU7zfPvX+eaYR5578TvehkehdaQbqAc+y+1FwxnqQ3WZ0gsYoOKp/mW+mqtNoWA==", - "license": "MIT", - "dependencies": { - "buffer": "~5.4.3", - "hash.js": "~1.1.7", - "js-crypto-env": "^0.3.2", - "md5": "~2.2.1", - "sha3": "~2.1.0" - } - }, - "node_modules/js-crypto-hkdf": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/js-crypto-hkdf/-/js-crypto-hkdf-0.7.3.tgz", - "integrity": "sha512-eAaVArAjS2GCacWGXY4hjBiexrLQYlI0PMOcbwtrSEj84XU3kUfMYZm9bpTyaTXgdHC/eQoXe/Of6biG+RSEaQ==", - "license": "MIT", - "dependencies": { - "js-crypto-env": "^0.3.2", - "js-crypto-hmac": "^0.6.3", - "js-crypto-random": "^0.4.3", - "js-encoding-utils": "0.5.6" - } - }, - "node_modules/js-crypto-hmac": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/js-crypto-hmac/-/js-crypto-hmac-0.6.3.tgz", - "integrity": "sha512-T0pKOaHACOSG6Xs6/06G8RDDeZouQwIQNBq9L/zoUGsd4F67gAjpT3q2lGigAGpUd1hiyy7vnhvLpz7VDt6DbA==", - "license": "MIT", - "dependencies": { - "js-crypto-env": "^0.3.2", - "js-crypto-hash": "^0.6.3" - } - }, - "node_modules/js-crypto-random": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/js-crypto-random/-/js-crypto-random-0.4.3.tgz", - "integrity": "sha512-C3gzphPPfw9jfQ9Q/LjhJMZxQNp3AaoVRDvyZkiB+zYltfs8tKQPsskWkXACpg1Nzh01PtSRUvVijjptd2qGHQ==", - "license": "MIT", - "dependencies": { - "js-crypto-env": "^0.3.2" - } - }, - "node_modules/js-encoding-utils": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/js-encoding-utils/-/js-encoding-utils-0.5.6.tgz", - "integrity": "sha512-qnAGsUIWrmzh5n+3AXqbxX1KsB9hkQmJZf3aA9DLAS7GpL/NEHCBreFFbW+imramoU+Q0TDyvkwhRbBRH1TVkg==", - "license": "MIT" - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "license": "MIT" - }, - "node_modules/libsodium": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", - "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==", - "license": "ISC" - }, - "node_modules/libsodium-wrappers": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", - "integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==", - "license": "ISC", - "dependencies": { - "libsodium": "^0.7.0" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "license": "Apache-2.0" - }, - "node_modules/md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "license": "BSD-3-Clause", - "dependencies": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "license": "MIT" - }, - "node_modules/miscreant": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/miscreant/-/miscreant-0.3.2.tgz", - "integrity": "sha512-fL9KxsQz9BJB2KGPMHFrReioywkiomBiuaLk6EuChijK0BsJsIKJXdVomR+/bPj5mvbFD6wM0CM3bZio9g7OHA==", - "license": "MIT" - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "license": "MIT", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/protobufjs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readonly-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz", - "integrity": "sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==", - "license": "Apache-2.0" - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/secretjs": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/secretjs/-/secretjs-0.17.5.tgz", - "integrity": "sha512-sf0+Je9KIEMQr/wJOgeqyBOV0ruiMNHSwP4L2vXiJbtzJWQqyVHyPkpavAhruNZ+91XlSzAFP2X5MPxqPBC9fQ==", - "dependencies": { - "@iov/crypto": "2.1.0", - "@iov/encoding": "2.1.0", - "@iov/utils": "2.0.2", - "axios": "0.21.1", - "curve25519-js": "0.0.4", - "fast-deep-equal": "3.1.1", - "js-crypto-hkdf": "0.7.3", - "miscreant": "0.3.2", - "pako": "1.0.11", - "protobufjs": "^6.11.2", - "secure-random": "1.1.2" - } - }, - "node_modules/secure-random": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/secure-random/-/secure-random-1.1.2.tgz", - "integrity": "sha512-H2bdSKERKdBV1SwoqYm6C0y+9EA94v6SUBOWO8kDndc4NoUih7Dv6Tsgma7zO1lv27wIvjlD0ZpMQk7um5dheQ==", - "license": "MIT" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/sha3": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", - "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", - "license": "MIT", - "dependencies": { - "buffer": "6.0.3" - } - }, - "node_modules/sha3/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/type-tagger": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/type-tagger/-/type-tagger-1.0.0.tgz", - "integrity": "sha512-FIPqqpmDgdaulCnRoKv1/d3U4xVBUrYn42QXWNP3XYmgfPUDuBUsgFOb9ntT0aIe0UsUP+lknpQ5d9Kn36RssA==", - "license": "Apache-2.0" - }, - "node_modules/unorm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", - "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==", - "license": "MIT or GPL-2.0", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "license": "MIT" - } - }, - "dependencies": { - "@cosmjs/amino": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.27.1.tgz", - "integrity": "sha512-w56ar/nK9+qlvWDpBPRmD0Blk2wfkkLqRi1COs1x7Ll1LF0AtkIBUjbRKplENLbNovK0T3h+w8bHiFm+GBGQOA==", - "requires": { - "@cosmjs/crypto": "0.27.1", - "@cosmjs/encoding": "0.27.1", - "@cosmjs/math": "0.27.1", - "@cosmjs/utils": "0.27.1" - }, - "dependencies": { - "@cosmjs/encoding": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.27.1.tgz", - "integrity": "sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==", - "requires": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "@cosmjs/math": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz", - "integrity": "sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ==", - "requires": { - "bn.js": "^5.2.0" - } - }, - "@cosmjs/utils": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz", - "integrity": "sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==" - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - } - } - }, - "@cosmjs/crypto": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.27.1.tgz", - "integrity": "sha512-vbcxwSt99tIYJg8Spp00wc3zx72qx+pY3ozGuBN8gAvySnagK9dQ/jHwtWQWdammmdD6oW+75WfIHZ+gNa+Ybg==", - "requires": { - "@cosmjs/encoding": "0.27.1", - "@cosmjs/math": "0.27.1", - "@cosmjs/utils": "0.27.1", - "bip39": "^3.0.2", - "bn.js": "^5.2.0", - "elliptic": "^6.5.3", - "js-sha3": "^0.8.0", - "libsodium-wrappers": "^0.7.6", - "ripemd160": "^2.0.2", - "sha.js": "^2.4.11" - }, - "dependencies": { - "@cosmjs/encoding": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.27.1.tgz", - "integrity": "sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==", - "requires": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "@cosmjs/math": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz", - "integrity": "sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ==", - "requires": { - "bn.js": "^5.2.0" - } - }, - "@cosmjs/utils": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz", - "integrity": "sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==" - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - } - } - }, - "@cosmjs/encoding": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.20.1.tgz", - "integrity": "sha512-aBp153iq2LD4GwDGwodDWZk/eyAUZ8J8bbiqZ1uK8rrylzm9Rdw84aa6JxykezJe+uBPtoI4lx9eH7VQXCGDXw==", - "requires": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "@cosmjs/launchpad": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/launchpad/-/launchpad-0.27.1.tgz", - "integrity": "sha512-DcFwGD/z5PK8CzO2sojDxa+Be9EIEtRZb2YawgVnw2Ht/p5FlNv+OVo8qlishpBdalXEN7FvQ1dVeDFEe9TuJw==", - "requires": { - "@cosmjs/amino": "0.27.1", - "@cosmjs/crypto": "0.27.1", - "@cosmjs/encoding": "0.27.1", - "@cosmjs/math": "0.27.1", - "@cosmjs/utils": "0.27.1", - "axios": "^0.21.2", - "fast-deep-equal": "^3.1.3" - }, - "dependencies": { - "@cosmjs/encoding": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.27.1.tgz", - "integrity": "sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==", - "requires": { - "base64-js": "^1.3.0", - "bech32": "^1.1.4", - "readonly-date": "^1.0.0" - } - }, - "@cosmjs/math": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz", - "integrity": "sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ==", - "requires": { - "bn.js": "^5.2.0" - } - }, - "@cosmjs/utils": { - "version": "0.27.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz", - "integrity": "sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==" - }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - } - } - }, - "@cosmjs/math": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.20.1.tgz", - "integrity": "sha512-xt7BmpSw2OVGM2+JhlJvKv9OJs9+3DqgVL6+byUDC355CSISrZhFjJg9GFko1EFssDXz5YgvBZR5FkifC0xazw==", - "requires": { - "bn.js": "^4.11.8" - } - }, - "@cosmjs/utils": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.20.1.tgz", - "integrity": "sha512-xl9YnIrAAaBd6nFffwFbyrnKjqjD9zKGP8OBKxzyglxamHfqAS+PcJPEiaEpt+oUt7HAIOyhL3KK75Dh52hGvA==" - }, - "@iov/crypto": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@iov/crypto/-/crypto-2.1.0.tgz", - "integrity": "sha512-jnb4XuK50admolm7fBxOcxfAW2TO+wYrZlhDWiMETItY/Y5gNNa1zaDSO2wNIjjfGng+8nQ1yqnNhqy7busV2Q==", - "requires": { - "@iov/encoding": "^2.1.0", - "bip39": "^3.0.2", - "bn.js": "^4.11.8", - "elliptic": "^6.4.0", - "js-sha3": "^0.8.0", - "libsodium-wrappers": "^0.7.6", - "pbkdf2": "^3.0.16", - "ripemd160": "^2.0.2", - "sha.js": "^2.4.11", - "type-tagger": "^1.0.0", - "unorm": "^1.5.0" - }, - "dependencies": { - "@iov/encoding": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@iov/encoding/-/encoding-2.5.0.tgz", - "integrity": "sha512-HGHLlQEvD23rFjW5PQrxD2B/6LiBHVSxqX6gjOz9KfcmIMIftRA0qROrTITfjjjUr/yZZEeNk4qjuBls9TaYcA==", - "requires": { - "@cosmjs/encoding": "^0.20.0", - "@cosmjs/math": "^0.20.0", - "@cosmjs/utils": "^0.20.0", - "readonly-date": "^1.0.0" - } - } - } - }, - "@iov/encoding": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@iov/encoding/-/encoding-2.1.0.tgz", - "integrity": "sha512-5IOdLO7Xg/uRykuiCqeMYghQ3IjWDtGxv7NTWXkgpHuna0aewx43mRpT2NPCpOZd1tpuorDtQ7/zbDNRaIIF/w==", - "requires": { - "base64-js": "^1.3.0", - "bech32": "^1.1.3", - "bn.js": "^4.11.8", - "readonly-date": "^1.0.0" - } - }, - "@iov/utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@iov/utils/-/utils-2.0.2.tgz", - "integrity": "sha512-4D8MEvTcFc/DVy5q25vHxRItmgJyeX85dixMH+MxdKr+yy71h3sYk+sVBEIn70uqGP7VqAJkGOPNFs08/XYELw==" - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, - "@types/node": { - "version": "17.0.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", - "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" - }, - "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" - }, - "bip39": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", - "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", - "requires": { - "@types/node": "11.11.6", - "create-hash": "^1.1.0", - "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1" - }, - "dependencies": { - "@types/node": { - "version": "11.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", - "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" - } - } - }, - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" - }, - "curve25519-js": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/curve25519-js/-/curve25519-js-0.0.4.tgz", - "integrity": "sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==" - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" - }, - "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "js-crypto-env": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/js-crypto-env/-/js-crypto-env-0.3.2.tgz", - "integrity": "sha512-F1uHiCkSOo36qBuuZABA4sBf+xeFBzhJZ0Sd7af8FAruszIhm1Xxv+Zr5Ne90Zlh7/fnxCsrdkj0N8f0a3lVlQ==" - }, - "js-crypto-hash": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/js-crypto-hash/-/js-crypto-hash-0.6.3.tgz", - "integrity": "sha512-SG8c9tM8y3sUb4k7WvpVfu5vU7zfPvX+eaYR5578TvehkehdaQbqAc+y+1FwxnqQ3WZ0gsYoOKp/mW+mqtNoWA==", - "requires": { - "buffer": "~5.4.3", - "hash.js": "~1.1.7", - "js-crypto-env": "^0.3.2", - "md5": "~2.2.1", - "sha3": "~2.1.0" - } - }, - "js-crypto-hkdf": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/js-crypto-hkdf/-/js-crypto-hkdf-0.7.3.tgz", - "integrity": "sha512-eAaVArAjS2GCacWGXY4hjBiexrLQYlI0PMOcbwtrSEj84XU3kUfMYZm9bpTyaTXgdHC/eQoXe/Of6biG+RSEaQ==", - "requires": { - "js-crypto-env": "^0.3.2", - "js-crypto-hmac": "^0.6.3", - "js-crypto-random": "^0.4.3", - "js-encoding-utils": "0.5.6" - } - }, - "js-crypto-hmac": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/js-crypto-hmac/-/js-crypto-hmac-0.6.3.tgz", - "integrity": "sha512-T0pKOaHACOSG6Xs6/06G8RDDeZouQwIQNBq9L/zoUGsd4F67gAjpT3q2lGigAGpUd1hiyy7vnhvLpz7VDt6DbA==", - "requires": { - "js-crypto-env": "^0.3.2", - "js-crypto-hash": "^0.6.3" - } - }, - "js-crypto-random": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/js-crypto-random/-/js-crypto-random-0.4.3.tgz", - "integrity": "sha512-C3gzphPPfw9jfQ9Q/LjhJMZxQNp3AaoVRDvyZkiB+zYltfs8tKQPsskWkXACpg1Nzh01PtSRUvVijjptd2qGHQ==", - "requires": { - "js-crypto-env": "^0.3.2" - } - }, - "js-encoding-utils": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/js-encoding-utils/-/js-encoding-utils-0.5.6.tgz", - "integrity": "sha512-qnAGsUIWrmzh5n+3AXqbxX1KsB9hkQmJZf3aA9DLAS7GpL/NEHCBreFFbW+imramoU+Q0TDyvkwhRbBRH1TVkg==" - }, - "js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "libsodium": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", - "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" - }, - "libsodium-wrappers": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", - "integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==", - "requires": { - "libsodium": "^0.7.0" - } - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "miscreant": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/miscreant/-/miscreant-0.3.2.tgz", - "integrity": "sha512-fL9KxsQz9BJB2KGPMHFrReioywkiomBiuaLk6EuChijK0BsJsIKJXdVomR+/bPj5mvbFD6wM0CM3bZio9g7OHA==" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "protobufjs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readonly-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz", - "integrity": "sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==" - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "secretjs": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/secretjs/-/secretjs-0.17.5.tgz", - "integrity": "sha512-sf0+Je9KIEMQr/wJOgeqyBOV0ruiMNHSwP4L2vXiJbtzJWQqyVHyPkpavAhruNZ+91XlSzAFP2X5MPxqPBC9fQ==", - "requires": { - "@iov/crypto": "2.1.0", - "@iov/encoding": "2.1.0", - "@iov/utils": "2.0.2", - "axios": "0.21.1", - "curve25519-js": "0.0.4", - "fast-deep-equal": "3.1.1", - "js-crypto-hkdf": "0.7.3", - "miscreant": "0.3.2", - "pako": "1.0.11", - "protobufjs": "^6.11.2", - "secure-random": "1.1.2" - } - }, - "secure-random": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/secure-random/-/secure-random-1.1.2.tgz", - "integrity": "sha512-H2bdSKERKdBV1SwoqYm6C0y+9EA94v6SUBOWO8kDndc4NoUih7Dv6Tsgma7zO1lv27wIvjlD0ZpMQk7um5dheQ==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "sha3": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", - "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", - "requires": { - "buffer": "6.0.3" - }, - "dependencies": { - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - } - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "type-tagger": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/type-tagger/-/type-tagger-1.0.0.tgz", - "integrity": "sha512-FIPqqpmDgdaulCnRoKv1/d3U4xVBUrYn42QXWNP3XYmgfPUDuBUsgFOb9ntT0aIe0UsUP+lknpQ5d9Kn36RssA==" - }, - "unorm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", - "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - } - } -} diff --git a/contracts/amm_pair/testscript/package.json b/contracts/amm_pair/testscript/package.json deleted file mode 100644 index 2aa0d94..0000000 --- a/contracts/amm_pair/testscript/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "cosmostest", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@cosmjs/launchpad": "^0.27.1", - "secretjs": "^0.17.5" - } -} diff --git a/contracts/amm_pair/testscript/scripts/deployment.js b/contracts/amm_pair/testscript/scripts/deployment.js deleted file mode 100644 index d4cad4f..0000000 --- a/contracts/amm_pair/testscript/scripts/deployment.js +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env node -import { SecretNetworkClient } from "secretjs"; -/* eslint-disable @typescript-eslint/camelcase */ -const { - BroadcastMode, EnigmaUtils, Secp256k1Pen, CosmWasmClient, SigningCosmWasmClient, pubkeyToAddress, encodeSecp256k1Pubkey, makeSignBytes -} = require("secretjs"); -const { Encoding } = require("@iov/encoding"); -const { coin } = require("@cosmjs/launchpad"); -const { - Bip39, - Random, -} = require("@cosmjs/crypto"); - -const fs = require("fs"); - -function usage() { - console.log("node secretjs-example-writing.js") -} - -const customFees = { - upload: { - amount: [{ amount: "2000000", denom: "uscrt" }], - gas: "2000000", - }, - init: { - amount: [{ amount: "500000", denom: "uscrt" }], - gas: "500000", - }, - exec: { - amount: [{ amount: "500000", denom: "uscrt" }], - gas: "500000", - }, - send: { - amount: [{ amount: "80000", denom: "uscrt" }], - gas: "80000", - }, -} - - - -// loadOrCreateMnemonic will try to load a mnemonic from the file. -// If missing, it will generate a random one and save to the file. -// -// This is not secure, but does allow simple developer access to persist a -// mnemonic between sessions -const loadOrCreateMnemonic = (filename) => { - try { - const mnemonic = fs.readFileSync(filename, "utf8"); - return mnemonic.trim(); - console.log(`mnemonic=${mnemonic}`) - } catch (err) { - const mnemonic = Bip39.encode(Random.getBytes(16)).toString(); - - console.log(`mnemonic=${mnemonic}`) - fs.writeFileSync(filename, mnemonic, "utf8"); - return mnemonic; - } -} - -const mnemonicToAddress = async (prefix, mnemonic) => { - const pen = await Secp256k1Pen.fromMnemonic(mnemonic); - const pubkey = encodeSecp256k1Pubkey(pen.pubkey); - return pubkeyToAddress(pubkey, prefix); -} - -async function main() { - - const httpUrl = "https://api.pulsar.griptapejs.com:443" - const rpcUrl = "https://rpc.pulsar.griptapejs.com:443" - - // Tp use holodeck testnet instead - // const httpUrl = "https://bootstrap.secrettestnet.io"; - - // mainnet - // const httpUrl = "https://api.secretapi.io/"; - - const mnemonic = loadOrCreateMnemonic("foo.key"); - const signingPen = await Secp256k1Pen.fromMnemonic(mnemonic); - const walletAddress = await mnemonicToAddress("secret", mnemonic); - - const txEncryptionSeed = EnigmaUtils.GenerateNewSeed(); - const client = new SigningCosmWasmClient( - httpUrl, - walletAddress, - (signBytes) => signingPen.sign(signBytes), - txEncryptionSeed, customFees - ); - - const secretjs = await SecretNetworkClient.create({ - grpcWebUrl: rpcUrl, - chainId: "pulsar-2", - }); - - - const { - balance: { amount }, - } = await secretjs.query.bank.balance({ - address: "secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03", - denom: "uscrt", - }); - - console.log(`I have ${Number(amount) / 1e6} SCRT!`); - - - console.log(`Wallet address=${walletAddress}`) - const snip20wasm = fs.readFileSync("./contracts/amm_pair/snip20/contract.wasm.gz"); - const uploadSnip20Receipt = await client.upload(snip20wasm, {}); - const wasm = fs.readFileSync("./contracts/amm_pair/contract.wasm.gz"); - const uploadReceipt = await client.upload(wasm, {}); - - // Get the code ID from the receipt - const codeId = uploadReceipt.codeId; - - // Create an instance - const initMsg = { "count": 0 } - - const contract = await client.instantiate(codeId, initMsg, "My Counter 2") - console.log('Contract initialized') - - const contractAddress = contract.contractAddress - - // Query the current count - let response = await client.queryContractSmart(contractAddress, { "get_count": {} }) - - console.log(`Count=${response.count}`) - - // The message to increment the counter requires no params - const handleMsg = { increment: {} } - - // execute the message - await client.execute(contractAddress, handleMsg); - - // Query again to confirm it worked - response = await client.queryContractSmart(contractAddress, { "get_count": {} }) - - console.log(`New Count=${response.count}`) -} - -main().then( - () => { - process.exit(0); - }, - error => { - console.error(error); - process.exit(1); - }, -); \ No newline at end of file diff --git a/contracts/amm_pair/testscript/yarn.lock b/contracts/amm_pair/testscript/yarn.lock deleted file mode 100644 index 5a53467..0000000 --- a/contracts/amm_pair/testscript/yarn.lock +++ /dev/null @@ -1,603 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@cosmjs/amino@0.27.1": - "integrity" "sha512-w56ar/nK9+qlvWDpBPRmD0Blk2wfkkLqRi1COs1x7Ll1LF0AtkIBUjbRKplENLbNovK0T3h+w8bHiFm+GBGQOA==" - "resolved" "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.27.1.tgz" - "version" "0.27.1" - dependencies: - "@cosmjs/crypto" "0.27.1" - "@cosmjs/encoding" "0.27.1" - "@cosmjs/math" "0.27.1" - "@cosmjs/utils" "0.27.1" - -"@cosmjs/crypto@0.27.1": - "integrity" "sha512-vbcxwSt99tIYJg8Spp00wc3zx72qx+pY3ozGuBN8gAvySnagK9dQ/jHwtWQWdammmdD6oW+75WfIHZ+gNa+Ybg==" - "resolved" "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.27.1.tgz" - "version" "0.27.1" - dependencies: - "@cosmjs/encoding" "0.27.1" - "@cosmjs/math" "0.27.1" - "@cosmjs/utils" "0.27.1" - "bip39" "^3.0.2" - "bn.js" "^5.2.0" - "elliptic" "^6.5.3" - "js-sha3" "^0.8.0" - "libsodium-wrappers" "^0.7.6" - "ripemd160" "^2.0.2" - "sha.js" "^2.4.11" - -"@cosmjs/encoding@^0.20.0": - "integrity" "sha512-aBp153iq2LD4GwDGwodDWZk/eyAUZ8J8bbiqZ1uK8rrylzm9Rdw84aa6JxykezJe+uBPtoI4lx9eH7VQXCGDXw==" - "resolved" "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.20.1.tgz" - "version" "0.20.1" - dependencies: - "base64-js" "^1.3.0" - "bech32" "^1.1.4" - "readonly-date" "^1.0.0" - -"@cosmjs/encoding@0.27.1": - "integrity" "sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==" - "resolved" "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.27.1.tgz" - "version" "0.27.1" - dependencies: - "base64-js" "^1.3.0" - "bech32" "^1.1.4" - "readonly-date" "^1.0.0" - -"@cosmjs/launchpad@^0.27.1": - "integrity" "sha512-DcFwGD/z5PK8CzO2sojDxa+Be9EIEtRZb2YawgVnw2Ht/p5FlNv+OVo8qlishpBdalXEN7FvQ1dVeDFEe9TuJw==" - "resolved" "https://registry.npmjs.org/@cosmjs/launchpad/-/launchpad-0.27.1.tgz" - "version" "0.27.1" - dependencies: - "@cosmjs/amino" "0.27.1" - "@cosmjs/crypto" "0.27.1" - "@cosmjs/encoding" "0.27.1" - "@cosmjs/math" "0.27.1" - "@cosmjs/utils" "0.27.1" - "axios" "^0.21.2" - "fast-deep-equal" "^3.1.3" - -"@cosmjs/math@^0.20.0": - "integrity" "sha512-xt7BmpSw2OVGM2+JhlJvKv9OJs9+3DqgVL6+byUDC355CSISrZhFjJg9GFko1EFssDXz5YgvBZR5FkifC0xazw==" - "resolved" "https://registry.npmjs.org/@cosmjs/math/-/math-0.20.1.tgz" - "version" "0.20.1" - dependencies: - "bn.js" "^4.11.8" - -"@cosmjs/math@0.27.1": - "integrity" "sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ==" - "resolved" "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz" - "version" "0.27.1" - dependencies: - "bn.js" "^5.2.0" - -"@cosmjs/utils@^0.20.0": - "integrity" "sha512-xl9YnIrAAaBd6nFffwFbyrnKjqjD9zKGP8OBKxzyglxamHfqAS+PcJPEiaEpt+oUt7HAIOyhL3KK75Dh52hGvA==" - "resolved" "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.20.1.tgz" - "version" "0.20.1" - -"@cosmjs/utils@0.27.1": - "integrity" "sha512-VG7QPDiMUzVPxRdJahDV8PXxVdnuAHiIuG56hldV4yPnOz/si/DLNd7VAUUA5923b6jS1Hhev0Hr6AhEkcxBMg==" - "resolved" "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz" - "version" "0.27.1" - -"@iov/crypto@2.1.0": - "integrity" "sha512-jnb4XuK50admolm7fBxOcxfAW2TO+wYrZlhDWiMETItY/Y5gNNa1zaDSO2wNIjjfGng+8nQ1yqnNhqy7busV2Q==" - "resolved" "https://registry.npmjs.org/@iov/crypto/-/crypto-2.1.0.tgz" - "version" "2.1.0" - dependencies: - "@iov/encoding" "^2.1.0" - "bip39" "^3.0.2" - "bn.js" "^4.11.8" - "elliptic" "^6.4.0" - "js-sha3" "^0.8.0" - "libsodium-wrappers" "^0.7.6" - "pbkdf2" "^3.0.16" - "ripemd160" "^2.0.2" - "sha.js" "^2.4.11" - "type-tagger" "^1.0.0" - "unorm" "^1.5.0" - -"@iov/encoding@^2.1.0": - "integrity" "sha512-HGHLlQEvD23rFjW5PQrxD2B/6LiBHVSxqX6gjOz9KfcmIMIftRA0qROrTITfjjjUr/yZZEeNk4qjuBls9TaYcA==" - "resolved" "https://registry.npmjs.org/@iov/encoding/-/encoding-2.5.0.tgz" - "version" "2.5.0" - dependencies: - "@cosmjs/encoding" "^0.20.0" - "@cosmjs/math" "^0.20.0" - "@cosmjs/utils" "^0.20.0" - "readonly-date" "^1.0.0" - -"@iov/encoding@2.1.0": - "integrity" "sha512-5IOdLO7Xg/uRykuiCqeMYghQ3IjWDtGxv7NTWXkgpHuna0aewx43mRpT2NPCpOZd1tpuorDtQ7/zbDNRaIIF/w==" - "resolved" "https://registry.npmjs.org/@iov/encoding/-/encoding-2.1.0.tgz" - "version" "2.1.0" - dependencies: - "base64-js" "^1.3.0" - "bech32" "^1.1.3" - "bn.js" "^4.11.8" - "readonly-date" "^1.0.0" - -"@iov/utils@2.0.2": - "integrity" "sha512-4D8MEvTcFc/DVy5q25vHxRItmgJyeX85dixMH+MxdKr+yy71h3sYk+sVBEIn70uqGP7VqAJkGOPNFs08/XYELw==" - "resolved" "https://registry.npmjs.org/@iov/utils/-/utils-2.0.2.tgz" - "version" "2.0.2" - -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - "integrity" "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - "resolved" "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" - "version" "1.1.2" - -"@protobufjs/base64@^1.1.2": - "integrity" "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - "resolved" "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz" - "version" "1.1.2" - -"@protobufjs/codegen@^2.0.4": - "integrity" "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - "resolved" "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz" - "version" "2.0.4" - -"@protobufjs/eventemitter@^1.1.0": - "integrity" "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - "resolved" "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" - "version" "1.1.0" - -"@protobufjs/fetch@^1.1.0": - "integrity" "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=" - "resolved" "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" - "version" "1.1.0" - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - "integrity" "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - "resolved" "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" - "version" "1.0.2" - -"@protobufjs/inquire@^1.1.0": - "integrity" "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - "resolved" "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" - "version" "1.1.0" - -"@protobufjs/path@^1.1.2": - "integrity" "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - "resolved" "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz" - "version" "1.1.2" - -"@protobufjs/pool@^1.1.0": - "integrity" "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - "resolved" "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz" - "version" "1.1.0" - -"@protobufjs/utf8@^1.1.0": - "integrity" "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - "resolved" "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" - "version" "1.1.0" - -"@types/long@^4.0.1": - "integrity" "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - "resolved" "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" - "version" "4.0.2" - -"@types/node@>=13.7.0": - "integrity" "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" - "resolved" "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz" - "version" "17.0.29" - -"@types/node@11.11.6": - "integrity" "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" - "resolved" "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz" - "version" "11.11.6" - -"axios@^0.21.2": - "integrity" "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==" - "resolved" "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" - "version" "0.21.4" - dependencies: - "follow-redirects" "^1.14.0" - -"axios@0.21.1": - "integrity" "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==" - "resolved" "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz" - "version" "0.21.1" - dependencies: - "follow-redirects" "^1.10.0" - -"base64-js@^1.0.2", "base64-js@^1.3.0", "base64-js@^1.3.1": - "integrity" "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - "resolved" "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" - "version" "1.5.1" - -"bech32@^1.1.3", "bech32@^1.1.4": - "integrity" "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" - "resolved" "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" - "version" "1.1.4" - -"bip39@^3.0.2": - "integrity" "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==" - "resolved" "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz" - "version" "3.0.4" - dependencies: - "@types/node" "11.11.6" - "create-hash" "^1.1.0" - "pbkdf2" "^3.0.9" - "randombytes" "^2.0.1" - -"bn.js@^4.11.8", "bn.js@^4.11.9": - "integrity" "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - "version" "4.12.0" - -"bn.js@^5.2.0": - "integrity" "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - "resolved" "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz" - "version" "5.2.0" - -"brorand@^1.1.0": - "integrity" "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - "resolved" "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" - "version" "1.1.0" - -"buffer@~5.4.3": - "integrity" "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==" - "resolved" "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz" - "version" "5.4.3" - dependencies: - "base64-js" "^1.0.2" - "ieee754" "^1.1.4" - -"buffer@6.0.3": - "integrity" "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==" - "resolved" "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" - "version" "6.0.3" - dependencies: - "base64-js" "^1.3.1" - "ieee754" "^1.2.1" - -"charenc@~0.0.1": - "integrity" "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - "resolved" "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz" - "version" "0.0.2" - -"cipher-base@^1.0.1", "cipher-base@^1.0.3": - "integrity" "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==" - "resolved" "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" - "version" "1.0.4" - dependencies: - "inherits" "^2.0.1" - "safe-buffer" "^5.0.1" - -"create-hash@^1.1.0", "create-hash@^1.1.2": - "integrity" "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==" - "resolved" "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" - "version" "1.2.0" - dependencies: - "cipher-base" "^1.0.1" - "inherits" "^2.0.1" - "md5.js" "^1.3.4" - "ripemd160" "^2.0.1" - "sha.js" "^2.4.0" - -"create-hmac@^1.1.4": - "integrity" "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==" - "resolved" "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" - "version" "1.1.7" - dependencies: - "cipher-base" "^1.0.3" - "create-hash" "^1.1.0" - "inherits" "^2.0.1" - "ripemd160" "^2.0.0" - "safe-buffer" "^5.0.1" - "sha.js" "^2.4.8" - -"crypt@~0.0.1": - "integrity" "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" - "resolved" "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz" - "version" "0.0.2" - -"curve25519-js@0.0.4": - "integrity" "sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==" - "resolved" "https://registry.npmjs.org/curve25519-js/-/curve25519-js-0.0.4.tgz" - "version" "0.0.4" - -"elliptic@^6.4.0", "elliptic@^6.5.3": - "integrity" "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==" - "resolved" "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" - "version" "6.5.4" - dependencies: - "bn.js" "^4.11.9" - "brorand" "^1.1.0" - "hash.js" "^1.0.0" - "hmac-drbg" "^1.0.1" - "inherits" "^2.0.4" - "minimalistic-assert" "^1.0.1" - "minimalistic-crypto-utils" "^1.0.1" - -"fast-deep-equal@^3.1.3": - "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" - "version" "3.1.3" - -"fast-deep-equal@3.1.1": - "integrity" "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" - "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz" - "version" "3.1.1" - -"follow-redirects@^1.10.0", "follow-redirects@^1.14.0": - "integrity" "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" - "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz" - "version" "1.14.9" - -"hash-base@^3.0.0": - "integrity" "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==" - "resolved" "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz" - "version" "3.1.0" - dependencies: - "inherits" "^2.0.4" - "readable-stream" "^3.6.0" - "safe-buffer" "^5.2.0" - -"hash.js@^1.0.0", "hash.js@^1.0.3", "hash.js@~1.1.7": - "integrity" "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==" - "resolved" "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" - "version" "1.1.7" - dependencies: - "inherits" "^2.0.3" - "minimalistic-assert" "^1.0.1" - -"hmac-drbg@^1.0.1": - "integrity" "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=" - "resolved" "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" - "version" "1.0.1" - dependencies: - "hash.js" "^1.0.3" - "minimalistic-assert" "^1.0.0" - "minimalistic-crypto-utils" "^1.0.1" - -"ieee754@^1.1.4", "ieee754@^1.2.1": - "integrity" "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - "resolved" "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" - "version" "1.2.1" - -"inherits@^2.0.1", "inherits@^2.0.3", "inherits@^2.0.4": - "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - "version" "2.0.4" - -"is-buffer@~1.1.1": - "integrity" "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - "resolved" "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" - "version" "1.1.6" - -"js-crypto-env@^0.3.2": - "integrity" "sha512-F1uHiCkSOo36qBuuZABA4sBf+xeFBzhJZ0Sd7af8FAruszIhm1Xxv+Zr5Ne90Zlh7/fnxCsrdkj0N8f0a3lVlQ==" - "resolved" "https://registry.npmjs.org/js-crypto-env/-/js-crypto-env-0.3.2.tgz" - "version" "0.3.2" - -"js-crypto-hash@^0.6.3": - "integrity" "sha512-SG8c9tM8y3sUb4k7WvpVfu5vU7zfPvX+eaYR5578TvehkehdaQbqAc+y+1FwxnqQ3WZ0gsYoOKp/mW+mqtNoWA==" - "resolved" "https://registry.npmjs.org/js-crypto-hash/-/js-crypto-hash-0.6.3.tgz" - "version" "0.6.3" - dependencies: - "buffer" "~5.4.3" - "hash.js" "~1.1.7" - "js-crypto-env" "^0.3.2" - "md5" "~2.2.1" - "sha3" "~2.1.0" - -"js-crypto-hkdf@0.7.3": - "integrity" "sha512-eAaVArAjS2GCacWGXY4hjBiexrLQYlI0PMOcbwtrSEj84XU3kUfMYZm9bpTyaTXgdHC/eQoXe/Of6biG+RSEaQ==" - "resolved" "https://registry.npmjs.org/js-crypto-hkdf/-/js-crypto-hkdf-0.7.3.tgz" - "version" "0.7.3" - dependencies: - "js-crypto-env" "^0.3.2" - "js-crypto-hmac" "^0.6.3" - "js-crypto-random" "^0.4.3" - "js-encoding-utils" "0.5.6" - -"js-crypto-hmac@^0.6.3": - "integrity" "sha512-T0pKOaHACOSG6Xs6/06G8RDDeZouQwIQNBq9L/zoUGsd4F67gAjpT3q2lGigAGpUd1hiyy7vnhvLpz7VDt6DbA==" - "resolved" "https://registry.npmjs.org/js-crypto-hmac/-/js-crypto-hmac-0.6.3.tgz" - "version" "0.6.3" - dependencies: - "js-crypto-env" "^0.3.2" - "js-crypto-hash" "^0.6.3" - -"js-crypto-random@^0.4.3": - "integrity" "sha512-C3gzphPPfw9jfQ9Q/LjhJMZxQNp3AaoVRDvyZkiB+zYltfs8tKQPsskWkXACpg1Nzh01PtSRUvVijjptd2qGHQ==" - "resolved" "https://registry.npmjs.org/js-crypto-random/-/js-crypto-random-0.4.3.tgz" - "version" "0.4.3" - dependencies: - "js-crypto-env" "^0.3.2" - -"js-encoding-utils@0.5.6": - "integrity" "sha512-qnAGsUIWrmzh5n+3AXqbxX1KsB9hkQmJZf3aA9DLAS7GpL/NEHCBreFFbW+imramoU+Q0TDyvkwhRbBRH1TVkg==" - "resolved" "https://registry.npmjs.org/js-encoding-utils/-/js-encoding-utils-0.5.6.tgz" - "version" "0.5.6" - -"js-sha3@^0.8.0": - "integrity" "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - "resolved" "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" - "version" "0.8.0" - -"libsodium-wrappers@^0.7.6": - "integrity" "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==" - "resolved" "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz" - "version" "0.7.10" - dependencies: - "libsodium" "^0.7.0" - -"libsodium@^0.7.0": - "integrity" "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" - "resolved" "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz" - "version" "0.7.10" - -"long@^4.0.0": - "integrity" "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - "resolved" "https://registry.npmjs.org/long/-/long-4.0.0.tgz" - "version" "4.0.0" - -"md5.js@^1.3.4": - "integrity" "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==" - "resolved" "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" - "version" "1.3.5" - dependencies: - "hash-base" "^3.0.0" - "inherits" "^2.0.1" - "safe-buffer" "^5.1.2" - -"md5@~2.2.1": - "integrity" "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=" - "resolved" "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz" - "version" "2.2.1" - dependencies: - "charenc" "~0.0.1" - "crypt" "~0.0.1" - "is-buffer" "~1.1.1" - -"minimalistic-assert@^1.0.0", "minimalistic-assert@^1.0.1": - "integrity" "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - "resolved" "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" - "version" "1.0.1" - -"minimalistic-crypto-utils@^1.0.1": - "integrity" "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - "resolved" "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" - "version" "1.0.1" - -"miscreant@0.3.2": - "integrity" "sha512-fL9KxsQz9BJB2KGPMHFrReioywkiomBiuaLk6EuChijK0BsJsIKJXdVomR+/bPj5mvbFD6wM0CM3bZio9g7OHA==" - "resolved" "https://registry.npmjs.org/miscreant/-/miscreant-0.3.2.tgz" - "version" "0.3.2" - -"pako@1.0.11": - "integrity" "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - "resolved" "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" - "version" "1.0.11" - -"pbkdf2@^3.0.16", "pbkdf2@^3.0.9": - "integrity" "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==" - "resolved" "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" - "version" "3.1.2" - dependencies: - "create-hash" "^1.1.2" - "create-hmac" "^1.1.4" - "ripemd160" "^2.0.1" - "safe-buffer" "^5.0.1" - "sha.js" "^2.4.8" - -"protobufjs@^6.11.2": - "integrity" "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==" - "resolved" "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz" - "version" "6.11.2" - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - "long" "^4.0.0" - -"randombytes@^2.0.1": - "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==" - "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - "version" "2.1.0" - dependencies: - "safe-buffer" "^5.1.0" - -"readable-stream@^3.6.0": - "integrity" "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==" - "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" - "version" "3.6.0" - dependencies: - "inherits" "^2.0.3" - "string_decoder" "^1.1.1" - "util-deprecate" "^1.0.1" - -"readonly-date@^1.0.0": - "integrity" "sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==" - "resolved" "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz" - "version" "1.0.0" - -"ripemd160@^2.0.0", "ripemd160@^2.0.1", "ripemd160@^2.0.2": - "integrity" "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==" - "resolved" "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" - "version" "2.0.2" - dependencies: - "hash-base" "^3.0.0" - "inherits" "^2.0.1" - -"safe-buffer@^5.0.1", "safe-buffer@^5.1.0", "safe-buffer@^5.1.2", "safe-buffer@^5.2.0", "safe-buffer@~5.2.0": - "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - "version" "5.2.1" - -"secretjs@^0.17.5": - "integrity" "sha512-sf0+Je9KIEMQr/wJOgeqyBOV0ruiMNHSwP4L2vXiJbtzJWQqyVHyPkpavAhruNZ+91XlSzAFP2X5MPxqPBC9fQ==" - "resolved" "https://registry.npmjs.org/secretjs/-/secretjs-0.17.5.tgz" - "version" "0.17.5" - dependencies: - "@iov/crypto" "2.1.0" - "@iov/encoding" "2.1.0" - "@iov/utils" "2.0.2" - "axios" "0.21.1" - "curve25519-js" "0.0.4" - "fast-deep-equal" "3.1.1" - "js-crypto-hkdf" "0.7.3" - "miscreant" "0.3.2" - "pako" "1.0.11" - "protobufjs" "^6.11.2" - "secure-random" "1.1.2" - -"secure-random@1.1.2": - "integrity" "sha512-H2bdSKERKdBV1SwoqYm6C0y+9EA94v6SUBOWO8kDndc4NoUih7Dv6Tsgma7zO1lv27wIvjlD0ZpMQk7um5dheQ==" - "resolved" "https://registry.npmjs.org/secure-random/-/secure-random-1.1.2.tgz" - "version" "1.1.2" - -"sha.js@^2.4.0", "sha.js@^2.4.11", "sha.js@^2.4.8": - "integrity" "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==" - "resolved" "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" - "version" "2.4.11" - dependencies: - "inherits" "^2.0.1" - "safe-buffer" "^5.0.1" - -"sha3@~2.1.0": - "integrity" "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==" - "resolved" "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz" - "version" "2.1.4" - dependencies: - "buffer" "6.0.3" - -"string_decoder@^1.1.1": - "integrity" "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" - "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - "version" "1.3.0" - dependencies: - "safe-buffer" "~5.2.0" - -"type-tagger@^1.0.0": - "integrity" "sha512-FIPqqpmDgdaulCnRoKv1/d3U4xVBUrYn42QXWNP3XYmgfPUDuBUsgFOb9ntT0aIe0UsUP+lknpQ5d9Kn36RssA==" - "resolved" "https://registry.npmjs.org/type-tagger/-/type-tagger-1.0.0.tgz" - "version" "1.0.0" - -"unorm@^1.5.0": - "integrity" "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" - "resolved" "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz" - "version" "1.6.0" - -"util-deprecate@^1.0.1": - "integrity" "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - "version" "1.0.2" diff --git a/contracts/factory/.github/workflows/Basic.yml b/contracts/factory/.github/workflows/Basic.yml deleted file mode 100644 index 196aebc..0000000 --- a/contracts/factory/.github/workflows/Basic.yml +++ /dev/null @@ -1,81 +0,0 @@ -# Based on https://github.com/actions-rs/example/blob/master/.github/workflows/quickstart.yml - -on: [push, pull_request] - -name: Basic - -jobs: - - test: - name: Test Suite - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.43.1 - target: wasm32-unknown-unknown - override: true - - - name: Run unit tests - uses: actions-rs/cargo@v1 - with: - command: unit-test - args: --locked - env: - RUST_BACKTRACE: 1 - - - name: Compile WASM contract - uses: actions-rs/cargo@v1 - with: - command: wasm - args: --locked - env: - RUSTFLAGS: "-C link-arg=-s" - - - name: Run integration tests - uses: actions-rs/cargo@v1 - with: - command: integration-test - args: --locked - - - lints: - name: Lints - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.43.1 - override: true - components: rustfmt, clippy - - - name: Run cargo fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -- -D warnings - - # TODO: we should check - # CHANGES_IN_REPO=$(git status --porcelain) - # after this, but I don't know how - - name: Generate Schema - uses: actions-rs/cargo@v1 - with: - command: schema - args: --locked diff --git a/contracts/factory/Cargo.toml b/contracts/factory/Cargo.toml index 6291d47..5729474 100644 --- a/contracts/factory/Cargo.toml +++ b/contracts/factory/Cargo.toml @@ -32,7 +32,11 @@ schemars = "0.8.1" cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } shadeswap-shared = {path = "../../packages/shadeswap-shared"} -secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } [dev-dependencies] -cosmwasm-schema = { git = "https://github.com/CosmWasm/cosmwasm" } +cosmwasm-schema = { git = "https://github.com/CosmWasm/cosmwasm"} +snip20-reference-impl = {path ="../../contracts/snip20"} +secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } +query-authentication = { git = "https://github.com/securesecrets/query-authentication", branch = "cosmwasm_v1_upgrade" } +multi_test = {path = "../../packages/multi_test"} +amm_pair = {path ="../../contracts/amm_pair"} diff --git a/contracts/factory/rustfmt.toml b/contracts/factory/rustfmt.toml deleted file mode 100644 index 11a85e6..0000000 --- a/contracts/factory/rustfmt.toml +++ /dev/null @@ -1,15 +0,0 @@ -# stable -newline_style = "unix" -hard_tabs = false -tab_spaces = 4 - -# unstable... should we require `rustup run nightly cargo fmt` ? -# or just update the style guide when they are stable? -#fn_single_line = true -#format_code_in_doc_comments = true -#overflow_delimited_expr = true -#reorder_impl_items = true -#struct_field_align_threshold = 20 -#struct_lit_single_line = true -#report_todo = "Always" - diff --git a/contracts/factory/src/contract.rs b/contracts/factory/src/contract.rs index 56cac9c..8935d08 100644 --- a/contracts/factory/src/contract.rs +++ b/contracts/factory/src/contract.rs @@ -1,17 +1,18 @@ use crate::{ operations::{ - add_amm_pairs, create_pair, list_pairs, query_amm_pair_address, - register_amm_pair, set_config, + add_amm_pairs, create_pair, list_pairs, query_amm_pair_address, register_amm_pair, + set_config, }, state::{config_r, config_w, ephemeral_storage_r, ephemeral_storage_w, prng_seed_w, Config}, }; use cosmwasm_std::{ entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, - StdResult, SubMsgResult, + StdResult, SubMsgResult, Addr, }; use shadeswap_shared::{ + admin::helpers::{validate_admin, AdminPermissions}, amm_pair::AMMPair, - core::{admin_r, admin_w, apply_admin_guard, ViewingKey}, + core::ViewingKey, msg::factory::{ExecuteMsg, InitMsg, QueryMsg, QueryResponse}, utils::{pad_query_result, pad_response_result}, BLOCK_SIZE, @@ -28,7 +29,6 @@ pub fn instantiate( ) -> StdResult { prng_seed_w(deps.storage).save(&msg.prng_seed)?; config_w(deps.storage).save(&Config::from_init_msg(msg))?; - admin_w(deps.storage).save(&_info.sender)?; Ok(Response::default()) } @@ -36,22 +36,25 @@ pub fn instantiate( pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> StdResult { pad_response_result( match msg { + //Only admins can create pairs via factory ExecuteMsg::CreateAMMPair { pair, entropy, staking_contract, - router_contract, } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; create_pair( deps, env, - &info, pair, - info.sender.clone(), entropy, - staking_contract, - router_contract, + staking_contract ) } ExecuteMsg::SetConfig { @@ -59,46 +62,34 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S lp_token_contract, amm_settings, api_key, + admin_auth, } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; set_config( pair_contract, lp_token_contract, amm_settings, deps.storage, api_key, + admin_auth ) } ExecuteMsg::AddAMMPairs { amm_pairs } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; add_amm_pairs(deps.storage, amm_pairs) } - ExecuteMsg::SetAdmin { admin } => { - apply_admin_guard(&info.sender, deps.storage)?; - admin_w(deps.storage).save(&admin)?; - Ok(Response::default()) - } - ExecuteMsg::RegisterAMMPair { pair, signature } => { - let config = ephemeral_storage_r(deps.storage).load()?; - if config.key != signature { - return Err(StdError::generic_err("Invalid signature given".to_string())); - } - if pair != config.pair { - return Err(StdError::generic_err( - "Provided pair is not equal.".to_string(), - )); - } - ephemeral_storage_w(deps.storage).remove(); - register_amm_pair( - deps.storage, - env, - AMMPair { - pair: config.pair, - address: info.sender, - enabled: true, - }, - ) - } }, BLOCK_SIZE, ) @@ -115,22 +106,18 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { lp_token_contract, api_key: _, authenticator, + admin_auth } = config_r(deps.storage).load()?; to_binary(&QueryResponse::GetConfig { pair_contract, amm_settings, lp_token_contract, authenticator, + admin_auth }) } QueryMsg::ListAMMPairs { pagination } => list_pairs(deps, pagination), QueryMsg::GetAMMPairAddress { pair } => query_amm_pair_address(&deps, pair), - QueryMsg::GetAdmin {} => { - let admin_address = admin_r(deps.storage).load()?; - to_binary(&QueryResponse::GetAdmin { - address: admin_address.to_string(), - }) - } QueryMsg::AuthorizeApiKey { api_key } => { let config = config_r(deps.storage).load()?; to_binary(&QueryResponse::AuthorizeApiKey { @@ -143,7 +130,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { } #[entry_point] -pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { +pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> StdResult { pad_response_result( match (msg.id, msg.result) { (INSTANTIATE_REPLY_ID, SubMsgResult::Ok(s)) => match s.data { @@ -152,10 +139,9 @@ pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> StdResult { let config = ephemeral_storage_r(deps.storage).load()?; register_amm_pair( deps.storage, - _env, AMMPair { pair: config.pair, - address: deps.api.addr_validate(&contract_address)?, + address: deps.api.addr_validate(&contract_address.replace(" ", ""))?, enabled: true, }, )?; diff --git a/contracts/factory/src/operations.rs b/contracts/factory/src/operations.rs index 854121b..c53c525 100644 --- a/contracts/factory/src/operations.rs +++ b/contracts/factory/src/operations.rs @@ -3,27 +3,25 @@ use crate::{ amm_pair_keys_r, amm_pair_keys_w, amm_pairs_r, amm_pairs_w, config_r, config_w, ephemeral_storage_w, prng_seed_r, total_amm_pairs_r, total_amm_pairs_w, NextPairKey, PAGINATION_LIMIT, - }, + }, contract::INSTANTIATE_REPLY_ID, }; use cosmwasm_std::{ - to_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, - Response, StdError, StdResult, Storage, WasmMsg, + to_binary, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, + Response, StdError, StdResult, Storage, WasmMsg, SubMsg, }; use shadeswap_shared::{ amm_pair::{generate_pair_key, AMMPair, AMMSettings}, - core::{admin_r, Callback, ContractInstantiationInfo, ContractLink, TokenPair, ViewingKey}, + core::{ContractInstantiationInfo, TokenPair, ViewingKey}, msg::{ amm_pair::InitMsg as AMMPairInitMsg, - factory::{ExecuteMsg, QueryResponse}, - router::ExecuteMsg as RouterExecuteMsg, + factory::{QueryResponse}, staking::StakingContractInit, }, - Pagination, + Pagination, Contract, }; pub fn register_amm_pair( storage: &mut dyn Storage, - _env: Env, pair: AMMPair, ) -> StdResult { add_amm_pairs(storage, vec![pair]) @@ -74,6 +72,7 @@ pub fn set_config( amm_settings: Option, storage: &mut dyn Storage, api_key: Option, + admin_auth: Option, ) -> StdResult { let mut config = config_r(storage).load()?; if let Some(new_value) = pair_contract { @@ -90,6 +89,9 @@ pub fn set_config( if let Some(new_value) = api_key { config.api_key = ViewingKey(new_value); } + if let Some(new_value) = admin_auth { + config.admin_auth = new_value; + } config_w(storage).save(&config)?; @@ -99,25 +101,17 @@ pub fn set_config( pub fn create_pair( deps: DepsMut, env: Env, - info: &MessageInfo, pair: TokenPair, - sender: Addr, entropy: Binary, - staking_contract: Option, - router_contract: Option, + staking_contract: Option ) -> StdResult { let config = config_r(deps.storage).load()?; - let admin = admin_r(deps.storage).load()?; - let signature = create_signature(&env, info)?; ephemeral_storage_w(deps.storage).save(&NextPairKey { - pair: pair.clone(), - is_verified: admin == sender, - key: signature.clone(), + pair: pair.clone() })?; let mut messages = vec![]; - - messages.push(CosmosMsg::Wasm(WasmMsg::Instantiate { + messages.push(SubMsg::reply_on_success(CosmosMsg::Wasm(WasmMsg::Instantiate { code_id: config.pair_contract.id, label: format!( "{}-{}-pair-{}-{}", @@ -126,53 +120,21 @@ pub fn create_pair( msg: to_binary(&AMMPairInitMsg { pair: pair.clone(), lp_token_contract: config.lp_token_contract.clone(), - factory_info: ContractLink { + factory_info: Contract { code_hash: env.contract.code_hash.clone(), address: env.contract.address.clone(), }, - entropy, + entropy: entropy, prng_seed: prng_seed_r(deps.storage).load()?, - admin: Some(admin_r(deps.storage).load()?), + admin_auth: config.admin_auth, staking_contract: staking_contract, - custom_fee: None, - callback: Some(Callback { - msg: to_binary(&ExecuteMsg::RegisterAMMPair { - pair: pair.clone(), - signature: signature, - })?, - contract: ContractLink { - address: env.contract.address, - code_hash: env.contract.code_hash, - }, - }), + custom_fee: None })?, code_hash: config.pair_contract.code_hash, funds: vec![], - })); - - if let Some(r) = router_contract { - for p in pair.into_iter() { - match p { - shadeswap_shared::core::TokenType::CustomToken { - contract_addr, - token_code_hash, - } => { - messages.push(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: r.address.to_string(), - code_hash: r.code_hash.to_string(), - msg: to_binary(&RouterExecuteMsg::RegisterSNIP20Token { - token_addr: contract_addr.clone(), - token_code_hash: token_code_hash.clone(), - })?, - funds: vec![], - })); - } - _ => (), - } - } - } + }), INSTANTIATE_REPLY_ID)); - Ok(Response::new().add_messages(messages)) + Ok(Response::new().add_submessages(messages)) } pub(crate) fn load_amm_pairs(deps: Deps, pagination: Pagination) -> StdResult> { @@ -200,14 +162,3 @@ pub(crate) fn load_amm_pairs(deps: Deps, pagination: Pagination) -> StdResult Ok(vec![]), } } - -pub(crate) fn create_signature(env: &Env, info: &MessageInfo) -> StdResult { - to_binary( - &[ - info.sender.as_bytes(), - &env.block.height.to_be_bytes(), - &env.block.time.seconds().to_be_bytes(), - ] - .concat(), - ) -} diff --git a/contracts/factory/src/state.rs b/contracts/factory/src/state.rs index 7c910a4..4acfbf1 100644 --- a/contracts/factory/src/state.rs +++ b/contracts/factory/src/state.rs @@ -24,7 +24,8 @@ pub struct Config { pub amm_settings: AMMSettings, pub lp_token_contract: ContractInstantiationInfo, pub api_key: ViewingKey, - pub authenticator: Option + pub authenticator: Option, + pub admin_auth: Contract } impl Config { @@ -35,15 +36,14 @@ impl Config { lp_token_contract: msg.lp_token_contract, api_key: ViewingKey(msg.api_key), authenticator: msg.authenticator, + admin_auth: msg.admin_auth } } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct NextPairKey { - pub pair: TokenPair, - pub key: Binary, - pub is_verified: bool + pub pair: TokenPair } pub fn config_w(storage: &mut dyn Storage) -> Singleton { diff --git a/contracts/factory/src/test.rs b/contracts/factory/src/test.rs index 6e7cf66..6b58977 100644 --- a/contracts/factory/src/test.rs +++ b/contracts/factory/src/test.rs @@ -1,440 +1,306 @@ -// use cosmwasm_std::testing::mock_dependencies; -// use cosmwasm_std::testing::mock_env; -// use cosmwasm_std::to_binary; -// use cosmwasm_std::Addr; -// use cosmwasm_std::Deps; -// use cosmwasm_std::DepsMut; -// use cosmwasm_std::Env; -// use cosmwasm_std::{Api, Binary, CanonicalAddr, Querier, StdError, StdResult, Storage}; -// use shadeswap_shared::amm_pair::AMMSettings; -// use shadeswap_shared::core::Fee; -// use shadeswap_shared::core::{ContractInstantiationInfo, ContractLink}; -// use shadeswap_shared::msg::factory::InitMsg; -// pub use shadeswap_shared::{msg::factory::QueryResponse, Pagination}; - -// use crate::state::Config; - -// #[cfg(test)] -// pub mod test_contract { -// use super::*; -// use crate::contract::execute; -// use crate::contract::instantiate; -// use crate::contract::query; -// use crate::operations::create_pair; -// use crate::state::config_r; -// use crate::state::config_w; -// use crate::state::PAGINATION_LIMIT; -// use cosmwasm_std::from_binary; -// use cosmwasm_std::Addr; -// use cosmwasm_std::MessageInfo; -// use shadeswap_shared::amm_pair::AMMPair; -// use shadeswap_shared::core::TokenPair; -// use shadeswap_shared::core::TokenType; -// use shadeswap_shared::msg::factory::ExecuteMsg; -// use shadeswap_shared::msg::factory::QueryMsg; -// pub use shadeswap_shared::{msg::factory::QueryResponse, Pagination}; - -// #[test] -// fn init_ok() -> StdResult<()> { -// let mut deps = mock_dependencies(); -// let config = mkconfig(0); -// let env = mock_env(); -// assert!(instantiate( -// deps.as_mut(), -// env, -// MessageInfo { -// sender: Addr::unchecked("admin"), -// funds: vec![] -// }, -// (&config).into() -// ) -// .is_ok()); -// assert_eq!(config, config_r(deps.as_ref().storage).load()?); -// Ok(()) -// } - -// #[test] -// fn get_set_config_ok() -> StdResult<()> { -// let mut deps = mock_dependencies(); -// let env = mock_env(); -// instantiate( -// deps.as_mut(), -// env.clone(), -// MessageInfo { -// sender: Addr::unchecked("admin"), -// funds: vec![], -// }, -// (&mkconfig(0)).into(), -// )?; - -// let new_config = mkconfig(5); -// execute( -// deps.as_mut(), -// env, -// MessageInfo { -// sender: Addr::unchecked("admin"), -// funds: vec![], -// }, -// ExecuteMsg::SetConfig { -// pair_contract: Some(new_config.pair_contract.clone()), -// amm_settings: Some(new_config.amm_settings.clone()), -// lp_token_contract: Some(new_config.lp_token_contract.clone()), -// }, -// ) -// .unwrap(); - -// let response: QueryResponse = from_binary(&query(deps.as_ref(), mock_env(), QueryMsg::GetConfig {})?)?; -// let compare: QueryResponse = (&new_config).into(); -// assert_eq!(compare, response); -// Ok(()) -// } - -// // #[test] -// // fn register_amm_pair_ok() -> StdResult<()> { -// // let ref mut deps = mock_dependencies(); -// // let env = mock_env(); -// // let config = mkconfig(0); - -// // config_w(deps.as_mut().storage).save(&config)?; - -// // let signature = create_signature(&env)?; -// // save(&mut deps.storage, EPHEMERAL_STORAGE_KEY, &signature)?; - -// // let pair = TokenPair( -// // TokenType::CustomToken { -// // contract_addr: Addr::unchecked("token_addr".into()), -// // token_code_hash: "13123adasd".into(), -// // }, -// // TokenType::NativeToken { -// // denom: "test1".into(), -// // }, -// // ); - -// // execute( -// // deps, -// // env, -// // MessageInfo { -// // sender: Addr::unchecked("admin"), -// // funds: vec![] -// // }, -// // ExecuteMsg::RegisterAMMPair { -// // pair: pair.clone(), -// // signature, -// // }, -// // )?; - -// // let result: Option = load(&deps.storage, EPHEMERAL_STORAGE_KEY)?; -// // match result { -// // None => {} -// // _ => panic!("Ephemeral storage should be empty!"), -// // } - -// // Ok(()) -// // } - -// #[test] -// fn create_pair_ok() -> StdResult<()> { -// let ref mut deps = mock_dependencies(); -// let env = mock_env(); -// let config = mkconfig(0); -// assert!(instantiate( -// deps.as_mut(), -// env, -// MessageInfo { -// sender: Addr::unchecked("admin"), -// funds: vec![] -// }, -// (&config).into() -// ) -// .is_ok()); - -// let pair = TokenPair( -// TokenType::CustomToken { -// contract_addr: Addr::unchecked("token_addr"), -// token_code_hash: "diff".into(), -// }, -// TokenType::CustomToken { -// contract_addr: Addr::unchecked("token_addr"), -// token_code_hash: "13123adasd".into(), -// }, -// ); - -// let result = create_pair(deps.as_mut(), mock_env(), pair, Addr::unchecked("admin"),to_binary(&"entropy").unwrap(), None); -// assert!(result.is_ok()); -// Ok(()) -// } -// #[test] -// fn add_amm_pairs() { -// let ref mut deps = mock_dependencies(); -// let config = mkconfig(0); -// let env = mock_env(); - -// instantiate(deps.as_mut(), env.clone(), MessageInfo { -// sender: Addr::unchecked("admin"), -// funds: vec![] -// },(&config).into()).unwrap(); - -// let mut amm_pairs: Vec = vec![]; - -// for i in 0..5 { -// amm_pairs.push(AMMPair { -// pair: TokenPair( -// TokenType::CustomToken { -// contract_addr: Addr::unchecked(format!("token_0_addr_{}", i)), -// token_code_hash: format!("token_0_hash_{}", i), -// }, -// TokenType::CustomToken { -// contract_addr: Addr::unchecked(format!("token_1_addr_{}", i)), -// token_code_hash: format!("token_1_hash_{}", i), -// }, -// ), -// address: Addr::unchecked(format!("pair_addr_{}", i)), -// enabled: true, -// }); -// } - -// execute( -// deps.as_mut(), -// env, -// MessageInfo { -// sender: Addr::unchecked("admin"), -// funds: vec![] -// }, -// ExecuteMsg::AddAMMPairs { -// amm_pairs: amm_pairs.clone()[0..].into(), -// }, -// ) -// .unwrap(); - -// let result = query( -// deps.as_ref(), -// mock_env(), -// QueryMsg::ListAMMPairs { -// pagination: pagination(0, PAGINATION_LIMIT), -// }, -// ) -// .unwrap(); - -// let response: QueryResponse = from_binary(&result).unwrap(); - -// match response { -// QueryResponse::ListAMMPairs { amm_pairs: stored } => { -// assert_eq!(amm_pairs, stored) -// } -// _ => panic!("QueryResponse::ListExchanges"), -// } -// } - -// /* -// #[test] -// fn increment() { -// let mut deps = mock_dependencies(20, &coins(2, "token")); - -// let msg = InitMsg { count: 17 }; -// let env = mock_env("creator", &coins(2, "token")); -// let _res = init(&mut deps, env, msg).unwrap(); - -// // anyone can increment -// let env = mock_env("anyone", &coins(2, "token")); -// let msg = ExecuteMsg::Increment {}; -// let _res = execute(&mut deps, env, msg).unwrap(); - -// // should increase counter by 1 -// let res = query(&deps, QueryMsg::GetCount {}).unwrap(); -// let value: CountResponse = from_binary(&res).unwrap(); -// assert_eq!(18, value.count); -// } - -// #[test] -// fn reset() { -// let mut deps = mock_dependencies(20, &coins(2, "token")); - -// let msg = InitMsg { count: 17 }; -// let env = mock_env("creator", &coins(2, "token")); -// let _res = init(&mut deps, env, msg).unwrap(); - -// // not anyone can reset -// let unauth_env = mock_env("anyone", &coins(2, "token")); -// let msg = ExecuteMsg::Reset { count: 5 }; -// let res = execute(&mut deps, unauth_env, msg); -// match res { -// Err(StdError::Unauthorized { .. }) => {} -// _ => panic!("Must return unauthorized error"), -// } - -// // only the original creator can reset the counter -// let auth_env = mock_env("creator", &coins(2, "token")); -// let msg = ExecuteMsg::Reset { count: 5 }; -// let _res = execute(&mut deps, auth_env, msg).unwrap(); - -// // should now be 5 -// let res = query(&deps, QueryMsg::GetCount {}).unwrap(); -// let value: CountResponse = from_binary(&res).unwrap(); -// assert_eq!(5, value.count); -// }*/ -// } - -// // pub mod test_state { -// // use shadeswap_shared::{amm_pair::AMMPair, core::Canonize}; - -// // use super::*; - -// // fn swap_pair(pair: &TokenPair) -> TokenPair { -// // TokenPair(pair.1.clone(), pair.0.clone()) -// // } - -// // #[test] -// // fn generate_pair_key_ok() -> StdResult<()> { -// // fn cmp_pair( -// // deps: &Deps, -// // pair: TokenPair, -// // ) -> StdResult<()> { -// // let stored_pair = pair.clone().canonize(&deps.api)?; -// // let key = generate_pair_key(&stored_pair); - -// // let pair = swap_pair(&pair.clone()); - -// // let stored_pair = pair.canonize(&deps.api)?; -// // let swapped_key = generate_pair_key(&stored_pair); - -// // assert_eq!(key, swapped_key); - -// // Ok(()) -// // } - -// // let ref deps = mock_dependencies(); - -// // cmp_pair( -// // deps, -// // TokenPair( -// // TokenType::CustomToken { -// // contract_addr: Addr::unchecked("first_addr".into()), -// // token_code_hash: "13123adasd".into(), -// // }, -// // TokenType::CustomToken { -// // contract_addr: Addr::unchecked("scnd_addr".into()), -// // token_code_hash: "4534qwerqqw".into(), -// // }, -// // ), -// // )?; - -// // cmp_pair( -// // deps, -// // TokenPair( -// // TokenType::NativeToken { -// // denom: "test1".into(), -// // }, -// // TokenType::NativeToken { -// // denom: "test2".into(), -// // }, -// // ), -// // )?; - -// // cmp_pair( -// // deps, -// // TokenPair( -// // TokenType::NativeToken { -// // denom: "test3".into(), -// // }, -// // TokenType::CustomToken { -// // contract_addr: Addr::unchecked("third_addr".into()), -// // token_code_hash: "asd21312asd".into(), -// // }, -// // ), -// // )?; - -// // Ok(()) -// // } - -// // #[test] -// // fn store_and_get_amm_pairs_ok() { -// // let ref mut deps = mock_dependencies(); -// // let mut amm_pairs: Vec = vec![]; -// // amm_pairs.push(AMMPair { -// // pair: TokenPair( -// // TokenType::CustomToken { -// // contract_addr: format!("token_0_addr_{}", 0).into(), -// // token_code_hash: format!("token_0_hash_{}", 0), -// // }, -// // TokenType::CustomToken { -// // contract_addr: format!("token_1_addr_{}", 0).into(), -// // token_code_hash: format!("token_1_hash_{}", 0), -// // }, -// // ), -// // address: format!("pair_addr_{}", 0).into(), -// // }); -// // save_amm_pairs(deps, amm_pairs.clone()).unwrap(); -// // let result = load_amm_pairs(deps, pagination(0, 1)).unwrap(); - -// // //Check Count was updated -// // assert_eq!(1, load_amm_pairs_count(&mut deps.storage).unwrap()); - -// // //Check number of result was returned -// // assert_eq!(1, result.len()); - -// // //Match result -// // assert_eq!(amm_pairs[0], result[0]); -// // } - -// // #[test] -// // fn save_and_load_amm_pairs_count_ok() { -// // let ref mut deps = mock_dependencies(); -// // save_amm_pairs_count(&mut deps.storage, 1).unwrap(); -// // assert_eq!(1, load_amm_pairs_count(&mut deps.storage).unwrap()); -// // assert_ne!(2, load_amm_pairs_count(&mut deps.storage).unwrap()) -// // } -// // } - -// fn mkconfig(id: u64) -> Config { -// Config::from_init_msg(InitMsg { -// pair_contract: ContractInstantiationInfo { -// id, -// code_hash: "2341586789".into(), -// }, -// amm_settings: AMMSettings { -// lp_fee: Fee::new(28, 10000), -// shade_dao_fee: Fee::new(2, 10000), -// shade_dao_address: ContractLink { -// address: Addr::unchecked("CALLBACKADDR"), -// code_hash: "Test".to_string(), -// }, -// }, -// lp_token_contract: ContractInstantiationInfo { -// id, -// code_hash: "123".into(), -// }, -// prng_seed: to_binary(&"prng").unwrap(), -// }) -// } - -// fn pagination(start: u64, limit: u8) -> Pagination { -// Pagination { start, limit } -// } - -// impl Into for &Config { -// fn into(self) -> InitMsg { -// InitMsg { -// pair_contract: self.pair_contract.clone(), -// amm_settings: AMMSettings { -// lp_fee: Fee::new(28, 10000), -// shade_dao_fee: Fee::new(2, 10000), -// shade_dao_address: ContractLink { -// address: Addr::unchecked("CALLBACKADDR"), -// code_hash: "Test".to_string(), -// }, -// }, -// lp_token_contract: self.lp_token_contract.clone(), -// prng_seed: to_binary(&"prng").unwrap(), -// } -// } -// } - -// impl Into for &Config { -// fn into(self) -> QueryResponse { -// QueryResponse::GetConfig { -// pair_contract: self.pair_contract.clone(), -// amm_settings: self.amm_settings.clone(), -// lp_token_contract: self.lp_token_contract.clone(), -// } -// } -// } +use cosmwasm_std::Coin; +use cosmwasm_std::Empty; +use cosmwasm_std::OwnedDeps; +use cosmwasm_std::QuerierResult; +use cosmwasm_std::QueryRequest; +use cosmwasm_std::WasmQuery; +use cosmwasm_std::from_slice; +use cosmwasm_std::testing::MockApi; +use cosmwasm_std::testing::MockStorage; +use cosmwasm_std::testing::mock_env; +use cosmwasm_std::to_binary; +use cosmwasm_std::Addr; + +use shadeswap_shared::contract_interfaces::admin::ValidateAdminPermissionResponse; +use cosmwasm_std::{Querier, StdResult}; +use serde::Deserialize; +use serde::Serialize; +use shadeswap_shared::utils::asset::Contract; +use shadeswap_shared::amm_pair::AMMSettings; +use shadeswap_shared::core::Fee; +use shadeswap_shared::core::{ContractInstantiationInfo}; +use shadeswap_shared::msg::factory::InitMsg; +pub use shadeswap_shared::{msg::factory::QueryResponse, Pagination}; +use shadeswap_shared::snip20::manager::Balance; +use crate::state::Config; + +#[cfg(test)] +pub mod test_contract { + use super::*; + use crate::contract::execute; + use crate::contract::instantiate; + use crate::contract::query; + use crate::operations::create_pair; + use crate::state::config_r; + use crate::state::PAGINATION_LIMIT; + use cosmwasm_std::from_binary; + use cosmwasm_std::Addr; + use cosmwasm_std::MessageInfo; + use cosmwasm_std::testing::mock_info; + use shadeswap_shared::amm_pair::AMMPair; + use shadeswap_shared::core::TokenPair; + use shadeswap_shared::core::TokenType; + use shadeswap_shared::msg::factory::ExecuteMsg; + use shadeswap_shared::msg::factory::QueryMsg; + pub use shadeswap_shared::{msg::factory::QueryResponse, Pagination}; + + #[test] + fn init_ok() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let config = mkconfig(0); + let env = mock_env(); + assert!(instantiate( + deps.as_mut(), + env, + MessageInfo { + sender: Addr::unchecked("admin"), + funds: vec![] + }, + create_init_msg_from_config(&config) + ) + .is_ok()); + assert_eq!(config, config_r(deps.as_ref().storage).load()?); + Ok(()) + } + + #[test] + fn get_set_config_ok() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_env(); + instantiate( + deps.as_mut(), + env.clone(), + MessageInfo { + sender: Addr::unchecked("admin"), + funds: vec![], + }, + create_init_msg_from_config(&mkconfig(0)), + )?; + + let new_config = mkconfig(5); + execute( + deps.as_mut(), + env, + MessageInfo { + sender: Addr::unchecked("admin"), + funds: vec![], + }, + ExecuteMsg::SetConfig { + pair_contract: Some(new_config.pair_contract.clone()), + amm_settings: Some(new_config.amm_settings.clone()), + lp_token_contract: Some(new_config.lp_token_contract.clone()), + api_key: Some("api_key".to_string()), + admin_auth: None, + }, + ) + .unwrap(); + + let response: QueryResponse = from_binary(&query(deps.as_ref(), mock_env(), QueryMsg::GetConfig {})?)?; + let compare: QueryResponse = create_query_response_from_config(&new_config); + assert_eq!(compare, response); + Ok(()) + } + + #[test] + fn create_pair_ok() -> StdResult<()> { + let ref mut deps = mock_dependencies(&[]); + let env = mock_env(); + let config = mkconfig(0); + assert!(instantiate( + deps.as_mut(), + env, + MessageInfo { + sender: Addr::unchecked("admin"), + funds: vec![] + }, + create_init_msg_from_config(&config) + ) + .is_ok()); + + let pair = TokenPair( + TokenType::CustomToken { + contract_addr: Addr::unchecked("token_addr"), + token_code_hash: "diff".to_string(), + }, + TokenType::CustomToken { + contract_addr: Addr::unchecked("token_addr"), + token_code_hash: "13123adasd".to_string(), + }, + ); + + let result = create_pair( + deps.as_mut(), + mock_env(), + pair, + to_binary(&"entropy").unwrap(), + None,); + + assert!(result.is_ok()); + Ok(()) + } + #[test] + fn add_amm_pairs() { + let ref mut deps = mock_dependencies(&[]); + let config = mkconfig(0); + let env = mock_env(); + + instantiate(deps.as_mut(), env.clone(), MessageInfo { + sender: Addr::unchecked("admin"), + funds: vec![] + }, create_init_msg_from_config(&config)).unwrap(); + + let mut amm_pairs: Vec = vec![]; + + for i in 0..5 { + amm_pairs.push(AMMPair { + pair: TokenPair( + TokenType::CustomToken { + contract_addr: Addr::unchecked(format!("token_0_addr_{}", i)), + token_code_hash: format!("token_0_hash_{}", i), + }, + TokenType::CustomToken { + contract_addr: Addr::unchecked(format!("token_1_addr_{}", i)), + token_code_hash: format!("token_1_hash_{}", i), + }, + ), + address: Addr::unchecked(format!("pair_addr_{}", i)), + enabled: true, + }); + } + + execute( + deps.as_mut(), + env, + MessageInfo { + sender: Addr::unchecked("admin"), + funds: vec![] + }, + ExecuteMsg::AddAMMPairs { + amm_pairs: amm_pairs.clone()[0..].into(), + }, + ) + .unwrap(); + + let result = query( + deps.as_ref(), + mock_env(), + QueryMsg::ListAMMPairs { + pagination: pagination(0, PAGINATION_LIMIT), + }, + ) + .unwrap(); + + let response: QueryResponse = from_binary(&result).unwrap(); + + match response { + QueryResponse::ListAMMPairs { amm_pairs: stored } => { + assert_eq!(amm_pairs, stored) + } + _ => panic!("QueryResponse::ListExchanges"), + } + } +} + +pub fn create_init_msg_from_config(config: &Config) -> InitMsg{ + InitMsg { + pair_contract: config.pair_contract.clone(), + amm_settings: AMMSettings { + lp_fee: Fee::new(28, 10000), + shade_dao_fee: Fee::new(2, 10000), + shade_dao_address: Contract { + address: Addr::unchecked("CALLBACKADDR"), + code_hash: "Test".to_string(), + }, + }, + lp_token_contract: config.lp_token_contract.clone(), + prng_seed: to_binary(&"prng").unwrap(), + api_key: "api_key".to_string(), + authenticator: None, + admin_auth: shadeswap_shared::Contract { + address: Addr::unchecked("admin"), + code_hash: "".to_string() + }, + } +} + +pub fn create_query_response_from_config(config: &Config) ->QueryResponse { + QueryResponse::GetConfig { + pair_contract: config.pair_contract.clone(), + amm_settings: config.amm_settings.clone(), + lp_token_contract: config.lp_token_contract.clone(), + authenticator: None, + admin_auth: config.admin_auth.clone(), + } +} + + pub fn mock_dependencies( + _contract_balance: &[Coin], + ) -> OwnedDeps { + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: MockQuerier { _portion: 100 }, + custom_query_type: std::marker::PhantomData, + } + } + + + #[derive(Serialize, Deserialize)] + struct IntBalanceResponse { + pub balance: Balance, + } + + pub struct MockQuerier { + _portion: u128, + } + + impl Querier for MockQuerier { + fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { + let request: QueryRequest = from_slice(bin_request).unwrap(); + match &request { + QueryRequest::Wasm(msg) => match msg { + WasmQuery::Smart { contract_addr, code_hash: _, msg: _} => { + match contract_addr.as_str() { + "admin" => { + QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(to_binary(&ValidateAdminPermissionResponse{ + has_permission: true, + }).unwrap())) + }, + _ => unimplemented!(), + } + } + _ => unimplemented!(), + }, + _ => unimplemented!(), + } + } + } + +fn mkconfig(id: u64) -> Config { + Config::from_init_msg(InitMsg { + pair_contract: ContractInstantiationInfo { + id, + code_hash: "2341586789".to_string(), + }, + amm_settings: AMMSettings { + lp_fee: Fee::new(28, 10000), + shade_dao_fee: Fee::new(2, 10000), + shade_dao_address: Contract { + address: Addr::unchecked("CALLBACKADDR"), + code_hash: "Test".to_string(), + }, + }, + lp_token_contract: ContractInstantiationInfo { + id, + code_hash: "123".to_string(), + }, + prng_seed: to_binary(&"prng").unwrap(), + api_key: "api_key".to_string(), + authenticator: None, + admin_auth: shadeswap_shared::Contract { address: Addr::unchecked("admin"), code_hash: "".to_string() } + }) +} + +fn pagination(start: u64, limit: u8) -> Pagination { + Pagination { start, limit } +} diff --git a/contracts/factory/tests/integration.rs b/contracts/factory/tests/integration.rs index a7e3c31..3af27da 100644 --- a/contracts/factory/tests/integration.rs +++ b/contracts/factory/tests/integration.rs @@ -1,68 +1,363 @@ use cosmwasm_std::{ - to_binary, Addr, Empty, + to_binary, Addr, Empty, ContractInfo, StdResult, }; use factory::contract::{execute, instantiate, query}; +use multi_test::{help_lib::integration_help_lib::{convert_to_contract_link, roll_blockchain, generate_snip20_contract, store_init_auth_contract}, + amm_pairs::amm_pairs_lib::amm_pairs_lib::{store_init_amm_pair_contract, amm_pair_contract_store_in}, util_addr::util_addr::OWNER}; use secret_multi_test::{App, Contract, ContractWrapper, Executor}; -use shadeswap_shared::{ - core::{ContractInstantiationInfo, ContractLink}, - factory::{InitMsg, QueryResponse, QueryMsg}, - utils::testing::TestingExt -}; +use multi_test::factory::factory_mock::factory_mock::reply; +use shadeswap_shared::{utils::testing::TestingExt, core::{ContractInstantiationInfo, CustomFee, }, factory::{InitMsg, QueryResponse, QueryMsg}, Contract as SContract, staking::StakingContractInit}; pub fn contract_counter() -> Box> { - let contract = ContractWrapper::new_with_empty(execute, instantiate, query); + let contract = ContractWrapper::new_with_empty(execute, instantiate, query).with_reply(reply); Box::new(contract) } #[cfg(not(target_arch = "wasm32"))] #[test] fn factory_integration_tests() { - let mut router = App::default(); - let owner = Addr::unchecked("owner"); + use cosmwasm_std::Uint128; + use multi_test::admin::admin_help::init_admin_contract; + use multi_test::amm_pairs::amm_pairs_lib::amm_pairs_lib::{amm_pair_contract_store_in}; + use multi_test::help_lib::integration_help_lib::{convert_to_contract_link, create_token_pair, mint_deposit_snip20, configure_block_send_init_funds, snip20_lp_token_contract_store, create_token_pair_with_native}; + use multi_test::staking::staking_lib::staking_lib::staking_contract_store_in; + use shadeswap_shared::Pagination; + use shadeswap_shared::amm_pair::{AMMPair, AMMSettings}; + use shadeswap_shared::core::{TokenType, Fee}; + use shadeswap_shared::factory::ExecuteMsg; + use multi_test::help_lib::integration_help_lib::{roll_blockchain}; + + use multi_test::util_addr::util_addr::{OWNER}; + use shadeswap_shared::staking::StakingContractInit; + use shadeswap_shared::utils::testing::TestingExt; + + let owner_addr = Addr::unchecked(OWNER); + let mut router = App::default(); + + configure_block_send_init_funds(&mut router, &owner_addr, Uint128::new(100000000000000u128)); + + let lp_token_contract_info = router.store_code(snip20_lp_token_contract_store()); + let auth_contract = init_admin_contract(&mut router, &owner_addr).unwrap(); + let amm_pair_contract_id = router.store_code(amm_pair_contract_store_in()); + let staking_contract_info = router.store_code(staking_contract_store_in()); + // GENERATE TOKEN PAIRS & REWARD TOKEN + let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); + // MINT AND DEPOSIT FOR LIQUIDITY + mint_deposit_snip20(&mut router,&reward_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + // CREATE FACTORY CONTRACT let init_msg = InitMsg { pair_contract: ContractInstantiationInfo { - code_hash: "".to_string(), - id: 0u64, + code_hash: amm_pair_contract_id.code_hash, + id: amm_pair_contract_id.code_id, }, amm_settings: shadeswap_shared::amm_pair::AMMSettings { lp_fee: shadeswap_shared::core::Fee { nom: 2, denom: 100 }, shade_dao_fee: shadeswap_shared::core::Fee { nom: 2, denom: 100 }, - shade_dao_address: ContractLink { + shade_dao_address: SContract { address: Addr::unchecked("".to_string()), code_hash: "".to_string(), }, }, lp_token_contract: ContractInstantiationInfo { - code_hash: "".to_string(), - id: 0u64, + code_hash: lp_token_contract_info.code_hash.clone(), + id: lp_token_contract_info.code_id, }, - prng_seed: to_binary(&"".to_string()).unwrap(), + prng_seed: to_binary(&"seed".to_string()).unwrap(), api_key: "api_key".to_string(), - authenticator: None, + authenticator: Some(convert_to_contract_link(&auth_contract)), + admin_auth: convert_to_contract_link(&auth_contract) }; - let counter_contract_code_id = router.store_code(contract_counter()); - - let mocked_contract_addr = router + let factory_contract_id = router.store_code(contract_counter()); + let factory_contract = router .instantiate_contract( - counter_contract_code_id, - owner.clone(), + factory_contract_id, + owner_addr.clone(), &init_msg, &[], - "counter", + "factory", None, ) .unwrap(); - - println!("{}", mocked_contract_addr.address.to_string()); - - let query: QueryResponse = router.query_test(mocked_contract_addr,to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + + // ASSERT FACTORY CONFIG + roll_blockchain(&mut router, 1).unwrap(); + let query: QueryResponse = router.query_test(factory_contract.clone(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); match query { - QueryResponse::GetConfig { pair_contract: _, amm_settings, lp_token_contract: _, authenticator: _ } => { + QueryResponse::GetConfig { pair_contract: _, amm_settings, lp_token_contract: _, authenticator: _, admin_auth: _} => { assert_eq!(amm_settings.lp_fee, shadeswap_shared::core::Fee { nom: 2, denom: 100 }); assert_eq!(amm_settings.shade_dao_fee, shadeswap_shared::core::Fee { nom: 2, denom: 100 }); }, _ => panic!("Query Responsedoes not match") } + + // ASSERT ADD AMM_PAIR + let (token_0_contract, token_1_contract, mock_amm_pairs) = setup_create_amm_pairs( + &mut router, + "ETH", + "USDT", + &factory_contract, + Some(StakingContractInit{ + contract_info: ContractInstantiationInfo { + code_hash: staking_contract_info.code_hash.clone(), + id: staking_contract_info.code_id + }, + daily_reward_amount: Uint128::new(30000u128), + reward_token: TokenType::CustomToken { + contract_addr: reward_contract.address.clone(), + token_code_hash: reward_contract.code_hash.clone() + }, + valid_to: Uint128::new(30000000u128) + }), + None, + "seed", + &owner_addr).unwrap(); + + // ADD NEW AMM_PAIR TO FACTORY + roll_blockchain(&mut router, 1).unwrap(); + let pair = create_token_pair( + &convert_to_contract_link(&token_0_contract), + &convert_to_contract_link(&token_1_contract) + ); + let amm_pair = AMMPair{ + pair: pair.clone(), + address: mock_amm_pairs.address, + enabled: true, + }; + let add_pair_msg = ExecuteMsg::AddAMMPairs { amm_pairs: vec![amm_pair]}; + let _ = router.execute_contract( + owner_addr.to_owned(), + &factory_contract, + &add_pair_msg, + &[], // + ) + .unwrap(); + + // LIST AMM PAIRS + let list_amm_pairs = to_binary(&QueryMsg::ListAMMPairs { + pagination: Pagination{ + start: 0, + limit: 30, + } + }).unwrap(); + + // ASSERT AMM PAIRS == 1 + let query_response: QueryResponse = router.query_test(factory_contract.clone(), list_amm_pairs.clone()).unwrap(); + match query_response{ + QueryResponse::ListAMMPairs { amm_pairs } => { + assert_eq!(amm_pairs.len(), 1); + }, + QueryResponse::GetConfig { pair_contract: _, amm_settings: _, lp_token_contract: _, authenticator: _ , admin_auth: _} => todo!(), + QueryResponse::GetAMMPairAddress { address: _ } => todo!(), + QueryResponse::AuthorizeApiKey { authorized: _ } => todo!(), + }; + roll_blockchain(&mut router, 1).unwrap(); + + let token_2_contract = generate_snip20_contract(&mut router, "BTC".to_string(), "BTC".to_string(), 18).unwrap(); + roll_blockchain(&mut router, 1).unwrap(); + + // CREATE NEW PAIR via FACTORY + let create_msg = ExecuteMsg::CreateAMMPair { + pair: create_token_pair( + &convert_to_contract_link(&token_1_contract), + &convert_to_contract_link(&token_2_contract) + ), + entropy: to_binary("seed").unwrap(), + staking_contract: Some(StakingContractInit{ + contract_info: ContractInstantiationInfo { + code_hash: staking_contract_info.code_hash.clone(), + id: staking_contract_info.code_id + }, + daily_reward_amount: Uint128::new(30000u128), + reward_token: TokenType::CustomToken { + contract_addr: reward_contract.address.clone(), + token_code_hash: reward_contract.code_hash.clone() + }, + valid_to: Uint128::new(30000000u128) + }), + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &factory_contract, + &create_msg, + &[], // + ) + .unwrap(); + + // ASSERT AMM_PAIR == 2 + let query_response: QueryResponse = router.query_test(factory_contract.clone(), list_amm_pairs.clone()).unwrap(); + match query_response{ + QueryResponse::ListAMMPairs { amm_pairs } => { + assert_eq!(amm_pairs.len(), 2); + }, + _ => {} + }; + + // CREATE NATIVE AMM PAIR + let create_msg = ExecuteMsg::CreateAMMPair { + pair: create_token_pair_with_native( + &convert_to_contract_link(&token_2_contract) + ), + entropy: to_binary("seed").unwrap(), + staking_contract: Some(StakingContractInit{ + contract_info: ContractInstantiationInfo { + code_hash: staking_contract_info.code_hash.clone(), + id: staking_contract_info.code_id + }, + daily_reward_amount: Uint128::new(30000u128), + reward_token: TokenType::CustomToken { + contract_addr: reward_contract.address.clone(), + token_code_hash: reward_contract.code_hash.clone() + }, + valid_to: Uint128::new(30000000u128) + }), + }; + + let _ = router.execute_contract( + owner_addr.to_owned(), + &factory_contract, + &create_msg, + &[], // + ) + .unwrap(); + + // ASSERT AMM_PAIR == 3 + let query_response: QueryResponse = router.query_test(factory_contract.clone(), list_amm_pairs.clone()).unwrap(); + match query_response{ + QueryResponse::ListAMMPairs { amm_pairs } => { + assert_eq!(amm_pairs.len(), 3); + }, + _ => {} + }; + + // ASSERT GETAMMPAIRSADDRESS + let msg = to_binary(&QueryMsg::GetAMMPairAddress { pair: pair.clone() }).unwrap(); + let query_response: QueryResponse = router.query_test(factory_contract.clone(), msg).unwrap(); + match query_response{ + QueryResponse::GetAMMPairAddress { address } => { + assert_eq!(address, address.clone()); + }, + _ => {} + }; + + // ASSERT AUTHORIZATIONAPIKEY TRUE + let msg = to_binary(&QueryMsg::AuthorizeApiKey { api_key: "api_key".to_string() }).unwrap(); + let query_response: QueryResponse = router.query_test(factory_contract.clone(), msg).unwrap(); + match query_response{ + QueryResponse::AuthorizeApiKey { authorized } => { + assert_eq!(authorized, true); + }, + _ => {} + }; + + // ASSERT AUTHORIZATIONAPIKEY FALSE + let msg = to_binary(&QueryMsg::AuthorizeApiKey { api_key: "api_keys".to_string() }).unwrap(); + let query_response: QueryResponse = router.query_test(factory_contract.clone(), msg).unwrap(); + match query_response{ + QueryResponse::AuthorizeApiKey { authorized } => { + assert_eq!(authorized, false); + }, + _ => {} + }; + + // SET CONFIG + let update_lp_token_info = router.store_code(snip20_lp_token_contract_store()); + let shade_dao_address_contract = generate_snip20_contract(&mut router, "DOA".to_string(), "DOA".to_string() , 18).unwrap(); + let auth_contract = init_admin_contract(&mut router, &owner_addr).unwrap(); + let amm_pair_contract_id = router.store_code(amm_pair_contract_store_in()); + // CREATE NATIVE AMM PAIR + let create_msg = ExecuteMsg::SetConfig { + pair_contract: Some(ContractInstantiationInfo { + code_hash: amm_pair_contract_id.code_hash.clone(), + id: amm_pair_contract_id.code_id + }), + lp_token_contract: Some(ContractInstantiationInfo{ + code_hash: update_lp_token_info.code_hash.clone(), + id: update_lp_token_info.code_id, + }), + amm_settings: Some(AMMSettings{ + lp_fee: Fee::new(5, 100), + shade_dao_fee: Fee::new(10, 100), + shade_dao_address: convert_to_contract_link(&shade_dao_address_contract) + }), + api_key: Some("pass_key".to_string()), + admin_auth: Some(convert_to_contract_link(&auth_contract)) + }; + let _ = router.execute_contract( + owner_addr.to_owned(), + &factory_contract, + &create_msg, + &[], // + ) + .unwrap(); + + // ASSERT SETCONFIG CHANGES + let query: QueryResponse = router.query_test(factory_contract.clone(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + QueryResponse::GetConfig { pair_contract: _, amm_settings, lp_token_contract, authenticator: _, admin_auth: _} => { + assert_eq!(amm_settings.lp_fee, shadeswap_shared::core::Fee { nom: 5, denom: 100 }); + assert_eq!(amm_settings.shade_dao_fee, shadeswap_shared::core::Fee { nom: 10, denom: 100 }); + assert_eq!(lp_token_contract.code_hash,update_lp_token_info.code_hash); + assert_eq!(lp_token_contract.id,update_lp_token_info.code_id); + }, + _ => panic!("Query Response does not match") + } + + // ASSERT AUTHORIZATIONAPIKEY TRUE + let msg = to_binary(&QueryMsg::AuthorizeApiKey { api_key: "pass_key".to_string() }).unwrap(); + let query_response: QueryResponse = router.query_test(factory_contract.clone(), msg).unwrap(); + match query_response{ + QueryResponse::AuthorizeApiKey { authorized } => { + assert_eq!(authorized, true); + }, + _ => {} + }; + + // ASSERT AUTHORIZATIONAPIKEY FALSE + let msg = to_binary(&QueryMsg::AuthorizeApiKey { api_key: "api_key".to_string() }).unwrap(); + let query_response: QueryResponse = router.query_test(factory_contract.clone(), msg).unwrap(); + match query_response{ + QueryResponse::AuthorizeApiKey { authorized } => { + assert_eq!(authorized, false); + }, + _ => {} + }; + } + +pub fn setup_create_amm_pairs( + router: &mut App, + symbol_0: &str, + symbol_1: &str, + factory_contract: &ContractInfo, + staking_contract_info: Option, + custom_fee: Option, + seed: &str, + sender: &Addr) + -> StdResult<(cosmwasm_std::ContractInfo, cosmwasm_std::ContractInfo, cosmwasm_std::ContractInfo)> { + let token_0_contract = generate_snip20_contract(router, symbol_0.to_string(), symbol_0.to_string(), 18).unwrap(); + roll_blockchain(router, 1).unwrap(); + let token_1_contract = generate_snip20_contract(router, symbol_1.to_string(), symbol_1.to_string(), 18).unwrap(); + roll_blockchain(router, 1).unwrap(); + // auth contract + let auth_query_contract = store_init_auth_contract(router)?; + let mock_amm_pairs = store_init_amm_pair_contract( + router, + sender, + &convert_to_contract_link(&token_0_contract), + &convert_to_contract_link(&token_1_contract), + &convert_to_contract_link(factory_contract), + &convert_to_contract_link(&auth_query_contract), + amm_pair_contract_store_in(), + seed, + staking_contract_info, + custom_fee, + ).unwrap(); + let response = (token_0_contract, token_1_contract, mock_amm_pairs); + Ok(response) +} + + + diff --git a/contracts/lp_token/Cargo.toml b/contracts/lp_token/Cargo.toml index 83a3c39..a0ea5ba 100644 --- a/contracts/lp_token/Cargo.toml +++ b/contracts/lp_token/Cargo.toml @@ -23,7 +23,7 @@ backtraces = ["cosmwasm-std/backtraces"] [dependencies] cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } -secret-toolkit = { git = "https://github.com/scrtlabs/secret-toolkit", branch = "cosmwasm-v1.0", features = [ +secret-toolkit = { git = "https://github.com/scrtlabs/secret-toolkit", rev = "8380c00", features = [ "permit", "viewing-key", "crypto", diff --git a/contracts/lp_token/src/contract.rs b/contracts/lp_token/src/contract.rs index 0822576..5eef80e 100644 --- a/contracts/lp_token/src/contract.rs +++ b/contracts/lp_token/src/contract.rs @@ -109,9 +109,7 @@ pub fn instantiate( MintersStore::save(deps.storage, minters)?; ViewingKey::set_seed(deps.storage, &prng_seed_hashed); - let mut response = Response::new(); - - println!("{}",env.contract.address.to_string()); + let mut response = Response::new(); response.data = Some(env.contract.address.as_bytes().into()); Ok(response) } diff --git a/contracts/router/.editorconfig b/contracts/router/.editorconfig deleted file mode 100644 index 43cda4c..0000000 --- a/contracts/router/.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/contracts/router/.gitignore b/contracts/router/.gitignore deleted file mode 100644 index 961cca6..0000000 --- a/contracts/router/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -# Build results -/target -Cargo.lock -contract.wasm* - -# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) -.cargo-ok - -# Text file backups -**/*.rs.bk - -# macOS -.DS_Store - -# IDEs -*.iml -.idea diff --git a/contracts/router/Cargo.toml b/contracts/router/Cargo.toml index 121bc1f..a11edfb 100644 --- a/contracts/router/Cargo.toml +++ b/contracts/router/Cargo.toml @@ -32,3 +32,9 @@ schemars = "0.8.1" cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } shadeswap-shared = {path = "../../packages/shadeswap-shared"} + +[dev-dependencies] +cosmwasm-schema = { git = "https://github.com/CosmWasm/cosmwasm"} +snip20-reference-impl = {path ="../../contracts/snip20"} +secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } +multi_test = {path = "../../packages/multi_test"} \ No newline at end of file diff --git a/contracts/router/README.md b/contracts/router/README.md index 75b7c16..47777a6 100644 --- a/contracts/router/README.md +++ b/contracts/router/README.md @@ -28,7 +28,7 @@ Initialize a Router Contract |Name|Type|Description|Optional| |-|-|-|-| -|factory_address|ContractLink|The Factory Contract to register the router for|No| +|factory_address|Contract|The Factory Contract to register the router for|No| |prng_seed|Binary|Seed used for generated viewing key|No| |entropy|Binary|Entropy used for generated viewing key|No| |viewing_key|Option|Fixed viewing key to use for router, useful for testing|No| diff --git a/contracts/router/rustfmt.toml b/contracts/router/rustfmt.toml deleted file mode 100644 index 432ac7a..0000000 --- a/contracts/router/rustfmt.toml +++ /dev/null @@ -1,15 +0,0 @@ -# stable -newline_style = "unix" -hard_tabs = false -tab_spaces = 4 - -# unstable... should we require `rustup run nightly cargo fmt` ? -# or just update the style guide when they are stable? -#fn_single_line = true -#format_code_in_doc_comments = true -#overflow_delimited_expr = true -#reorder_impl_items = true -#struct_field_align_threshold = 20 -#struct_lit_single_line = true -#report_todo = "Always" - diff --git a/contracts/router/schema/count_response.json b/contracts/router/schema/count_response.json deleted file mode 100644 index 68a9247..0000000 --- a/contracts/router/schema/count_response.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "CountResponse", - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - } - } -} diff --git a/contracts/router/schema/handle_msg.json b/contracts/router/schema/handle_msg.json deleted file mode 100644 index f019438..0000000 --- a/contracts/router/schema/handle_msg.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "HandleMsg", - "anyOf": [ - { - "type": "object", - "required": [ - "increment" - ], - "properties": { - "increment": { - "type": "object" - } - } - }, - { - "type": "object", - "required": [ - "reset" - ], - "properties": { - "reset": { - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - } - } - } - } - } - ] -} diff --git a/contracts/router/schema/init_msg.json b/contracts/router/schema/init_msg.json deleted file mode 100644 index bc35b47..0000000 --- a/contracts/router/schema/init_msg.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "InitMsg", - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - } - } -} diff --git a/contracts/router/schema/query_msg.json b/contracts/router/schema/query_msg.json deleted file mode 100644 index a6ee001..0000000 --- a/contracts/router/schema/query_msg.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "QueryMsg", - "anyOf": [ - { - "type": "object", - "required": [ - "get_count" - ], - "properties": { - "get_count": { - "type": "object" - } - } - } - ] -} diff --git a/contracts/router/schema/state.json b/contracts/router/schema/state.json deleted file mode 100644 index ef1c444..0000000 --- a/contracts/router/schema/state.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "State", - "type": "object", - "required": [ - "count", - "owner" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - }, - "owner": { - "$ref": "#/definitions/CanonicalAddr" - } - }, - "definitions": { - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", - "type": "string" - }, - "CanonicalAddr": { - "$ref": "#/definitions/Binary" - } - } -} diff --git a/contracts/router/src/contract.rs b/contracts/router/src/contract.rs index 192ec57..89e57a5 100644 --- a/contracts/router/src/contract.rs +++ b/contracts/router/src/contract.rs @@ -1,18 +1,18 @@ use cosmwasm_std::{ - entry_point, from_binary, to_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Response, - StdError, StdResult, Uint128, CosmosMsg, BankMsg, Coin, + entry_point, from_binary, to_binary, Addr, BankMsg, Binary, Coin, CosmosMsg, Deps, DepsMut, + Env, MessageInfo, Reply, Response, StdError, StdResult, Uint128, }; -use shadeswap_shared::Contract; -use shadeswap_shared::core::apply_admin_guard; +use shadeswap_shared::admin::helpers::{validate_admin, AdminPermissions}; +use shadeswap_shared::router::{InitMsg, QueryMsgResponse}; use shadeswap_shared::snip20::helpers::send_msg; use shadeswap_shared::utils::{pad_query_result, pad_response_result}; -use shadeswap_shared::{core::admin_w, router::InitMsg}; +use shadeswap_shared::Contract; use shadeswap_shared::{ - core::{ContractLink, TokenAmount, TokenType}, + core::{TokenAmount, TokenType}, router::{ExecuteMsg, InvokeMsg, QueryMsg}, + amm_pair::{ QueryMsgResponse as AMMPairQueryReponse} }; - use crate::{ operations::{ next_swap, query_pair_contract_config, refresh_tokens, swap_simulation, @@ -24,21 +24,20 @@ use crate::{ /// Pad handle responses and log attributes to blocks /// of 256 bytes to prevent leaking info based on response size const BLOCK_SIZE: usize = 256; -const SHADE_ROUTER_KEY: &str = "SHADE_ROUTER_KEY"; +pub const SHADE_ROUTER_KEY: &str = "SHADE_ROUTER_KEY"; +pub const SWAP_REPLY_ID: u64 = 1u64; #[entry_point] pub fn instantiate( deps: DepsMut, _env: Env, - info: MessageInfo, + _info: MessageInfo, msg: InitMsg, ) -> StdResult { config_w(deps.storage).save(&Config { viewing_key: SHADE_ROUTER_KEY.to_string(), - pair_contract_code_hash: msg.pair_contract_code_hash, + admin_auth: msg.admin_auth, })?; - - admin_w(deps.storage).save(&info.sender)?; Ok(Response::default()) } @@ -48,7 +47,10 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S match msg { ExecuteMsg::Receive { from, amount, msg, .. - } => receiver_callback(deps, env, info, from, amount, msg), + } => { + let checked_address = deps.api.addr_validate(&from)?; + receiver_callback(deps, env, info, checked_address, amount, msg) + } ExecuteMsg::SwapTokensForExact { offer, expected_return, @@ -62,43 +64,56 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S } offer.assert_sent_native_token_balance(&info)?; let sender = info.sender.clone(); - swap_tokens_for_exact_tokens( + let checked_address = match recipient { + Some(x) => Some(deps.api.addr_validate(&x)?), + None => None, + }; + let response = Response::new(); + Ok(swap_tokens_for_exact_tokens( deps, env, - info, offer, expected_return, &path, sender, - recipient, - ) + checked_address, + response, + )?) } - ExecuteMsg::SwapCallBack { - last_token_out, - signature, - } => next_swap(deps, env, last_token_out, signature), ExecuteMsg::RegisterSNIP20Token { token_addr, token_code_hash, - } => refresh_tokens(deps, env, token_addr, token_code_hash), + } => { + let checked_token_addr = deps.api.addr_validate(&token_addr)?; + refresh_tokens(deps, env, checked_token_addr, token_code_hash) + } ExecuteMsg::RecoverFunds { token, amount, to, msg, } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; let send_msg = match token { - TokenType::CustomToken { contract_addr, token_code_hash } => vec![send_msg( - to, + TokenType::CustomToken { + contract_addr, + token_code_hash, + } => vec![send_msg( + deps.api.addr_validate(&to)?, amount, msg, None, None, - &Contract{ + &Contract { address: contract_addr, - code_hash: token_code_hash - } + code_hash: token_code_hash, + }, )?], TokenType::NativeToken { denom } => vec![CosmosMsg::Bank(BankMsg::Send { to_address: to.to_string(), @@ -126,40 +141,59 @@ fn receiver_callback( match from_binary(&content)? { InvokeMsg::SwapTokensForExact { expected_return, - paths, + path, recipient, } => { - let config = config_r(deps.storage).load()?; - let pair_config = query_pair_contract_config( + let pair_contract_config = query_pair_contract_config( &deps.querier, - ContractLink { - address: paths[0].clone(), - code_hash: config.pair_contract_code_hash, + Contract { + address: deps.api.addr_validate(&path[0].addr.to_string())?, + code_hash: path[0].code_hash.clone(), }, )?; - for token in pair_config.pair.into_iter() { - match token { - TokenType::CustomToken { contract_addr, .. } => { - if *contract_addr == info.sender { - let offer = TokenAmount { - token: token.clone(), - amount, - }; - return swap_tokens_for_exact_tokens( - deps, - env, - info, - offer, - expected_return, - &paths, - from, - recipient, - ); + match pair_contract_config { + AMMPairQueryReponse::GetPairInfo { + liquidity_token: _, + factory: _, + pair, + amount_0: _, + amount_1: _, + total_liquidity: _, + contract_version: _, + } => { + for token in pair.into_iter() { + match token { + TokenType::CustomToken { contract_addr, .. } => { + if *contract_addr == info.sender { + let offer = TokenAmount { + token: token.clone(), + amount, + }; + + let checked_address = match recipient { + Some(x) => Some(deps.api.addr_validate(&x)?), + None => None, + }; + + let response = Response::new(); + return Ok(swap_tokens_for_exact_tokens( + deps, + env, + offer, + expected_return, + &path, + from, + checked_address, + response, + )?); + } + } + _ => continue, } } - _ => continue, } + _ => {} } return Err(StdError::generic_err( "No matching token in pair".to_string(), @@ -178,7 +212,21 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { pad_query_result( match msg { QueryMsg::SwapSimulation { offer, path } => swap_simulation(deps, path, offer), - QueryMsg::GetConfig {} => return Ok(to_binary(&config_r(deps.storage).load()?)?), + QueryMsg::GetConfig {} => return Ok(to_binary(&QueryMsgResponse::GetConfig {})?), + }, + BLOCK_SIZE, + ) +} + +#[entry_point] +pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> StdResult { + pad_response_result( + match msg.id { + SWAP_REPLY_ID => { + let response = Response::new(); + Ok(next_swap(deps, env, response)?) + } + _ => Ok(Response::default()), }, BLOCK_SIZE, ) diff --git a/contracts/router/src/operations.rs b/contracts/router/src/operations.rs index f27b068..a06c24d 100644 --- a/contracts/router/src/operations.rs +++ b/contracts/router/src/operations.rs @@ -1,19 +1,16 @@ use std::str::FromStr; use cosmwasm_std::{ - to_binary, Addr, Binary, Coin, CosmosMsg, Deps, DepsMut, Env, MessageInfo, QuerierWrapper, - QueryRequest, Response, StdError, StdResult, Storage, Uint128, Uint256, WasmMsg, WasmQuery, + to_binary, Addr, Binary, Coin, CosmosMsg, Deps, DepsMut, Env, QuerierWrapper, QueryRequest, + Response, StdError, StdResult, Storage, SubMsg, Uint128, Uint256, WasmMsg, WasmQuery, }; use shadeswap_shared::{ - amm_pair::AMMSettings, - core::{ - ContractInstantiationInfo, ContractLink, TokenAmount, TokenPair, TokenType - }, + core::{TokenAmount, TokenType}, msg::amm_pair::{ ExecuteMsg as AMMPairExecuteMsg, InvokeMsg as AMMPairInvokeMsg, QueryMsg as AMMPairQueryMsg, QueryMsgResponse as AMMPairQueryReponse, SwapResult, }, - router::QueryMsgResponse, + router::{Hop, QueryMsgResponse}, snip20::{ self, helpers::{register_receive, set_viewing_key_msg}, @@ -21,7 +18,10 @@ use shadeswap_shared::{ Contract, }; -use crate::state::{config_r, config_w, epheral_storage_r, epheral_storage_w, CurrentSwapInfo}; +use crate::{ + contract::{SHADE_ROUTER_KEY, SWAP_REPLY_ID}, + state::{config_r, config_w, epheral_storage_r, epheral_storage_w, CurrentSwapInfo}, +}; pub fn refresh_tokens( deps: DepsMut, @@ -31,6 +31,14 @@ pub fn refresh_tokens( ) -> StdResult { let mut msg = vec![]; let config = config_r(deps.storage).load()?; + set_viewing_key_msg( + SHADE_ROUTER_KEY.to_string(), + None, + &Contract { + address: token_address.clone(), + code_hash: token_code_hash.clone(), + }, + )?; register_pair_token( &env, &mut msg, @@ -44,48 +52,57 @@ pub fn refresh_tokens( Ok(Response::new().add_messages(msg)) } -pub fn next_swap( - deps: DepsMut, - env: Env, - last_token_out: TokenAmount, - signature: Binary, -) -> StdResult { +pub fn next_swap(deps: DepsMut, env: Env, mut response: Response) -> StdResult { let current_trade_info: Option = epheral_storage_r(deps.storage).may_load()?; - let config = config_r(deps.storage).load()?; if let Some(mut info) = current_trade_info { - if signature != info.signature { - return Err(StdError::generic_err("".to_string())); - } - let pair_contract = query_pair_contract_config( - &deps.querier, - ContractLink { - address: info.paths[info.current_index as usize].clone(), - code_hash: config.pair_contract_code_hash.clone(), - }, - )?; - - let mut next_token_in = pair_contract.pair.0.clone(); - - if pair_contract.pair.1 == last_token_out.token { - next_token_in = pair_contract.pair.1; - } - let token_in: TokenAmount = TokenAmount { - token: next_token_in.clone(), - amount: last_token_out.amount, + token: info.next_token_in.clone(), + amount: info.next_token_in.query_balance( + deps.as_ref(), + env.contract.address.to_string(), + SHADE_ROUTER_KEY.to_owned(), + )?, }; - if info.paths.len() > (info.current_index + 1) as usize { - info.current_index = info.current_index + 1; - epheral_storage_w(deps.storage).save(&info)?; - Ok(Response::new().add_messages(get_trade_with_callback( - deps, - env, - token_in, - info.paths[(info.current_index) as usize].clone(), - config.pair_contract_code_hash.clone(), - info.signature, - )?)) + if info.path.len() > (info.current_index + 1) as usize { + let next_pair_contract = query_pair_contract_config( + &deps.querier, + Contract { + address: deps + .api + .addr_validate(&info.path[info.current_index as usize + 1].addr.clone())?, + code_hash: info.path[info.current_index as usize + 1].code_hash.clone(), + }, + )?; + + match next_pair_contract { + AMMPairQueryReponse::GetPairInfo { + liquidity_token, + factory, + pair, + amount_0, + amount_1, + total_liquidity, + contract_version, + } => { + info.current_index = info.current_index + 1; + + if pair.0 == info.next_token_in { + info.next_token_in = pair.1; + } else { + info.next_token_in = pair.0; + } + epheral_storage_w(deps.storage).save(&info)?; + response = get_trade_with_callback( + env, + token_in, + info.path[(info.current_index) as usize].clone(), + response, + )?; + Ok(response) + } + _ => Err(StdError::generic_err("Contract not found.")), + } } else { if let Some(min_out) = info.amount_out_min { if token_in.amount.lt(&min_out) { @@ -99,13 +116,13 @@ pub fn next_swap( } epheral_storage_w(deps.storage).remove(); - Ok( - Response::new().add_messages(vec![token_in.token.create_send_msg( - env.contract.address.to_string(), - info.recipient.to_string(), - token_in.amount, - )?]), - ) + response = response.add_messages(vec![token_in.token.create_send_msg( + env.contract.address.to_string(), + info.recipient.to_string(), + token_in.amount, + )?]); + + Ok(response) } } else { Err(StdError::generic_err( @@ -117,106 +134,112 @@ pub fn next_swap( pub fn swap_tokens_for_exact_tokens( deps: DepsMut, env: Env, - info: MessageInfo, amount_in: TokenAmount, amount_out_min: Option, - paths: &Vec, + path: &Vec, sender: Addr, recipient: Option, + mut response: Response, ) -> StdResult { //Validates whether the amount received is greater then the amount_out_min - let config = config_r(deps.storage).load()?; - let signature = create_signature(&env, info)?; - epheral_storage_w(deps.storage).save(&CurrentSwapInfo { - amount: amount_in.clone(), - amount_out_min: amount_out_min, - paths: paths.clone(), - signature: signature.clone(), - recipient: recipient.unwrap_or(sender), - current_index: 0, - })?; - Ok(Response::new().add_messages(get_trade_with_callback( - deps, - env, - amount_in, - paths[0].clone(), - config.pair_contract_code_hash, - signature.clone(), - )?)) + let next_pair_contract = query_pair_contract_config( + &deps.querier, + Contract { + address: deps.api.addr_validate(&path[0].addr.clone())?, + code_hash: path[0].code_hash.clone(), + }, + )?; + + match next_pair_contract { + AMMPairQueryReponse::GetPairInfo { + liquidity_token, + factory, + pair, + amount_0, + amount_1, + total_liquidity, + contract_version, + } => { + let next_token_in; + if pair.0 == amount_in.token { + next_token_in = pair.1; + } else { + next_token_in = pair.0; + } + + epheral_storage_w(deps.storage).save(&CurrentSwapInfo { + amount: amount_in.clone(), + amount_out_min: amount_out_min, + path: path.clone(), + recipient: recipient.unwrap_or(sender), + current_index: 0, + next_token_in: next_token_in, + })?; + + response = get_trade_with_callback(env, amount_in, path[0].clone(), response)?; + + Ok(response) + } + _ => Err(StdError::generic_err("Pair Contract not found.")) + } } fn get_trade_with_callback( - _deps: DepsMut, env: Env, token_in: TokenAmount, - path: Addr, - code_hash: String, - signature: Binary, -) -> StdResult> { - let mut messages: Vec = vec![]; - + hop: Hop, + mut response: Response, +) -> StdResult { match &token_in.token { TokenType::NativeToken { denom } => { let msg = to_binary(&AMMPairExecuteMsg::SwapTokens { expected_return: None, to: None, - router_link: Some(ContractLink { - address: env.contract.address.clone(), - code_hash: env.contract.code_hash.clone(), - }), offer: token_in.clone(), - callback_signature: Some(signature), })?; - messages.push( + response = response.add_submessage(SubMsg::reply_always( WasmMsg::Execute { - contract_addr: path.to_string(), - code_hash: code_hash, + contract_addr: hop.addr.to_string(), + code_hash: hop.code_hash, msg, funds: vec![Coin { denom: denom.clone(), amount: token_in.amount, }], - } - .into(), - ); + }, + SWAP_REPLY_ID, + )); } TokenType::CustomToken { contract_addr, token_code_hash, } => { let msg = to_binary(&snip20::ExecuteMsg::Send { - recipient: path.to_string(), + recipient: hop.addr.to_string(), amount: token_in.amount, - msg: Some( - to_binary(&AMMPairInvokeMsg::SwapTokens { - expected_return: None, - to: Some(env.contract.address.clone()), - router_link: Some(ContractLink { - address: env.contract.address.clone(), - code_hash: env.contract.code_hash.clone(), - }), - callback_signature: Some(signature), - })?, - ), + msg: Some(to_binary(&AMMPairInvokeMsg::SwapTokens { + expected_return: None, + to: Some(env.contract.address.to_string()), + })?), padding: None, recipient_code_hash: None, memo: None, })?; - messages.push( + response = response.add_submessage(SubMsg::reply_always( WasmMsg::Execute { contract_addr: contract_addr.to_string(), code_hash: token_code_hash.clone(), msg, funds: vec![], - } - .into(), - ); + }, + SWAP_REPLY_ID, + )); } }; - return Ok(messages); + return Ok(response); } pub fn update_viewing_key(storage: &mut dyn Storage, viewing_key: String) -> StdResult { @@ -228,50 +251,28 @@ pub fn update_viewing_key(storage: &mut dyn Storage, viewing_key: String) -> Std pub fn query_pair_contract_config( querier: &QuerierWrapper, - pair_contract_address: ContractLink, -) -> StdResult { + pair_contract_address: Contract, +) -> StdResult { let result: AMMPairQueryReponse = querier.query(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr: pair_contract_address.address.to_string(), code_hash: pair_contract_address.code_hash.clone(), msg: to_binary(&AMMPairQueryMsg::GetPairInfo {})?, }))?; - match result { - AMMPairQueryReponse::GetPairInfo { - liquidity_token, - factory, - pair, - amount_0, - amount_1, - total_liquidity, - contract_version, - } => Ok(PairConfig { - liquidity_token: liquidity_token, - factory: factory, - pair: pair, - amount_0: amount_0, - amount_1: amount_1, - total_liquidity: total_liquidity, - contract_version: contract_version, - }), - _ => Err(StdError::generic_err( - "An error occurred while trying to retrieve pair contract settings.", - )), - } + return Ok(result); } -pub fn swap_simulation(deps: Deps, path: Vec, offer: TokenAmount) -> StdResult { +pub fn swap_simulation(deps: Deps, path: Vec, offer: TokenAmount) -> StdResult { let mut sum_total_fee_amount: Uint128 = Uint128::zero(); let mut sum_lp_fee_amount: Uint128 = Uint128::zero(); let mut sum_shade_dao_fee_amount: Uint128 = Uint128::zero(); let mut next_in = offer.clone(); let querier = &deps.querier; - let config = config_r(deps.storage).load()?; for hop in path { - let contract = ContractLink { - address: hop, - code_hash: config.pair_contract_code_hash.clone(), + let contract = Contract { + address: deps.api.addr_validate(&hop.addr)?, + code_hash: hop.code_hash, }; let contract_info: AMMPairQueryReponse = querier.query(&QueryRequest::Wasm(WasmQuery::Smart { @@ -323,10 +324,10 @@ pub fn swap_simulation(deps: Deps, path: Vec, offer: TokenAmount) -> StdRe sum_shade_dao_fee_amount = shade_dao_fee_amount.checked_add(sum_shade_dao_fee_amount)?; } - _ => panic!("Failed to complete hop."), + _ => return Err(StdError::generic_err("Failed to complete hop.")), }; } - _ => panic!("Failed to complete hop."), + _ => return Err(StdError::generic_err("Failed to complete hop.")), } } @@ -343,32 +344,6 @@ pub fn swap_simulation(deps: Deps, path: Vec, offer: TokenAmount) -> StdRe }) } -pub struct FactoryConfig { - pub pair_contract: ContractInstantiationInfo, - pub amm_settings: AMMSettings, -} - -pub struct PairConfig { - pub liquidity_token: ContractLink, - pub factory: ContractLink, - pub pair: TokenPair, - pub amount_0: Uint128, - pub amount_1: Uint128, - pub total_liquidity: Uint128, - pub contract_version: u32, -} - -pub(crate) fn create_signature(env: &Env, info: MessageInfo) -> StdResult { - to_binary( - &[ - info.sender.as_bytes(), - &env.block.height.to_be_bytes(), - &env.block.time.seconds().to_be_bytes(), - ] - .concat(), - ) -} - fn register_pair_token( env: &Env, messages: &mut Vec, @@ -400,4 +375,4 @@ fn register_pair_token( } Ok(()) -} \ No newline at end of file +} diff --git a/contracts/router/src/state.rs b/contracts/router/src/state.rs index eb20b31..7093a52 100644 --- a/contracts/router/src/state.rs +++ b/contracts/router/src/state.rs @@ -1,5 +1,4 @@ use cosmwasm_std::Addr; -use cosmwasm_std::Binary; use cosmwasm_std::Storage; use cosmwasm_std::Uint128; use cosmwasm_storage::ReadonlySingleton; @@ -9,7 +8,10 @@ use cosmwasm_storage::singleton_read; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use shadeswap_shared::Contract; use shadeswap_shared::core::TokenAmount; +use shadeswap_shared::core::TokenType; +use shadeswap_shared::router::Hop; pub static CONFIG: &[u8] = b"config"; pub static ADDED_TOKEN_LIST: &[u8] = b"added_token_list"; @@ -18,7 +20,7 @@ pub const EPHEMERAL_STORAGE_KEY: &[u8] = b"ephemeral_storage"; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Config { pub viewing_key: String, - pub pair_contract_code_hash: String, + pub admin_auth: Contract } pub fn config_w(storage: &mut dyn Storage) -> Singleton { @@ -50,8 +52,9 @@ pub fn epheral_storage_r(storage: &dyn Storage) -> ReadonlySingleton, - pub paths: Vec, - pub signature: Binary, + pub path: Vec, pub recipient: Addr, pub current_index: u32, + //The next token that will be in the hop + pub next_token_in: TokenType, } diff --git a/contracts/router/src/test.rs b/contracts/router/src/test.rs index c9a170d..bd4c70e 100644 --- a/contracts/router/src/test.rs +++ b/contracts/router/src/test.rs @@ -1,666 +1,575 @@ -// #[cfg(test)] -// pub mod tests { -// use crate::contract::init; -// use crate::contract::EPHEMERAL_STORAGE_KEY; -// use crate::state::config_read; -// use crate::state::Config; -// use crate::state::CurrentSwapInfo; -// use cosmwasm_std::from_binary; -// use cosmwasm_std::from_slice; -// use cosmwasm_std::testing::mock_dependencies; -// use cosmwasm_std::testing::mock_env; -// use cosmwasm_std::testing::MockApi; -// use cosmwasm_std::testing::MockStorage; -// use cosmwasm_std::to_binary; -// use cosmwasm_std::to_vec; -// use cosmwasm_std::AllBalanceResponse; -// use cosmwasm_std::Api; -// use cosmwasm_std::BalanceResponse; -// use cosmwasm_std::BankQuery; -// use cosmwasm_std::Coin; -// use cosmwasm_std::CosmosMsg; -// use cosmwasm_std::Empty; -// use cosmwasm_std::Env; -// use cosmwasm_std::Extern; -// use cosmwasm_std::HumanAddr; -// use cosmwasm_std::InitResponse; -// use cosmwasm_std::Querier; -// use cosmwasm_std::QuerierResult; -// use cosmwasm_std::QueryRequest; -// use cosmwasm_std::StdError; -// use cosmwasm_std::Storage; -// use cosmwasm_std::Uint128; -// use cosmwasm_std::WasmMsg; -// use cosmwasm_std::WasmQuery; -// use secret_toolkit::snip20::Balance; -// use shadeswap_shared::core::ContractInstantiationInfo; -// use shadeswap_shared::core::ContractLink; -// use shadeswap_shared::scrt_storage::load; -// use shadeswap_shared::scrt_storage::save; - -// use crate::contract::handle; -// use cosmwasm_std::StdResult; -// use serde::{de::DeserializeOwned, Deserialize, Serialize}; -// use shadeswap_shared::custom_fee::Fee; -// use shadeswap_shared::{ -// msg::{ -// amm_pair::QueryMsgResponse as AMMPairQueryMsgResponse, -// factory::QueryResponse as FactoryQueryResponse, -// router::{ExecuteMsg, InitMsg, InvokeMsg}, -// }, -// secret_toolkit::snip20::{self}, -// TokenAmount, TokenPair, TokenType, -// }; - -// pub const FACTORY_ADDRESS: &str = "FACTORY_ADDRESS"; -// pub const PAIR_CONTRACT_1: &str = "PAIR_CONTRACT_1"; -// pub const PAIR_CONTRACT_2: &str = "PAIR_CONTRACT_2"; -// pub const CUSTOM_TOKEN_1: &str = "CUSTOM_TOKEN_1"; - -// #[test] -// fn ok_init() -> StdResult<()> { -// let ref mut deps = mkdeps(); -// let env = mkenv("admin"); -// let config = mkconfig(env.clone(), 0); -// assert!(init(deps, env.clone(), (&config).into()).is_ok()); -// assert_eq!(config, config_read(deps)?); -// Ok(()) -// } - -// #[test] -// fn swap_native_for_snip20_tokens_ok() -> StdResult<()> { -// let (init_result, mut deps) = init_helper(100); -// let mut env = mkenv("admin"); - -// env.message.sent_funds = vec![Coin { -// denom: "uscrt".into(), -// amount: Uint128(10), -// }]; - -// assert!( -// init_result.is_ok(), -// "Init failed: {}", -// init_result.err().unwrap() -// ); - -// let result = handle( -// &mut deps, -// env, -// ExecuteMsg::SwapTokensForExact { -// offer: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// expected_return: None, -// path: vec![HumanAddr("token_addr".into())], -// recipient: None, -// }, -// ) -// .unwrap(); - -// assert!(result.messages.len() > 0); -// let result: Option = load(&deps.storage, EPHEMERAL_STORAGE_KEY)?; -// match result { -// Some(info) => { -// assert_eq!( -// info.amount, -// TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// } -// ); - -// assert_eq!(info.paths, vec![HumanAddr("token_addr".into())]); -// } -// None => panic!("Ephemeral storage should not be empty!"), -// } - -// Ok(()) -// } - -// /*#[test] -// fn swap_snip20_native_for_tokens_ok() -> StdResult<()> { -// let (init_result, mut deps) = init_helper(100); -// let mut env = mkenv("admin"); - -// env.message.sent_funds = vec![Coin { -// denom: "uscrt".into(), -// amount: Uint128(10), -// }]; - -// assert!( -// init_result.is_ok(), -// "Init failed: {}", -// init_result.err().unwrap() -// ); - -// let result = handle( -// &mut deps, -// env, -// snip20::SwapTokensForExact { -// offer: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// expected_return: None, -// path: vec![HumanAddr("token_addr".into())], -// }, -// ) -// .unwrap(); - -// assert!(result.messages.len() > 0); -// let result: Option = load(&deps.storage, EPHEMERAL_STORAGE_KEY)?; -// match result { -// Some(info) => { -// assert_eq!( -// info.amount, -// TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// } -// ); -// assert_eq!( -// info.paths, -// vec![HumanAddr("token_addr".into())] -// ); -// } -// None => panic!("Ephemeral storage should not be empty!"), -// } - -// Ok(()) -// }*/ - -// #[test] -// fn snip20_swap() -> StdResult<()> { -// let (init_result, mut deps) = init_helper(100); -// let mut env = mkenv("admin"); - -// assert!( -// init_result.is_ok(), -// "Init failed: {}", -// init_result.err().unwrap() -// ); - -// save( -// &mut deps.storage, -// EPHEMERAL_STORAGE_KEY, -// &CurrentSwapInfo { -// amount_out_min: Some(Uint128(10)), -// amount: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// paths: vec![ -// HumanAddr(PAIR_CONTRACT_1.into()), -// HumanAddr(PAIR_CONTRACT_2.into()), -// ], -// signature: to_binary("this is signature").unwrap(), -// recipient: HumanAddr("recipient".into()), -// current_index: 0, -// }, -// )?; - -// let result = handle( -// &mut deps, -// mkenv("CUSTOM_TOKEN_1"), -// ExecuteMsg::Receive { -// from: HumanAddr("recipient".into()), -// msg: Some( -// to_binary(&InvokeMsg::SwapTokensForExact { -// expected_return: Some(Uint128(1000)), -// paths: vec![PAIR_CONTRACT_1.into()], -// recipient: None, -// }) -// .unwrap(), -// ), -// amount: Uint128(100), -// }, -// ); - -// match result { -// Ok(info) => { -// println!("{:?}", info.messages); -// } -// Err(err) => { -// let test = err.to_string(); -// panic!("{}", "Must not return error ".to_string() + &test) -// } -// } - -// Ok(()) -// } - -// #[test] -// fn first_swap_callback_with_one_more_unauthorized() -> StdResult<()> { -// let (init_result, mut deps) = init_helper(100); -// let mut env = mkenv("admin"); - -// assert!( -// init_result.is_ok(), -// "Init failed: {}", -// init_result.err().unwrap() -// ); - -// save( -// &mut deps.storage, -// EPHEMERAL_STORAGE_KEY, -// &CurrentSwapInfo { -// amount_out_min: Some(Uint128(10)), -// amount: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// paths: vec![ -// HumanAddr(PAIR_CONTRACT_1.into()), -// HumanAddr(PAIR_CONTRACT_2.into()), -// ], -// signature: to_binary("this is signature").unwrap(), -// recipient: HumanAddr("recipient".into()), -// current_index: 0, -// }, -// )?; - -// let result = handle( -// &mut deps, -// env, -// ExecuteMsg::SwapCallBack { -// last_token_out: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(100), -// }, -// signature: to_binary("wrong signature").unwrap(), -// }, -// ); - -// match result { -// Err(StdError::Unauthorized { .. }) => {} -// _ => panic!("Must return unauthorized error"), -// } - -// Ok(()) -// } - -// #[test] -// fn first_swap_callback_with_one_more_ok() -> StdResult<()> { -// let (init_result, mut deps) = init_helper(100); -// let mut env = mkenv("admin"); - -// assert!( -// init_result.is_ok(), -// "Init failed: {}", -// init_result.err().unwrap() -// ); - -// save( -// &mut deps.storage, -// EPHEMERAL_STORAGE_KEY, -// &CurrentSwapInfo { -// amount_out_min: Some(Uint128(10)), -// amount: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// paths: vec![ -// HumanAddr(PAIR_CONTRACT_1.into()), -// HumanAddr(PAIR_CONTRACT_2.into()), -// ], -// signature: to_binary("this is signature").unwrap(), -// recipient: HumanAddr("recipient".into()), -// current_index: 0, -// }, -// )?; - -// let result = handle( -// &mut deps, -// env, -// ExecuteMsg::SwapCallBack { -// last_token_out: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// signature: to_binary("this is signature").unwrap(), -// }, -// ) -// .unwrap(); - -// println!("{:?}", result.messages); - -// Ok(()) -// } - -// #[test] -// fn first_swap_callback_with_no_more_ok() -> StdResult<()> { -// let (init_result, mut deps) = init_helper(100); -// let mut env = mkenv("admin"); - -// assert!( -// init_result.is_ok(), -// "Init failed: {}", -// init_result.err().unwrap() -// ); - -// save( -// &mut deps.storage, -// EPHEMERAL_STORAGE_KEY, -// &CurrentSwapInfo { -// amount_out_min: Some(Uint128(10)), -// amount: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// paths: vec![HumanAddr(PAIR_CONTRACT_1.into())], -// signature: to_binary("this is signature").unwrap(), -// recipient: HumanAddr("recipient".into()), -// current_index: 0, -// }, -// )?; - -// let result = handle( -// &mut deps, -// env.clone(), -// ExecuteMsg::SwapCallBack { -// last_token_out: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// signature: to_binary("this is signature").unwrap(), -// }, -// ) -// .unwrap(); - -// assert_eq!(result.messages.len(), 1); - -// println!("{:?}", result.messages[0]); -// let test: CosmosMsg = CosmosMsg::Wasm(WasmMsg::Execute { -// contract_addr: HumanAddr::from(CUSTOM_TOKEN_1), -// callback_code_hash: "hash".into(), -// msg: to_binary(&snip20::ExecuteMsg::Send { -// recipient: HumanAddr("recipient".into()), -// amount: Uint128(10), -// padding: None, -// msg: None, -// recipient_code_hash: None, -// memo: None, -// })?, -// send: vec![], -// }); -// println!("{:?}", test); -// assert!(result.messages.contains(&CosmosMsg::Wasm(WasmMsg::Execute { -// contract_addr: HumanAddr::from(CUSTOM_TOKEN_1), -// callback_code_hash: "hash".into(), -// msg: to_binary(&snip20::ExecuteMsg::Send { -// recipient: HumanAddr("recipient".into()), -// amount: Uint128(10), //This is how much balance the address has -// padding: None, -// msg: None, -// recipient_code_hash: None, -// memo: None, -// })?, -// send: vec![] -// }))); -// Ok(()) -// } - -// #[test] -// fn first_swap_callback_with_no_more_not_enough_return() -> StdResult<()> { -// let (init_result, mut deps) = init_helper(100); -// let mut env = mkenv("admin"); - -// assert!( -// init_result.is_ok(), -// "Init failed: {}", -// init_result.err().unwrap() -// ); - -// save( -// &mut deps.storage, -// EPHEMERAL_STORAGE_KEY, -// &CurrentSwapInfo { -// amount_out_min: Some(Uint128(100)), -// amount: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// paths: vec![HumanAddr(PAIR_CONTRACT_1.into())], -// signature: to_binary("this is signature").unwrap(), -// recipient: HumanAddr("recipient".into()), -// current_index: 0, -// }, -// )?; - -// let result = handle( -// &mut deps, -// env.clone(), -// ExecuteMsg::SwapCallBack { -// last_token_out: TokenAmount { -// token: TokenType::NativeToken { -// denom: "uscrt".into(), -// }, -// amount: Uint128(10), -// }, -// signature: to_binary("this is signature").unwrap(), -// }, -// ); - -// match result { -// Err(StdError::GenericErr { .. }) => {} -// _ => panic!("Must return error"), -// } -// Ok(()) -// } - -// /* - -// //*** */ -// #[test] -// fn swap_tokens_for_exact_tokens() -> StdResult<()> { -// Ok(()) -// } -// */ -// fn mkconfig(env: Env, id: u64) -> Config { -// Config::from_init_msg( -// env, -// InitMsg { -// factory_address: ContractLink { -// address: HumanAddr(String::from(FACTORY_ADDRESS)), -// code_hash: "Test".to_string(), -// }, -// prng_seed: to_binary(&"prng").unwrap(), -// entropy: to_binary(&"entropy").unwrap(), -// viewing_key: None, -// }, -// ) -// } -// fn mkdeps() -> Deps { -// mock_dependencies(30, &[]) -// } -// fn mkenv(sender: impl Into) -> Env { -// mock_env(sender, &[]) -// } - -// impl Into for &Config { -// fn into(self) -> InitMsg { -// InitMsg { -// factory_address: self.factory_address.clone(), -// prng_seed: to_binary(&"prng").unwrap(), -// entropy: to_binary(&"entropy").unwrap(), -// viewing_key: None, -// } -// } -// } - -// fn init_helper( -// contract_bal: u128, -// ) -> ( -// StdResult, -// Deps, -// ) { -// let mut deps = mock_deps(); -// let env = mock_env("admin", &[]); - -// let init_msg = InitMsg { -// factory_address: ContractLink { -// address: HumanAddr(String::from(FACTORY_ADDRESS)), -// code_hash: "Test".to_string(), -// }, -// prng_seed: to_binary(&"prng").unwrap(), -// entropy: to_binary(&"entropy").unwrap(), -// viewing_key: None, -// }; - -// (init(&mut deps, env, init_msg), deps) -// } - -// fn mock_deps() -> Deps { -// Extern { -// storage: MockStorage::default(), -// api: MockApi::new(123), -// querier: MockQuerier { portion: 2500 }, -// } -// } -// struct MockQuerier { -// portion: u128, -// } -// impl Querier for MockQuerier { -// fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { -// let request: QueryRequest = from_slice(bin_request).unwrap(); -// match &request { -// QueryRequest::Wasm(msg) => match msg { -// WasmQuery::Smart { contract_addr, .. } => { -// println!("{}", contract_addr); -// match contract_addr.as_str() { -// FACTORY_ADDRESS => { -// QuerierResult::Ok(to_binary(&FactoryQueryResponse::GetConfig { -// pair_contract: ContractInstantiationInfo { -// code_hash: "".to_string(), -// id: 1, -// }, -// amm_settings: shadeswap_shared::amm_pair::AMMSettings { -// lp_fee: Fee::new(28, 10000), -// shade_dao_fee: Fee::new(2, 10000), -// shade_dao_address: ContractLink { -// address: HumanAddr(String::from("DAO")), -// code_hash: "".to_string(), -// }, -// }, -// lp_token_contract: ContractInstantiationInfo { -// code_hash: "".to_string(), -// id: 1, -// }, -// })) -// } -// PAIR_CONTRACT_1 => QuerierResult::Ok(to_binary( -// &AMMPairQueryMsgResponse::GetPairInfo { -// liquidity_token: ContractLink { -// address: HumanAddr::from("asd"), -// code_hash: "".to_string(), -// }, -// factory: ContractLink { -// address: HumanAddr::from("asd"), -// code_hash: "".to_string(), -// }, -// pair: TokenPair( -// TokenType::CustomToken { -// contract_addr: CUSTOM_TOKEN_1.into(), -// token_code_hash: "hash".into(), -// }, -// TokenType::NativeToken { -// denom: "denom".into(), -// }, -// ), -// amount_0: Uint128(100), -// amount_1: Uint128(101), -// total_liquidity: Uint128(100), -// contract_version: 1, -// }, -// )), -// CUSTOM_TOKEN_1 => QuerierResult::Ok(to_binary(&IntBalanceResponse { -// balance: Balance { -// amount: Uint128(100), -// }, -// })), -// _ => unimplemented!(), -// } -// } -// _ => unimplemented!(), -// }, -// _ => unimplemented!(), -// } -// } - -// fn query(&self, request: &QueryRequest) -> StdResult { -// self.custom_query(request) -// } - -// fn custom_query( -// &self, -// request: &QueryRequest, -// ) -> StdResult { -// let raw = match to_vec(request) { -// Ok(raw) => raw, -// Err(e) => { -// return Err(StdError::generic_err(format!( -// "Serializing QueryRequest: {}", -// e -// ))) -// } -// }; -// match self.raw_query(&raw) { -// Err(sys) => Err(StdError::generic_err(format!( -// "Querier system error: {}", -// sys -// ))), -// Ok(Err(err)) => Err(err), -// // in theory we would process the response, but here it is the same type, so just pass through -// Ok(Ok(res)) => from_binary(&res), -// } -// } - -// fn query_balance>(&self, address: U, denom: &str) -> StdResult { -// let request = BankQuery::Balance { -// address: address.into(), -// denom: denom.to_string(), -// } -// .into(); -// let res: BalanceResponse = self.query(&request)?; -// Ok(res.amount) -// } - -// fn query_all_balances>(&self, address: U) -> StdResult> { -// let request = BankQuery::AllBalances { -// address: address.into(), -// } -// .into(); -// let res: AllBalanceResponse = self.query(&request)?; -// Ok(res.amount) -// } -// } -// #[derive(Serialize, Deserialize)] -// struct IntBalanceResponse { -// pub balance: Balance, -// } -// } +#[cfg(test)] +pub mod tests { + use crate::contract::SWAP_REPLY_ID; + use crate::contract::execute; + use crate::contract::instantiate; + use crate::state::Config; + use crate::state::CurrentSwapInfo; + use crate::state::config_r; + use crate::state::epheral_storage_r; + use crate::state::epheral_storage_w; + use cosmwasm_std::Addr; + use cosmwasm_std::OwnedDeps; + use cosmwasm_std::Response; + use cosmwasm_std::StdResult; + use cosmwasm_std::SubMsg; + use cosmwasm_std::from_slice; + use cosmwasm_std::testing::mock_env; + use cosmwasm_std::testing::MockApi; + use cosmwasm_std::testing::MockStorage; + use cosmwasm_std::testing::mock_info; + use cosmwasm_std::to_binary; + + use serde::Deserialize; + use serde::Serialize; + use shadeswap_shared::admin::ValidateAdminPermissionResponse; + use shadeswap_shared::core::TokenPair; + use shadeswap_shared::msg::amm_pair::{ExecuteMsg as AMMPairExecuteMsg}; + use shadeswap_shared::msg::factory::{ QueryResponse as FactoryQueryResponse}; + use shadeswap_shared::msg::amm_pair::{QueryMsgResponse as AMMPairQueryMsgResponse}; + use cosmwasm_std::Api; + use cosmwasm_std::Coin; + + use cosmwasm_std::Empty; + use cosmwasm_std::Env; + use cosmwasm_std::Querier; + use cosmwasm_std::QuerierResult; + use shadeswap_shared::utils::asset::Contract; + use cosmwasm_std::QueryRequest; + use cosmwasm_std::StdError; + use cosmwasm_std::Storage; + use cosmwasm_std::Uint128; + use cosmwasm_std::WasmMsg; + use cosmwasm_std::WasmQuery; + use shadeswap_shared::core::ContractInstantiationInfo; + use shadeswap_shared::core::Fee; + use shadeswap_shared::core::TokenAmount; + use shadeswap_shared::core::TokenType; + use shadeswap_shared::router::ExecuteMsg; + use shadeswap_shared::router::Hop; + use shadeswap_shared::router::InitMsg; + use shadeswap_shared::router::InvokeMsg; + + use shadeswap_shared::snip20::manager::Balance; + + pub const FACTORY_ADDRESS: &str = "FACTORY_ADDRESS"; + pub const PAIR_CONTRACT_1: &str = "paircontracta"; + pub const PAIR_CONTRACT_2: &str = "paircontractb"; + pub const CUSTOM_TOKEN_1: &str = "CUSTOM_TOKEN_1"; + + #[test] + fn ok_init() -> StdResult<()> { + let ref mut deps = mkdeps(); + let env = mock_env(); + let config = mkconfig(env.clone(), 0); + let mock_info = mock_info("admin", &[]); + assert!(instantiate(deps.as_mut(), env.clone(),mock_info, (&config).into()).is_ok()); + assert_eq!(config, config_r(deps.as_mut().storage).load()?); + Ok(()) + } + + #[test] + fn swap_native_for_snip20_tokens_ok() -> StdResult<()> { + let (init_result, mut deps) = init_helper(); + assert!( + init_result.is_ok(), + "Init failed: {}", + init_result.err().unwrap() + ); + + let result = execute( + deps.as_mut(), + mock_env(), + mock_info("admin", &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(10u128) }]), + ExecuteMsg::SwapTokensForExact { + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + expected_return: None, + path: vec![Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}], + recipient: None, + }, + ) + .unwrap(); + + assert!(result.messages.len() > 0); + let result = epheral_storage_r(&deps.storage).load(); + match result { + Ok(info) => { + assert_eq!( + info.amount, + TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + } + ); + + assert_eq!(info.path, vec![Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}]); + } + Err(_) => panic!("Ephemeral storage should not be empty!"), + } + + Ok(()) + } + + #[test] + fn swap_snip20_native_for_tokens_ok() -> StdResult<()> { + let (init_result, mut deps) = init_helper(); + let env = mock_env(); + let mock_info = mock_info("admin", &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(10u128) }]); + + assert!( + init_result.is_ok(), + "Init failed: {}", + init_result.err().unwrap() + ); + + let result = execute( + deps.as_mut(), + env, + mock_info, + ExecuteMsg::SwapTokensForExact { + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + expected_return: None, + path: vec![Hop{addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}], + recipient: Some("sender_addr".to_string()), + }, + ) + .unwrap(); + + assert!(result.messages.len() > 0); + let result = epheral_storage_r(&deps.storage).load(); + match result { + Ok(info) => { + assert_eq!( + info.amount, + TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + } + ); + assert_eq!( + info.path, + vec![Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}] + ); + } + Err(_) => panic!("Ephemeral storage should not be empty!"), + } + + Ok(()) + } + + #[test] + fn snip20_swap() -> StdResult<()> { + let mock_info = mock_info("admin", &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(1000000000000000u128) }]); + let (init_result, mut deps) = init_helper(); + assert!( + init_result.is_ok(), + "Init failed: {}", + init_result.err().unwrap() + ); + + epheral_storage_w(&mut deps.storage).save( &CurrentSwapInfo { + amount_out_min: Some(Uint128::new(10u128)), + amount: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + path: vec![ + Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}, + Hop{ addr: PAIR_CONTRACT_2.to_string(), code_hash: "".to_string()}, + ], + next_token_in: TokenType::CustomToken { contract_addr: Addr::unchecked("token_1"), token_code_hash: "".to_string() }, + recipient: Addr::unchecked("recipient".to_string()), + current_index: 0, + })?; + + + let result = execute( + deps.as_mut(), + mock_env(), + mock_info, + ExecuteMsg::Receive { + from: "recipient".to_string(), + msg: Some( + to_binary(&InvokeMsg::SwapTokensForExact { + expected_return: Some(Uint128::new(1000u128)), + path: vec![Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}], + recipient: None + }) + .unwrap(), + ), + amount: Uint128::new(100u128), + }, + ); + + match result { + Ok(info) => { + println!("{:?}", info.messages); + } + Err(err) => { + let _test = err.to_string(); + assert_eq!(StdError::generic_err("No matching token in pair"),err); + } + } + + Ok(()) + } + + #[test] + fn first_swap_callback_with_one_more_ok() -> StdResult<()> { + let (init_result, mut deps) = init_helper(); + let env = mock_env(); + + assert!( + init_result.is_ok(), + "Init failed: {}", + init_result.err().unwrap() + ); + + epheral_storage_w(&mut deps.storage).save(&CurrentSwapInfo { + amount: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".into(), + }, + amount: Uint128::new(10u128), + }, + amount_out_min: Some(Uint128::new(10u128)), + path: vec![ + Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}, + Hop{ addr: PAIR_CONTRACT_2.to_string(), code_hash: "".to_string()}, + ], + recipient: Addr::unchecked("recipient".to_string()), + current_index: 0, + next_token_in: TokenType::NativeToken { + denom: "uscrt".into(), + }, + })?; + + let result = execute( + deps.as_mut(), + env, + mock_info("admin", &[Coin{denom: "uscrt".to_string(), amount: Uint128::new(10u128) }]), + ExecuteMsg::SwapTokensForExact { + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + expected_return: None, + path: vec![Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}], + recipient: None, + } + ) + .unwrap(); + + let msg = to_binary(&AMMPairExecuteMsg::SwapTokens { + expected_return: None, + to: None, + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + })?; + + assert_eq!(result.messages[0],SubMsg::reply_always( + WasmMsg::Execute { + contract_addr: PAIR_CONTRACT_1.to_string(), + code_hash: "".to_string(), + msg, + funds: vec![Coin { + denom: "uscrt".to_string(), + amount: Uint128::new(10u128), + }], + }, + SWAP_REPLY_ID, + )); + + Ok(()) + } + + #[test] + fn first_swap_callback_with_no_more_ok() -> StdResult<()> { + let (init_result, mut deps) = init_helper(); + let env = mock_env(); + + assert!( + init_result.is_ok(), + "Init failed: {}", + init_result.err().unwrap() + ); + + epheral_storage_w(&mut deps.storage).save( + &CurrentSwapInfo { + amount_out_min: Some(Uint128::new(10u128)), + amount: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".into(), + }, + amount: Uint128::new(10u128), + }, + path: vec![ + Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}, + ], + recipient: Addr::unchecked("recipient".to_string()), + current_index: 0, + next_token_in: TokenType::NativeToken { + denom: "uscrt".into(), + }, + } + )?; + + let result = execute( + deps.as_mut(), + env.clone(), + mock_info("admin", &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(10u128)}]), + ExecuteMsg::SwapTokensForExact { + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + expected_return: None, + path: vec![Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}], + recipient: None, + }, + ) + .unwrap(); + + let msg = to_binary(&AMMPairExecuteMsg::SwapTokens { + expected_return: None, + to: None, + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + })?; + assert_eq!(result.messages[0],SubMsg::reply_always( + WasmMsg::Execute { + contract_addr: PAIR_CONTRACT_1.to_string(), + code_hash: "".to_string(), + msg, + funds: vec![Coin { + denom: "uscrt".to_string(), + amount: Uint128::new(10u128), + }], + }, + SWAP_REPLY_ID, + )); + + Ok(()) + } + + #[test] + fn first_swap_callback_with_no_more_not_enough_return() -> StdResult<()> { + let (init_result, mut deps) = init_helper(); + let env = mock_env(); + + assert!( + init_result.is_ok(), + "Init failed: {}", + init_result.err().unwrap() + ); + + epheral_storage_w(&mut deps.storage).save( + &CurrentSwapInfo { + amount_out_min: Some(Uint128::new(100)), + amount: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".into(), + }, + amount: Uint128::new(10), + }, + path: vec![ + Hop{ addr: PAIR_CONTRACT_1.to_string(), code_hash: "".to_string()}, + ], + recipient: Addr::unchecked("recipient".to_string()), + current_index: 0, + next_token_in: TokenType::NativeToken { + denom: "uscrt".into(), + }, + } + )?; + + let result = execute( + deps.as_mut(), + env.clone(), + mock_info("admin", &[]), + ExecuteMsg::SwapTokensForExact { + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), + }, + amount: Uint128::new(10u128), + }, + expected_return: None, + path: vec![Hop{ addr: "token_addr".to_string(), code_hash: "".to_string()}], + recipient: None, + }, + ); + + match result { + Err(StdError::GenericErr { .. }) => {} + _ => panic!("Must return error"), + } + Ok(()) + } + + fn mkconfig(_env: Env, _id: u64) -> Config { + Config{ + viewing_key: "SHADE_ROUTER_KEY".to_string(), + admin_auth: Contract{address: Addr::unchecked("".to_string()), code_hash: "".to_string()}, + } + } + fn mkdeps() -> OwnedDeps { + mock_dependencies(&[]) + } + + + impl Into for &Config { + fn into(self) -> InitMsg { + InitMsg { + prng_seed: to_binary(&"prng").unwrap(), + entropy: to_binary(&"entropy").unwrap(), + admin_auth: Contract{address: Addr::unchecked("".to_string()), code_hash: "".to_string()}, + } + } + } + + fn init_helper( + ) -> ( + StdResult, + OwnedDeps, + ) { + let mut deps = mock_dependencies(&[]); + let env = mock_env(); + + let init_msg = InitMsg { + prng_seed: to_binary(&"prng").unwrap(), + entropy: to_binary(&"entropy").unwrap(), + admin_auth: Contract { + address: Addr::unchecked("admin_auth".to_string()), + code_hash: "".to_string() + }, + }; + + (instantiate(deps.as_mut(), env, mock_info("admin", &[]), init_msg), deps) + } + + pub fn mock_dependencies( + _contract_balance: &[Coin], + ) -> OwnedDeps { + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: MockQuerier { portion: 100 }, + custom_query_type: std::marker::PhantomData, + } + } + + + #[derive(Serialize, Deserialize)] + struct IntBalanceResponse { + pub balance: Balance, + } + + pub struct MockQuerier { + portion: u128, + } + + impl Querier for MockQuerier { + fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { + let request: QueryRequest = from_slice(bin_request).unwrap(); + match &request { + QueryRequest::Wasm(msg) => match msg { + WasmQuery::Smart { contract_addr, code_hash: _, msg: _} => { + println!("{}", contract_addr); + match contract_addr.as_str() { + FACTORY_ADDRESS => { + QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(to_binary(&FactoryQueryResponse::GetConfig { + pair_contract: ContractInstantiationInfo { + code_hash: "".to_string(), + id: 1, + }, + amm_settings: shadeswap_shared::amm_pair::AMMSettings { + lp_fee: Fee::new(28, 10000), + shade_dao_fee: Fee::new(2, 10000), + shade_dao_address: Contract { + address: Addr::unchecked(String::from("DAO")), + code_hash: "".to_string(), + }, + }, + lp_token_contract: ContractInstantiationInfo { + code_hash: "".to_string(), + id: 1, + }, + authenticator: None, + admin_auth: Contract { address: Addr::unchecked("admin_auth".to_string()), code_hash: "".to_string() }, + }).unwrap())) + } + "admin_auth" => { + QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(to_binary(&ValidateAdminPermissionResponse{ + has_permission: true, + }).unwrap())) + }, + PAIR_CONTRACT_1 => + { + QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(to_binary( + &AMMPairQueryMsgResponse::GetPairInfo { + liquidity_token: Contract { + address: Addr::unchecked("asd"), + code_hash: "".to_string(), + }, + factory: Contract { + address: Addr::unchecked("asd"), + code_hash: "".to_string(), + }, + pair: TokenPair( + TokenType::CustomToken { + contract_addr: Addr::unchecked(CUSTOM_TOKEN_1.to_string()), + token_code_hash: "hash".into(), + }, + TokenType::NativeToken { + denom: "denom".into(), + }, + ), + amount_0: Uint128::new(100), + amount_1: Uint128::new(101), + total_liquidity: Uint128::new(100), + contract_version: 1, + }, + ).unwrap())) + }, + CUSTOM_TOKEN_1 => QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(to_binary(&IntBalanceResponse { + balance: Balance(Uint128::new(100)), + }).unwrap())), + _ => unimplemented!(), + } + } + _ => unimplemented!(), + }, + _ => unimplemented!(), + } + } + } +} diff --git a/contracts/router/tests/integration.rs b/contracts/router/tests/integration.rs index 33b3860..ab27e64 100644 --- a/contracts/router/tests/integration.rs +++ b/contracts/router/tests/integration.rs @@ -1,18 +1,345 @@ -//! This integration test tries to run and call the generated wasm. -//! It depends on a Wasm build being available, which you can create with `cargo wasm`. -//! Then running `cargo integration-test` will validate we can properly call into that generated Wasm. -//! -//! You can easily convert unit tests to integration tests. -//! 1. First copy them over verbatum, -//! 2. Then change -//! let mut deps = mock_dependencies(20, &[]); -//! to -//! let mut deps = mock_instance(WASM, &[]); -//! 3. If you access raw storage, where ever you see something like: -//! deps.storage.get(CONFIG_KEY).expect("no data stored"); -//! replace it with: -//! deps.with_storage(|store| { -//! let data = store.get(CONFIG_KEY).expect("no data stored"); -//! //... -//! }); -//! 4. Anywhere you see query(&deps, ...) you must replace it with query(&mut deps, ...) +use secret_multi_test::{App, Contract, ContractWrapper, Executor}; +use shadeswap_shared::msg::router::{InitMsg, ExecuteMsg, QueryMsg}; +use cosmwasm_std::{ + to_binary, Addr, Empty, Uint128, +}; + +#[cfg(not(target_arch = "wasm32"))] +#[test] +pub fn router_integration_tests() { + use multi_test::admin::admin_help::init_admin_contract; + use multi_test::amm_pairs::amm_pairs_lib::amm_pairs_lib::{init_amm_pair, create_amm_settings, create_amm_pairs, create_custom_token, amm_pair_contract_store_in, add_liquidity_to_amm_pairs}; + use multi_test::staking::staking_lib::staking_lib::{staking_contract_store_in, create_staking_info_contract}; + use router::contract::{instantiate, query, execute, reply}; + use multi_test::help_lib::integration_help_lib::{roll_blockchain, mint_deposit_snip20, store_init_factory_contract, + convert_to_contract_link, snip20_lp_token_contract_store, create_token_pair, increase_allowance, snip_20_balance_query, configure_block_send_init_funds, create_token_pair_with_native, set_viewing_key}; + use cosmwasm_std::{Uint128, Coin, ContractInfo, BlockInfo}; + use multi_test::util_addr::util_addr::{OWNER, STAKER_A}; + use multi_test::util_addr::util_blockchain::CHAIN_ID; + use shadeswap_shared::core::{TokenAmount, Callback, ContractInstantiationInfo}; + use shadeswap_shared::msg::amm_pair::{InvokeMsg, ExecuteMsg as AMMPairExecuteMsg}; + use shadeswap_shared::msg::router::QueryMsgResponse; + use shadeswap_shared::router::Hop; + use shadeswap_shared::utils::testing::TestingExt; + use shadeswap_shared::utils::asset::Contract as SContract; + use shadeswap_shared::{core::{TokenType}}; + use multi_test::help_lib::integration_help_lib::{generate_snip20_contract}; + use multi_test::help_lib::integration_help_lib::print_events; + use multi_test::factory::factory_lib::factory_lib::{init_factory, create_amm_pairs_to_factory, list_amm_pairs_from_factory}; + use cosmwasm_std::Timestamp; + + pub fn router_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(execute, instantiate, query).with_reply(reply); + Box::new(contract) + } + + let staker_a_addr = Addr::unchecked(STAKER_A.to_owned()); + let owner_addr = Addr::unchecked(OWNER); + let mut router = App::default(); + + configure_block_send_init_funds(&mut router, &owner_addr, Uint128::new(100000000000000u128)); + // GENERATE TOKEN PAIRS & REWARD TOKEN + let token_0_contract = generate_snip20_contract(&mut router, "ETH".to_string(),"ETH".to_string(),18).unwrap(); + let token_1_contract = generate_snip20_contract(&mut router, "USDT".to_string(),"USDT".to_string(),18).unwrap(); + let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); + + // MINT AND DEPOSIT FOR LIQUIDITY + mint_deposit_snip20(&mut router,&token_0_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + mint_deposit_snip20(&mut router,&token_1_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + mint_deposit_snip20(&mut router,&reward_contract,&owner_addr,Uint128::new(10000000000u128), &owner_addr); + + roll_blockchain(&mut router, 1).unwrap(); + + // INIT LP, STAKING, AMM PAIRS + let admin_contract = init_admin_contract(&mut router, &owner_addr).unwrap(); //store_init_factory_contract(&mut router, &convert_to_contract_link(&admin_contract)).unwrap(); + let amm_contract_info = router.store_code(amm_pair_contract_store_in()); + let lp_token_info = router.store_code(snip20_lp_token_contract_store()); + let staking_info = router.store_code(staking_contract_store_in()); + + // STORE ROUTER CONTRACT + let router_contract_info = router.store_code(router_contract_store()); + roll_blockchain(&mut router, 1).unwrap(); + + // INIT ROUTER CONTRACTs + let init_msg = InitMsg { + prng_seed: to_binary("password").unwrap(), + entropy: to_binary("password").unwrap(), + admin_auth: convert_to_contract_link(&admin_contract), + }; + + roll_blockchain(&mut router, 1).unwrap(); + let router_contract = router + .instantiate_contract( + router_contract_info, + owner_addr.to_owned(), + &init_msg, + &[], + "router", + Some(OWNER.to_string()), + ).unwrap(); + + // CREATE FACTORY + roll_blockchain(&mut router, 1).unwrap(); + let factory_contract = init_factory( + &mut router, + &convert_to_contract_link(&admin_contract), + &OWNER, + false, + create_amm_settings(3,100,8,100, &staker_a_addr), + ContractInstantiationInfo{ + code_hash: amm_contract_info.code_hash.clone(), + id: amm_contract_info.code_id, + }, + ContractInstantiationInfo{ + code_hash: lp_token_info.code_hash.clone(), + id: lp_token_info.code_id, + }, + "seed", + "api_key", + None + ).unwrap(); + + // CREATE AMM_PAIR SNIP20 vs SNIP20 + create_amm_pairs_to_factory( + &mut router, + &factory_contract, + &create_token_pair( + &convert_to_contract_link(&token_0_contract), + &convert_to_contract_link(&token_1_contract) + ), + "seed", + &create_staking_info_contract( + staking_info.code_id, + &staking_info.code_hash, + Uint128::new(30000u128), + TokenType::CustomToken { + contract_addr: reward_contract.address.clone(), + token_code_hash: reward_contract.code_hash.clone() }, + Uint128::new(30000000000u128) + ), + &router_contract, + &owner_addr).unwrap(); + + // LIST AMM PAIR + let amm_pairs = list_amm_pairs_from_factory( + &mut router, + &factory_contract, + 0, 30 + ).unwrap(); + + // ASSERT AMM PAIRS == 1 + assert_eq!(amm_pairs.len(), 1); + + // INCREASE ALLOWANCE FOR AMM PAIR + increase_allowance(&mut router, &token_0_contract, Uint128::new(10000000000000000u128),&amm_pairs[0].address , &owner_addr).unwrap(); + increase_allowance(&mut router, &token_1_contract, Uint128::new(10000000000000000u128),&amm_pairs[0].address , &owner_addr).unwrap(); + + // ADD LIQUIDITY TO AMM_PAIR SNIP20 vs SNIP20 + add_liquidity_to_amm_pairs( + &mut router, + &ContractInfo{ + address: amm_pairs[0].address.clone(), + code_hash: "".to_string(), + }, + &amm_pairs[0].pair, + Uint128::new(1000000000u128), + Uint128::new(1000000000u128), + Some(Uint128::new(1000000000u128)), + Some(true), + &owner_addr, + &[] + ).unwrap(); + + // REGISTER SNIP 20 ROUTER + roll_blockchain(&mut router, 1).unwrap(); + let msg = ExecuteMsg::RegisterSNIP20Token { + token_addr: token_0_contract.address.to_string() , + token_code_hash: token_0_contract.code_hash.to_owned() + }; + roll_blockchain(&mut router, 1).unwrap(); + let _ = router.execute_contract( + owner_addr.to_owned(), + &router_contract, + &msg, + &[]).unwrap(); + + roll_blockchain(&mut router, 1).unwrap(); + let msg = ExecuteMsg::RegisterSNIP20Token { + token_addr: token_1_contract.address.to_string() , + token_code_hash: token_1_contract.code_hash.to_owned() + }; + roll_blockchain(&mut router, 1).unwrap(); + let _ = router.execute_contract( + owner_addr.to_owned(), + &router_contract, + &msg, + &[]).unwrap(); + + roll_blockchain(&mut router, 1).unwrap(); + // SWAPSIMULATION - QUERY + let offer = TokenAmount{ + token: TokenType::CustomToken { + contract_addr: token_0_contract.address.to_owned(), + token_code_hash: token_0_contract.code_hash.to_owned() + }, + amount: Uint128::new(1000u128) + }; + let swap_query = QueryMsg::SwapSimulation { + offer: offer.to_owned(), + path: vec![Hop{addr: amm_pairs[0].address.to_string(), code_hash: amm_contract_info.code_hash.clone()}] + }; + + // ASSERT SWAPSIMULATION + let query_response:QueryMsgResponse = router.query_test( + router_contract.to_owned(), + to_binary(&swap_query).unwrap() + ).unwrap(); + + match query_response { + QueryMsgResponse::SwapSimulation { + total_fee_amount, + lp_fee_amount, + shade_dao_fee_amount, + result, + price , + } => { + // Verify result not actual amount + assert_ne!(total_fee_amount, Uint128::zero()); + assert_ne!(lp_fee_amount, Uint128::zero()); + assert_ne!(shade_dao_fee_amount, Uint128::zero()); + assert_ne!(result.return_amount, Uint128::zero()); + assert_eq!(price, "1".to_string()); + }, + _ => panic!("Query Responsedoes not match") + } + + // ASSERT SWAPTOKENS + roll_blockchain(&mut router, 1).unwrap(); + let invoke_msg = to_binary(&InvokeMsg::SwapTokens { + expected_return: Some(Uint128::new(100u128)), + to: Some(staker_a_addr.to_string()), + }).unwrap(); + + let msg = snip20_reference_impl::msg::ExecuteMsg::Send { + recipient: amm_pairs[0].address.to_owned(), + recipient_code_hash: Some(amm_contract_info.code_hash.clone()), + amount: Uint128::new(1000u128), + msg: Some(invoke_msg), + memo: None, + padding: None, + }; + + let response = router.execute_contract( + owner_addr.to_owned(), + &token_0_contract, + &msg, + &[], // + ) + .unwrap(); + + // ASSERT SWAPTOKENSFOREXACT + roll_blockchain(&mut router, 1).unwrap(); + let execute_swap = ExecuteMsg::SwapTokensForExact { + offer:offer.to_owned(), + expected_return: Some(Uint128::new(1000u128)), + path: vec![Hop{addr: amm_pairs[0].address.to_string(), code_hash: amm_contract_info.code_hash.clone()}], + recipient: Some(owner_addr.to_string()) + }; + + let _response = router.execute_contract( + owner_addr.to_owned(), + &router_contract, + &execute_swap, + &[]); + + // ASSERT BALANCE TOKEN_1 + let balance = snip_20_balance_query( + &mut router, + &owner_addr, + "seed", + &token_1_contract + ).unwrap(); + assert_eq!(balance, Uint128::new(1000019000000000u128)); + + // CREATE AMM_PAIR NATIVE - SNIP20 + create_amm_pairs_to_factory( + &mut router, + &factory_contract, + &create_token_pair_with_native( + &convert_to_contract_link(&token_1_contract), + ), + "seed", + &create_staking_info_contract( + staking_info.code_id, + &staking_info.code_hash, + Uint128::new(30000u128), + TokenType::CustomToken { + contract_addr: reward_contract.address.clone(), + token_code_hash: reward_contract.code_hash.clone() }, + Uint128::new(30000000000u128) + ), + &router_contract, + &owner_addr).unwrap(); + + // LIST AMM PAIR + let amm_pairs = list_amm_pairs_from_factory( + &mut router, + &factory_contract, + 0, 30 + ).unwrap(); + + // ASSERT AMM PAIRS == 2 + assert_eq!(amm_pairs.len(), 2); + increase_allowance(&mut router, &token_1_contract, Uint128::new(10000000000000000u128),&amm_pairs[1].address , &owner_addr).unwrap(); + // ADD LIQUIDITY TO AMM_PAIR NATIVE vs SNIP20 + add_liquidity_to_amm_pairs( + &mut router, + &ContractInfo{ + address: amm_pairs[1].address.clone(), + code_hash: "".to_string(), + }, + &amm_pairs[1].pair, + Uint128::new(1000000000u128), + Uint128::new(1000000000u128), + Some(Uint128::new(1000000000u128)), + Some(true), + &owner_addr, + &[Coin{ denom: "uscrt".to_string(), amount: Uint128::new(1000000000u128)}] + ).unwrap(); + roll_blockchain(&mut router, 1).unwrap(); + + // SWAP NATIVE TOKEN -> SNIP20 + let native_offer = TokenAmount{ + token: TokenType::NativeToken { + denom:"uscrt".to_string() + }, + amount: Uint128::new(1000u128) + }; + let _ = router.send_tokens(owner_addr.clone(), staker_a_addr.clone(), &[Coin{denom: "uscrt".to_string(), amount: Uint128::new(1000)}]).unwrap(); + let execute_swap = ExecuteMsg::SwapTokensForExact { + offer:native_offer.to_owned(), + expected_return: Some(Uint128::new(100u128)), + path: vec![Hop{addr: amm_pairs[1].address.to_string(), code_hash: amm_contract_info.code_hash.clone()}], + recipient:None + }; + + let _response = router.execute_contract( + staker_a_addr.to_owned(), + &router_contract, + &execute_swap, + &[Coin{denom: "uscrt".to_string(), amount: Uint128::new(1000u128)}]); + + // ASSERT BALANCE TOKEN_1 889 + let _ = set_viewing_key(&mut router, &token_1_contract, "password", &staker_a_addr).unwrap(); + let balance = snip_20_balance_query( + &mut router, + &staker_a_addr, + "password", + &token_1_contract + ).unwrap(); + assert_eq!(balance, Uint128::new(889u128)); + +} + + + diff --git a/contracts/snip20/Cargo.toml b/contracts/snip20/Cargo.toml index 887bd79..8a51f04 100644 --- a/contracts/snip20/Cargo.toml +++ b/contracts/snip20/Cargo.toml @@ -23,7 +23,7 @@ backtraces = ["cosmwasm-std/backtraces"] [dependencies] cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } -secret-toolkit = { git = "https://github.com/scrtlabs/secret-toolkit", branch = "cosmwasm-v1.0", features = [ +secret-toolkit = { git = "https://github.com/scrtlabs/secret-toolkit", rev = "8380c00", features = [ "permit", "viewing-key", "crypto", diff --git a/contracts/snip20/src/transaction_history.rs b/contracts/snip20/src/transaction_history.rs index 4e0d4f2..388467e 100644 --- a/contracts/snip20/src/transaction_history.rs +++ b/contracts/snip20/src/transaction_history.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Addr, Api, CanonicalAddr, Coin, StdError, StdResult, Storage, Uint128}; +use cosmwasm_std::{Addr, Api, CanonicalAddr, Coin, StdError, StdResult, Uint128, Storage}; use secret_toolkit::storage::AppendStore; diff --git a/contracts/staking/Cargo.toml b/contracts/staking/Cargo.toml index ad0f908..590349a 100644 --- a/contracts/staking/Cargo.toml +++ b/contracts/staking/Cargo.toml @@ -36,4 +36,6 @@ shadeswap-shared = {path = "../../packages/shadeswap-shared"} [dev-dependencies] cosmwasm-schema = { git = "https://github.com/CosmWasm/cosmwasm"} snip20-reference-impl = {path ="../../contracts/snip20"} -secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } \ No newline at end of file +secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } +query-authentication = { git = "https://github.com/securesecrets/query-authentication", branch = "cosmwasm_v1_upgrade" } +multi_test = {path = "../../packages/multi_test"} \ No newline at end of file diff --git a/contracts/staking/README.md b/contracts/staking/README.md index 631c121..2ffbff5 100644 --- a/contracts/staking/README.md +++ b/contracts/staking/README.md @@ -37,7 +37,7 @@ The Contract to hold Pair Between Swap Tokens. |-------------------|----------------------------------|----------------------------------------------------------------------------|----------| | staking_amount | Uint128 | Total Reward Amount for staking | no | | reward_token | TokenType | Reward Token Type | no | -| contract | ContractLink | AMMPair Contract Address Link to register staking contract | no | +| contract | Contract | AMMPair Contract Address Link to register staking contract | no | @@ -114,7 +114,7 @@ Get Staker Lp Token Information. { "staked_lp_token": "Uint128", "total_staked_lp_token": "Uint128", - "reward_token" : "ContractLink" + "reward_token" : "Contract" } ``` @@ -131,7 +131,7 @@ Get Reward Token Balance for staker ```json { "amount": "Uint128", - "reward_token" : "ContractLink" + "reward_token" : "Contract" } ``` @@ -213,7 +213,7 @@ Set either new reward token or update existing with emission_rate and valid to ##### Request | Name | Type | Description | optional | |---------|-----------|-----------------------------------------------|----------| -| reward_token | ContractLink | Reward Token Contract Link | no | +| reward_token | Contract | Reward Token Contract Link | no | | amount | Uint128 | Emission Rate | no | | valid_to | Uint128 | Timestamp till Reward Token is valid - milliseconds | no | diff --git a/contracts/staking/rustfmt.toml b/contracts/staking/rustfmt.toml deleted file mode 100644 index 11a85e6..0000000 --- a/contracts/staking/rustfmt.toml +++ /dev/null @@ -1,15 +0,0 @@ -# stable -newline_style = "unix" -hard_tabs = false -tab_spaces = 4 - -# unstable... should we require `rustup run nightly cargo fmt` ? -# or just update the style guide when they are stable? -#fn_single_line = true -#format_code_in_doc_comments = true -#overflow_delimited_expr = true -#reorder_impl_items = true -#struct_field_align_threshold = 20 -#struct_lit_single_line = true -#report_todo = "Always" - diff --git a/contracts/staking/src/contract.rs b/contracts/staking/src/contract.rs index 997da5c..0656dec 100644 --- a/contracts/staking/src/contract.rs +++ b/contracts/staking/src/contract.rs @@ -1,20 +1,21 @@ use cosmwasm_std::{ - entry_point, Addr, Attribute, Deps, DepsMut, Env, MessageInfo, Response, - StdResult, Uint128, to_binary, Binary, StdError, from_binary, CosmosMsg, BankMsg, Coin}; + entry_point, from_binary, Addr, Attribute, BankMsg, Binary, Coin, CosmosMsg, Deps, + DepsMut, Env, MessageInfo, Response, StdError, StdResult, Uint128, +}; use shadeswap_shared::{ - core::{admin_r, admin_w, apply_admin_guard, ContractLink, TokenType}, + core::{TokenType}, query_auth::helpers::{authenticate_permit, PermitAuthentication}, + snip20::helpers::{send_msg, register_receive}, staking::{AuthQuery, ExecuteMsg, InitMsg, InvokeMsg, QueryData, QueryMsg}, - utils::{pad_query_result, pad_response_result}, snip20::helpers::send_msg, Contract, + utils::{pad_query_result, pad_response_result}, + Contract, admin::helpers::{validate_admin, AdminPermissions}, }; -use shadeswap_shared::staking::QueryResponse; - use crate::{ operations::{ claim_rewards, get_claim_reward_for_user, get_config, get_staking_stake_lp_token_info, - set_reward_token, stake, store_init_reward_token_and_timestamp, unstake, - update_authenticator, proxy_stake, proxy_unstake, + proxy_stake, proxy_unstake, set_reward_token, stake, store_init_reward_token_and_timestamp, + unstake, update_authenticator, get_reward_token_to_list, }, state::{config_r, config_w, prng_seed_w, Config}, }; @@ -25,26 +26,34 @@ pub const BLOCK_SIZE: usize = 256; pub fn instantiate( deps: DepsMut, env: Env, - _info: MessageInfo, + info: MessageInfo, msg: InitMsg, ) -> StdResult { let config = Config { - amm_pair: _info.sender.clone(), + amm_pair: info.sender.clone(), daily_reward_amount: msg.daily_reward_amount, reward_token: msg.reward_token.to_owned(), - lp_token: msg.lp_token, + lp_token: msg.lp_token.clone(), authenticator: msg.authenticator, + admin_auth: msg.admin_auth, }; config_w(deps.storage).save(&config)?; - admin_w(deps.storage).save(&_info.sender)?; prng_seed_w(deps.storage).save(&msg.prng_seed.as_slice().to_vec())?; + let mut messages: Vec = vec![]; + + messages.push(register_receive( + env.contract.code_hash.clone(), + None, + &msg.lp_token + )?); + // store reward token to the list - let reward_token_address: ContractLink = match msg.reward_token { + let reward_token_address: Contract = match msg.reward_token { TokenType::CustomToken { contract_addr, token_code_hash, - } => ContractLink { + } => Contract { address: contract_addr.to_owned(), code_hash: token_code_hash.to_owned(), }, @@ -53,18 +62,17 @@ pub fn instantiate( "Invalid Token Type for Reward Token".to_string(), )) } - }; - let current_timestamp = Uint128::new((env.block.time.seconds() * 1000) as u128); + }; store_init_reward_token_and_timestamp( deps.storage, reward_token_address.to_owned(), - msg.daily_reward_amount, - current_timestamp, + msg.daily_reward_amount, + msg.valid_to )?; let mut response = Response::new(); response.data = Some(env.contract.address.as_bytes().into()); - Ok(response.add_attributes(vec![ + Ok(response.add_messages(messages).add_attributes(vec![ Attribute::new("staking_contract_addr", env.contract.address), Attribute::new("reward_token", reward_token_address.address.to_string()), Attribute::new("daily_reward_amount", msg.daily_reward_amount), @@ -76,23 +84,41 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S pad_response_result( match msg { ExecuteMsg::ProxyUnstake { for_addr, amount } => { - proxy_unstake(deps, env, info, for_addr, amount) - }, + let checked_for_addr = deps.api.addr_validate(&for_addr)?; + proxy_unstake(deps, env, info, checked_for_addr, amount) + } ExecuteMsg::Receive { from, amount, msg, .. - } => receiver_callback(deps, env, info, from, amount, msg), + } => { + let checked_from = deps.api.addr_validate(&from)?; + receiver_callback(deps, env, info, checked_from, amount, msg) + }, ExecuteMsg::ClaimRewards {} => claim_rewards(deps, info, env), ExecuteMsg::Unstake { amount, remove_liqudity, } => unstake(deps, env, info, amount, remove_liqudity), ExecuteMsg::SetAuthenticator { authenticator } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; update_authenticator(deps.storage, authenticator) } - ExecuteMsg::SetAdmin { admin } => { - apply_admin_guard(&info.sender, deps.storage)?; - admin_w(deps.storage).save(&admin)?; + ExecuteMsg::SetConfig { admin_auth } => { + let mut config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; + if let Some(admin_auth) = admin_auth { + config.admin_auth = admin_auth; + } Ok(Response::default()) } ExecuteMsg::SetRewardToken { @@ -100,27 +126,42 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S daily_reward_amount, valid_to, } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; set_reward_token(deps, env, info, reward_token, daily_reward_amount, valid_to) - }, + } ExecuteMsg::RecoverFunds { token, amount, to, msg, } => { - apply_admin_guard(&info.sender, deps.storage)?; + let config = config_r(deps.storage).load()?; + validate_admin( + &deps.querier, + AdminPermissions::ShadeSwapAdmin, + &info.sender, + &config.admin_auth, + )?; let send_msg = match token { - TokenType::CustomToken { contract_addr, token_code_hash } => vec![send_msg( - to, + TokenType::CustomToken { + contract_addr, + token_code_hash, + } => vec![send_msg( + deps.api.addr_validate(&to)?, amount, msg, None, None, - &Contract{ + &Contract { address: contract_addr, - code_hash: token_code_hash - } + code_hash: token_code_hash, + }, )?], TokenType::NativeToken { denom } => vec![CosmosMsg::Bank(BankMsg::Send { to_address: to.to_string(), @@ -154,13 +195,15 @@ fn receiver_callback( if config.lp_token.address != info.sender { return Err(StdError::generic_err("Sender was not LP Token".to_string())); } - stake(deps, env, info, amount, from) + let checked_from = deps.api.addr_validate(&from)?; + stake(deps, env, info, amount, checked_from) } InvokeMsg::ProxyStake { for_addr } => { if config.lp_token.address != info.sender { return Err(StdError::generic_err("Sender was not LP Token".to_string())); } - proxy_stake(deps, env, info, amount, from, for_addr) + let checked_for_addr = deps.api.addr_validate(&for_addr)?; + proxy_stake(deps, env, info, amount, from, checked_for_addr) } }, BLOCK_SIZE, @@ -179,14 +222,11 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { authenticate_permit(deps, permit, &deps.querier, config.authenticator)?; if res.revoked { - return Err(StdError::generic_err("".to_string())); + return Err(StdError::generic_err("Permit has been revoked".to_string())); } auth_queries(deps, env, query, res.sender) } - QueryMsg::GetAdmin {} => to_binary(&QueryResponse::GetAdmin { - admin: admin_r(deps.storage).load()?, - }), }, BLOCK_SIZE, ) @@ -196,5 +236,6 @@ pub fn auth_queries(deps: Deps, _env: Env, msg: AuthQuery, user: Addr) -> StdRes match msg { AuthQuery::GetClaimReward { time } => get_claim_reward_for_user(deps, user, time), AuthQuery::GetStakerLpTokenInfo {} => get_staking_stake_lp_token_info(deps, user), + AuthQuery::GetRewardTokens { } => get_reward_token_to_list(deps.storage), } } diff --git a/contracts/staking/src/operations.rs b/contracts/staking/src/operations.rs index 3a91c62..3bee4b2 100644 --- a/contracts/staking/src/operations.rs +++ b/contracts/staking/src/operations.rs @@ -2,24 +2,29 @@ // needs to check for the amount const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); -use cosmwasm_std::Binary; +use cosmwasm_std::{Binary}; use cosmwasm_std::{ - to_binary, wasm_execute, Addr, Attribute, CosmosMsg, Decimal, Deps, DepsMut, Env, MessageInfo, + to_binary, Addr, Attribute, CosmosMsg, Decimal, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, Storage, Uint128, WasmMsg, }; use shadeswap_shared::core::TokenType; use shadeswap_shared::snip20; -use shadeswap_shared::stake_contract::ClaimableInfo; +use shadeswap_shared::stake_contract::{ClaimableInfo}; use shadeswap_shared::staking::QueryResponse; +use shadeswap_shared::utils::ExecuteCallback; use shadeswap_shared::{ - core::ContractLink, msg::amm_pair::InvokeMsg as AmmPairInvokeMsg, Contract, + msg::amm_pair::InvokeMsg as AmmPairInvokeMsg, Contract, }; +use crate::state::{RewardTokenInfo}; +use shadeswap_shared::stake_contract::RewardTokenInfo as ResponseRewardTokenInfo; + +const SECONDS_IN_DAY:Uint128 = Uint128::new(24u128 * 60u128 * 60u128); use crate::state::{ claim_reward_info_r, claim_reward_info_w, config_r, config_w, proxy_staker_info_r, proxy_staker_info_w, reward_token_list_r, reward_token_list_w, reward_token_r, reward_token_w, staker_index_r, staker_index_w, stakers_r, stakers_w, total_staked_r, total_staked_w, - total_stakers_r, total_stakers_w, ClaimRewardsInfo, ProxyStakingInfo, RewardTokenInfo, + total_stakers_r, total_stakers_w, ClaimRewardsInfo, ProxyStakingInfo, StakingInfo, }; @@ -29,7 +34,7 @@ pub fn calculate_staker_shares(storage: &dyn Storage, amount: Uint128) -> StdRes None => Uint128::zero(), }; if total_staking_amount.is_zero() { - return Ok(Decimal::one()); + return Ok(Decimal::zero()); } let user_share = Decimal::from_ratio(amount, total_staking_amount); @@ -38,7 +43,7 @@ pub fn calculate_staker_shares(storage: &dyn Storage, amount: Uint128) -> StdRes pub fn store_init_reward_token_and_timestamp( storage: &mut dyn Storage, - reward_token: ContractLink, + reward_token: Contract, emission_amount: Uint128, current_timestamp: Uint128, ) -> StdResult<()> { @@ -51,7 +56,7 @@ pub fn store_init_reward_token_and_timestamp( &RewardTokenInfo { reward_token: reward_token.to_owned(), daily_reward_amount: emission_amount, - valid_to: Uint128::new(3747905010000u128), + valid_to: current_timestamp }, )?; Ok(()) @@ -61,7 +66,7 @@ pub fn set_reward_token( deps: DepsMut, env: Env, info: MessageInfo, - reward_token: ContractLink, + reward_token: Contract, daily_reward_amount: Uint128, valid_to: Uint128, ) -> StdResult { @@ -76,13 +81,14 @@ pub fn set_reward_token( let result = reward_list_token .iter() .find(|&x| x.to_owned() == reward_token.address.to_owned()); - if result == None { + if result.is_none() { reward_list_token.push(reward_token.address.to_owned()); } reward_token_w(deps.storage).save(&reward_token.address.as_bytes(), &reward_token_info)?; + reward_token_list_w(deps.storage).save(&reward_list_token)?; Ok(Response::new().add_attributes(vec![ Attribute::new("action", "set_reward_token"), - Attribute::new("owner", info.sender.to_string()), + Attribute::new("owner", info.sender.to_string()), Attribute::new("daily_reward_amount", daily_reward_amount.to_string()), Attribute::new("valid_to", valid_to.to_string()), ])) @@ -231,7 +237,7 @@ pub fn proxy_stake( // return response Ok(Response::new().add_attributes(vec![ - Attribute::new("action", "stake"), + Attribute::new("action", "proxy stake"), Attribute::new("staker", staker.as_str()), Attribute::new("amount", amount), ])) @@ -244,6 +250,18 @@ pub fn get_total_stakers_count(storage: &dyn Storage) -> StdResult { }; } +pub fn get_reward_token_to_list(storage:& dyn Storage) + -> StdResult { + let list: Vec = get_reward_tokens_info(storage)?; + let mut response: Vec = vec![]; + for i in list.iter(){ + response.push(i.to_owned().to_reward_token_response()) + } + to_binary(&QueryResponse::RewardTokens{ + tokens: response + }) +} + pub fn claim_rewards(deps: DepsMut, info: MessageInfo, env: Env) -> StdResult { let receiver = info.sender.clone(); let current_timestamp = Uint128::new((env.block.time.seconds()) as u128); @@ -253,7 +271,7 @@ pub fn claim_rewards(deps: DepsMut, info: MessageInfo, env: Env) -> StdResult = get_actual_reward_tokens(deps.storage, current_timestamp)?; + let reward_token_list: Vec = get_reward_tokens_info(deps.storage)?; for reward_token in reward_token_list.iter() { // calculate reward amount for each reward token let mut reward = find_claimable_reward_for_staker_by_reward_token( @@ -309,28 +327,21 @@ fn process_all_claimable_rewards( let mut claim_reward_tokens = claim_reward_info_r(storage).load(receiver.as_bytes())?; for claim_reward in claim_reward_tokens.iter_mut() { // send all remaing reward token - let msg = snip20::ExecuteMsg::Send { + let cosmos_msg = snip20::ExecuteMsg::Send { recipient: receiver.to_owned(), recipient_code_hash: None, amount: claim_reward.amount, msg: None, memo: None, padding: None, - }; - - let cosmos_msg = wasm_execute( - claim_reward.reward_token_addr.to_owned(), - claim_reward.reward_token_code_hash.to_owned(), - &msg, - vec![], - )? - .into(); + }.to_cosmos_msg(&Contract{ + address: claim_reward.reward_token_addr.to_owned(), + code_hash: claim_reward.reward_token_code_hash.to_owned(), + }, vec![])?; messages.push(cosmos_msg); claim_reward.amount = Uint128::zero(); - } - // let mut staker_info = stakers_r(storage).load(receiver.as_bytes())?; - // staker_info.last_time_updated = timestamp; + } claim_reward_info_w(storage).save(receiver.as_bytes(), &claim_reward_tokens)?; Ok(()) } @@ -350,8 +361,7 @@ pub fn claim_rewards_for_all_stakers( let mut staker_info = stakers_r(storage).load(staker_address.as_bytes())?; let staker_share = calculate_staker_shares(storage, staker_info.amount)?; - let reward_token_list: Vec = - get_actual_reward_tokens(storage, current_timestamp)?; + let reward_token_list: Vec = get_reward_tokens_info(storage)?; for reward_token in reward_token_list.iter() { // calculate reward amount for each reward token let mut reward = find_claimable_reward_for_staker_by_reward_token( @@ -394,13 +404,10 @@ pub fn claim_rewards_for_all_stakers( Ok(()) } -pub fn get_actual_reward_tokens( - storage: &dyn Storage, - current_timestamp: Uint128, -) -> StdResult> { +pub fn get_reward_tokens_info(storage: &dyn Storage) -> StdResult> { let mut list_token: Vec = Vec::new(); let reward_list = reward_token_list_r(storage).load()?; - for addr in &reward_list { + for addr in &reward_list { // load total reward token let reward_token: RewardTokenInfo = reward_token_r(storage).load(addr.as_bytes())?; list_token.push(reward_token.to_owned()) @@ -422,7 +429,7 @@ pub fn get_all_claimable_reward_for_staker( pub fn find_claimable_reward_for_staker_by_reward_token( storage: &dyn Storage, staker_address: &Addr, - reward_token: &ContractLink, + reward_token: &Contract, ) -> StdResult { let all_claimable_reward = get_all_claimable_reward_for_staker(storage, staker_address)?; let result = match all_claimable_reward @@ -442,7 +449,7 @@ pub fn find_claimable_reward_for_staker_by_reward_token( pub fn find_claimable_reward_index_for_staker( storage: &dyn Storage, staker_address: &Addr, - reward_token: &ContractLink, + reward_token: &Contract, ) -> StdResult> { let all_claimable_reward = get_all_claimable_reward_for_staker(storage, staker_address)?; return Ok(all_claimable_reward @@ -454,7 +461,7 @@ pub fn save_claimable_amount_staker_by_reward_token( storage: &mut dyn Storage, amount: Uint128, staker_address: &Addr, - reward_token: &ContractLink, + reward_token: &Contract, ) -> StdResult<()> { let mut list_claimable_reward = get_all_claimable_reward_for_staker(storage, &staker_address)?; let claimable_reward_index = @@ -483,11 +490,10 @@ pub fn calculate_incremental_staking_reward( to_timestamp: Uint128, emmision_rate: Uint128, ) -> StdResult { - let seconds_in_day = Uint128::new(24u128 * 60u128 * 60u128); if last_timestamp < to_timestamp { let time_dif = to_timestamp - last_timestamp; - let total_available_reward = emmision_rate.multiply_ratio(time_dif, seconds_in_day); - let converted_total_reward = Decimal::from_atomics(total_available_reward, 0).unwrap(); + let total_available_reward = emmision_rate.multiply_ratio(time_dif, SECONDS_IN_DAY); + let converted_total_reward = Decimal::from_atomics(total_available_reward, 0).or_else(|_|Err(StdError::generic_err("Decimal range exceeded on total available rewards.")))?; let result = converted_total_reward.checked_mul(percentage)?; Ok(result.atomics().checked_div(DECIMAL_FRACTIONAL)?) } else { @@ -504,13 +510,14 @@ pub fn get_config(deps: Deps) -> StdResult { } = config.reward_token.clone() { let response = QueryResponse::Config { - reward_token: ContractLink { + reward_token: Contract { address: contract_addr.clone(), code_hash: token_code_hash.clone(), }, lp_token: config.lp_token.clone(), daily_reward_amount: config.daily_reward_amount.clone(), - amm_pair: config.amm_pair.clone(), + amm_pair: config.amm_pair.to_string(), + admin_auth: config.admin_auth, }; return to_binary(&response); } else { @@ -529,23 +536,25 @@ pub fn update_authenticator( } pub fn get_staking_stake_lp_token_info(deps: Deps, staker: Addr) -> StdResult { - let staker_info = stakers_r(deps.storage).load(&staker.as_bytes())?; + let staker_amount = stakers_r(deps.storage).may_load(&staker.as_bytes())?.map_or_else(|| Uint128::zero(), |v| v.amount); + let response_msg = QueryResponse::StakerLpTokenInfo { - staked_lp_token: staker_info.amount, - total_staked_lp_token: total_staked_r(deps.storage).load()?, + staked_lp_token: staker_amount, + total_staked_lp_token: total_staked_r(deps.storage).may_load()?.map_or_else(|| Uint128::zero(), |v| v), }; to_binary(&response_msg) } pub fn get_claim_reward_for_user(deps: Deps, staker: Addr, time: Uint128) -> StdResult { - // load stakers + // load stakers let mut result_list: Vec = Vec::new(); let staker_info = stakers_r(deps.storage).load(staker.as_bytes())?; - let reward_token_list: Vec = get_actual_reward_tokens(deps.storage, time)?; + let reward_token_list: Vec = get_reward_tokens_info(deps.storage)?; let percentage = calculate_staker_shares(deps.storage, staker_info.amount)?; for reward_token in reward_token_list.iter() { if reward_token.valid_to < staker_info.last_time_updated { let reward: Uint128; + println!("time {} - valid_to {}", time.to_string(), reward_token.valid_to.to_string()); if time > reward_token.valid_to { // calculate reward amount for each reward token reward = calculate_incremental_staking_reward( @@ -568,6 +577,24 @@ pub fn get_claim_reward_for_user(deps: Deps, staker: Addr, time: Uint128) -> Std &staker, &reward_token.reward_token, )?; + + result_list.push(ClaimableInfo { + token_address: reward_token.reward_token.address.to_owned(), + amount: claimable_reward.amount + reward, + }); + } + else{ + let reward = calculate_incremental_staking_reward( + percentage, + staker_info.last_time_updated, + time, + reward_token.daily_reward_amount, + )?; + let claimable_reward = find_claimable_reward_for_staker_by_reward_token( + deps.storage, + &staker, + &reward_token.reward_token, + )?; result_list.push(ClaimableInfo { token_address: reward_token.reward_token.address.to_owned(), amount: claimable_reward.amount + reward, @@ -587,6 +614,7 @@ pub fn proxy_unstake( amount: Uint128, ) -> StdResult { let caller = info.sender.clone(); + println!("caller {}", caller.to_owned()); let current_timestamp = Uint128::new((env.block.time.seconds()) as u128); let mut staker_info = stakers_r(deps.storage).load(for_addr.as_bytes())?; let proxy_staking_key = &generate_proxy_staking_key(&caller, &for_addr); @@ -604,7 +632,7 @@ pub fn proxy_unstake( )); } - staker_info.amount -= staker_info.amount; + staker_info.amount -= amount; staker_info.last_time_updated = current_timestamp; stakers_w(deps.storage).save(for_addr.as_bytes(), &staker_info)?; @@ -619,22 +647,14 @@ pub fn proxy_unstake( // send back amount of lp token to pair contract to send pair token back with burn let config = config_r(deps.storage).load()?; - let msg = snip20::ExecuteMsg::Transfer { + let cosmos_msg = snip20::ExecuteMsg::Transfer { recipient: caller.to_string(), amount: amount, memo: None, padding: None, - }; + }.to_cosmos_msg(&config.lp_token, vec![])?; - let coms_msg = wasm_execute( - config.lp_token.address.to_string(), - config.lp_token.code_hash.clone(), - &msg, - vec![], - )? - .into(); - - messages.push(coms_msg); + messages.push(cosmos_msg); Ok(Response::new().add_messages(messages).add_attributes(vec![ Attribute::new("action", "unstake"), Attribute::new("amount", amount), @@ -679,44 +699,28 @@ pub fn unstake( if let Some(true) = remove_liqudity { // SEND LP Token back to Pair Contract With Remove Liquidity let remove_liquidity_msg = to_binary(&AmmPairInvokeMsg::RemoveLiquidity { - from: Some(caller.clone()), + from: Some(caller.to_string()), })?; - let msg = snip20::ExecuteMsg::Send { + let cosmos_msg = snip20::ExecuteMsg::Send { recipient: config.amm_pair.to_string(), recipient_code_hash: None, amount: amount, msg: Some(remove_liquidity_msg.clone()), memo: None, padding: None, - }; + }.to_cosmos_msg(&config.lp_token, vec![])?; - let coms_msg = wasm_execute( - config.lp_token.address.to_string(), - config.lp_token.code_hash.clone(), - &msg, - vec![], - )? - .into(); - - messages.push(coms_msg); + messages.push(cosmos_msg); } else { // SEND LP Token back to Staker And User Will Manually Remove Liquidity - let msg = snip20::ExecuteMsg::Transfer { + let cosmos_msg = snip20::ExecuteMsg::Transfer { recipient: caller.to_string(), amount: amount, memo: None, padding: None, - }; - - let coms_msg = wasm_execute( - config.lp_token.address.to_string(), - config.lp_token.code_hash.clone(), - &msg, - vec![], - )? - .into(); + }.to_cosmos_msg(&config.lp_token, vec![])?; - messages.push(coms_msg); + messages.push(cosmos_msg); } Ok(Response::new().add_messages(messages).add_attributes(vec![ Attribute::new("action", "unstake"), @@ -733,7 +737,7 @@ pub fn unstake( pub fn create_send_msg( recipient: String, amount: Uint128, - token_link: ContractLink, + token_link: Contract, ) -> StdResult { let msg = CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: token_link.address.to_string(), diff --git a/contracts/staking/src/state.rs b/contracts/staking/src/state.rs index c507dc3..52adffa 100644 --- a/contracts/staking/src/state.rs +++ b/contracts/staking/src/state.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{Addr, Uint128, Storage}; use cosmwasm_storage::{singleton, Singleton, ReadonlySingleton, singleton_read, bucket_read, bucket, ReadonlyBucket, Bucket}; use serde::{Serialize, Deserialize}; -use shadeswap_shared::{core::{TokenType, ContractLink, ViewingKey}, Contract}; - +use shadeswap_shared::{core::{TokenType, ViewingKey}, Contract}; +use shadeswap_shared::stake_contract::RewardTokenInfo as ResponseRewardTokenInfo; pub static CONFIG: &[u8] = b"CONFIG"; pub static STAKERS: &[u8] = b"LIST_STAKERS"; @@ -23,10 +23,28 @@ pub struct Config { pub amm_pair: Addr, pub daily_reward_amount: Uint128, pub reward_token: TokenType, - pub lp_token: ContractLink, - pub authenticator: Option + pub lp_token: Contract, + pub authenticator: Option, + pub admin_auth: Contract +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +pub struct RewardTokenInfo{ + pub reward_token: Contract, + pub daily_reward_amount: Uint128, + pub valid_to: Uint128, } + impl RewardTokenInfo{ + pub fn to_reward_token_response(&mut self)-> ResponseRewardTokenInfo{ + ResponseRewardTokenInfo{ + reward_token: self.reward_token.to_owned(), + daily_reward_amount: self.daily_reward_amount, + valid_to: self.valid_to, + } + } + } + #[derive(Serialize, Deserialize, PartialEq, Debug)] pub struct StakingInfo{ pub amount: Uint128, @@ -39,12 +57,6 @@ pub struct ProxyStakingInfo{ pub amount: Uint128 } -#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] -pub struct RewardTokenInfo{ - pub reward_token: ContractLink, - pub daily_reward_amount: Uint128, - pub valid_to: Uint128, -} #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub struct RewardTokenInfoList{ diff --git a/contracts/staking/src/test.rs b/contracts/staking/src/test.rs index f63cd33..b187110 100644 --- a/contracts/staking/src/test.rs +++ b/contracts/staking/src/test.rs @@ -7,41 +7,37 @@ pub const STAKER_B: &str = "secret1pf42ypa2awg0pxkx8lfyyrjvm28vq0qpffa8qx"; pub const STAKER_C: &str = "secret1nulgwu6es24us9urgyvms7y02txyg0s02msgzw"; pub const SENDER: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy2"; + #[cfg(test)] pub mod tests { + use shadeswap_shared::{utils::{asset::Contract}, staking::{AuthQuery, QueryResponse}}; + + use crate::state::RewardTokenInfo; use super::*; use crate::{ - contract::instantiate, operations::{ calculate_incremental_staking_reward, calculate_staker_shares, claim_rewards, claim_rewards_for_all_stakers, generate_proxy_staking_key, get_total_stakers_count, - proxy_stake, proxy_unstake, set_reward_token, stake, unstake, + proxy_stake, proxy_unstake, set_reward_token, stake, unstake, get_config, }, state::{ claim_reward_info_r, proxy_staker_info_r, reward_token_list_r, reward_token_r, - staker_index_r, staker_index_w, stakers_r, stakers_vk_r, total_staked_r, - ClaimRewardsInfo, Config, RewardTokenInfo, + staker_index_r, stakers_r, total_staked_r, + ClaimRewardsInfo, Config, config_w, total_staked_w, }, test::test_help_lib::{ make_init_config, make_reward_token_contract, mock_custom_env, mock_dependencies, MockQuerier, - }, + }, contract::{execute, auth_queries}, }; use cosmwasm_std::{ - from_binary, from_slice, - testing::{mock_info, MockApi, MockStorage}, - to_binary, to_vec, Addr, AllBalanceResponse, Api, BalanceResponse, BankQuery, BlockInfo, - Coin, Decimal, Empty, Env, MessageInfo, Querier, QuerierResult, QueryRequest, StdError, - StdResult, Storage, Uint128, WasmQuery, - }; - use secret_multi_test::Contract; - use shadeswap_shared::{msg::factory::{ - QueryMsg as FactoryQueryMsg, QueryResponse as FactoryQueryResponse, - }, utils::testing::assert_error}; + testing::{mock_info, MockApi, MockStorage}, Addr, Decimal, MessageInfo, StdError, + StdResult, Uint128, from_binary}; + + use shadeswap_shared::{utils::testing::assert_error}; use shadeswap_shared::{ - c_std::{CustomQuery, Deps, OwnedDeps}, - core::{ContractLink, TokenType}, - msg::staking::{ExecuteMsg, InitMsg, QueryMsg, QueryResponse}, + c_std::{ OwnedDeps}, + core::{TokenType}, }; #[test] @@ -65,6 +61,7 @@ pub mod tests { let mut deps = mock_dependencies(&[]); let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); let _config: Config = make_init_config(deps.as_mut(), env, Uint128::from(100u128))?; + total_staked_w(deps.as_mut().storage).save(&Uint128::new(100u128)).unwrap(); let user_shares = calculate_staker_shares(deps.as_mut().storage, Uint128::from(100u128)).unwrap(); assert_eq!(user_shares, Decimal::one()); @@ -98,6 +95,38 @@ pub mod tests { Ok(()) } + + #[test] + fn assert_get_reward_token_list_success() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + let msg = shadeswap_shared::staking::ExecuteMsg::SetRewardToken { + reward_token: Contract{ + address: Addr::unchecked("REWARD_TOKEN_0".to_string()), + code_hash: "".to_string() }, + daily_reward_amount: Uint128::new(100000000000u128), + valid_to: Uint128::new(30000000000000u128) + }; + let _ = execute(deps.as_mut(), env.clone(), mock_info(CONTRACT_ADDRESS, &[]), msg); + let auth_query = AuthQuery::GetRewardTokens { }; + let raw_response = auth_queries(deps.as_ref(),env, auth_query,Addr::unchecked("sender"))?; + let query_response: QueryResponse = from_binary(&raw_response)?; + match query_response{ + // QueryResponse::ClaimRewards { claimable_rewards: _ } => todo!(), + // QueryResponse::ContractOwner { address: _ } => todo!(), + // QueryResponse::StakerLpTokenInfo { staked_lp_token: _, total_staked_lp_token:_ } => todo!(), + // QueryResponse::RewardTokenBalance { amount: _, reward_token:_ } => todo!(), + // QueryResponse::StakerRewardTokenBalance { reward_amount: _, total_reward_liquidity:_, reward_token:_ } => todo!(), + // QueryResponse::Config { reward_token: _, lp_token:_, daily_reward_amount:_, amm_pair:_, admin_auth:_ } => todo!(), + QueryResponse::RewardTokens { tokens } => { + assert_eq!(tokens.len(), 1); + }, + _ => todo!() + }; + Ok(()) + } + #[test] fn assert_proxy_stake_calculate_user_share_already_return() -> StdResult<()> { let mut deps: OwnedDeps = mock_dependencies(&[]).into(); @@ -213,8 +242,7 @@ pub mod tests { fn assert_unstake_set_claimable_to_zero() -> StdResult<()> { let mut deps = mock_dependencies(&[]); let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); - let env_b = mock_custom_env(CONTRACT_ADDRESS, 1571797854, 1534); - let stake_mock_info = mock_info(LP_TOKEN, &[]); + let stake_mock_info = mock_info(LP_TOKEN, &[]); let unstake_mock_info = mock_info(STAKER_A, &[]); let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; let mut deps_owned: OwnedDeps = mock_dependencies(&[]); @@ -257,11 +285,191 @@ pub mod tests { Ok(()) } + #[test] + fn assert_unstake_higher_than_actual_amount_throws_exception() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let stake_mock_info = mock_info(LP_TOKEN, &[]); + let unstake_mock_info = mock_info(STAKER_A, &[]); + let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + let mut deps_owned: OwnedDeps = mock_dependencies(&[]); + let _stake_a = stake( + deps.as_mut(), + env.clone(), + stake_mock_info.clone(), + Uint128::from(1000u128), + deps_owned.as_mut().api.addr_validate(STAKER_A)?, + )?; + + let _unstake_a = unstake( + deps.as_mut(), + env.clone(), + unstake_mock_info.clone(), + Uint128::from(100000u128), + Some(true), + ); + + match _unstake_a { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::generic_err("Staking Amount is higher then actual staking amount"),err) + } + Ok(()) + } + + #[test] + fn assert_unstake_non_staker_throws_exception() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let unstake_mock_info = mock_info(STAKER_A, &[]); + let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + + let _unstake_a = unstake( + deps.as_mut(), + env.clone(), + unstake_mock_info.clone(), + Uint128::from(100000u128), + Some(true), + ); + + match _unstake_a { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::generic_err("Staking information does not exist"),err) + } + Ok(()) + } + + #[test] + fn assert_set_native_token_throws_exception() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let mut _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + _config.reward_token = TokenType::NativeToken { denom:"uscrt".to_string() }; + config_w(&mut deps.storage).save(&_config)?; + + let error_msg = get_config(deps.as_ref()); + match error_msg { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::generic_err("Invalid reward token"),err) + } + Ok(()) + } + + #[test] + fn assert_proxy_unstake_non_staker_throws_exception() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let unstake_mock_info = mock_info(STAKER_A, &[]); + let stake_mock_info = mock_info(LP_TOKEN, &[]); + let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + let _stake_a = proxy_stake( + deps.as_mut(), + env.clone(), + stake_mock_info.clone(), + Uint128::from(1000u128), + Addr::unchecked(STAKER_A), + Addr::unchecked(STAKER_B), + )?; + let _unstake_proxy_a = proxy_unstake( + deps.as_mut(), + env.clone(), + unstake_mock_info.clone(), + Addr::unchecked(STAKER_C), + Uint128::from(100000u128) + ); + + match _unstake_proxy_a { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::not_found("staking::state::StakingInfo"),err) + } + + let _stake_a = proxy_stake( + deps.as_mut(), + env.clone(), + stake_mock_info.clone(), + Uint128::from(1000u128), + Addr::unchecked(STAKER_A), + Addr::unchecked(STAKER_B), + )?; + let _unstake_proxy_a = proxy_unstake( + deps.as_mut(), + env.clone(), + unstake_mock_info.clone(), + Addr::unchecked(STAKER_B), + Uint128::from(100000u128) + ); + + match _unstake_proxy_a { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::generic_err("Staking Amount is higher then actual staking amount"),err) + } + Ok(()) + } + + #[test] + fn assert_proxy_stake_with_same_staker_address_throws_exception() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let stake_mock_info = mock_info(LP_TOKEN, &[]); + let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + let _stake_a = proxy_stake( + deps.as_mut(), + env.clone(), + stake_mock_info.clone(), + Uint128::from(1000u128), + Addr::unchecked(STAKER_A), + Addr::unchecked(STAKER_A), + ); + match _stake_a { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::generic_err("You cannot proxy stake for yourself."),err) + } + Ok(()) + } + + #[test] + fn assert_proxy_stake_with_wrong_caller_throws_exception() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let stake_mock_info = mock_info(STAKER_B, &[]); + let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + let _stake_a = proxy_stake( + deps.as_mut(), + env.clone(), + stake_mock_info.clone(), + Uint128::from(1000u128), + Addr::unchecked(STAKER_A), + Addr::unchecked(STAKER_C), + ); + match _stake_a { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::generic_err("Token sent is not LP Token."),err) + } + Ok(()) + } + + #[test] + fn assert_stake_with_wrong_caller_throws_exception() -> StdResult<()> { + let mut deps = mock_dependencies(&[]); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); + let stake_mock_info = mock_info(STAKER_B, &[]); + let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; + let _stake_a = stake( + deps.as_mut(), + env.clone(), + stake_mock_info.clone(), + Uint128::from(1000u128), + Addr::unchecked(STAKER_A), + ); + match _stake_a { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::generic_err("Token sent is not LP Token"),err) + } + Ok(()) + } #[test] fn assert_proxy_unstake_set_claimable_to_zero() -> StdResult<()> { let mut deps = mock_dependencies(&[]); - let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); - let env_b = mock_custom_env(CONTRACT_ADDRESS, 1571797854, 1534); + let env = mock_custom_env(CONTRACT_ADDRESS, 1571797523, 1524); let stake_mock_info = mock_info(LP_TOKEN, &[]); let unstake_mock_info = mock_info(PROXY_STAKER_A, &[]); let _config: Config = make_init_config(deps.as_mut(), env.clone(), Uint128::from(100u128))?; @@ -772,9 +980,9 @@ pub mod test_help_lib { }; use serde::{Deserialize, Serialize}; use shadeswap_shared::{ - core::{ContractLink, TokenType}, + core::{TokenType}, snip20::{manager::Balance, QueryAnswer}, - staking::InitMsg, + staking::InitMsg, Contract, admin::ValidateAdminPermissionResponse, }; use crate::{ @@ -790,9 +998,9 @@ pub mod test_help_lib { }); } - pub fn make_reward_token_contract(address: &str, code_hash: &str) -> StdResult { + pub fn make_reward_token_contract(address: &str, code_hash: &str) -> StdResult { let mut deps = mock_dependencies(&[]); - return Ok(ContractLink { + return Ok(Contract { address: deps.as_mut().api.addr_validate(address)?, code_hash: code_hash.to_string(), }); @@ -810,21 +1018,22 @@ pub mod test_help_lib { contract_addr: deps.api.addr_validate(CONTRACT_ADDRESS)?, token_code_hash: CONTRACT_ADDRESS.to_string(), }, - pair_contract: ContractLink { + pair_contract: Contract { address: deps.api.addr_validate(CONTRACT_ADDRESS)?, code_hash: "".to_string().clone(), }, prng_seed: to_binary(&"prng")?, - lp_token: ContractLink { + lp_token: Contract { address: Addr::unchecked("".to_string()), code_hash: "".to_string(), }, authenticator: None, - admin: Addr::unchecked("Sender"), + admin_auth: Contract { address: Addr::unchecked("admin"), code_hash: "".to_string() }, + valid_to: Uint128::new(3747905010000u128) }; assert!(instantiate(deps.branch(), env.clone(), info.clone(), msg).is_ok()); let mut config = config_r(deps.storage).load()?; - config.lp_token = ContractLink { + config.lp_token = Contract { address: deps.api.addr_validate(LP_TOKEN)?, code_hash: "".to_string(), }; @@ -881,6 +1090,11 @@ pub mod test_help_lib { .unwrap(); QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(balance)) } + "admin" => { + QuerierResult::Ok(cosmwasm_std::ContractResult::Ok(to_binary(&ValidateAdminPermissionResponse{ + has_permission: true, + }).unwrap())) + } _factory_contract_address => { let balance = to_binary(&BalanceResponse { amount: Coin { diff --git a/contracts/staking/tests/integration.rs b/contracts/staking/tests/integration.rs index 9b066eb..2459949 100644 --- a/contracts/staking/tests/integration.rs +++ b/contracts/staking/tests/integration.rs @@ -1,180 +1,405 @@ use staking::contract::{execute, instantiate, query}; -use snip20_reference_impl::contract::{execute as snip20_execute, instantiate as snip20_instantiate, query as snip20_query}; -// use lp_token::contract::{execute as lp_execute, instantiate as lp_instantiate, query as lp_query}; - -use secret_multi_test::{App, BankKeeper, Contract, ContractWrapper, Executor}; -use shadeswap_shared::{ - core::{ContractInstantiationInfo, ContractLink}, - c_std::{QueryRequest, WasmQuery}, - utils::testing::TestingExt -}; -use shadeswap_shared::msg::staking::{{InitMsg, QueryResponse}}; -use crate::integration_help_lib::{mk_contract_link, mk_address}; +use secret_multi_test::{App, Contract, ContractWrapper, Executor}; +use shadeswap_shared::msg::staking::{{InitMsg, QueryResponse, ExecuteMsg}}; +use multi_test::help_lib::integration_help_lib::{mk_address}; use cosmwasm_std::{ - testing::{mock_env, MockApi}, - to_binary, Addr, Empty, Binary, ContractInfo, + to_binary, Addr, Empty, }; - +use shadeswap_shared::utils::asset::Contract as AuthContract; pub fn staking_contract_store() -> Box> { let contract = ContractWrapper::new_with_empty(execute, instantiate, query); Box::new(contract) -} - -pub fn snip20_contract_store() -> Box> { - let contract = ContractWrapper::new_with_empty(snip20_execute, snip20_instantiate, snip20_query); - Box::new(contract) -} +} +use shadeswap_shared::Contract as SContract; -// pub fn lp_token_contract_store() -> Box> { -// let contract = ContractWrapper::new_with_empty(lp_execute, lp_instantiate, lp_query); //.with_reply(reply); -// Box::new(contract) -// } -pub const CONTRACT_ADDRESS: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy6"; -pub const TOKEN_A: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy2"; -pub const TOKEN_B: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy4"; -pub const FACTORY: &str = "secret13q9rgw3ez5mf808vm6k0naye090hh0m5fe2436"; -pub const OWNER: &str = "secret1pf42ypa2awg0pxkx8lfyyrjvm28vq0qpffa8qx"; #[cfg(not(target_arch = "wasm32"))] #[test] -pub fn staking_integration_tests() { - use cosmwasm_std::{Uint128, from_binary}; - use shadeswap_shared::staking::QueryMsg; +pub fn staking_integration_tests_without_proxy() { + use multi_test::admin::admin_help::init_admin_contract; + use multi_test::help_lib::integration_help_lib::{roll_blockchain, store_init_auth_contract, mint_deposit_snip20, send_snip20_to_stake, get_current_block_time, convert_to_contract_link}; + use cosmwasm_std::{Uint128, Coin, StdError}; + use multi_test::util_addr::util_addr::{OWNER, OWNER_PUB_KEY, STAKER_A, PUB_KEY_STAKER_A}; + use multi_test::util_addr::util_blockchain::CHAIN_ID; + use shadeswap_shared::staking::{QueryMsg}; use shadeswap_shared::utils::testing::TestingExt; - use shadeswap_shared::{core::{TokenType, TokenPair}, snip20::{InstantiateMsg, InitConfig}, stake_contract::StakingContractInit}; - use crate::integration_help_lib::{generate_snip20_contract, mint_snip20}; + use shadeswap_shared::{core::{TokenType}}; + use multi_test::help_lib::integration_help_lib::{generate_snip20_contract}; + + use crate::staking_help_query::query_claimable_reward; + + let staker_a_addr = Addr::unchecked(STAKER_A.to_owned()); + let owner_addr = Addr::unchecked(OWNER); + let mut router = App::default(); + + router.init_modules(|router, _, storage| { + router + .bank + .init_balance(storage, &owner_addr.clone(), vec![Coin{denom: "uscrt".into(), amount: Uint128::new(100000000000000u128)}]) + .unwrap(); + }); - let mut router = App::default(); - let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); - let snip20_contract_code_id = router.store_code(snip20_contract_store()); - let staking_contract = router.store_code(staking_contract_store()); + router.block_info().chain_id = CHAIN_ID.to_string(); + roll_blockchain(&mut router, 1).unwrap(); + let admin_contract = init_admin_contract(&mut router, &owner_addr).unwrap(); + let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); + let staking_contract_info = router.store_code(staking_contract_store()); + let auth_contract = store_init_auth_contract(&mut router).unwrap(); let lp_token_contract = generate_snip20_contract(&mut router, "LPT".to_string(),"LPT".to_string(),18).unwrap(); let init_msg = InitMsg { - daily_reward_amount: Uint128::new(50u128), + daily_reward_amount: Uint128::new(30000u128), reward_token: TokenType::CustomToken { contract_addr:reward_contract.address.to_owned(), token_code_hash: reward_contract.code_hash.to_owned() }, - pair_contract: ContractLink { address: Addr::unchecked("AMMPAIR"), code_hash: "".to_string() }, + pair_contract: SContract { address: Addr::unchecked("AMMPAIR"), code_hash: "".to_string() }, prng_seed: to_binary(&"password").unwrap(), - lp_token: ContractLink { address:lp_token_contract.address.to_owned(), code_hash: lp_token_contract.code_hash.to_owned() }, - authenticator: None, - admin: Addr::unchecked(OWNER), + lp_token: SContract { address:lp_token_contract.address.to_owned(), code_hash: lp_token_contract.code_hash.to_owned() }, + authenticator: Some(AuthContract{ + address: auth_contract.address.to_owned(), + code_hash: auth_contract.code_hash.to_owned() + }), + admin_auth: convert_to_contract_link(&admin_contract), + valid_to: Uint128::new(3747905010000u128) }; - let mocked_contract_addr = router + let staking_contract = router .instantiate_contract( - staking_contract, + staking_contract_info, mk_address(&OWNER).to_owned(), &init_msg, &[], "staking", - None, + Some(OWNER.to_string()), ).unwrap(); - - // mint lp token for test - mint_snip20(&mut router, Uint128::new(1000),Addr::unchecked(OWNER),lp_token_contract.to_owned()).unwrap(); - - println!("{}", mocked_contract_addr.address.to_string()); - let query: QueryResponse = router.query_test(mocked_contract_addr,to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + + roll_blockchain(&mut router, 2).unwrap(); + + // Assert Staking Config + let query: QueryResponse = router.query_test(staking_contract.to_owned(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); match query { - QueryResponse::Config { reward_token, lp_token, daily_reward_amount, amm_pair } => { - assert_eq!(daily_reward_amount, Uint128::new(50u128)); + QueryResponse::Config { reward_token, lp_token, daily_reward_amount, amm_pair: _, admin_auth: _ } => { + assert_eq!(daily_reward_amount, Uint128::new(30000u128)); + assert_eq!(reward_token.address.to_string(), reward_contract.address.to_string()); assert_eq!(lp_token.address.to_owned(), lp_token_contract.address.to_owned()); }, _ => panic!("Query Responsedoes not match") } -} + roll_blockchain(&mut router, 1).unwrap(); + + // Assert Error StakingInfo not found + let permit_query = query_claimable_reward(&router, + &staking_contract,OWNER_PUB_KEY, OWNER_PUB_KEY, get_current_block_time(&router)); + match permit_query { + Ok(_) => todo!(), + Err(err) =>assert_eq!(StdError::GenericErr{ msg: "Querier contract error: staking::state::StakingInfo not found".to_string() }, err), + } + + // MINT & DEPOSIT LP TOKEN & REWARD TOKEN + mint_deposit_snip20(&mut router,&lp_token_contract,&owner_addr,Uint128::new(100000000), &owner_addr); + mint_deposit_snip20(&mut router,&reward_contract,&staking_contract.address,Uint128::new(100000000), &owner_addr); + // STAKE LP TOKEN + send_snip20_to_stake(&mut router, + &lp_token_contract, + &staking_contract, + Uint128::new(1000u128), + &owner_addr, + &owner_addr).unwrap(); + + // Assert zero for the same time + let permit_query = query_claimable_reward(&router, + &staking_contract,OWNER_PUB_KEY, OWNER_PUB_KEY, get_current_block_time(&router)).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),1); + assert_eq!(claimable_rewards[0].amount, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } + + roll_blockchain(&mut router, 1000).unwrap(); + let msg = ExecuteMsg::ClaimRewards { }; + router.execute_contract( + owner_addr.to_owned(), + &staking_contract.clone(), + &msg, + &[], // + ) + .unwrap(); + + // Assert claim_rewards to set claimable_reward to zero (already paid) + let permit_query = query_claimable_reward(&router, + &staking_contract,OWNER_PUB_KEY, OWNER_PUB_KEY, get_current_block_time(&router) ).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),1); + assert_eq!(claimable_rewards[0].amount, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } + + roll_blockchain(&mut router, 1).unwrap(); + // set 2 reward token + let reward_contract_b = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); + let set_reward_msg = ExecuteMsg::SetRewardToken { + reward_token: SContract { + address:reward_contract_b.address.to_owned(), + code_hash: reward_contract_b.code_hash.to_owned() + }, + daily_reward_amount: Uint128::new(3000u128), + valid_to: Uint128::new(3747905010000u128) + }; + + let _ = router.execute_contract(owner_addr.to_owned(), &staking_contract, &set_reward_msg, &[]).unwrap(); + mint_deposit_snip20(&mut router, &reward_contract_b, &staking_contract.address, Uint128::new(100000), &owner_addr); + roll_blockchain(&mut router, 500).unwrap(); + let msg = ExecuteMsg::ClaimRewards { }; + router.execute_contract( + Addr::unchecked(OWNER.to_owned()), + &staking_contract.clone(), + &msg, + &[], // + ) + .unwrap(); -pub mod integration_help_lib{ - use cosmwasm_std::{Addr, ContractInfo, StdResult, Uint128}; - use secret_multi_test::{App, Executor}; - use shadeswap_shared::{msg::amm_pair::InitMsg, core::TokenPair, core::{TokenType, ContractLink}, snip20::{InitConfig, InstantiateMsg}}; - use crate::{{TOKEN_A, TOKEN_B}, OWNER, snip20_contract_store}; - use cosmwasm_std::to_binary; + // Assert 2 Reward Token + Claimable Reward + let permit_query = query_claimable_reward(&router, &staking_contract,OWNER_PUB_KEY, OWNER_PUB_KEY, get_current_block_time(&router) + Uint128::new(1000u128) ).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),2); + assert_eq!(claimable_rewards[0].amount, Uint128::new(347u128)); + assert_eq!(claimable_rewards[1].amount, Uint128::new(34u128)); + }, + _ => panic!("Query Responsedoes not match") + } - pub fn mk_token_pair() -> TokenPair{ - return TokenPair( - TokenType::CustomToken { contract_addr: mk_address(TOKEN_A), token_code_hash: "".to_string() }, - TokenType::CustomToken { contract_addr: mk_address(TOKEN_B), token_code_hash: "".to_string() } - ); - } + // Assert New Staker A + mint_deposit_snip20(&mut router,&lp_token_contract, &staker_a_addr, Uint128::new(10000u128), &owner_addr); + let _ = send_snip20_to_stake(&mut router, &lp_token_contract, &staking_contract, Uint128::new(1000u128), &staker_a_addr, &staker_a_addr).unwrap(); + // Query Balance + let permit_query = query_claimable_reward( + &router, + &staking_contract, + PUB_KEY_STAKER_A, + PUB_KEY_STAKER_A, + get_current_block_time(&router) + Uint128::new(1000u128) + ).unwrap(); - pub fn mk_address(address: &str) -> Addr{ - return Addr::unchecked(address.to_string()) - } + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),2); + assert_eq!(claimable_rewards[0].amount, Uint128::new(173u128)); + assert_eq!(claimable_rewards[1].amount, Uint128::new(17u128)); + }, + _ => panic!("Query Responsedoes not match") + } + + // Assert Unstake amount < total amount + roll_blockchain(&mut router, 1000).unwrap(); + let unstake_msg = ExecuteMsg::Unstake { amount: Uint128::new(500u128), remove_liqudity: Some(false)}; + let _ = router.execute_contract(owner_addr.to_owned(), &staking_contract, &unstake_msg, &[]).unwrap(); + + let permit_query = query_claimable_reward(&router, + &staking_contract,OWNER_PUB_KEY, OWNER_PUB_KEY, get_current_block_time(&router) + Uint128::new(1000)).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),2); + assert_eq!(claimable_rewards[0].amount, Uint128::new(86u128)); + assert_eq!(claimable_rewards[1].amount, Uint128::new(8u128)); + }, + _ => panic!("Query Responsedoes not match") + } + // Assert Unstake the whole amount + roll_blockchain(&mut router, 1).unwrap(); + let _ = router.execute_contract(owner_addr.to_owned(), &staking_contract, &unstake_msg, &[]).unwrap(); + let permit_query = query_claimable_reward(&router, + &staking_contract,OWNER_PUB_KEY, OWNER_PUB_KEY, get_current_block_time(&router)).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),2); + assert_eq!(claimable_rewards[0].amount, Uint128::zero()); + assert_eq!(claimable_rewards[1].amount, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } +} - pub fn mk_contract_link(address: &str) -> ContractLink{ - return ContractLink{ - address: mk_address(address), - code_hash: "".to_string(), - } - } - pub fn mint_snip20( - router: &mut App, - amount: Uint128, - recipient: Addr, - contract: ContractInfo - ) -> StdResult<()>{ - let msg = snip20_reference_impl::msg::ExecuteMsg::Mint { - recipient: recipient, - amount: amount, - memo: None, - padding: None - }; - - let _ = router.execute_contract( - Addr::unchecked(OWNER.to_owned()), - &contract.clone(), - &msg, +#[cfg(not(target_arch = "wasm32"))] +#[test] +pub fn staking_integration_tests_with_proxy() { + use multi_test::admin::admin_help::init_admin_contract; + use multi_test::help_lib::integration_help_lib::{roll_blockchain, store_init_auth_contract, mint_deposit_snip20, send_snip20_to_proxy_stake, set_viewing_key, convert_to_contract_link, get_current_block_time}; + use cosmwasm_std::{Uint128, Coin, StdError}; + use multi_test::util_addr::util_addr::{OWNER, OWNER_PUB_KEY, STAKER_A, PUB_KEY_STAKER_A}; + use multi_test::util_addr::util_blockchain::CHAIN_ID; + use shadeswap_shared::staking::{QueryMsg}; + use shadeswap_shared::utils::testing::TestingExt; + use shadeswap_shared::{core::{TokenType}}; + use multi_test::help_lib::integration_help_lib::{generate_snip20_contract, snip_20_balance_query}; + use crate::staking_help_query::query_claimable_reward; + + let staker_a_addr = Addr::unchecked(STAKER_A.to_owned()); + let owner_addr = Addr::unchecked(OWNER); + let mut router = App::default(); + + router.init_modules(|router, _, storage| { + router + .bank + .init_balance(storage, &owner_addr.clone(), vec![Coin{denom: "uscrt".into(), amount: Uint128::new(100000000000000u128)}]) + .unwrap(); + }); + + router.block_info().chain_id = CHAIN_ID.to_string(); + roll_blockchain(&mut router, 1).unwrap(); + let admin_contract = init_admin_contract(&mut router, &owner_addr).unwrap(); + roll_blockchain(&mut router, 1).unwrap(); + let reward_contract = generate_snip20_contract(&mut router, "RWD".to_string(),"RWD".to_string(),18).unwrap(); + let staking_contract_info = router.store_code(staking_contract_store()); + let auth_contract = store_init_auth_contract(&mut router).unwrap(); + let lp_token_contract = generate_snip20_contract(&mut router, "LPT".to_string(),"LPT".to_string(),18).unwrap(); + let init_msg = InitMsg { + daily_reward_amount: Uint128::new(30000u128), + reward_token: TokenType::CustomToken { contract_addr:reward_contract.address.to_owned(), token_code_hash: reward_contract.code_hash.to_owned() }, + pair_contract: SContract { address: Addr::unchecked("AMMPAIR"), code_hash: "".to_string() }, + prng_seed: to_binary(&"password").unwrap(), + lp_token: SContract { address:lp_token_contract.address.to_owned(), code_hash: lp_token_contract.code_hash.to_owned() }, + authenticator: Some(AuthContract{ + address: auth_contract.address.to_owned(), + code_hash: auth_contract.code_hash.to_owned() + }), + admin_auth: convert_to_contract_link(&admin_contract), + valid_to: Uint128::new(3747905010000u128) + }; + + let staking_contract = router + .instantiate_contract( + staking_contract_info, + mk_address(&OWNER).to_owned(), + &init_msg, &[], - ) - .unwrap(); + "staking", + Some(OWNER.to_string()), + ).unwrap(); + + roll_blockchain(&mut router, 2).unwrap(); + + // Assert Staking Config + let query: QueryResponse = router.query_test(staking_contract.to_owned(),to_binary(&QueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + QueryResponse::Config { reward_token, lp_token, daily_reward_amount, amm_pair: _, admin_auth: _ } => { + assert_eq!(daily_reward_amount, Uint128::new(30000u128)); + assert_eq!(reward_token.address.to_string(), reward_contract.address.to_string()); + assert_eq!(lp_token.address.to_owned(), lp_token_contract.address.to_owned()); + }, + _ => panic!("Query Responsedoes not match") + } - Ok(()) + roll_blockchain(&mut router, 1).unwrap(); + + // Assert Error StakingInfo not found + let permit_query = query_claimable_reward(&router, + &staking_contract,OWNER_PUB_KEY, OWNER_PUB_KEY, get_current_block_time(&router)); + match permit_query { + Ok(_) => todo!(), + Err(err) => assert_eq!(StdError::GenericErr{ msg: "Querier contract error: staking::state::StakingInfo not found".to_string() }, err), } - // pub fn send_amount_snip20() -> StdResult<()>{ + // MINT & DEPOSIT LP TOKEN & REWARD TOKEN + mint_deposit_snip20(&mut router,&lp_token_contract,&owner_addr,Uint128::new(100000000), &owner_addr); + mint_deposit_snip20(&mut router,&reward_contract,&staking_contract.address,Uint128::new(100000000), &owner_addr); + // STAKE LP TOKEN + send_snip20_to_proxy_stake(&mut router, + &lp_token_contract, + &staking_contract, + Uint128::new(1000u128), + &staker_a_addr, + &owner_addr, + &owner_addr).unwrap(); - // } + // Assert zero for the Staker A + let permit_query = query_claimable_reward(&router, + &staking_contract,PUB_KEY_STAKER_A, PUB_KEY_STAKER_A, get_current_block_time(&router)).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),1); + assert_eq!(claimable_rewards[0].amount, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } + + let permit_query = query_claimable_reward(&router, + &staking_contract,PUB_KEY_STAKER_A, PUB_KEY_STAKER_A, get_current_block_time(&router) + Uint128::new(1000u128)).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),1); + assert_eq!(claimable_rewards[0].amount, Uint128::new(347u128)); + }, + _ => panic!("Query Responsedoes not match") + } + roll_blockchain(&mut router, 200).unwrap(); + let msg = ExecuteMsg::ClaimRewards { }; + router.execute_contract( + staker_a_addr.to_owned(), + &staking_contract.clone(), + &msg, + &[], // + ) + .unwrap(); + // Assert claim_rewards to set claimable_reward to zero (already paid) + let permit_query = query_claimable_reward(&router, + &staking_contract,PUB_KEY_STAKER_A, PUB_KEY_STAKER_A, get_current_block_time(&router)).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),1); + assert_eq!(claimable_rewards[0].amount, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } + + + set_viewing_key(&mut router, &reward_contract, "password", &staker_a_addr).unwrap(); + let balance = snip_20_balance_query(&router, &staker_a_addr,"password",&reward_contract).unwrap(); + assert_eq!(balance, Uint128::new(347u128)); - pub fn generate_snip20_contract( - router: &mut App, - name: String, - symbol: String, - decimal: u8) -> StdResult { - - let snip20_contract_code_id = router.store_code(snip20_contract_store()); - let init_snip20_msg = InstantiateMsg { - name: name.to_string(), - admin: Some(OWNER.to_string()), - symbol: symbol.to_string(), - decimals: decimal, - initial_balances: None, - prng_seed: to_binary("password")?, - config: Some(InitConfig { - public_total_supply: Some(true), - enable_deposit: Some(true), - enable_redeem: Some(false), - enable_mint: Some(true), - enable_burn: Some(true), - enable_transfer: Some(true), - }), - query_auth: None, - }; - let init_snip20_code_id = router - .instantiate_contract( - snip20_contract_code_id, - mk_address(&OWNER).to_owned(), - &init_snip20_msg, - &[], - "token_a", - None, - ).unwrap(); - Ok(init_snip20_code_id) + // Assert Unstake amount < total amount + roll_blockchain(&mut router, 100).unwrap(); + let unstake_msg = ExecuteMsg::ProxyUnstake { for_addr: staker_a_addr.to_string(), amount: Uint128::new(1000u128) }; + let _ = router.execute_contract(owner_addr.to_owned(), &staking_contract, &unstake_msg, &[]).unwrap(); + // ASSERT Claimable reward + let permit_query = query_claimable_reward(&router, + &staking_contract,PUB_KEY_STAKER_A, PUB_KEY_STAKER_A, get_current_block_time(&router)).unwrap(); + match permit_query { + QueryResponse::ClaimRewards { claimable_rewards } => { + assert_eq!(claimable_rewards.len(),1); + assert_eq!(claimable_rewards[0].amount, Uint128::zero()); + }, + _ => panic!("Query Responsedoes not match") + } +} + +pub mod staking_help_query{ + use cosmwasm_std::{StdResult, ContractInfo, to_binary, Uint128}; + use multi_test::{util_addr::util_blockchain::CHAIN_ID, help_lib::integration_help_lib::{ mk_create_permit_data}}; + use secret_multi_test::App; + use shadeswap_shared::staking::{QueryResponse, QueryMsg, AuthQuery}; + use shadeswap_shared::utils::testing::TestingExt; + + pub fn query_claimable_reward(router: &App, staking_contract: &ContractInfo, pub_key: &str, signature: &str, time: Uint128) + -> StdResult { + let permit = mk_create_permit_data(pub_key, signature, CHAIN_ID).unwrap(); + let query: StdResult = router.query_test( + staking_contract.to_owned(), + to_binary(&QueryMsg::WithPermit { + permit:permit, + query: AuthQuery::GetClaimReward { time: time} + })?); + return query } +} + + + -} \ No newline at end of file diff --git a/deployer.info b/deployer.info deleted file mode 100644 index dbf6d03..0000000 --- a/deployer.info +++ /dev/null @@ -1 +0,0 @@ -fjitCoKB08JeXJeXhU8/99vsCXCENNYrCk3nVGWn7dQJR59YlRSq7CrLFxkYcm6ONzyFpen6CObocaHEsCvBVVe+UhVYFGipBgdcvQA==S9OQ \ No newline at end of file diff --git a/dockerfile/dockerfile b/dockerfile/dockerfile index f954a99..5399965 100644 --- a/dockerfile/dockerfile +++ b/dockerfile/dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/scrtlabs/localsecret:v1.4.1-beta.8 +FROM ghcr.io/scrtlabs/localsecret:beta-nested-attributes RUN curl https://sh.rustup.rs -sSf | sh -s -- -y diff --git a/file b/file deleted file mode 100644 index 3498bc6..0000000 --- a/file +++ /dev/null @@ -1,20 +0,0 @@ -{ - "account_number": "0", - "chain_id": "secretdev-1", - "fee": { - "amount": [{ - "amount": "0", - "denom": "uscrt" - }], - "gas": "1" - }, - "memo": "", - "msgs": [{ - "type": "signature_proof", - "value": { - "data": "e30=", - "key": "0" - } - }], - "sequence": "0" -} diff --git a/makefile b/makefile index 48cf232..ae5e835 100644 --- a/makefile +++ b/makefile @@ -64,12 +64,14 @@ format: # Downloads the docker server server-download: - docker pull securesecrets/sn-testnet:v0.2 + docker pull cryptobrokersglobal/localsecret:beta-nested-attributes # Starts the docker server / private testnet server-start: - docker run -it --rm -p 9091:9091 -p 26657:26657 -p 1317:1317 -p 5000:5000 -v $$(pwd):/root/code --name shade-testnet cryptobrokersglobal/localsecret:v1.4.0-beta.14 + docker run -it --rm -p 9091:9091 -p 26657:26657 -p 1317:1317 -p 5000:5000 -v $$(pwd):/root/code --name shade-testnet cryptobrokersglobal/localsecret:beta-nested-attributes +server-start-background: + docker run -p 9091:9091 -p 26657:26657 -d -p 1317:1317 -p 5000:5000 -v $$(pwd):/root/code --name shade-testnet cryptobrokersglobal/localsecret:beta-nested-attributes # Connects to the docker server server-connect: docker exec -it shade-testnet /bin/bash diff --git a/misc/admin.wasm b/misc/admin.wasm new file mode 100644 index 0000000..0e3e990 Binary files /dev/null and b/misc/admin.wasm differ diff --git a/misc/admin.wasm.gz b/misc/admin.wasm.gz new file mode 100644 index 0000000..8a45eb8 Binary files /dev/null and b/misc/admin.wasm.gz differ diff --git a/packages/cosmwasm_math_compat/.gitignore b/packages/cosmwasm_math_compat/.gitignore deleted file mode 100644 index 96ef6c0..0000000 --- a/packages/cosmwasm_math_compat/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/packages/cosmwasm_math_compat/Cargo.toml b/packages/cosmwasm_math_compat/Cargo.toml deleted file mode 100644 index 485f434..0000000 --- a/packages/cosmwasm_math_compat/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "cosmwasm-math-compat" -authors = ["Chris Ricketts "] -version = "0.1.0" -edition = "2018" - -[lib] -doctest = false - -[dependencies] -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } -schemars = "0.8.1" -serde = { version = "1.0.114", default-features = false, features = [ - "derive", - "alloc" -] } -snafu = { version = "0.6.3" } -uint = "=0.9.3" diff --git a/packages/cosmwasm_math_compat/src/errors.rs b/packages/cosmwasm_math_compat/src/errors.rs deleted file mode 100644 index e90d16b..0000000 --- a/packages/cosmwasm_math_compat/src/errors.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::fmt; - -use snafu::Snafu; - -pub use cosmwasm_std::StdError; - -impl From for StdError { - fn from(err: OverflowError) -> Self { - Self::generic_err(err.to_string()) - } -} - -impl From for StdError { - fn from(err: ConversionOverflowError) -> Self { - Self::generic_err(err.to_string()) - } -} - -impl From for StdError { - fn from(err: DivideByZeroError) -> Self { - Self::generic_err(err.to_string()) - } -} - -#[derive(Debug, PartialEq, Eq)] -pub enum OverflowOperation { - Add, - Sub, - Mul, - Pow, - Shr, - Shl, -} - -impl fmt::Display for OverflowOperation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -#[derive(Snafu, Debug, PartialEq, Eq)] -#[snafu(display( - "Overflow Error: cannot {} with {} and {}", - operation, - operand1, - operand2 -))] -pub struct OverflowError { - pub operation: OverflowOperation, - pub operand1: String, - pub operand2: String, -} - -impl OverflowError { - pub fn new( - operation: OverflowOperation, - operand1: impl ToString, - operand2: impl ToString, - ) -> Self { - Self { - operation, - operand1: operand1.to_string(), - operand2: operand2.to_string(), - } - } -} - -/// The error returned by [`TryFrom`] conversions that overflow, for example -/// when converting from [`Uint256`] to [`Uint128`]. -/// -/// [`TryFrom`]: std::convert::TryFrom -/// [`Uint256`]: crate::Uint256 -/// [`Uint128`]: crate::Uint128 -#[derive(Snafu, Debug, PartialEq, Eq)] -#[snafu(display( - "Conversion Overflow Error: cannot convert {} to {} for {}", - source_type, - target_type, - value -))] -pub struct ConversionOverflowError { - pub source_type: &'static str, - pub target_type: &'static str, - pub value: String, -} - -impl ConversionOverflowError { - pub fn new( - source_type: &'static str, - target_type: &'static str, - value: impl Into, - ) -> Self { - Self { - source_type, - target_type, - value: value.into(), - } - } -} - -#[derive(Snafu, Debug, PartialEq, Eq)] -#[snafu(display("Divide By Zero: cannot devide {} by zero", operand))] -pub struct DivideByZeroError { - pub operand: String, -} - -impl DivideByZeroError { - pub fn new(operand: impl ToString) -> Self { - Self { - operand: operand.to_string(), - } - } -} diff --git a/packages/cosmwasm_math_compat/src/lib.rs b/packages/cosmwasm_math_compat/src/lib.rs deleted file mode 100644 index 1407091..0000000 --- a/packages/cosmwasm_math_compat/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -mod math; - -pub(crate) mod errors; - -mod compat { - impl From for cosmwasm_std::Uint128 { - fn from(x: crate::Uint128) -> Self { - cosmwasm_std::Uint128(x.u128()) - } - } - - impl From for crate::Uint128 { - fn from(x: cosmwasm_std::Uint128) -> Self { - x.0.into() - } - } -} - -pub use crate::math::{ - Decimal, - Decimal256, - Decimal256RangeExceeded, - DecimalRangeExceeded, - Fraction, - Isqrt, - Uint128, - Uint256, - Uint512, - Uint64, -}; diff --git a/packages/cosmwasm_math_compat/src/math/decimal.rs b/packages/cosmwasm_math_compat/src/math/decimal.rs deleted file mode 100644 index cc8ae74..0000000 --- a/packages/cosmwasm_math_compat/src/math/decimal.rs +++ /dev/null @@ -1,1208 +0,0 @@ -use schemars::JsonSchema; -use serde::{de, ser, Deserialize, Deserializer, Serialize}; -use snafu::Snafu; -use std::{ - cmp::Ordering, - convert::TryInto, - fmt::{self, Write}, - ops, - str::FromStr, -}; - -use crate::errors::StdError; - -use super::{Fraction, Isqrt, Uint128, Uint256}; - -/// A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0 -/// -/// The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18) -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] -pub struct Decimal(#[schemars(with = "String")] Uint128); - -#[derive(Snafu, Debug, PartialEq)] -#[snafu(display("Decimal range exceeded"))] -pub struct DecimalRangeExceeded; - -impl Decimal { - const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); - // 1*10**18 - const DECIMAL_FRACTIONAL_SQUARED: Uint128 = - Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000u128); - // (1*10**18)**2 = 1*10**36 - const DECIMAL_PLACES: usize = 18; - // This needs to be an even number. - - pub const MAX: Self = Self(Uint128::MAX); - - /// Create a 1.0 Decimal - pub const fn one() -> Self { - Decimal(Self::DECIMAL_FRACTIONAL) - } - - /// Create a 0.0 Decimal - pub const fn zero() -> Self { - Decimal(Uint128::zero()) - } - - /// Convert x% into Decimal - pub fn percent(x: u64) -> Self { - Decimal(((x as u128) * 10_000_000_000_000_000).into()) - } - - /// Convert permille (x/1000) into Decimal - pub fn permille(x: u64) -> Self { - Decimal(((x as u128) * 1_000_000_000_000_000).into()) - } - - /// Creates a decimal from a number of atomic units and the number - /// of decimal places. The inputs will be converted internally to form - /// a decimal with 18 decimal places. So the input 123 and 2 will create - /// the decimal 1.23. - /// - /// Using 18 decimal places is slightly more efficient than other values - /// as no internal conversion is necessary. - /// - /// ## Examples - /// - /// ``` - /// # use cosmwasm_math::{Decimal, Uint128}; - /// let a = Decimal::from_atomics(Uint128::new(1234), 3).unwrap(); - /// assert_eq!(a.to_string(), "1.234"); - /// - /// let a = Decimal::from_atomics(1234u128, 0).unwrap(); - /// assert_eq!(a.to_string(), "1234"); - /// - /// let a = Decimal::from_atomics(1u64, 18).unwrap(); - /// assert_eq!(a.to_string(), "0.000000000000000001"); - /// ``` - pub fn from_atomics( - atomics: impl Into, - decimal_places: u32, - ) -> Result { - let atomics = atomics.into(); - const TEN: Uint128 = Uint128::new(10); - Ok(match decimal_places.cmp(&(Self::DECIMAL_PLACES as u32)) { - Ordering::Less => { - let digits = (Self::DECIMAL_PLACES as u32) - decimal_places; // No overflow because decimal_places < DECIMAL_PLACES - let factor = TEN.checked_pow(digits).unwrap(); // Safe because digits <= 17 - Self( - atomics - .checked_mul(factor) - .map_err(|_| DecimalRangeExceeded)?, - ) - } - Ordering::Equal => Self(atomics), - Ordering::Greater => { - let digits = decimal_places - (Self::DECIMAL_PLACES as u32); // No overflow because decimal_places > DECIMAL_PLACES - if let Ok(factor) = TEN.checked_pow(digits) { - Self(atomics.checked_div(factor).unwrap()) // Safe because factor cannot be zero - } else { - // In this case `factor` exceeds the Uint128 range. - // Any Uint128 `x` divided by `factor` with `factor > Uint128::MAX` is 0. - // Try e.g. Python3: `(2**128-1) // 2**128` - Self(Uint128::zero()) - } - } - }) - } - - /// Returns the ratio (numerator / denominator) as a Decimal - pub fn from_ratio(numerator: impl Into, denominator: impl Into) -> Self { - let numerator: Uint128 = numerator.into(); - let denominator: Uint128 = denominator.into(); - if denominator.is_zero() { - panic!("Denominator must not be zero"); - } - - Decimal( - // numerator * DECIMAL_FRACTIONAL / denominator - numerator.multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator), - ) - } - - pub fn is_zero(&self) -> bool { - self.0.is_zero() - } - - /// A decimal is an integer of atomic units plus a number that specifies the - /// position of the decimal dot. So any decimal can be expressed as two numbers. - /// - /// ## Examples - /// - /// ``` - /// # use cosmwasm_math::{Decimal, Uint128}; - /// # use std::str::FromStr; - /// // Value with whole and fractional part - /// let a = Decimal::from_str("1.234").unwrap(); - /// assert_eq!(a.decimal_places(), 18); - /// assert_eq!(a.atomics(), Uint128::new(1234000000000000000)); - /// - /// // Smallest possible value - /// let b = Decimal::from_str("0.000000000000000001").unwrap(); - /// assert_eq!(b.decimal_places(), 18); - /// assert_eq!(b.atomics(), Uint128::new(1)); - /// ``` - pub fn atomics(&self) -> Uint128 { - self.0 - } - - /// The number of decimal places. This is a constant value for now - /// but this could potentially change as the type evolves. - /// - /// See also [`Decimal::atomics()`]. - pub fn decimal_places(&self) -> u32 { - Self::DECIMAL_PLACES as u32 - } - - /// Returns the approximate square root as a Decimal. - /// - /// This should not overflow or panic. - pub fn sqrt(&self) -> Self { - // Algorithm described in https://hackmd.io/@webmaster128/SJThlukj_ - // We start with the highest precision possible and lower it until - // there's no overflow. - // - // TODO: This could be made more efficient once log10 is in: - // https://github.com/rust-lang/rust/issues/70887 - // The max precision is something like `9 - log10(self.0) / 2`. - (0..=Self::DECIMAL_PLACES / 2) - .rev() - .find_map(|i| self.sqrt_with_precision(i)) - // The last step (i = 0) is guaranteed to succeed because `isqrt(u128::MAX) * 10^9` does not overflow - .unwrap() - } - - /// Lower precision means more aggressive rounding, but less risk of overflow. - /// Precision *must* be a number between 0 and 9 (inclusive). - /// - /// Returns `None` if the internal multiplication overflows. - fn sqrt_with_precision(&self, precision: usize) -> Option { - let precision = precision as u32; - - let inner_mul = 100u128.pow(precision); - self.0.checked_mul(inner_mul.into()).ok().map(|inner| { - let outer_mul = 10u128.pow(Self::DECIMAL_PLACES as u32 / 2 - precision); - Decimal(inner.isqrt().checked_mul(Uint128::from(outer_mul)).unwrap()) - }) - } -} - -impl Fraction for Decimal { - #[inline] - fn numerator(&self) -> Uint128 { - self.0 - } - - #[inline] - fn denominator(&self) -> Uint128 { - Self::DECIMAL_FRACTIONAL - } - - /// Returns the multiplicative inverse `1/d` for decimal `d`. - /// - /// If `d` is zero, none is returned. - fn inv(&self) -> Option { - if self.is_zero() { - None - } else { - // Let self be p/q with p = self.0 and q = DECIMAL_FRACTIONAL. - // Now we calculate the inverse a/b = q/p such that b = DECIMAL_FRACTIONAL. Then - // `a = DECIMAL_FRACTIONAL*DECIMAL_FRACTIONAL / self.0`. - Some(Decimal(Self::DECIMAL_FRACTIONAL_SQUARED / self.0)) - } - } -} - -impl FromStr for Decimal { - type Err = StdError; - - /// Converts the decimal string to a Decimal - /// Possible inputs: "1.23", "1", "000012", "1.123000000" - /// Disallowed: "", ".23" - /// - /// This never performs any kind of rounding. - /// More than DECIMAL_PLACES fractional digits, even zeros, result in an error. - fn from_str(input: &str) -> Result { - let mut parts_iter = input.split('.'); - - let whole_part = parts_iter.next().unwrap(); // split always returns at least one element - let whole = whole_part - .parse::() - .map_err(|_| StdError::generic_err("Error parsing whole"))?; - let mut atomics = whole - .checked_mul(Self::DECIMAL_FRACTIONAL) - .map_err(|_| StdError::generic_err("Value too big"))?; - - if let Some(fractional_part) = parts_iter.next() { - let fractional = fractional_part - .parse::() - .map_err(|_| StdError::generic_err("Error parsing fractional"))?; - let exp = - (Self::DECIMAL_PLACES.checked_sub(fractional_part.len())).ok_or_else(|| { - StdError::generic_err(format!( - "Cannot parse more than {} fractional digits", - Self::DECIMAL_PLACES - )) - })?; - debug_assert!(exp <= Self::DECIMAL_PLACES); - let fractional_factor = Uint128::from(10u128.pow(exp as u32)); - atomics = atomics - .checked_add( - // The inner multiplication can't overflow because - // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES - fractional.checked_mul(fractional_factor).unwrap(), - ) - .map_err(|_| StdError::generic_err("Value too big"))?; - } - - if parts_iter.next().is_some() { - return Err(StdError::generic_err("Unexpected number of dots")); - } - - Ok(Decimal(atomics)) - } -} - -impl fmt::Display for Decimal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let whole = (self.0) / Self::DECIMAL_FRACTIONAL; - let fractional = (self.0).checked_rem(Self::DECIMAL_FRACTIONAL).unwrap(); - - if fractional.is_zero() { - write!(f, "{}", whole) - } else { - let fractional_string = - format!("{:0>padding$}", fractional, padding = Self::DECIMAL_PLACES); - f.write_str(&whole.to_string())?; - f.write_char('.')?; - f.write_str(fractional_string.trim_end_matches('0'))?; - Ok(()) - } - } -} - -impl ops::Add for Decimal { - type Output = Self; - - fn add(self, other: Self) -> Self { - Decimal(self.0 + other.0) - } -} - -impl ops::Add<&Decimal> for Decimal { - type Output = Self; - - fn add(self, other: &Decimal) -> Self { - Decimal(self.0 + other.0) - } -} - -impl ops::Sub for Decimal { - type Output = Self; - - fn sub(self, other: Self) -> Self { - Decimal(self.0 - other.0) - } -} - -impl ops::Mul for Decimal { - type Output = Self; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn mul(self, other: Self) -> Self { - // Decimals are fractions. We can multiply two decimals a and b - // via - // (a.numerator() * b.numerator()) / (a.denominator() * b.denominator()) - // = (a.numerator() * b.numerator()) / a.denominator() / b.denominator() - - let result_as_uint256 = self.numerator().full_mul(other.numerator()) - / Uint256::from_uint128(Self::DECIMAL_FRACTIONAL); // from_uint128 is a const method and should be "free" - match result_as_uint256.try_into() { - Ok(result) => Self(result), - Err(_) => panic!("attempt to multiply with overflow"), - } - } -} - -/// Both d*u and u*d with d: Decimal and u: Uint128 returns an Uint128. There is no -/// specific reason for this decision other than the initial use cases we have. If you -/// need a Decimal result for the same calculation, use Decimal(d*u) or Decimal(u*d). -impl ops::Mul for Uint128 { - type Output = Self; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn mul(self, rhs: Decimal) -> Self::Output { - // 0*a and b*0 is always 0 - if self.is_zero() || rhs.is_zero() { - return Uint128::zero(); - } - self.multiply_ratio(rhs.0, Decimal::DECIMAL_FRACTIONAL) - } -} - -impl ops::Mul for Decimal { - type Output = Uint128; - - fn mul(self, rhs: Uint128) -> Self::Output { - rhs * self - } -} - -impl ops::Div for Decimal { - type Output = Self; - - fn div(self, rhs: Uint128) -> Self::Output { - Decimal(self.0 / rhs) - } -} - -impl ops::DivAssign for Decimal { - fn div_assign(&mut self, rhs: Uint128) { - self.0 /= rhs; - } -} - -impl std::iter::Sum for Decimal -where - Self: ops::Add, -{ - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), ops::Add::add) - } -} - -/// Serializes as a decimal string -impl Serialize for Decimal { - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -/// Deserializes as a base64 string -impl<'de> Deserialize<'de> for Decimal { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(DecimalVisitor) - } -} - -struct DecimalVisitor; - -impl<'de> de::Visitor<'de> for DecimalVisitor { - type Value = Decimal; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("string-encoded decimal") - } - - fn visit_str(self, v: &str) -> Result - where - E: de::Error, - { - match Decimal::from_str(v) { - Ok(d) => Ok(d), - Err(e) => Err(E::custom(format!("Error parsing decimal '{}': {}", v, e))), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::{from_slice, to_vec}; - - #[test] - fn decimal_one() { - let value = Decimal::one(); - assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL); - } - - #[test] - fn decimal_zero() { - let value = Decimal::zero(); - assert!(value.0.is_zero()); - } - - #[test] - fn decimal_percent() { - let value = Decimal::percent(50); - assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(2u8)); - } - - #[test] - fn decimal_permille() { - let value = Decimal::permille(125); - assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(8u8)); - } - - #[test] - fn decimal_from_atomics_works() { - let one = Decimal::one(); - let two = one + one; - - assert_eq!(Decimal::from_atomics(1u128, 0).unwrap(), one); - assert_eq!(Decimal::from_atomics(10u128, 1).unwrap(), one); - assert_eq!(Decimal::from_atomics(100u128, 2).unwrap(), one); - assert_eq!(Decimal::from_atomics(1000u128, 3).unwrap(), one); - assert_eq!( - Decimal::from_atomics(1000000000000000000u128, 18).unwrap(), - one - ); - assert_eq!( - Decimal::from_atomics(10000000000000000000u128, 19).unwrap(), - one - ); - assert_eq!( - Decimal::from_atomics(100000000000000000000u128, 20).unwrap(), - one - ); - - assert_eq!(Decimal::from_atomics(2u128, 0).unwrap(), two); - assert_eq!(Decimal::from_atomics(20u128, 1).unwrap(), two); - assert_eq!(Decimal::from_atomics(200u128, 2).unwrap(), two); - assert_eq!(Decimal::from_atomics(2000u128, 3).unwrap(), two); - assert_eq!( - Decimal::from_atomics(2000000000000000000u128, 18).unwrap(), - two - ); - assert_eq!( - Decimal::from_atomics(20000000000000000000u128, 19).unwrap(), - two - ); - assert_eq!( - Decimal::from_atomics(200000000000000000000u128, 20).unwrap(), - two - ); - - // Cuts decimal digits (20 provided but only 18 can be stored) - assert_eq!( - Decimal::from_atomics(4321u128, 20).unwrap(), - Decimal::from_str("0.000000000000000043").unwrap() - ); - assert_eq!( - Decimal::from_atomics(6789u128, 20).unwrap(), - Decimal::from_str("0.000000000000000067").unwrap() - ); - assert_eq!( - Decimal::from_atomics(u128::MAX, 38).unwrap(), - Decimal::from_str("3.402823669209384634").unwrap() - ); - assert_eq!( - Decimal::from_atomics(u128::MAX, 39).unwrap(), - Decimal::from_str("0.340282366920938463").unwrap() - ); - assert_eq!( - Decimal::from_atomics(u128::MAX, 45).unwrap(), - Decimal::from_str("0.000000340282366920").unwrap() - ); - assert_eq!( - Decimal::from_atomics(u128::MAX, 51).unwrap(), - Decimal::from_str("0.000000000000340282").unwrap() - ); - assert_eq!( - Decimal::from_atomics(u128::MAX, 56).unwrap(), - Decimal::from_str("0.000000000000000003").unwrap() - ); - assert_eq!( - Decimal::from_atomics(u128::MAX, 57).unwrap(), - Decimal::from_str("0.000000000000000000").unwrap() - ); - assert_eq!( - Decimal::from_atomics(u128::MAX, u32::MAX).unwrap(), - Decimal::from_str("0.000000000000000000").unwrap() - ); - - // Can be used with max value - let max = Decimal::MAX; - assert_eq!( - Decimal::from_atomics(max.atomics(), max.decimal_places()).unwrap(), - max - ); - - // Overflow is only possible with digits < 18 - let result = Decimal::from_atomics(u128::MAX, 17); - assert_eq!(result.unwrap_err(), DecimalRangeExceeded); - } - - #[test] - fn decimal_from_ratio_works() { - // 1.0 - assert_eq!(Decimal::from_ratio(1u128, 1u128), Decimal::one()); - assert_eq!(Decimal::from_ratio(53u128, 53u128), Decimal::one()); - assert_eq!(Decimal::from_ratio(125u128, 125u128), Decimal::one()); - - // 1.5 - assert_eq!(Decimal::from_ratio(3u128, 2u128), Decimal::percent(150)); - assert_eq!(Decimal::from_ratio(150u128, 100u128), Decimal::percent(150)); - assert_eq!(Decimal::from_ratio(333u128, 222u128), Decimal::percent(150)); - - // 0.125 - assert_eq!(Decimal::from_ratio(1u64, 8u64), Decimal::permille(125)); - assert_eq!(Decimal::from_ratio(125u64, 1000u64), Decimal::permille(125)); - - // 1/3 (result floored) - assert_eq!( - Decimal::from_ratio(1u64, 3u64), - Decimal(Uint128::from(333_333_333_333_333_333u128)) - ); - - // 2/3 (result floored) - assert_eq!( - Decimal::from_ratio(2u64, 3u64), - Decimal(Uint128::from(666_666_666_666_666_666u128)) - ); - - // large inputs - assert_eq!(Decimal::from_ratio(0u128, u128::MAX), Decimal::zero()); - assert_eq!(Decimal::from_ratio(u128::MAX, u128::MAX), Decimal::one()); - // 340282366920938463463 is the largest integer <= Decimal::MAX - assert_eq!( - Decimal::from_ratio(340282366920938463463u128, 1u128), - Decimal::from_str("340282366920938463463").unwrap() - ); - } - - #[test] - #[should_panic(expected = "Denominator must not be zero")] - fn decimal_from_ratio_panics_for_zero_denominator() { - Decimal::from_ratio(1u128, 0u128); - } - - #[test] - fn decimal_implements_fraction() { - let fraction = Decimal::from_str("1234.567").unwrap(); - assert_eq!( - fraction.numerator(), - Uint128::from(1_234_567_000_000_000_000_000u128) - ); - assert_eq!( - fraction.denominator(), - Uint128::from(1_000_000_000_000_000_000u128) - ); - } - - #[test] - fn decimal_from_str_works() { - // Integers - assert_eq!(Decimal::from_str("0").unwrap(), Decimal::percent(0)); - assert_eq!(Decimal::from_str("1").unwrap(), Decimal::percent(100)); - assert_eq!(Decimal::from_str("5").unwrap(), Decimal::percent(500)); - assert_eq!(Decimal::from_str("42").unwrap(), Decimal::percent(4200)); - assert_eq!(Decimal::from_str("000").unwrap(), Decimal::percent(0)); - assert_eq!(Decimal::from_str("001").unwrap(), Decimal::percent(100)); - assert_eq!(Decimal::from_str("005").unwrap(), Decimal::percent(500)); - assert_eq!(Decimal::from_str("0042").unwrap(), Decimal::percent(4200)); - - // Decimals - assert_eq!(Decimal::from_str("1.0").unwrap(), Decimal::percent(100)); - assert_eq!(Decimal::from_str("1.5").unwrap(), Decimal::percent(150)); - assert_eq!(Decimal::from_str("0.5").unwrap(), Decimal::percent(50)); - assert_eq!(Decimal::from_str("0.123").unwrap(), Decimal::permille(123)); - - assert_eq!(Decimal::from_str("40.00").unwrap(), Decimal::percent(4000)); - assert_eq!(Decimal::from_str("04.00").unwrap(), Decimal::percent(400)); - assert_eq!(Decimal::from_str("00.40").unwrap(), Decimal::percent(40)); - assert_eq!(Decimal::from_str("00.04").unwrap(), Decimal::percent(4)); - - // Can handle DECIMAL_PLACES fractional digits - assert_eq!( - Decimal::from_str("7.123456789012345678").unwrap(), - Decimal(Uint128::from(7123456789012345678u128)) - ); - assert_eq!( - Decimal::from_str("7.999999999999999999").unwrap(), - Decimal(Uint128::from(7999999999999999999u128)) - ); - - // Works for documented max value - assert_eq!( - Decimal::from_str("340282366920938463463.374607431768211455").unwrap(), - Decimal::MAX - ); - } - - #[test] - fn decimal_from_str_errors_for_broken_whole_part() { - match Decimal::from_str("").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal::from_str(" ").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal::from_str("-1").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal_from_str_errors_for_broken_fractinal_part() { - match Decimal::from_str("1.").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal::from_str("1. ").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal::from_str("1.e").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal::from_str("1.2e3").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal_from_str_errors_for_more_than_18_fractional_digits() { - match Decimal::from_str("7.1234567890123456789").unwrap_err() { - StdError::GenericErr { msg, .. } => { - assert_eq!(msg, "Cannot parse more than 18 fractional digits",) - } - e => panic!("Unexpected error: {:?}", e), - } - - // No special rules for trailing zeros. This could be changed but adds gas cost for the happy path. - match Decimal::from_str("7.1230000000000000000").unwrap_err() { - StdError::GenericErr { msg, .. } => { - assert_eq!(msg, "Cannot parse more than 18 fractional digits") - } - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal_from_str_errors_for_invalid_number_of_dots() { - match Decimal::from_str("1.2.3").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal::from_str("1.2.3.4").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal_from_str_errors_for_more_than_max_value() { - // Integer - match Decimal::from_str("340282366920938463464").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"), - e => panic!("Unexpected error: {:?}", e), - } - - // Decimal - match Decimal::from_str("340282366920938463464.0").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"), - e => panic!("Unexpected error: {:?}", e), - } - match Decimal::from_str("340282366920938463463.374607431768211456").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal_atomics_works() { - let zero = Decimal::zero(); - let one = Decimal::one(); - let half = Decimal::percent(50); - let two = Decimal::percent(200); - let max = Decimal::MAX; - - assert_eq!(zero.atomics(), Uint128::new(0)); - assert_eq!(one.atomics(), Uint128::new(1000000000000000000)); - assert_eq!(half.atomics(), Uint128::new(500000000000000000)); - assert_eq!(two.atomics(), Uint128::new(2000000000000000000)); - assert_eq!(max.atomics(), Uint128::MAX); - } - - #[test] - fn decimal_decimal_places_works() { - let zero = Decimal::zero(); - let one = Decimal::one(); - let half = Decimal::percent(50); - let two = Decimal::percent(200); - let max = Decimal::MAX; - - assert_eq!(zero.decimal_places(), 18); - assert_eq!(one.decimal_places(), 18); - assert_eq!(half.decimal_places(), 18); - assert_eq!(two.decimal_places(), 18); - assert_eq!(max.decimal_places(), 18); - } - - #[test] - fn decimal_is_zero_works() { - assert!(Decimal::zero().is_zero()); - assert!(Decimal::percent(0).is_zero()); - assert!(Decimal::permille(0).is_zero()); - - assert!(!Decimal::one().is_zero()); - assert!(!Decimal::percent(123).is_zero()); - assert!(!Decimal::permille(1234).is_zero()); - } - - #[test] - fn decimal_inv_works() { - // d = 0 - assert_eq!(Decimal::zero().inv(), None); - - // d == 1 - assert_eq!(Decimal::one().inv(), Some(Decimal::one())); - - // d > 1 exact - assert_eq!( - Decimal::from_str("2").unwrap().inv(), - Some(Decimal::from_str("0.5").unwrap()) - ); - assert_eq!( - Decimal::from_str("20").unwrap().inv(), - Some(Decimal::from_str("0.05").unwrap()) - ); - assert_eq!( - Decimal::from_str("200").unwrap().inv(), - Some(Decimal::from_str("0.005").unwrap()) - ); - assert_eq!( - Decimal::from_str("2000").unwrap().inv(), - Some(Decimal::from_str("0.0005").unwrap()) - ); - - // d > 1 rounded - assert_eq!( - Decimal::from_str("3").unwrap().inv(), - Some(Decimal::from_str("0.333333333333333333").unwrap()) - ); - assert_eq!( - Decimal::from_str("6").unwrap().inv(), - Some(Decimal::from_str("0.166666666666666666").unwrap()) - ); - - // d < 1 exact - assert_eq!( - Decimal::from_str("0.5").unwrap().inv(), - Some(Decimal::from_str("2").unwrap()) - ); - assert_eq!( - Decimal::from_str("0.05").unwrap().inv(), - Some(Decimal::from_str("20").unwrap()) - ); - assert_eq!( - Decimal::from_str("0.005").unwrap().inv(), - Some(Decimal::from_str("200").unwrap()) - ); - assert_eq!( - Decimal::from_str("0.0005").unwrap().inv(), - Some(Decimal::from_str("2000").unwrap()) - ); - } - - #[test] - fn decimal_add() { - let value = Decimal::one() + Decimal::percent(50); // 1.5 - assert_eq!( - value.0, - Decimal::DECIMAL_FRACTIONAL * Uint128::from(3u8) / Uint128::from(2u8) - ); - } - - #[test] - #[should_panic(expected = "attempt to add with overflow")] - fn decimal_add_overflow_panics() { - let _value = Decimal::MAX + Decimal::percent(50); - } - - #[test] - fn decimal_sub() { - let value = Decimal::one() - Decimal::percent(50); // 0.5 - assert_eq!(value.0, Decimal::DECIMAL_FRACTIONAL / Uint128::from(2u8)); - } - - #[test] - #[should_panic(expected = "attempt to subtract with overflow")] - fn decimal_sub_overflow_panics() { - let _value = Decimal::zero() - Decimal::percent(50); - } - - #[test] - fn decimal_implements_mul() { - let one = Decimal::one(); - let two = one + one; - let half = Decimal::percent(50); - - // 1*x and x*1 - assert_eq!(one * Decimal::percent(0), Decimal::percent(0)); - assert_eq!(one * Decimal::percent(1), Decimal::percent(1)); - assert_eq!(one * Decimal::percent(10), Decimal::percent(10)); - assert_eq!(one * Decimal::percent(100), Decimal::percent(100)); - assert_eq!(one * Decimal::percent(1000), Decimal::percent(1000)); - assert_eq!(one * Decimal::MAX, Decimal::MAX); - assert_eq!(Decimal::percent(0) * one, Decimal::percent(0)); - assert_eq!(Decimal::percent(1) * one, Decimal::percent(1)); - assert_eq!(Decimal::percent(10) * one, Decimal::percent(10)); - assert_eq!(Decimal::percent(100) * one, Decimal::percent(100)); - assert_eq!(Decimal::percent(1000) * one, Decimal::percent(1000)); - assert_eq!(Decimal::MAX * one, Decimal::MAX); - - // double - assert_eq!(two * Decimal::percent(0), Decimal::percent(0)); - assert_eq!(two * Decimal::percent(1), Decimal::percent(2)); - assert_eq!(two * Decimal::percent(10), Decimal::percent(20)); - assert_eq!(two * Decimal::percent(100), Decimal::percent(200)); - assert_eq!(two * Decimal::percent(1000), Decimal::percent(2000)); - assert_eq!(Decimal::percent(0) * two, Decimal::percent(0)); - assert_eq!(Decimal::percent(1) * two, Decimal::percent(2)); - assert_eq!(Decimal::percent(10) * two, Decimal::percent(20)); - assert_eq!(Decimal::percent(100) * two, Decimal::percent(200)); - assert_eq!(Decimal::percent(1000) * two, Decimal::percent(2000)); - - // half - assert_eq!(half * Decimal::percent(0), Decimal::percent(0)); - assert_eq!(half * Decimal::percent(1), Decimal::permille(5)); - assert_eq!(half * Decimal::percent(10), Decimal::percent(5)); - assert_eq!(half * Decimal::percent(100), Decimal::percent(50)); - assert_eq!(half * Decimal::percent(1000), Decimal::percent(500)); - assert_eq!(Decimal::percent(0) * half, Decimal::percent(0)); - assert_eq!(Decimal::percent(1) * half, Decimal::permille(5)); - assert_eq!(Decimal::percent(10) * half, Decimal::percent(5)); - assert_eq!(Decimal::percent(100) * half, Decimal::percent(50)); - assert_eq!(Decimal::percent(1000) * half, Decimal::percent(500)); - - fn dec(input: &str) -> Decimal { - Decimal::from_str(input).unwrap() - } - - // Move left - let a = dec("123.127726548762582"); - assert_eq!(a * dec("1"), dec("123.127726548762582")); - assert_eq!(a * dec("10"), dec("1231.27726548762582")); - assert_eq!(a * dec("100"), dec("12312.7726548762582")); - assert_eq!(a * dec("1000"), dec("123127.726548762582")); - assert_eq!(a * dec("1000000"), dec("123127726.548762582")); - assert_eq!(a * dec("1000000000"), dec("123127726548.762582")); - assert_eq!(a * dec("1000000000000"), dec("123127726548762.582")); - assert_eq!(a * dec("1000000000000000"), dec("123127726548762582")); - assert_eq!(a * dec("1000000000000000000"), dec("123127726548762582000")); - assert_eq!(dec("1") * a, dec("123.127726548762582")); - assert_eq!(dec("10") * a, dec("1231.27726548762582")); - assert_eq!(dec("100") * a, dec("12312.7726548762582")); - assert_eq!(dec("1000") * a, dec("123127.726548762582")); - assert_eq!(dec("1000000") * a, dec("123127726.548762582")); - assert_eq!(dec("1000000000") * a, dec("123127726548.762582")); - assert_eq!(dec("1000000000000") * a, dec("123127726548762.582")); - assert_eq!(dec("1000000000000000") * a, dec("123127726548762582")); - assert_eq!(dec("1000000000000000000") * a, dec("123127726548762582000")); - - // Move right - let max = Decimal::MAX; - assert_eq!( - max * dec("1.0"), - dec("340282366920938463463.374607431768211455") - ); - assert_eq!( - max * dec("0.1"), - dec("34028236692093846346.337460743176821145") - ); - assert_eq!( - max * dec("0.01"), - dec("3402823669209384634.633746074317682114") - ); - assert_eq!( - max * dec("0.001"), - dec("340282366920938463.463374607431768211") - ); - assert_eq!( - max * dec("0.000001"), - dec("340282366920938.463463374607431768") - ); - assert_eq!( - max * dec("0.000000001"), - dec("340282366920.938463463374607431") - ); - assert_eq!( - max * dec("0.000000000001"), - dec("340282366.920938463463374607") - ); - assert_eq!( - max * dec("0.000000000000001"), - dec("340282.366920938463463374") - ); - assert_eq!( - max * dec("0.000000000000000001"), - dec("340.282366920938463463") - ); - } - - #[test] - #[should_panic(expected = "attempt to multiply with overflow")] - fn decimal_mul_overflow_panics() { - let _value = Decimal::MAX * Decimal::percent(101); - } - - #[test] - // in this test the Decimal is on the right - fn uint128_decimal_multiply() { - // a*b - let left = Uint128::new(300); - let right = Decimal::one() + Decimal::percent(50); // 1.5 - assert_eq!(left * right, Uint128::new(450)); - - // a*0 - let left = Uint128::new(300); - let right = Decimal::zero(); - assert_eq!(left * right, Uint128::new(0)); - - // 0*a - let left = Uint128::new(0); - let right = Decimal::one() + Decimal::percent(50); // 1.5 - assert_eq!(left * right, Uint128::new(0)); - } - - #[test] - // in this test the Decimal is on the left - fn decimal_uint128_multiply() { - // a*b - let left = Decimal::one() + Decimal::percent(50); // 1.5 - let right = Uint128::new(300); - assert_eq!(left * right, Uint128::new(450)); - - // 0*a - let left = Decimal::zero(); - let right = Uint128::new(300); - assert_eq!(left * right, Uint128::new(0)); - - // a*0 - let left = Decimal::one() + Decimal::percent(50); // 1.5 - let right = Uint128::new(0); - assert_eq!(left * right, Uint128::new(0)); - } - - #[test] - fn decimal_uint128_division() { - // a/b - let left = Decimal::percent(150); // 1.5 - let right = Uint128::new(3); - assert_eq!(left / right, Decimal::percent(50)); - - // 0/a - let left = Decimal::zero(); - let right = Uint128::new(300); - assert_eq!(left / right, Decimal::zero()); - } - - #[test] - #[should_panic(expected = "attempt to divide by zero")] - fn decimal_uint128_divide_by_zero() { - let left = Decimal::percent(150); // 1.5 - let right = Uint128::new(0); - let _result = left / right; - } - - #[test] - fn decimal_uint128_div_assign() { - // a/b - let mut dec = Decimal::percent(150); // 1.5 - dec /= Uint128::new(3); - assert_eq!(dec, Decimal::percent(50)); - - // 0/a - let mut dec = Decimal::zero(); - dec /= Uint128::new(300); - assert_eq!(dec, Decimal::zero()); - } - - #[test] - #[should_panic(expected = "attempt to divide by zero")] - fn decimal_uint128_div_assign_by_zero() { - // a/0 - let mut dec = Decimal::percent(50); - dec /= Uint128::new(0); - } - - #[test] - fn decimal_uint128_sqrt() { - assert_eq!(Decimal::percent(900).sqrt(), Decimal::percent(300)); - - assert!(Decimal::percent(316) < Decimal::percent(1000).sqrt()); - assert!(Decimal::percent(1000).sqrt() < Decimal::percent(317)); - } - - /// sqrt(2) is an irrational number, i.e. all 18 decimal places should be used. - #[test] - fn decimal_uint128_sqrt_is_precise() { - assert_eq!( - Decimal::from_str("2").unwrap().sqrt(), - Decimal::from_str("1.414213562373095048").unwrap() // https://www.wolframalpha.com/input/?i=sqrt%282%29 - ); - } - - #[test] - fn decimal_uint128_sqrt_does_not_overflow() { - assert_eq!( - Decimal::from_str("400").unwrap().sqrt(), - Decimal::from_str("20").unwrap() - ); - } - - #[test] - fn decimal_uint128_sqrt_intermediate_precision_used() { - assert_eq!( - Decimal::from_str("400001").unwrap().sqrt(), - // The last two digits (27) are truncated below due to the algorithm - // we use. Larger numbers will cause less precision. - // https://www.wolframalpha.com/input/?i=sqrt%28400001%29 - Decimal::from_str("632.456322602596803200").unwrap() - ); - } - - #[test] - fn decimal_to_string() { - // Integers - assert_eq!(Decimal::zero().to_string(), "0"); - assert_eq!(Decimal::one().to_string(), "1"); - assert_eq!(Decimal::percent(500).to_string(), "5"); - - // Decimals - assert_eq!(Decimal::percent(125).to_string(), "1.25"); - assert_eq!(Decimal::percent(42638).to_string(), "426.38"); - assert_eq!(Decimal::percent(3).to_string(), "0.03"); - assert_eq!(Decimal::permille(987).to_string(), "0.987"); - - assert_eq!( - Decimal(Uint128::from(1u128)).to_string(), - "0.000000000000000001" - ); - assert_eq!( - Decimal(Uint128::from(10u128)).to_string(), - "0.00000000000000001" - ); - assert_eq!( - Decimal(Uint128::from(100u128)).to_string(), - "0.0000000000000001" - ); - assert_eq!( - Decimal(Uint128::from(1000u128)).to_string(), - "0.000000000000001" - ); - assert_eq!( - Decimal(Uint128::from(10000u128)).to_string(), - "0.00000000000001" - ); - assert_eq!( - Decimal(Uint128::from(100000u128)).to_string(), - "0.0000000000001" - ); - assert_eq!( - Decimal(Uint128::from(1000000u128)).to_string(), - "0.000000000001" - ); - assert_eq!( - Decimal(Uint128::from(10000000u128)).to_string(), - "0.00000000001" - ); - assert_eq!( - Decimal(Uint128::from(100000000u128)).to_string(), - "0.0000000001" - ); - assert_eq!( - Decimal(Uint128::from(1000000000u128)).to_string(), - "0.000000001" - ); - assert_eq!( - Decimal(Uint128::from(10000000000u128)).to_string(), - "0.00000001" - ); - assert_eq!( - Decimal(Uint128::from(100000000000u128)).to_string(), - "0.0000001" - ); - assert_eq!( - Decimal(Uint128::from(10000000000000u128)).to_string(), - "0.00001" - ); - assert_eq!( - Decimal(Uint128::from(100000000000000u128)).to_string(), - "0.0001" - ); - assert_eq!( - Decimal(Uint128::from(1000000000000000u128)).to_string(), - "0.001" - ); - assert_eq!( - Decimal(Uint128::from(10000000000000000u128)).to_string(), - "0.01" - ); - assert_eq!( - Decimal(Uint128::from(100000000000000000u128)).to_string(), - "0.1" - ); - } - - #[test] - fn decimal_iter_sum() { - let items = vec![ - Decimal::zero(), - Decimal(Uint128::from(2u128)), - Decimal(Uint128::from(2u128)), - ]; - assert_eq!(items.iter().sum::(), Decimal(Uint128::from(4u128))); - assert_eq!( - items.into_iter().sum::(), - Decimal(Uint128::from(4u128)) - ); - - let empty: Vec = vec![]; - assert_eq!(Decimal::zero(), empty.iter().sum()); - } - - #[test] - fn decimal_serialize() { - assert_eq!(to_vec(&Decimal::zero()).unwrap(), br#""0""#); - assert_eq!(to_vec(&Decimal::one()).unwrap(), br#""1""#); - assert_eq!(to_vec(&Decimal::percent(8)).unwrap(), br#""0.08""#); - assert_eq!(to_vec(&Decimal::percent(87)).unwrap(), br#""0.87""#); - assert_eq!(to_vec(&Decimal::percent(876)).unwrap(), br#""8.76""#); - assert_eq!(to_vec(&Decimal::percent(8765)).unwrap(), br#""87.65""#); - } - - #[test] - fn decimal_deserialize() { - assert_eq!(from_slice::(br#""0""#).unwrap(), Decimal::zero()); - assert_eq!(from_slice::(br#""1""#).unwrap(), Decimal::one()); - assert_eq!(from_slice::(br#""000""#).unwrap(), Decimal::zero()); - assert_eq!(from_slice::(br#""001""#).unwrap(), Decimal::one()); - - assert_eq!( - from_slice::(br#""0.08""#).unwrap(), - Decimal::percent(8) - ); - assert_eq!( - from_slice::(br#""0.87""#).unwrap(), - Decimal::percent(87) - ); - assert_eq!( - from_slice::(br#""8.76""#).unwrap(), - Decimal::percent(876) - ); - assert_eq!( - from_slice::(br#""87.65""#).unwrap(), - Decimal::percent(8765) - ); - } -} diff --git a/packages/cosmwasm_math_compat/src/math/decimal256.rs b/packages/cosmwasm_math_compat/src/math/decimal256.rs deleted file mode 100644 index 72e640b..0000000 --- a/packages/cosmwasm_math_compat/src/math/decimal256.rs +++ /dev/null @@ -1,1301 +0,0 @@ -use schemars::JsonSchema; -use serde::{de, ser, Deserialize, Deserializer, Serialize}; -use snafu::Snafu; -use std::{ - cmp::Ordering, - convert::TryInto, - fmt::{self, Write}, - ops, - str::FromStr, -}; - -use crate::{errors::StdError, Uint512}; - -use super::{Fraction, Isqrt, Uint256}; - -/// A fixed-point decimal value with 18 fractional digits, i.e. Decimal256(1_000_000_000_000_000_000) == 1.0 -/// -/// The greatest possible value that can be represented is -/// 115792089237316195423570985008687907853269984665640564039457.584007913129639935 -/// (which is (2^256 - 1) / 10^18) -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] -pub struct Decimal256(#[schemars(with = "String")] Uint256); - -#[derive(Snafu, Debug, PartialEq)] -#[snafu(display("Decimal256 range exceeded"))] -pub struct Decimal256RangeExceeded; - -impl Decimal256 { - const DECIMAL_FRACTIONAL: Uint256 = // 1*10**18 - Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 224, 182, - 179, 167, 100, 0, 0, - ]); - const DECIMAL_FRACTIONAL_SQUARED: Uint256 = // 1*10**36 - Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 151, 206, 123, 201, 7, 21, 179, - 75, 159, 16, 0, 0, 0, 0, - ]); - const DECIMAL_PLACES: usize = 18; - pub const MAX: Self = Self(Uint256::MAX); - - /// Create a 1.0 Decimal256 - pub const fn one() -> Self { - Self(Self::DECIMAL_FRACTIONAL) - } - - /// Create a 0.0 Decimal256 - pub const fn zero() -> Self { - Self(Uint256::zero()) - } - - /// Convert x% into Decimal256 - pub fn percent(x: u64) -> Self { - Self(Uint256::from(x) * Uint256::from(10_000_000_000_000_000u128)) - } - - /// Convert permille (x/1000) into Decimal256 - pub fn permille(x: u64) -> Self { - Self(Uint256::from(x) * Uint256::from(1_000_000_000_000_000u128)) - } - - /// Creates a decimal from a number of atomic units and the number - /// of decimal places. The inputs will be converted internally to form - /// a decimal with 18 decimal places. So the input 123 and 2 will create - /// the decimal 1.23. - /// - /// Using 18 decimal places is slightly more efficient than other values - /// as no internal conversion is necessary. - /// - /// ## Examples - /// - /// ``` - /// # use cosmwasm_math::{Decimal256, Uint256}; - /// let a = Decimal256::from_atomics(1234u64, 3).unwrap(); - /// assert_eq!(a.to_string(), "1.234"); - /// - /// let a = Decimal256::from_atomics(1234u128, 0).unwrap(); - /// assert_eq!(a.to_string(), "1234"); - /// - /// let a = Decimal256::from_atomics(1u64, 18).unwrap(); - /// assert_eq!(a.to_string(), "0.000000000000000001"); - /// - /// let a = Decimal256::from_atomics(Uint256::MAX, 18).unwrap(); - /// assert_eq!(a, Decimal256::MAX); - /// ``` - pub fn from_atomics( - atomics: impl Into, - decimal_places: u32, - ) -> Result { - let atomics = atomics.into(); - let ten = Uint256::from(10u64); // TODO: make const - Ok(match decimal_places.cmp(&(Self::DECIMAL_PLACES as u32)) { - Ordering::Less => { - let digits = (Self::DECIMAL_PLACES as u32) - decimal_places; // No overflow because decimal_places < DECIMAL_PLACES - let factor = ten.checked_pow(digits).unwrap(); // Safe because digits <= 17 - Self( - atomics - .checked_mul(factor) - .map_err(|_| Decimal256RangeExceeded)?, - ) - } - Ordering::Equal => Self(atomics), - Ordering::Greater => { - let digits = decimal_places - (Self::DECIMAL_PLACES as u32); // No overflow because decimal_places > DECIMAL_PLACES - if let Ok(factor) = ten.checked_pow(digits) { - Self(atomics.checked_div(factor).unwrap()) // Safe because factor cannot be zero - } else { - // In this case `factor` exceeds the Uint256 range. - // Any Uint256 `x` divided by `factor` with `factor > Uint256::MAX` is 0. - // Try e.g. Python3: `(2**256-1) // 2**256` - Self(Uint256::zero()) - } - } - }) - } - - /// Returns the ratio (numerator / denominator) as a Decimal256 - pub fn from_ratio(numerator: impl Into, denominator: impl Into) -> Self { - let numerator: Uint256 = numerator.into(); - let denominator: Uint256 = denominator.into(); - if denominator.is_zero() { - panic!("Denominator must not be zero"); - } - - Self( - // numerator * DECIMAL_FRACTIONAL / denominator - numerator.multiply_ratio(Self::DECIMAL_FRACTIONAL, denominator), - ) - } - - pub fn is_zero(&self) -> bool { - self.0.is_zero() - } - - /// A decimal is an integer of atomic units plus a number that specifies the - /// position of the decimal dot. So any decimal can be expressed as two numbers. - /// - /// ## Examples - /// - /// ``` - /// # use cosmwasm_math::{Decimal256, Uint256}; - /// # use std::str::FromStr; - /// // Value with whole and fractional part - /// let a = Decimal256::from_str("1.234").unwrap(); - /// assert_eq!(a.decimal_places(), 18); - /// assert_eq!(a.atomics(), Uint256::from(1234000000000000000u128)); - /// - /// // Smallest possible value - /// let b = Decimal256::from_str("0.000000000000000001").unwrap(); - /// assert_eq!(b.decimal_places(), 18); - /// assert_eq!(b.atomics(), Uint256::from(1u128)); - /// ``` - pub fn atomics(&self) -> Uint256 { - self.0 - } - - /// The number of decimal places. This is a constant value for now - /// but this could potentially change as the type evolves. - /// - /// See also [`Decimal256::atomics()`]. - pub fn decimal_places(&self) -> u32 { - Self::DECIMAL_PLACES as u32 - } - - /// Returns the approximate square root as a Decimal256. - /// - /// This should not overflow or panic. - pub fn sqrt(&self) -> Self { - // Algorithm described in https://hackmd.io/@webmaster128/SJThlukj_ - // We start with the highest precision possible and lower it until - // there's no overflow. - // - // TODO: This could be made more efficient once log10 is in: - // https://github.com/rust-lang/rust/issues/70887 - // The max precision is something like `18 - log10(self.0) / 2`. - (0..=Self::DECIMAL_PLACES / 2) - .rev() - .find_map(|i| self.sqrt_with_precision(i)) - // The last step (i = 0) is guaranteed to succeed because `isqrt(Uint256::MAX) * 10^9` does not overflow - .unwrap() - } - - /// Lower precision means more aggressive rounding, but less risk of overflow. - /// Precision *must* be a number between 0 and 9 (inclusive). - /// - /// Returns `None` if the internal multiplication overflows. - fn sqrt_with_precision(&self, precision: usize) -> Option { - let precision = precision as u32; - - let inner_mul = Uint256::from(100u128).pow(precision); - self.0.checked_mul(inner_mul).ok().map(|inner| { - let outer_mul = Uint256::from(10u128).pow(Self::DECIMAL_PLACES as u32 / 2 - precision); - Self(inner.isqrt().checked_mul(outer_mul).unwrap()) - }) - } -} - -impl Fraction for Decimal256 { - #[inline] - fn numerator(&self) -> Uint256 { - self.0 - } - - #[inline] - fn denominator(&self) -> Uint256 { - Self::DECIMAL_FRACTIONAL - } - - /// Returns the multiplicative inverse `1/d` for decimal `d`. - /// - /// If `d` is zero, none is returned. - fn inv(&self) -> Option { - if self.is_zero() { - None - } else { - // Let self be p/q with p = self.0 and q = DECIMAL_FRACTIONAL. - // Now we calculate the inverse a/b = q/p such that b = DECIMAL_FRACTIONAL. Then - // `a = DECIMAL_FRACTIONAL*DECIMAL_FRACTIONAL / self.0`. - Some(Self(Self::DECIMAL_FRACTIONAL_SQUARED / self.0)) - } - } -} - -impl FromStr for Decimal256 { - type Err = StdError; - - /// Converts the decimal string to a Decimal256 - /// Possible inputs: "1.23", "1", "000012", "1.123000000" - /// Disallowed: "", ".23" - /// - /// This never performs any kind of rounding. - /// More than DECIMAL_PLACES fractional digits, even zeros, result in an error. - fn from_str(input: &str) -> Result { - let mut parts_iter = input.split('.'); - - let whole_part = parts_iter.next().unwrap(); // split always returns at least one element - let whole = whole_part - .parse::() - .map_err(|_| StdError::generic_err("Error parsing whole"))?; - let mut atomics = whole - .checked_mul(Self::DECIMAL_FRACTIONAL) - .map_err(|_| StdError::generic_err("Value too big"))?; - - if let Some(fractional_part) = parts_iter.next() { - let fractional = fractional_part - .parse::() - .map_err(|_| StdError::generic_err("Error parsing fractional"))?; - let exp = - (Self::DECIMAL_PLACES.checked_sub(fractional_part.len())).ok_or_else(|| { - StdError::generic_err(format!( - "Cannot parse more than {} fractional digits", - Self::DECIMAL_PLACES - )) - })?; - debug_assert!(exp <= Self::DECIMAL_PLACES); - let fractional_factor = Uint256::from(10u128).pow(exp as u32); - atomics = atomics - .checked_add( - // The inner multiplication can't overflow because - // fractional < 10^DECIMAL_PLACES && fractional_factor <= 10^DECIMAL_PLACES - fractional.checked_mul(fractional_factor).unwrap(), - ) - .map_err(|_| StdError::generic_err("Value too big"))?; - } - - if parts_iter.next().is_some() { - return Err(StdError::generic_err("Unexpected number of dots")); - } - - Ok(Self(atomics)) - } -} - -impl fmt::Display for Decimal256 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let whole = (self.0) / Self::DECIMAL_FRACTIONAL; - let fractional = (self.0).checked_rem(Self::DECIMAL_FRACTIONAL).unwrap(); - - if fractional.is_zero() { - write!(f, "{}", whole) - } else { - let fractional_string = - format!("{:0>padding$}", fractional, padding = Self::DECIMAL_PLACES); - f.write_str(&whole.to_string())?; - f.write_char('.')?; - f.write_str(fractional_string.trim_end_matches('0'))?; - Ok(()) - } - } -} - -impl ops::Add for Decimal256 { - type Output = Self; - - fn add(self, other: Self) -> Self { - Self(self.0 + other.0) - } -} - -impl ops::Add<&Decimal256> for Decimal256 { - type Output = Self; - - fn add(self, other: &Decimal256) -> Self { - Self(self.0 + other.0) - } -} - -impl ops::Sub for Decimal256 { - type Output = Self; - - fn sub(self, other: Self) -> Self { - Self(self.0 - other.0) - } -} - -impl ops::Mul for Decimal256 { - type Output = Self; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn mul(self, other: Self) -> Self { - // Decimals are fractions. We can multiply two decimals a and b - // via - // (a.numerator() * b.numerator()) / (a.denominator() * b.denominator()) - // = (a.numerator() * b.numerator()) / a.denominator() / b.denominator() - - let result_as_uint512 = self.numerator().full_mul(other.numerator()) - / Uint512::from_uint256(Self::DECIMAL_FRACTIONAL); // from_uint256 is a const method and should be "free" - match result_as_uint512.try_into() { - Ok(result) => Self(result), - Err(_) => panic!("attempt to multiply with overflow"), - } - } -} - -/// Both d*u and u*d with d: Decimal256 and u: Uint256 returns an Uint256. There is no -/// specific reason for this decision other than the initial use cases we have. If you -/// need a Decimal256 result for the same calculation, use Decimal256(d*u) or Decimal256(u*d). -impl ops::Mul for Uint256 { - type Output = Self; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn mul(self, rhs: Decimal256) -> Self::Output { - // 0*a and b*0 is always 0 - if self.is_zero() || rhs.is_zero() { - return Uint256::zero(); - } - self.multiply_ratio(rhs.0, Decimal256::DECIMAL_FRACTIONAL) - } -} - -impl ops::Mul for Decimal256 { - type Output = Uint256; - - fn mul(self, rhs: Uint256) -> Self::Output { - rhs * self - } -} - -impl ops::Div for Decimal256 { - type Output = Self; - - fn div(self, rhs: Uint256) -> Self::Output { - Self(self.0 / rhs) - } -} - -impl ops::DivAssign for Decimal256 { - fn div_assign(&mut self, rhs: Uint256) { - self.0 /= rhs; - } -} - -impl std::iter::Sum for Decimal256 -where - Self: ops::Add, -{ - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), ops::Add::add) - } -} - -/// Serializes as a decimal string -impl Serialize for Decimal256 { - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -/// Deserializes as a base64 string -impl<'de> Deserialize<'de> for Decimal256 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Decimal256Visitor) - } -} - -struct Decimal256Visitor; - -impl<'de> de::Visitor<'de> for Decimal256Visitor { - type Value = Decimal256; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("string-encoded decimal") - } - - fn visit_str(self, v: &str) -> Result - where - E: de::Error, - { - match Self::Value::from_str(v) { - Ok(d) => Ok(d), - Err(e) => Err(E::custom(format!("Error parsing decimal '{}': {}", v, e))), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::errors::StdError; - use cosmwasm_std::{from_slice, to_vec}; - - #[test] - fn decimal256_one() { - let value = Decimal256::one(); - assert_eq!(value.0, Decimal256::DECIMAL_FRACTIONAL); - } - - #[test] - fn decimal256_zero() { - let value = Decimal256::zero(); - assert!(value.0.is_zero()); - } - - #[test] - fn decimal256_percent() { - let value = Decimal256::percent(50); - assert_eq!(value.0, Decimal256::DECIMAL_FRACTIONAL / Uint256::from(2u8)); - } - - #[test] - fn decimal256_permille() { - let value = Decimal256::permille(125); - assert_eq!(value.0, Decimal256::DECIMAL_FRACTIONAL / Uint256::from(8u8)); - } - - #[test] - fn decimal256_from_atomics_works() { - let one = Decimal256::one(); - let two = one + one; - - assert_eq!(Decimal256::from_atomics(1u128, 0).unwrap(), one); - assert_eq!(Decimal256::from_atomics(10u128, 1).unwrap(), one); - assert_eq!(Decimal256::from_atomics(100u128, 2).unwrap(), one); - assert_eq!(Decimal256::from_atomics(1000u128, 3).unwrap(), one); - assert_eq!( - Decimal256::from_atomics(1000000000000000000u128, 18).unwrap(), - one - ); - assert_eq!( - Decimal256::from_atomics(10000000000000000000u128, 19).unwrap(), - one - ); - assert_eq!( - Decimal256::from_atomics(100000000000000000000u128, 20).unwrap(), - one - ); - - assert_eq!(Decimal256::from_atomics(2u128, 0).unwrap(), two); - assert_eq!(Decimal256::from_atomics(20u128, 1).unwrap(), two); - assert_eq!(Decimal256::from_atomics(200u128, 2).unwrap(), two); - assert_eq!(Decimal256::from_atomics(2000u128, 3).unwrap(), two); - assert_eq!( - Decimal256::from_atomics(2000000000000000000u128, 18).unwrap(), - two - ); - assert_eq!( - Decimal256::from_atomics(20000000000000000000u128, 19).unwrap(), - two - ); - assert_eq!( - Decimal256::from_atomics(200000000000000000000u128, 20).unwrap(), - two - ); - - // Cuts decimal digits (20 provided but only 18 can be stored) - assert_eq!( - Decimal256::from_atomics(4321u128, 20).unwrap(), - Decimal256::from_str("0.000000000000000043").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(6789u128, 20).unwrap(), - Decimal256::from_str("0.000000000000000067").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(u128::MAX, 38).unwrap(), - Decimal256::from_str("3.402823669209384634").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(u128::MAX, 39).unwrap(), - Decimal256::from_str("0.340282366920938463").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(u128::MAX, 45).unwrap(), - Decimal256::from_str("0.000000340282366920").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(u128::MAX, 51).unwrap(), - Decimal256::from_str("0.000000000000340282").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(u128::MAX, 56).unwrap(), - Decimal256::from_str("0.000000000000000003").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(u128::MAX, 57).unwrap(), - Decimal256::from_str("0.000000000000000000").unwrap() - ); - assert_eq!( - Decimal256::from_atomics(u128::MAX, u32::MAX).unwrap(), - Decimal256::from_str("0.000000000000000000").unwrap() - ); - - // Can be used with max value - let max = Decimal256::MAX; - assert_eq!( - Decimal256::from_atomics(max.atomics(), max.decimal_places()).unwrap(), - max - ); - - // Overflow is only possible with digits < 18 - let result = Decimal256::from_atomics(Uint256::MAX, 17); - assert_eq!(result.unwrap_err(), Decimal256RangeExceeded); - } - - #[test] - fn decimal256_from_ratio_works() { - // 1.0 - assert_eq!(Decimal256::from_ratio(1u128, 1u128), Decimal256::one()); - assert_eq!(Decimal256::from_ratio(53u128, 53u128), Decimal256::one()); - assert_eq!(Decimal256::from_ratio(125u128, 125u128), Decimal256::one()); - - // 1.5 - assert_eq!( - Decimal256::from_ratio(3u128, 2u128), - Decimal256::percent(150) - ); - assert_eq!( - Decimal256::from_ratio(150u128, 100u128), - Decimal256::percent(150) - ); - assert_eq!( - Decimal256::from_ratio(333u128, 222u128), - Decimal256::percent(150) - ); - - // 0.125 - assert_eq!( - Decimal256::from_ratio(1u64, 8u64), - Decimal256::permille(125) - ); - assert_eq!( - Decimal256::from_ratio(125u64, 1000u64), - Decimal256::permille(125) - ); - - // 1/3 (result floored) - assert_eq!( - Decimal256::from_ratio(1u64, 3u64), - Decimal256(Uint256::from_str("333333333333333333").unwrap()) - ); - - // 2/3 (result floored) - assert_eq!( - Decimal256::from_ratio(2u64, 3u64), - Decimal256(Uint256::from_str("666666666666666666").unwrap()) - ); - - // large inputs - assert_eq!(Decimal256::from_ratio(0u128, u128::MAX), Decimal256::zero()); - assert_eq!( - Decimal256::from_ratio(u128::MAX, u128::MAX), - Decimal256::one() - ); - // 340282366920938463463 is the largest integer <= Decimal256::MAX - assert_eq!( - Decimal256::from_ratio(340282366920938463463u128, 1u128), - Decimal256::from_str("340282366920938463463").unwrap() - ); - } - - #[test] - #[should_panic(expected = "Denominator must not be zero")] - fn decimal256_from_ratio_panics_for_zero_denominator() { - Decimal256::from_ratio(1u128, 0u128); - } - - #[test] - fn decimal256_implements_fraction() { - let fraction = Decimal256::from_str("1234.567").unwrap(); - assert_eq!( - fraction.numerator(), - Uint256::from_str("1234567000000000000000").unwrap() - ); - assert_eq!( - fraction.denominator(), - Uint256::from_str("1000000000000000000").unwrap() - ); - } - - #[test] - fn decimal256_from_str_works() { - // Integers - assert_eq!(Decimal256::from_str("0").unwrap(), Decimal256::percent(0)); - assert_eq!(Decimal256::from_str("1").unwrap(), Decimal256::percent(100)); - assert_eq!(Decimal256::from_str("5").unwrap(), Decimal256::percent(500)); - assert_eq!( - Decimal256::from_str("42").unwrap(), - Decimal256::percent(4200) - ); - assert_eq!(Decimal256::from_str("000").unwrap(), Decimal256::percent(0)); - assert_eq!( - Decimal256::from_str("001").unwrap(), - Decimal256::percent(100) - ); - assert_eq!( - Decimal256::from_str("005").unwrap(), - Decimal256::percent(500) - ); - assert_eq!( - Decimal256::from_str("0042").unwrap(), - Decimal256::percent(4200) - ); - - // Decimals - assert_eq!( - Decimal256::from_str("1.0").unwrap(), - Decimal256::percent(100) - ); - assert_eq!( - Decimal256::from_str("1.5").unwrap(), - Decimal256::percent(150) - ); - assert_eq!( - Decimal256::from_str("0.5").unwrap(), - Decimal256::percent(50) - ); - assert_eq!( - Decimal256::from_str("0.123").unwrap(), - Decimal256::permille(123) - ); - - assert_eq!( - Decimal256::from_str("40.00").unwrap(), - Decimal256::percent(4000) - ); - assert_eq!( - Decimal256::from_str("04.00").unwrap(), - Decimal256::percent(400) - ); - assert_eq!( - Decimal256::from_str("00.40").unwrap(), - Decimal256::percent(40) - ); - assert_eq!( - Decimal256::from_str("00.04").unwrap(), - Decimal256::percent(4) - ); - - // Can handle 18 fractional digits - assert_eq!( - Decimal256::from_str("7.123456789012345678").unwrap(), - Decimal256(Uint256::from(7123456789012345678u128)) - ); - assert_eq!( - Decimal256::from_str("7.999999999999999999").unwrap(), - Decimal256(Uint256::from(7999999999999999999u128)) - ); - - // Works for documented max value - assert_eq!( - Decimal256::from_str( - "115792089237316195423570985008687907853269984665640564039457.584007913129639935" - ) - .unwrap(), - Decimal256::MAX - ); - } - - #[test] - fn decimal256_from_str_errors_for_broken_whole_part() { - match Decimal256::from_str("").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal256::from_str(" ").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal256::from_str("-1").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing whole"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal256_from_str_errors_for_broken_fractinal_part() { - match Decimal256::from_str("1.").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal256::from_str("1. ").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal256::from_str("1.e").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal256::from_str("1.2e3").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Error parsing fractional"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal256_from_str_errors_for_more_than_36_fractional_digits() { - match Decimal256::from_str("7.1234567890123456789").unwrap_err() { - StdError::GenericErr { msg, .. } => { - assert_eq!(msg, "Cannot parse more than 18 fractional digits") - } - e => panic!("Unexpected error: {:?}", e), - } - - // No special rules for trailing zeros. This could be changed but adds gas cost for the happy path. - match Decimal256::from_str("7.1230000000000000000").unwrap_err() { - StdError::GenericErr { msg, .. } => { - assert_eq!(msg, "Cannot parse more than 18 fractional digits") - } - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal256_from_str_errors_for_invalid_number_of_dots() { - match Decimal256::from_str("1.2.3").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"), - e => panic!("Unexpected error: {:?}", e), - } - - match Decimal256::from_str("1.2.3.4").unwrap_err() { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Unexpected number of dots"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal256_from_str_errors_for_more_than_max_value() { - // Integer - match Decimal256::from_str("115792089237316195423570985008687907853269984665640564039458") - .unwrap_err() - { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"), - e => panic!("Unexpected error: {:?}", e), - } - - // Decimal - match Decimal256::from_str("115792089237316195423570985008687907853269984665640564039458.0") - .unwrap_err() - { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"), - e => panic!("Unexpected error: {:?}", e), - } - match Decimal256::from_str( - "115792089237316195423570985008687907853269984665640564039457.584007913129639936", - ) - .unwrap_err() - { - StdError::GenericErr { msg, .. } => assert_eq!(msg, "Value too big"), - e => panic!("Unexpected error: {:?}", e), - } - } - - #[test] - fn decimal256_atomics_works() { - let zero = Decimal256::zero(); - let one = Decimal256::one(); - let half = Decimal256::percent(50); - let two = Decimal256::percent(200); - let max = Decimal256::MAX; - - assert_eq!(zero.atomics(), Uint256::from(0u128)); - assert_eq!(one.atomics(), Uint256::from(1000000000000000000u128)); - assert_eq!(half.atomics(), Uint256::from(500000000000000000u128)); - assert_eq!(two.atomics(), Uint256::from(2000000000000000000u128)); - assert_eq!(max.atomics(), Uint256::MAX); - } - - #[test] - fn decimal256_decimal_places_works() { - let zero = Decimal256::zero(); - let one = Decimal256::one(); - let half = Decimal256::percent(50); - let two = Decimal256::percent(200); - let max = Decimal256::MAX; - - assert_eq!(zero.decimal_places(), 18); - assert_eq!(one.decimal_places(), 18); - assert_eq!(half.decimal_places(), 18); - assert_eq!(two.decimal_places(), 18); - assert_eq!(max.decimal_places(), 18); - } - - #[test] - fn decimal256_is_zero_works() { - assert!(Decimal256::zero().is_zero()); - assert!(Decimal256::percent(0).is_zero()); - assert!(Decimal256::permille(0).is_zero()); - - assert!(!Decimal256::one().is_zero()); - assert!(!Decimal256::percent(123).is_zero()); - assert!(!Decimal256::permille(1234).is_zero()); - } - - #[test] - fn decimal256_inv_works() { - // d = 0 - assert_eq!(Decimal256::zero().inv(), None); - - // d == 1 - assert_eq!(Decimal256::one().inv(), Some(Decimal256::one())); - - // d > 1 exact - assert_eq!( - Decimal256::from_str("2").unwrap().inv(), - Some(Decimal256::from_str("0.5").unwrap()) - ); - assert_eq!( - Decimal256::from_str("20").unwrap().inv(), - Some(Decimal256::from_str("0.05").unwrap()) - ); - assert_eq!( - Decimal256::from_str("200").unwrap().inv(), - Some(Decimal256::from_str("0.005").unwrap()) - ); - assert_eq!( - Decimal256::from_str("2000").unwrap().inv(), - Some(Decimal256::from_str("0.0005").unwrap()) - ); - - // d > 1 rounded - assert_eq!( - Decimal256::from_str("3").unwrap().inv(), - Some(Decimal256::from_str("0.333333333333333333").unwrap()) - ); - assert_eq!( - Decimal256::from_str("6").unwrap().inv(), - Some(Decimal256::from_str("0.166666666666666666").unwrap()) - ); - - // d < 1 exact - assert_eq!( - Decimal256::from_str("0.5").unwrap().inv(), - Some(Decimal256::from_str("2").unwrap()) - ); - assert_eq!( - Decimal256::from_str("0.05").unwrap().inv(), - Some(Decimal256::from_str("20").unwrap()) - ); - assert_eq!( - Decimal256::from_str("0.005").unwrap().inv(), - Some(Decimal256::from_str("200").unwrap()) - ); - assert_eq!( - Decimal256::from_str("0.0005").unwrap().inv(), - Some(Decimal256::from_str("2000").unwrap()) - ); - } - - #[test] - fn decimal256_add() { - let value = Decimal256::one() + Decimal256::percent(50); // 1.5 - assert_eq!( - value.0, - Decimal256::DECIMAL_FRACTIONAL * Uint256::from(3u8) / Uint256::from(2u8) - ); - } - - #[test] - #[should_panic(expected = "attempt to add with overflow")] - fn decimal256_add_overflow_panics() { - let _value = Decimal256::MAX + Decimal256::percent(50); - } - - #[test] - fn decimal256_sub() { - let value = Decimal256::one() - Decimal256::percent(50); // 0.5 - assert_eq!(value.0, Decimal256::DECIMAL_FRACTIONAL / Uint256::from(2u8)); - } - - #[test] - #[should_panic(expected = "attempt to subtract with overflow")] - fn decimal256_sub_overflow_panics() { - let _value = Decimal256::zero() - Decimal256::percent(50); - } - - #[test] - fn decimal256_implements_mul() { - let one = Decimal256::one(); - let two = one + one; - let half = Decimal256::percent(50); - - // 1*x and x*1 - assert_eq!(one * Decimal256::percent(0), Decimal256::percent(0)); - assert_eq!(one * Decimal256::percent(1), Decimal256::percent(1)); - assert_eq!(one * Decimal256::percent(10), Decimal256::percent(10)); - assert_eq!(one * Decimal256::percent(100), Decimal256::percent(100)); - assert_eq!(one * Decimal256::percent(1000), Decimal256::percent(1000)); - assert_eq!(one * Decimal256::MAX, Decimal256::MAX); - assert_eq!(Decimal256::percent(0) * one, Decimal256::percent(0)); - assert_eq!(Decimal256::percent(1) * one, Decimal256::percent(1)); - assert_eq!(Decimal256::percent(10) * one, Decimal256::percent(10)); - assert_eq!(Decimal256::percent(100) * one, Decimal256::percent(100)); - assert_eq!(Decimal256::percent(1000) * one, Decimal256::percent(1000)); - assert_eq!(Decimal256::MAX * one, Decimal256::MAX); - - // double - assert_eq!(two * Decimal256::percent(0), Decimal256::percent(0)); - assert_eq!(two * Decimal256::percent(1), Decimal256::percent(2)); - assert_eq!(two * Decimal256::percent(10), Decimal256::percent(20)); - assert_eq!(two * Decimal256::percent(100), Decimal256::percent(200)); - assert_eq!(two * Decimal256::percent(1000), Decimal256::percent(2000)); - assert_eq!(Decimal256::percent(0) * two, Decimal256::percent(0)); - assert_eq!(Decimal256::percent(1) * two, Decimal256::percent(2)); - assert_eq!(Decimal256::percent(10) * two, Decimal256::percent(20)); - assert_eq!(Decimal256::percent(100) * two, Decimal256::percent(200)); - assert_eq!(Decimal256::percent(1000) * two, Decimal256::percent(2000)); - - // half - assert_eq!(half * Decimal256::percent(0), Decimal256::percent(0)); - assert_eq!(half * Decimal256::percent(1), Decimal256::permille(5)); - assert_eq!(half * Decimal256::percent(10), Decimal256::percent(5)); - assert_eq!(half * Decimal256::percent(100), Decimal256::percent(50)); - assert_eq!(half * Decimal256::percent(1000), Decimal256::percent(500)); - assert_eq!(Decimal256::percent(0) * half, Decimal256::percent(0)); - assert_eq!(Decimal256::percent(1) * half, Decimal256::permille(5)); - assert_eq!(Decimal256::percent(10) * half, Decimal256::percent(5)); - assert_eq!(Decimal256::percent(100) * half, Decimal256::percent(50)); - assert_eq!(Decimal256::percent(1000) * half, Decimal256::percent(500)); - - fn dec(input: &str) -> Decimal256 { - Decimal256::from_str(input).unwrap() - } - - // Move left - let a = dec("123.127726548762582"); - assert_eq!(a * dec("1"), dec("123.127726548762582")); - assert_eq!(a * dec("10"), dec("1231.27726548762582")); - assert_eq!(a * dec("100"), dec("12312.7726548762582")); - assert_eq!(a * dec("1000"), dec("123127.726548762582")); - assert_eq!(a * dec("1000000"), dec("123127726.548762582")); - assert_eq!(a * dec("1000000000"), dec("123127726548.762582")); - assert_eq!(a * dec("1000000000000"), dec("123127726548762.582")); - assert_eq!(a * dec("1000000000000000"), dec("123127726548762582")); - assert_eq!(a * dec("1000000000000000000"), dec("123127726548762582000")); - assert_eq!(dec("1") * a, dec("123.127726548762582")); - assert_eq!(dec("10") * a, dec("1231.27726548762582")); - assert_eq!(dec("100") * a, dec("12312.7726548762582")); - assert_eq!(dec("1000") * a, dec("123127.726548762582")); - assert_eq!(dec("1000000") * a, dec("123127726.548762582")); - assert_eq!(dec("1000000000") * a, dec("123127726548.762582")); - assert_eq!(dec("1000000000000") * a, dec("123127726548762.582")); - assert_eq!(dec("1000000000000000") * a, dec("123127726548762582")); - assert_eq!(dec("1000000000000000000") * a, dec("123127726548762582000")); - - // Move right - let max = Decimal256::MAX; - assert_eq!( - max * dec("1.0"), - dec("115792089237316195423570985008687907853269984665640564039457.584007913129639935") - ); - assert_eq!( - max * dec("0.1"), - dec("11579208923731619542357098500868790785326998466564056403945.758400791312963993") - ); - assert_eq!( - max * dec("0.01"), - dec("1157920892373161954235709850086879078532699846656405640394.575840079131296399") - ); - assert_eq!( - max * dec("0.001"), - dec("115792089237316195423570985008687907853269984665640564039.457584007913129639") - ); - assert_eq!( - max * dec("0.000001"), - dec("115792089237316195423570985008687907853269984665640564.039457584007913129") - ); - assert_eq!( - max * dec("0.000000001"), - dec("115792089237316195423570985008687907853269984665640.564039457584007913") - ); - assert_eq!( - max * dec("0.000000000001"), - dec("115792089237316195423570985008687907853269984665.640564039457584007") - ); - assert_eq!( - max * dec("0.000000000000001"), - dec("115792089237316195423570985008687907853269984.665640564039457584") - ); - assert_eq!( - max * dec("0.000000000000000001"), - dec("115792089237316195423570985008687907853269.984665640564039457") - ); - } - - #[test] - #[should_panic(expected = "attempt to multiply with overflow")] - fn decimal256_mul_overflow_panics() { - let _value = Decimal256::MAX * Decimal256::percent(101); - } - - #[test] - // in this test the Decimal256 is on the right - fn uint128_decimal_multiply() { - // a*b - let left = Uint256::from(300u128); - let right = Decimal256::one() + Decimal256::percent(50); // 1.5 - assert_eq!(left * right, Uint256::from(450u32)); - - // a*0 - let left = Uint256::from(300u128); - let right = Decimal256::zero(); - assert_eq!(left * right, Uint256::from(0u128)); - - // 0*a - let left = Uint256::from(0u128); - let right = Decimal256::one() + Decimal256::percent(50); // 1.5 - assert_eq!(left * right, Uint256::from(0u128)); - } - - #[test] - // in this test the Decimal256 is on the left - fn decimal256_uint128_multiply() { - // a*b - let left = Decimal256::one() + Decimal256::percent(50); // 1.5 - let right = Uint256::from(300u128); - assert_eq!(left * right, Uint256::from(450u128)); - - // 0*a - let left = Decimal256::zero(); - let right = Uint256::from(300u128); - assert_eq!(left * right, Uint256::from(0u128)); - - // a*0 - let left = Decimal256::one() + Decimal256::percent(50); // 1.5 - let right = Uint256::from(0u128); - assert_eq!(left * right, Uint256::from(0u128)); - } - - #[test] - fn decimal256_uint128_division() { - // a/b - let left = Decimal256::percent(150); // 1.5 - let right = Uint256::from(3u128); - assert_eq!(left / right, Decimal256::percent(50)); - - // 0/a - let left = Decimal256::zero(); - let right = Uint256::from(300u128); - assert_eq!(left / right, Decimal256::zero()); - } - - #[test] - #[should_panic(expected = "attempt to divide by zero")] - fn decimal256_uint128_divide_by_zero() { - let left = Decimal256::percent(150); // 1.5 - let right = Uint256::from(0u128); - let _result = left / right; - } - - #[test] - fn decimal256_uint128_div_assign() { - // a/b - let mut dec = Decimal256::percent(150); // 1.5 - dec /= Uint256::from(3u128); - assert_eq!(dec, Decimal256::percent(50)); - - // 0/a - let mut dec = Decimal256::zero(); - dec /= Uint256::from(300u128); - assert_eq!(dec, Decimal256::zero()); - } - - #[test] - #[should_panic(expected = "attempt to divide by zero")] - fn decimal256_uint128_div_assign_by_zero() { - // a/0 - let mut dec = Decimal256::percent(50); - dec /= Uint256::from(0u128); - } - - #[test] - fn decimal256_uint128_sqrt() { - assert_eq!(Decimal256::percent(900).sqrt(), Decimal256::percent(300)); - - assert!(Decimal256::percent(316) < Decimal256::percent(1000).sqrt()); - assert!(Decimal256::percent(1000).sqrt() < Decimal256::percent(317)); - } - - /// sqrt(2) is an irrational number, i.e. all 36 decimal places should be used. - #[test] - fn decimal256_uint128_sqrt_is_precise() { - assert_eq!( - Decimal256::from_str("2").unwrap().sqrt(), - Decimal256::from_str("1.414213562373095048").unwrap() // https://www.wolframalpha.com/input/?i=sqrt%282%29 - ); - } - - #[test] - fn decimal256_uint128_sqrt_does_not_overflow() { - assert_eq!( - Decimal256::from_str("40000000000000000000000000000000000000000000000000000000000") - .unwrap() - .sqrt(), - Decimal256::from_str("200000000000000000000000000000").unwrap() - ); - } - - #[test] - fn decimal256_uint128_sqrt_intermediate_precision_used() { - assert_eq!( - Decimal256::from_str("40000000000000000000000000000000000000000000000001") - .unwrap() - .sqrt(), - // The last few digits (39110) are truncated below due to the algorithm - // we use. Larger numbers will cause less precision. - // https://www.wolframalpha.com/input/?i=sqrt%2840000000000000000000000000000000000000000000000001%29 - Decimal256::from_str("6324555320336758663997787.088865437067400000").unwrap() - ); - } - - #[test] - fn decimal256_to_string() { - // Integers - assert_eq!(Decimal256::zero().to_string(), "0"); - assert_eq!(Decimal256::one().to_string(), "1"); - assert_eq!(Decimal256::percent(500).to_string(), "5"); - - // Decimals - assert_eq!(Decimal256::percent(125).to_string(), "1.25"); - assert_eq!(Decimal256::percent(42638).to_string(), "426.38"); - assert_eq!(Decimal256::percent(3).to_string(), "0.03"); - assert_eq!(Decimal256::permille(987).to_string(), "0.987"); - - assert_eq!( - Decimal256(Uint256::from(1u128)).to_string(), - "0.000000000000000001" - ); - assert_eq!( - Decimal256(Uint256::from(10u128)).to_string(), - "0.00000000000000001" - ); - assert_eq!( - Decimal256(Uint256::from(100u128)).to_string(), - "0.0000000000000001" - ); - assert_eq!( - Decimal256(Uint256::from(1000u128)).to_string(), - "0.000000000000001" - ); - assert_eq!( - Decimal256(Uint256::from(10000u128)).to_string(), - "0.00000000000001" - ); - assert_eq!( - Decimal256(Uint256::from(100000u128)).to_string(), - "0.0000000000001" - ); - assert_eq!( - Decimal256(Uint256::from(1000000u128)).to_string(), - "0.000000000001" - ); - assert_eq!( - Decimal256(Uint256::from(10000000u128)).to_string(), - "0.00000000001" - ); - assert_eq!( - Decimal256(Uint256::from(100000000u128)).to_string(), - "0.0000000001" - ); - assert_eq!( - Decimal256(Uint256::from(1000000000u128)).to_string(), - "0.000000001" - ); - assert_eq!( - Decimal256(Uint256::from(10000000000u128)).to_string(), - "0.00000001" - ); - assert_eq!( - Decimal256(Uint256::from(100000000000u128)).to_string(), - "0.0000001" - ); - assert_eq!( - Decimal256(Uint256::from(10000000000000u128)).to_string(), - "0.00001" - ); - assert_eq!( - Decimal256(Uint256::from(100000000000000u128)).to_string(), - "0.0001" - ); - assert_eq!( - Decimal256(Uint256::from(1000000000000000u128)).to_string(), - "0.001" - ); - assert_eq!( - Decimal256(Uint256::from(10000000000000000u128)).to_string(), - "0.01" - ); - assert_eq!( - Decimal256(Uint256::from(100000000000000000u128)).to_string(), - "0.1" - ); - } - - #[test] - fn decimal256_iter_sum() { - let items = vec![ - Decimal256::zero(), - Decimal256::from_str("2").unwrap(), - Decimal256::from_str("2").unwrap(), - ]; - assert_eq!( - items.iter().sum::(), - Decimal256::from_str("4").unwrap() - ); - assert_eq!( - items.into_iter().sum::(), - Decimal256::from_str("4").unwrap() - ); - - let empty: Vec = vec![]; - assert_eq!(Decimal256::zero(), empty.iter().sum()); - } - - #[test] - fn decimal256_serialize() { - assert_eq!(to_vec(&Decimal256::zero()).unwrap(), br#""0""#); - assert_eq!(to_vec(&Decimal256::one()).unwrap(), br#""1""#); - assert_eq!(to_vec(&Decimal256::percent(8)).unwrap(), br#""0.08""#); - assert_eq!(to_vec(&Decimal256::percent(87)).unwrap(), br#""0.87""#); - assert_eq!(to_vec(&Decimal256::percent(876)).unwrap(), br#""8.76""#); - assert_eq!(to_vec(&Decimal256::percent(8765)).unwrap(), br#""87.65""#); - } - - #[test] - fn decimal256_deserialize() { - assert_eq!( - from_slice::(br#""0""#).unwrap(), - Decimal256::zero() - ); - assert_eq!( - from_slice::(br#""1""#).unwrap(), - Decimal256::one() - ); - assert_eq!( - from_slice::(br#""000""#).unwrap(), - Decimal256::zero() - ); - assert_eq!( - from_slice::(br#""001""#).unwrap(), - Decimal256::one() - ); - - assert_eq!( - from_slice::(br#""0.08""#).unwrap(), - Decimal256::percent(8) - ); - assert_eq!( - from_slice::(br#""0.87""#).unwrap(), - Decimal256::percent(87) - ); - assert_eq!( - from_slice::(br#""8.76""#).unwrap(), - Decimal256::percent(876) - ); - assert_eq!( - from_slice::(br#""87.65""#).unwrap(), - Decimal256::percent(8765) - ); - } -} diff --git a/packages/cosmwasm_math_compat/src/math/fraction.rs b/packages/cosmwasm_math_compat/src/math/fraction.rs deleted file mode 100644 index ca187ad..0000000 --- a/packages/cosmwasm_math_compat/src/math/fraction.rs +++ /dev/null @@ -1,14 +0,0 @@ -/// A fraction `p`/`q` with integers `p` and `q`. -/// -/// `p` is called the numerator and `q` is called the denominator. -pub trait Fraction: Sized { - /// Returns the numerator `p` - fn numerator(&self) -> T; - /// Returns the denominator `q` - fn denominator(&self) -> T; - - /// Returns the multiplicative inverse `q/p` for fraction `p/q`. - /// - /// If `p` is zero, None is returned. - fn inv(&self) -> Option; -} diff --git a/packages/cosmwasm_math_compat/src/math/isqrt.rs b/packages/cosmwasm_math_compat/src/math/isqrt.rs deleted file mode 100644 index 8716232..0000000 --- a/packages/cosmwasm_math_compat/src/math/isqrt.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::{cmp, ops}; - -use crate::{Uint128, Uint256, Uint512, Uint64}; - -/// A trait for calculating the -/// [integer square root](https://en.wikipedia.org/wiki/Integer_square_root). -pub trait Isqrt { - /// The [integer square root](https://en.wikipedia.org/wiki/Integer_square_root). - fn isqrt(self) -> Self; -} - -impl Isqrt for I -where - I: Unsigned - + ops::Add - + ops::Div - + ops::Shr - + cmp::PartialOrd - + Copy - + From, -{ - /// Algorithm adapted from - /// [Wikipedia](https://en.wikipedia.org/wiki/Integer_square_root#Example_implementation_in_C). - fn isqrt(self) -> Self { - let mut x0 = self >> 1; - - if x0 > 0.into() { - let mut x1 = (x0 + self / x0) >> 1; - - while x1 < x0 { - x0 = x1; - x1 = (x0 + self / x0) >> 1; - } - - return x0; - } - self - } -} - -/// Marker trait for types that represent unsigned integers. -pub trait Unsigned {} -impl Unsigned for u8 {} -impl Unsigned for u16 {} -impl Unsigned for u32 {} -impl Unsigned for u64 {} -impl Unsigned for u128 {} -impl Unsigned for Uint64 {} -impl Unsigned for Uint128 {} -impl Unsigned for Uint256 {} -impl Unsigned for Uint512 {} -impl Unsigned for usize {} - -#[cfg(test)] -mod tests { - use std::convert::TryFrom; - - use super::*; - - #[test] - fn isqrt_primitives() { - // Let's check correctness. - assert_eq!(0u8.isqrt(), 0); - assert_eq!(1u8.isqrt(), 1); - assert_eq!(24u8.isqrt(), 4); - assert_eq!(25u8.isqrt(), 5); - assert_eq!(26u8.isqrt(), 5); - assert_eq!(36u8.isqrt(), 6); - - // Let's also check different types. - assert_eq!(26u8.isqrt(), 5); - assert_eq!(26u16.isqrt(), 5); - assert_eq!(26u32.isqrt(), 5); - assert_eq!(26u64.isqrt(), 5); - assert_eq!(26u128.isqrt(), 5); - } - - #[test] - fn isqrt_uint64() { - assert_eq!(Uint64::new(24).isqrt(), Uint64::new(4)); - } - - #[test] - fn isqrt_uint128() { - assert_eq!(Uint128::new(24).isqrt(), Uint128::new(4)); - } - - #[test] - fn isqrt_uint256() { - assert_eq!(Uint256::from(24u32).isqrt(), Uint256::from(4u32)); - assert_eq!( - (Uint256::from(u128::MAX) * Uint256::from(u128::MAX)).isqrt(), - Uint256::try_from("340282366920938463463374607431768211455").unwrap() - ); - } - - #[test] - fn isqrt_uint512() { - assert_eq!(Uint512::from(24u32).isqrt(), Uint512::from(4u32)); - assert_eq!( - (Uint512::from(Uint256::MAX) * Uint512::from(Uint256::MAX)).isqrt(), - Uint512::try_from( - "115792089237316195423570985008687907853269984665640564039457584007913129639935" - ) - .unwrap() - ); - } -} diff --git a/packages/cosmwasm_math_compat/src/math/mod.rs b/packages/cosmwasm_math_compat/src/math/mod.rs deleted file mode 100644 index 3a7a4e8..0000000 --- a/packages/cosmwasm_math_compat/src/math/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod decimal; -mod decimal256; -mod fraction; -mod isqrt; -mod uint128; -mod uint256; -mod uint512; -mod uint64; - -pub use decimal::{Decimal, DecimalRangeExceeded}; -pub use decimal256::{Decimal256, Decimal256RangeExceeded}; -pub use fraction::Fraction; -pub use isqrt::Isqrt; -pub use uint128::Uint128; -pub use uint256::Uint256; -pub use uint512::Uint512; -pub use uint64::Uint64; diff --git a/packages/cosmwasm_math_compat/src/math/uint128.rs b/packages/cosmwasm_math_compat/src/math/uint128.rs deleted file mode 100644 index 632f38f..0000000 --- a/packages/cosmwasm_math_compat/src/math/uint128.rs +++ /dev/null @@ -1,779 +0,0 @@ -use schemars::JsonSchema; -use serde::{de, ser, Deserialize, Deserializer, Serialize}; -use std::{ - convert::{TryFrom, TryInto}, - fmt::{self}, - ops, - str::FromStr, -}; - -use crate::{ - errors::{ - ConversionOverflowError, - DivideByZeroError, - OverflowError, - OverflowOperation, - StdError, - }, - Uint256, - Uint64, -}; - -/// A thin wrapper around u128 that is using strings for JSON encoding/decoding, -/// such that the full u128 range can be used for clients that convert JSON numbers to floats, -/// like JavaScript and jq. -/// -/// # Examples -/// -/// Use `from` to create instances of this and `u128` to get the value out: -/// -/// ``` -/// # use cosmwasm_math::Uint128; -/// let a = Uint128::from(123u128); -/// assert_eq!(a.u128(), 123); -/// -/// let b = Uint128::from(42u64); -/// assert_eq!(b.u128(), 42); -/// -/// let c = Uint128::from(70u32); -/// assert_eq!(c.u128(), 70); -/// ``` -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] -pub struct Uint128(#[schemars(with = "String")] u128); - -impl Uint128 { - pub const MAX: Self = Self(u128::MAX); - - /// Creates a Uint128(value). - /// - /// This method is less flexible than `from` but can be called in a const context. - pub const fn new(value: u128) -> Self { - Uint128(value) - } - - /// Creates a Uint128(0) - pub const fn zero() -> Self { - Uint128(0) - } - - /// Returns a copy of the internal data - pub const fn u128(&self) -> u128 { - self.0 - } - - /// Returns a copy of the number as big endian bytes. - pub const fn to_be_bytes(self) -> [u8; 16] { - self.0.to_be_bytes() - } - - /// Returns a copy of the number as little endian bytes. - pub const fn to_le_bytes(self) -> [u8; 16] { - self.0.to_le_bytes() - } - - pub fn is_zero(&self) -> bool { - self.0 == 0 - } - - pub fn checked_add(self, other: Self) -> Result { - self.0 - .checked_add(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Add, self, other)) - } - - pub fn checked_sub(self, other: Self) -> Result { - self.0 - .checked_sub(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Sub, self, other)) - } - - pub fn checked_mul(self, other: Self) -> Result { - self.0 - .checked_mul(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other)) - } - - pub fn checked_pow(self, exp: u32) -> Result { - self.0 - .checked_pow(exp) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Pow, self, exp)) - } - - pub fn checked_div(self, other: Self) -> Result { - self.0 - .checked_div(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_div_euclid(self, other: Self) -> Result { - self.0 - .checked_div_euclid(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_rem(self, other: Self) -> Result { - self.0 - .checked_rem(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn wrapping_add(self, other: Self) -> Self { - Self(self.0.wrapping_add(other.0)) - } - - pub fn wrapping_sub(self, other: Self) -> Self { - Self(self.0.wrapping_sub(other.0)) - } - - pub fn wrapping_mul(self, other: Self) -> Self { - Self(self.0.wrapping_mul(other.0)) - } - - pub fn wrapping_pow(self, other: u32) -> Self { - Self(self.0.wrapping_pow(other)) - } - - pub fn saturating_add(self, other: Self) -> Self { - Self(self.0.saturating_add(other.0)) - } - - pub fn saturating_sub(self, other: Self) -> Self { - Self(self.0.saturating_sub(other.0)) - } - - pub fn saturating_mul(self, other: Self) -> Self { - Self(self.0.saturating_mul(other.0)) - } - - pub fn saturating_pow(self, other: u32) -> Self { - Self(self.0.saturating_pow(other)) - } -} - -// `From` is implemented manually instead of -// using `impl> From for Uint128` because -// of the conflict with `TryFrom<&str>` as described here -// https://stackoverflow.com/questions/63136970/how-do-i-work-around-the-upstream-crates-may-add-a-new-impl-of-trait-error - -impl From for Uint128 { - fn from(val: Uint64) -> Self { - val.u64().into() - } -} - -impl From for Uint128 { - fn from(val: u128) -> Self { - Uint128(val) - } -} - -impl From for Uint128 { - fn from(val: u64) -> Self { - Uint128(val.into()) - } -} - -impl From for Uint128 { - fn from(val: u32) -> Self { - Uint128(val.into()) - } -} - -impl From for Uint128 { - fn from(val: u16) -> Self { - Uint128(val.into()) - } -} - -impl From for Uint128 { - fn from(val: u8) -> Self { - Uint128(val.into()) - } -} - -impl TryFrom for Uint64 { - type Error = ConversionOverflowError; - - fn try_from(value: Uint128) -> Result { - Ok(Uint64::new(value.0.try_into().map_err(|_| { - ConversionOverflowError::new("Uint128", "Uint64", value.to_string()) - })?)) - } -} - -impl TryFrom<&str> for Uint128 { - type Error = StdError; - - fn try_from(val: &str) -> Result { - Self::from_str(val) - } -} - -impl FromStr for Uint128 { - type Err = StdError; - - fn from_str(s: &str) -> Result { - match s.parse::() { - Ok(u) => Ok(Uint128(u)), - Err(e) => Err(StdError::generic_err(format!("Parsing u128: {}", e))), - } - } -} - -impl From for String { - fn from(original: Uint128) -> Self { - original.to_string() - } -} - -impl From for u128 { - fn from(original: Uint128) -> Self { - original.0 - } -} - -impl fmt::Display for Uint128 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl ops::Add for Uint128 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Uint128( - self.u128() - .checked_add(rhs.u128()) - .expect("attempt to add with overflow"), - ) - } -} - -impl<'a> ops::Add<&'a Uint128> for Uint128 { - type Output = Self; - - fn add(self, rhs: &'a Uint128) -> Self { - self + *rhs - } -} - -impl ops::Sub for Uint128 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - Uint128( - self.u128() - .checked_sub(rhs.u128()) - .expect("attempt to subtract with overflow"), - ) - } -} - -impl<'a> ops::Sub<&'a Uint128> for Uint128 { - type Output = Self; - - fn sub(self, rhs: &'a Uint128) -> Self { - self - *rhs - } -} - -impl ops::Mul for Uint128 { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Self( - self.u128() - .checked_mul(rhs.u128()) - .expect("attempt to multiply with overflow"), - ) - } -} - -impl<'a> ops::Mul<&'a Uint128> for Uint128 { - type Output = Self; - - fn mul(self, rhs: &'a Uint128) -> Self::Output { - self.mul(*rhs) - } -} - -impl ops::Div for Uint128 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - Self( - self.u128() - .checked_div(rhs.u128()) - .expect("attempt to divide by zero"), - ) - } -} - -impl<'a> ops::Div<&'a Uint128> for Uint128 { - type Output = Self; - - fn div(self, rhs: &'a Uint128) -> Self::Output { - self / *rhs - } -} - -impl ops::Shr for Uint128 { - type Output = Self; - - fn shr(self, rhs: u32) -> Self::Output { - Self( - self.u128() - .checked_shr(rhs) - .expect("attempt to shift right with overflow"), - ) - } -} - -impl<'a> ops::Shr<&'a u32> for Uint128 { - type Output = Self; - - fn shr(self, rhs: &'a u32) -> Self::Output { - self >> *rhs - } -} - -impl ops::AddAssign for Uint128 { - fn add_assign(&mut self, rhs: Uint128) { - *self = *self + rhs; - } -} - -impl<'a> ops::AddAssign<&'a Uint128> for Uint128 { - fn add_assign(&mut self, rhs: &'a Uint128) { - *self = *self + rhs; - } -} - -impl ops::SubAssign for Uint128 { - fn sub_assign(&mut self, rhs: Uint128) { - *self = *self - rhs; - } -} - -impl<'a> ops::SubAssign<&'a Uint128> for Uint128 { - fn sub_assign(&mut self, rhs: &'a Uint128) { - *self = *self - rhs; - } -} - -impl ops::MulAssign for Uint128 { - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl<'a> ops::MulAssign<&'a Uint128> for Uint128 { - fn mul_assign(&mut self, rhs: &'a Uint128) { - *self = *self * rhs; - } -} - -impl ops::DivAssign for Uint128 { - fn div_assign(&mut self, rhs: Self) { - *self = *self / rhs; - } -} - -impl<'a> ops::DivAssign<&'a Uint128> for Uint128 { - fn div_assign(&mut self, rhs: &'a Uint128) { - *self = *self / rhs; - } -} - -impl ops::ShrAssign for Uint128 { - fn shr_assign(&mut self, rhs: u32) { - *self = *self >> rhs; - } -} - -impl<'a> ops::ShrAssign<&'a u32> for Uint128 { - fn shr_assign(&mut self, rhs: &'a u32) { - *self = *self >> rhs; - } -} - -impl Uint128 { - /// Returns `self * numerator / denominator` - pub fn multiply_ratio, B: Into>( - &self, - numerator: A, - denominator: B, - ) -> Uint128 { - let numerator: u128 = numerator.into(); - let denominator: u128 = denominator.into(); - if denominator == 0 { - panic!("Denominator must not be zero"); - } - (self.full_mul(numerator) / Uint256::from(denominator)) - .try_into() - .expect("multiplication overflow") - } - - /// Multiplies two u128 values without overflow, producing an - /// [`Uint256`]. - /// - /// # Examples - /// - /// ``` - /// use cosmwasm_math::Uint128; - /// - /// let a = Uint128::MAX; - /// let result = a.full_mul(2u32); - /// assert_eq!(result.to_string(), "680564733841876926926749214863536422910"); - /// ``` - pub fn full_mul(self, rhs: impl Into) -> Uint256 { - Uint256::from(self.u128()) - .checked_mul(Uint256::from(rhs.into())) - .unwrap() - } -} - -impl Serialize for Uint128 { - /// Serializes as an integer string using base 10 - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl<'de> Deserialize<'de> for Uint128 { - /// Deserialized from an integer string using base 10 - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Uint128Visitor) - } -} - -struct Uint128Visitor; - -impl<'de> de::Visitor<'de> for Uint128Visitor { - type Value = Uint128; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("string-encoded integer") - } - - fn visit_str(self, v: &str) -> Result - where - E: de::Error, - { - match v.parse::() { - Ok(u) => Ok(Uint128(u)), - Err(e) => Err(E::custom(format!("invalid Uint128 '{}' - {}", v, e))), - } - } -} - -impl std::iter::Sum for Uint128 -where - Self: ops::Add, -{ - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), ops::Add::add) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::{from_slice, to_vec}; - - #[test] - fn uint128_convert_into() { - let original = Uint128(12345); - let a = u128::from(original); - assert_eq!(a, 12345); - - let original = Uint128(12345); - let a = String::from(original); - assert_eq!(a, "12345"); - } - - #[test] - fn uint128_convert_from() { - let a = Uint128::from(5u128); - assert_eq!(a.0, 5); - - let a = Uint128::from(5u64); - assert_eq!(a.0, 5); - - let a = Uint128::from(5u32); - assert_eq!(a.0, 5); - - let a = Uint128::from(5u16); - assert_eq!(a.0, 5); - - let a = Uint128::from(5u8); - assert_eq!(a.0, 5); - - let result = Uint128::try_from("34567"); - assert_eq!(result.unwrap().0, 34567); - - let result = Uint128::try_from("1.23"); - assert!(result.is_err()); - } - - #[test] - fn uint128_implements_display() { - let a = Uint128(12345); - assert_eq!(format!("Embedded: {}", a), "Embedded: 12345"); - assert_eq!(a.to_string(), "12345"); - - let a = Uint128(0); - assert_eq!(format!("Embedded: {}", a), "Embedded: 0"); - assert_eq!(a.to_string(), "0"); - } - - #[test] - fn uint128_display_padding_works() { - let a = Uint128::from(123u64); - assert_eq!(format!("Embedded: {:05}", a), "Embedded: 00123"); - } - - #[test] - fn uint128_to_be_bytes_works() { - assert_eq!(Uint128::zero().to_be_bytes(), [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]); - assert_eq!(Uint128::MAX.to_be_bytes(), [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ]); - assert_eq!(Uint128::new(1).to_be_bytes(), [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 - ]); - // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(16, "big")]` - assert_eq!( - Uint128::new(240282366920938463463374607431768124608).to_be_bytes(), - [ - 180, 196, 179, 87, 165, 121, 59, 133, 246, 117, 221, 191, 255, 254, 172, 192 - ] - ); - } - - #[test] - fn uint128_to_le_bytes_works() { - assert_eq!(Uint128::zero().to_le_bytes(), [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]); - assert_eq!(Uint128::MAX.to_le_bytes(), [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ]); - assert_eq!(Uint128::new(1).to_le_bytes(), [ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]); - // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(16, "little")]` - assert_eq!( - Uint128::new(240282366920938463463374607431768124608).to_le_bytes(), - [ - 192, 172, 254, 255, 191, 221, 117, 246, 133, 59, 121, 165, 87, 179, 196, 180 - ] - ); - } - - #[test] - fn uint128_is_zero_works() { - assert!(Uint128::zero().is_zero()); - assert!(Uint128(0).is_zero()); - - assert!(!Uint128(1).is_zero()); - assert!(!Uint128(123).is_zero()); - } - - #[test] - fn uint128_json() { - let orig = Uint128(1234567890987654321); - let serialized = to_vec(&orig).unwrap(); - assert_eq!(serialized.as_slice(), b"\"1234567890987654321\""); - let parsed: Uint128 = from_slice(&serialized).unwrap(); - assert_eq!(parsed, orig); - } - - #[test] - fn uint128_compare() { - let a = Uint128(12345); - let b = Uint128(23456); - - assert!(a < b); - assert!(b > a); - assert_eq!(a, Uint128(12345)); - } - - #[test] - #[allow(clippy::op_ref)] - fn uint128_math() { - let a = Uint128(12345); - let b = Uint128(23456); - - // test + with owned and reference right hand side - assert_eq!(a + b, Uint128(35801)); - assert_eq!(a + &b, Uint128(35801)); - - // test - with owned and reference right hand side - assert_eq!(b - a, Uint128(11111)); - assert_eq!(b - &a, Uint128(11111)); - - // test += with owned and reference right hand side - let mut c = Uint128(300000); - c += b; - assert_eq!(c, Uint128(323456)); - let mut d = Uint128(300000); - d += &b; - assert_eq!(d, Uint128(323456)); - - // test -= with owned and reference right hand side - let mut c = Uint128(300000); - c -= b; - assert_eq!(c, Uint128(276544)); - let mut d = Uint128(300000); - d -= &b; - assert_eq!(d, Uint128(276544)); - - // error result on underflow (- would produce negative result) - let underflow_result = a.checked_sub(b); - let OverflowError { - operand1, operand2, .. - } = underflow_result.unwrap_err(); - assert_eq!((operand1, operand2), (a.to_string(), b.to_string())); - } - - #[test] - #[should_panic] - fn uint128_add_overflow_panics() { - // almost_max is 2^128 - 10 - let almost_max = Uint128(340282366920938463463374607431768211446); - let _ = almost_max + Uint128(12); - } - - #[test] - #[should_panic] - fn uint128_sub_overflow_panics() { - let _ = Uint128(1) - Uint128(2); - } - - #[test] - fn uint128_multiply_ratio_works() { - let base = Uint128(500); - - // factor 1/1 - assert_eq!(base.multiply_ratio(1u128, 1u128), base); - assert_eq!(base.multiply_ratio(3u128, 3u128), base); - assert_eq!(base.multiply_ratio(654321u128, 654321u128), base); - assert_eq!(base.multiply_ratio(u128::MAX, u128::MAX), base); - - // factor 3/2 - assert_eq!(base.multiply_ratio(3u128, 2u128), Uint128(750)); - assert_eq!(base.multiply_ratio(333333u128, 222222u128), Uint128(750)); - - // factor 2/3 (integer devision always floors the result) - assert_eq!(base.multiply_ratio(2u128, 3u128), Uint128(333)); - assert_eq!(base.multiply_ratio(222222u128, 333333u128), Uint128(333)); - - // factor 5/6 (integer devision always floors the result) - assert_eq!(base.multiply_ratio(5u128, 6u128), Uint128(416)); - assert_eq!(base.multiply_ratio(100u128, 120u128), Uint128(416)); - } - - #[test] - fn uint128_multiply_ratio_does_not_overflow_when_result_fits() { - // Almost max value for Uint128. - let base = Uint128(u128::MAX - 9); - - assert_eq!(base.multiply_ratio(2u128, 2u128), base); - } - - #[test] - #[should_panic] - fn uint128_multiply_ratio_panicks_on_overflow() { - // Almost max value for Uint128. - let base = Uint128(u128::MAX - 9); - - assert_eq!(base.multiply_ratio(2u128, 1u128), base); - } - - #[test] - #[should_panic(expected = "Denominator must not be zero")] - fn uint128_multiply_ratio_panics_for_zero_denominator() { - Uint128(500).multiply_ratio(1u128, 0u128); - } - - #[test] - fn sum_works() { - let nums = vec![Uint128(17), Uint128(123), Uint128(540), Uint128(82)]; - let expected = Uint128(762); - - let sum_as_ref = nums.iter().sum(); - assert_eq!(expected, sum_as_ref); - - let sum_as_owned = nums.into_iter().sum(); - assert_eq!(expected, sum_as_owned); - } - - #[test] - fn uint128_methods() { - // checked_* - assert!(matches!( - Uint128(u128::MAX).checked_add(Uint128(1)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint128(0).checked_sub(Uint128(1)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint128(u128::MAX).checked_mul(Uint128(2)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint128(u128::MAX).checked_div(Uint128(0)), - Err(DivideByZeroError { .. }) - )); - assert!(matches!( - Uint128(u128::MAX).checked_div_euclid(Uint128(0)), - Err(DivideByZeroError { .. }) - )); - assert!(matches!( - Uint128(u128::MAX).checked_rem(Uint128(0)), - Err(DivideByZeroError { .. }) - )); - - // saturating_* - assert_eq!( - Uint128(u128::MAX).saturating_add(Uint128(1)), - Uint128(u128::MAX) - ); - assert_eq!(Uint128(0).saturating_sub(Uint128(1)), Uint128(0)); - assert_eq!( - Uint128(u128::MAX).saturating_mul(Uint128(2)), - Uint128(u128::MAX) - ); - assert_eq!(Uint128(u128::MAX).saturating_pow(2), Uint128(u128::MAX)); - - // wrapping_* - assert_eq!(Uint128(u128::MAX).wrapping_add(Uint128(1)), Uint128(0)); - assert_eq!(Uint128(0).wrapping_sub(Uint128(1)), Uint128(u128::MAX)); - assert_eq!( - Uint128(u128::MAX).wrapping_mul(Uint128(2)), - Uint128(u128::MAX - 1) - ); - assert_eq!(Uint128(u128::MAX).wrapping_pow(2), Uint128(1)); - } -} diff --git a/packages/cosmwasm_math_compat/src/math/uint256.rs b/packages/cosmwasm_math_compat/src/math/uint256.rs deleted file mode 100644 index 1a864dd..0000000 --- a/packages/cosmwasm_math_compat/src/math/uint256.rs +++ /dev/null @@ -1,1386 +0,0 @@ -use cosmwasm_std::StdResult; -use schemars::JsonSchema; -use serde::{de, ser, Deserialize, Deserializer, Serialize}; -use std::{ - convert::{TryFrom, TryInto}, - fmt, - ops::{self, Shl, Shr}, - str::FromStr, -}; - -use crate::{ - errors::{ - ConversionOverflowError, DivideByZeroError, OverflowError, OverflowOperation, StdError, - }, - Uint128, Uint512, Uint64, -}; - -/// This module is purely a workaround that lets us ignore lints for all the code -/// the `construct_uint!` macro generates. -#[allow(clippy::all)] -mod uints { - uint::construct_uint! { - pub struct U256(4); - } -} - -/// Used internally - we don't want to leak this type since we might change -/// the implementation in the future. -use uints::U256; - -/// An implementation of u256 that is using strings for JSON encoding/decoding, -/// such that the full u256 range can be used for clients that convert JSON numbers to floats, -/// like JavaScript and jq. -/// -/// # Examples -/// -/// Use `from` to create instances out of primitive uint types or `new` to provide big -/// endian bytes: -/// -/// ``` -/// # use cosmwasm_math::Uint256; -/// let a = Uint256::from(258u128); -/// let b = Uint256::new([ -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, -/// ]); -/// assert_eq!(a, b); -/// ``` -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] -pub struct Uint256(#[schemars(with = "String")] U256); - -impl Uint256 { - pub const MAX: Uint256 = Uint256(U256::MAX); - - /// Creates a Uint256(value) from a big endian representation. It's just an alias for - /// [`Uint256::from_be_bytes`]. - /// - /// This method is less flexible than `from` but can be called in a const context. - pub const fn new(value: [u8; 32]) -> Self { - Self::from_be_bytes(value) - } - - pub fn clamp_u128(self) -> StdResult { - if self.0.0[3] > 0 { - return Err(StdError::generic_err("u128 overflow")); - } - - Ok(self.0.low_u128()) - } - - pub fn sqrt(self) -> StdResult { - let mut z = Self::from(0 as i32); - - if self.gt(&Self::from(3 as i32)) { - z = self.clone(); - let mut x = self - .checked_div(Self::from(2 as i32))? - .checked_add(Self::from(1 as i32))?; - - while x.lt(&z) { - z = x.clone(); - x = self - .checked_div(x)? - .checked_add(x)? - .checked_div(Self::from(2 as i32))?; - } - } else if !self.is_zero() { - z = Self::from(1 as i32); - } - - return Ok(z); - } - - /// Creates a Uint256(0) - pub const fn zero() -> Self { - Uint256(U256::zero()) - } - - pub const fn from_be_bytes(data: [u8; 32]) -> Self { - let words: [u64; 4] = [ - u64::from_le_bytes([ - data[31], data[30], data[29], data[28], data[27], data[26], data[25], data[24], - ]), - u64::from_le_bytes([ - data[23], data[22], data[21], data[20], data[19], data[18], data[17], data[16], - ]), - u64::from_le_bytes([ - data[15], data[14], data[13], data[12], data[11], data[10], data[9], data[8], - ]), - u64::from_le_bytes([ - data[7], data[6], data[5], data[4], data[3], data[2], data[1], data[0], - ]), - ]; - Self(U256(words)) - } - - pub const fn from_le_bytes(data: [u8; 32]) -> Self { - let words: [u64; 4] = [ - u64::from_le_bytes([ - data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], - ]), - u64::from_le_bytes([ - data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], - ]), - u64::from_le_bytes([ - data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], - ]), - u64::from_le_bytes([ - data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], - ]), - ]; - Uint256(U256(words)) - } - - /// A conversion from `Uint128` that, unlike the one provided by the `From` trait, - /// can be used in a `const` context. - pub const fn from_uint128(num: Uint128) -> Self { - let bytes = num.to_le_bytes(); - - Self::from_le_bytes([ - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], - bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]) - } - - /// Returns a copy of the number as big endian bytes. - pub const fn to_be_bytes(self) -> [u8; 32] { - let words = [ - (self.0).0[3].to_be_bytes(), - (self.0).0[2].to_be_bytes(), - (self.0).0[1].to_be_bytes(), - (self.0).0[0].to_be_bytes(), - ]; - - // In Rust 1.56+ we can use `unsafe { std::mem::transmute::<[[u8; 8]; 4], [u8; 32]>(words) }` for this - [ - words[0][0], - words[0][1], - words[0][2], - words[0][3], - words[0][4], - words[0][5], - words[0][6], - words[0][7], - words[1][0], - words[1][1], - words[1][2], - words[1][3], - words[1][4], - words[1][5], - words[1][6], - words[1][7], - words[2][0], - words[2][1], - words[2][2], - words[2][3], - words[2][4], - words[2][5], - words[2][6], - words[2][7], - words[3][0], - words[3][1], - words[3][2], - words[3][3], - words[3][4], - words[3][5], - words[3][6], - words[3][7], - ] - } - - /// Returns a copy of the number as little endian bytes. - pub const fn to_le_bytes(self) -> [u8; 32] { - let words = [ - (self.0).0[0].to_le_bytes(), - (self.0).0[1].to_le_bytes(), - (self.0).0[2].to_le_bytes(), - (self.0).0[3].to_le_bytes(), - ]; - - // In Rust 1.56+ we can use `unsafe { std::mem::transmute::<[[u8; 8]; 4], [u8; 32]>(words) }` for this - [ - words[0][0], - words[0][1], - words[0][2], - words[0][3], - words[0][4], - words[0][5], - words[0][6], - words[0][7], - words[1][0], - words[1][1], - words[1][2], - words[1][3], - words[1][4], - words[1][5], - words[1][6], - words[1][7], - words[2][0], - words[2][1], - words[2][2], - words[2][3], - words[2][4], - words[2][5], - words[2][6], - words[2][7], - words[3][0], - words[3][1], - words[3][2], - words[3][3], - words[3][4], - words[3][5], - words[3][6], - words[3][7], - ] - } - - pub fn is_zero(&self) -> bool { - self.0.is_zero() - } - - pub fn checked_add(self, other: Self) -> Result { - self.0 - .checked_add(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Add, self, other)) - } - - pub fn checked_sub(self, other: Self) -> Result { - self.0 - .checked_sub(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Sub, self, other)) - } - - pub fn checked_mul(self, other: Self) -> Result { - self.0 - .checked_mul(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other)) - } - - pub fn checked_div(self, other: Self) -> Result { - self.0 - .checked_div(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_rem(self, other: Self) -> Result { - self.0 - .checked_rem(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_pow(self, exp: u32) -> Result { - self.0 - .checked_pow(exp.into()) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Pow, self, exp)) - } - - pub fn pow(self, exp: u32) -> Self { - self.checked_pow(exp) - .expect("attempt to raise to a power with overflow") - } - - pub fn checked_shr(self, other: u32) -> Result { - if other >= 256 { - return Err(OverflowError::new(OverflowOperation::Shr, self, other)); - } - - Ok(Self(self.0.shr(other))) - } - - pub fn checked_shl(self, other: u32) -> Result { - if other >= 256 { - return Err(OverflowError::new(OverflowOperation::Shl, self, other)); - } - - Ok(Self(self.0.shl(other))) - } - - pub fn saturating_add(self, other: Self) -> Self { - Self(self.0.saturating_add(other.0)) - } - - pub fn saturating_sub(self, other: Self) -> Self { - Self(self.0.saturating_sub(other.0)) - } - - pub fn saturating_mul(self, other: Self) -> Self { - Self(self.0.saturating_mul(other.0)) - } -} - -impl From for Uint256 { - fn from(val: Uint128) -> Self { - val.u128().into() - } -} - -impl From for Uint256 { - fn from(val: Uint64) -> Self { - val.u64().into() - } -} - -impl From for Uint256 { - fn from(val: u128) -> Self { - Uint256(val.into()) - } -} - -impl From for Uint256 { - fn from(val: u64) -> Self { - Uint256(val.into()) - } -} - -impl From for Uint256 { - fn from(val: u32) -> Self { - Uint256(val.into()) - } -} - -impl From for Uint256 { - fn from(val: u16) -> Self { - Uint256(val.into()) - } -} - -impl From for Uint256 { - fn from(val: u8) -> Self { - Uint256(val.into()) - } -} - -impl From for Uint256 { - fn from(value: i32) -> Self { - Uint256(U256::from(value)) - } -} - -impl TryFrom for Uint128 { - type Error = ConversionOverflowError; - - fn try_from(value: Uint256) -> Result { - Ok(Uint128::new(value.0.try_into().map_err(|_| { - ConversionOverflowError::new("Uint256", "Uint128", value.to_string()) - })?)) - } -} - -impl TryFrom<&str> for Uint256 { - type Error = StdError; - - fn try_from(val: &str) -> Result { - Self::from_str(val) - } -} - -impl FromStr for Uint256 { - type Err = StdError; - - fn from_str(s: &str) -> Result { - if s.is_empty() { - return Err(StdError::generic_err("Parsing u256: received empty string")); - } - - match U256::from_dec_str(s) { - Ok(u) => Ok(Uint256(u)), - Err(e) => Err(StdError::generic_err(format!("Parsing u256: {}", e))), - } - } -} - -impl From for String { - fn from(original: Uint256) -> Self { - original.to_string() - } -} - -impl fmt::Display for Uint256 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // The inner type doesn't work as expected with padding, so we - // work around that. - let unpadded = self.0.to_string(); - - f.pad_integral(true, "", &unpadded) - } -} - -impl ops::Add for Uint256 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Self( - self.0 - .checked_add(rhs.0) - .expect("attempt to add with overflow"), - ) - } -} - -impl<'a> ops::Add<&'a Uint256> for Uint256 { - type Output = Self; - - fn add(self, rhs: &'a Uint256) -> Self { - self + *rhs - } -} - -impl ops::Sub for Uint256 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - Self( - self.0 - .checked_sub(rhs.0) - .expect("attempt to subtract with overflow"), - ) - } -} - -impl<'a> ops::Sub<&'a Uint256> for Uint256 { - type Output = Self; - - fn sub(self, rhs: &'a Uint256) -> Self { - self - *rhs - } -} - -impl ops::Div for Uint256 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - Self( - self.0 - .checked_div(rhs.0) - .expect("attempt to divide by zero"), - ) - } -} - -impl<'a> ops::Div<&'a Uint256> for Uint256 { - type Output = Self; - - fn div(self, rhs: &'a Uint256) -> Self::Output { - self / *rhs - } -} - -impl ops::Mul for Uint256 { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Self( - self.0 - .checked_mul(rhs.0) - .expect("attempt to multiply with overflow"), - ) - } -} - -impl<'a> ops::Mul<&'a Uint256> for Uint256 { - type Output = Self; - - fn mul(self, rhs: &'a Uint256) -> Self::Output { - self.mul(*rhs) - } -} - -impl ops::Shr for Uint256 { - type Output = Self; - - fn shr(self, rhs: u32) -> Self::Output { - self.checked_shr(rhs).unwrap_or_else(|_| { - panic!( - "right shift error: {} is larger or equal than the number of bits in Uint256", - rhs, - ) - }) - } -} - -impl<'a> ops::Shr<&'a u32> for Uint256 { - type Output = Self; - - fn shr(self, rhs: &'a u32) -> Self::Output { - self.shr(*rhs) - } -} - -impl ops::Shl for Uint256 { - type Output = Self; - - fn shl(self, rhs: u32) -> Self::Output { - self.checked_shl(rhs).unwrap_or_else(|_| { - panic!( - "left shift error: {} is larger or equal than the number of bits in Uint256", - rhs, - ) - }) - } -} - -impl<'a> ops::Shl<&'a u32> for Uint256 { - type Output = Self; - - fn shl(self, rhs: &'a u32) -> Self::Output { - self.shl(*rhs) - } -} - -impl ops::AddAssign for Uint256 { - fn add_assign(&mut self, rhs: Uint256) { - *self = *self + rhs; - } -} - -impl<'a> ops::AddAssign<&'a Uint256> for Uint256 { - fn add_assign(&mut self, rhs: &'a Uint256) { - *self = *self + rhs; - } -} - -impl ops::SubAssign for Uint256 { - fn sub_assign(&mut self, rhs: Uint256) { - *self = *self - rhs; - } -} - -impl<'a> ops::SubAssign<&'a Uint256> for Uint256 { - fn sub_assign(&mut self, rhs: &'a Uint256) { - *self = *self - rhs; - } -} - -impl ops::MulAssign for Uint256 { - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl<'a> ops::MulAssign<&'a Uint256> for Uint256 { - fn mul_assign(&mut self, rhs: &'a Uint256) { - *self = *self * rhs; - } -} - -impl ops::DivAssign for Uint256 { - fn div_assign(&mut self, rhs: Self) { - *self = *self / rhs; - } -} - -impl<'a> ops::DivAssign<&'a Uint256> for Uint256 { - fn div_assign(&mut self, rhs: &'a Uint256) { - *self = *self / rhs; - } -} - -impl ops::ShrAssign for Uint256 { - fn shr_assign(&mut self, rhs: u32) { - *self = Shr::::shr(*self, rhs); - } -} - -impl<'a> ops::ShrAssign<&'a u32> for Uint256 { - fn shr_assign(&mut self, rhs: &'a u32) { - *self = Shr::::shr(*self, *rhs); - } -} - -impl Uint256 { - /// Returns `self * numerator / denominator` - pub fn multiply_ratio, B: Into>( - &self, - numerator: A, - denominator: B, - ) -> Uint256 { - let numerator: Uint256 = numerator.into(); - let denominator: Uint256 = denominator.into(); - if denominator.is_zero() { - panic!("Denominator must not be zero"); - } - (self.full_mul(numerator) / Uint512::from(denominator)) - .try_into() - .expect("multiplication overflow") - } - - /// Multiplies two u256 values without overflow, producing an - /// [`Uint512`]. - /// - /// # Examples - /// - /// ``` - /// use cosmwasm_math::Uint256; - /// - /// let a = Uint256::MAX; - /// let result = a.full_mul(2u32); - /// assert_eq!( - /// result.to_string(), - /// "231584178474632390847141970017375815706539969331281128078915168015826259279870", - /// ); - /// ``` - pub fn full_mul(self, rhs: impl Into) -> Uint512 { - Uint512::from(self) - .checked_mul(Uint512::from(rhs.into())) - .unwrap() - } -} - -impl Serialize for Uint256 { - /// Serializes as an integer string using base 10 - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl<'de> Deserialize<'de> for Uint256 { - /// Deserialized from an integer string using base 10 - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Uint256Visitor) - } -} - -struct Uint256Visitor; - -impl<'de> de::Visitor<'de> for Uint256Visitor { - type Value = Uint256; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("string-encoded integer") - } - - fn visit_str(self, v: &str) -> Result - where - E: de::Error, - { - Uint256::try_from(v).map_err(|e| E::custom(format!("invalid Uint256 '{}' - {}", v, e))) - } -} - -impl std::iter::Sum for Uint256 -where - Self: ops::Add, -{ - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), ops::Add::add) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::{from_slice, to_vec}; - - #[test] - fn uint256_construct() { - let num = Uint256::new([1; 32]); - let a: [u8; 32] = num.to_be_bytes(); - assert_eq!(a, [1; 32]); - - let be_bytes = [ - 0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8, - ]; - let num = Uint256::new(be_bytes); - let resulting_bytes: [u8; 32] = num.to_be_bytes(); - assert_eq!(be_bytes, resulting_bytes); - } - - #[test] - fn uint256_from_be_bytes() { - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(0u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 42, - ]); - assert_eq!(a, Uint256::from(42u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, - ]); - assert_eq!(a, Uint256::from(1u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, - ]); - assert_eq!(a, Uint256::from(256u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, - ]); - assert_eq!(a, Uint256::from(65536u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(16777216u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(4294967296u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1099511627776u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(281474976710656u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(72057594037927936u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(18446744073709551616u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(4722366482869645213696u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1208925819614629174706176u128)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1329227995784915872903807060280344576u128)); - - // Values > u128::MAX - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 16)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 17)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 18)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 19)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 20)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 21)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 22)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 23)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 24)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 25)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 26)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 27)); - let a = Uint256::from_be_bytes([ - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 28)); - let a = Uint256::from_be_bytes([ - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 29)); - let a = Uint256::from_be_bytes([ - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 30)); - let a = Uint256::from_be_bytes([ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 31)); - } - - #[test] - fn uint256_from_le_bytes() { - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(0u128)); - let a = Uint256::from_le_bytes([ - 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(42u128)); - let a = Uint256::from_le_bytes([ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128)); - let a = Uint256::from_le_bytes([ - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(256u128)); - let a = Uint256::from_le_bytes([ - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(65536u128)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(16777216u128)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(4294967296u128)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(72057594037927936u128)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(18446744073709551616u128)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1329227995784915872903807060280344576u128)); - - // Values > u128::MAX - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 16)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 17)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 18)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 19)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 20)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 21)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 22)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 23)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 24)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 25)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 26)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 27)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 28)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 29)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 30)); - let a = Uint256::from_le_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, - ]); - assert_eq!(a, Uint256::from(1u128) << (8 * 31)); - } - - #[test] - fn uint256_endianness() { - let be_bytes = [ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8, - ]; - let le_bytes = [ - 3u8, 2u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ]; - - // These should all be the same. - let num1 = Uint256::new(be_bytes); - let num2 = Uint256::from_be_bytes(be_bytes); - let num3 = Uint256::from_le_bytes(le_bytes); - assert_eq!(num1, Uint256::from(65536u32 + 512 + 3)); - assert_eq!(num1, num2); - assert_eq!(num1, num3); - } - - #[test] - fn uint256_convert_from() { - let a = Uint256::from(5u128); - assert_eq!(a.0, U256::from(5)); - - let a = Uint256::from(5u64); - assert_eq!(a.0, U256::from(5)); - - let a = Uint256::from(5u32); - assert_eq!(a.0, U256::from(5)); - - let a = Uint256::from(5u16); - assert_eq!(a.0, U256::from(5)); - - let a = Uint256::from(5u8); - assert_eq!(a.0, U256::from(5)); - - let result = Uint256::try_from("34567"); - assert_eq!(result.unwrap().0, U256::from_dec_str("34567").unwrap()); - - let result = Uint256::try_from("1.23"); - assert!(result.is_err()); - } - - #[test] - fn uint256_convert_to_uint128() { - let source = Uint256::from(42u128); - let target = Uint128::try_from(source); - assert_eq!(target, Ok(Uint128::new(42u128))); - - let source = Uint256::MAX; - let target = Uint128::try_from(source); - assert_eq!( - target, - Err(ConversionOverflowError::new( - "Uint256", - "Uint128", - Uint256::MAX.to_string() - )) - ); - } - - #[test] - fn uint256_from_uint128() { - assert_eq!( - Uint256::from_uint128(Uint128::new(123)), - Uint256::from_str("123").unwrap() - ); - - assert_eq!( - Uint256::from_uint128(Uint128::new(9785746283745)), - Uint256::from_str("9785746283745").unwrap() - ); - } - - #[test] - fn uint256_implements_display() { - let a = Uint256::from(12345u32); - assert_eq!(format!("Embedded: {}", a), "Embedded: 12345"); - assert_eq!(a.to_string(), "12345"); - - let a = Uint256::zero(); - assert_eq!(format!("Embedded: {}", a), "Embedded: 0"); - assert_eq!(a.to_string(), "0"); - } - - #[test] - fn uint256_display_padding_works() { - let a = Uint256::from(123u64); - assert_eq!(format!("Embedded: {:05}", a), "Embedded: 00123"); - } - - #[test] - fn uint256_to_be_bytes_works() { - assert_eq!( - Uint256::zero().to_be_bytes(), - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ] - ); - assert_eq!( - Uint256::MAX.to_be_bytes(), - [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - ] - ); - assert_eq!( - Uint256::from(1u128).to_be_bytes(), - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1 - ] - ); - // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(32, "big")]` - assert_eq!( - Uint256::from(240282366920938463463374607431768124608u128).to_be_bytes(), - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 196, 179, 87, 165, 121, 59, - 133, 246, 117, 221, 191, 255, 254, 172, 192 - ] - ); - assert_eq!( - Uint256::from_be_bytes([ - 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134, 238, 119, 85, 22, 14, - 88, 166, 195, 154, 73, 64, 10, 44, 252, 96, 230, 187, 38, 29 - ]) - .to_be_bytes(), - [ - 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134, 238, 119, 85, 22, 14, - 88, 166, 195, 154, 73, 64, 10, 44, 252, 96, 230, 187, 38, 29 - ] - ); - } - - #[test] - fn uint256_to_le_bytes_works() { - assert_eq!( - Uint256::zero().to_le_bytes(), - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 - ] - ); - assert_eq!( - Uint256::MAX.to_le_bytes(), - [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff - ] - ); - assert_eq!( - Uint256::from(1u128).to_le_bytes(), - [ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0 - ] - ); - // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(32, "little")]` - assert_eq!( - Uint256::from(240282366920938463463374607431768124608u128).to_le_bytes(), - [ - 192, 172, 254, 255, 191, 221, 117, 246, 133, 59, 121, 165, 87, 179, 196, 180, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - assert_eq!( - Uint256::from_be_bytes([ - 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134, 238, 119, 85, 22, 14, - 88, 166, 195, 154, 73, 64, 10, 44, 252, 96, 230, 187, 38, 29 - ]) - .to_le_bytes(), - [ - 29, 38, 187, 230, 96, 252, 44, 10, 64, 73, 154, 195, 166, 88, 14, 22, 85, 119, 238, - 134, 208, 45, 106, 88, 218, 240, 150, 115, 200, 240, 2, 233 - ] - ); - } - - #[test] - fn uint256_is_zero_works() { - assert!(Uint256::zero().is_zero()); - assert!(Uint256(U256::from(0)).is_zero()); - - assert!(!Uint256::from(1u32).is_zero()); - assert!(!Uint256::from(123u32).is_zero()); - } - - #[test] - fn uint256_json() { - let orig = Uint256::from(1234567890987654321u128); - let serialized = to_vec(&orig).unwrap(); - assert_eq!(serialized.as_slice(), b"\"1234567890987654321\""); - let parsed: Uint256 = from_slice(&serialized).unwrap(); - assert_eq!(parsed, orig); - } - - #[test] - fn uint256_compare() { - let a = Uint256::from(12345u32); - let b = Uint256::from(23456u32); - - assert!(a < b); - assert!(b > a); - assert_eq!(a, Uint256::from(12345u32)); - } - - #[test] - #[allow(clippy::op_ref)] - fn uint256_math() { - let a = Uint256::from(12345u32); - let b = Uint256::from(23456u32); - - // test + with owned and reference right hand side - assert_eq!(a + b, Uint256::from(35801u32)); - assert_eq!(a + &b, Uint256::from(35801u32)); - - // test - with owned and reference right hand side - assert_eq!(b - a, Uint256::from(11111u32)); - assert_eq!(b - &a, Uint256::from(11111u32)); - - // test += with owned and reference right hand side - let mut c = Uint256::from(300000u32); - c += b; - assert_eq!(c, Uint256::from(323456u32)); - let mut d = Uint256::from(300000u32); - d += &b; - assert_eq!(d, Uint256::from(323456u32)); - - // test -= with owned and reference right hand side - let mut c = Uint256::from(300000u32); - c -= b; - assert_eq!(c, Uint256::from(276544u32)); - let mut d = Uint256::from(300000u32); - d -= &b; - assert_eq!(d, Uint256::from(276544u32)); - - // error result on underflow (- would produce negative result) - let underflow_result = a.checked_sub(b); - let OverflowError { - operand1, operand2, .. - } = underflow_result.unwrap_err(); - assert_eq!((operand1, operand2), (a.to_string(), b.to_string())); - } - - #[test] - #[should_panic] - fn uint256_add_overflow_panics() { - let max = Uint256::new([255u8; 32]); - let _ = max + Uint256::from(12u32); - } - - #[test] - #[should_panic] - fn uint256_sub_overflow_panics() { - let _ = Uint256::from(1u32) - Uint256::from(2u32); - } - - #[test] - fn uint256_multiply_ratio_works() { - let base = Uint256::from(500u32); - - // factor 1/1 - assert_eq!(base.multiply_ratio(1u128, 1u128), base); - assert_eq!(base.multiply_ratio(3u128, 3u128), base); - assert_eq!(base.multiply_ratio(654321u128, 654321u128), base); - assert_eq!(base.multiply_ratio(Uint256::MAX, Uint256::MAX), base); - - // factor 3/2 - assert_eq!(base.multiply_ratio(3u128, 2u128), Uint256::from(750u32)); - assert_eq!( - base.multiply_ratio(333333u128, 222222u128), - Uint256::from(750u32) - ); - - // factor 2/3 (integer devision always floors the result) - assert_eq!(base.multiply_ratio(2u128, 3u128), Uint256::from(333u32)); - assert_eq!( - base.multiply_ratio(222222u128, 333333u128), - Uint256::from(333u32) - ); - - // factor 5/6 (integer devision always floors the result) - assert_eq!(base.multiply_ratio(5u128, 6u128), Uint256::from(416u32)); - assert_eq!(base.multiply_ratio(100u128, 120u128), Uint256::from(416u32)); - } - - #[test] - fn uint256_multiply_ratio_does_not_overflow_when_result_fits() { - // Almost max value for Uint256. - let base = Uint256::MAX - Uint256::from(9u8); - - assert_eq!(base.multiply_ratio(2u128, 2u128), base); - } - - #[test] - #[should_panic] - fn uint256_multiply_ratio_panicks_on_overflow() { - // Almost max value for Uint256. - let base = Uint256::MAX - Uint256::from(9u8); - - assert_eq!(base.multiply_ratio(2u128, 1u128), base); - } - - #[test] - #[should_panic(expected = "Denominator must not be zero")] - fn uint256_multiply_ratio_panics_for_zero_denominator() { - Uint256::from(500u32).multiply_ratio(1u128, 0u128); - } - - #[test] - fn uint256_shr_works() { - let original = Uint256::new([ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8, - ]); - - let shifted = Uint256::new([ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8, - ]); - - assert_eq!(original >> 2u32, shifted); - } - - #[test] - #[should_panic] - fn uint256_shr_overflow_panics() { - let _ = Uint256::from(1u32) >> 256u32; - } - - #[test] - fn sum_works() { - let nums = vec![ - Uint256::from(17u32), - Uint256::from(123u32), - Uint256::from(540u32), - Uint256::from(82u32), - ]; - let expected = Uint256::from(762u32); - - let sum_as_ref = nums.iter().sum(); - assert_eq!(expected, sum_as_ref); - - let sum_as_owned = nums.into_iter().sum(); - assert_eq!(expected, sum_as_owned); - } - - #[test] - fn uint256_methods() { - // checked_* - assert!(matches!( - Uint256::MAX.checked_add(Uint256::from(1u32)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint256::from(0u32).checked_sub(Uint256::from(1u32)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint256::MAX.checked_mul(Uint256::from(2u32)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint256::MAX.checked_div(Uint256::from(0u32)), - Err(DivideByZeroError { .. }) - )); - assert!(matches!( - Uint256::MAX.checked_rem(Uint256::from(0u32)), - Err(DivideByZeroError { .. }) - )); - - // saturating_* - assert_eq!( - Uint256::MAX.saturating_add(Uint256::from(1u32)), - Uint256::MAX - ); - assert_eq!( - Uint256::from(0u32).saturating_sub(Uint256::from(1u32)), - Uint256::from(0u32) - ); - assert_eq!( - Uint256::MAX.saturating_mul(Uint256::from(2u32)), - Uint256::MAX - ); - } -} diff --git a/packages/cosmwasm_math_compat/src/math/uint512.rs b/packages/cosmwasm_math_compat/src/math/uint512.rs deleted file mode 100644 index 622b720..0000000 --- a/packages/cosmwasm_math_compat/src/math/uint512.rs +++ /dev/null @@ -1,1060 +0,0 @@ -use schemars::JsonSchema; -use serde::{de, ser, Deserialize, Deserializer, Serialize}; -use std::{ - convert::{TryFrom, TryInto}, - fmt, - ops::{self, Shr}, - str::FromStr, -}; - -use crate::{ - errors::{ - ConversionOverflowError, - DivideByZeroError, - OverflowError, - OverflowOperation, - StdError, - }, - Uint128, - Uint256, - Uint64, -}; - -/// This module is purely a workaround that lets us ignore lints for all the code -/// the `construct_uint!` macro generates. -#[allow(clippy::all)] -mod uints { - uint::construct_uint! { - pub struct U512(8); - } -} - -/// Used internally - we don't want to leak this type since we might change -/// the implementation in the future. -use uints::U512; - -/// An implementation of u512 that is using strings for JSON encoding/decoding, -/// such that the full u512 range can be used for clients that convert JSON numbers to floats, -/// like JavaScript and jq. -/// -/// # Examples -/// -/// Use `from` to create instances out of primitive uint types or `new` to provide big -/// endian bytes: -/// -/// ``` -/// # use cosmwasm_math::Uint512; -/// let a = Uint512::from(258u128); -/// let b = Uint512::new([ -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, -/// 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, -/// ]); -/// assert_eq!(a, b); -/// ``` -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] -pub struct Uint512(#[schemars(with = "String")] U512); - -impl Uint512 { - pub const MAX: Uint512 = Uint512(U512::MAX); - - /// Creates a Uint512(value) from a big endian representation. It's just an alias for - /// `from_big_endian`. - pub fn new(value: [u8; 64]) -> Self { - Self::from_be_bytes(value) - } - - /// Creates a Uint512(0) - pub const fn zero() -> Self { - Uint512(U512::zero()) - } - - pub const fn from_be_bytes(data: [u8; 64]) -> Self { - let words: [u64; 8] = [ - u64::from_le_bytes([ - data[63], data[62], data[61], data[60], data[59], data[58], data[57], data[56], - ]), - u64::from_le_bytes([ - data[55], data[54], data[53], data[52], data[51], data[50], data[49], data[48], - ]), - u64::from_le_bytes([ - data[47], data[46], data[45], data[44], data[43], data[42], data[41], data[40], - ]), - u64::from_le_bytes([ - data[39], data[38], data[37], data[36], data[35], data[34], data[33], data[32], - ]), - u64::from_le_bytes([ - data[31], data[30], data[29], data[28], data[27], data[26], data[25], data[24], - ]), - u64::from_le_bytes([ - data[23], data[22], data[21], data[20], data[19], data[18], data[17], data[16], - ]), - u64::from_le_bytes([ - data[15], data[14], data[13], data[12], data[11], data[10], data[9], data[8], - ]), - u64::from_le_bytes([ - data[7], data[6], data[5], data[4], data[3], data[2], data[1], data[0], - ]), - ]; - Self(U512(words)) - } - - pub const fn from_le_bytes(data: [u8; 64]) -> Self { - let words: [u64; 8] = [ - u64::from_le_bytes([ - data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], - ]), - u64::from_le_bytes([ - data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], - ]), - u64::from_le_bytes([ - data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], - ]), - u64::from_le_bytes([ - data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], - ]), - u64::from_le_bytes([ - data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39], - ]), - u64::from_le_bytes([ - data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], - ]), - u64::from_le_bytes([ - data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], - ]), - u64::from_le_bytes([ - data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63], - ]), - ]; - Self(U512(words)) - } - - /// A conversion from `Uint256` that, unlike the one provided by the `From` trait, - /// can be used in a `const` context. - pub const fn from_uint256(num: Uint256) -> Self { - let bytes = num.to_le_bytes(); - Self::from_le_bytes([ - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], - bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], - bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23], - bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31], - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]) - } - - /// Returns a copy of the number as big endian bytes. - pub const fn to_be_bytes(self) -> [u8; 64] { - let words = [ - (self.0).0[7].to_be_bytes(), - (self.0).0[6].to_be_bytes(), - (self.0).0[5].to_be_bytes(), - (self.0).0[4].to_be_bytes(), - (self.0).0[3].to_be_bytes(), - (self.0).0[2].to_be_bytes(), - (self.0).0[1].to_be_bytes(), - (self.0).0[0].to_be_bytes(), - ]; - - // In Rust 1.56+ we can use `unsafe { std::mem::transmute::<[[u8; 8]; 8], [u8; 64]>(words) }` for this - [ - words[0][0], - words[0][1], - words[0][2], - words[0][3], - words[0][4], - words[0][5], - words[0][6], - words[0][7], - words[1][0], - words[1][1], - words[1][2], - words[1][3], - words[1][4], - words[1][5], - words[1][6], - words[1][7], - words[2][0], - words[2][1], - words[2][2], - words[2][3], - words[2][4], - words[2][5], - words[2][6], - words[2][7], - words[3][0], - words[3][1], - words[3][2], - words[3][3], - words[3][4], - words[3][5], - words[3][6], - words[3][7], - words[4][0], - words[4][1], - words[4][2], - words[4][3], - words[4][4], - words[4][5], - words[4][6], - words[4][7], - words[5][0], - words[5][1], - words[5][2], - words[5][3], - words[5][4], - words[5][5], - words[5][6], - words[5][7], - words[6][0], - words[6][1], - words[6][2], - words[6][3], - words[6][4], - words[6][5], - words[6][6], - words[6][7], - words[7][0], - words[7][1], - words[7][2], - words[7][3], - words[7][4], - words[7][5], - words[7][6], - words[7][7], - ] - } - - /// Returns a copy of the number as little endian bytes. - pub const fn to_le_bytes(self) -> [u8; 64] { - let words = [ - (self.0).0[0].to_le_bytes(), - (self.0).0[1].to_le_bytes(), - (self.0).0[2].to_le_bytes(), - (self.0).0[3].to_le_bytes(), - (self.0).0[4].to_le_bytes(), - (self.0).0[5].to_le_bytes(), - (self.0).0[6].to_le_bytes(), - (self.0).0[7].to_le_bytes(), - ]; - - // In Rust 1.56+ we can use `unsafe { std::mem::transmute::<[[u8; 8]; 8], [u8; 64]>(words) }` for this - [ - words[0][0], - words[0][1], - words[0][2], - words[0][3], - words[0][4], - words[0][5], - words[0][6], - words[0][7], - words[1][0], - words[1][1], - words[1][2], - words[1][3], - words[1][4], - words[1][5], - words[1][6], - words[1][7], - words[2][0], - words[2][1], - words[2][2], - words[2][3], - words[2][4], - words[2][5], - words[2][6], - words[2][7], - words[3][0], - words[3][1], - words[3][2], - words[3][3], - words[3][4], - words[3][5], - words[3][6], - words[3][7], - words[4][0], - words[4][1], - words[4][2], - words[4][3], - words[4][4], - words[4][5], - words[4][6], - words[4][7], - words[5][0], - words[5][1], - words[5][2], - words[5][3], - words[5][4], - words[5][5], - words[5][6], - words[5][7], - words[6][0], - words[6][1], - words[6][2], - words[6][3], - words[6][4], - words[6][5], - words[6][6], - words[6][7], - words[7][0], - words[7][1], - words[7][2], - words[7][3], - words[7][4], - words[7][5], - words[7][6], - words[7][7], - ] - } - - pub fn is_zero(&self) -> bool { - self.0.is_zero() - } - - pub fn checked_add(self, other: Self) -> Result { - self.0 - .checked_add(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Add, self, other)) - } - - pub fn checked_sub(self, other: Self) -> Result { - self.0 - .checked_sub(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Sub, self, other)) - } - - pub fn checked_mul(self, other: Self) -> Result { - self.0 - .checked_mul(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other)) - } - - pub fn checked_div(self, other: Self) -> Result { - self.0 - .checked_div(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_rem(self, other: Self) -> Result { - self.0 - .checked_rem(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_shr(self, other: u32) -> Result { - if other >= 512 { - return Err(OverflowError::new(OverflowOperation::Shr, self, other)); - } - - Ok(Self(self.0.shr(other))) - } - - pub fn saturating_add(self, other: Self) -> Self { - Self(self.0.saturating_add(other.0)) - } - - pub fn saturating_sub(self, other: Self) -> Self { - Self(self.0.saturating_sub(other.0)) - } - - pub fn saturating_mul(self, other: Self) -> Self { - Self(self.0.saturating_mul(other.0)) - } -} - -impl From for Uint512 { - fn from(val: Uint256) -> Self { - let bytes = [[0u8; 32], val.to_be_bytes()].concat(); - - Self::from_be_bytes(bytes.try_into().unwrap()) - } -} - -impl From for Uint512 { - fn from(val: Uint128) -> Self { - val.u128().into() - } -} - -impl From for Uint512 { - fn from(val: Uint64) -> Self { - val.u64().into() - } -} - -impl From for Uint512 { - fn from(val: u128) -> Self { - Uint512(val.into()) - } -} - -impl From for Uint512 { - fn from(val: u64) -> Self { - Uint512(val.into()) - } -} - -impl From for Uint512 { - fn from(val: u32) -> Self { - Uint512(val.into()) - } -} - -impl From for Uint512 { - fn from(val: u16) -> Self { - Uint512(val.into()) - } -} - -impl From for Uint512 { - fn from(val: u8) -> Self { - Uint512(val.into()) - } -} - -impl TryFrom for Uint256 { - type Error = ConversionOverflowError; - - fn try_from(value: Uint512) -> Result { - let bytes = value.to_be_bytes(); - let (first_bytes, last_bytes) = bytes.split_at(32); - - if first_bytes != [0u8; 32] { - return Err(ConversionOverflowError::new( - "Uint512", - "Uint256", - value.to_string(), - )); - } - - Ok(Self::from_be_bytes(last_bytes.try_into().unwrap())) - } -} - -impl TryFrom for Uint128 { - type Error = ConversionOverflowError; - - fn try_from(value: Uint512) -> Result { - Ok(Uint128::new(value.0.try_into().map_err(|_| { - ConversionOverflowError::new("Uint512", "Uint128", value.to_string()) - })?)) - } -} - -impl TryFrom<&str> for Uint512 { - type Error = StdError; - - fn try_from(val: &str) -> Result { - Self::from_str(val) - } -} - -impl FromStr for Uint512 { - type Err = StdError; - - fn from_str(s: &str) -> Result { - match U512::from_dec_str(s) { - Ok(u) => Ok(Self(u)), - Err(e) => Err(StdError::generic_err(format!("Parsing u512: {}", e))), - } - } -} - -impl From for String { - fn from(original: Uint512) -> Self { - original.to_string() - } -} - -impl fmt::Display for Uint512 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // The inner type doesn't work as expected with padding, so we - // work around that. - let unpadded = self.0.to_string(); - - f.pad_integral(true, "", &unpadded) - } -} - -impl ops::Add for Uint512 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Uint512(self.0.checked_add(rhs.0).unwrap()) - } -} - -impl<'a> ops::Add<&'a Uint512> for Uint512 { - type Output = Self; - - fn add(self, rhs: &'a Uint512) -> Self { - Uint512(self.0.checked_add(rhs.0).unwrap()) - } -} - -impl ops::Sub for Uint512 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - Uint512(self.0.checked_sub(rhs.0).unwrap()) - } -} - -impl<'a> ops::Sub<&'a Uint512> for Uint512 { - type Output = Self; - - fn sub(self, rhs: &'a Uint512) -> Self { - Uint512(self.0.checked_sub(rhs.0).unwrap()) - } -} - -impl ops::Div for Uint512 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - Self(self.0.checked_div(rhs.0).unwrap()) - } -} - -impl<'a> ops::Div<&'a Uint512> for Uint512 { - type Output = Self; - - fn div(self, rhs: &'a Uint512) -> Self::Output { - Self(self.0.checked_div(rhs.0).unwrap()) - } -} - -impl ops::Mul for Uint512 { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Self(self.0.checked_mul(rhs.0).unwrap()) - } -} - -impl<'a> ops::Mul<&'a Uint512> for Uint512 { - type Output = Self; - - fn mul(self, rhs: &'a Uint512) -> Self::Output { - Self(self.0.checked_mul(rhs.0).unwrap()) - } -} - -impl ops::Shr for Uint512 { - type Output = Self; - - fn shr(self, rhs: u32) -> Self::Output { - self.checked_shr(rhs).unwrap_or_else(|_| { - panic!( - "right shift error: {} is larger or equal than the number of bits in Uint512", - rhs, - ) - }) - } -} - -impl<'a> ops::Shr<&'a u32> for Uint512 { - type Output = Self; - - fn shr(self, rhs: &'a u32) -> Self::Output { - Shr::::shr(self, *rhs) - } -} - -impl ops::AddAssign for Uint512 { - fn add_assign(&mut self, rhs: Uint512) { - self.0 = self.0.checked_add(rhs.0).unwrap(); - } -} - -impl<'a> ops::AddAssign<&'a Uint512> for Uint512 { - fn add_assign(&mut self, rhs: &'a Uint512) { - self.0 = self.0.checked_add(rhs.0).unwrap(); - } -} - -impl ops::SubAssign for Uint512 { - fn sub_assign(&mut self, rhs: Uint512) { - self.0 = self.0.checked_sub(rhs.0).unwrap(); - } -} - -impl<'a> ops::SubAssign<&'a Uint512> for Uint512 { - fn sub_assign(&mut self, rhs: &'a Uint512) { - self.0 = self.0.checked_sub(rhs.0).unwrap(); - } -} - -impl ops::DivAssign for Uint512 { - fn div_assign(&mut self, rhs: Self) { - self.0 = self.0.checked_div(rhs.0).unwrap(); - } -} - -impl<'a> ops::DivAssign<&'a Uint512> for Uint512 { - fn div_assign(&mut self, rhs: &'a Uint512) { - self.0 = self.0.checked_div(rhs.0).unwrap(); - } -} - -impl ops::MulAssign for Uint512 { - fn mul_assign(&mut self, rhs: Self) { - self.0 = self.0.checked_mul(rhs.0).unwrap(); - } -} - -impl<'a> ops::MulAssign<&'a Uint512> for Uint512 { - fn mul_assign(&mut self, rhs: &'a Uint512) { - self.0 = self.0.checked_mul(rhs.0).unwrap(); - } -} - -impl ops::ShrAssign for Uint512 { - fn shr_assign(&mut self, rhs: u32) { - *self = Shr::::shr(*self, rhs); - } -} - -impl<'a> ops::ShrAssign<&'a u32> for Uint512 { - fn shr_assign(&mut self, rhs: &'a u32) { - *self = Shr::::shr(*self, *rhs); - } -} - -impl Serialize for Uint512 { - /// Serializes as an integer string using base 10 - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl<'de> Deserialize<'de> for Uint512 { - /// Deserialized from an integer string using base 10 - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Uint512Visitor) - } -} - -struct Uint512Visitor; - -impl<'de> de::Visitor<'de> for Uint512Visitor { - type Value = Uint512; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("string-encoded integer") - } - - fn visit_str(self, v: &str) -> Result - where - E: de::Error, - { - Uint512::try_from(v).map_err(|e| E::custom(format!("invalid Uint512 '{}' - {}", v, e))) - } -} - -impl std::iter::Sum for Uint512 -where - Self: ops::Add, -{ - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), ops::Add::add) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::{from_slice, to_vec}; - - #[test] - fn uint512_construct() { - let num = Uint512::new([1; 64]); - let a: [u8; 64] = num.to_be_bytes(); - assert_eq!(a, [1; 64]); - - let be_bytes = [ - 0u8, 222u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8, - ]; - let num = Uint512::new(be_bytes); - let resulting_bytes: [u8; 64] = num.to_be_bytes(); - assert_eq!(be_bytes, resulting_bytes); - } - - #[test] - fn uint512_endianness() { - let be_bytes = [ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8, - ]; - let le_bytes = [ - 3u8, 2u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - ]; - - // These should all be the same. - let num1 = Uint512::new(be_bytes); - let num2 = Uint512::from_be_bytes(be_bytes); - let num3 = Uint512::from_le_bytes(le_bytes); - assert_eq!(num1, Uint512::from(65536u32 + 512 + 3)); - assert_eq!(num1, num2); - assert_eq!(num1, num3); - } - - #[test] - fn uint512_convert_from() { - let a = Uint512::from(5u128); - assert_eq!(a.0, U512::from(5)); - - let a = Uint512::from(5u64); - assert_eq!(a.0, U512::from(5)); - - let a = Uint512::from(5u32); - assert_eq!(a.0, U512::from(5)); - - let a = Uint512::from(5u16); - assert_eq!(a.0, U512::from(5)); - - let a = Uint512::from(5u8); - assert_eq!(a.0, U512::from(5)); - - let result = Uint512::try_from("34567"); - assert_eq!(result.unwrap().0, U512::from_dec_str("34567").unwrap()); - - let result = Uint512::try_from("1.23"); - assert!(result.is_err()); - } - - #[test] - fn uint512_convert_to_uint128() { - let source = Uint512::from(42u128); - let target = Uint128::try_from(source); - assert_eq!(target, Ok(Uint128::new(42u128))); - - let source = Uint512::MAX; - let target = Uint128::try_from(source); - assert_eq!( - target, - Err(ConversionOverflowError::new( - "Uint512", - "Uint128", - Uint512::MAX.to_string() - )) - ); - } - - #[test] - fn uint512_from_uint256() { - assert_eq!( - Uint512::from_uint256(Uint256::from_str("123").unwrap()), - Uint512::from_str("123").unwrap() - ); - - assert_eq!( - Uint512::from_uint256(Uint256::from_str("9785746283745").unwrap()), - Uint512::from_str("9785746283745").unwrap() - ); - - assert_eq!( - Uint512::from_uint256( - Uint256::from_str( - "97857462837575757832978493758398593853985452378423874623874628736482736487236" - ) - .unwrap() - ), - Uint512::from_str( - "97857462837575757832978493758398593853985452378423874623874628736482736487236" - ) - .unwrap() - ); - } - - #[test] - fn uint512_implements_display() { - let a = Uint512::from(12345u32); - assert_eq!(format!("Embedded: {}", a), "Embedded: 12345"); - assert_eq!(a.to_string(), "12345"); - - let a = Uint512::zero(); - assert_eq!(format!("Embedded: {}", a), "Embedded: 0"); - assert_eq!(a.to_string(), "0"); - } - - #[test] - fn uint512_display_padding_works() { - let a = Uint512::from(123u64); - assert_eq!(format!("Embedded: {:05}", a), "Embedded: 00123"); - } - - #[test] - fn uint512_to_be_bytes_works() { - assert_eq!(Uint512::zero().to_be_bytes(), [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ]); - assert_eq!(Uint512::MAX.to_be_bytes(), [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - ]); - assert_eq!(Uint512::from(1u128).to_be_bytes(), [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1 - ]); - // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(64, "big")]` - assert_eq!( - Uint512::from(240282366920938463463374607431768124608u128).to_be_bytes(), - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 196, 179, 87, 165, - 121, 59, 133, 246, 117, 221, 191, 255, 254, 172, 192 - ] - ); - assert_eq!( - Uint512::from_be_bytes([ - 17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54, - 211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134, - 238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8, - 252, 96, 230, 187, 38, 29 - ]) - .to_be_bytes(), - [ - 17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54, - 211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134, - 238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8, - 252, 96, 230, 187, 38, 29 - ] - ); - } - - #[test] - fn uint512_to_le_bytes_works() { - assert_eq!(Uint512::zero().to_le_bytes(), [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 - ]); - assert_eq!(Uint512::MAX.to_le_bytes(), [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - ]); - assert_eq!(Uint512::from(1u128).to_le_bytes(), [ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 - ]); - // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(64, "little")]` - assert_eq!( - Uint512::from(240282366920938463463374607431768124608u128).to_le_bytes(), - [ - 192, 172, 254, 255, 191, 221, 117, 246, 133, 59, 121, 165, 87, 179, 196, 180, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ] - ); - assert_eq!( - Uint512::from_be_bytes([ - 17, 4, 23, 32, 87, 67, 123, 200, 58, 91, 0, 38, 33, 21, 67, 78, 87, 76, 65, 54, - 211, 201, 192, 7, 42, 233, 2, 240, 200, 115, 150, 240, 218, 88, 106, 45, 208, 134, - 238, 119, 85, 22, 14, 88, 166, 195, 154, 73, 64, 10, 44, 59, 13, 22, 47, 12, 99, 8, - 252, 96, 230, 187, 38, 29 - ]) - .to_le_bytes(), - [ - 29, 38, 187, 230, 96, 252, 8, 99, 12, 47, 22, 13, 59, 44, 10, 64, 73, 154, 195, - 166, 88, 14, 22, 85, 119, 238, 134, 208, 45, 106, 88, 218, 240, 150, 115, 200, 240, - 2, 233, 42, 7, 192, 201, 211, 54, 65, 76, 87, 78, 67, 21, 33, 38, 0, 91, 58, 200, - 123, 67, 87, 32, 23, 4, 17 - ] - ); - } - - #[test] - fn uint512_is_zero_works() { - assert!(Uint512::zero().is_zero()); - assert!(Uint512(U512::from(0)).is_zero()); - - assert!(!Uint512::from(1u32).is_zero()); - assert!(!Uint512::from(123u32).is_zero()); - } - - #[test] - fn uint512_json() { - let orig = Uint512::from(1234567890987654321u128); - let serialized = to_vec(&orig).unwrap(); - assert_eq!(serialized.as_slice(), b"\"1234567890987654321\""); - let parsed: Uint512 = from_slice(&serialized).unwrap(); - assert_eq!(parsed, orig); - } - - #[test] - fn uint512_compare() { - let a = Uint512::from(12345u32); - let b = Uint512::from(23456u32); - - assert!(a < b); - assert!(b > a); - assert_eq!(a, Uint512::from(12345u32)); - } - - #[test] - #[allow(clippy::op_ref)] - fn uint512_math() { - let a = Uint512::from(12345u32); - let b = Uint512::from(23456u32); - - // test + with owned and reference right hand side - assert_eq!(a + b, Uint512::from(35801u32)); - assert_eq!(a + &b, Uint512::from(35801u32)); - - // test - with owned and reference right hand side - assert_eq!(b - a, Uint512::from(11111u32)); - assert_eq!(b - &a, Uint512::from(11111u32)); - - // test += with owned and reference right hand side - let mut c = Uint512::from(300000u32); - c += b; - assert_eq!(c, Uint512::from(323456u32)); - let mut d = Uint512::from(300000u32); - d += &b; - assert_eq!(d, Uint512::from(323456u32)); - - // test -= with owned and reference right hand side - let mut c = Uint512::from(300000u32); - c -= b; - assert_eq!(c, Uint512::from(276544u32)); - let mut d = Uint512::from(300000u32); - d -= &b; - assert_eq!(d, Uint512::from(276544u32)); - - // error result on underflow (- would produce negative result) - let underflow_result = a.checked_sub(b); - let OverflowError { - operand1, operand2, .. - } = underflow_result.unwrap_err(); - assert_eq!((operand1, operand2), (a.to_string(), b.to_string())); - } - - #[test] - #[should_panic] - fn uint512_add_overflow_panics() { - let max = Uint512::new([255u8; 64]); - let _ = max + Uint512::from(12u32); - } - - #[test] - #[should_panic] - fn uint512_sub_overflow_panics() { - let _ = Uint512::from(1u32) - Uint512::from(2u32); - } - - #[test] - fn uint512_shr_works() { - let original = Uint512::new([ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 4u8, 2u8, - ]); - - let shifted = Uint512::new([ - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, - 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 128u8, 1u8, 0u8, - ]); - - assert_eq!(original >> 2u32, shifted); - } - - #[test] - #[should_panic] - fn uint512_shr_overflow_panics() { - let _ = Uint512::from(1u32) >> 512u32; - } - - #[test] - fn sum_works() { - let nums = vec![ - Uint512::from(17u32), - Uint512::from(123u32), - Uint512::from(540u32), - Uint512::from(82u32), - ]; - let expected = Uint512::from(762u32); - - let sum_as_ref = nums.iter().sum(); - assert_eq!(expected, sum_as_ref); - - let sum_as_owned = nums.into_iter().sum(); - assert_eq!(expected, sum_as_owned); - } - - #[test] - fn uint512_methods() { - // checked_* - assert!(matches!( - Uint512::MAX.checked_add(Uint512::from(1u32)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint512::from(0u32).checked_sub(Uint512::from(1u32)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint512::MAX.checked_mul(Uint512::from(2u32)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint512::MAX.checked_div(Uint512::from(0u32)), - Err(DivideByZeroError { .. }) - )); - assert!(matches!( - Uint512::MAX.checked_rem(Uint512::from(0u32)), - Err(DivideByZeroError { .. }) - )); - - // saturating_* - assert_eq!( - Uint512::MAX.saturating_add(Uint512::from(1u32)), - Uint512::MAX - ); - assert_eq!( - Uint512::from(0u32).saturating_sub(Uint512::from(1u32)), - Uint512::from(0u32) - ); - assert_eq!( - Uint512::MAX.saturating_mul(Uint512::from(2u32)), - Uint512::MAX - ); - } -} diff --git a/packages/cosmwasm_math_compat/src/math/uint64.rs b/packages/cosmwasm_math_compat/src/math/uint64.rs deleted file mode 100644 index d047980..0000000 --- a/packages/cosmwasm_math_compat/src/math/uint64.rs +++ /dev/null @@ -1,616 +0,0 @@ -use schemars::JsonSchema; -use serde::{de, ser, Deserialize, Deserializer, Serialize}; -use std::{ - convert::{TryFrom, TryInto}, - fmt::{self}, - ops, -}; - -use crate::{ - errors::{DivideByZeroError, OverflowError, OverflowOperation, StdError}, - Uint128, -}; - -/// A thin wrapper around u64 that is using strings for JSON encoding/decoding, -/// such that the full u64 range can be used for clients that convert JSON numbers to floats, -/// like JavaScript and jq. -/// -/// # Examples -/// -/// Use `from` to create instances of this and `u64` to get the value out: -/// -/// ``` -/// # use cosmwasm_math::Uint64; -/// let a = Uint64::from(42u64); -/// assert_eq!(a.u64(), 42); -/// -/// let b = Uint64::from(70u32); -/// assert_eq!(b.u64(), 70); -/// ``` -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] -pub struct Uint64(#[schemars(with = "String")] u64); - -impl Uint64 { - pub const MAX: Self = Self(u64::MAX); - - /// Creates a Uint64(value). - /// - /// This method is less flexible than `from` but can be called in a const context. - pub const fn new(value: u64) -> Self { - Uint64(value) - } - - /// Creates a Uint64(0) - pub const fn zero() -> Self { - Uint64(0) - } - - /// Returns a copy of the internal data - pub const fn u64(&self) -> u64 { - self.0 - } - - /// Returns a copy of the number as big endian bytes. - pub const fn to_be_bytes(self) -> [u8; 8] { - self.0.to_be_bytes() - } - - /// Returns a copy of the number as little endian bytes. - pub const fn to_le_bytes(self) -> [u8; 8] { - self.0.to_le_bytes() - } - - pub fn is_zero(&self) -> bool { - self.0 == 0 - } - - pub fn checked_add(self, other: Self) -> Result { - self.0 - .checked_add(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Add, self, other)) - } - - pub fn checked_sub(self, other: Self) -> Result { - self.0 - .checked_sub(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Sub, self, other)) - } - - pub fn checked_mul(self, other: Self) -> Result { - self.0 - .checked_mul(other.0) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other)) - } - - pub fn checked_div(self, other: Self) -> Result { - self.0 - .checked_div(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_div_euclid(self, other: Self) -> Result { - self.0 - .checked_div_euclid(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn checked_rem(self, other: Self) -> Result { - self.0 - .checked_rem(other.0) - .map(Self) - .ok_or_else(|| DivideByZeroError::new(self)) - } - - pub fn wrapping_add(self, other: Self) -> Self { - Self(self.0.wrapping_add(other.0)) - } - - pub fn wrapping_sub(self, other: Self) -> Self { - Self(self.0.wrapping_sub(other.0)) - } - - pub fn wrapping_mul(self, other: Self) -> Self { - Self(self.0.wrapping_mul(other.0)) - } - - pub fn wrapping_pow(self, other: u32) -> Self { - Self(self.0.wrapping_pow(other)) - } - - pub fn saturating_add(self, other: Self) -> Self { - Self(self.0.saturating_add(other.0)) - } - - pub fn saturating_sub(self, other: Self) -> Self { - Self(self.0.saturating_sub(other.0)) - } - - pub fn saturating_mul(self, other: Self) -> Self { - Self(self.0.saturating_mul(other.0)) - } - - pub fn saturating_pow(self, other: u32) -> Self { - Self(self.0.saturating_pow(other)) - } -} - -// `From` is implemented manually instead of -// using `impl> From for Uint64` because -// of the conflict with `TryFrom<&str>` as described here -// https://stackoverflow.com/questions/63136970/how-do-i-work-around-the-upstream-crates-may-add-a-new-impl-of-trait-error - -impl From for Uint64 { - fn from(val: u64) -> Self { - Uint64(val) - } -} - -impl From for Uint64 { - fn from(val: u32) -> Self { - Uint64(val.into()) - } -} - -impl From for Uint64 { - fn from(val: u16) -> Self { - Uint64(val.into()) - } -} - -impl From for Uint64 { - fn from(val: u8) -> Self { - Uint64(val.into()) - } -} - -impl TryFrom<&str> for Uint64 { - type Error = StdError; - - fn try_from(val: &str) -> Result { - match val.parse::() { - Ok(u) => Ok(Uint64(u)), - Err(e) => Err(StdError::generic_err(format!("Parsing u64: {}", e))), - } - } -} - -impl From for String { - fn from(original: Uint64) -> Self { - original.to_string() - } -} - -impl From for u64 { - fn from(original: Uint64) -> Self { - original.0 - } -} - -impl fmt::Display for Uint64 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl ops::Add for Uint64 { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Uint64(self.u64().checked_add(rhs.u64()).unwrap()) - } -} - -impl<'a> ops::Add<&'a Uint64> for Uint64 { - type Output = Self; - - fn add(self, rhs: &'a Uint64) -> Self { - Uint64(self.u64().checked_add(rhs.u64()).unwrap()) - } -} - -impl ops::Div for Uint64 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - Self(self.u64().checked_div(rhs.u64()).unwrap()) - } -} - -impl<'a> ops::Div<&'a Uint64> for Uint64 { - type Output = Self; - - fn div(self, rhs: &'a Uint64) -> Self::Output { - Self(self.u64().checked_div(rhs.u64()).unwrap()) - } -} - -impl ops::Shr for Uint64 { - type Output = Self; - - fn shr(self, rhs: u32) -> Self::Output { - Self(self.u64().checked_shr(rhs).unwrap()) - } -} - -impl<'a> ops::Shr<&'a u32> for Uint64 { - type Output = Self; - - fn shr(self, rhs: &'a u32) -> Self::Output { - Self(self.u64().checked_shr(*rhs).unwrap()) - } -} - -impl ops::AddAssign for Uint64 { - fn add_assign(&mut self, rhs: Uint64) { - self.0 = self.0.checked_add(rhs.u64()).unwrap(); - } -} - -impl<'a> ops::AddAssign<&'a Uint64> for Uint64 { - fn add_assign(&mut self, rhs: &'a Uint64) { - self.0 = self.0.checked_add(rhs.u64()).unwrap(); - } -} - -impl ops::DivAssign for Uint64 { - fn div_assign(&mut self, rhs: Self) { - self.0 = self.0.checked_div(rhs.u64()).unwrap(); - } -} - -impl<'a> ops::DivAssign<&'a Uint64> for Uint64 { - fn div_assign(&mut self, rhs: &'a Uint64) { - self.0 = self.0.checked_div(rhs.u64()).unwrap(); - } -} - -impl ops::ShrAssign for Uint64 { - fn shr_assign(&mut self, rhs: u32) { - self.0 = self.0.checked_shr(rhs).unwrap(); - } -} - -impl<'a> ops::ShrAssign<&'a u32> for Uint64 { - fn shr_assign(&mut self, rhs: &'a u32) { - self.0 = self.0.checked_shr(*rhs).unwrap(); - } -} - -impl Uint64 { - /// Returns `self * numerator / denominator` - pub fn multiply_ratio, B: Into>( - &self, - numerator: A, - denominator: B, - ) -> Uint64 { - let numerator = numerator.into(); - let denominator = denominator.into(); - if denominator == 0 { - panic!("Denominator must not be zero"); - } - - (self.full_mul(numerator) / Uint128::from(denominator)) - .try_into() - .expect("multiplication overflow") - } - - /// Multiplies two `Uint64`/`u64` values without overflow, producing an - /// [`Uint128`]. - /// - /// # Examples - /// - /// ``` - /// use cosmwasm_math::Uint64; - /// - /// let a = Uint64::MAX; - /// let result = a.full_mul(2u32); - /// assert_eq!(result.to_string(), "36893488147419103230"); - /// ``` - pub fn full_mul(self, rhs: impl Into) -> Uint128 { - Uint128::from(self.u64()) - .checked_mul(Uint128::from(rhs.into())) - .unwrap() - } -} - -impl Serialize for Uint64 { - /// Serializes as an integer string using base 10 - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl<'de> Deserialize<'de> for Uint64 { - /// Deserialized from an integer string using base 10 - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Uint64Visitor) - } -} - -struct Uint64Visitor; - -impl<'de> de::Visitor<'de> for Uint64Visitor { - type Value = Uint64; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("string-encoded integer") - } - - fn visit_str(self, v: &str) -> Result - where - E: de::Error, - { - match v.parse::() { - Ok(u) => Ok(Uint64(u)), - Err(e) => Err(E::custom(format!("invalid Uint64 '{}' - {}", v, e))), - } - } -} - -impl std::iter::Sum for Uint64 -where - Self: ops::Add, -{ - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), ops::Add::add) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::{from_slice, to_vec}; - - #[test] - fn uint64_convert_into() { - let original = Uint64(12345); - let a = u64::from(original); - assert_eq!(a, 12345); - - let original = Uint64(12345); - let a = String::from(original); - assert_eq!(a, "12345"); - } - - #[test] - fn uint64_convert_from() { - let a = Uint64::from(5u64); - assert_eq!(a.0, 5); - - let a = Uint64::from(5u32); - assert_eq!(a.0, 5); - - let a = Uint64::from(5u16); - assert_eq!(a.0, 5); - - let a = Uint64::from(5u8); - assert_eq!(a.0, 5); - - let result = Uint64::try_from("34567"); - assert_eq!(result.unwrap().0, 34567); - - let result = Uint64::try_from("1.23"); - assert!(result.is_err()); - } - - #[test] - fn uint64_implements_display() { - let a = Uint64(12345); - assert_eq!(format!("Embedded: {}", a), "Embedded: 12345"); - assert_eq!(a.to_string(), "12345"); - - let a = Uint64(0); - assert_eq!(format!("Embedded: {}", a), "Embedded: 0"); - assert_eq!(a.to_string(), "0"); - } - - #[test] - fn uint64_display_padding_works() { - let a = Uint64::from(123u64); - assert_eq!(format!("Embedded: {:05}", a), "Embedded: 00123"); - } - - #[test] - fn uint64_to_be_bytes_works() { - assert_eq!(Uint64::zero().to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(Uint64::MAX.to_be_bytes(), [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - ]); - assert_eq!(Uint64::new(1).to_be_bytes(), [0, 0, 0, 0, 0, 0, 0, 1]); - // Python: `[b for b in (63374607431768124608).to_bytes(8, "big")]` - assert_eq!(Uint64::new(874607431768124608).to_be_bytes(), [ - 12, 35, 58, 211, 72, 116, 172, 192 - ]); - } - - #[test] - fn uint64_to_le_bytes_works() { - assert_eq!(Uint64::zero().to_le_bytes(), [0, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(Uint64::MAX.to_le_bytes(), [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - ]); - assert_eq!(Uint64::new(1).to_le_bytes(), [1, 0, 0, 0, 0, 0, 0, 0]); - // Python: `[b for b in (240282366920938463463374607431768124608).to_bytes(16, "little")]` - assert_eq!(Uint64::new(874607431768124608).to_le_bytes(), [ - 192, 172, 116, 72, 211, 58, 35, 12 - ]); - } - - #[test] - fn uint64_is_zero_works() { - assert!(Uint64::zero().is_zero()); - assert!(Uint64(0).is_zero()); - - assert!(!Uint64(1).is_zero()); - assert!(!Uint64(123).is_zero()); - } - - #[test] - fn uint64_json() { - let orig = Uint64(1234567890987654321); - let serialized = to_vec(&orig).unwrap(); - assert_eq!(serialized.as_slice(), b"\"1234567890987654321\""); - let parsed: Uint64 = from_slice(&serialized).unwrap(); - assert_eq!(parsed, orig); - } - - #[test] - fn uint64_compare() { - let a = Uint64(12345); - let b = Uint64(23456); - - assert!(a < b); - assert!(b > a); - assert_eq!(a, Uint64(12345)); - } - - #[test] - #[allow(clippy::op_ref)] - fn uint64_math() { - let a = Uint64(12345); - let b = Uint64(23456); - - // test + with owned and reference right hand side - assert_eq!(a + b, Uint64(35801)); - assert_eq!(a + &b, Uint64(35801)); - - // test - with owned and reference right hand side - assert_eq!((b.checked_sub(a)).unwrap(), Uint64(11111)); - - // test += with owned and reference right hand side - let mut c = Uint64(300000); - c += b; - assert_eq!(c, Uint64(323456)); - let mut d = Uint64(300000); - d += &b; - assert_eq!(d, Uint64(323456)); - - // error result on underflow (- would produce negative result) - let underflow_result = a.checked_sub(b); - let OverflowError { - operand1, operand2, .. - } = underflow_result.unwrap_err(); - assert_eq!((operand1, operand2), (a.to_string(), b.to_string())); - } - - #[test] - #[should_panic] - fn uint64_math_overflow_panics() { - // almost_max is 2^64 - 10 - let almost_max = Uint64(18446744073709551606); - let _ = almost_max + Uint64(12); - } - - #[test] - fn uint64_multiply_ratio_works() { - let base = Uint64(500); - - // factor 1/1 - assert_eq!(base.multiply_ratio(1u64, 1u64), base); - assert_eq!(base.multiply_ratio(3u64, 3u64), base); - assert_eq!(base.multiply_ratio(654321u64, 654321u64), base); - assert_eq!(base.multiply_ratio(u64::MAX, u64::MAX), base); - - // factor 3/2 - assert_eq!(base.multiply_ratio(3u64, 2u64), Uint64(750)); - assert_eq!(base.multiply_ratio(333333u64, 222222u64), Uint64(750)); - - // factor 2/3 (integer devision always floors the result) - assert_eq!(base.multiply_ratio(2u64, 3u64), Uint64(333)); - assert_eq!(base.multiply_ratio(222222u64, 333333u64), Uint64(333)); - - // factor 5/6 (integer devision always floors the result) - assert_eq!(base.multiply_ratio(5u64, 6u64), Uint64(416)); - assert_eq!(base.multiply_ratio(100u64, 120u64), Uint64(416)); - } - - #[test] - fn uint64_multiply_ratio_does_not_overflow_when_result_fits() { - // Almost max value for Uint64. - let base = Uint64(u64::MAX - 9); - - assert_eq!(base.multiply_ratio(2u64, 2u64), base); - } - - #[test] - #[should_panic] - fn uint64_multiply_ratio_panicks_on_overflow() { - // Almost max value for Uint64. - let base = Uint64(u64::MAX - 9); - - assert_eq!(base.multiply_ratio(2u64, 1u64), base); - } - - #[test] - #[should_panic(expected = "Denominator must not be zero")] - fn uint64_multiply_ratio_panics_for_zero_denominator() { - Uint64(500).multiply_ratio(1u64, 0u64); - } - - #[test] - fn sum_works() { - let nums = vec![Uint64(17), Uint64(123), Uint64(540), Uint64(82)]; - let expected = Uint64(762); - - let sum_as_ref = nums.iter().sum(); - assert_eq!(expected, sum_as_ref); - - let sum_as_owned = nums.into_iter().sum(); - assert_eq!(expected, sum_as_owned); - } - - #[test] - fn uint64_methods() { - // checked_* - assert!(matches!( - Uint64(u64::MAX).checked_add(Uint64(1)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint64(0).checked_sub(Uint64(1)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint64(u64::MAX).checked_mul(Uint64(2)), - Err(OverflowError { .. }) - )); - assert!(matches!( - Uint64(u64::MAX).checked_div(Uint64(0)), - Err(DivideByZeroError { .. }) - )); - assert!(matches!( - Uint64(u64::MAX).checked_div_euclid(Uint64(0)), - Err(DivideByZeroError { .. }) - )); - assert!(matches!( - Uint64(u64::MAX).checked_rem(Uint64(0)), - Err(DivideByZeroError { .. }) - )); - - // saturating_* - assert_eq!(Uint64(u64::MAX).saturating_add(Uint64(1)), Uint64(u64::MAX)); - assert_eq!(Uint64(0).saturating_sub(Uint64(1)), Uint64(0)); - assert_eq!(Uint64(u64::MAX).saturating_mul(Uint64(2)), Uint64(u64::MAX)); - assert_eq!(Uint64(u64::MAX).saturating_pow(2), Uint64(u64::MAX)); - - // wrapping_* - assert_eq!(Uint64(u64::MAX).wrapping_add(Uint64(1)), Uint64(0)); - assert_eq!(Uint64(0).wrapping_sub(Uint64(1)), Uint64(u64::MAX)); - assert_eq!( - Uint64(u64::MAX).wrapping_mul(Uint64(2)), - Uint64(u64::MAX - 1) - ); - assert_eq!(Uint64(u64::MAX).wrapping_pow(2), Uint64(1)); - } -} diff --git a/packages/multi-test/src/interfaces/snip20.rs b/packages/multi-test/src/interfaces/snip20.rs deleted file mode 100644 index eeb480f..0000000 --- a/packages/multi-test/src/interfaces/snip20.rs +++ /dev/null @@ -1,42 +0,0 @@ - - -pub fn init( - chain: &mut App, - sender: &str, - contracts: &mut DeployedContracts, - name: &str, - snip20_symbol: &str, - decimals: u8, - config: Option, -) -> StdResult<()> { - let snip20 = Contract::from( - match (snip20::InstantiateMsg { - name: name.to_string(), - admin: Some(sender.into()), - symbol: snip20_symbol.to_string(), - decimals, - initial_balances: Some(vec![snip20::InitialBalance { - address: sender.into(), - amount: Uint128::from(1_000_000_000 * 10 ^ decimals as u128), - }]), - prng_seed: Binary::default(), - query_auth: None, - config, - } - .test_init( - Snip20::default(), - chain, - Addr::unchecked(sender), - "snip20", - &[], - )) { - Ok(contract_info) => contract_info, - Err(e) => return Err(StdError::generic_err(e.to_string())), - }, - ); - contracts.insert( - SupportedContracts::Snip20(snip20_symbol.to_string()), - snip20, - ); - Ok(()) -} \ No newline at end of file diff --git a/packages/multi-test/src/lib.rs b/packages/multi-test/src/lib.rs deleted file mode 100644 index 51a504c..0000000 --- a/packages/multi-test/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg(not(target_arch = "wasm32"))] -pub mod multi; - -pub mod interfaces; diff --git a/packages/multi-test/src/multi.rs b/packages/multi-test/src/multi.rs deleted file mode 100644 index 1123439..0000000 --- a/packages/multi-test/src/multi.rs +++ /dev/null @@ -1,7 +0,0 @@ - - - -#[cfg(feature = "snip20")] -pub mod snip20{ - use snip20; -} \ No newline at end of file diff --git a/packages/multi-test/Cargo.toml b/packages/multi_test/Cargo.toml similarity index 76% rename from packages/multi-test/Cargo.toml rename to packages/multi_test/Cargo.toml index 72cc767..6754067 100644 --- a/packages/multi-test/Cargo.toml +++ b/packages/multi_test/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "multi-test" +name = "multi_test" version = "0.1.0" authors = ["Tony "] edition = "2018" @@ -27,11 +27,15 @@ cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } cosmwasm-schema = { git = "https://github.com/CosmWasm/cosmwasm"} snip20-reference-impl = { path = "../../contracts/snip20"} +lp-token = { path = "../../contracts/lp_token"} sha2 = { version = "0.9.1", default-features = false } subtle = { version = "2.2.3", default-features = false } rand_chacha = { version = "0.2.2", default-features = false } rand_core = { version = "0.5.1", default-features = false } chrono = { version = "=0.4.19" } secret-multi-test = { git = "https://github.com/securesecrets/secret-plus-utils", version = "0.13.4" } - - +shadeswap-shared = {path = "../../packages/shadeswap-shared"} +query-authentication = { git = "https://github.com/securesecrets/query-authentication", branch = "cosmwasm_v1_upgrade" } +factory = {path = "../../contracts/factory"} +staking = {path = "../../contracts/staking"} +amm_pair = {path = "../../contracts/amm_pair"} \ No newline at end of file diff --git a/packages/multi_test/src/admin/admin_lib.rs b/packages/multi_test/src/admin/admin_lib.rs new file mode 100644 index 0000000..4738b5b --- /dev/null +++ b/packages/multi_test/src/admin/admin_lib.rs @@ -0,0 +1,32 @@ +pub mod admin_help{ + use cosmwasm_std::{Empty, Addr, ContractInfo, StdResult}; + use secret_multi_test::{Contract, ContractWrapper, App, Executor}; + use crate::admin::admin_mock::admin_mock::{execute, query,instantiate, InitMsg}; + + pub fn admin_contract_init_store() -> Box> { + let contract = ContractWrapper::new_with_empty(execute,instantiate, query); + Box::new(contract) + } + + pub fn init_admin_contract( + router: &mut App, + sender: &Addr + ) -> StdResult { + + // ADMIN INIT MSG + let init_msg = InitMsg{ + + }; + + let admin_store_info = router.store_code(admin_contract_init_store()); + let admin_contract = router.instantiate_contract( + admin_store_info, + sender.clone(), + &init_msg, + &[], + "admin", + Some(sender.to_string()), + ).unwrap(); + Ok(admin_contract) + } +} \ No newline at end of file diff --git a/packages/multi_test/src/admin/admin_mock.rs b/packages/multi_test/src/admin/admin_mock.rs new file mode 100644 index 0000000..ee68a09 --- /dev/null +++ b/packages/multi_test/src/admin/admin_mock.rs @@ -0,0 +1,54 @@ +pub mod admin_mock{ + use cosmwasm_std::{Response, StdResult, MessageInfo, DepsMut, Env, entry_point, to_binary, Deps, Binary}; + use schemars::JsonSchema; + use serde::{Serialize, Deserialize}; + use shadeswap_shared::{utils::{pad_query_result, pad_response_result}, admin::{ExecuteMsg, QueryMsg, ValidateAdminPermissionResponse}}; + + pub const BLOCK_SIZE: usize = 256; + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] + pub struct InitMsg{ + + } + + #[entry_point] + pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: InitMsg, + ) -> StdResult { + Ok(Response::new()) + } + + #[entry_point] + pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + pad_query_result( + match msg { + QueryMsg::GetConfig { } => to_binary(""), + QueryMsg::GetAdmins { } => to_binary(""), + QueryMsg::GetPermissions { user: _ } => to_binary(""), + QueryMsg::ValidateAdminPermission { permission: _, user:_ } => to_binary(&ValidateAdminPermissionResponse{ + has_permission: true }) + }, + BLOCK_SIZE, + ) + } + + + #[entry_point] + pub fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, msg: ExecuteMsg) -> StdResult { + pad_response_result( + match msg { + ExecuteMsg::UpdateRegistry { action: _ } => Ok(Response::new()), + ExecuteMsg::UpdateRegistryBulk { actions: _ } => Ok(Response::new()), + ExecuteMsg::TransferSuper { new_super:_ } => Ok(Response::new()), + ExecuteMsg::SelfDestruct { } => Ok(Response::new()), + ExecuteMsg::ToggleStatus { new_status :_ } => Ok(Response::new()), + }, + BLOCK_SIZE, + ) + } +} + + diff --git a/packages/multi_test/src/admin/mod.rs b/packages/multi_test/src/admin/mod.rs new file mode 100644 index 0000000..0ec0853 --- /dev/null +++ b/packages/multi_test/src/admin/mod.rs @@ -0,0 +1,4 @@ +pub use admin_mock::*; +pub mod admin_mock; +pub use admin_lib::*; +pub mod admin_lib; \ No newline at end of file diff --git a/packages/multi_test/src/amm_pairs/amm_pairs_lib.rs b/packages/multi_test/src/amm_pairs/amm_pairs_lib.rs new file mode 100644 index 0000000..4f322e9 --- /dev/null +++ b/packages/multi_test/src/amm_pairs/amm_pairs_lib.rs @@ -0,0 +1,182 @@ +pub mod amm_pairs_lib{ + use cosmwasm_std::{ContractInfo, StdResult, Addr, to_binary, Empty, Uint128, Coin}; + use secret_multi_test::{App, ContractWrapper, Executor, Contract}; + use shadeswap_shared::amm_pair::{AMMSettings, AMMPair}; + use shadeswap_shared::core::{ContractInstantiationInfo, CustomFee, Callback, Fee, TokenPair, TokenType, TokenPairAmount}; + use shadeswap_shared::msg::amm_pair::{InitMsg, ExecuteMsg, QueryMsg, QueryMsgResponse}; + use crate::amm_pairs::amm_pairs_mock::amm_pairs_mock::{execute, instantiate, query, reply as amm_reply}; + use crate::help_lib::integration_help_lib::{snip20_lp_token_contract_store, create_token_pair}; + use shadeswap_shared::utils::asset::Contract as SContract; + use crate::amm_pairs::amm_pairs_mock::amm_pairs_mock::reply; + use amm_pair::contract::{execute as amm_pair_execute, instantiate as amm_pair_instantiate, query as amm_pair_query }; + use shadeswap_shared::staking::StakingContractInit; + + pub fn store_init_amm_pair_contract( + router: &mut App, + sender: &Addr, + token_0: &SContract, + token_1: &SContract, + factory: &SContract, + admin_auth: &SContract, + store_code: Box>, + seed: &str, + staking_contract: Option, + custom_fee: Option, + ) -> StdResult + { + let contract_info = router.store_code(store_code); + let lp_token_info = router.store_code(snip20_lp_token_contract_store()); + let contract = router.instantiate_contract( + contract_info, + sender.clone(), + &InitMsg{ + pair: create_token_pair(&token_0, &token_1), + lp_token_contract: ContractInstantiationInfo{ + code_hash: lp_token_info.code_hash, + id: lp_token_info.code_id, + }, + factory_info: factory.clone(), + prng_seed: to_binary(seed)?, + entropy: to_binary(seed)?, + admin_auth: admin_auth.clone() , + staking_contract: staking_contract, + custom_fee: custom_fee + }, + &[], + "amm_pairs", + Some(sender.to_string()) + ).unwrap(); + Ok(contract) + } + + pub fn create_amm_settings( + lp_fee_nom: u8, + lp_fee_denom: u16, + shade_fee_nom: u8, + shade_fee_denom: u16, + shade_dao_address: &Addr + ) -> AMMSettings + { + AMMSettings{ + lp_fee: Fee::new(lp_fee_nom, lp_fee_denom), + shade_dao_fee: Fee::new(shade_fee_nom, shade_fee_denom), + shade_dao_address: SContract { address: shade_dao_address.clone(), code_hash: "".to_string() }, + } + } + + pub fn create_amm_pairs( + address: &Addr, + enabled: bool, + token_pair: TokenPair + ) -> AMMPair{ + AMMPair { + pair: token_pair, + address: address.clone(), + enabled: enabled } + } + + pub fn create_native_token(denom: &str) -> TokenType{ + TokenType::NativeToken { denom: denom.to_string() } + } + + pub fn create_custom_token(contract: &ContractInfo) -> TokenType{ + TokenType::CustomToken { + contract_addr: contract.address.clone(), + token_code_hash: contract.code_hash.clone() } + } + + pub fn create_token_pair_amount( + token_pair: &TokenPair, + amount_0: Uint128, + amount_1: Uint128) -> TokenPairAmount{ + TokenPairAmount{ + pair: token_pair.clone(), + amount_0: amount_0, + amount_1: amount_1, + } + } + + pub fn add_liquidity_to_amm_pairs( + router: &mut App, + contract: &ContractInfo, + pair: &TokenPair, + amount_0: Uint128, + amount_1: Uint128, + expected_return: Option, + staking: Option, + sender: &Addr, + funds: &[Coin] + ) -> StdResult<()>{ + let add_liq_msg = ExecuteMsg::AddLiquidityToAMMContract { + deposit: create_token_pair_amount( + &pair, + amount_0, + amount_1 + ), + expected_return: expected_return, + staking: staking + }; + + let _ = router.execute_contract( + sender.to_owned(), + contract, + &add_liq_msg, + funds + ).unwrap(); + + Ok(()) + } + + pub fn init_amm_pair( + router: &mut App, + sender: &Addr, + token_0: &SContract, + token_1: &SContract, + factory: &SContract, + admin_auth: &SContract, + mock: bool, + seed: &str, + staking_contract: Option, + custom_fee: Option + ) -> StdResult { + // Create AMM_Pair or Mock + if mock { + return store_init_amm_pair_contract( + router, + sender, + token_0, + token_1, + factory, + admin_auth, + amm_pair_contract_store(), + seed, + staking_contract, + custom_fee + ) + } + + return store_init_amm_pair_contract( + router, + sender, + token_0, + token_1, + factory, + admin_auth, + amm_pair_contract_store_in(), + seed, + staking_contract, + custom_fee + ) + } + + pub fn amm_pair_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(execute, instantiate, query); + Box::new(contract) + } + + pub fn amm_pair_contract_store_in() -> Box> { + let contract = ContractWrapper::new_with_empty(amm_pair_execute, amm_pair_instantiate, query).with_reply(reply); + Box::new(contract) + } + +} \ No newline at end of file diff --git a/packages/multi_test/src/amm_pairs/amm_pairs_mock.rs b/packages/multi_test/src/amm_pairs/amm_pairs_mock.rs new file mode 100644 index 0000000..d3846fd --- /dev/null +++ b/packages/multi_test/src/amm_pairs/amm_pairs_mock.rs @@ -0,0 +1,241 @@ +pub mod amm_pairs_mock { + use crate::{ + help_lib::integration_help_lib::get_contract_link_from_token_type + }; + use cosmwasm_std::{ + entry_point, to_binary, Addr, Binary, CosmosMsg, + Deps, DepsMut, Env, MessageInfo, Reply, Response, StdError, StdResult, Storage, SubMsg, + SubMsgResult, Uint128, WasmMsg, QueryRequest, WasmQuery, + }; + use cosmwasm_storage::{singleton, singleton_read, ReadonlySingleton, Singleton}; + use serde::{Deserialize, Serialize}; + use shadeswap_shared::{ + core::{ + create_viewing_key, CustomFee, TokenPair, TokenType, ViewingKey, + }, + msg::amm_pair::{ExecuteMsg, InitMsg, QueryMsg, QueryMsgResponse, SwapResult}, + snip20::helpers::register_receive, + staking::StakingContractInit, + utils::{pad_query_result, pad_response_result}, amm_pair::AMMSettings, + }; + use amm_pair::operations::register_lp_token; + use amm_pair::state::config_r; + use shadeswap_shared::msg::factory::{QueryResponse as FactoryQueryResponse, QueryMsg as FactoryQueryMsg}; + pub const BLOCK_SIZE: usize = 256; + //use crate::staking::staking_mock::staking_mock::InitMsg as StakingInitMsg; + use shadeswap_shared::msg::staking::InitMsg as StakingInitMsg; + use shadeswap_shared::Contract; + pub const INSTANTIATE_LP_TOKEN_REPLY_ID: u64 = 1u64; + pub const INSTANTIATE_STAKING_CONTRACT_REPLY_ID: u64 = 2u64; + + pub static CONFIG: &[u8] = b"config"; + pub static TOKEN_0: &[u8] = b"token_0"; + pub static TOKEN_1: &[u8] = b"token_1"; + pub static FACTORY: &[u8] = b"factory"; + use amm_pair::operations::set_staking_contract; + + struct FactoryConfig { + amm_settings: AMMSettings, + authenticator: Option, + admin_auth: Contract + } + + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + pub struct Config { + pub factory_contract: Contract, + pub lp_token: Contract, + pub staking_contract: Option, + pub pair: TokenPair, + pub viewing_key: ViewingKey, + pub custom_fee: Option, + pub staking_contract_init: Option, + pub prng_seed: Binary, + pub admin_auth: Contract + } + + #[entry_point] + pub fn instantiate( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: InitMsg, + ) -> StdResult { + let mut response = Response::new(); + let config = Config { + factory_contract: msg.factory_info.clone(), + lp_token: Contract { + code_hash: msg.lp_token_contract.code_hash, + address: Addr::unchecked(""), + }, + pair: msg.pair, + viewing_key: create_viewing_key( + &env, + &info, + msg.prng_seed.clone(), + msg.entropy.clone(), + ), + custom_fee: msg.custom_fee.clone(), + staking_contract: None, + staking_contract_init: msg.staking_contract, + prng_seed: msg.prng_seed, + admin_auth: msg.admin_auth + }; + singleton(deps.storage, CONFIG).save(&config)?; + Ok(response.add_attribute("created_exchange_address", env.contract.address.to_string())) + } + + #[entry_point] + pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + pad_query_result( + match msg { + QueryMsg::GetConfig {} => to_binary(""), + QueryMsg::GetPairInfo {} => { + let config: Config = singleton_read(deps.storage, CONFIG).load()?; + let token_0 = get_contract_link_from_token_type(&config.pair.0); + let token_1: Contract = get_contract_link_from_token_type(&config.pair.0); + let response = QueryMsgResponse::GetPairInfo { + liquidity_token: token_0.to_owned(), + factory: config.factory_contract.to_owned(), + pair: TokenPair( + TokenType::CustomToken { + contract_addr: token_0.address.to_owned(), + token_code_hash: token_0.code_hash.to_owned(), + }, + TokenType::CustomToken { + contract_addr: token_1.address.to_owned(), + token_code_hash: token_1.code_hash.to_owned(), + }, + ), + amount_0: Uint128::new(1000u128), + amount_1: Uint128::new(1000u128), + total_liquidity: Uint128::new(1000000), + contract_version: 1, + }; + to_binary(&response) + } + QueryMsg::GetTradeHistory { + api_key: _, + pagination: _, + } => to_binary(""), + QueryMsg::GetWhiteListAddress {} => to_binary(""), + QueryMsg::GetTradeCount {} => to_binary(""), + QueryMsg::GetStakingContract {} => to_binary(""), + QueryMsg::GetEstimatedPrice { offer: _, exclude_fee: _ } => to_binary(""), + QueryMsg::SwapSimulation { offer } => { + let response = QueryMsgResponse::SwapSimulation { + total_fee_amount: Uint128::new(150u128), + lp_fee_amount: Uint128::new(50u128), + shade_dao_fee_amount: Uint128::new(150u128), + result: SwapResult { + return_amount: offer.amount, + }, + price: "1.2".to_string(), + }; + return to_binary(&response); + } + QueryMsg::GetShadeDaoInfo {} => to_binary(""), + QueryMsg::GetEstimatedLiquidity { deposit: _ } => to_binary(""), + }, + BLOCK_SIZE, + ) + } + + #[entry_point] + pub fn execute( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: ExecuteMsg, + ) -> StdResult { + pad_response_result( + match msg { + ExecuteMsg::AddLiquidityToAMMContract { + deposit: _, + expected_return: _, + staking: _, + } => Ok(Response::new()), + ExecuteMsg::SwapTokens { + offer: _, + expected_return: _, + to: _, + } => Ok(Response::new()), + ExecuteMsg::Receive { + from: _, + msg: _, + amount: _, + } => Ok(Response::new()), + ExecuteMsg::AddWhiteListAddress { address: _ } => Ok(Response::new()), + ExecuteMsg::RemoveWhitelistAddresses { addresses: _ } => Ok(Response::new()), + ExecuteMsg::SetCustomPairFee { custom_fee: _ } => Ok(Response::new()), + ExecuteMsg::SetViewingKey { viewing_key: _ } => Ok(Response::new()), + ExecuteMsg::RecoverFunds { + token: _, + amount: _, + to: _, + msg: _msg, + } => Ok(Response::new()), + ExecuteMsg::SetConfig { admin_auth: _ } => Ok(Response::new()), + }, + BLOCK_SIZE, + ) + } + + #[entry_point] + pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> StdResult { + pad_response_result( + match (msg.id, msg.result) { + (INSTANTIATE_LP_TOKEN_REPLY_ID, SubMsgResult::Ok(s)) => match s.data { + Some(x) => { + let mut temp = String::from_utf8(x.to_vec())?; + temp = temp.replace("(", ""); + temp = temp.replace("\n", ""); + let address = &temp[..40]; + let contract_address = Addr::unchecked(address); + let config = config_r(deps.storage).load()?; + let mut response = register_lp_token( + deps, + &env, + Contract { + address: contract_address, + code_hash: config.lp_token.code_hash, + }, + )?; + response.data = Some(env.contract.address.to_string().as_bytes().into()); + Ok(response) + } + None => Err(StdError::generic_err(format!("Unknown reply id"))), + }, + (INSTANTIATE_STAKING_CONTRACT_REPLY_ID, SubMsgResult::Ok(s)) => match s.data { + Some(x) => { + let mut temp = String::from_utf8(x.to_vec())?; + temp = temp.replace("(", ""); + temp = temp.replace("\n", ""); + let address = &temp[..40]; + let contract_address = Addr::unchecked(address); + let config = config_r(deps.storage).load()?; + let mut response = set_staking_contract( + deps.storage, + Some(Contract { + address: contract_address, + code_hash: config + .staking_contract_init + .ok_or(StdError::generic_err( + "Staking contract does not match.".to_string(), + ))? + .contract_info + .code_hash, + }), + )?; + response.data = Some(env.contract.address.to_string().as_bytes().into()); + Ok(response) + } + None => Err(StdError::generic_err(format!("Unknown reply id"))), + }, + _ => Err(StdError::generic_err(format!("Unknown reply id"))), + }, + BLOCK_SIZE, + ) + } + + +} diff --git a/packages/multi_test/src/amm_pairs/mod.rs b/packages/multi_test/src/amm_pairs/mod.rs new file mode 100644 index 0000000..f1a7368 --- /dev/null +++ b/packages/multi_test/src/amm_pairs/mod.rs @@ -0,0 +1,2 @@ +pub mod amm_pairs_mock; +pub mod amm_pairs_lib; \ No newline at end of file diff --git a/packages/multi_test/src/auth/auth_query.rs b/packages/multi_test/src/auth/auth_query.rs new file mode 100644 index 0000000..228de58 --- /dev/null +++ b/packages/multi_test/src/auth/auth_query.rs @@ -0,0 +1,62 @@ +pub mod auth_query{ + use cosmwasm_std::{Response, StdResult, MessageInfo, DepsMut, Env, entry_point, to_binary, Deps, Binary}; + use query_authentication::transaction::{PubKeyValue}; + use schemars::JsonSchema; + use serde::{Deserialize, Serialize}; + use shadeswap_shared::{utils::{pad_query_result, pad_response_result}, query_auth::{ExecuteMsg, QueryMsg, QueryAnswer}}; + + pub const BLOCK_SIZE: usize = 256; + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] + pub struct InitMsg{ + + } + + + #[entry_point] + pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: InitMsg, + ) -> StdResult { + Ok(Response::new()) + } + + #[entry_point] + pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + pad_query_result( + match msg { + QueryMsg::Config { } => to_binary(""), + QueryMsg::ValidateViewingKey { user:_, key:_ } => to_binary(""), + QueryMsg::ValidatePermit { permit } => { + let pub_key = permit.signature.pub_key.value.clone(); + let pub_key_value = PubKeyValue(pub_key); + println!(" Mock Validating Permit for Addr {}", pub_key_value.as_addr(None)?); + return to_binary(&QueryAnswer::ValidatePermit { + user: pub_key_value.as_addr(None)?, + is_revoked: false + }); + } + }, + BLOCK_SIZE, + ) + } + + + #[entry_point] + pub fn execute(_deps: DepsMut, _env: Env, _info: MessageInfo, msg: ExecuteMsg) -> StdResult { + pad_response_result( + match msg { + ExecuteMsg::SetAdminAuth { admin: _, padding: _ } => Ok(Response::new()), + ExecuteMsg::SetRunState { state: _, padding: _ } => Ok(Response::new()), + ExecuteMsg::SetViewingKey { key: _, padding: _ } => Ok(Response::new()), + ExecuteMsg::CreateViewingKey { entropy: _, padding: _ } => Ok(Response::new()), + ExecuteMsg::BlockPermitKey { key: _, padding: _ } => Ok(Response::new()), + }, + BLOCK_SIZE, + ) + } +} + + diff --git a/packages/multi_test/src/auth/mod.rs b/packages/multi_test/src/auth/mod.rs new file mode 100644 index 0000000..ce6aed6 --- /dev/null +++ b/packages/multi_test/src/auth/mod.rs @@ -0,0 +1,2 @@ +pub use auth_query::*; +pub mod auth_query; \ No newline at end of file diff --git a/packages/multi_test/src/factory/factory_lib.rs b/packages/multi_test/src/factory/factory_lib.rs new file mode 100644 index 0000000..ce020ce --- /dev/null +++ b/packages/multi_test/src/factory/factory_lib.rs @@ -0,0 +1,172 @@ +pub mod factory_lib{ + use cosmwasm_std::{StdResult, ContractInfo, Addr, Empty, to_binary}; + use secret_multi_test::{App, Executor, Contract, ContractWrapper, AppResponse}; + use shadeswap_shared::Pagination; + use shadeswap_shared::amm_pair::AMMSettings; + use shadeswap_shared::core::{ContractInstantiationInfo, TokenPair}; + use shadeswap_shared::staking::StakingContractInit; + use shadeswap_shared::utils::testing::TestingExt; + use shadeswap_shared::{amm_pair::AMMPair, factory::InitMsg}; + use shadeswap_shared::utils::asset::Contract as SContract; + use crate::auth; + use crate::factory::factory_mock::factory_mock::{execute, instantiate, query, reply}; + use crate::help_lib::integration_help_lib::convert_to_contract_link; + use factory::contract::{execute as factory_execute, instantiate as factory_instantiate, query as factory_query}; + use shadeswap_shared::msg::factory::{ExecuteMsg, QueryMsg, QueryResponse}; + + pub fn init_factory( + router: &mut App, + admin: &SContract, + sender: &str, + mock: bool, + amm_settings: AMMSettings, + pair: ContractInstantiationInfo, + lp_token_info: ContractInstantiationInfo, + seed: &str, + api_key: &str, + authenticator: Option + ) -> StdResult + { + if mock { + return store_init_factory_contract( + router, + admin, + sender, + factory_contract_store(), + amm_settings, + pair, + lp_token_info, + &seed, + &api_key, + authenticator + ) + } + + return store_init_factory_contract( + router, + admin, + sender, + factory_contract_store_in(), + amm_settings, + pair, + lp_token_info, + &seed, + &api_key, + authenticator + ) + } + + pub fn store_init_factory_contract( + router: &mut App, + admin: &SContract, + sender: &str, + store_code: Box>, + amm_settings: AMMSettings, + pair: ContractInstantiationInfo, + lp_token_info: ContractInstantiationInfo, + seed: &str, + api_key: &str, + authenticator: Option + ) + -> StdResult + { + let contract_info = router.store_code(store_code); + let contract = router.instantiate_contract( + contract_info, + Addr::unchecked(sender.to_string()), + &InitMsg{ + admin_auth: admin.clone(), + pair_contract: pair, + amm_settings: amm_settings, + lp_token_contract: lp_token_info, + prng_seed: to_binary(seed)?, + api_key: api_key.to_string(), + authenticator: authenticator, + }, + &[], + "staking", + Some(sender.to_string()) + ).unwrap(); + Ok(contract) + } + + pub fn create_amm_pairs() -> StdResult<()>{ + Ok(()) + } + + pub fn add_amm_pairs_to_factory( + router: &mut App, + factory_contract: &ContractInfo, + amm_pair: &AMMPair, + sender: &Addr + ) -> StdResult<()>{ + let amm_pair_msg = ExecuteMsg::AddAMMPairs { + amm_pairs: vec![amm_pair.to_owned()] + }; + + let _ = router.execute_contract( + sender.to_owned(), + + factory_contract, + &amm_pair_msg, + &[] + ).unwrap(); + Ok(()) + } + + pub fn create_amm_pairs_to_factory( + router: &mut App, + factory_contract: &ContractInfo, + token_pair: &TokenPair, + seed: &str, + staking_contract_info: &StakingContractInit, + router_contract: &ContractInfo, + sender: &Addr, + ) -> StdResult<()>{ + let create_amm_pair_msg = ExecuteMsg::CreateAMMPair { + pair: token_pair.to_owned(), + entropy: to_binary(seed)?, + staking_contract: Some(staking_contract_info.to_owned()), + }; + + let _ = router.execute_contract( + sender.to_owned(), + factory_contract, + &create_amm_pair_msg, + &[] + ).unwrap(); + Ok(()) + } + + pub fn list_amm_pairs_from_factory( + router: &mut App, + factory_contract: &ContractInfo, + start: u64, + limit: u8 + ) -> StdResult>{ + let query_msg = to_binary(&QueryMsg::ListAMMPairs { + pagination: Pagination{ + start: start, + limit: limit, + } + })?; + + let response: QueryResponse = router.query_test(factory_contract.clone(), query_msg).unwrap(); + match response { + QueryResponse::ListAMMPairs { amm_pairs } => Ok(amm_pairs), + _ => panic!("wrong response") + } + } + + pub fn factory_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(execute, instantiate, query); + Box::new(contract) + } + + pub fn factory_contract_store_in() -> Box> { + let contract = ContractWrapper::new_with_empty(factory_execute, factory_instantiate, factory_query).with_reply(reply); + Box::new(contract) + } + + +} \ No newline at end of file diff --git a/packages/multi_test/src/factory/factory_mock.rs b/packages/multi_test/src/factory/factory_mock.rs new file mode 100644 index 0000000..86fe3a4 --- /dev/null +++ b/packages/multi_test/src/factory/factory_mock.rs @@ -0,0 +1,140 @@ +pub mod factory_mock { + use std::io::Read; + + use crate::util_addr::util_addr::OWNER; + use cosmwasm_std::{ + entry_point, to_binary, Addr, Binary, Deps, DepsMut, Env, + MessageInfo, Response, StdResult, StdError, SubMsgResult, Reply, + }; + use factory::state::ephemeral_storage_r; + use factory::operations::register_amm_pair; + use cosmwasm_storage::{singleton, singleton_read}; + use schemars::{JsonSchema, _private::NoSerialize}; + use shadeswap_shared::{utils::asset::Contract, amm_pair::AMMPair}; + use serde::{Deserialize, Serialize}; + use shadeswap_shared::{ + amm_pair::AMMSettings, + core::{ContractInstantiationInfo, Fee}, + factory::{ExecuteMsg, QueryMsg, QueryResponse}, + utils::{pad_query_result, pad_response_result}, + }; + use factory::state::ephemeral_storage_w; + use shadeswap_shared::Contract as sContract; + pub const INSTANTIATE_REPLY_ID: u64 = 1u64; + + pub static CONFIG: &[u8] = b"config"; + pub const BLOCK_SIZE: usize = 256; + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] + pub struct InitMsg { + pub admin_auth: Contract + } + + #[entry_point] + pub fn instantiate( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: InitMsg, + ) -> StdResult { + singleton(deps.storage, CONFIG).save(&msg.admin_auth)?; + Ok(Response::new()) + } + + #[entry_point] + pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + pad_query_result( + match msg { + QueryMsg::ListAMMPairs { pagination: _ } => to_binary(""), + QueryMsg::GetAMMPairAddress { pair: _ } => to_binary(""), + QueryMsg::GetConfig => { + println!("getconfig factory"); + let admin_auth: Contract = singleton_read(deps.storage, CONFIG).load()?; + to_binary(&QueryResponse::GetConfig { + pair_contract: ContractInstantiationInfo { + code_hash: "".to_string(), + id: 0u64, + }, + amm_settings: AMMSettings { + lp_fee: Fee::new(3, 100), + shade_dao_fee: Fee::new(3, 100), + shade_dao_address: sContract { + address: Addr::unchecked(OWNER), + code_hash: "".to_string(), + }, + }, + lp_token_contract: ContractInstantiationInfo { + code_hash: "".to_string(), + id: 0u64, + }, + authenticator: None, + admin_auth: admin_auth.clone(), + }) + }, + QueryMsg::AuthorizeApiKey { api_key: _ } => to_binary(""), + }, + BLOCK_SIZE, + ) + } + + #[entry_point] + pub fn execute( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: ExecuteMsg, + ) -> StdResult { + pad_response_result( + match msg { + ExecuteMsg::SetConfig { + pair_contract: _, + lp_token_contract: _, + amm_settings: _, + api_key: _, + admin_auth: _, + } => Ok(Response::new()), + ExecuteMsg::CreateAMMPair { + pair: _, + entropy: _, + staking_contract: _ + } => Ok(Response::new()), + ExecuteMsg::AddAMMPairs { amm_pairs: _ } => Ok(Response::new()) + }, + BLOCK_SIZE, + ) + } + + #[entry_point] + pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> StdResult { + pad_response_result( + match (msg.id, msg.result) { + (INSTANTIATE_REPLY_ID, SubMsgResult::Ok(s)) => match s.data { + Some(x) => { + let tempsss: Vec = x.to_vec().to_owned(); + let mut temp = String::from_utf8_lossy(&tempsss); + let mut temp: String = temp.to_string(); + temp = temp.replace("(", ""); + temp = temp.replace("\n", ""); + let address = &temp[..40]; + let contract_address = Addr::unchecked(address.clone()); + let config = ephemeral_storage_r(deps.storage).load()?; + register_amm_pair( + deps.storage, + AMMPair { + pair: config.pair, + address: contract_address, + enabled: true, + }, + )?; + ephemeral_storage_w(deps.storage).remove(); + Ok(Response::default()) + } + None => Err(StdError::generic_err(format!("Expecting contract id"))), + }, + _ => Err(StdError::generic_err(format!("Unknown reply id"))), + }, + BLOCK_SIZE, + ) + } + +} diff --git a/packages/multi_test/src/factory/mod.rs b/packages/multi_test/src/factory/mod.rs new file mode 100644 index 0000000..a13ab7d --- /dev/null +++ b/packages/multi_test/src/factory/mod.rs @@ -0,0 +1,4 @@ +pub use factory_mock::*; +pub mod factory_mock; +pub mod factory_lib; +pub use factory_lib::*; \ No newline at end of file diff --git a/packages/multi_test/src/help_lib.rs b/packages/multi_test/src/help_lib.rs new file mode 100644 index 0000000..742ed64 --- /dev/null +++ b/packages/multi_test/src/help_lib.rs @@ -0,0 +1,559 @@ + + +pub mod integration_help_lib{ + use std::time::{SystemTime, UNIX_EPOCH}; + use cosmwasm_std::{StdError, BlockInfo, Timestamp}; + use cosmwasm_std::Empty; + use query_authentication::permit::Permit; + use query_authentication::transaction::PermitSignature; + use query_authentication::transaction::PubKey; + use secret_multi_test::AppResponse; + use secret_multi_test::next_block; + use shadeswap_shared::core::{ CustomFee}; + use shadeswap_shared::snip20::{QueryAnswer, QueryMsg}; + use shadeswap_shared::utils::testing::TestingExt; + use cosmwasm_std::{Addr, ContractInfo, StdResult, Uint128, Coin, Binary}; + use shadeswap_shared::Contract as SContract; + use secret_multi_test::Contract; + use secret_multi_test::ContractWrapper; + use secret_multi_test::{App, Executor}; + use shadeswap_shared::{ + msg::staking::{InvokeMsg}, + core::TokenPair, + core::{TokenType}, + snip20::{InitConfig, InstantiateMsg, self}, + query_auth::PermitData, + staking::QueryData + }; + use crate::auth::auth_query::auth_query::{execute as auth_execute, InitMsg as AuthInitMsg, instantiate as auth_instantiate, query as auth_query}; + use crate::factory::factory_lib::factory_lib::factory_contract_store; + use crate::factory::factory_mock::factory_mock::InitMsg; + use shadeswap_shared::msg::amm_pair::{QueryMsgResponse as AMMPairQueryResponse, QueryMsg as AMMPairQueryMsg}; + use snip20_reference_impl::contract::{execute as snip20_execute, instantiate as snip20_instantiate, query as snip20_query}; + use lp_token::contract::{execute as lp_execute, instantiate as lp_instantiate, query as lp_query}; + use cosmwasm_std::to_binary; + use crate::util_addr::util_addr::{OWNER, TOKEN_B, TOKEN_A}; + use crate::staking::staking_mock::staking_mock::{execute as staking_execute_mock, query as staking_query_mock,instantiate as staking_instantiate_mock, InitMsg as StakingInitMsg }; + type TestPermit = Permit; + + pub fn mk_token_pair() -> TokenPair{ + return TokenPair( + TokenType::CustomToken { contract_addr: mk_address(TOKEN_A), token_code_hash: "".to_string() }, + TokenType::CustomToken { contract_addr: mk_address(TOKEN_B), token_code_hash: "".to_string() } + ); + } + + pub fn store_init_auth_contract(router: &mut App) + -> StdResult + { + let auth_contract_info = router.store_code(auth_permit_contract_store()); + let auth_contract = router.instantiate_contract( + auth_contract_info, + mk_address(&OWNER).to_owned(), + &AuthInitMsg{}, + &[], + "auth_permit", + Some(OWNER.to_string()) + ).unwrap(); + Ok(auth_contract) + } + + pub fn store_init_factory_contract( + router: &mut App, + admin: &SContract + ) + -> StdResult + { + let contract_info = router.store_code(factory_contract_store()); + let contract = router.instantiate_contract( + contract_info, + mk_address(&OWNER).to_owned(), + &InitMsg{ + admin_auth: admin.clone(), + }, + &[], + "staking", + Some(OWNER.to_string()) + ).unwrap(); + Ok(contract) + } + + pub fn store_init_staking_contract(router: &mut App) + -> StdResult + { + let contract_info = router.store_code(staking_contract_store()); + let contract = router.instantiate_contract( + contract_info, + mk_address(&OWNER).to_owned(), + &StakingInitMsg{}, + &[], + "staking", + Some(OWNER.to_string()) + ).unwrap(); + Ok(contract) + } + + + pub fn convert_to_contract_link(contract: &ContractInfo) -> SContract { + SContract{ + address: contract.address.to_owned(), + code_hash: contract.code_hash.to_owned(), + } + } + + + pub fn roll_blockchain(router: &mut App, count: u128) -> StdResult<()>{ + let temp_count = count + 1; + for _i in 1..temp_count { + router.update_block(next_block); + } + Ok(()) + } + + pub fn snip20_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(snip20_execute, snip20_instantiate, snip20_query); + Box::new(contract) + } + + pub fn snip20_lp_token_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(lp_execute, lp_instantiate, lp_query); + Box::new(contract) + } + + pub fn auth_permit_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(auth_execute, auth_instantiate, auth_query); + Box::new(contract) + } + + pub fn staking_contract_store() -> Box> { + let contract = ContractWrapper::new_with_empty(staking_execute_mock, staking_instantiate_mock, staking_query_mock); + Box::new(contract) + } + + + pub fn mk_address(address: &str) -> Addr{ + return Addr::unchecked(address.to_string()) + } + + pub fn mk_contract_link(address: &str) -> SContract{ + return SContract{ + address: mk_address(address), + code_hash: "".to_string(), + } + } + + pub fn get_current_timestamp() -> StdResult { + let start = SystemTime::now(); + let since_the_epoch = start + .duration_since(UNIX_EPOCH) + .expect("Time went backwards"); + Ok(Uint128::from(since_the_epoch.as_millis())) + } + + +pub fn configure_block_send_init_funds(router: &mut App, owner_addr: &Addr, amount: Uint128) -> StdResult<()> { + router.set_block(BlockInfo { + height: 1, + time: Timestamp::from_seconds(1 as u64), + chain_id: "chain_id".to_string(), + }); + router.init_modules(|router, _, storage| { + router + .bank + .init_balance(storage, &owner_addr.clone(), vec![Coin{denom: "uscrt".into(), amount: Uint128::new(100000000000000u128)}]) + .unwrap(); + }); + Ok(()) +} + + + pub fn get_snip20_balance( + router: &mut App, + contract: &ContractInfo, + from: &str, + view_key: &str + ) -> Uint128 { + let msg = to_binary(&snip20::QueryMsg::Balance { + address: from.to_string(), + key: view_key.to_string(), + }).unwrap(); + + let balance: snip20::QueryAnswer = router.query_test(contract.to_owned(), msg).unwrap(); + if let snip20::QueryAnswer::Balance { amount } = balance { + return amount; + } + Uint128::zero() + } + + pub fn get_amm_pair_config(router: &mut App, amm_pair_contract: &ContractInfo) + -> (SContract, SContract, Option, TokenPair, Option) { + let query: AMMPairQueryResponse = router.query_test(amm_pair_contract.to_owned(),to_binary(&AMMPairQueryMsg::GetConfig { }).unwrap()).unwrap(); + match query { + AMMPairQueryResponse::GetConfig { + factory_contract, + lp_token, + staking_contract, + pair, + custom_fee + } => { + return (factory_contract, lp_token,staking_contract, pair,custom_fee ) + }, + _ => panic!("Query Responsedoes not match") + } + } + + pub fn get_pair_liquidity_pool_balance(router: &mut App, amm_pair_contract: &ContractInfo) + -> (Uint128, Uint128, Uint128) { + let query: AMMPairQueryResponse = router.query_test(amm_pair_contract.to_owned(),to_binary(&AMMPairQueryMsg::GetPairInfo { }).unwrap()).unwrap(); + match query { + AMMPairQueryResponse::GetPairInfo { + liquidity_token: _, + factory: _, + pair: _, + amount_0, + amount_1, + total_liquidity, + contract_version: _, + } => { + return (total_liquidity, amount_0, amount_1) + }, + _ => panic!("Query Responsedoes not match") + } + } + + + pub fn mk_create_permit_data(pub_key: &str, sign: &str, chain_id: &str) + -> StdResult + { + //secretd tx sign-doc file --from a + let new_permit = TestPermit{ + params: PermitData { data: to_binary(&QueryData {}).unwrap(), key: "0".to_string()}, + chain_id: Some(chain_id.to_string()), + sequence: Some(Uint128::zero()), + signature: PermitSignature { + pub_key: PubKey::new(Binary::from_base64(pub_key).unwrap()), + signature: Binary::from_base64(sign).unwrap(), + }, + account_number: Some(Uint128::zero()), + memo: Some("".to_string()) + }; + return Ok(new_permit); + } + + pub fn get_current_block_time(router: &App) -> Uint128 { + let current_timestamp = router.block_info().time; + Uint128::new(current_timestamp.seconds() as u128) + } + + pub fn mint_deposit_snip20( + router: &mut App, + contract: &ContractInfo, + recipient: &Addr, + amount: Uint128, + sender: &Addr + ) { + let _viewing_key_response = set_viewing_key(router, &contract, "seed", sender).unwrap(); + let _deposit_resposne = deposit_snip20(router,&contract, amount, &sender).unwrap(); + let _mint_response = mint_snip20(router, amount, &recipient,&contract, &sender).unwrap(); + } + + pub fn increase_allowance( + router: &mut App, + contract: &ContractInfo, + amount: Uint128, + spender: &Addr, + sender: &Addr + ) + -> StdResult{ + let msg = snip20::ExecuteMsg::IncreaseAllowance { + spender: spender.to_string() , + amount: amount, + expiration: None, + padding: None + }; + + let respone = router.execute_contract(sender.to_owned(), contract, &msg, &[]).unwrap(); + Ok(respone) + } + + pub fn create_token_pair(token_0_contract: &SContract, token_1_contract: &SContract) -> TokenPair { + let pair = TokenPair( + TokenType::CustomToken { + contract_addr: token_0_contract.address.to_owned(), + token_code_hash: token_0_contract.code_hash.to_owned(), + }, + TokenType::CustomToken { + contract_addr: token_1_contract.address.to_owned(), + token_code_hash: token_1_contract.code_hash.to_owned(), + }, + ); + pair + } + + pub fn create_token_pair_with_native(token_contract: &SContract) -> TokenPair { + let pair = TokenPair( + TokenType::NativeToken { + denom: "uscrt".to_string() + }, + TokenType::CustomToken { + contract_addr: token_contract.address.to_owned(), + token_code_hash: token_contract.code_hash.to_owned(), + }, + ); + pair + } + + pub fn get_contract_link_from_token_type(token_type: &TokenType) -> SContract{ + match token_type{ + TokenType::CustomToken { contract_addr, token_code_hash } => SContract { address: contract_addr.to_owned(), code_hash: token_code_hash.to_string()}, + TokenType::NativeToken { denom: _ } => SContract { address: Addr::unchecked(""), code_hash: "".to_string()}, + } + } + + + pub fn send_snip20_to_stake( + router: &mut App, + contract: &ContractInfo, + stake_contract: &ContractInfo, + amount: Uint128, + staker: &Addr, + sender: &Addr + ) -> StdResult{ + let invoke_msg = to_binary(&InvokeMsg::Stake { + from: staker.to_string(), + })?; + + let msg = snip20_reference_impl::msg::ExecuteMsg::Send { + recipient: stake_contract.address.to_owned(), + recipient_code_hash: Some(stake_contract.code_hash.clone()), + amount: amount, + msg: Some(invoke_msg), + memo: None, + padding: None, + }; + + let response: AppResponse = router.execute_contract( + sender.to_owned(), + &contract.clone(), + &msg, + &[], // + ) + .unwrap(); + Ok(response) + } + + pub fn send_snip20_to_proxy_stake( + router: &mut App, + contract: &ContractInfo, + stake_contract: &ContractInfo, + amount: Uint128, + staker: &Addr, + _proxy_addr: &Addr, + sender: &Addr + ) -> StdResult{ + let invoke_msg = to_binary(&InvokeMsg::ProxyStake { + for_addr: staker.to_string()})?; + + let msg = snip20_reference_impl::msg::ExecuteMsg::Send { + recipient: stake_contract.address.to_owned(), + recipient_code_hash: Some(stake_contract.code_hash.clone()), + amount: amount, + msg: Some(invoke_msg), + memo: None, + padding: None, + }; + + let response: AppResponse = router.execute_contract( + sender.to_owned(), + &contract.clone(), + &msg, + &[], // + ) + .unwrap(); + Ok(response) + } + + + pub fn send_snip20_with_msg( + router: &mut App, + contract: &ContractInfo, + receiver: &ContractInfo, + amount: Uint128, + sender: &Addr, + msg: &Binary + ) -> StdResult{ + let msg = snip20_reference_impl::msg::ExecuteMsg::Send { + recipient: receiver.address.to_owned(), + recipient_code_hash: Some(receiver.code_hash.clone()), + amount: amount, + msg: Some(msg.clone()), + memo: None, + padding: None, + }; + + let response: AppResponse = router.execute_contract( + sender.to_owned(), + &contract.clone(), + &msg, + &[], // + ) + .unwrap(); + Ok(response) + } + + pub fn snip_20_balance_query( + router: &App, + address: &Addr, + key: &str, + contract: &ContractInfo, + ) -> StdResult { + let answer = to_binary(&QueryMsg::Balance { + address: address.to_string(), + key: key.to_string(), + }).unwrap(); + + let query_response = router.query_test(contract.to_owned(), answer).unwrap(); + match query_response { + QueryAnswer::Balance { amount, .. } => Ok(amount), + _ => Err(StdError::generic_err("Invalid Balance Response")), //TODO: better error + } + } + + pub fn snip20_send( + router: &mut App, + contract: &ContractInfo, + recipient: &Addr, + amount: Uint128, + sender: &Addr + ) -> StdResult{ + let msg = snip20_reference_impl::msg::ExecuteMsg::Send { + recipient: recipient.to_owned(), + recipient_code_hash: None, + amount: amount, + msg: None, + memo: None, + padding: None, + }; + + let response: AppResponse = router.execute_contract( + sender.to_owned(), + &contract.clone(), + &msg, + &[], + ) + .unwrap(); + Ok(response) + } + + pub fn mint_snip20( + router: &mut App, + amount: Uint128, + recipient: &Addr, + contract: &ContractInfo, + sender: &Addr + ) -> StdResult{ + let msg = snip20_reference_impl::msg::ExecuteMsg::Mint { + recipient: recipient.to_owned(), + amount: amount, + memo: None, + padding: None + }; + + let response = router.execute_contract( + sender.to_owned(), + contract, + &msg, + &[Coin{ denom: "uscrt".to_string(), amount: amount}], // Coin{ denom: "uscrt".to_string(), amount: Uint128::new(3000000)} + ) + .unwrap(); + Ok(response) + } + + pub fn print_events(app_response: AppResponse) -> (){ + for i in app_response.events { + println!("{:}", i.ty); + for msg in i.attributes{ + println!("key {:} - value {:}", msg.key, msg.value) + } + } + } + + pub fn deposit_snip20( + router: &mut App, + contract: &ContractInfo, + amount: Uint128, + sender: &Addr + ) -> StdResult{ + let msg = snip20::ExecuteMsg::Deposit { padding: None }; + let app_response = router.execute_contract( + sender.clone(), + contract, + &msg, + &[Coin{ + denom: "uscrt".to_string(), + amount: amount + }], + ) + .unwrap(); + + Ok(app_response) + } + + pub fn set_viewing_key( + router: &mut App, + contract: &ContractInfo, + key: &str, + sender: &Addr + ) -> StdResult{ + let msg = snip20::ExecuteMsg::SetViewingKey { key: key.to_string(), padding: None}; + let app_response = router.execute_contract( + sender.to_owned(), + contract, + &msg, + &[], + ) + .unwrap(); + Ok(app_response) + } + + pub fn generate_snip20_contract( + router: &mut App, + name: String, + symbol: String, + decimal: u8) -> StdResult { + + let snip20_contract_code_id = router.store_code(snip20_contract_store()); + let init_snip20_msg = InstantiateMsg { + name: name.to_string(), + admin: Some(OWNER.to_string()), + symbol: symbol.to_string(), + decimals: decimal, + initial_balances: Some(vec![snip20::InitialBalance { + address: OWNER.into(), + amount: Uint128::from(1000000000000000u128), + }]), + prng_seed: to_binary("seed")?, + config: Some(InitConfig { + public_total_supply: Some(true), + enable_deposit: Some(true), + enable_redeem: Some(true), + enable_mint: Some(true), + enable_burn: Some(false), + enable_transfer: Some(true), + }), + query_auth: None, + }; + let init_snip20_code_id = router + .instantiate_contract( + snip20_contract_code_id, + mk_address(&OWNER), + &init_snip20_msg, + &[], + "label", + Some(OWNER.to_string()), + ).unwrap(); + Ok(init_snip20_code_id) + } + + +} \ No newline at end of file diff --git a/packages/multi_test/src/lib.rs b/packages/multi_test/src/lib.rs new file mode 100644 index 0000000..3555216 --- /dev/null +++ b/packages/multi_test/src/lib.rs @@ -0,0 +1,14 @@ +#[cfg(not(target_arch = "wasm32"))] +pub mod help_lib; +#[cfg(not(target_arch = "wasm32"))] +pub mod auth; +#[cfg(not(target_arch = "wasm32"))] +pub mod util_addr; +#[cfg(not(target_arch = "wasm32"))] +pub mod factory; +#[cfg(not(target_arch = "wasm32"))] +pub mod staking; +#[cfg(not(target_arch = "wasm32"))] +pub mod amm_pairs; +#[cfg(not(target_arch = "wasm32"))] +pub mod admin; \ No newline at end of file diff --git a/packages/multi_test/src/staking/mod.rs b/packages/multi_test/src/staking/mod.rs new file mode 100644 index 0000000..7728df6 --- /dev/null +++ b/packages/multi_test/src/staking/mod.rs @@ -0,0 +1,4 @@ +pub use staking_mock::*; +pub mod staking_mock; +pub mod staking_lib; +pub use staking_lib::*; \ No newline at end of file diff --git a/packages/multi_test/src/staking/staking_lib.rs b/packages/multi_test/src/staking/staking_lib.rs new file mode 100644 index 0000000..d018a6c --- /dev/null +++ b/packages/multi_test/src/staking/staking_lib.rs @@ -0,0 +1,30 @@ +pub mod staking_lib{ + + use cosmwasm_std::{Uint128, Addr, Empty}; + use secret_multi_test::{App, Contract, ContractWrapper}; + use staking::contract::{execute as staking_execute, instantiate as staking_instantiate, query as staking_query}; + use shadeswap_shared::{staking::StakingContractInit, core::{TokenType, ContractInstantiationInfo}}; + + pub fn staking_contract_store_in() -> Box> { + let contract = ContractWrapper::new_with_empty(staking_execute, staking_instantiate, staking_query); + Box::new(contract) + } + + pub fn create_staking_info_contract( + code_id: u64, + code_hash: &str, + daily_reward_amount: Uint128, + reward_token: TokenType, + valid_to: Uint128 + ) -> StakingContractInit { + StakingContractInit{ + contract_info: ContractInstantiationInfo{ + code_hash: code_hash.to_string(), + id: code_id, + }, + daily_reward_amount: daily_reward_amount, + reward_token: reward_token, + valid_to: valid_to, + } + } +} \ No newline at end of file diff --git a/packages/multi_test/src/staking/staking_mock.rs b/packages/multi_test/src/staking/staking_mock.rs new file mode 100644 index 0000000..adada0e --- /dev/null +++ b/packages/multi_test/src/staking/staking_mock.rs @@ -0,0 +1,79 @@ +pub mod staking_mock { + use cosmwasm_std::{ + entry_point, to_binary, Binary, Deps, DepsMut, + Env, MessageInfo, Response, StdResult, + }; + use schemars::JsonSchema; + use serde::{Deserialize, Serialize}; + use shadeswap_shared::{ + staking::{ExecuteMsg, QueryMsg}, + utils::{pad_query_result, pad_response_result}, + }; + + pub const BLOCK_SIZE: usize = 256; + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] + pub struct InitMsg {} + + #[entry_point] + pub fn instantiate( + _deps: DepsMut, + env: Env, + _info: MessageInfo, + _msg: InitMsg, + ) -> StdResult { + println!("test init staking"); + let mut response = Response::new(); + response.data = Some(env.contract.address.as_bytes().into()); + Ok(response) + } + + #[entry_point] + pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + pad_query_result( + match msg { + QueryMsg::GetContractOwner {} => to_binary(""), + QueryMsg::GetConfig {} => to_binary(""), + QueryMsg::WithPermit { + permit: _, + query: _, + } => to_binary(""), + }, + BLOCK_SIZE, + ) + } + + #[entry_point] + pub fn execute( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: ExecuteMsg, + ) -> StdResult { + pad_response_result( + match msg { + ExecuteMsg::ClaimRewards {} => Ok(Response::new()), + ExecuteMsg::ProxyUnstake { for_addr: _, amount: _ } => Ok(Response::new()), + ExecuteMsg::Unstake { + amount: _, + remove_liqudity: _, + } => Ok(Response::new()), + ExecuteMsg::Receive { from: _, msg: _, amount: _ } => Ok(Response::new()), + ExecuteMsg::SetRewardToken { + reward_token: _, + daily_reward_amount: _, + valid_to: _, + } => Ok(Response::new()), + ExecuteMsg::SetAuthenticator { authenticator: _ } => Ok(Response::new()), + ExecuteMsg::RecoverFunds { + token: _, + amount: _, + to: _, + msg: _, + } => Ok(Response::new()), + ExecuteMsg::SetConfig { admin_auth: _ } => todo!(), + }, + BLOCK_SIZE, + ) + } +} diff --git a/packages/multi_test/src/util_addr.rs b/packages/multi_test/src/util_addr.rs new file mode 100644 index 0000000..9a8ee4e --- /dev/null +++ b/packages/multi_test/src/util_addr.rs @@ -0,0 +1,18 @@ +pub mod util_addr{ + + pub const CONTRACT_ADDRESS: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy6"; + pub const TOKEN_A: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy2"; + pub const TOKEN_B: &str = "secret12qmz6uuapxgz7t0zed82wckl4mff5pt5czcmy4"; + pub const SENDER: &str = "secret13q9rgw3ez5mf808vm6k0naye090hh0m5fe2436"; + pub const OWNER: &str = "secret102nasmxnxvwp5agc4lp3flc6s23335xm8g7gn9"; + pub const OWNER_PUB_KEY: &str = "A0qzJ3s16OKUfn1KFyh533vBnBOQIT0jm+R/FBobJCfa"; + pub const OWNER_SIGNATURE: &str = + "4pZtghyHKHHmwiGNC5JD8JxCJiO+44j6GqaLPc19Q7lt85tr0IRZHYcnc0pkokIds8otxU9rcuvPXb0+etLyVA=="; + pub const STAKER_A: &str = "secret1m79yd3jh97vz4tqu0m8g49gfl7qmknhhwsc58g"; + pub const STAKER_B: &str = "secret1r5gk4wy0jyqg7mndw8gjks65evrtffs3ud2vk6"; + pub const PUB_KEY_STAKER_A: &str = "A50CTeVnMYyZGh7K4x4NtdfG1H1oicog6lEoPMi65IK2"; +} + +pub mod util_blockchain{ + pub const CHAIN_ID: &str = "pulsar-2"; +} \ No newline at end of file diff --git a/packages/network_integration/Cargo.toml b/packages/network_integration/Cargo.toml index 6aa44cf..dc6ec75 100644 --- a/packages/network_integration/Cargo.toml +++ b/packages/network_integration/Cargo.toml @@ -14,9 +14,9 @@ crate-type = ["cdylib", "rlib"] [features] default = [] -#[[bin]] -#name="scrtcli" -#path="src/launch/scrtcli.rs" +[[bin]] +name="cli_run" +path="src/launch/cli_run.rs" [dependencies] colored = "2.0.0" diff --git a/packages/network_integration/src/cli_commands.rs b/packages/network_integration/src/cli_commands.rs index 7240b57..0af64e7 100644 --- a/packages/network_integration/src/cli_commands.rs +++ b/packages/network_integration/src/cli_commands.rs @@ -1,76 +1,114 @@ - -pub mod snip20_lib{ +pub mod snip20_lib { use std::io; - - use secretcli::{secretcli::{Report, handle, query}, cli_types::NetContract}; + use serde_json::Result; + use secretcli::{ + cli_types::NetContract, + secretcli::{handle, query, Report}, + }; use snip20_reference_impl::msg::QueryAnswer; - - use crate::utils::{InitConfig, init_snip20_cli, GAS}; + use crate::utils::{init_snip20_cli, InitConfig, GAS}; use cosmwasm_std::Addr; - pub const SNIP20_FILE: &str = "../../compiled/snip20.wasm.gz"; - - pub fn create_new_snip_20(account_name: &str, backend: &str, name:&str, symbol:&str, decimal: u8, - viewing_key:&str, reports: &mut Vec, enable_burn: bool, enable_mint: bool, enable_deposit: bool, - enable_redeem: bool, public_total_sypply:bool) -> io::Result - { - println!("Creating SNIP20 token - Name: {}, Symbol: {}, Decimals: {}", name, symbol, decimal); - let snip20 = init_snip20_contract(&name.trim(), &symbol.trim(), - reports, decimal, account_name, backend, enable_burn, enable_mint, enable_deposit, - enable_redeem, public_total_sypply)?; - - let contract = NetContract{ + + pub fn create_new_snip_20( + account_name: &str, + backend: &str, + name: &str, + symbol: &str, + decimal: u8, + viewing_key: &str, + reports: &mut Vec, + enable_burn: bool, + enable_mint: bool, + enable_deposit: bool, + enable_redeem: bool, + public_total_sypply: bool, + ) -> io::Result { + println!( + "Creating SNIP20 token - Name: {}, Symbol: {}, Decimals: {}", + name, symbol, decimal + ); + let snip20 = init_snip20_contract( + &name.trim(), + &symbol.trim(), + reports, + decimal, + account_name, + backend, + enable_burn, + enable_mint, + enable_deposit, + enable_redeem, + public_total_sypply, + )?; + + let contract = NetContract { label: snip20.label.to_string(), id: snip20.id.clone().to_string(), code_hash: snip20.code_hash.clone(), - address: snip20.address.clone().to_string() + address: snip20.address.clone().to_string(), }; - - set_viewing_key(viewing_key, &contract.clone(), reports, - account_name, backend)?; + + set_viewing_key( + viewing_key, + &contract.clone(), + reports, + account_name, + backend, + )?; Ok(contract) } - - pub fn init_snip20_contract(symbol: &str, name: &str, reports: &mut Vec, - decimal: u8, account_name: &str, keyring_backend: &str, enable_burn: bool, enable_mint: bool, enable_deposit: bool, - enable_redeem: bool, public_total_sypply:bool) -> io::Result{ - - let config = InitConfig{ + + pub fn init_snip20_contract( + symbol: &str, + name: &str, + reports: &mut Vec, + decimal: u8, + account_name: &str, + keyring_backend: &str, + enable_burn: bool, + enable_mint: bool, + enable_deposit: bool, + enable_redeem: bool, + public_total_sypply: bool, + ) -> Result { + let config = InitConfig { enable_burn: Some(enable_burn), enable_mint: Some(enable_mint), - enable_deposit : Some(enable_deposit), + enable_deposit: Some(enable_deposit), enable_redeem: Some(enable_redeem), public_total_supply: Some(public_total_sypply), }; - + let s_contract = init_snip20_cli( name.to_string(), symbol.to_string(), decimal, Some(config), reports, - &account_name, - Some(&SNIP20_FILE), - &keyring_backend + &account_name, + None, + &keyring_backend, )?; - + println!("Contract address - {}", s_contract.1.address.clone()); println!("Code hash - {}", s_contract.1.code_hash.clone()); println!("Code Id - {}", s_contract.1.id); - + Ok(s_contract.1) } - fn set_viewing_key( - viewing_key: &str, - net_contract: &NetContract, + pub fn set_viewing_key( + viewing_key: &str, + net_contract: &NetContract, reports: &mut Vec, account_name: &str, - backend: &str) ->io::Result<()>{ + backend: &str, + ) -> io::Result<()> { let msg = snip20_reference_impl::msg::ExecuteMsg::SetViewingKey { key: String::from(viewing_key), padding: None, }; - + handle( &msg, &net_contract, @@ -82,117 +120,187 @@ pub mod snip20_lib{ None, )?; Ok(()) - } + } - pub fn balance_snip20_query( snip20_addr: String, spender: String, - key: String - ) -> io::Result<()> - { - let msg = &snip20_reference_impl::msg::QueryMsg::Balance { address: Addr::unchecked(spender.clone()), key: key.clone() }; + key: String, + ) -> io::Result<()> { + let msg = &snip20_reference_impl::msg::QueryMsg::Balance { + address: Addr::unchecked(spender.clone()), + key: key.clone(), + }; - let snip20_contract = NetContract { label: "".to_string(), id: "".to_string(), address: snip20_addr.clone(), code_hash: "".to_string() }; + let snip20_contract = NetContract { + label: "".to_string(), + id: "".to_string(), + address: snip20_addr.clone(), + code_hash: "".to_string(), + }; let snip_query: QueryAnswer = query(&snip20_contract, msg, None)?; - if let QueryAnswer::Balance { amount } = snip_query { - println!("Balance Snip20 {} - address {} - amount {}", snip20_addr.clone(), spender.clone(),amount); + if let QueryAnswer::Balance { amount } = snip_query { + println!( + "Balance Snip20 {} - address {} - amount {}", + snip20_addr.clone(), + spender.clone(), + amount + ); } - + Ok(()) } } -pub mod factory_lib{ +pub mod factory_lib { use std::io; - use cosmwasm_std::Uint128; - use secretcli::{cli_types::NetContract, secretcli::{Report, store_and_return_contract, handle}}; + use cosmwasm_std::{Uint128, Binary}; + use secretcli::{ + cli_types::NetContract, + secretcli::{handle, store_and_return_contract, Report}, + }; use shadeswap_shared::{ - amm_pair::{AMMSettings}, - core::{ContractInstantiationInfo, ContractLink, Fee}, - msg::{ - factory::{ - InitMsg as FactoryInitMsg, - }, - }, - c_std::{Addr, to_binary}, + amm_pair::AMMSettings, + c_std::{to_binary, Addr}, + core::{ContractInstantiationInfo, Fee}, + msg::factory::InitMsg as FactoryInitMsg, + Contract, }; - use crate::utils::{init_contract_factory, STORE_GAS, GAS, API_KEY}; - + use crate::utils::{init_contract_factory, API_KEY, GAS, STORE_GAS}; + pub const LPTOKEN20_FILE: &str = "../../compiled/lp_token.wasm.gz"; pub const AMM_PAIR_FILE: &str = "../../compiled/amm_pair.wasm.gz"; pub const FACTORY_FILE: &str = "../../compiled/factory.wasm.gz"; - pub fn create_factory_contract(account_name: &str, backend: &str, reports: &mut Vec) - -> io::Result - { + pub fn create_factory_contract( + account_name: &str, + backend: &str, + reports: &mut Vec, + api_key:&str, + seed: &str, + lp_fee_nom: u8, + lp_fee_denom: u16, + shade_dao_fee_nom: u8, + shade_dao_fee_denom: u16, + shade_dao_address: &str, + shade_dao_code_hash: &str, + admin_contract: &str, + admin_contract_code_hash: &str, + auth_addr: &str, + auth_code_hash: &str + ) -> io::Result { println!("Creating New Factory"); - let lp_token = - store_and_return_contract(&LPTOKEN20_FILE, - &account_name, - Some(STORE_GAS), - Some(backend) - )?; - - let pair_contract = - store_and_return_contract(&AMM_PAIR_FILE, - &account_name, - Some(STORE_GAS), - Some(backend) - )?; - - let init_msg = FactoryInitMsg{ - pair_contract: ContractInstantiationInfo{ - code_hash: pair_contract.code_hash.to_string().clone(), - id: pair_contract.id.clone().parse::().unwrap() + let lp_token = store_and_return_contract( + &LPTOKEN20_FILE, + &account_name, + Some(STORE_GAS), + Some(backend), + )?; + + let mut auth_contract: Option = None; + if auth_addr != ""{ + auth_contract = Some(Contract{address: Addr::unchecked(auth_addr), code_hash: auth_code_hash.to_string()}) + } + + let pair_contract = store_and_return_contract( + &AMM_PAIR_FILE, + &account_name, + Some(STORE_GAS), + Some(backend), + )?; + + let init_msg = FactoryInitMsg { + pair_contract: ContractInstantiationInfo { + code_hash: pair_contract.code_hash.to_string().clone(), + id: pair_contract.id.clone().parse::().unwrap(), }, - amm_settings: AMMSettings{ - shade_dao_fee: Fee::new(8, 100), - lp_fee: Fee::new(2, 8), - shade_dao_address: ContractLink { - address: Addr::unchecked("".to_string()), - code_hash: "".to_string(), + amm_settings: AMMSettings { + shade_dao_fee: Fee::new(shade_dao_fee_nom, shade_dao_fee_denom), + lp_fee: Fee::new(lp_fee_nom, lp_fee_denom), + shade_dao_address: Contract { + address: Addr::unchecked(shade_dao_address.to_string()), + code_hash: shade_dao_code_hash.to_string() }, }, - lp_token_contract: ContractInstantiationInfo{ - code_hash: lp_token.code_hash.to_string().clone(), - id: lp_token.id.clone().parse::().unwrap() + lp_token_contract: ContractInstantiationInfo { + code_hash: lp_token.code_hash.to_string().clone(), + id: lp_token.id.clone().parse::().unwrap(), }, - prng_seed: to_binary(&"".to_string()).unwrap(), + prng_seed: to_binary(seed).unwrap(), api_key: API_KEY.to_string(), - authenticator: None, + authenticator: auth_contract, + admin_auth: Contract{address: Addr::unchecked(admin_contract.to_string()), code_hash: admin_contract_code_hash.to_string()}, }; - - let factory_contract = init_contract_factory( - &account_name, - &backend, - &FACTORY_FILE, - &init_msg, - reports - )?; - + + let factory_contract = + init_contract_factory(&account_name, &backend, &FACTORY_FILE, &init_msg, reports)?; + Ok(factory_contract) } + pub fn deposit_snip20( + account_name: &str, + backend: &str, + token_addr: &str, + amount: &str, + reports: &mut Vec, + ) -> io::Result<()> { + println!( + "Deposit to SNIP20 - token {} - amount {}", + token_addr.to_string(), + amount + ); + let net_contract = NetContract { + label: "".to_string(), + id: "".to_string(), + address: token_addr.to_string(), + code_hash: "".to_string(), + }; + + let msg = snip20_reference_impl::msg::ExecuteMsg::Deposit { padding: None }; + handle( + &msg, + &net_contract, + account_name, + Some(GAS), + Some(backend), + Some(amount), + reports, + None, + )?; + Ok(()) + } + pub fn mint_snip20( account_name: &str, backend: &str, recipient: String, - amount: Uint128, - amount_uscrt: &str, + amount: Uint128, + amount_uscrt: &str, reports: &mut Vec, - snip20_addr: String - ) -> io::Result<()>{ - println!("Minting SNIP20 {} - recipient {} - amount {} - amount scrt {}", snip20_addr.clone(), recipient.clone(),amount, amount_uscrt.clone()); - let net_contract = NetContract{ + snip20_addr: String, + ) -> io::Result<()> { + println!( + "Minting SNIP20 {} - recipient {} - amount {} - amount scrt {}", + snip20_addr.clone(), + recipient.clone(), + amount, + amount_uscrt.clone() + ); + let net_contract = NetContract { label: "".to_string(), id: "".to_string(), address: snip20_addr.clone(), code_hash: "".to_string(), }; - let msg = snip20_reference_impl::msg::ExecuteMsg::Mint { padding: None, recipient: Addr::unchecked(recipient.clone()), amount: amount, memo: None }; + let msg = snip20_reference_impl::msg::ExecuteMsg::Mint { + padding: None, + recipient: Addr::unchecked(recipient.clone()), + amount: amount, + memo: None, + }; handle( &msg, &net_contract, @@ -206,17 +314,78 @@ pub mod factory_lib{ Ok(()) } + pub fn send_snip_with_msg( + account_name: &str, + backend: &str, + token_addr: &str, + snip_20_amount: Uint128, + recipient: &str, + recipient_code_hash: Option, + msg: Option, + reports: &mut Vec, + ) -> io::Result<()> { + println!( + "Send to SNIP20 - token {} - amount {} - recipient {}", + token_addr.to_string(), + snip_20_amount.to_string(), + recipient.to_string() + ); + + let msg_binary: Option = match msg{ + Some(mg) => Some(to_binary(&mg).unwrap()), + None => None, + }; + + let rec_code_hash = match recipient_code_hash{ + Some(hash) => Some(hash), + None => None, + }; + + let net_contract = NetContract { + label: "".to_string(), + id: "".to_string(), + address: token_addr.to_string(), + code_hash: "".to_string(), + }; + + let msg = snip20_reference_impl::msg::ExecuteMsg::Send { + recipient: Addr::unchecked(token_addr.to_string()), + recipient_code_hash: rec_code_hash, + amount: snip_20_amount, + msg: msg_binary, + memo: None, + padding: None + }; + + handle( + &msg, + &net_contract, + account_name, + Some(GAS), + Some(backend), + None, + reports, + None, + )?; + Ok(()) + } + + pub fn increase_allowance( spender: String, amount: Uint128, snip20_addr: String, account_name: &str, backend: &str, - reports: &mut Vec - ) -> io::Result<()> - { - println!("Increase Allowance SNIP20 {} - spender {} - amount {}", snip20_addr.clone(), spender.clone(),amount); - let net_contract = NetContract{ + reports: &mut Vec, + ) -> io::Result<()> { + println!( + "Increase Allowance SNIP20 {} - spender {} - amount {}", + snip20_addr.clone(), + spender.clone(), + amount + ); + let net_contract = NetContract { label: "".to_string(), id: "".to_string(), address: snip20_addr.clone(), @@ -242,334 +411,443 @@ pub mod factory_lib{ } } -pub mod router_lib{ +pub mod router_lib { use std::io; - use secretcli::{cli_types::NetContract, secretcli::{Report, init, handle}}; + use secretcli::{ + cli_types::NetContract, + secretcli::{handle, init, Report}, + }; + use shadeswap_shared::utils::asset::Contract; use shadeswap_shared::{ - msg::{ - router::{ - ExecuteMsg as RouterExecuteMsg, InitMsg as RouterInitMsg - }, - },c_std::{Addr, to_binary}, + c_std::{to_binary, Addr}, + msg::router::{ExecuteMsg as RouterExecuteMsg, InitMsg as RouterInitMsg}, }; - use crate::utils::{STORE_GAS, GAS, generate_label}; - + use crate::utils::{generate_label, GAS, STORE_GAS}; + pub const LPTOKEN20_FILE: &str = "../../compiled/lp_token.wasm.gz"; pub const AMM_PAIR_FILE: &str = "../../compiled/amm_pair.wasm.gz"; pub const FACTORY_FILE: &str = "../../compiled/factory.wasm.gz"; pub const ROUTER_FILE: &str = "../../compiled/router.wasm.gz"; - pub fn create_router_contract(code_hash: String, + pub fn create_router_contract( + admin_code_hash: String, account_name: &str, backend: &str, - reports: &mut Vec) -> io::Result - { - println!("Creating New Router Contract with Pair Code Hash {}", code_hash.clone()); - let router_msg = RouterInitMsg { - prng_seed: to_binary(&"".to_string()).unwrap(), - entropy: to_binary(&"".to_string()).unwrap(), - pair_contract_code_hash: code_hash, - }; - - let router_contract = init( - &router_msg, - &ROUTER_FILE, - &*generate_label(8), - account_name, - Some(STORE_GAS), - Some(GAS), - Some(backend), - reports, - )?; - - Ok(router_contract) - } + reports: &mut Vec, + admin: &str + ) -> io::Result { + let router_msg = RouterInitMsg { + prng_seed: to_binary(&"".to_string()).unwrap(), + entropy: to_binary(&"".to_string()).unwrap(), + admin_auth: Contract { address: Addr::unchecked(admin.to_string()), code_hash: admin_code_hash.to_string()}, + }; - pub fn register_snip20_router( - account_name: &str, - backend: &str, - snip20_address: String, - snip20_code_hash: String, - router_address: String, - reports: &mut Vec - ) -> io::Result<()> - { - println!("Registering SNIP20 {} {} to the Router {}",snip20_address.clone(),snip20_code_hash.clone(), router_address.clone()); - let net_contract = NetContract{ - address: router_address.clone(), - label: "".to_string(), - id: "".to_string(), - code_hash: "".to_string(), - }; + let router_contract = init( + &router_msg, + &ROUTER_FILE, + &*generate_label(8), + account_name, + Some(STORE_GAS), + Some(GAS), + Some(backend), + reports, + )?; - handle( - &RouterExecuteMsg::RegisterSNIP20Token { - token_addr: Addr::unchecked(snip20_address.clone()), - token_code_hash: snip20_code_hash.clone(), - }, - &net_contract, - account_name, - Some(GAS), - Some(backend), - None, - reports, - None, - ) - .unwrap(); - - Ok(()) - } - + Ok(router_contract) + } + + pub fn register_snip20_router( + account_name: &str, + backend: &str, + snip20_address: String, + snip20_code_hash: String, + router_address: String, + reports: &mut Vec, + ) -> io::Result<()> { + println!( + "Registering SNIP20 {} {} to the Router {}", + snip20_address.clone(), + snip20_code_hash.clone(), + router_address.clone() + ); + let net_contract = NetContract { + address: router_address.clone(), + label: "".to_string(), + id: "".to_string(), + code_hash: "".to_string(), + }; + + handle( + &RouterExecuteMsg::RegisterSNIP20Token { + token_addr: snip20_address.clone(), + token_code_hash: snip20_code_hash.clone(), + }, + &net_contract, + account_name, + Some(GAS), + Some(backend), + None, + reports, + None, + ) + .unwrap(); + + Ok(()) + } } -pub mod amm_pair_lib{ +pub mod amm_pair_lib { use cosmwasm_std::Uint128; use secretcli::{ cli_types::{NetContract, StoredContract}, secretcli::{handle, query, store_and_return_contract, Report}, }; - use std::io; use shadeswap_shared::{ - core::{ContractInstantiationInfo, TokenType, TokenPair, TokenPairAmount}, + c_std::{to_binary, Addr}, + core::{ContractInstantiationInfo, TokenPair, TokenPairAmount, TokenType}, msg::{ amm_pair::{ - ExecuteMsg as AMMPairHandlMsg + ExecuteMsg as AMMPairHandlMsg, + QueryMsg as AMMPairQueryMsg, + QueryMsgResponse as AMMPairQueryMsgResponse }, factory::{ - ExecuteMsg as FactoryExecuteMsg, - QueryMsg as FactoryQueryMsg, QueryResponse as FactoryQueryResponse, + ExecuteMsg as FactoryExecuteMsg, QueryMsg as FactoryQueryMsg, + QueryResponse as FactoryQueryResponse, }, - staking::StakingContractInit, + staking::{ExecuteMsg as StakingExecuteMsg, StakingContractInit}, }, - Pagination, c_std::{Addr, to_binary}, + Contract, Pagination, amm_pair::AMMPair, }; + use std::io; + + use crate::utils::{GAS, STORE_GAS}; + + use super::factory_lib::increase_allowance; - use crate::utils::{STORE_GAS, GAS}; - pub const LPTOKEN20_FILE: &str = "../../compiled/lp_token.wasm.gz"; pub const AMM_PAIR_FILE: &str = "../../compiled/amm_pair.wasm.gz"; pub const FACTORY_FILE: &str = "../../compiled/factory.wasm.gz"; pub const ROUTER_FILE: &str = "../../compiled/router.wasm.gz"; pub const STAKING_FILE: &str = "../../compiled/staking.wasm.gz"; - pub fn store_amm_pair(account_name: &str, - backend: &str) -> io::Result - { - println!("Storing AMM Pair Contract"); - let stored_amm_pairs = store_and_return_contract(AMM_PAIR_FILE, account_name, - Some(STORE_GAS), Some(backend))?; - Ok(stored_amm_pairs) - } + pub fn store_amm_pair(account_name: &str, backend: &str) -> io::Result { + println!("Storing AMM Pair Contract"); + let stored_amm_pairs = + store_and_return_contract(AMM_PAIR_FILE, account_name, Some(STORE_GAS), Some(backend))?; + Ok(stored_amm_pairs) + } - pub fn store_staking_contract(account_name: &str, - backend: &str) -> io::Result - { - println!("Storing Staking Contract"); - let stored_amm_pairs = store_and_return_contract(AMM_PAIR_FILE, account_name, - Some(STORE_GAS), Some(backend))?; - Ok(stored_amm_pairs) - } + pub fn store_staking_contract(account_name: &str, backend: &str) -> io::Result { + println!("Storing Staking Contract"); + let stored_amm_pairs = + store_and_return_contract(STAKING_FILE, account_name, Some(STORE_GAS), Some(backend))?; + Ok(stored_amm_pairs) + } - pub fn add_amm_pairs_with_staking( - factory_addr: String, - backend: &str, - account_name: &str, - token_0_address: String, - token_1_address: String, - token_code_hash: String, - reward_contract_address: String, - reward_contract_code_hash: String, - reward_amount: Uint128, - reports: &mut Vec - ) -> io::Result<()> { - println!("Creating New Pairs for factory {} - token_0 {} - token_1 {} - amount {} with staking", factory_addr.clone(), token_0_address.clone(),token_1_address.clone(), reward_amount); - let factory_contract = NetContract { label: "".to_string(), id: "".to_string(), address: factory_addr.clone(), code_hash: "".to_string() }; - - let pairs = TokenPair( - TokenType::CustomToken { - contract_addr: Addr::unchecked(token_0_address.clone()), - token_code_hash: token_code_hash.clone(), - }, + pub fn add_amm_pairs( + factory_addr: String, + factory_code_hash: String, + backend: &str, + account_name: &str, + token_0_address: String, + token_0_code_hash: String, + token_1_address: String, + token_1_code_hash: String, + entropy: &str, + reward_contract_address: Option, + reward_contract_code_hash: Option, + reward_amount: Option, + valid_to: Option, + reports: &mut Vec, + ) -> io::Result<()> { + + let factory_contract = NetContract { + label: "".to_string(), + id: "".to_string(), + address: factory_addr.clone(), + code_hash: factory_code_hash, + }; + + let mut pairs:Option = None; + if &token_0_address == "" { + pairs = Some(TokenPair( + TokenType::NativeToken { + denom:"uscrt".to_string() + }, TokenType::CustomToken { contract_addr: Addr::unchecked(token_1_address.clone()), - token_code_hash: token_code_hash.clone(), + token_code_hash: token_1_code_hash.clone(), }, - ); - - let staking_contract = store_staking_contract(&account_name, &backend)?; - - handle( - &FactoryExecuteMsg::CreateAMMPair { - pair: pairs.clone(), - entropy: to_binary(&"".to_string()).unwrap(), - staking_contract: Some(StakingContractInit { - contract_info: ContractInstantiationInfo { - code_hash: staking_contract.code_hash.to_string(), - id: staking_contract.id.clone().parse::().unwrap(), - }, - daily_reward_amount: Uint128::from(reward_amount), - reward_token: TokenType::CustomToken { - contract_addr: Addr::unchecked(reward_contract_address.clone()), - token_code_hash: reward_contract_code_hash.to_string(), - }, - }), - router_contract: None, - }, - &factory_contract, - account_name, - Some(GAS), - Some(backend), - None, - reports, - None, - ) - .unwrap(); - - Ok(()) - + )); } - - pub fn add_amm_pairs_no_staking( - factory_addr: String, - backend: &str, - account_name: &str, - token_0_address: String, - token_1_address: String, - token_code_hash: String, - reports: &mut Vec - ) -> io::Result<()> { - println!("Creating New Pairs for factory {} - token_0 {} - token_1 {} - no staking", factory_addr.clone(), token_0_address.clone(),token_1_address.clone()); - let factory_contract = NetContract { label: "".to_string(), id: "".to_string(), address: factory_addr.clone(), code_hash: "".to_string() }; - - let pairs = TokenPair( + else{ + pairs = Some(TokenPair( TokenType::CustomToken { contract_addr: Addr::unchecked(token_0_address.clone()), - token_code_hash: token_code_hash.clone(), + token_code_hash: token_0_code_hash.clone(), }, TokenType::CustomToken { contract_addr: Addr::unchecked(token_1_address.clone()), - token_code_hash: token_code_hash.clone(), + token_code_hash: token_1_code_hash.clone(), }, - ); - - handle( - &FactoryExecuteMsg::CreateAMMPair { - pair: pairs.clone(), - entropy: to_binary(&"".to_string()).unwrap(), - staking_contract: None, - router_contract: None, - }, - &factory_contract, - account_name, - Some(GAS), - Some(backend), - None, - reports, - None, - ) - .unwrap(); - Ok(()) - + )); } - - pub fn list_pair_from_factory( - factory_addr: String, - start: u64, - limit: u8 - ) -> io::Result<()> - { - let factory_contract = NetContract { label: "".to_string(), id: "".to_string(), address: factory_addr.clone(), code_hash: "".to_string() }; - let msg = FactoryQueryMsg::ListAMMPairs { - pagination: Pagination { - start: start, - limit: limit, - }, - }; - let factory_query: FactoryQueryResponse = query(&factory_contract, msg, None)?; - if let FactoryQueryResponse::ListAMMPairs { amm_pairs } = factory_query { - for i in 0..amm_pairs.len() { - println!("{:?}", amm_pairs[i]); - } + + let staking_contract = store_staking_contract(&account_name, &backend)?; + let staking_contract_init: Option = match reward_contract_address { + Some(msg) => { + Some(StakingContractInit { + contract_info: ContractInstantiationInfo { + code_hash: staking_contract.code_hash.to_string(), + id: staking_contract.id.clone().parse::().unwrap(), + }, + daily_reward_amount: Uint128::from(reward_amount.unwrap()), + reward_token: TokenType::CustomToken { + contract_addr: Addr::unchecked(msg.clone()), + token_code_hash: reward_contract_code_hash.unwrap().to_string(), + }, + valid_to: Uint128::new(valid_to.unwrap()), + }) + } + None => None + }; + + handle( + &FactoryExecuteMsg::CreateAMMPair { + pair: pairs.unwrap().clone(), + entropy: to_binary(&entropy).unwrap(), + staking_contract: staking_contract_init, + }, + &factory_contract, + account_name, + Some(GAS), + Some(backend), + None, + reports, + None, + ) + .unwrap(); + + Ok(()) + } + + pub fn list_pair_from_factory(factory_addr: String, start: u64, limit: u8) -> io::Result> { + let factory_contract = NetContract { + label: "".to_string(), + id: "".to_string(), + address: factory_addr.clone(), + code_hash: "".to_string(), + }; + let msg = FactoryQueryMsg::ListAMMPairs { + pagination: Pagination { + start: start, + limit: limit, + }, + }; + let factory_query: FactoryQueryResponse = query(&factory_contract, msg, None)?; + if let FactoryQueryResponse::ListAMMPairs { amm_pairs } = factory_query { + for i in 0..amm_pairs.len() { + println!("{:?}", amm_pairs[i]); } - - Ok(()) + return Ok(amm_pairs); } + return Ok(Vec::new()); + } - pub fn get_token_type(pairs: TokenPair) -> io::Result<(String,String)>{ - let token_0_address = match pairs.0 { - TokenType::CustomToken { contract_addr, token_code_hash: _ } =>{ - contract_addr.clone().to_string() - }, - TokenType::NativeToken { denom: _ } => { - "".to_string() - } - }; - - let token_1_address = match pairs.1 { - TokenType::CustomToken { contract_addr, token_code_hash: _ } =>{ - contract_addr.clone().to_string() + pub fn get_token_type(pairs: TokenPair) -> io::Result<(String, String)> { + let token_0_address = match pairs.0 { + TokenType::CustomToken { + contract_addr, + token_code_hash: _, + } => contract_addr.clone().to_string(), + TokenType::NativeToken { denom: _ } => "".to_string(), + }; + + let token_1_address = match pairs.1 { + TokenType::CustomToken { + contract_addr, + token_code_hash: _, + } => contract_addr.clone().to_string(), + TokenType::NativeToken { denom: _ } => "".to_string(), + }; + + Ok((token_0_address, token_1_address)) + } + + pub fn set_reward_token( + account_name: &str, + backend: &str, + staking_addr: &str, + token_addr: &str, + token_code_hash: &str, + daily_reward_amount: Uint128, + valid_to: Uint128, + reports: &mut Vec, + ) -> io::Result<()> { + let staking_contract = NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_addr.to_string(), + code_hash: "".to_string(), + }; + + handle( + &StakingExecuteMsg::SetRewardToken { + reward_token: Contract { + address: Addr::unchecked(token_addr.to_string()), + code_hash: token_code_hash.to_string(), }, - TokenType::NativeToken { denom: _ } => { - "".to_string() - } - }; - - Ok((token_0_address, token_1_address)) - } + daily_reward_amount: daily_reward_amount, + valid_to: valid_to, + }, + &staking_contract, + account_name, + Some(GAS), + Some(backend), + None, + reports, + None, + ) + .unwrap(); - pub fn add_liquidity( - account_name: &str, - backend: &str, - pair_addr: String, - token_0_addr: String, - token_1_addr: String, - token_code_hash: String, - amount_0: Uint128, - amount_1: Uint128, - staking_opt: bool, - reports: &mut Vec - ) -> io::Result<()> + Ok(()) + } + + pub fn get_staking_contract(amm_pair_address: &str) -> io::Result> { + let staking_contract_msg = AMMPairQueryMsg::GetStakingContract {}; + let staking_contract_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_address.to_string(), + code_hash:"".to_string(), + }, + staking_contract_msg, + None, + )?; + if let AMMPairQueryMsgResponse::StakingContractInfo { staking_contract } = + staking_contract_query { - let pair_contract= NetContract { - label: "".to_string(), - id: "".to_string(), - address: pair_addr.clone(), - code_hash: "".to_string() }; - - let pair = TokenPair( - TokenType::CustomToken { contract_addr: Addr::unchecked(token_0_addr.clone()), token_code_hash: token_code_hash.clone() }, - TokenType::CustomToken { contract_addr: Addr::unchecked(token_1_addr.clone()), token_code_hash: token_code_hash.clone() } - ); + return Ok(staking_contract) + } + return Ok(None); + } - let mut staking:Option = None; - if staking_opt == true{ - staking = Some(true); - } + pub fn add_liquidity( + account_name: &str, + backend: &str, + pair_addr: String, + token_0_addr: String, + token_0_code_hash: String, + token_1_addr: String, + token_1_code_hash: String, + amount_0: Uint128, + amount_1: Uint128, + staking_opt: bool, + exp_return: &str, + reports: &mut Vec, + ) -> io::Result<()> { + let pair_contract = NetContract { + label: "".to_string(), + id: "".to_string(), + address: pair_addr.clone(), + code_hash: "".to_string(), + }; + + let mut pair: Option = None; + let mut native_amount: Option = None; + if token_0_addr == "" || token_1_addr == "" { + + if token_0_addr == "" { + let mut amo = amount_0.to_owned().to_string(); + let denom = "uscrt".to_string(); + amo.push_str(&denom) ; + native_amount = Some(amo.to_string()); + pair = Some(TokenPair( + TokenType::NativeToken { + denom: "uscrt".to_string() + }, + TokenType::CustomToken { + contract_addr: Addr::unchecked(token_1_addr.clone()), + token_code_hash: token_1_code_hash.clone(), + })); - handle( - &AMMPairHandlMsg::AddLiquidityToAMMContract { - deposit: TokenPairAmount { - pair: pair.clone(), - amount_0: amount_0, - amount_1: amount_1, + // increase allowance + increase_allowance(pair_addr.to_owned(), amount_1, token_1_addr, account_name, backend, reports).unwrap(); + } + else + { + + let mut amo = amount_1.to_owned().to_string(); + let denom = "uscrt".to_string(); + amo.push_str(&denom) ; + native_amount = Some(amo.to_string()); + pair = Some(TokenPair( + TokenType::CustomToken { + contract_addr: Addr::unchecked(token_0_addr.clone()), + token_code_hash: token_0_code_hash.clone(), }, - expected_return: None, - staking: staking + TokenType::NativeToken { + denom: "uscrt".to_string() + })); + + // increase allowance + increase_allowance(pair_addr.to_owned(), amount_0, token_0_addr, account_name, backend, reports).unwrap(); + + } + } + else{ + // increase allowance + increase_allowance(pair_addr.to_owned(), amount_0, token_0_addr.to_owned(), account_name, backend, reports).unwrap(); + increase_allowance(pair_addr.to_owned(), amount_1, token_1_addr.to_owned(), account_name, backend, reports).unwrap(); + + pair = Some(TokenPair( + TokenType::CustomToken { + contract_addr: Addr::unchecked(token_0_addr.clone()), + token_code_hash: token_0_code_hash.clone(), }, - &pair_contract, - account_name, - Some(GAS), - Some(backend), - None, - reports, - None, - ) - .unwrap(); - - Ok(()) + TokenType::CustomToken { + contract_addr: Addr::unchecked(token_1_addr.clone()), + token_code_hash: token_1_code_hash.clone(), + }, + )); } + + let mut expected_return: Option = None; + if exp_return != "" { + expected_return = Some(Uint128::new(exp_return.parse::().unwrap())); + } + + let mut staking: Option = None; + if staking_opt == true { + staking = Some(true); + } + -} \ No newline at end of file + handle( + &AMMPairHandlMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount { + pair: pair.unwrap(), + amount_0: amount_0, + amount_1: amount_1, + }, + expected_return: expected_return, + staking: staking, + }, + &pair_contract, + account_name, + Some(GAS), + Some(backend), + native_amount.as_ref().map(String::as_ref), + reports, + None, + ) + .unwrap(); + + Ok(()) + } +} diff --git a/packages/network_integration/src/cli_helpers.rs b/packages/network_integration/src/cli_helpers.rs index 755daec..8440223 100644 --- a/packages/network_integration/src/cli_helpers.rs +++ b/packages/network_integration/src/cli_helpers.rs @@ -1,105 +1,7 @@ use schemars::JsonSchema; -use shadeswap_shared::viewing_keys::ViewingKey; -use colored::*; -use rand::{distributions::Alphanumeric, Rng}; -use secretcli::cli_types::StoredContract; -use secretcli::secretcli::{init, handle, Report}; -use secretcli::{cli_types::NetContract, secretcli::query}; -use serde::{Serialize, Deserialize}; -use snip20_reference_impl::contract; -use std::fmt::Display; -use std::fs; -use cosmwasm_std::{ - Binary, HumanAddr, Uint128, Env -}; -use shadeswap_shared::{ - amm_pair::{AMMPair}, - msg::{ - amm_pair::{ - HandleMsg as AMMPairHandlMsg, - }, - factory::{ - HandleMsg as FactoryHandleMsg, QueryMsg as FactoryQueryMsg, - QueryResponse as FactoryQueryResponse, InitMsg as FactoryInitMsg - }, - router::{ - HandleMsg as RouterHandleMsg, - }, - }, - stake_contract::StakingContractInit, - Pagination, TokenPair, TokenPairAmount, TokenType, -}; -use shadeswap_shared::snip20_reference_impl::msg::{ - InitConfig as Snip20ComposableConfig, InitMsg as Snip20ComposableMsg, InitialBalance, -}; - -use serde_json::Result; -// Smart contracts -pub const SNIP20_FILE: &str = "../../compiled/snip20.wasm.gz"; -pub const LPTOKEN20_FILE: &str = "../../compiled/lp_token.wasm.gz"; -pub const AMM_PAIR_FILE: &str = "../../compiled/amm_pair.wasm.gz"; -pub const FACTORY_FILE: &str = "../../compiled/factory.wasm.gz"; -pub const ROUTER_FILE: &str = "../../compiled/router.wasm.gz"; -pub const STAKING_FILE: &str = "../../compiled/staking.wasm.gz"; - -pub const STORE_GAS: &str = "10000000"; -pub const GAS: &str = "800000"; -pub const VIEW_KEY: &str = "password"; -pub const ACCOUNT_KEY: &str = "a"; -pub const STAKER_KEY: &str = "b"; -pub const SHADE_DAO_KEY: &str = "c"; - -pub fn generate_label(size: usize) -> String { - rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(size) - .map(char::from) - .collect() -} - -pub fn print_header(header: &str) { - println!("{}", header.on_blue()); -} - -pub fn print_warning(warn: &str) { - println!("{}", warn.on_yellow()); -} - -pub fn print_contract(contract: &NetContract) { - println!( - "\tLabel: {}\n\tID: {}\n\tAddress: {}\n\tHash: {}", - contract.label, contract.id, contract.address, contract.code_hash - ); -} - -pub fn print_stored_contract(contract: &StoredContract) { - println!( - "\tID: {}\n\tHash: {}", - contract.id, contract.code_hash - ); -} - -pub fn print_struct(item: Printable) { - println!("{}", serde_json::to_string_pretty(&item).unwrap()); -} - -pub fn print_vec(prefix: &str, vec: Vec) { - for e in vec.iter().take(1) { - print!("{}{}", prefix, e); - } - for e in vec.iter().skip(1) { - print!(", {}", e); - } - println!(); -} - -pub fn store_struct(path: &str, data: &T) { - fs::write( - path, - serde_json::to_string_pretty(data).expect("Could not serialize data"), - ) - .expect(&format!("Could not store {}", path)); -} +use serde::{Deserialize, Serialize}; +use shadeswap_shared::snip20::InitialBalance; +use cosmwasm_std::{Addr, Uint128, Binary }; /// This type represents optional configuration values which can be overridden. /// All values are optional and have defaults which are more private by default, @@ -124,32 +26,10 @@ pub struct InitConfig { pub enable_burn: Option, } -impl InitConfig { - pub fn public_total_supply(&self) -> bool { - self.public_total_supply.unwrap_or(false) - } - - pub fn deposit_enabled(&self) -> bool { - self.enable_deposit.unwrap_or(false) - } - - pub fn redeem_enabled(&self) -> bool { - self.enable_redeem.unwrap_or(false) - } - - pub fn mint_enabled(&self) -> bool { - self.enable_mint.unwrap_or(false) - } - - pub fn burn_enabled(&self) -> bool { - self.enable_burn.unwrap_or(false) - } -} - #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema)] pub struct InitialAllowance { - pub owner: HumanAddr, - pub spender: HumanAddr, + pub owner: Addr, + pub spender: Addr, pub amount: Uint128, pub expiration: Option, } @@ -157,7 +37,7 @@ pub struct InitialAllowance { #[derive(Serialize, Deserialize, JsonSchema)] pub struct InitMsg { pub name: String, - pub admin: Option, + pub admin: Option, pub symbol: String, pub decimals: u8, pub initial_balances: Option>, @@ -166,48 +46,9 @@ pub struct InitMsg { } impl InitMsg { + + #[allow(dead_code)] pub fn config(&self) -> InitConfig { self.config.clone().unwrap_or_default() } } - - -pub fn init_snip20( - name: String, - symbol: String, - decimals: u8, - config: Option, - reports: &mut Vec, - account_key: &str, - customized_snip20_file: Option<&str>, - backend: &str -) -> Result<(InitMsg, NetContract)> { - - let init_msg = InitMsg { - name: name.to_string(), - admin: None, - symbol: symbol.to_string(), - decimals: decimals, - initial_balances: None, - prng_seed: Default::default(), - config: config - }; - - let snip_20 = init( - &init_msg, - customized_snip20_file.unwrap_or(SNIP20_FILE), - &*generate_label(8), - account_key, - Some(STORE_GAS), - Some(GAS), - Some(backend), - reports, - )?; - Ok((init_msg, snip_20)) -} - - - -pub fn create_viewing_key(env: &Env, seed: Binary, entroy: Binary) -> ViewingKey { - ViewingKey::new(&env, seed.as_slice(), entroy.as_slice()) -} \ No newline at end of file diff --git a/packages/network_integration/src/cli_menu.rs b/packages/network_integration/src/cli_menu.rs index 3888146..7c3ef9e 100644 --- a/packages/network_integration/src/cli_menu.rs +++ b/packages/network_integration/src/cli_menu.rs @@ -1,12 +1,12 @@ use std::io::{self, Write, Error, ErrorKind}; - +use cosmwasm_std::Addr; use secretcli::cli_types::StoredContract; use secretcli::{secretcli::Report, cli_types::NetContract}; use shadeswap_shared::c_std::Uint128; - -use crate::cli_commands::amm_pair_lib::{store_amm_pair, store_staking_contract, add_amm_pairs_with_staking, list_pair_from_factory, add_amm_pairs_no_staking, add_liquidity}; -use crate::cli_commands::snip20_lib::{create_new_snip_20, balance_snip20_query}; -use crate::cli_commands::factory_lib::{create_factory_contract, mint_snip20, increase_allowance}; +use shadeswap_shared::utils::asset::Contract; +use crate::cli_commands::amm_pair_lib::{store_amm_pair, store_staking_contract, add_amm_pairs, list_pair_from_factory, add_liquidity, set_reward_token}; +use crate::cli_commands::snip20_lib::{create_new_snip_20, balance_snip20_query, set_viewing_key}; +use crate::cli_commands::factory_lib::{create_factory_contract, mint_snip20, increase_allowance, deposit_snip20, send_snip_with_msg}; use crate::cli_commands::router_lib::{create_router_contract, register_snip20_router}; pub const HELP: &str = "help"; pub const CMDCREATESNIP20: &str = "snip20"; @@ -21,6 +21,11 @@ pub const CMDADDAMMPAIRS: &str = "add_amm_pair"; pub const CMDLISTAMMPAIR: &str = "list_amm_pair"; pub const CMDADDLIQ: &str = "add_liq"; pub const CMDBALANCE: &str = "snip20_bal"; +pub const CMDSETREWARDTOKEN: &str = "set_reward_token"; +pub const CMDDEPOSITSNIP20: &str = "deposit"; +pub const CMDSETVIEWINGKEY: &str = "set_viewing_key"; +pub const CMDADDLIQUIDITY: &str = "add_liquidity"; +pub const CMDSENDMSGSNIP20: &str = "send_with_msg"; pub fn parse_args(args: &[String], reports: &mut Vec) -> io::Result<()> { @@ -55,19 +60,78 @@ pub fn parse_args(args: &[String], reports: &mut Vec) -> io::Result<()> print_contract_details_cli(snip20, "Snip20".to_string()); } + if args_command == CMDSENDMSGSNIP20 { + if args.len() < 7 { + return Err(Error::new(ErrorKind::Other, "Please provide all args")); + } + let account_name = args[2].clone(); + let backend = args[3].clone(); + let token_addr = args[4].clone(); + let amount = args[5].clone().parse::().unwrap(); + let recipient = args[6].clone(); + // OPTION + let mut recipient_code_hash: Option = None; + if args.len() >= 8 { + recipient_code_hash = Some(args[7].clone()); + } + let mut msg: Option = None; + if args.len() >= 9 { + msg = Some(args[8].clone()); + } + let _ = send_snip_with_msg( + &account_name, + &backend, + &token_addr, + Uint128::new(amount), + &recipient, + recipient_code_hash, + msg, + reports + )?; + } + if args_command == CMDCREATEFACTORY { - if args.len() != 4 { + if args.len() < 16 { return Err(Error::new(ErrorKind::Other, "Please provide all args")); } let account_name = args[2].clone(); - let backend = args[3].clone(); - let factory: NetContract = create_factory_contract(&account_name, &backend, reports)?; + let backend = args[3].clone(); + let api_key = args[4].clone(); + let seed = args[5].clone(); + let lp_fee_nom = args[6].clone().parse::().unwrap(); + let lp_fee_denom = args[7].clone().parse::().unwrap(); + let shade_dao_fee_nom = args[8].clone().parse::().unwrap(); + let shade_dao_fee_denom = args[9].clone().parse::().unwrap(); + let shade_dao_address = args[10].clone(); + let shade_dao_code_hash = args[11].clone(); + let admin_contract = args[12].clone(); + let admin_contract_code_hash = args[13].clone(); + let auth_contract = args[14].clone(); + let auth_contract_code_hash = args[15].clone(); + + let factory: NetContract = create_factory_contract(& + account_name, + &backend, + reports, + &api_key, + &seed, + lp_fee_nom, + lp_fee_denom, + shade_dao_fee_nom, + shade_dao_fee_denom, + &shade_dao_address, + &shade_dao_code_hash, + &admin_contract, + &admin_contract_code_hash, + &auth_contract, + &auth_contract_code_hash + )?; print_contract_details_cli(factory, "Factory".to_string()); } if args_command == CMDCREATEROUTER{ - if args.len() != 6 { + if args.len() != 7 { return Err(Error::new(ErrorKind::Other, "Please provide all args")); } @@ -75,10 +139,41 @@ pub fn parse_args(args: &[String], reports: &mut Vec) -> io::Result<()> let backend = args[3].clone(); let _viewing_key = args[4].clone(); let code_hash = args[5].clone(); - let router: NetContract = create_router_contract(code_hash.clone(), &account_name, &backend, reports)?; + let admin = args[6].clone(); + let router: NetContract = create_router_contract(code_hash.clone(), &account_name, &backend, reports, &admin)?; print_contract_details_cli(router, "Router".to_string()); } + if args_command == CMDSETVIEWINGKEY{ + if args.len() != 6 { + return Err(Error::new(ErrorKind::Other, "Please provide all args")); + } + + let account_name = args[2].clone(); + let backend = args[3].clone(); + let token_addr = args[4].clone(); + let viewing_key = args[5].clone(); + let net_contract = NetContract{ + label: "".to_string(), + id: "".to_string(), + address: token_addr, + code_hash: "".to_string(), + }; + set_viewing_key(&viewing_key,&net_contract,reports, &account_name, &backend)?; + } + + if args_command == CMDDEPOSITSNIP20{ + if args.len() != 6 { + return Err(Error::new(ErrorKind::Other, "Please provide all args")); + } + + let account_name = args[2].clone(); + let backend = args[3].clone(); + let token_addr = args[4].clone(); + let amount = args[5].clone(); + deposit_snip20(&account_name,&backend,&token_addr,&amount,reports)?; + } + if args_command == CMDSTOREAMMPAIR{ if args.len() != 4 { return Err(Error::new(ErrorKind::Other, "Please provide all args")); @@ -136,6 +231,25 @@ pub fn parse_args(args: &[String], reports: &mut Vec) -> io::Result<()> println!("Increase Allowance SNIP20 {} has been completed", snip20_addr); } + if args_command == CMDSETREWARDTOKEN{ + let account_name = args[2].clone(); + let backend = args[3].clone(); + let staking_addr = args[4].clone(); + let reward_token_addr = args[5].clone(); + let reward_token_hash = args[6].clone(); + let daily_reward_amount = args[5].clone().parse::().unwrap(); + let valid_to = args[6].clone().parse::().unwrap(); + set_reward_token( + &account_name, + &backend, + &staking_addr, + &reward_token_addr, + &reward_token_hash, + Uint128::new(daily_reward_amount), + Uint128::new(valid_to), + reports)?; + } + if args_command == CMDSTORESTAKINGCONTRACT{ if args.len() != 4 { return Err(Error::new(ErrorKind::Other, "Please provide all args")); @@ -148,33 +262,56 @@ pub fn parse_args(args: &[String], reports: &mut Vec) -> io::Result<()> } if args_command == CMDADDAMMPAIRS{ - if args.len() != 9 { + if args.len() < 11 { return Err(Error::new(ErrorKind::Other, "Please provide all args")); } let account_name = args[2].clone(); let backend = args[3].clone(); let factory_addr = args[4].clone(); - let token_0 = args[5].clone(); - let token_1 = args[6].clone(); - let token_hash = args[7].clone(); - let staking = args[8].clone(); - let staking_enabled = staking.parse::().unwrap(); + let factory_code_hash = args[5].clone(); + let token_0 = args[6].clone(); + let token_0_hash = args[7].clone(); + let token_1 = args[8].clone(); + let token_1_hash = args[9].clone(); + let entropy = args[10].clone(); + let staking = args[11].clone(); + let staking_enabled = staking.parse::().unwrap(); + // CHECK ROUTER + let mut reward_addr:Option = None; + let mut reward_addr_code_hash:Option = None; + let mut amount:Option = None; + let mut amount_u128:Option = None; + let mut valid_to :Option= None; + if staking_enabled == true { - if args.len() != 11 { + if args.len() < 16 { return Err(Error::new(ErrorKind::Other, "Please provide all args")); } - let reward_addr = args[9].clone(); - let reward_addr_code_hash = args[11].clone(); - let amount = args[10].clone(); - let amount_u128 = amount.parse::().unwrap(); - - add_amm_pairs_with_staking(factory_addr.clone(),&backend, &account_name, token_0.clone(),token_1.clone(),token_hash.clone(), - reward_addr, reward_addr_code_hash, Uint128::from(amount_u128),reports)?; - } - else{ - add_amm_pairs_no_staking(factory_addr.clone(),&backend, &account_name, token_0.clone(),token_1.clone(),token_hash.clone(),reports)?; + reward_addr = Some(args[12].clone()); + reward_addr_code_hash = Some(args[13].clone()); + amount = Some(args[14].clone()); + amount_u128 = Some(amount.unwrap_or_default().parse::().unwrap()); + valid_to = Some(args[15].clone().parse::().unwrap()); + println!("STAKING INFO {} - {} - {} - {}", reward_addr.clone().unwrap(), reward_addr_code_hash.clone().unwrap(), amount_u128.unwrap(), valid_to.unwrap()); } + + add_amm_pairs( + factory_addr.clone(), + factory_code_hash, + &backend, + &account_name, + token_0.clone(), + token_0_hash.clone(), + token_1.clone(), + token_1_hash.clone(), + &entropy, + reward_addr, + reward_addr_code_hash, + amount_u128, + valid_to, + reports + )?; println!("Adding AMM Pair has to Factory {} has been completed", factory_addr.clone()); } @@ -202,7 +339,7 @@ pub fn parse_args(args: &[String], reports: &mut Vec) -> io::Result<()> } if args_command == CMDADDLIQ{ - if args.len() != 11 { + if args.len() != 13 { return Err(Error::new(ErrorKind::Other, "Please provide all args")); } @@ -210,16 +347,31 @@ pub fn parse_args(args: &[String], reports: &mut Vec) -> io::Result<()> let backend = args[3].clone(); let pair_addr = args[4].clone(); let token_0 = args[5].clone(); - let token_1 = args[6].clone(); - let token_code_hash = args[7].clone(); - let amount_0 = args[8].clone(); - let amount_1 = args[9].clone(); - let staking = args[10].clone(); + let token_0_code_hash = args[6].clone(); + let token_1 = args[7].clone(); + let token_1_code_hash = args[8].clone(); + let amount_0 = args[9].clone(); + let amount_1 = args[10].clone(); + let staking = args[11].clone(); let amount_0_u128 = amount_0.parse::().unwrap(); let amount_1_u128 = amount_1.parse::().unwrap(); let staking_bool = staking.parse::().unwrap(); - add_liquidity(&account_name, &backend,pair_addr.clone(),token_0.clone(), token_1.clone(), token_code_hash.clone(),Uint128::from(amount_0_u128), - Uint128::from(amount_1_u128), staking_bool, reports)?; + let exptected_return =args[12].clone(); + + add_liquidity( + &account_name, + &backend, + pair_addr, + token_0, + token_0_code_hash, + token_1, + token_1_code_hash, + Uint128::from(amount_0_u128), + Uint128::from(amount_1_u128), + staking_bool, + &exptected_return, + reports + )?; } Ok(()) } @@ -242,17 +394,32 @@ pub fn print_help() -> io::Result<()> let mut handle = stdout.lock(); handle.write_all(b"Welcome to the Shadeswap CLI.")?; handle.write_all(b"\n\t1. Command:: snip20 -- Create new Snip20 Contract")?; - handle.write_all(b"\n\t2. Command:: factory -- Create new Factory Contract")?; - handle.write_all(b"\n\t3. Command:: router -- Create new Router Contract")?; + handle.write_all(b"\n\t2. Command:: factory + + + -- Create new Factory Contract")?; + handle.write_all(b"\n\t3. Command:: router -- Create new Router Contract")?; handle.write_all(b"\n\t4. Command:: store_amm_pair -- Store AMM Pair Contract")?; handle.write_all(b"\n\t5. Command:: reg_snip20 -- Register Snip20 to Router")?; handle.write_all(b"\n\t6. Command:: allow_snip20 -- Increase Allowance for SNIP20")?; handle.write_all(b"\n\t7. Command:: mint_snip20 -- Mint Snip20")?; handle.write_all(b"\n\t8. Command:: store_stake -- Store Staking Contract Contract")?; - handle.write_all(b"\n\t9. Command:: add_amm_pair ? - if yes additional args -- Add new Pair for Factory")?; + handle.write_all(b"\n\t9. Command:: add_amm_pair + ? + if yes additional args + ) + Add new Pair for Factory")?; + handle.write_all(b"\n\t10. Command:: list_amm_pair -- List All Pairs for Factory")?; - handle.write_all(b"\n\t11. Command:: add_liq -- Add Liquidity to the AMM Pair")?; + handle.write_all(b"\n\t11. Command:: add_liq + + + Add Liquidity to the AMM Pair")?; handle.write_all(b"\n\t12. Command:: snip20_bal -- Balance Snip 20 for spender")?; + handle.write_all(b"\n\t13. Command:: set_reward_token -- Set Reward Token for Staking Contract")?; + handle.write_all(b"\n\t14. Command:: deposit -- Deposit to Snip20 Token")?; + handle.write_all(b"\n\t15. Command:: set_viewing_key -- Set Viewing Key")?; + handle.write_all(b"\n\t16. Command:: send_with_msg -- Send Amount & Msg with Callback")?; handle.write_all(b"\n")?; handle.flush()?; diff --git a/packages/network_integration/src/launch/cli_run.rs b/packages/network_integration/src/launch/cli_run.rs new file mode 100644 index 0000000..c73d691 --- /dev/null +++ b/packages/network_integration/src/launch/cli_run.rs @@ -0,0 +1,13 @@ +use std::{io, string}; +use std::env; +use std::io::{Write}; +use std::io::BufRead; +use network_integration::cli_menu::parse_args; + +fn main() +-> io::Result<()> { + let mut reports = vec![]; + let args: Vec = env::args().collect(); + parse_args(&args, &mut reports)?; + Ok(()) +} \ No newline at end of file diff --git a/packages/network_integration/src/launch/deploy.rs b/packages/network_integration/src/launch/deploy.rs index c057274..0d55a6b 100644 --- a/packages/network_integration/src/launch/deploy.rs +++ b/packages/network_integration/src/launch/deploy.rs @@ -2,18 +2,19 @@ use cosmwasm_std::to_binary; use cosmwasm_std::Addr; use cosmwasm_std::BalanceResponse; use cosmwasm_std::Uint128; -use network_integration::utils::API_KEY; +use network_integration::utils::ADMIN_FILE; use network_integration::utils::InitConfig; +use network_integration::utils::API_KEY; use network_integration::utils::{ - generate_label, init_snip20, print_contract, print_header, print_warning, - AMM_PAIR_FILE, FACTORY_FILE, GAS, LPTOKEN20_FILE, ROUTER_FILE, SNIP20_FILE, - STAKING_FILE, VIEW_KEY, + generate_label, init_snip20, print_contract, print_header, print_warning, AMM_PAIR_FILE, + FACTORY_FILE, GAS, LPTOKEN20_FILE, ROUTER_FILE, SNIP20_FILE, STAKING_FILE, VIEW_KEY, }; use secretcli::{ cli_types::NetContract, secretcli::{handle, init, query, store_and_return_contract}, }; +use shadeswap_shared::Contract; use shadeswap_shared::core::ContractInstantiationInfo; use shadeswap_shared::core::Fee; use shadeswap_shared::core::TokenPair; @@ -21,21 +22,19 @@ use shadeswap_shared::core::TokenPairAmount; use shadeswap_shared::core::TokenType; use shadeswap_shared::snip20::QueryMsg; use shadeswap_shared::{ - amm_pair::{AMMSettings}, - core::ContractLink, + amm_pair::AMMSettings, msg::{ - amm_pair::{ - ExecuteMsg as AMMPairHandlMsg - }, + amm_pair::ExecuteMsg as AMMPairHandlMsg, factory::{ ExecuteMsg as FactoryExecuteMsg, InitMsg as FactoryInitMsg, QueryMsg as FactoryQueryMsg, QueryResponse as FactoryQueryResponse, }, - router::{ - ExecuteMsg as RouterExecuteMsg, InitMsg as RouterInitMsg - }, + router::{ExecuteMsg as RouterExecuteMsg, InitMsg as RouterInitMsg}, staking::StakingContractInit, }, + contract_interfaces::admin::{ + InstantiateMsg as AdminInstantiateMsg + }, Pagination, }; @@ -56,7 +55,8 @@ pub fn get_balance(contract: &NetContract, from: String, view_key: String) -> Ui } fn main() -> serde_json::Result<()> { - redeploy_infra()?; + //redeploy_infra()?; + deploy_fresh()?; return Ok(()); } @@ -155,6 +155,33 @@ fn redeploy_infra() -> serde_json::Result<()> { Some("test"), )?; + let _admin_contract = store_and_return_contract( + &ADMIN_FILE.replace("../", ""), + ACCOUNT_KEY, + Some(STORE_GAS), + Some("test"), + )?; + + print_header("\n\tInitializing Admin Contract"); + + let admin_msg = AdminInstantiateMsg { + super_admin: Some("secret138pqmt4gyyhjrtzj9vnf2k622d5cdvwucr423q".to_string()) + }; + + let admin_contract = init( + &admin_msg, + &ADMIN_FILE.replace("../", ""), + &*generate_label(8), + ACCOUNT_KEY, + Some(STORE_GAS), + Some(GAS), + Some("test"), + &mut reports, + )?; + + print_contract(&admin_contract); + + print_header("\n\tInitializing Factory Contract"); let factory_msg = FactoryInitMsg { @@ -165,7 +192,7 @@ fn redeploy_infra() -> serde_json::Result<()> { amm_settings: AMMSettings { lp_fee: Fee::new(2, 100), shade_dao_fee: Fee::new(1, 100), - shade_dao_address: ContractLink { + shade_dao_address: Contract { address: Addr::unchecked( "secret1hfvezhepf6ahwry0gzhcra6zsdmva5xhphhzdh".to_string(), ), @@ -179,6 +206,8 @@ fn redeploy_infra() -> serde_json::Result<()> { prng_seed: to_binary(&"".to_string()).unwrap(), api_key: API_KEY.to_string(), authenticator: None, + admin_auth: Contract { address: Addr::unchecked(admin_contract.address.to_string()), + code_hash: admin_contract.code_hash.clone()} }; let factory_contract = init( @@ -212,7 +241,8 @@ fn redeploy_infra() -> serde_json::Result<()> { let router_msg = RouterInitMsg { prng_seed: to_binary(&"".to_string()).unwrap(), entropy: to_binary(&"".to_string()).unwrap(), - pair_contract_code_hash: s_amm_pair.code_hash.clone(), + admin_auth: Contract { address: Addr::unchecked(admin_contract.address.to_string()), + code_hash: admin_contract.code_hash.clone()} }; let router_contract = init( @@ -229,7 +259,7 @@ fn redeploy_infra() -> serde_json::Result<()> { handle( &RouterExecuteMsg::RegisterSNIP20Token { - token_addr: Addr::unchecked(usdt_contract.address.clone()), + token_addr: usdt_contract.address.clone(), token_code_hash: usdt_contract.code_hash.to_string(), }, &NetContract { @@ -249,7 +279,7 @@ fn redeploy_infra() -> serde_json::Result<()> { handle( &RouterExecuteMsg::RegisterSNIP20Token { - token_addr: Addr::unchecked(btc_contract.address.clone()), + token_addr: btc_contract.address.clone(), token_code_hash: btc_contract.code_hash.to_string(), }, &NetContract { @@ -282,8 +312,8 @@ fn redeploy_infra() -> serde_json::Result<()> { contract_addr: Addr::unchecked(usdt_contract.address.clone()), token_code_hash: usdt_contract.code_hash.to_string(), }, - }), - router_contract: None, + valid_to: Uint128::new(3747905010000u128) + }) }, &factory_contract, ACCOUNT_KEY, @@ -427,9 +457,39 @@ fn deploy_fresh() -> serde_json::Result<()> { )?; print_contract(&usdt_contract); + let (_eth_init, eth_contract) = init_snip20( + "ETH".to_string(), + "ETH".to_string(), + 18, + Some(InitConfig { + public_total_supply: Some(true), + enable_deposit: Some(true), + enable_redeem: Some(true), + enable_mint: Some(true), + enable_burn: Some(false), + }), + &mut reports, + ACCOUNT_KEY, + Some(&SNIP20_FILE.replace("../", "")), + )?; + print_contract(ð_contract); + { let msg = snip20_reference_impl::ExecuteMsg::Deposit { padding: None }; + handle( + &msg, + ð_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("1000000000000uscrt"), + &mut reports, + None, + )?; + + let msg = snip20_reference_impl::ExecuteMsg::Deposit { padding: None }; + handle( &msg, &usdt_contract, @@ -487,6 +547,81 @@ fn deploy_fresh() -> serde_json::Result<()> { None, )?; } + + { + let msg = snip20_reference_impl::ExecuteMsg::SetViewingKey { + key: String::from(VIEW_KEY), + padding: None, + }; + handle( + &msg, + ð_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + )?; + } + + { + let msg = snip20_reference_impl::ExecuteMsg::Mint { + padding: None, + recipient: "secret138pqmt4gyyhjrtzj9vnf2k622d5cdvwucr423q".to_string(), + amount: Uint128::new(100000000000000u128), + memo: None, + }; + + handle( + &msg, + &usdt_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("10000000uscrt"), + &mut reports, + None, + )?; + } + { + let msg = snip20_reference_impl::ExecuteMsg::Mint { + padding: None, + recipient: "secret138pqmt4gyyhjrtzj9vnf2k622d5cdvwucr423q".to_string(), + amount: Uint128::new(100000000000000000000000u128), + memo: None, + }; + + handle( + &msg, + ð_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("10000000uscrt"), + &mut reports, + None, + )?; + } + { + let msg = snip20_reference_impl::ExecuteMsg::Mint { + padding: None, + recipient: "secret138pqmt4gyyhjrtzj9vnf2k622d5cdvwucr423q".to_string(), + amount: Uint128::new(100000000000000000u128), + memo: None, + }; + + handle( + &msg, + &btc_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("10000000uscrt"), + &mut reports, + None, + )?; + } } let test_pair = TokenPair( @@ -500,6 +635,17 @@ fn deploy_fresh() -> serde_json::Result<()> { }, ); + let test_pair_2 = TokenPair( + TokenType::CustomToken { + contract_addr: Addr::unchecked(usdt_contract.address.clone()), + token_code_hash: usdt_contract.code_hash.to_string(), + }, + TokenType::CustomToken { + contract_addr: Addr::unchecked(eth_contract.address.clone()), + token_code_hash: eth_contract.code_hash.to_string(), + }, + ); + print_header("Storing all contracts"); let entropy = to_binary(&"ENTROPY".to_string()).unwrap(); @@ -526,6 +672,32 @@ fn deploy_fresh() -> serde_json::Result<()> { Some("test"), )?; + let _admin_contract = store_and_return_contract( + &ADMIN_FILE.replace("../", ""), + ACCOUNT_KEY, + Some(STORE_GAS), + Some("test"), + )?; + + print_header("\n\tInitializing Admin Contract"); + + let admin_msg = AdminInstantiateMsg { + super_admin: Some("secret138pqmt4gyyhjrtzj9vnf2k622d5cdvwucr423q".to_string()) + }; + + let admin_contract = init( + &admin_msg, + &ADMIN_FILE.replace("../", ""), + &*generate_label(8), + ACCOUNT_KEY, + Some(STORE_GAS), + Some(GAS), + Some("test"), + &mut reports, + )?; + + print_contract(&admin_contract); + print_header("\n\tInitializing Factory Contract"); let factory_msg = FactoryInitMsg { @@ -536,7 +708,7 @@ fn deploy_fresh() -> serde_json::Result<()> { amm_settings: AMMSettings { lp_fee: Fee::new(8, 100), shade_dao_fee: Fee::new(2, 100), - shade_dao_address: ContractLink { + shade_dao_address: Contract { address: Addr::unchecked( "secret1hfvezhepf6ahwry0gzhcra6zsdmva5xhphhzdh".to_string(), ), @@ -550,6 +722,8 @@ fn deploy_fresh() -> serde_json::Result<()> { prng_seed: to_binary(&"".to_string()).unwrap(), api_key: API_KEY.to_string(), authenticator: None, + admin_auth: Contract { address: Addr::unchecked(admin_contract.address.to_string()), + code_hash: admin_contract.code_hash.clone()} }; let factory_contract = init( @@ -583,7 +757,8 @@ fn deploy_fresh() -> serde_json::Result<()> { let router_msg = RouterInitMsg { prng_seed: to_binary(&"".to_string()).unwrap(), entropy: to_binary(&"".to_string()).unwrap(), - pair_contract_code_hash: s_amm_pair.code_hash.clone(), + admin_auth: Contract { address: Addr::unchecked(admin_contract.address.to_string()), + code_hash: admin_contract.code_hash.clone()} }; let router_contract = init( @@ -600,7 +775,7 @@ fn deploy_fresh() -> serde_json::Result<()> { handle( &RouterExecuteMsg::RegisterSNIP20Token { - token_addr: Addr::unchecked(usdt_contract.address.clone()), + token_addr: usdt_contract.address.clone(), token_code_hash: usdt_contract.code_hash.to_string(), }, &NetContract { @@ -620,7 +795,7 @@ fn deploy_fresh() -> serde_json::Result<()> { handle( &RouterExecuteMsg::RegisterSNIP20Token { - token_addr: Addr::unchecked(btc_contract.address.clone()), + token_addr: btc_contract.address.clone(), token_code_hash: btc_contract.code_hash.to_string(), }, &NetContract { @@ -638,11 +813,31 @@ fn deploy_fresh() -> serde_json::Result<()> { ) .unwrap(); + handle( + &RouterExecuteMsg::RegisterSNIP20Token { + token_addr: eth_contract.address.clone(), + token_code_hash: eth_contract.code_hash.to_string(), + }, + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: router_contract.address.to_string().to_string(), + code_hash: "".to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + { handle( &FactoryExecuteMsg::CreateAMMPair { pair: test_pair.clone(), - entropy: entropy, + entropy: entropy.clone(), staking_contract: Some(StakingContractInit { contract_info: ContractInstantiationInfo { code_hash: staking_contract.code_hash.to_string(), @@ -653,8 +848,37 @@ fn deploy_fresh() -> serde_json::Result<()> { contract_addr: Addr::unchecked(usdt_contract.address.clone()), token_code_hash: usdt_contract.code_hash.to_string(), }, + valid_to: Uint128::new(3747905010000u128) }), - router_contract: None, + }, + &factory_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + } + + { + handle( + &FactoryExecuteMsg::CreateAMMPair { + pair: test_pair_2.clone(), + entropy: entropy, + staking_contract: Some(StakingContractInit { + contract_info: ContractInstantiationInfo { + code_hash: staking_contract.code_hash.to_string(), + id: staking_contract.id.clone().parse::().unwrap(), + }, + daily_reward_amount: Uint128::from(100000u128), + reward_token: TokenType::CustomToken { + contract_addr: Addr::unchecked(usdt_contract.address.clone()), + token_code_hash: usdt_contract.code_hash.to_string(), + }, + valid_to: Uint128::new(3747905010000u128) + }) }, &factory_contract, ACCOUNT_KEY, @@ -678,78 +902,154 @@ fn deploy_fresh() -> serde_json::Result<()> { let factory_query: FactoryQueryResponse = query(&factory_contract, msg, None)?; if let FactoryQueryResponse::ListAMMPairs { amm_pairs } = factory_query { - let amm_pair = amm_pairs[0].clone(); - - print_header("\n\tAdding Liquidity to Pair Contract"); - handle( - &snip20_reference_impl::ExecuteMsg::IncreaseAllowance { - spender: amm_pair.address.to_string(), - amount: Uint128::from(1000000000u64), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: btc_contract.id.clone(), - address: btc_contract.address.clone(), - code_hash: btc_contract.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - - handle( - &snip20_reference_impl::ExecuteMsg::IncreaseAllowance { - spender: amm_pair.address.to_string(), - amount: Uint128::from(200000000000u64), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: usdt_contract.id.clone(), - address: usdt_contract.address.clone(), - code_hash: usdt_contract.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - - handle( - &AMMPairHandlMsg::AddLiquidityToAMMContract { - deposit: TokenPairAmount { - pair: test_pair.clone(), - amount_0: Uint128::from(200000000000u64), - amount_1: Uint128::from(1000000000u64), + { + let amm_pair = amm_pairs[0].clone(); + + print_header("\n\tAdding Liquidity to Pair Contract"); + handle( + &snip20_reference_impl::ExecuteMsg::IncreaseAllowance { + spender: amm_pair.address.to_string(), + amount: Uint128::from(1000000000u64), + expiration: None, + padding: None, }, - expected_return: None, - - staking: None, - }, - &NetContract { - label: "".to_string(), - id: s_amm_pair.id.clone(), - address: amm_pair.address.to_string(), - code_hash: s_amm_pair.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + &NetContract { + label: "".to_string(), + id: btc_contract.id.clone(), + address: btc_contract.address.clone(), + code_hash: btc_contract.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + handle( + &snip20_reference_impl::ExecuteMsg::IncreaseAllowance { + spender: amm_pair.address.to_string(), + amount: Uint128::from(200000000000u64), + expiration: None, + padding: None, + }, + &NetContract { + label: "".to_string(), + id: usdt_contract.id.clone(), + address: usdt_contract.address.clone(), + code_hash: usdt_contract.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + handle( + &AMMPairHandlMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount { + pair: test_pair.clone(), + amount_0: Uint128::from(200000000000u64), + amount_1: Uint128::from(1000000000u64), + }, + expected_return: None, + + staking: None, + }, + &NetContract { + label: "".to_string(), + id: s_amm_pair.id.clone(), + address: amm_pair.address.to_string(), + code_hash: s_amm_pair.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + } + + { + let amm_pair = amm_pairs[1].clone(); + + print_header("\n\tAdding Liquidity to Pair Contract"); + handle( + &snip20_reference_impl::ExecuteMsg::IncreaseAllowance { + spender: amm_pair.address.to_string(), + amount: Uint128::from(1308000000000000000000000u128), + expiration: None, + padding: None, + }, + &NetContract { + label: "".to_string(), + id: eth_contract.id.clone(), + address: eth_contract.address.clone(), + code_hash: eth_contract.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + handle( + &snip20_reference_impl::ExecuteMsg::IncreaseAllowance { + spender: amm_pair.address.to_string(), + amount: Uint128::from(200000000000u64), + expiration: None, + padding: None, + }, + &NetContract { + label: "".to_string(), + id: usdt_contract.id.clone(), + address: usdt_contract.address.clone(), + code_hash: usdt_contract.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + handle( + &AMMPairHandlMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount { + pair: test_pair_2.clone(), + amount_0: Uint128::from(13_080_000_000u64), + amount_1: Uint128::from(1000000000000000000u128), + }, + expected_return: None, + staking: None, + }, + &NetContract { + label: "".to_string(), + id: s_amm_pair.id.clone(), + address: amm_pair.address.to_string(), + code_hash: s_amm_pair.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + } } } } else { diff --git a/packages/network_integration/src/launch/scrtcli.rs b/packages/network_integration/src/launch/scrtcli.rs deleted file mode 100644 index e2a9ea2..0000000 --- a/packages/network_integration/src/launch/scrtcli.rs +++ /dev/null @@ -1,829 +0,0 @@ -// use std::{io, string}; -// use std::env; -// use std::io::{Write}; -// use std::io::BufRead; -// use network_integration::cli_menu::parse_args; -// use secretcli::cli_types::StoredContract; -// use shadeswap_shared::core::{ TokenPair, TokenPairAmount, TokenType, Fee, ViewingKey}; -// use shadeswap_shared::router; -// use cosmwasm_std::{Uint128, Addr}; -// use cosmwasm_std::to_binary; -// use colored::Colorize; -// use network_integration::utils::{ -// generate_label, init_snip20, print_contract, print_header, print_vec, print_warning, -// AMM_PAIR_FILE, FACTORY_FILE, GAS, LPTOKEN20_FILE, ROUTER_FILE, SHADE_DAO_KEY, -// STAKING_FILE, VIEW_KEY, InitConfig, init_contract_factory, init_snip20_cli, -// }; -// use secretcli::{ -// cli_types::NetContract, -// secretcli::{account_address, handle, init, query, store_and_return_contract, Report}, -// }; -// use shadeswap_shared::{ -// amm_pair::{AMMPair, AMMSettings}, -// core::{ContractInstantiationInfo, ContractLink}, -// msg::{ -// amm_pair::{ -// ExecuteMsg as AMMPairHandlMsg, InitMsg as AMMPairInitMsg, InvokeMsg, -// QueryMsg as AMMPairQueryMsg, QueryMsgResponse as AMMPairQueryMsgResponse, -// }, -// factory::{ -// ExecuteMsg as FactoryExecuteMsg, InitMsg as FactoryInitMsg, -// QueryMsg as FactoryQueryMsg, QueryResponse as FactoryQueryResponse, -// }, -// router::{ -// ExecuteMsg as RouterExecuteMsg, InitMsg as RouterInitMsg, InvokeMsg as RouterInvokeMsg, -// QueryMsg as RouterQueryMsg, QueryMsgResponse as RouterQueryResponse, -// }, -// staking::{ -// ExecuteMsg as StakingMsgHandle, QueryMsg as StakingQueryMsg, -// QueryResponse as StakingQueryMsgResponse, -// }, -// }, -// stake_contract::StakingContractInit, -// Pagination, -// }; - -// pub const SNIP20_FILE: &str = "../../compiled/snip20.wasm.gz"; -// // pub const LPTOKEN20_FILE: &str = "../../compiled/lp_token.wasm.gz"; -// // pub const AMM_PAIR_FILE: &str = "../../compiled/amm_pair.wasm.gz"; -// // pub const FACTORY_FILE: &str = "../../compiled/factory.wasm.gz"; -// // pub const ROUTER_FILE: &str = "../../compiled/router.wasm.gz"; -// // pub const STAKING_FILE: &str = "../../compiled/staking.wasm.gz"; - - -// pub const STORE_GAS: &str = "10000000"; - -// fn main() -> io::Result<()> { - -// // let account_name = read_string("Account Name ")?; -// // let keyring_backend = read_string("Keyring Backend ")?; -// let mut reports = vec![]; -// let args: Vec = env::args().collect(); -// parse_args(&args, &mut reports)?; - -// // while true -// // { -// // print_options()?; -// // let input = read_input()?; -// // if input == 10 -// // { -// // let stdout = io::stdout(); -// // let mut handle = stdout.lock(); -// // handle.write_all(b"Exiting Secretd Cli.\n\t")?; -// // handle.flush()?; -// // break; -// // } - -// // if input == 1{ -// // let mut reports = vec![]; -// // let contract = create_new_snip_20(&account_name.trim(), &keyring_backend.trim(), &mut reports)?; -// // } - -// // if input == 2{ -// // create_new_deployment(account_name.trim(), keyring_backend.trim())?; -// // } - -// // if input == 3{ -// // let mut reports = vec![]; -// // add_new_pair_into_existing_factory(&account_name.trim(), &keyring_backend.trim(), &mut reports)?; -// // } - -// // if input == 4 { -// // let mut reports = vec![]; -// // let contract = create_snip20_and_register(&account_name.trim(), &keyring_backend.trim(), -// // &mut reports)?; -// // } - - -// // if input == 5 { -// // let mut reports = vec![]; - -// // let btc_contrat = NetContract{ -// // label : "".to_string(), -// // id : "12143".to_string(), -// // address: "secret1yn7jaxaukswkrqykvnz8rs8dvc4nqqty4dut9l".to_string(), -// // code_hash: "DFE53F3E3FFF02E59077AD4986FF6B620B084E2B3A4E9CE133155EABE105FFF1".to_string() -// // }; - -// // let etc_contrat = NetContract{ -// // label : "".to_string(), -// // id : "12144".to_string(), -// // address: "secret1hvgu4gt8w20j5m3vc8tjvgewff3rx88ewewyq8".to_string(), -// // code_hash: "DFE53F3E3FFF02E59077AD4986FF6B620B084E2B3A4E9CE133155EABE105FFF1".to_string() -// // }; - -// // let usdt_contrat = NetContract{ -// // label : "".to_string(), -// // id : "".to_string(), -// // address: "secret199mjvc9ggw9yh23lr5xya2dxw7qemeqktzw2wc".to_string(), -// // code_hash: "DFE53F3E3FFF02E59077AD4986FF6B620B084E2B3A4E9CE133155EABE105FFF1".to_string() -// // }; - -// // let recipient = read_string("Recipient address: ")?; -// // let amount = read_amount("Amount:: ")?; -// // // _ = mint_snip20(&account_name.trim(), & -// // // keyring_backend.trim(), -// // // Addr::unchecked(recipient.clone().trim()), -// // // Uint128(1000000), -// // // "1000000uscrt", -// // // &mut reports, -// // // btc_contrat.clone())?; - -// // _ = mint_snip20( -// // &account_name.trim(), -// // &keyring_backend.trim(), -// // Addr::unchecked(recipient.clone().trim()), -// // Uint128::from(1000000u128), -// // "1000000uscrt", -// // &mut reports, -// // usdt_contrat.clone())?; - - -// // _ = mint_snip20(&account_name.trim(), & -// // keyring_backend.trim(), -// // Addr::unchecked(recipient.clone().trim()), -// // Uint128::from(1000000u128), -// // "1000000uscrt", -// // &mut reports, -// // etc_contrat.clone())?; -// // } -// // } -// Ok(()) -// } - -// fn print_options() -> io::Result<()> -// { -// let stdout = io::stdout(); -// let mut handle = stdout.lock(); -// handle.write_all(b"Please select list of the action would you like to perform")?; -// handle.write_all(b"\n\t1. Create New Snip20 token. ")?; -// handle.write_all(b"\n\t2. Create New Deployment. ")?; -// handle.write_all(b"\n\t3. Create New AMMPair Contract. ")?; -// handle.write_all(b"\n\t4. Create Snip20 And Create New AMM Pair. ")?; -// handle.write_all(b"\n\t5. Mint20 Snip20. \n\t")?; -// handle.write_all(b"\n\t10. Exit Secretd Cli. \n\t")?; -// handle.flush()?; - -// Ok(()) -// } - -// fn create_new_deployment(account_name: &str, backend: &str) -> io::Result<()> -// { -// let mut reports = vec![]; -// let contract_0 = create_new_snip_20(account_name, backend, &mut reports)?; -// let contract_1 = create_new_snip_20(account_name, backend, &mut reports)?; -// let reward_token = create_new_snip_20(account_name, backend, &mut reports)?; -// let factory = create_factory_contract(account_name, backend, &mut reports)?; - -// let router_contract = init_router_contract(factory.clone(), -// account_name, backend, &mut reports)?; - -// let staking_contract = -// store_and_return_contract(&STAKING_FILE.replace("../", ""), -// &account_name, -// Some(STORE_GAS), -// Some(backend) -// )?; -// let pairs = TokenPair( -// TokenType::CustomToken { -// contract_addr: Addr::unchecked(contract_0.address.clone()), -// token_code_hash: contract_0.code_hash.to_string(), -// }, -// TokenType::CustomToken { -// contract_addr: Addr::unchecked(contract_1.address.clone()), -// token_code_hash: contract_1.code_hash.to_string(), -// }, -// ); - -// register_snip20_router(account_name,backend, contract_0.clone(), router_contract.clone(), &mut reports)?; -// register_snip20_router(account_name,backend, contract_1.clone(), router_contract.clone(), &mut reports)?; - -// add_amm_pairs(pairs.clone(), staking_contract, factory.clone(),backend,account_name,reward_token.clone(),&mut reports)?; -// let pair_address = get_all_pairs_from_factory(factory.clone(), contract_0.clone(), -// contract_1.clone())?; - - -// // register - -// increase_allowance(pair_address.clone(),Uint128::from(100000000u128), contract_0.clone(), -// account_name, backend, &mut reports)?; -// increase_allowance(pair_address.clone(),Uint128::from(100000000u128), contract_1.clone(), -// account_name, backend, &mut reports)?; - -// mint_snip20(account_name, backend, Addr::unchecked(""), -// Uint128::from(100000u128), "100000uscrt",&mut reports, contract_0.clone())?; - -// mint_snip20(account_name, backend, Addr::unchecked(""), -// Uint128::from(100000u128), "100000uscrt",&mut reports, contract_1.clone())?; - -// add_liquidity(pairs.clone(), -// NetContract { -// label: "".to_string(), -// id: "".to_string(), -// address: pair_address.clone(), -// code_hash: "".to_string() -// }, -// account_name, -// backend, -// Uint128::from(100000u128), -// Uint128::from(100000u128), -// &mut reports -// )?; - -// println!("Results...\n\t"); -// println!("Token 0 Address {}", contract_0.address.clone().to_string()); -// println!("Token 0 Id {}", contract_0.id.clone().to_string()); -// println!("Token 0 Code Hash {}", contract_0.code_hash.clone().to_string()); -// println!("Token 1 Address {}", contract_1.address.clone().to_string()); -// println!("Token 1 Id {}", contract_1.id.clone().to_string()); -// println!("Token 1 Code Hash {}", contract_1.code_hash.clone().to_string()); -// println!("Factory Address {}", factory.address.clone().to_string()); -// println!("Factory Id {}", factory.id.clone().to_string()); -// println!("Factory Code Hash {}", factory.code_hash.clone().to_string()); -// println!("Router Address {}", router_contract.address.clone().to_string()); -// println!("Router Id {}", router_contract.id.clone().to_string()); -// println!("Router Code Hash {}", router_contract.code_hash.clone().to_string()); -// println!("Pair Address {:?}", pair_address); - -// Ok(()) -// } - - -// fn read_string(text: &str)-> io::Result -// { -// let stdout = io::stdout(); -// let mut handle = stdout.lock(); -// let mut question ="Please type ".to_string(); -// question.push_str(text); -// handle.write_all(question.as_bytes())?; -// handle.flush()?; - -// // let stdout = io::stdout(); -// // let mut handle = stdout.lock(); -// // handle.flush()?; -// let mut output = String::new(); -// std::io::stdin().read_line(&mut output).unwrap(); -// Ok(output) -// } - -// fn read_int(text: &str) -> io::Result -// { -// let stdout = io::stdout(); -// let mut handle = stdout.lock(); -// let mut question ="Please type ".to_string(); -// question.push_str(text); -// handle.write_all(question.as_bytes())?; -// handle.flush()?; - -// println!("Please choose option."); -// let option: u8 = std::io::stdin() -// .lock() -// .lines() -// .next() -// .expect("stdin should be available") -// .expect("couldn't read from stdin") -// .trim() -// .parse() -// .expect("input was not an integer"); -// Ok(option) -// } - -// fn read_amount(text: &str) -> io::Result -// { -// let stdout = io::stdout(); -// let mut handle = stdout.lock(); -// let mut question ="Please type ".to_string(); -// question.push_str(text); -// handle.write_all(question.as_bytes())?; -// handle.flush()?; - -// println!("Please choose option."); -// let option: u128 = std::io::stdin() -// .lock() -// .lines() -// .next() -// .expect("stdin should be available") -// .expect("couldn't read from stdin") -// .trim() -// .parse() -// .expect("input was not an integer"); -// Ok(option) -// } - -// fn read_input() -> io::Result -// { -// println!("Please choose option."); -// let option: i32 = std::io::stdin() -// .lock() -// .lines() -// .next() -// .expect("stdin should be available") -// .expect("couldn't read from stdin") -// .trim() -// .parse() -// .expect("input was not an integer"); -// Ok(option) -// } - -// fn create_new_snip_20(account_name: &str, backend: &str, reports: &mut Vec) -> io::Result -// { -// let name = read_string(&"Type Name Snip20:: ".to_string())?; -// let symbol = read_string(&"Type Symbol Snip20:: ".to_string())?; -// let decimals = read_int(&"Type decimals:: ".to_string())?; -// let snip20 = init_snip20_contract(&name.trim(), &symbol.trim(), -// reports, decimals, account_name, backend)?; - -// let contract = NetContract{ -// label: snip20.label.to_string(), -// id: snip20.id.clone().to_string(), -// code_hash: snip20.code_hash.clone(), -// address: snip20.address.clone().to_string() -// }; - -// set_viewing_key(VIEW_KEY.to_owned(), &contract.clone(), reports, -// account_name.trim(), backend.trim())?; -// Ok(contract) -// } - -// fn init_snip20_contract(symbol: &str, name: &str, reports: &mut Vec, -// decimal: u8, account_name: &str, keyring_backend: &str) -> io::Result{ - -// let config = InitConfig{ -// enable_burn: Some(true), -// enable_mint: Some(true), -// enable_deposit : Some(true), -// enable_redeem: Some(false), -// public_total_supply: Some(true), -// }; - -// let s_contract = init_snip20_cli( -// name.to_string(), -// symbol.to_string(), -// decimal, -// None, // Some(config), -// reports, -// &account_name, -// Some(&SNIP20_FILE), -// &keyring_backend -// )?; - -// println!("Contract address - {}", s_contract.1.address.clone()); -// println!("Code hash - {}", s_contract.1.code_hash.clone()); -// println!("Code Id - {}", s_contract.1.id); - -// Ok(s_contract.1) -// } - -// fn add_new_pair_into_existing_factory(account_name: &str, -// backend:&str, -// reports: &mut Vec) -> io::Result<()> -// { -// let staking_contract = -// store_and_return_contract(&STAKING_FILE.replace("../", ""), -// &account_name, -// Some(STORE_GAS), -// Some(backend) -// )?; -// // let factory_contract = NetContract{ -// // address : "secret15llpx5ahfhadk29pm9qswe0ssw6x7pkpkhvnj5".to_string(), -// // code_hash: "71EB188450FBE579E5601AF81D8416890E502BA3A2799B693185B304239F2E20" .to_string(), -// // label: "".to_string(), -// // id: "12148".to_string() -// // }; - -// let factory_contract = NetContract{ -// address : "secret1tzgh5rd8v6rk2telfleaf3k55nzgvzm92zz93s".to_string(), -// code_hash: "71EB188450FBE579E5601AF81D8416890E502BA3A2799B693185B304239F2E20" .to_string(), -// label: "".to_string(), -// id: "12156".to_string() -// }; - -// let reward_token = create_new_snip_20(account_name, backend, reports)?; -// let contract_0 = create_new_snip_20(account_name, backend, reports)?; - -// // let contract_1 = NetContract{ -// // id: "12144".to_string(), -// // address: "secret1hvgu4gt8w20j5m3vc8tjvgewff3rx88ewewyq8".to_string(), -// // code_hash: "DFE53F3E3FFF02E59077AD4986FF6B620B084E2B3A4E9CE133155EABE105FFF1".to_string(), -// // label: "".to_string(), -// // }; - -// let contract_1 = NetContract{ -// id: "12144".to_string(), -// address: "secret1092ufc3ur5538y7cv4cr3ksu6v8k7t30l2ahvy".to_string(), -// code_hash: "DFE53F3E3FFF02E59077AD4986FF6B620B084E2B3A4E9CE133155EABE105FFF1".to_string(), -// label: "".to_string(), -// }; - -// let router_contract = NetContract { -// id: "12157".to_string(), -// address: "secret12yyrnm0y3duxzelge2nexythvvc03jthx6qr6h".to_string(), -// code_hash: "5ABF0B785628E960511C3A2AD0F27C0BDD48E8D4C8EAE3150562701D72772AF4".to_string(), -// label: "".to_string() -// }; - -// register_snip20_router(account_name, backend, contract_0.clone(), router_contract.clone(), reports)?; - -// let pairs = TokenPair( -// TokenType::CustomToken { -// contract_addr: Addr::unchecked(contract_0.address.clone()), -// token_code_hash: contract_0.code_hash.to_string(), -// }, -// TokenType::CustomToken { -// contract_addr: Addr::unchecked(contract_1.address.clone()), -// token_code_hash: contract_1.code_hash.to_string(), -// }, -// ); - -// create_amm_pair_and_set_liquidity(pairs.clone(), account_name, backend, reward_token.clone(), -// reports, staking_contract, contract_1.clone(), contract_1.clone(), factory_contract.clone())?; - -// Ok(()) -// } - - - -// fn create_amm_pair_and_set_liquidity( -// pairs: TokenPair, -// account_name: &str, -// backend: &str, -// reward_token: NetContract, -// reports: &mut Vec, -// staking_contract: StoredContract, -// contract_token_0: NetContract, -// contract_token_1: NetContract, -// factory_contract: NetContract, -// ) -> io::Result<()>{ - -// add_amm_pairs(pairs.clone(), staking_contract, factory_contract.clone(),backend,account_name,reward_token.clone(), reports)?; -// let pair_address = get_all_pairs_from_factory(factory_contract.clone(), contract_token_0.clone(), -// contract_token_1.clone())?; - -// increase_allowance(pair_address.clone(),Uint128::from(100000000u128), contract_token_0.clone(), -// account_name, backend, reports)?; -// increase_allowance(pair_address.clone(),Uint128::from(100000000u128), contract_token_1.clone(), -// account_name, backend, reports)?; - -// mint_snip20(account_name, backend, Addr::unchecked("secret10x73565sfrn8veawzz69le0na4y5nluqlwdvqu"), -// Uint128::from(100000000u128), "100000000uscrt", reports, contract_token_0.clone())?; - -// mint_snip20(account_name, backend, Addr::unchecked("secret10x73565sfrn8veawzz69le0na4y5nluqlwdvqu"), -// Uint128::from(100000000u128), "100000000uscrt", reports, contract_token_1.clone())?; - -// add_liquidity(pairs.clone(), -// NetContract { -// label: "".to_string(), -// id: "".to_string(), -// address: pair_address.clone(), -// code_hash: "".to_string() -// }, -// account_name, -// backend, -// Uint128::from(100000000u128), -// Uint128::from(100000000u128), -// reports -// )?; - -// println!("Results...\n\t"); -// println!("Token 0 Address {}", contract_token_0.address.clone().to_string()); -// println!("Token 0 Id {}", contract_token_0.id.clone().to_string()); -// println!("Token 0 Code Hash {}", contract_token_0.code_hash.clone().to_string()); -// println!("Token 1 Address {}", contract_token_1.address.clone().to_string()); -// println!("Token 1 Id {}", contract_token_1.id.clone().to_string()); -// println!("Token 1 Code Hash {}", contract_token_1.code_hash.clone().to_string()); -// println!("Factory Address {}", factory_contract.address.clone().to_string()); -// println!("Factory Id {}", factory_contract.id.clone().to_string()); -// println!("Factory Code Hash {}", factory_contract.code_hash.clone().to_string()); -// println!("Pair Address {:?}", pair_address); -// Ok(()) -// } - -// fn create_factory_contract(account_name: &str, backend: &str, reports: &mut Vec) -// -> io::Result -// { -// let lp_token = -// store_and_return_contract(&LPTOKEN20_FILE.replace("../", ""), -// &account_name, -// Some(STORE_GAS), -// Some(backend) -// )?; - -// let pair_contract = -// store_and_return_contract(&AMM_PAIR_FILE.replace("../", ""), -// &account_name, -// Some(STORE_GAS), -// Some(backend) -// )?; - -// let init_msg = FactoryInitMsg{ -// pair_contract: ContractInstantiationInfo{ -// code_hash: pair_contract.code_hash.to_string().clone(), -// id: pair_contract.id.clone().parse::().unwrap() -// }, -// amm_settings: AMMSettings{ -// shade_dao_fee: Fee::new(8, 100), -// lp_fee: Fee::new(2, 8), -// shade_dao_address: ContractLink { -// address: Addr::unchecked("".to_string()), -// code_hash: "".to_string(), -// }, -// }, -// lp_token_contract: ContractInstantiationInfo{ -// code_hash: lp_token.code_hash.to_string().clone(), -// id: lp_token.id.clone().parse::().unwrap() -// }, -// prng_seed: to_binary(&"".to_string()).unwrap(), -// }; - -// println!("Creating Factory "); -// let factory_contract = init_contract_factory( -// &account_name, -// &backend, -// &FACTORY_FILE.replace("../", ""), -// &init_msg, -// reports -// )?; - -// println!("Factory address {}", factory_contract.address.clone().to_string()); -// Ok(factory_contract) -// } - -// fn add_amm_pairs(pairs: TokenPair, -// staking_contract: StoredContract, -// factory_contract: NetContract, -// backend: &str, -// account_name: &str, -// reward_contract: NetContract, -// reports: &mut Vec -// ) -> io::Result<()> { -// handle( -// &FactoryExecuteMsg::CreateAMMPair { -// pair: pairs.clone(), -// entropy: to_binary(&"".to_string()).unwrap(), -// staking_contract: Some(StakingContractInit { -// contract_info: ContractInstantiationInfo { -// code_hash: staking_contract.code_hash.to_string(), -// id: staking_contract.id.clone().parse::().unwrap(), -// }, -// amount: Uint128::from(3450000000000u128), -// reward_token: TokenType::CustomToken { -// contract_addr: Addr::unchecked(reward_contract.address.clone()), -// token_code_hash: reward_contract.code_hash.to_string(), -// }, -// }), -// }, -// &factory_contract, -// account_name, -// Some(GAS), -// Some(backend), -// None, -// reports, -// None, -// ) -// .unwrap(); - -// Ok(()) - -// } - -// fn set_viewing_key( -// viewingKey: String, -// netContract: &NetContract, -// reports: &mut Vec, -// account_name: &str, -// backend: &str) ->io::Result<()>{ -// let msg = snip20_reference_impl::msg::ExecuteMsg::SetViewingKey { -// key: String::from(VIEW_KEY), -// padding: None, -// }; - -// handle( -// &msg, -// &netContract, -// account_name, -// Some(GAS), -// Some(backend), -// None, -// reports, -// None, -// )?; -// Ok(()) -// } - - -// fn get_all_pairs_from_factory( -// factory_contract: NetContract, -// token_0_contract: NetContract, -// token_1_contract: NetContract -// ) -> io::Result -// { -// let mut pair_address = "".to_string(); -// let mut start = 0; -// let mut limit = 30; - -// let msg = FactoryQueryMsg::ListAMMPairs { -// pagination: Pagination { -// start: start, -// limit: limit, -// }, -// }; -// let factory_query: FactoryQueryResponse = query(&factory_contract, msg, None)?; -// if let FactoryQueryResponse::ListAMMPairs { amm_pairs } = factory_query { -// for pair in amm_pairs.iter() -// { -// for i in 0..amm_pairs.len() { -// println!("{:?}", amm_pairs[i]); - -// let pair = amm_pairs[i].clone(); -// let token_type = get_token_type(pair.pair)?; -// if token_type.0 == token_0_contract.address && token_1_contract.address == token_type.1 -// { -// pair_address = pair.address.clone().to_string(); -// } -// } -// } -// } - -// Ok(pair_address) -// } - -// pub fn get_token_type(pairs: TokenPair) -> io::Result<(String,String)>{ -// let token_0_address = match pairs.0 { -// TokenType::CustomToken { contract_addr, token_code_hash } =>{ -// contract_addr.clone().to_string() -// }, -// TokenType::NativeToken { denom } => { -// "".to_string() -// } -// }; - -// let token_1_address = match pairs.1 { -// TokenType::CustomToken { contract_addr, token_code_hash } =>{ -// contract_addr.clone().to_string() -// }, -// TokenType::NativeToken { denom } => { -// "".to_string() -// } -// }; - -// Ok((token_0_address, token_1_address)) -// } - -// pub fn init_router_contract(pair_contract: NetContract, -// account_name: &str, -// backend: &str, -// reports: &mut Vec) -> io::Result -// { -// let router_msg = RouterInitMsg { -// prng_seed: to_binary(&"".to_string()).unwrap(), -// entropy: to_binary(&"".to_string()).unwrap(), -// viewing_key: Some(ViewingKey::from(VIEW_KEY).to_string()), -// pair_contract_code_hash: pair_contract.code_hash, -// }; - -// let router_contract = init( -// &router_msg, -// &ROUTER_FILE.replace("../", ""), -// &*generate_label(8), -// account_name, -// Some(STORE_GAS), -// Some(GAS), -// Some(backend), -// reports, -// )?; - -// Ok(router_contract) -// } - -// pub fn register_snip20_router( -// account_name: &str, -// backend: &str, -// contract_snip20: NetContract, -// router_contract: NetContract, -// reports: &mut Vec -// ) -> io::Result<()> -// { -// handle( -// &RouterExecuteMsg::RegisterSNIP20Token { -// token_addr: Addr::unchecked(contract_snip20.address.clone()), -// token_code_hash: contract_snip20.code_hash.to_string(), -// }, -// &router_contract, -// account_name, -// Some(GAS), -// Some(backend), -// None, -// reports, -// None, -// ) -// .unwrap(); - -// Ok(()) -// } - -// pub fn create_snip20_and_register( -// account_name: &str, -// backend: &str, -// reports: &mut Vec -// ) -> io::Result -// { -// let contract_0 = create_new_snip_20(account_name, backend, reports)?; -// let router_contract = NetContract { -// id: "12157".to_string(), -// address: "secret12yyrnm0y3duxzelge2nexythvvc03jthx6qr6h".to_string(), -// code_hash: "5ABF0B785628E960511C3A2AD0F27C0BDD48E8D4C8EAE3150562701D72772AF4".to_string(), -// label: "".to_string() -// }; - -// register_snip20_router(account_name, backend, contract_0.clone(), router_contract.clone(), reports)?; -// Ok(contract_0) -// } - -// pub fn increase_allowance( -// pair_address: String, -// amount: Uint128, -// contract_snip20: NetContract, -// account_name: &str, -// backend: &str, -// reports: &mut Vec -// ) -> io::Result<()> -// { -// handle( -// &snip20_reference_impl::msg::ExecuteMsg::IncreaseAllowance { -// spender: Addr::unchecked(String::from(pair_address)), -// amount: amount, // Uint128(100000000), -// expiration: None, -// padding: None, -// }, -// &NetContract { -// label: "".to_string(), -// id: contract_snip20.id.clone(), -// address: contract_snip20.address.clone(), -// code_hash: contract_snip20.code_hash.to_string(), -// }, -// account_name, -// Some(GAS), -// Some(backend), -// None, -// reports, -// None, -// ) -// .unwrap(); -// Ok(()) -// } - -// pub fn mint_snip20( -// account_name: &str, -// backend: &str, -// recipient: Addr, -// amount: Uint128, -// amount_uscrt: &str, -// reports: &mut Vec, -// contract_snip20: NetContract -// ) -> io::Result<()>{ -// let msg = snip20_reference_impl::msg::ExecuteMsg::Mint { padding: None, recipient: recipient, amount: amount, memo: None }; -// handle( -// &msg, -// &contract_snip20, -// account_name, -// Some(GAS), -// Some(backend), -// Some(amount_uscrt), -// reports, -// None, -// )?; -// Ok(()) -// } - -// pub fn add_liquidity( -// pair: TokenPair, -// pair_contract: NetContract, -// account_name: &str, -// backend: &str, -// amount_0: Uint128, -// amount_1: Uint128, -// reports: &mut Vec -// ) -> io::Result<()> -// { -// handle( -// &AMMPairHandlMsg::AddLiquidityToAMMContract { -// deposit: TokenPairAmount { -// pair: pair.clone(), -// amount_0: amount_0, -// amount_1: amount_1, -// }, -// slippage: None, -// staking: None -// }, -// &pair_contract, -// account_name, -// Some(GAS), -// Some(backend), -// None, -// reports, -// None, -// ) -// .unwrap(); - -// Ok(()) -// } \ No newline at end of file diff --git a/packages/network_integration/src/lib.rs b/packages/network_integration/src/lib.rs index 7287cc8..8669c6e 100644 --- a/packages/network_integration/src/lib.rs +++ b/packages/network_integration/src/lib.rs @@ -3,3 +3,4 @@ pub mod utils; pub mod trade_lib; pub mod cli_commands; pub mod cli_menu; +mod cli_helpers; diff --git a/packages/network_integration/src/utils.rs b/packages/network_integration/src/utils.rs index 8f6631d..728231c 100644 --- a/packages/network_integration/src/utils.rs +++ b/packages/network_integration/src/utils.rs @@ -22,6 +22,7 @@ pub const AMM_PAIR_FILE: &str = "../../compiled/amm_pair.wasm.gz"; pub const FACTORY_FILE: &str = "../../compiled/factory.wasm.gz"; pub const ROUTER_FILE: &str = "../../compiled/router.wasm.gz"; pub const STAKING_FILE: &str = "../../compiled/staking.wasm.gz"; +pub const ADMIN_FILE: &str = "../../misc/admin.wasm.gz"; pub const STORE_GAS: &str = "100000000"; pub const GAS: &str = "8000000"; diff --git a/packages/network_integration/tests/testnet_integration.rs b/packages/network_integration/tests/testnet_integration.rs index d7115e7..d7f0572 100644 --- a/packages/network_integration/tests/testnet_integration.rs +++ b/packages/network_integration/tests/testnet_integration.rs @@ -1,14 +1,25 @@ use colored::Colorize; use cosmwasm_std::Addr; - use cosmwasm_std::StdResult; use cosmwasm_std::Uint128; -use network_integration::utils::API_KEY; +use network_integration::cli_commands::amm_pair_lib::add_amm_pairs; +use network_integration::cli_commands::amm_pair_lib::add_liquidity; +use network_integration::cli_commands::amm_pair_lib::get_staking_contract; +use network_integration::cli_commands::amm_pair_lib::list_pair_from_factory; +use network_integration::cli_commands::factory_lib::create_factory_contract; +use network_integration::cli_commands::factory_lib::deposit_snip20; +use network_integration::cli_commands::factory_lib::increase_allowance; +use network_integration::cli_commands::router_lib::create_router_contract; +use network_integration::cli_commands::snip20_lib::set_viewing_key; use network_integration::utils::InitConfig; +use network_integration::utils::ADMIN_FILE; +use network_integration::utils::API_KEY; use query_authentication::permit::Permit; use query_authentication::transaction::PermitSignature; use query_authentication::transaction::PubKey; +use std::{thread, time}; +use shadeswap_shared::admin::RegistryAction; use shadeswap_shared::c_std::Binary; use shadeswap_shared::core::Fee; use shadeswap_shared::core::TokenAmount; @@ -16,14 +27,16 @@ use shadeswap_shared::core::TokenPair; use shadeswap_shared::core::TokenPairAmount; use shadeswap_shared::core::TokenType; use shadeswap_shared::query_auth::PermitData; +use shadeswap_shared::router::Hop; use shadeswap_shared::snip20; use shadeswap_shared::staking::AuthQuery; - +use shadeswap_shared::Contract; use cosmwasm_std::to_binary; use network_integration::utils::{ - generate_label, init_snip20, print_contract, print_header, print_warning, - ACCOUNT_KEY, AMM_PAIR_FILE, FACTORY_FILE, GAS, LPTOKEN20_FILE, ROUTER_FILE, SHADE_DAO_KEY, STAKER_KEY, STAKING_FILE, STORE_GAS, VIEW_KEY, + generate_label, init_snip20, print_contract, print_header, print_warning, ACCOUNT_KEY, + AMM_PAIR_FILE, FACTORY_FILE, GAS, LPTOKEN20_FILE, ROUTER_FILE, SHADE_DAO_KEY, STAKER_KEY, + STAKING_FILE, STORE_GAS, VIEW_KEY, }; use secretcli::{ cli_types::NetContract, @@ -32,12 +45,13 @@ use secretcli::{ use serde_json::Result; use shadeswap_shared::staking::QueryData; use shadeswap_shared::{ - amm_pair::{AMMSettings}, - core::{ContractInstantiationInfo, ContractLink}, + amm_pair::AMMSettings, + contract_interfaces::admin::InstantiateMsg as AdminInstantiateMsg, + core::ContractInstantiationInfo, msg::{ amm_pair::{ - ExecuteMsg as AMMPairHandlMsg, - QueryMsg as AMMPairQueryMsg, QueryMsgResponse as AMMPairQueryMsgResponse, + ExecuteMsg as AMMPairHandlMsg, QueryMsg as AMMPairQueryMsg, + QueryMsgResponse as AMMPairQueryMsgResponse, }, factory::{ ExecuteMsg as FactoryExecuteMsg, InitMsg as FactoryInitMsg, @@ -48,8 +62,8 @@ use shadeswap_shared::{ QueryMsg as RouterQueryMsg, QueryMsgResponse as RouterQueryResponse, }, staking::{ - ExecuteMsg as StakingMsgHandle, QueryMsg as StakingQueryMsg, - QueryResponse as StakingQueryMsgResponse, + ExecuteMsg as StakingMsgHandle, InvokeMsg as StakingInvokeMsg, + QueryMsg as StakingQueryMsg, QueryResponse as StakingQueryMsgResponse, StakingContractInit, }, }, @@ -58,8 +72,6 @@ use shadeswap_shared::{ use std::time::{SystemTime, UNIX_EPOCH}; - - pub fn get_current_timestamp() -> StdResult { let start = SystemTime::now(); let since_the_epoch = start @@ -74,7 +86,6 @@ fn run_testnet() -> Result<()> { let _shade_dao = account_address(SHADE_DAO_KEY)?; let _staker_account = account_address(STAKER_KEY)?; println!("Using Account: {}", account.blue()); - let entropy = to_binary(&"ENTROPY".to_string()).unwrap(); let mut reports = vec![]; @@ -83,6 +94,9 @@ fn run_testnet() -> Result<()> { print_header("\n\t Set Viewing Key for Staker - Staking Contract password"); print_header(&to_binary(&QueryData {}).unwrap().to_base64()); + let pair_contract_code_hash = store_and_return_contract(AMM_PAIR_FILE, ACCOUNT_KEY, Some(STORE_GAS), Some("test"))?.code_hash; + + type TestPermit = Permit; //secretd tx sign-doc file --from a let newPermit = TestPermit{ @@ -97,35 +111,39 @@ fn run_testnet() -> Result<()> { memo: Some("".to_string()) }; - // print_header("Initializing sSCRT"); - // let (s_sSINIT, s_sCRT) = init_snip20( - // "SSCRT".to_string(), - // "SSCRT".to_string(), - // 6, - // Some(InitConfig { - // public_total_supply: Some(true), - // enable_deposit: Some(true), - // enable_redeem: Some(true), - // enable_mint: Some(true), - // enable_burn: Some(false), - // }), - // &mut reports, - // ACCOUNT_KEY, - // None, - // )?; - // print_contract(&s_sCRT); - - print_header("Storing all contracts"); - print_warning("Storing LP Token Contract"); - let s_lp = - store_and_return_contract(LPTOKEN20_FILE, ACCOUNT_KEY, Some(STORE_GAS), Some("test"))?; - print_warning("Storing AMM Pair Token Contract"); - let s_ammPair = - store_and_return_contract(AMM_PAIR_FILE, ACCOUNT_KEY, Some(STORE_GAS), Some("test"))?; - print_warning("Storing Staking Contract"); - let staking_contract = - store_and_return_contract(STAKING_FILE, ACCOUNT_KEY, Some(STORE_GAS), Some("test"))?; + print_header("\n\tInitializing Admin Contract"); + + let admin_msg = AdminInstantiateMsg { + super_admin: Some("secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03".to_string()), + }; + + let admin_contract = init( + &admin_msg, + &ADMIN_FILE, + &*generate_label(8), + ACCOUNT_KEY, + Some(STORE_GAS), + Some(GAS), + Some("test"), + &mut reports, + )?; + + let admin_register_msg = RegistryAction::RegisterAdmin { + user: "secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03".to_string(), + }; + + handle( + &admin_register_msg, + &admin_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("1000000000000uscrt"), + &mut reports, + None, + )?; + print_contract(&admin_contract); print_header("Initializing sSCRT"); let (_s_sSINIT, s_sCRT) = init_snip20( "SSCRT".to_string(), @@ -143,23 +161,9 @@ fn run_testnet() -> Result<()> { None, )?; - { - let msg = snip20::ExecuteMsg::SetViewingKey { - key: String::from(VIEW_KEY), - padding: None, - }; + let snip_20_code_hash = s_sCRT.code_hash.clone(); - handle( - &msg, - &s_sCRT, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - )?; - } + set_viewing_key(VIEW_KEY, &s_sCRT, &mut reports, ACCOUNT_KEY, "test"); print_contract(&s_sCRT); print_header("Initializing s_sREWARDSNIP20"); @@ -181,23 +185,15 @@ fn run_testnet() -> Result<()> { )?; print_contract(&s_sREWARDSNIP20); - { - let msg = snip20::ExecuteMsg::SetViewingKey { - key: String::from(VIEW_KEY), - padding: None, - }; - handle( - &msg, - &s_sREWARDSNIP20, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - )?; - } + set_viewing_key( + VIEW_KEY, + &s_sREWARDSNIP20, + &mut reports, + ACCOUNT_KEY, + "test", + ); + print_header("Initializing sSHD"); let (_s_sSHDINIT, s_sSHD) = init_snip20( @@ -218,41 +214,17 @@ fn run_testnet() -> Result<()> { print_contract(&s_sSHD); - { - let msg = snip20::ExecuteMsg::SetViewingKey { - key: String::from(VIEW_KEY), - padding: None, - }; - - handle( - &msg, - &s_sSHD, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - )?; - } + set_viewing_key(VIEW_KEY, &s_sSHD, &mut reports, ACCOUNT_KEY, "test"); println!("\n\tDepositing 1000000000000uscrt s_sREWARDSNIP20"); - { - let msg = snip20::ExecuteMsg::Deposit { padding: None }; - - handle( - &msg, - &s_sREWARDSNIP20, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - Some("1000000000000uscrt"), - &mut reports, - None, - )?; - } - + deposit_snip20( + ACCOUNT_KEY, + "test", + &s_sREWARDSNIP20.address, + "1000000000000uscrt", + &mut reports, + ); assert_eq!( get_balance(&s_sREWARDSNIP20, account.to_string(), VIEW_KEY.to_string()), Uint128::new(1000000000000) @@ -260,20 +232,13 @@ fn run_testnet() -> Result<()> { println!("\n\tDepositing 1000000000000uscrt sSCRT"); - { - let msg = snip20::ExecuteMsg::Deposit { padding: None }; - - handle( - &msg, - &s_sCRT, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - Some("1000000000000uscrt"), - &mut reports, - None, - )?; - } + deposit_snip20( + ACCOUNT_KEY, + "test", + &s_sCRT.address, + "1000000000000uscrt", + &mut reports, + ); assert_eq!( get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), @@ -282,820 +247,1095 @@ fn run_testnet() -> Result<()> { println!("\n\tDepositing 1000000000000uscrt sSHD"); - { - let msg = snip20::ExecuteMsg::Deposit { padding: None }; + deposit_snip20( + ACCOUNT_KEY, + "test", + &s_sSHD.address, + "1000000000000uscrt", + &mut reports, + ); - handle( - &msg, - &s_sSHD, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - Some("1000000000000uscrt"), - &mut reports, - None, - )?; - assert_eq!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), - Uint128::new(1000000000000) - ); - } - print_header("\n\tInitializing Factory Contract"); + let token_1 = TokenType::CustomToken { + contract_addr: Addr::unchecked(s_sCRT.address.clone()), + token_code_hash: snip_20_code_hash.clone(), + }; - let factory_msg = FactoryInitMsg { - pair_contract: ContractInstantiationInfo { - code_hash: s_ammPair.code_hash.to_string(), - id: s_ammPair.id.clone().parse::().unwrap(), - }, - amm_settings: AMMSettings { - lp_fee: Fee::new(8, 100), - shade_dao_fee: Fee::new(2, 100), - shade_dao_address: ContractLink { - address: Addr::unchecked(s_sSHD.address.clone()), - code_hash: s_sSHD.code_hash.clone(), - }, - }, - lp_token_contract: ContractInstantiationInfo { - code_hash: s_lp.code_hash.clone(), - id: s_lp.id.clone().parse::().unwrap(), - }, - prng_seed: to_binary(&"".to_string()).unwrap(), - api_key: API_KEY.to_string(), - authenticator: None, + let token_2 = TokenType::CustomToken { + contract_addr: Addr::unchecked(s_sSHD.address.clone()), + token_code_hash: s_sSHD.code_hash.to_string(), }; - let factory_contract = init( - &factory_msg, - FACTORY_FILE, - &*generate_label(8), - ACCOUNT_KEY, - Some(STORE_GAS), - Some(GAS), - Some("test"), - &mut reports, - )?; + let token_native = TokenType::NativeToken { + denom: "uscrt".to_string(), + }; - print_contract(&factory_contract); + print_header("\n\tInitializing Factory Contract"); + let factory_contract = + create_factory_contract( + ACCOUNT_KEY, + "test", + &mut reports, + API_KEY, + "password", + 3, + 100, + 8, + 100, + &_shade_dao, + "", + &admin_contract.address.to_string(), + &admin_contract.code_hash, + "", + "") + .unwrap(); + + print_contract(&factory_contract); print_header("\n\tInitializing Router"); - let router_msg = RouterInitMsg { - prng_seed: to_binary(&"".to_string()).unwrap(), - entropy: to_binary(&"".to_string()).unwrap(), - pair_contract_code_hash: s_ammPair.code_hash.clone(), - }; + let router_contract = create_router_contract(admin_contract.code_hash.to_string(), +ACCOUNT_KEY, "test", &mut reports, &admin_contract.address).unwrap(); - let router_contract = init( - &router_msg, - ROUTER_FILE, - &*generate_label(8), + print_header("\n\tInitializing New Pair Contract (SNIP20/SNIP20) via Factory"); + + let token_pair_1 = TokenPair( + token_1.clone(), + token_2.clone(), + ); + + let token_pair_2 = TokenPair( + token_native.clone(), + token_1.clone(), + ); + + add_amm_pairs( + factory_contract.address.clone(), + factory_contract.code_hash.clone(), + "test", ACCOUNT_KEY, - Some(STORE_GAS), - Some(GAS), - Some("test"), + s_sCRT.address.clone(), + snip_20_code_hash.clone(), + s_sSHD.address.clone(), + snip_20_code_hash.clone(), + "seed", + Some(s_sREWARDSNIP20.address.to_string()), + Some(s_sREWARDSNIP20.code_hash.to_string()), + Some(30000u128), + Some(3450000000000u128), &mut reports, - )?; - print_contract(&router_contract); + ) + .unwrap(); - print_header("\n\tInitializing New Pair Contract (SNIP20/SNIP20) via Factory"); + print_header("\n\tInitializing New Pair Contract (SCRT/SNIP20) via Factory"); - let test_pair = TokenPair( - TokenType::CustomToken { - contract_addr: Addr::unchecked(s_sCRT.address.clone()), - token_code_hash: s_sCRT.code_hash.to_string(), - }, - TokenType::CustomToken { - contract_addr: Addr::unchecked(s_sSHD.address.clone()), - token_code_hash: s_sSHD.code_hash.to_string(), - }, + add_amm_pairs( + factory_contract.address.clone(), + factory_contract.code_hash.clone(), + "test", + ACCOUNT_KEY, + "".to_string(), + "".to_string(), + s_sCRT.address.clone(), + snip_20_code_hash.clone(), + "seed", + None, + None, + None, + None, + &mut reports, + ) + .unwrap(); + + print_header("\n\tGetting Pairs from Factory"); + let amm_pairs = list_pair_from_factory(factory_contract.address.clone(), 0, 10).unwrap(); + assert_eq!(amm_pairs.len(), 2); + let amm_pair_1 = amm_pairs[0].clone(); + let amm_pair_2 = amm_pairs[1].clone(); + + print_header("\n\tIncreasing Allowances"); + + increase_allowance( + amm_pair_1.address.to_string(), + Uint128::new(100000000000), + s_sSHD.address.clone(), + ACCOUNT_KEY, + "test", + &mut reports, + ); + increase_allowance( + amm_pair_1.address.to_string(), + Uint128::new(100000000000), + s_sCRT.address.clone(), + ACCOUNT_KEY, + "test", + &mut reports, + ); + increase_allowance( + amm_pair_2.address.to_string(), + Uint128::new(100000000000), + s_sCRT.address.clone(), + ACCOUNT_KEY, + "test", + &mut reports, ); - { - handle( - &FactoryExecuteMsg::CreateAMMPair { - pair: test_pair.clone(), - entropy: entropy, - // staking_contract: None, - staking_contract: Some(StakingContractInit { - contract_info: ContractInstantiationInfo { - code_hash: staking_contract.code_hash.to_string(), - id: staking_contract.id.clone().parse::().unwrap(), - }, - daily_reward_amount: Uint128::new(3450000000000u128), - reward_token: TokenType::CustomToken { - contract_addr: Addr::unchecked(s_sREWARDSNIP20.address.clone()), - token_code_hash: s_sREWARDSNIP20.code_hash.to_string(), - }, - }), - router_contract: Some(ContractLink{ address: Addr::unchecked(router_contract.address.clone()), code_hash: router_contract.code_hash.clone() }) - }, - &factory_contract, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - } + print_header("\n\tGet Staking Contract"); - print_header("\n\tInitializing New Pair Contract (SCRT/SNIP20) via Factory"); + let staking_contract = get_staking_contract(&amm_pair_1.address.to_string()).unwrap(); + + assert_ne!(staking_contract, None); + + print_header("\n\tAdding Liquidity to SNIP20/20 staking contract"); + + add_liquidity(ACCOUNT_KEY, "test", amm_pair_1.address.to_string(), + s_sCRT.address.clone(), snip_20_code_hash.clone(), s_sSHD.address.clone(), snip_20_code_hash.clone(), + Uint128::new(10000000000), Uint128::new(10000000000), true, "", &mut reports); - let test_native_pair = TokenPair( - TokenType::NativeToken { - denom: "uscrt".to_string(), + print_header("\n\tAdding Liquidity to NATIVE/SNIP20 staking contract"); + handle( + &AMMPairHandlMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount { + pair: token_pair_2.clone(), + amount_0: Uint128::new(10000000000), + amount_1: Uint128::new(10000000000), + }, + expected_return: None, + staking: None, }, - TokenType::CustomToken { - contract_addr: Addr::unchecked(s_sCRT.address.clone()), - token_code_hash: s_sCRT.code_hash.to_string(), + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_2.address.to_string(), + code_hash: "".to_string(), }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("10000000000uscrt"), + &mut reports, + None, + ) + .unwrap(); + + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + Uint128::new(1000000000000 - 20000000000) + ); + assert_eq!( + get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), + Uint128::new(1000000000000 - 10000000000) ); + print_header("\n\tRegistering Tokens"); + + handle( + &RouterExecuteMsg::RegisterSNIP20Token { + token_addr: s_sCRT.address.clone(), + token_code_hash: snip_20_code_hash.clone(), + }, + &router_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + handle( + &RouterExecuteMsg::RegisterSNIP20Token { + token_addr: s_sSHD.address.clone(), + token_code_hash: s_sSHD.code_hash.to_string(), + }, + &router_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + print_header("Get Trade Count"); { - handle( - &FactoryExecuteMsg::CreateAMMPair { - pair: test_native_pair.clone(), - entropy: to_binary(&"".to_string()).unwrap(), - staking_contract: None, - router_contract: None - // staking_contract: Some(StakingContractInit { - // contract_info: ContractInstantiationInfo{ - // code_hash: staking_contract.code_hash.to_string(), - // id: staking_contract.id.clone().parse::().unwrap(), - // }, - // amount: Uint128::new(100000u128), - // reward_token: TokenType::CustomToken { - // contract_addr: s_sCRT.address.clone().into(), - // token_code_hash: s_sCRT.code_hash.to_string(), - // }, - // }) + let trade_count_info_msg = AMMPairQueryMsg::GetTradeCount {}; + let trade_count_info_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), }, - &factory_contract, - ACCOUNT_KEY, - Some(GAS), - Some("test"), + trade_count_info_msg, None, - &mut reports, - None, - ) - .unwrap(); + )?; + + if let AMMPairQueryMsgResponse::GetTradeCount { count } = trade_count_info_query { + assert_eq!(count, 0u64); + } else { + panic!("Trade count couldnt pass") + } } - print_header("\n\tGetting Pairs from Factory"); { - let msg = FactoryQueryMsg::ListAMMPairs { + let trade_count_info_msg = AMMPairQueryMsg::GetTradeHistory { pagination: Pagination { - start: 0, - limit: 10, + start: 0u64, + limit: 10u8, }, + api_key: API_KEY.to_string(), }; + let trade_count_info_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + trade_count_info_msg, + None, + )?; - let factory_query: FactoryQueryResponse = query(&factory_contract, msg, None)?; - if let FactoryQueryResponse::ListAMMPairs { amm_pairs } = factory_query { - assert_eq!(amm_pairs.len(), 2); - let ammPair = amm_pairs[0].clone(); - let amm_pair_2 = amm_pairs[1].clone(); + if let AMMPairQueryMsgResponse::GetTradeHistory { data } = trade_count_info_query { + assert_eq!(data.len(), 0u32 as usize); + } else { + panic!("Trade count couldnt pass") + } + } - print_header("\n\tIncreasing Allowances"); - handle( - &snip20::ExecuteMsg::IncreaseAllowance { - spender: ammPair.address.to_string(), - amount: Uint128::new(10000000000), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: s_sSHD.id.clone(), - address: s_sSHD.address.clone(), - code_hash: s_sSHD.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + print_header("\n\t 1. - BUY 100 sSHD Initiating sSCRT to sSHD Swap "); + let old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + let old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); + handle( + &snip20::ExecuteMsg::Send { + recipient: router_contract.address.to_string(), + amount: Uint128::new(100), + msg: Some( + to_binary(&RouterInvokeMsg::SwapTokensForExact { + expected_return: Some(Uint128::new(10)), + path: vec![Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }], + recipient: Some(account.to_string()), + }) + .unwrap(), + ), + padding: None, + recipient_code_hash: None, + memo: None, + }, + &s_sCRT, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); - handle( - &snip20::ExecuteMsg::IncreaseAllowance { - spender: ammPair.address.to_string(), - amount: Uint128::new(10000000000), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: s_sCRT.id.clone(), - address: s_sCRT.address.clone(), - code_hash: s_sCRT.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + (old_scrt_balance - Uint128::new(100)) + ); - handle( - &snip20::ExecuteMsg::IncreaseAllowance { - spender: amm_pair_2.address.to_string(), - amount: Uint128::new(10000000000), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: s_sCRT.id.clone(), - address: s_sCRT.address.clone(), - code_hash: s_sCRT.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), + (old_shd_balance + Uint128::new(89)) + ); - print_header("\n\tGet Staking Contract"); - let staking_contract_msg = AMMPairQueryMsg::GetStakingContract {}; - let staking_contract_query: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - staking_contract_msg, - None, - )?; - if let AMMPairQueryMsgResponse::StakingContractInfo { staking_contract } = - staking_contract_query - { - assert_ne!(staking_contract, None); - } + { + let trade_count_info_msg = AMMPairQueryMsg::GetTradeCount {}; + let trade_count_info_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + trade_count_info_msg, + None, + )?; - print_header("\n\tAdding Liquidity to SNIP20/20 staking contract"); - handle( - &AMMPairHandlMsg::AddLiquidityToAMMContract { - deposit: TokenPairAmount { - pair: test_pair.clone(), - amount_0: Uint128::new(10000000000), - amount_1: Uint128::new(10000000000), - }, - expected_return: None, - staking: Some(true), - }, - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + if let AMMPairQueryMsgResponse::GetTradeCount { count } = trade_count_info_query { + assert_eq!(count, 1u64); + } else { + panic!("Trade count couldnt pass") + } + } - print_header("\n\tAdding Liquidity to NATIVE/SNIP20 staking contract"); - handle( - &AMMPairHandlMsg::AddLiquidityToAMMContract { - deposit: TokenPairAmount { - pair: test_native_pair.clone(), - amount_0: Uint128::new(10000000000), - amount_1: Uint128::new(10000000000), - }, - expected_return: None, - staking: None, - }, - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: amm_pair_2.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - Some("10000000000uscrt"), - &mut reports, - None, - ) - .unwrap(); + { + let trade_count_info_msg = AMMPairQueryMsg::GetTradeHistory { + pagination: Pagination { + start: 0u64, + limit: 10u8, + }, + api_key: API_KEY.to_string(), + }; + let trade_count_info_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + trade_count_info_msg, + None, + )?; - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - Uint128::new(1000000000000 - 20000000000) - ); - assert_eq!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), - Uint128::new(1000000000000 - 10000000000) - ); - print_header("\n\tRegistering Tokens"); + if let AMMPairQueryMsgResponse::GetTradeHistory { data } = trade_count_info_query { + assert_eq!(data.len(), 1u32 as usize); + } else { + panic!("Trade count couldnt pass") + } + } - handle( - &RouterExecuteMsg::RegisterSNIP20Token { - token_addr: Addr::unchecked(s_sCRT.address.clone()), - token_code_hash: s_sCRT.code_hash.to_string(), - }, - &router_contract, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + let old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); + let old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + print_header("\n\t 2 - BUY 50 sSHD Initiating sSCRT to sSHD Swap "); + + handle( + &snip20::ExecuteMsg::Send { + recipient: router_contract.address.to_string(), + amount: Uint128::new(50), + msg: Some( + to_binary(&RouterInvokeMsg::SwapTokensForExact { + expected_return: Some(Uint128::new(5)), + path: vec![Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }], + recipient: Some(account.to_string()), + }) + .unwrap(), + ), + padding: None, + recipient_code_hash: None, + memo: None, + }, + &s_sCRT, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); - handle( - &RouterExecuteMsg::RegisterSNIP20Token { - token_addr: Addr::unchecked(s_sSHD.address.clone()), - token_code_hash: s_sSHD.code_hash.to_string(), - }, - &router_contract, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + assert_eq!( + get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), + old_shd_balance + Uint128::new(44) + ); - { - let trade_count_info_msg = AMMPairQueryMsg::GetTradeCount {}; - let trade_count_info_query: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - trade_count_info_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::GetTradeCount { count } = trade_count_info_query { - assert_eq!(count, 0u64); - } else { - panic!("Trade count couldnt pass") - } - } + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + (old_scrt_balance - Uint128::new(50)) + ); - { - let trade_count_info_msg = AMMPairQueryMsg::GetTradeHistory { - pagination: Pagination { - start: 0u64, - limit: 10u8, - }, - api_key: API_KEY.to_string(), - }; - let trade_count_info_query: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - trade_count_info_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::GetTradeHistory { data } = trade_count_info_query { - assert_eq!(data.len(), 0u32 as usize); - } else { - panic!("Trade count couldnt pass") - } - } + print_header("\n\t 3 - SELL 2500 sSHD Initiating sSHD to sSCRT Swap "); + let old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); + let old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + handle( + &snip20::ExecuteMsg::Send { + recipient: router_contract.address.to_string(), + amount: Uint128::new(2500), + msg: Some( + to_binary(&RouterInvokeMsg::SwapTokensForExact { + expected_return: Some(Uint128::new(5)), + path: vec![Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }], + recipient: Some(account.to_string()), + }) + .unwrap(), + ), + padding: None, + recipient_code_hash: None, + memo: None, + }, + &s_sSHD, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); - print_header("\n\t 1. - BUY 100 sSHD Initiating sSCRT to sSHD Swap "); - let old_scrt_balance = - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - let old_shd_balance = - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); - handle( - &snip20::ExecuteMsg::Send { - recipient: router_contract.address.to_string(), - amount: Uint128::new(100), - msg: Some( - to_binary(&RouterInvokeMsg::SwapTokensForExact { - expected_return: Some(Uint128::new(10)), - paths: vec![ammPair.address.clone()], - recipient: Some(Addr::unchecked(account.to_string())), - }) - .unwrap(), - ), - padding: None, - recipient_code_hash: None, - memo: None, - }, - &s_sCRT, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + assert_eq!( + get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), + (old_shd_balance - Uint128::new(2500)) + ); - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - (old_scrt_balance - Uint128::new(100)) - ); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + old_scrt_balance + Uint128::new(2249) + ); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), - (old_shd_balance + Uint128::new(89)) - ); + print_header("\n\t 4 - SELL 36500 sSHD Initiating sSHD to sSCRT Swap "); + let old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); + let old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + handle( + &snip20::ExecuteMsg::Send { + recipient: router_contract.address.to_string(), + amount: Uint128::new(36500), + msg: Some( + to_binary(&RouterInvokeMsg::SwapTokensForExact { + expected_return: Some(Uint128::new(5)), + path: vec![Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }], + recipient: Some(account.to_string()), + }) + .unwrap(), + ), + padding: None, + recipient_code_hash: None, + memo: None, + }, + &s_sSHD, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); - { - let trade_count_info_msg = AMMPairQueryMsg::GetTradeCount {}; - let trade_count_info_query: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - trade_count_info_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::GetTradeCount { count } = trade_count_info_query { - assert_eq!(count, 1u64); - } else { - panic!("Trade count couldnt pass") - } - } + assert_eq!( + get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), + (old_shd_balance - Uint128::new(36500)) + ); - - { - let trade_count_info_msg = AMMPairQueryMsg::GetTradeHistory { - pagination: Pagination { - start: 0u64, - limit: 10u8, - }, - api_key: API_KEY.to_string(), - }; - let trade_count_info_query: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - trade_count_info_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::GetTradeHistory { data } = trade_count_info_query { - assert_eq!(data.len(), 1u32 as usize); - } else { - panic!("Trade count couldnt pass") - } - } + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + old_scrt_balance + Uint128::new(32849) + ); - let old_shd_balance = - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); - let old_scrt_balance = - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - print_header("\n\t 2 - BUY 50 sSHD Initiating sSCRT to sSHD Swap "); + print_header("\n\t 5 - BUY 25000 sSHD Initiating sSCRT to sSHD Swap "); + let mut old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); + let mut old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + handle( + &snip20::ExecuteMsg::Send { + recipient: router_contract.address.to_string(), + amount: Uint128::new(25000), + msg: Some( + to_binary(&RouterInvokeMsg::SwapTokensForExact { + expected_return: Some(Uint128::new(5)), + path: vec![Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }], + recipient: Some(account.to_string()), + }) + .unwrap(), + ), + padding: None, + recipient_code_hash: None, + memo: None, + }, + &s_sCRT, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); - handle( - &snip20::ExecuteMsg::Send { - recipient: router_contract.address.to_string(), - amount: Uint128::new(50), - msg: Some( - to_binary(&RouterInvokeMsg::SwapTokensForExact { - expected_return: Some(Uint128::new(5)), - paths: vec![ammPair.address.clone()], - recipient: Some(Addr::unchecked(account.to_string())), - }) - .unwrap(), - ), - padding: None, - recipient_code_hash: None, - memo: None, - }, - &s_sCRT, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + assert_eq!( + get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), + old_shd_balance + Uint128::new(22500) + ); - assert_eq!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), - old_shd_balance + Uint128::new(44) - ); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance( + &s_sCRT, + router_contract.address.to_string(), + VIEW_KEY.to_string() + ), + Uint128::new(0) + ); + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + (old_scrt_balance - Uint128::new(25000)) + ); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - (old_scrt_balance - Uint128::new(50)) - ); + print_header("\n\tInitiating SCRT to sSCRT Swap"); + old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - print_header("\n\t 3 - SELL 2500 sSHD Initiating sSHD to sSCRT Swap "); - let old_shd_balance = - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); - let old_scrt_balance = - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - handle( - &snip20::ExecuteMsg::Send { - recipient: router_contract.address.to_string(), - amount: Uint128::new(2500), - msg: Some( - to_binary(&RouterInvokeMsg::SwapTokensForExact { - expected_return: Some(Uint128::new(5)), - paths: vec![ammPair.address.clone()], - recipient: Some(Addr::unchecked(account.to_string())), - }) - .unwrap(), - ), - padding: None, - recipient_code_hash: None, - memo: None, + handle( + &RouterExecuteMsg::SwapTokensForExact { + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), }, - &s_sSHD, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + amount: Uint128::new(100), + }, + expected_return: None, + path: vec![Hop { + addr: amm_pair_2.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }], + recipient: None, + }, + &router_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("100uscrt"), + &mut reports, + None, + ) + .unwrap(); - assert_eq!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), - (old_shd_balance - Uint128::new(2500)) - ); + assert!(get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()) > old_scrt_balance); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - old_scrt_balance + Uint128::new(2249) - ); + print_header("\n\tInitiating Multi Leg Swap SCRT > sSHD"); + old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); - print_header("\n\t 4 - SELL 36500 sSHD Initiating sSHD to sSCRT Swap "); - let old_shd_balance = - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); - let old_scrt_balance = - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - handle( - &snip20::ExecuteMsg::Send { - recipient: router_contract.address.to_string(), - amount: Uint128::new(36500), - msg: Some( - to_binary(&RouterInvokeMsg::SwapTokensForExact { - expected_return: Some(Uint128::new(5)), - paths: vec![ammPair.address.clone()], - recipient: Some(Addr::unchecked(account.to_string())), - }) - .unwrap(), - ), - padding: None, - recipient_code_hash: None, - memo: None, + handle( + &RouterExecuteMsg::SwapTokensForExact { + offer: TokenAmount { + token: TokenType::NativeToken { + denom: "uscrt".to_string(), }, - &s_sSHD, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); + amount: Uint128::new(100), + }, + expected_return: None, + path: vec![ + Hop { + addr: amm_pair_2.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }, + Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }, + ], + recipient: None, + }, + &router_contract, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + Some("100uscrt"), + &mut reports, + None, + ) + .unwrap(); - assert_eq!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), - (old_shd_balance - Uint128::new(36500)) - ); + assert!(get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()) > old_shd_balance); + + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + old_scrt_balance + ); + + print_header("\n\tInitiating Multi Leg Swap sSHD > SCRT"); + old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); + + handle( + &snip20::ExecuteMsg::Send { + recipient: router_contract.address.to_string(), + amount: Uint128::new(100), + msg: Some( + to_binary(&RouterInvokeMsg::SwapTokensForExact { + expected_return: Some(Uint128::new(10)), + path: vec![ + Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }, + Hop { + addr: amm_pair_2.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }, + ], + recipient: Some(account.to_string()), + }) + .unwrap(), + ), + padding: None, + recipient_code_hash: None, + memo: None, + }, + &s_sSHD, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + assert!(get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()) < old_shd_balance); + + assert_eq!( + get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), + old_scrt_balance + ); + + print_header("\n\tGet Estimated Price for AMM Pair"); + let estimated_price_query_msg = AMMPairQueryMsg::GetEstimatedPrice { + offer: TokenAmount { + token: TokenType::CustomToken { + contract_addr: Addr::unchecked(s_sCRT.address.clone()), + token_code_hash: snip_20_code_hash.clone(), + }, + amount: Uint128::new(100), + }, + exclude_fee: None, + }; + let estimated_price_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + estimated_price_query_msg, + None, + )?; + if let AMMPairQueryMsgResponse::EstimatedPrice { estimated_price } = estimated_price_query { + assert_eq!(estimated_price, "0.9".to_string()); + } + + print_header("\n\tGet LP Token for AMM Pair"); + let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; + let lp_token_info_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + lp_token_info_msg, + None, + )?; + + if let AMMPairQueryMsgResponse::GetPairInfo { + liquidity_token, + factory: _, + pair: _, + amount_0: _, + amount_1: _, + total_liquidity, + contract_version: _, + } = lp_token_info_query + { + println!( + "\n\tLP Token Address {}", + liquidity_token.address.to_string() + ); + print_header("\n\tLP Token Liquidity - 10000000000"); + assert_eq!(total_liquidity, Uint128::new(10000000000)); + } + + let staking_contract_msg = AMMPairQueryMsg::GetStakingContract {}; + let staking_contract_query: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + staking_contract_msg, + None, + )?; + + if let AMMPairQueryMsgResponse::StakingContractInfo { staking_contract } = + staking_contract_query + { + println!("\n\tAllowed IncreaseAllowance for reward token - staking contract"); + // increase allowance for reward token + handle( + &snip20::ExecuteMsg::IncreaseAllowance { + spender: staking_contract.clone().unwrap().address.to_string(), + amount: Uint128::new(1000000000000), + expiration: None, + padding: None, + }, + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: s_sREWARDSNIP20.address.to_string(), + code_hash: s_sREWARDSNIP20.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + // send Reward token to staking contract + handle( + &snip20::ExecuteMsg::Send { + recipient: staking_contract.clone().unwrap().address.to_string(), + amount: Uint128::new(100000000000), + msg: None, + padding: None, + recipient_code_hash: None, + memo: None, + }, + &s_sREWARDSNIP20, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + println!("\n\tUnstake 5000000000LP TOKEN"); + + handle( + &StakingMsgHandle::Unstake { + amount: Uint128::new(5000000000), + remove_liqudity: Some(true), + }, + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.clone(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + print_header("\n\tGet LP Token for AMM Pair"); + let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; + let lp_token_info_query_unstake_a: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + lp_token_info_msg, + None, + )?; - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) + if let AMMPairQueryMsgResponse::GetPairInfo { + liquidity_token, + factory: _, + pair: _, + amount_0: _, + amount_1: _, + total_liquidity, + contract_version: _, + } = lp_token_info_query_unstake_a + { + println!( + "\n\tLP Token Address {}", + liquidity_token.address.to_string() ); - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - old_scrt_balance + Uint128::new(32849) + print_header("\n\tLP Token Liquidity - 5000000000"); + assert_eq!(total_liquidity.clone(), Uint128::new(5000000000)); + } + handle( + &StakingMsgHandle::Unstake { + amount: Uint128::new(50000000), + remove_liqudity: Some(true), + }, + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.clone(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + + let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; + let lp_token_info_query_unstake_b: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + lp_token_info_msg, + None, + )?; + if let AMMPairQueryMsgResponse::GetPairInfo { + liquidity_token, + factory: _, + pair: _, + amount_0: _, + amount_1: _, + total_liquidity, + contract_version: _, + } = lp_token_info_query_unstake_b + { + println!( + "\n\tLP Token Address {}", + liquidity_token.address.to_string() ); + print_header("\n\tLP Token Liquidity - 4950000000"); + assert_eq!(total_liquidity.clone(), Uint128::new(4950000000)); + } - print_header("\n\t 5 - BUY 25000 sSHD Initiating sSCRT to sSHD Swap "); - let mut old_shd_balance = - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); - let mut old_scrt_balance = - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - handle( - &snip20::ExecuteMsg::Send { - recipient: router_contract.address.to_string(), - amount: Uint128::new(25000), - msg: Some( - to_binary(&RouterInvokeMsg::SwapTokensForExact { - expected_return: Some(Uint128::new(5)), - paths: vec![ammPair.address.clone()], - recipient: Some(Addr::unchecked(account.to_string())), - }) - .unwrap(), - ), - padding: None, - recipient_code_hash: None, - memo: None, + print_header("\n\tIncreaseAllowance - 500000000 for liqudity "); + handle( + &snip20::ExecuteMsg::IncreaseAllowance { + spender: amm_pair_1.address.to_string(), + amount: Uint128::new(500000000), + expiration: None, + padding: None, + }, + &NetContract { + label: "".to_string(), + id: s_sCRT.id.clone(), + address: s_sCRT.address.clone(), + code_hash: snip_20_code_hash.clone(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + handle( + &snip20::ExecuteMsg::IncreaseAllowance { + spender: amm_pair_1.address.to_string(), + amount: Uint128::new(500000000), + expiration: None, + padding: None, + }, + &NetContract { + label: "".to_string(), + id: s_sSHD.id.clone(), + address: s_sSHD.address.clone(), + code_hash: s_sSHD.code_hash.to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + print_header("\n\tAddLiquidityToAMMContract - 500000000 with staking"); + handle( + &AMMPairHandlMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount { + pair: token_pair_1.clone(), + amount_0: Uint128::new(500000000), + amount_1: Uint128::new(500000000), }, - &s_sCRT, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - - assert_eq!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()), - old_shd_balance + Uint128::new(22500) - ); + expected_return: None, + staking: Some(true), + }, + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + ACCOUNT_KEY, + Some(GAS), + Some("test"), + None, + &mut reports, + None, + ) + .unwrap(); + print_header("\n\tGet LP Token for AMM Pair"); + let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; + let lp_token_info_query_unstake: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + lp_token_info_msg, + None, + )?; - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance( - &s_sCRT, - router_contract.address.to_string(), - VIEW_KEY.to_string() - ), - Uint128::new(0) - ); - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - (old_scrt_balance - Uint128::new(25000)) + if let AMMPairQueryMsgResponse::GetPairInfo { + liquidity_token, + factory: _, + pair: _, + amount_0: _, + amount_1: _, + total_liquidity, + contract_version: _, + } = lp_token_info_query_unstake + { + println!( + "\n\tLP Token Address {}", + liquidity_token.address.to_string() ); + print_header("\n\tLP Token Liquidity - 5449999219"); + assert_eq!(total_liquidity, Uint128::new(5449999219)); - print_header("\n\tInitiating SCRT to sSCRT Swap"); - old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); + let get_stake_lp_token_info = StakingQueryMsg::WithPermit { + permit: newPermit.clone(), + query: AuthQuery::GetStakerLpTokenInfo {}, + }; - handle( - &RouterExecuteMsg::SwapTokensForExact { - offer: TokenAmount { - token: TokenType::NativeToken { - denom: "uscrt".to_string(), - }, - amount: Uint128::new(100), - }, - expected_return: None, - path: vec![amm_pair_2.address.clone()], - recipient: None, + let stake_lp_token_info: StakingQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.to_string(), }, - &router_contract, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - Some("100uscrt"), - &mut reports, + get_stake_lp_token_info, None, - ) - .unwrap(); + )?; - assert!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()) > old_scrt_balance - ); + let mut old_staked_lp_token = Uint128::zero(); - print_header("\n\tInitiating Multi Leg Swap SCRT > sSHD"); - old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); + if let StakingQueryMsgResponse::StakerLpTokenInfo { + staked_lp_token, + total_staked_lp_token, + } = stake_lp_token_info + { + old_staked_lp_token = staked_lp_token; + } + print_header("\n\tRAW Adding Liquidity to SNIP20/20 staking contract"); handle( - &RouterExecuteMsg::SwapTokensForExact { - offer: TokenAmount { - token: TokenType::NativeToken { - denom: "uscrt".to_string(), - }, - amount: Uint128::new(100), + &AMMPairHandlMsg::AddLiquidityToAMMContract { + deposit: TokenPairAmount { + pair: token_pair_1.clone(), + amount_0: Uint128::new(10000000000), + amount_1: Uint128::new(10000000000), }, expected_return: None, - path: vec![amm_pair_2.address.clone(), ammPair.address.clone()], - recipient: None, + staking: Some(false), + }, + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), }, - &router_contract, ACCOUNT_KEY, Some(GAS), Some("test"), - Some("100uscrt"), + None, &mut reports, None, ) .unwrap(); - assert!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()) > old_shd_balance - ); - - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - old_scrt_balance - ); - - print_header("\n\tInitiating Multi Leg Swap sSHD > SCRT"); - old_scrt_balance = get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()); - old_shd_balance = get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()); - handle( &snip20::ExecuteMsg::Send { - recipient: router_contract.address.to_string(), - amount: Uint128::new(100), + recipient: staking_contract.clone().unwrap().address.to_string(), + amount: Uint128::new(1000), msg: Some( - to_binary(&RouterInvokeMsg::SwapTokensForExact { - expected_return: Some(Uint128::new(10)), - paths: vec![ammPair.address.clone(), amm_pair_2.address.clone()], - recipient: Some(Addr::unchecked(account.to_string())), + to_binary(&StakingInvokeMsg::Stake { + from:account, }) .unwrap(), ), @@ -1103,7 +1343,12 @@ fn run_testnet() -> Result<()> { recipient_code_hash: None, memo: None, }, - &s_sSHD, + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: liquidity_token.address.to_string(), + code_hash: liquidity_token.code_hash, + }, ACCOUNT_KEY, Some(GAS), Some("test"), @@ -1113,698 +1358,297 @@ fn run_testnet() -> Result<()> { ) .unwrap(); - assert!( - get_balance(&s_sSHD, account.to_string(), VIEW_KEY.to_string()) < old_shd_balance - ); - - assert_eq!( - get_balance(&s_sCRT, account.to_string(), VIEW_KEY.to_string()), - old_scrt_balance - ); - - print_header("\n\tGet Estimated Price for AMM Pair"); - let estimated_price_query_msg = AMMPairQueryMsg::GetEstimatedPrice { - offer: TokenAmount { - token: TokenType::CustomToken { - contract_addr: Addr::unchecked(s_sCRT.address.clone()), - token_code_hash: s_sCRT.code_hash.clone(), - }, - amount: Uint128::new(100), - }, - exclude_fee: None, + let get_stake_lp_token_info = StakingQueryMsg::WithPermit { + permit: newPermit.clone(), + query: AuthQuery::GetStakerLpTokenInfo {}, }; - let estimated_price_query: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - estimated_price_query_msg, - None, - )?; - if let AMMPairQueryMsgResponse::EstimatedPrice { estimated_price } = - estimated_price_query - { - assert_eq!(estimated_price, "0.9".to_string()); - } - print_header("\n\tGet LP Token for AMM Pair"); - let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; - let lp_token_info_query: AMMPairQueryMsgResponse = query( + let stake_lp_token_info: StakingQueryMsgResponse = query( &NetContract { label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.to_string(), }, - lp_token_info_msg, + get_stake_lp_token_info, None, )?; - if let AMMPairQueryMsgResponse::GetPairInfo { - liquidity_token, - factory: _, - pair: _, - amount_0: _, - amount_1: _, - total_liquidity, - contract_version: _, - } = lp_token_info_query + if let StakingQueryMsgResponse::StakerLpTokenInfo { + staked_lp_token, + total_staked_lp_token, + } = stake_lp_token_info { - println!( - "\n\tLP Token Address {}", - liquidity_token.address.to_string() - ); - print_header("\n\tLP Token Liquidity - 10000000000"); - assert_eq!(total_liquidity, Uint128::new(10000000000)); + assert!(old_staked_lp_token < staked_lp_token) } - let staking_contract_msg = AMMPairQueryMsg::GetStakingContract {}; - let staking_contract_query: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - staking_contract_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::StakingContractInfo { staking_contract } = - staking_contract_query - { - println!("\n\tAllowed IncreaseAllowance for reward token - staking contract"); - // increase allowance for reward token - handle( - &snip20::ExecuteMsg::IncreaseAllowance { - spender: staking_contract.clone().unwrap().address.to_string(), - amount: Uint128::new(1000000000000), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: s_sREWARDSNIP20.address.to_string(), - code_hash: s_sREWARDSNIP20.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - - // send Reward token to staking contract - handle( - &snip20::ExecuteMsg::Send { - recipient: staking_contract.clone().unwrap().address.to_string(), - amount: Uint128::new(100000000000), - msg: None, - padding: None, - recipient_code_hash: None, - memo: None, - }, - &s_sREWARDSNIP20, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - - println!("\n\tUnstake 5000000000LP TOKEN"); - - handle( - &StakingMsgHandle::Unstake { - amount: Uint128::new(5000000000), - remove_liqudity: Some(true), - }, - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: staking_contract.clone().unwrap().address.to_string(), - code_hash: staking_contract.clone().unwrap().code_hash.clone(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - print_header("\n\tGet LP Token for AMM Pair"); - let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; - let lp_token_info_query_unstake_a: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - lp_token_info_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::GetPairInfo { - liquidity_token, - factory: _, - pair: _, - amount_0: _, - amount_1: _, - total_liquidity, - contract_version: _, - } = lp_token_info_query_unstake_a - { - println!( - "\n\tLP Token Address {}", - liquidity_token.address.to_string() - ); - print_header("\n\tLP Token Liquidity - 5000000000"); - assert_eq!(total_liquidity.clone(), Uint128::new(5000000000)); - } - handle( - &StakingMsgHandle::Unstake { - amount: Uint128::new(50000000), - remove_liqudity: Some(true), - }, - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: staking_contract.clone().unwrap().address.to_string(), - code_hash: staking_contract.clone().unwrap().code_hash.clone(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - - let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; - let lp_token_info_query_unstake_b: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - lp_token_info_msg, - None, - )?; - if let AMMPairQueryMsgResponse::GetPairInfo { - liquidity_token, - factory: _, - pair: _, - amount_0: _, - amount_1: _, - total_liquidity, - contract_version: _, - } = lp_token_info_query_unstake_b - { - println!( - "\n\tLP Token Address {}", - liquidity_token.address.to_string() - ); - print_header("\n\tLP Token Liquidity - 4950000000"); - assert_eq!(total_liquidity.clone(), Uint128::new(4950000000)); - } - - print_header("\n\tIncreaseAllowance - 500000000 for liqudity "); - handle( - &snip20::ExecuteMsg::IncreaseAllowance { - spender: ammPair.address.to_string(), - amount: Uint128::new(500000000), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: s_sCRT.id.clone(), - address: s_sCRT.address.clone(), - code_hash: s_sCRT.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - handle( - &snip20::ExecuteMsg::IncreaseAllowance { - spender: ammPair.address.to_string(), - amount: Uint128::new(500000000), - expiration: None, - padding: None, - }, - &NetContract { - label: "".to_string(), - id: s_sSHD.id.clone(), - address: s_sSHD.address.clone(), - code_hash: s_sSHD.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - print_header("\n\tAddLiquidityToAMMContract - 500000000 with staking"); - handle( - &AMMPairHandlMsg::AddLiquidityToAMMContract { - deposit: TokenPairAmount { - pair: test_pair.clone(), - amount_0: Uint128::new(500000000), - amount_1: Uint128::new(500000000), - }, - expected_return: None, - staking: Some(true), - }, - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - ACCOUNT_KEY, - Some(GAS), - Some("test"), - None, - &mut reports, - None, - ) - .unwrap(); - print_header("\n\tGet LP Token for AMM Pair"); - let lp_token_info_msg = AMMPairQueryMsg::GetPairInfo {}; - let lp_token_info_query_unstake: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - lp_token_info_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::GetPairInfo { - liquidity_token, - factory: _, - pair: _, - amount_0: _, - amount_1: _, - total_liquidity, - contract_version: _, - } = lp_token_info_query_unstake - { - println!( - "\n\tLP Token Address {}", - liquidity_token.address.to_string() - ); - print_header("\n\tLP Token Liquidity - 5449999219"); - assert_eq!(total_liquidity, Uint128::new(5449999219)); - } - - print_header("\n\tSwap Simulation - Buy 540000SSH"); - let swap_simulation_msg = RouterQueryMsg::SwapSimulation { - offer: TokenAmount { - amount: Uint128::new(540000), - token: TokenType::CustomToken { - token_code_hash: s_sCRT.code_hash.to_string(), - contract_addr: Addr::unchecked(s_sCRT.address.clone()), - }, - }, - path: vec![ammPair.address.clone()], - }; - - let swap_result_response: RouterQueryResponse = query( - &NetContract { - label: "".to_string(), - id: router_contract.id.clone(), - address: router_contract.address.clone(), - code_hash: router_contract.code_hash.to_string(), - }, - swap_simulation_msg, - None, - )?; - - if let RouterQueryResponse::SwapSimulation { - total_fee_amount: _, - lp_fee_amount: _, - shade_dao_fee_amount: _, - result, - price: _, - } = swap_result_response - { - assert_ne!(result.return_amount, Uint128::new(0u128)); - } - - print_header("\n\tGet Shade DAO Info with Admin Address"); - let get_shade_dao_msg = AMMPairQueryMsg::GetShadeDaoInfo {}; - let shade_dao_response: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - get_shade_dao_msg, - None, - )?; - - if let AMMPairQueryMsgResponse::ShadeDAOInfo { - shade_dao_address, - shade_dao_fee: _, - admin_address, - lp_fee: _, - } = shade_dao_response - { - assert_ne!( - admin_address.to_string(), - Addr::unchecked("".to_string()).to_string() - ); - assert_ne!( - shade_dao_address.to_string(), - Addr::unchecked("".to_string()).to_string() - ) - } - - print_header("\n\tGet Claimamble Rewards "); - let get_claims_reward_msg = StakingQueryMsg::WithPermit { - permit: newPermit.clone(), - query: AuthQuery::GetClaimReward { - time: get_current_timestamp().unwrap(), - }, - }; - let claims_reward_response: StakingQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: staking_contract.clone().unwrap().address.to_string(), - code_hash: staking_contract.clone().unwrap().code_hash.to_string(), - }, - get_claims_reward_msg, - None, - )?; - - // if let StakingQueryMsgResponse::ClaimRewards { - // } = claims_reward_response - // { - // assert_ne!(amount, Uint128::new(0)); - // assert_eq!( - // reward_token.address.to_string(), - // s_sREWARDSNIP20.address.clone().to_string() - // ) - // } - - print_header("\n\tGet Staking Contract Config Info"); - let get_config_msg = StakingQueryMsg::GetConfig {}; - let config_query_response: StakingQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: staking_contract.clone().unwrap().address.to_string(), - code_hash: staking_contract.clone().unwrap().code_hash.to_string(), - }, - get_config_msg, - None, - )?; - - if let StakingQueryMsgResponse::Config { - reward_token, - lp_token: _, - daily_reward_amount, - amm_pair, - } = config_query_response - { - assert_eq!( - reward_token.address.to_string(), - s_sREWARDSNIP20.address.clone().to_string() - ); - assert_eq!( - reward_token.code_hash.to_string(), - s_sREWARDSNIP20.code_hash.clone() - ); - assert_eq!(daily_reward_amount, Uint128::new(3450000000000)); - } - print_header("\n\tGet Estimated LP Token & Total LP Token Liquditiy"); - let get_estimated_lp_token = AMMPairQueryMsg::GetEstimatedLiquidity { - deposit: TokenPairAmount { - pair: test_pair.clone(), - amount_0: Uint128::new(10000000000), - amount_1: Uint128::new(10000000000), - }, - slippage: None, - }; - let estimated_lp_token: AMMPairQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: s_ammPair.id.clone(), - address: ammPair.address.to_string(), - code_hash: s_ammPair.code_hash.to_string(), - }, - get_estimated_lp_token, - None, - )?; - - if let AMMPairQueryMsgResponse::EstimatedLiquidity { - lp_token, - total_lp_token, - } = estimated_lp_token - { - assert_ne!(lp_token, Uint128::new(0)); - assert_ne!(total_lp_token, Uint128::new(0)) - } - print_header("\n\tGetStakeLpTokenInfo For Staker"); - let get_stake_lp_token_info = StakingQueryMsg::WithPermit { - permit: newPermit, - query: AuthQuery::GetStakerLpTokenInfo {}, - }; - - let stake_lp_token_info: StakingQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: staking_contract.clone().unwrap().address.to_string(), - code_hash: staking_contract.clone().unwrap().code_hash.to_string(), - }, - get_stake_lp_token_info, - None, - )?; - - if let StakingQueryMsgResponse::StakerLpTokenInfo { - staked_lp_token, - total_staked_lp_token, - } = stake_lp_token_info - { - assert_ne!(staked_lp_token, Uint128::new(0)); - assert_ne!(total_staked_lp_token, Uint128::new(0)) - } - /* TO DO FIX - print_header("\n\tGetRewardTokenBalance"); - let get_balance_reward_token_msg = StakingQueryMsg::WithPermit { permit: newPermit, query: AuthQuery::GetRewardTokenBalance { - }}; - - let balance_reward_token: StakingQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: staking_contract.clone().unwrap().address.to_string(), - code_hash: staking_contract.clone().unwrap().code_hash.to_string(), - }, - get_balance_reward_token_msg, - None, - )?;*/ - - /*if let StakingQueryMsgResponse::RewardTokenBalance { - amount, - reward_token, - } = balance_reward_token - { - assert_eq!( - reward_token.address.to_string().clone(), - s_sREWARDSNIP20.address.clone() - ); - assert_eq!( - reward_token.code_hash.clone(), - s_sREWARDSNIP20.code_hash.to_string() - ); - assert_ne!(amount, Uint128::new(0)); - }*/ - print_header("\n\t GetStakerRewardTokenBalance for Non Staker"); - // let get_staker_reward_token_balance_msg = - // StakingQueryMsg::GetStakerRewardTokenBalance { - // key: String::from(VIEW_KEY), - // staker: Addr::unchecked(staker_account.to_string()), - // }; - // let staker_reward_token_balance: StakingQueryMsgResponse = query( - // &NetContract { - // label: "".to_string(), - // id: "".to_string(), - // address: staking_contract.address.to_string(), - // code_hash: staking_contract.code_hash.to_string(), - // }, - // get_staker_reward_token_balance_msg, - // None, - // )?; - - // if let StakingQueryMsgResponse::StakerRewardTokenBalance { - // reward_amount, - // total_reward_liquidity, - // } = staker_reward_token_balance - // { - // assert_ne!(reward_amount, Uint128::new(0)); - // assert_ne!(total_reward_liquidity, Uint128::new(0)); - // } - - /*print_header("\n\t GetStakerRewardTokenBalance for Staker"); - let get_staker_reward_token_balance_msg = - StakingQueryMsg::WithPermit { permit: newPermit.clone(), query: AuthQuery::GetStakerRewardTokenBalance { - }}; - let staker_reward_token_balance: StakingQueryMsgResponse = query( - &NetContract { - label: "".to_string(), - id: "".to_string(), - address: staking_contract.clone().unwrap().address.to_string(), - code_hash: staking_contract.clone().unwrap().code_hash.to_string(), - }, - get_staker_reward_token_balance_msg, - None, - )?; - - if let StakingQueryMsgResponse::StakerRewardTokenBalance { - reward_amount, - total_reward_liquidity, - reward_token, - } = staker_reward_token_balance - { - assert_ne!(reward_amount, Uint128::new(0)); - assert_ne!(total_reward_liquidity, Uint128::new(0)); - assert_eq!( - reward_token.address.to_string(), - s_sREWARDSNIP20.address.clone() - ); - assert_eq!( - reward_token.code_hash.clone(), - s_sREWARDSNIP20.code_hash.to_string() - ); - }*/ - } - } else { - assert!(false, "Query returned unexpected response") + print_header("\n\tEND Adding Liquidity to SNIP20/20 staking contract"); } - } - return Ok(()); -} + print_header("\n\tSwap Simulation - Buy 540000SSH"); + let swap_simulation_msg = RouterQueryMsg::SwapSimulation { + offer: TokenAmount { + amount: Uint128::new(540000), + token: TokenType::CustomToken { + token_code_hash: snip_20_code_hash.clone(), + contract_addr: Addr::unchecked(s_sCRT.address.clone()), + }, + }, + path: vec![Hop { + addr: amm_pair_1.address.to_string(), + code_hash: pair_contract_code_hash.clone(), + }], + }; -#[test] -fn run_test_deploy() -> Result<()> { - let account = account_address(ACCOUNT_KEY)?; - let shade_dao = account_address(SHADE_DAO_KEY)?; + let swap_result_response: RouterQueryResponse = query( + &NetContract { + label: "".to_string(), + id: router_contract.id.clone(), + address: router_contract.address.clone(), + code_hash: router_contract.code_hash.to_string(), + }, + swap_simulation_msg, + None, + )?; - println!("Using Account: {}", account.blue()); + if let RouterQueryResponse::SwapSimulation { + total_fee_amount: _, + lp_fee_amount: _, + shade_dao_fee_amount: _, + result, + price: _, + } = swap_result_response + { + assert_ne!(result.return_amount, Uint128::new(0u128)); + } - let _entropy = to_binary(&"ENTROPY".to_string()).unwrap(); + print_header("\n\tGet Shade DAO Info with Admin Address"); + let get_shade_dao_msg = AMMPairQueryMsg::GetShadeDaoInfo {}; + let shade_dao_response: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), + code_hash: "".to_string(), + }, + get_shade_dao_msg, + None, + )?; - let mut reports = vec![]; + if let AMMPairQueryMsgResponse::ShadeDAOInfo { + shade_dao_address, + shade_dao_fee: _, + lp_fee: _, + admin_auth: _, + } = shade_dao_response + { + assert_ne!( + shade_dao_address.to_string(), + Addr::unchecked("".to_string()).to_string() + ) + } - print_header("Storing all contracts"); - print_warning("Storing LP Token Contract"); - let s_lp = - store_and_return_contract(LPTOKEN20_FILE, ACCOUNT_KEY, Some(STORE_GAS), Some("test"))?; - print_warning("Storing AMM Pair Token Contract"); - let s_ammPair = - store_and_return_contract(AMM_PAIR_FILE, ACCOUNT_KEY, Some(STORE_GAS), Some("test"))?; - print_warning("Storing Staking Contract"); - let _staking_contract = - store_and_return_contract(STAKING_FILE, ACCOUNT_KEY, Some(STORE_GAS), Some("test"))?; + print_header("\n\tGet Claimamble Rewards "); + let get_claims_reward_msg = StakingQueryMsg::WithPermit { + permit: newPermit.clone(), + query: AuthQuery::GetClaimReward { + time: get_current_timestamp().unwrap(), + }, + }; + let _claims_reward_response: StakingQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.to_string(), + }, + get_claims_reward_msg, + None, + )?; - print_header("\n\tInitializing Factory Contract"); + // if let StakingQueryMsgResponse::ClaimRewards { + // } = claims_reward_response + // { + // assert_ne!(amount, Uint128::new(0)); + // assert_eq!( + // reward_token.address.to_string(), + // s_sREWARDSNIP20.address.clone().to_string() + // ) + // } + + print_header("\n\tGet Staking Contract Config Info"); + let get_config_msg = StakingQueryMsg::GetConfig {}; + let config_query_response: StakingQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.to_string(), + }, + get_config_msg, + None, + )?; - let factory_msg = FactoryInitMsg { - pair_contract: ContractInstantiationInfo { - code_hash: s_ammPair.code_hash.to_string(), - id: s_ammPair.id.clone().parse::().unwrap(), - }, - amm_settings: AMMSettings { - lp_fee: Fee::new(8, 100), - shade_dao_fee: Fee::new(2, 100), - shade_dao_address: ContractLink { - address: Addr::unchecked(String::from(shade_dao.to_string())), + if let StakingQueryMsgResponse::Config { + reward_token, + lp_token: _, + daily_reward_amount, + amm_pair: _, + admin_auth: _, + } = config_query_response + { + assert_eq!( + reward_token.address.to_string(), + s_sREWARDSNIP20.address.clone().to_string() + ); + assert_eq!( + reward_token.code_hash.to_string(), + s_sREWARDSNIP20.code_hash.clone() + ); + assert_eq!(daily_reward_amount, Uint128::new(3450000000000)); + } + print_header("\n\tGet Estimated LP Token & Total LP Token Liquditiy"); + let get_estimated_lp_token = AMMPairQueryMsg::GetEstimatedLiquidity { + deposit: TokenPairAmount { + pair: token_pair_1.clone(), + amount_0: Uint128::new(10000000000), + amount_1: Uint128::new(10000000000), + }, + }; + let estimated_lp_token: AMMPairQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: amm_pair_1.address.to_string(), code_hash: "".to_string(), }, - }, - lp_token_contract: ContractInstantiationInfo { - code_hash: s_lp.code_hash.clone(), - id: s_lp.id.clone().parse::().unwrap(), - }, - prng_seed: to_binary(&"".to_string()).unwrap(), - api_key: API_KEY.to_string(), - authenticator: None - }; - - let factory_contract = init( - &factory_msg, - FACTORY_FILE, - &*generate_label(8), - ACCOUNT_KEY, - Some(STORE_GAS), - Some(GAS), - Some("test"), - &mut reports, - )?; + get_estimated_lp_token, + None, + )?; - print_contract(&factory_contract); + if let AMMPairQueryMsgResponse::EstimatedLiquidity { + lp_token, + total_lp_token, + } = estimated_lp_token + { + assert_ne!(lp_token, Uint128::new(0)); + assert_ne!(total_lp_token, Uint128::new(0)) + } + print_header("\n\tGetStakeLpTokenInfo For Staker"); + let get_stake_lp_token_info = StakingQueryMsg::WithPermit { + permit: newPermit.clone(), + query: AuthQuery::GetStakerLpTokenInfo {}, + }; - print_header("\n\tGetting Pairs from Factory"); - { - let msg = FactoryQueryMsg::ListAMMPairs { - pagination: Pagination { - start: 0, - limit: 10, + let stake_lp_token_info: StakingQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.to_string(), }, - }; + get_stake_lp_token_info, + None, + )?; - let factory_query: FactoryQueryResponse = query(&factory_contract, msg, None)?; - if let FactoryQueryResponse::ListAMMPairs { amm_pairs } = factory_query { - assert_eq!(amm_pairs.len(), 0); + if let StakingQueryMsgResponse::StakerLpTokenInfo { + staked_lp_token, + total_staked_lp_token, + } = stake_lp_token_info + { + assert_ne!(staked_lp_token, Uint128::new(0)); + assert_ne!(total_staked_lp_token, Uint128::new(0)) + } - print_header("\n\tInitializing Router"); + /* TO DO FIX + print_header("\n\tGetRewardTokenBalance"); + let get_balance_reward_token_msg = StakingQueryMsg::WithPermit { permit: newPermit, query: AuthQuery::GetRewardTokenBalance { + }}; + + let balance_reward_token: StakingQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.to_string(), + }, + get_balance_reward_token_msg, + None, + )?;*/ - let router_msg = RouterInitMsg { - prng_seed: to_binary(&"".to_string()).unwrap(), - entropy: to_binary(&"".to_string()).unwrap(), - pair_contract_code_hash: s_ammPair.code_hash.to_string(), - }; + /*if let StakingQueryMsgResponse::RewardTokenBalance { + amount, + reward_token, + } = balance_reward_token + { + assert_eq!( + reward_token.address.to_string().clone(), + s_sREWARDSNIP20.address.clone() + ); + assert_eq!( + reward_token.code_hash.clone(), + s_sREWARDSNIP20.code_hash.to_string() + ); + assert_ne!(amount, Uint128::new(0)); + }*/ + print_header("\n\t GetStakerRewardTokenBalance for Non Staker"); + // let get_staker_reward_token_balance_msg = + // StakingQueryMsg::GetStakerRewardTokenBalance { + // key: String::from(VIEW_KEY), + // staker: Addr::unchecked(staker_account.to_string()), + // }; + // let staker_reward_token_balance: StakingQueryMsgResponse = query( + // &NetContract { + // label: "".to_string(), + // id: "".to_string(), + // address: staking_contract.address.to_string(), + // code_hash: staking_contract.code_hash.to_string(), + // }, + // get_staker_reward_token_balance_msg, + // None, + // )?; + + // if let StakingQueryMsgResponse::StakerRewardTokenBalance { + // reward_amount, + // total_reward_liquidity, + // } = staker_reward_token_balance + // { + // assert_ne!(reward_amount, Uint128::new(0)); + // assert_ne!(total_reward_liquidity, Uint128::new(0)); + // } + + /*print_header("\n\t GetStakerRewardTokenBalance for Staker"); + let get_staker_reward_token_balance_msg = + StakingQueryMsg::WithPermit { permit: newPermit.clone(), query: AuthQuery::GetStakerRewardTokenBalance { + }}; + let staker_reward_token_balance: StakingQueryMsgResponse = query( + &NetContract { + label: "".to_string(), + id: "".to_string(), + address: staking_contract.clone().unwrap().address.to_string(), + code_hash: staking_contract.clone().unwrap().code_hash.to_string(), + }, + get_staker_reward_token_balance_msg, + None, + )?; - let router_contract = init( - &router_msg, - ROUTER_FILE, - &*generate_label(8), - ACCOUNT_KEY, - Some(STORE_GAS), - Some(GAS), - Some("test"), - &mut reports, - )?; - print_contract(&router_contract); - } else { - assert!(false, "Query returned unexpected response") - } + if let StakingQueryMsgResponse::StakerRewardTokenBalance { + reward_amount, + total_reward_liquidity, + reward_token, + } = staker_reward_token_balance + { + assert_ne!(reward_amount, Uint128::new(0)); + assert_ne!(total_reward_liquidity, Uint128::new(0)); + assert_eq!( + reward_token.address.to_string(), + s_sREWARDSNIP20.address.clone() + ); + assert_eq!( + reward_token.code_hash.clone(), + s_sREWARDSNIP20.code_hash.to_string() + ); + }*/ } return Ok(()); diff --git a/packages/shadeswap-shared/src/amm_pair.rs b/packages/shadeswap-shared/src/amm_pair.rs deleted file mode 100644 index f6a4ec5..0000000 --- a/packages/shadeswap-shared/src/amm_pair.rs +++ /dev/null @@ -1,43 +0,0 @@ -use cosmwasm_std::{ - Addr -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use crate::core::{ContractLink, TokenPair, Fee, TokenType}; - -/// Represents the address of an exchange and the pair that it manages -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] -pub struct AMMPair { - /// The pair that the contract manages. - pub pair: TokenPair, - /// Address of the contract that manages the exchange. - pub address: Addr, - /// Used to enable or disable the AMMPair - pub enabled: bool -} - - -#[derive(Serialize, Deserialize, JsonSchema, PartialEq, Debug,Clone)] -pub struct AMMSettings { - pub lp_fee: Fee, - pub shade_dao_fee: Fee, - pub shade_dao_address: ContractLink -} - -pub fn generate_pair_key(pair: &TokenPair) -> Vec { - let mut bytes: Vec<&[u8]> = Vec::new(); - - match &pair.0 { - TokenType::NativeToken { denom } => bytes.push(denom.as_bytes()), - TokenType::CustomToken { contract_addr, .. } => bytes.push(contract_addr.as_bytes()) - } - - match &pair.1 { - TokenType::NativeToken { denom } => bytes.push(denom.as_bytes()), - TokenType::CustomToken { contract_addr, .. } => bytes.push(contract_addr.as_bytes()) - } - - bytes.sort(); - - bytes.concat() -} \ No newline at end of file diff --git a/packages/shadeswap-shared/src/contract_interfaces/admin/errors.rs b/packages/shadeswap-shared/src/contract_interfaces/admin/errors.rs new file mode 100644 index 0000000..e7125e4 --- /dev/null +++ b/packages/shadeswap-shared/src/contract_interfaces/admin/errors.rs @@ -0,0 +1,74 @@ +use crate::{ + impl_into_u8, + utils::errors::{build_string, CodeType, DetailedError}, +}; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::StdError; + +#[cw_serde] +#[repr(u8)] +pub enum Error { + UnregisteredAdmin, + UnauthorizedAdmin, + UnauthorizedSuper, + NoPermissions, + IsShutdown, + IsUnderMaintenance, + InvalidPermissionFormat, +} + +impl_into_u8!(Error); + +impl CodeType for Error { + fn to_verbose(&self, context: &Vec<&str>) -> String { + build_string( + match self { + Error::UnregisteredAdmin => "{} has not been registered as an admin", + Error::UnauthorizedAdmin => "{} does not have this permissions - {}", + Error::UnauthorizedSuper => "{} is not the authorized super admin", + Error::NoPermissions => "There are not permissions for {}", + Error::IsShutdown => { + "Contract is currently shutdown. It must be turned on for any changes to be made or any permissions to be validates" + } + Error::IsUnderMaintenance => { + "Contract is under maintenance. Oly registry updated may be made. Permission validation is disabled." + } + Error::InvalidPermissionFormat => { + "{} must be > 10 characters and only contains 0-9, A-Z, and underscores" + } + }, + context, + ) + } +} + +const ADMIN_TARGET: &str = "admin"; + +pub fn unregistered_admin(address: &str) -> StdError { + DetailedError::from_code(ADMIN_TARGET, Error::UnregisteredAdmin, vec![address]).to_error() +} + +pub fn unauthorized_admin(address: &str, permission: &str) -> StdError { + DetailedError::from_code(ADMIN_TARGET, Error::UnauthorizedAdmin, vec![ + address, permission, + ]) + .to_error() +} +pub fn unauthorized_super(super_admin: &str) -> StdError { + DetailedError::from_code(ADMIN_TARGET, Error::UnauthorizedSuper, vec![super_admin]).to_error() +} +pub fn no_permission(user: &str) -> StdError { + DetailedError::from_code(ADMIN_TARGET, Error::NoPermissions, vec![user]).to_error() +} +pub fn is_shutdown() -> StdError { + DetailedError::from_code(ADMIN_TARGET, Error::IsShutdown, vec![]).to_error() +} +pub fn is_under_maintenance() -> StdError { + DetailedError::from_code(ADMIN_TARGET, Error::IsUnderMaintenance, vec![]).to_error() +} +pub fn invalid_permission_format(permission: &str) -> StdError { + DetailedError::from_code(ADMIN_TARGET, Error::InvalidPermissionFormat, vec![ + permission, + ]) + .to_error() +} diff --git a/packages/shadeswap-shared/src/contract_interfaces/admin/helpers.rs b/packages/shadeswap-shared/src/contract_interfaces/admin/helpers.rs new file mode 100644 index 0000000..e57bc64 --- /dev/null +++ b/packages/shadeswap-shared/src/contract_interfaces/admin/helpers.rs @@ -0,0 +1,72 @@ +use crate::{ + admin::{errors::unauthorized_admin, QueryMsg, ValidateAdminPermissionResponse}, + utils::Query, + Contract, +}; +use cosmwasm_std::{QuerierWrapper, StdResult}; + +pub fn validate_admin + Clone>( + querier: &QuerierWrapper, + permission: AdminPermissions, + user: T, + admin_auth: &Contract, +) -> StdResult<()> { + if admin_is_valid(querier, permission.clone(), user.clone(), admin_auth)? { + Ok(()) + } else { + Err(unauthorized_admin(&user.into(), &permission.into_string())) + } +} + +pub fn admin_is_valid>( + querier: &QuerierWrapper, + permission: AdminPermissions, + user: T, + admin_auth: &Contract, +) -> StdResult { + let admin_resp: StdResult = + QueryMsg::ValidateAdminPermission { + permission: permission.into_string(), + user: user.into(), + } + .query(querier, admin_auth); + + match admin_resp { + Ok(resp) => Ok(resp.has_permission), + Err(err) => Err(err), + } +} + +#[derive(Clone)] +pub enum AdminPermissions { + QueryAuthAdmin, + ScrtStakingAdmin, + TreasuryManager, + TreasuryAdmin, + StabilityAdmin, + SkyAdmin, + LendAdmin, + OraclesAdmin, + SilkAdmin, + ShadeSwapAdmin, +} + +// NOTE: SHADE_{CONTRACT_NAME}_{CONTRACT_ROLE}_{POTENTIAL IDs} + +impl AdminPermissions { + pub fn into_string(self) -> String { + match self { + AdminPermissions::QueryAuthAdmin => "SHADE_QUERY_AUTH_ADMIN", + AdminPermissions::ScrtStakingAdmin => "SHADE_SCRT_STAKING_ADMIN", + AdminPermissions::TreasuryManager => "SHADE_TREASURY_MANAGER", + AdminPermissions::TreasuryAdmin => "SHADE_TREASURY_ADMIN", + AdminPermissions::StabilityAdmin => "SHADE_STABILITY_ADMIN", + AdminPermissions::SkyAdmin => "SHADE_SKY_ADMIN", + AdminPermissions::LendAdmin => "SHADE_LEND_ADMIN", + AdminPermissions::OraclesAdmin => "SHADE_ORACLES_ADMIN", + AdminPermissions::SilkAdmin => "SHADE_SILK_ADMIN", + AdminPermissions::ShadeSwapAdmin => "SHADE_SWAP_ADMIN" + } + .to_string() + } +} diff --git a/packages/shadeswap-shared/src/contract_interfaces/admin/mod.rs b/packages/shadeswap-shared/src/contract_interfaces/admin/mod.rs new file mode 100644 index 0000000..9c1d41b --- /dev/null +++ b/packages/shadeswap-shared/src/contract_interfaces/admin/mod.rs @@ -0,0 +1,112 @@ +use crate::{ + admin::errors::{is_shutdown, is_under_maintenance}, + utils::{ExecuteCallback, InstantiateCallback, Query}, +}; +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{Addr, StdResult}; + +pub mod errors; +pub mod helpers; + +#[cw_serde] +pub enum AdminAuthStatus { + Active, + Maintenance, + Shutdown, +} + +impl AdminAuthStatus { + // Throws an error if status is under maintenance + pub fn not_under_maintenance(&self) -> StdResult<&Self> { + if self.eq(&AdminAuthStatus::Maintenance) { + return Err(is_under_maintenance()); + } + Ok(self) + } + + // Throws an error if status is shutdown + pub fn not_shutdown(&self) -> StdResult<&Self> { + if self.eq(&AdminAuthStatus::Shutdown) { + return Err(is_shutdown()); + } + Ok(self) + } +} + +#[cw_serde] +pub struct InstantiateMsg { + pub super_admin: Option, +} + +impl InstantiateCallback for InstantiateMsg { + const BLOCK_SIZE: usize = 256; +} + +#[cw_serde] +pub enum ExecuteMsg { + UpdateRegistry { action: RegistryAction }, + UpdateRegistryBulk { actions: Vec }, + TransferSuper { new_super: String }, + SelfDestruct {}, + ToggleStatus { new_status: AdminAuthStatus }, +} + +#[cw_serde] +pub enum RegistryAction { + RegisterAdmin { + user: String, + }, + GrantAccess { + permissions: Vec, + user: String, + }, + RevokeAccess { + permissions: Vec, + user: String, + }, + DeleteAdmin { + user: String, + }, +} + +impl ExecuteCallback for ExecuteMsg { + const BLOCK_SIZE: usize = 256; +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + #[returns(ConfigResponse)] + GetConfig {}, + #[returns(AdminsResponse)] + GetAdmins {}, + #[returns(PermissionsResponse)] + GetPermissions { user: String }, + #[returns(ValidateAdminPermissionResponse)] + ValidateAdminPermission { permission: String, user: String }, +} + +impl Query for QueryMsg { + const BLOCK_SIZE: usize = 256; +} + +#[cw_serde] +pub struct ConfigResponse { + pub super_admin: Addr, + pub status: AdminAuthStatus, +} + +#[cw_serde] +pub struct PermissionsResponse { + pub permissions: Vec, +} + +#[cw_serde] +pub struct AdminsResponse { + pub admins: Vec, +} + +#[cw_serde] +pub struct ValidateAdminPermissionResponse { + pub has_permission: bool, +} diff --git a/packages/shadeswap-shared/src/contract_interfaces/mod.rs b/packages/shadeswap-shared/src/contract_interfaces/mod.rs index f75b750..21ba483 100644 --- a/packages/shadeswap-shared/src/contract_interfaces/mod.rs +++ b/packages/shadeswap-shared/src/contract_interfaces/mod.rs @@ -1,3 +1,4 @@ #![allow(dead_code)] pub mod snip20; -pub mod query_auth; \ No newline at end of file +pub mod query_auth; +pub mod admin; \ No newline at end of file diff --git a/packages/shadeswap-shared/src/core/admin.rs b/packages/shadeswap-shared/src/core/admin.rs index b174dac..08ff6b4 100644 --- a/packages/shadeswap-shared/src/core/admin.rs +++ b/packages/shadeswap-shared/src/core/admin.rs @@ -1,37 +1,37 @@ -use cosmwasm_std::{ - StdError, - StdResult, - Storage, Response, MessageInfo, Addr -}; -use cosmwasm_storage::{singleton, Singleton, singleton_read, ReadonlySingleton}; +// use cosmwasm_std::{ +// StdError, +// StdResult, +// Storage, Response, MessageInfo, Addr +// }; +// use cosmwasm_storage::{singleton, Singleton, singleton_read, ReadonlySingleton}; -pub static ADMIN: &[u8] =b"contract_pair_admin"; +// pub static ADMIN: &[u8] =b"contract_pair_admin"; -pub fn admin_w(storage: &mut dyn Storage) -> Singleton { - singleton(storage, ADMIN) -} +// pub fn admin_w(storage: &mut dyn Storage) -> Singleton { +// singleton(storage, ADMIN) +// } -pub fn admin_r(storage: & dyn Storage) -> ReadonlySingleton { - singleton_read(storage, ADMIN) -} +// pub fn admin_r(storage: & dyn Storage) -> ReadonlySingleton { +// singleton_read(storage, ADMIN) +// } -pub fn apply_admin_guard( - caller: &Addr, - storage: &mut dyn Storage, -) -> StdResult { - let admin_address = admin_r(storage).load()?; - if caller != &admin_address { - return Err(StdError::generic_err("Caller is not admin")) - } - return Ok(true) -} +// // pub fn apply_admin_guard( +// // caller: &Addr, +// // storage: &mut dyn Storage, +// // ) -> StdResult { +// // let admin_address = admin_r(storage).load()?; +// // if caller != &admin_address { +// // return Err(StdError::generic_err("Caller is not admin")) +// // } +// // return Ok(true) +// // } -pub fn set_admin_guard( - storage: &mut dyn Storage, - info: MessageInfo, - admin: Addr -) -> StdResult{ - apply_admin_guard(&info.sender, storage)?; - admin_w(storage).save(&admin)?; - Ok(Response::default()) -} \ No newline at end of file +// pub fn set_admin_guard( +// storage: &mut dyn Storage, +// info: MessageInfo, +// admin: Addr +// ) -> StdResult{ +// apply_admin_guard(&info.sender, storage)?; +// admin_w(storage).save(&admin)?; +// Ok(Response::default()) +// } \ No newline at end of file diff --git a/packages/shadeswap-shared/src/core/callback.rs b/packages/shadeswap-shared/src/core/callback.rs index df2dcde..f9d1c1f 100644 --- a/packages/shadeswap-shared/src/core/callback.rs +++ b/packages/shadeswap-shared/src/core/callback.rs @@ -4,7 +4,7 @@ use cosmwasm_std::{Binary, CosmosMsg, WasmMsg}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use super::{ContractLink}; +use crate::Contract; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] /// Info needed to have the other contract respond. @@ -12,7 +12,7 @@ pub struct Callback { /// The message to call. pub msg: Binary, /// Info about the contract requesting the callback. - pub contract: ContractLink + pub contract: Contract } impl Into for Callback { diff --git a/packages/shadeswap-shared/src/core/link.rs b/packages/shadeswap-shared/src/core/link.rs index 31dbaa8..6fb1f94 100644 --- a/packages/shadeswap-shared/src/core/link.rs +++ b/packages/shadeswap-shared/src/core/link.rs @@ -1,4 +1,3 @@ -use cosmwasm_std::{Addr, Env}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; pub type CodeId = u64; @@ -21,32 +20,6 @@ impl PartialEq for ContractInstantiationInfo { } } -/// Info needed to talk to a contract instance. -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)] -pub struct ContractLink { - pub address: Addr, - pub code_hash: CodeHash, -} - -// Disregard code hash because it is case insensitive. -// Converting to the same case first and the comparing is unnecessary -// as providing the wrong code hash when calling a contract will result -// in an error regardless and we have no way of checking that here. -impl PartialEq for ContractLink { - fn eq(&self, other: &Self) -> bool { - self.address == other.address - } -} - -impl From for ContractLink { - fn from(env: Env) -> ContractLink { - ContractLink { - address: env.contract.address, - code_hash: env.contract.code_hash, - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -92,43 +65,5 @@ mod tests { } ); - assert_eq!( - ContractLink { - address: Addr::unchecked("secret1rgm2m5t530tdzyd99775n6vzumxa5luxcllml4"), - code_hash: "c1dc8261059fee1de9f1873cd1359ccd7a6bc5623772661fa3d55332eb652084" - .into() - }, - ContractLink { - address: Addr::unchecked("secret1rgm2m5t530tdzyd99775n6vzumxa5luxcllml4"), - code_hash: "c1dc8261059fee1de9f1873cd1359ccd7a6bc5623772661fa3d55332eb652084" - .into() - } - ); - - assert_eq!( - ContractLink { - address: Addr::unchecked("secret1rgm2m5t530tdzyd99775n6vzumxa5luxcllml4"), - code_hash: "c1dc8261059fee1de9f1873cd1359ccd7a6bc5623772661fa3d55332eb652084" - .into() - }, - ContractLink { - address: Addr::unchecked("secret1rgm2m5t530tdzyd99775n6vzumxa5luxcllml4"), - code_hash: "C1dc8261059fee1de9f1873cd1359ccd7a6bc5623772661fa3d55332eb652084" - .into() - } - ); - - assert_ne!( - ContractLink { - address: Addr::unchecked("secret1rgm2m5t530tdzyd99775n6vzumxa5luxcllml4"), - code_hash: "c1dc8261059fee1de9f1873cd1359ccd7a6bc5623772661fa3d55332eb652084" - .into() - }, - ContractLink { - address: Addr::unchecked("secret1rgm2m5t530tdzyd99775n6vzumxa5luxcllml5"), - code_hash: "C1dc8261059fee1de9f1873cd1359ccd7a6bc5623772661fa3d55332eb652084" - .into() - } - ); } } diff --git a/packages/shadeswap-shared/src/core/token_type.rs b/packages/shadeswap-shared/src/core/token_type.rs index 325120e..fe38181 100644 --- a/packages/shadeswap-shared/src/core/token_type.rs +++ b/packages/shadeswap-shared/src/core/token_type.rs @@ -72,7 +72,7 @@ impl TokenType { TokenType::CustomToken { contract_addr, token_code_hash, - } => { + } => { balance_query(&deps.querier, deps.api.addr_validate(&exchange_addr)?, viewing_key, &Contract { address: contract_addr.clone(), code_hash: token_code_hash.clone(), diff --git a/packages/shadeswap-shared/src/lib.rs b/packages/shadeswap-shared/src/lib.rs index 06ecf1b..ad3c541 100644 --- a/packages/shadeswap-shared/src/lib.rs +++ b/packages/shadeswap-shared/src/lib.rs @@ -1,6 +1,5 @@ pub mod msg; pub use msg::*; -pub mod amm_pair; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; pub use sha2; diff --git a/packages/shadeswap-shared/src/msg.rs b/packages/shadeswap-shared/src/msg.rs index f57f0b4..67fee88 100644 --- a/packages/shadeswap-shared/src/msg.rs +++ b/packages/shadeswap-shared/src/msg.rs @@ -1,5 +1,4 @@ use crate::core::ContractInstantiationInfo; -use crate::core::ContractLink; use cosmwasm_std::Binary; use cosmwasm_std::Uint128; use schemars::JsonSchema; @@ -10,19 +9,20 @@ use serde::{Deserialize, Serialize}; pub struct CountResponse { pub count: i32, } +use crate::{utils::ExecuteCallback}; pub mod router { - use cosmwasm_std::Addr; + use super::{amm_pair::SwapResult, *}; - use crate::core::{TokenAmount, TokenType}; + use crate::{core::{TokenAmount, TokenType}, Contract}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub enum InvokeMsg { SwapTokensForExact { - paths: Vec, + path: Vec, expected_return: Option, - recipient: Option, + recipient: Option, }, } @@ -30,7 +30,14 @@ pub mod router { pub struct InitMsg { pub prng_seed: Binary, pub entropy: Binary, - pub pair_contract_code_hash: String, + pub admin_auth: Contract + } + + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] + pub struct Hop { + pub addr: String, + pub code_hash: String } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -38,7 +45,7 @@ pub mod router { pub enum ExecuteMsg { // SNIP20 receiver interface Receive { - from: Addr, + from: String, msg: Option, amount: Uint128, }, @@ -46,29 +53,29 @@ pub mod router { /// The token type to swap from. offer: TokenAmount, expected_return: Option, - path: Vec, - recipient: Option, - }, - SwapCallBack { - last_token_out: TokenAmount, - signature: Binary, + path: Vec, + recipient: Option, }, RegisterSNIP20Token { - token_addr: Addr, + token_addr: String, token_code_hash: String, }, RecoverFunds { token: TokenType, amount: Uint128, - to: Addr, + to: String, msg: Option, }, } + impl ExecuteCallback for ExecuteMsg { + const BLOCK_SIZE: usize = 256; + } + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { - SwapSimulation { offer: TokenAmount, path: Vec }, + SwapSimulation { offer: TokenAmount, path: Vec }, GetConfig {}, } @@ -83,8 +90,7 @@ pub mod router { price: String, }, GetConfig { - pair_contract_code_hash: String, - }, + } } } @@ -92,14 +98,51 @@ pub mod amm_pair { use super::*; use crate::{ core::{ - Callback, ContractInstantiationInfo, ContractLink, CustomFee, Fee, TokenAmount, + Callback, ContractInstantiationInfo, CustomFee, Fee, TokenAmount, TokenPair, TokenPairAmount, TokenType, }, - Pagination, staking::StakingContractInit, + Pagination, staking::StakingContractInit, Contract, }; - use cosmwasm_std::{Addr, Decimal}; + use cosmwasm_std::{Addr}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; + + /// Represents the address of an exchange and the pair that it manages + #[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] + pub struct AMMPair { + /// The pair that the contract manages. + pub pair: TokenPair, + /// Address of the contract that manages the exchange. + pub address: Addr, + /// Used to enable or disable the AMMPair + pub enabled: bool + } + + + #[derive(Serialize, Deserialize, JsonSchema, PartialEq, Debug,Clone)] + pub struct AMMSettings { + pub lp_fee: Fee, + pub shade_dao_fee: Fee, + pub shade_dao_address: Contract + } + + pub fn generate_pair_key(pair: &TokenPair) -> Vec { + let mut bytes: Vec<&[u8]> = Vec::new(); + + match &pair.0 { + TokenType::NativeToken { denom } => bytes.push(denom.as_bytes()), + TokenType::CustomToken { contract_addr, .. } => bytes.push(contract_addr.as_bytes()) + } + + match &pair.1 { + TokenType::NativeToken { denom } => bytes.push(denom.as_bytes()), + TokenType::CustomToken { contract_addr, .. } => bytes.push(contract_addr.as_bytes()) + } + + bytes.sort(); + + bytes.concat() + } #[derive(Serialize, Deserialize, PartialEq, Debug, JsonSchema)] pub struct SwapInfo { @@ -130,13 +173,12 @@ pub mod amm_pair { pub struct InitMsg { pub pair: TokenPair, pub lp_token_contract: ContractInstantiationInfo, - pub factory_info: ContractLink, + pub factory_info: Contract, pub prng_seed: Binary, pub entropy: Binary, - pub admin: Option, + pub admin_auth: Contract, pub staking_contract: Option, - pub custom_fee: Option, - pub callback: Option, + pub custom_fee: Option } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -150,24 +192,22 @@ pub mod amm_pair { /// The token type to swap from. offer: TokenAmount, expected_return: Option, - to: Option, - router_link: Option, - callback_signature: Option, + to: Option }, // SNIP20 receiver interface Receive { - from: Addr, + from: String, msg: Option, amount: Uint128, }, AddWhiteListAddress { - address: Addr, + address: String, }, RemoveWhitelistAddresses { - addresses: Vec, + addresses: Vec, }, - SetAdmin { - admin: Addr, + SetConfig { + admin_auth: Option }, SetCustomPairFee { custom_fee: Option, @@ -178,21 +218,24 @@ pub mod amm_pair { RecoverFunds { token: TokenType, amount: Uint128, - to: Addr, + to: String, msg: Option, }, } + + impl ExecuteCallback for ExecuteMsg { + const BLOCK_SIZE: usize = 256; + } + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum InvokeMsg { SwapTokens { expected_return: Option, - to: Option, - router_link: Option, - callback_signature: Option, + to: Option, }, RemoveLiquidity { - from: Option, + from: Option, }, } #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug)] @@ -206,7 +249,6 @@ pub mod amm_pair { }, GetWhiteListAddress {}, GetTradeCount {}, - GetAdmin {}, GetStakingContract {}, GetEstimatedPrice { offer: TokenAmount, @@ -217,8 +259,7 @@ pub mod amm_pair { }, GetShadeDaoInfo {}, GetEstimatedLiquidity { - deposit: TokenPairAmount, - slippage: Option, + deposit: TokenPairAmount }, } @@ -226,8 +267,8 @@ pub mod amm_pair { #[serde(rename_all = "snake_case")] pub enum QueryMsgResponse { GetPairInfo { - liquidity_token: ContractLink, - factory: ContractLink, + liquidity_token: Contract, + factory: Contract, pair: TokenPair, amount_0: Uint128, amount_1: Uint128, @@ -243,14 +284,11 @@ pub mod amm_pair { GetTradeCount { count: u64, }, - GetAdmin { - address: Addr, - }, GetClaimReward { amount: Uint128, }, StakingContractInfo { - staking_contract: Option, + staking_contract: Option, }, EstimatedPrice { estimated_price: String, @@ -266,16 +304,16 @@ pub mod amm_pair { shade_dao_address: String, shade_dao_fee: Fee, lp_fee: Fee, - admin_address: String, + admin_auth: Contract, }, EstimatedLiquidity { lp_token: Uint128, total_lp_token: Uint128, }, GetConfig { - factory_contract: ContractLink, - lp_token: ContractLink, - staking_contract: Option, + factory_contract: Contract, + lp_token: Contract, + staking_contract: Option, pair: TokenPair, custom_fee: Option, }, @@ -289,7 +327,6 @@ pub mod factory { use crate::Contract; use crate::staking::StakingContractInit; use crate::{amm_pair::AMMSettings, Pagination}; - use cosmwasm_std::Addr; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -302,6 +339,7 @@ pub mod factory { pub api_key: String, //Set the default authenticator for all permits on the contracts pub authenticator: Option, + pub admin_auth: Contract } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -312,24 +350,20 @@ pub mod factory { lp_token_contract: Option, amm_settings: Option, api_key: Option, + admin_auth: Option, }, CreateAMMPair { pair: TokenPair, entropy: Binary, staking_contract: Option, - // This is used to optionally register the token - router_contract: Option, }, AddAMMPairs { amm_pairs: Vec, - }, - SetAdmin { - admin: Addr, - }, - RegisterAMMPair { - pair: TokenPair, - signature: Binary, - }, + } + } + + impl ExecuteCallback for ExecuteMsg { + const BLOCK_SIZE: usize = 256; } #[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq)] @@ -343,13 +377,11 @@ pub mod factory { amm_settings: AMMSettings, lp_token_contract: ContractInstantiationInfo, authenticator: Option, + admin_auth: Contract, }, GetAMMPairAddress { address: String, }, - GetAdmin { - address: String, - }, AuthorizeApiKey { authorized: bool, }, @@ -362,17 +394,16 @@ pub mod factory { ListAMMPairs { pagination: Pagination }, GetAMMPairAddress { pair: TokenPair }, GetConfig, - GetAdmin, AuthorizeApiKey { api_key: String }, } } pub mod staking { - use crate::{core::TokenType, query_auth::QueryPermit,Contract, stake_contract::ClaimableInfo}; + use crate::{core::TokenType, query_auth::QueryPermit,Contract, stake_contract::{ClaimableInfo, RewardTokenInfo}}; use super::*; use cosmwasm_schema::cw_serde; - use cosmwasm_std::Addr; + use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -381,6 +412,7 @@ pub mod staking { pub contract_info: ContractInstantiationInfo, pub daily_reward_amount: Uint128, pub reward_token: TokenType, + pub valid_to: Uint128 } #[cw_serde] @@ -390,12 +422,13 @@ pub mod staking { pub struct InitMsg { pub daily_reward_amount: Uint128, pub reward_token: TokenType, - pub pair_contract: ContractLink, + pub valid_to: Uint128, + pub pair_contract: Contract, pub prng_seed: Binary, - pub lp_token: ContractLink, + pub lp_token: Contract, //Used for permits pub authenticator: Option, - pub admin: Addr, + pub admin_auth: Contract, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -403,7 +436,7 @@ pub mod staking { pub enum ExecuteMsg { ClaimRewards {}, ProxyUnstake { - for_addr: Addr, + for_addr: String, amount: Uint128, }, Unstake { @@ -411,35 +444,39 @@ pub mod staking { remove_liqudity: Option, }, Receive { - from: Addr, + from: String, msg: Option, amount: Uint128, }, SetRewardToken { - reward_token: ContractLink, + reward_token: Contract, daily_reward_amount: Uint128, valid_to: Uint128 }, SetAuthenticator { authenticator: Option, }, - SetAdmin { - admin: Addr, + SetConfig { + admin_auth: Option, }, RecoverFunds { token: TokenType, amount: Uint128, - to: Addr, + to: String, msg: Option, - }, + }, + } + + impl ExecuteCallback for ExecuteMsg { + const BLOCK_SIZE: usize = 256; } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum InvokeMsg { - Stake { from: Addr }, + Stake { from: String }, ProxyStake { - for_addr: Addr + for_addr: String } } @@ -452,7 +489,6 @@ pub mod staking { permit: QueryPermit, query: AuthQuery, }, - GetAdmin {}, } #[derive(Serialize, Deserialize, Debug, JsonSchema, PartialEq, Clone)] @@ -460,6 +496,7 @@ pub mod staking { pub enum AuthQuery { GetStakerLpTokenInfo {}, GetClaimReward { time: Uint128 }, + GetRewardTokens {} } #[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, PartialEq)] @@ -477,29 +514,30 @@ pub mod staking { }, RewardTokenBalance { amount: Uint128, - reward_token: ContractLink, + reward_token: Contract, }, StakerRewardTokenBalance { reward_amount: Uint128, total_reward_liquidity: Uint128, - reward_token: ContractLink, + reward_token: Contract, }, Config { - reward_token: ContractLink, - lp_token: ContractLink, + reward_token: Contract, + lp_token: Contract, daily_reward_amount: Uint128, - amm_pair: Addr, - }, - GetAdmin { - admin: Addr, + amm_pair: String, + admin_auth: Contract }, + RewardTokens{ + tokens: Vec + } } } pub mod lp_token { - use cosmwasm_std::Addr; + - use crate::snip20::InitialBalance; + use crate::{snip20::InitialBalance}; use super::*; @@ -525,7 +563,7 @@ pub mod lp_token { #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)] pub struct InstantiateMsg { pub name: String, - pub admin: Option, + pub admin: Option, pub symbol: String, pub decimals: u8, pub initial_balances: Option>, diff --git a/packages/shadeswap-shared/src/stake_contract.rs b/packages/shadeswap-shared/src/stake_contract.rs index be87d88..e6fa59b 100644 --- a/packages/shadeswap-shared/src/stake_contract.rs +++ b/packages/shadeswap-shared/src/stake_contract.rs @@ -1,5 +1,6 @@ use cosmwasm_std::{Uint128, Addr}; use schemars::JsonSchema; +use crate::utils::asset::Contract; use serde::{Deserialize, Serialize}; use crate::{core::{ContractInstantiationInfo, TokenType}}; @@ -16,3 +17,10 @@ pub struct ClaimableInfo{ pub token_address: Addr, pub amount: Uint128 } + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct RewardTokenInfo{ + pub reward_token: Contract, + pub daily_reward_amount: Uint128, + pub valid_to: Uint128, +} diff --git a/packages/shadeswap-shared/src/utils/addr.rs b/packages/shadeswap-shared/src/utils/addr.rs new file mode 100644 index 0000000..7a3c831 --- /dev/null +++ b/packages/shadeswap-shared/src/utils/addr.rs @@ -0,0 +1,9 @@ +use cosmwasm_std::{StdResult, Addr}; + +pub fn try_addr_validate_option(api: &dyn cosmwasm_std::Api, addr: Option) -> StdResult> +{ + return match addr { + Some(a) => Ok(Some(api.addr_validate(&a)?)), + None => Ok(None), + }; +} \ No newline at end of file diff --git a/packages/shadeswap-shared/src/utils/mod.rs b/packages/shadeswap-shared/src/utils/mod.rs index d3713a7..c3c5d25 100644 --- a/packages/shadeswap-shared/src/utils/mod.rs +++ b/packages/shadeswap-shared/src/utils/mod.rs @@ -14,6 +14,8 @@ pub mod cycle; pub mod wrap; pub mod price; pub mod calc; +pub mod addr; +pub use addr::*; #[cfg(not(target_arch = "wasm32"))] pub mod testing; diff --git a/packages/shadeswap-shared/src/utils/padding.rs b/packages/shadeswap-shared/src/utils/padding.rs index e77a6e4..32d8ab7 100644 --- a/packages/shadeswap-shared/src/utils/padding.rs +++ b/packages/shadeswap-shared/src/utils/padding.rs @@ -19,7 +19,7 @@ pub fn space_pad(message: &mut Vec, block_size: usize) -> &mut Vec { // Users don't need to care about it as the type `T` has a default, and will // always be known in the context of the caller. pub fn pad_response_result(response: StdResult, block_size: usize) -> StdResult{ - response.map(|mut response| { + response.map(|mut response| { response.data = response.data.map(|mut data| { space_pad(&mut data.0, block_size); data