diff --git a/Cargo.lock b/Cargo.lock index a89d5ead..18ae0fd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ "getrandom", "once_cell", @@ -15,21 +15,21 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "base16ct" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -63,21 +63,21 @@ dependencies = [ [[package]] name = "bnum" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "845141a4fade3f790628b7daaaa298a25b204fb28907eb54febe5142db6ce653" +checksum = "128a44527fc0d6abf05f9eda748b9027536e12dff93f5acc8449f51583309350" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cfg-if" @@ -87,17 +87,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "const-oid" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "cosmwasm-crypto" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e272708a9745dad8b591ef8a718571512130f2b39b33e3d7a27c558e3069394" +checksum = "d8bb3c77c3b7ce472056968c745eb501c440fbc07be5004eba02782c35bfbbe3" dependencies = [ "digest 0.10.7", + "ecdsa", "ed25519-zebra", "k256", "rand_core 0.6.4", @@ -106,18 +107,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "296db6a3caca5283425ae0cf347f4e46999ba3f6620dbea8939a0e00347831ce" +checksum = "fea73e9162e6efde00018d55ed0061e93a108b5d6ec4548b4f8ce3c706249687" dependencies = [ "syn 1.0.109", ] [[package]] name = "cosmwasm-schema" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c337e097a089e5b52b5d914a7ff6613332777f38ea6d9d36e1887cd0baa72e" +checksum = "0df41ea55f2946b6b43579659eec048cc2f66e8c8e2e3652fc5e5e476f673856" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -128,9 +129,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "766cc9e7c1762d8fc9c0265808910fcad755200cd0e624195a491dd885a61169" +checksum = "43609e92ce1b9368aa951b334dd354a2d0dd4d484931a5f83ae10e12a26c8ba9" dependencies = [ "proc-macro2", "quote", @@ -139,11 +140,12 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5e05a95fd2a420cca50f4e94eb7e70648dac64db45e90403997ebefeb143bd" +checksum = "04d6864742e3a7662d024b51a94ea81c9af21db6faea2f9a6d2232bb97c6e53e" dependencies = [ "base64", + "bech32", "bnum", "cosmwasm-crypto", "cosmwasm-derive", @@ -153,15 +155,16 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", - "sha2 0.10.7", + "sha2 0.10.8", + "static_assertions", "thiserror", ] [[package]] name = "cosmwasm-storage" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "800aaddd70ba915e19bf3d2d992aa3689d8767857727fdd3b414df4fd52d2aa1" +checksum = "bd2b4ae72a03e8f56c85df59d172d51d2d7dc9cec6e2bc811e3fb60c588032a4" dependencies = [ "cosmwasm-std", "serde", @@ -169,18 +172,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] [[package]] name = "crypto-bigint" -version = "0.4.9" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -230,20 +233,20 @@ dependencies = [ [[package]] name = "cw-multi-test" -version = "0.16.5" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "127c7bb95853b8e828bdab97065c81cb5ddc20f7339180b61b2300565aaa99d1" +checksum = "579e2c2f2c0877b839c5cad85e67811074e854a50c1ff3085eb8290b1c27809c" dependencies = [ "anyhow", "cosmwasm-std", "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", + "cw-utils 1.0.2", "derivative", "itertools", - "k256", "prost", "schemars", "serde", + "sha2 0.10.8", "thiserror", ] @@ -258,7 +261,7 @@ dependencies = [ "cw-address-like", "cw-ownable-derive", "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", + "cw-utils 1.0.2", "thiserror", ] @@ -275,8 +278,8 @@ dependencies = [ [[package]] name = "cw-paginate-storage" -version = "2.2.0" -source = "git+https://github.com/DA0-DA0/dao-contracts.git#7f89ad1604e8022f202aef729853b0c8c7196988" +version = "2.3.0" +source = "git+https://github.com/DA0-DA0/dao-contracts.git#db42d45c097174572b55f789aa3908af591e7a29" dependencies = [ "cosmwasm-std", "cosmwasm-storage", @@ -291,7 +294,7 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", + "cw-utils 1.0.2", "thiserror", ] @@ -347,13 +350,13 @@ dependencies = [ [[package]] name = "cw-utils" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7" +checksum = "1b9f351a4e4d81ef7c890e44d903f8c0bdcdc00f094fd3a181eaf70c0eec7a3a" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw2 1.1.0", + "cw2 1.1.1", "schemars", "semver", "serde", @@ -375,9 +378,9 @@ dependencies = [ [[package]] name = "cw2" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ac2dc7a55ad64173ca1e0a46697c31b7a5c51342f55a1e84a724da4eb99908" +checksum = "9431d14f64f49e41c6ef5561ed11a5391c417d0cb16455dea8cdcb9037a8d197" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -408,7 +411,7 @@ checksum = "e3c4d286625ccadc957fe480dd3bdc54ada19e0e6b5b9325379db3130569e914" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-utils 1.0.1", + "cw-utils 1.0.2", "schemars", "serde", ] @@ -440,8 +443,8 @@ dependencies = [ "cosmwasm-std", "cw-ownable", "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.1.0", + "cw-utils 1.0.2", + "cw2 1.1.1", "cw721 0.18.0", "cw721-base 0.16.0", "schemars", @@ -482,7 +485,7 @@ dependencies = [ "cosmwasm-std", "cw-rate-limiter", "cw-storage-plus 1.1.0", - "cw2 1.1.0", + "cw2 1.1.1", "cw721 0.18.0", "cw721-proxy", "cw721-proxy-derive", @@ -497,16 +500,16 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus 1.1.0", - "cw2 1.1.0", + "cw2 1.1.1", "cw721-base 0.18.0", "thiserror", ] [[package]] name = "der" -version = "0.6.1" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ "const-oid", "zeroize", @@ -539,26 +542,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] [[package]] name = "dyn-clone" -version = "1.0.12" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "ecdsa" -version = "0.14.8" +version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ "der", + "digest 0.10.7", "elliptic-curve", "rfc6979", "signature", + "spki", ] [[package]] @@ -584,13 +590,12 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" -version = "0.12.3" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" dependencies = [ "base16ct", "crypto-bigint", - "der", "digest 0.10.7", "ff", "generic-array", @@ -604,9 +609,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core 0.6.4", "subtle", @@ -635,13 +640,14 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -650,9 +656,9 @@ dependencies = [ [[package]] name = "group" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", @@ -697,8 +703,8 @@ dependencies = [ "cw-paginate-storage", "cw-pause-once", "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.1.0", + "cw-utils 1.0.2", + "cw2 1.1.1", "cw721 0.16.0", "cw721 0.18.0", "cw721-base 0.16.0", @@ -706,6 +712,7 @@ dependencies = [ "cw721-proxy-derive", "cw721-rate-limited-proxy", "serde", + "sha2 0.10.8", "thiserror", "zip-optional", ] @@ -715,7 +722,7 @@ name = "ics721-base" version = "0.1.0" dependencies = [ "cosmwasm-std", - "cw2 1.1.0", + "cw2 1.1.1", "ics721", ] @@ -727,7 +734,7 @@ dependencies = [ "cosmwasm-std", "cosmwasm-storage", "cw-storage-plus 1.1.0", - "cw2 1.1.0", + "cw2 1.1.1", "ics721", "thiserror", ] @@ -744,9 +751,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -759,21 +766,23 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "k256" -version = "0.11.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "sha2 0.10.7", + "once_cell", + "sha2 0.10.8", + "signature", ] [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "once_cell" @@ -795,9 +804,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pkcs8" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", @@ -805,18 +814,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.9.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d" dependencies = [ "bytes", "prost-derive", @@ -824,22 +833,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.9.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -861,13 +870,12 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "crypto-bigint", "hmac", - "zeroize", + "subtle", ] [[package]] @@ -878,9 +886,9 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "schemars" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c" dependencies = [ "dyn-clone", "schemars_derive", @@ -890,9 +898,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c" dependencies = [ "proc-macro2", "quote", @@ -902,9 +910,9 @@ dependencies = [ [[package]] name = "sec1" -version = "0.3.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", @@ -916,15 +924,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.183" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] @@ -940,13 +948,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.183" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -962,9 +970,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -983,42 +991,26 @@ dependencies = [ "cw-multi-test", "cw-pause-once", "cw-storage-plus 1.1.0", - "cw2 1.1.0", + "cw2 1.1.1", "cw721 0.18.0", "cw721-base 0.18.0", "cw721-rate-limited-proxy", "ics721", - "sg-std 3.1.0", - "sg721 2.4.0", - "sg721 3.1.0", - "sg721-base 2.4.0", - "sg721-base 3.1.0", -] - -[[package]] -name = "sg-std" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc9b4ab6090f777940d3277632b1a3fff89f5a52191443a19da7cd99e3845041" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-utils 0.16.0", - "cw721 0.16.0", - "schemars", - "serde", - "thiserror", + "sg-std", + "sg721", + "sg721-base", + "sha2 0.10.8", ] [[package]] name = "sg-std" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171f97d3032b7d713dd16decaed06479e7ce5585147f387860ad2fb3f7b9ed94" +checksum = "4db53aebc2b4f981dc20a51213544adde8beaace6880345627f4babe2e1bc3ab" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-utils 1.0.1", + "cw-utils 1.0.2", "cw721 0.18.0", "schemars", "serde", @@ -1027,28 +1019,14 @@ dependencies = [ [[package]] name = "sg721" -version = "2.4.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37ea61753635e1de01a16947784ddd5ba8e256fa403be6246b2d88578914fb2" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-utils 0.16.0", - "cw721-base 0.16.0", - "serde", - "thiserror", -] - -[[package]] -name = "sg721" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e7d8f93b519c4c95973a68c7abee2de838497974d666dddb4dabd04d9c7cbf6" +checksum = "65af43465c79bc5a2af7b41a526876cd757a6ba2a9051bbeb2f95133285f89dc" dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-ownable", - "cw-utils 1.0.1", + "cw-utils 1.0.2", "cw721-base 0.18.0", "serde", "thiserror", @@ -1056,41 +1034,21 @@ dependencies = [ [[package]] name = "sg721-base" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b81900474a5a2a6cf25e70720d62a565abc56caa1fe3613cfd15157c63dfb89" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus 0.16.0", - "cw-utils 0.16.0", - "cw2 0.16.0", - "cw721 0.16.0", - "cw721-base 0.16.0", - "serde", - "sg-std 2.4.0", - "sg721 2.4.0", - "thiserror", - "url", -] - -[[package]] -name = "sg721-base" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af08801d6f50cb13be05a3d2e815fbdb9dbba82086bbab877599ed4d422e9441" +checksum = "bcaffbe4a8d278a54c3ac4dcce30aa971cd55bce8184b43b6344a45cff9eea48" dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-ownable", "cw-storage-plus 1.1.0", - "cw-utils 1.0.1", - "cw2 1.1.0", + "cw-utils 1.0.2", + "cw2 1.1.1", "cw721 0.18.0", "cw721-base 0.18.0", "serde", - "sg-std 3.1.0", - "sg721 3.1.0", + "sg-std", + "sg721", "thiserror", "url", ] @@ -1110,9 +1068,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1121,9 +1079,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -1131,14 +1089,20 @@ dependencies = [ [[package]] name = "spki" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", "der", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "subtle" version = "2.5.0" @@ -1158,9 +1122,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -1169,22 +1133,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -1204,9 +1168,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" @@ -1216,9 +1180,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" diff --git a/Cargo.toml b/Cargo.toml index 26692e5a..2a8f4f1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,17 +22,16 @@ cw721-base = "0.18" cw721-base-016 = { version = "0.16.0", package = "cw721-base" } cw721-proxy-derive = { git = "https://github.com/arkprotocol/cw721-proxy.git", tag = "v0.0.7" } cw721-rate-limited-proxy = { git = "https://github.com/arkprotocol/cw721-proxy.git", tag = "v0.0.7" } -cw-multi-test = "0.16" +cw-multi-test = { version = "0.18", features = ["cosmwasm_1_2"] } cw-utils = "1.0" +sha2 = "^0.10" serde = "1.0" thiserror = "1" # Stargaze libs -sg-std = "3.0" +sg-std = "^3.2" sg-multi-test = "^3.1" sg721 = "^3.1" -sg721-240 = { version = "^2.4", package = "sg721" } sg721-base = "^3.1" -sg721-base-240 = { version = "^2.4", package = "sg721-base" } # packages and contracts cw-cii = { path = "./packages/cw-cii" } cw-pause-once = { path = "./packages/cw-pause-once" } diff --git a/contracts/ics721-base-tester/src/ack.rs b/contracts/ics721-base-tester/src/ack.rs index d9d5a2cd..e16b2a4c 100644 --- a/contracts/ics721-base-tester/src/ack.rs +++ b/contracts/ics721-base-tester/src/ack.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{to_binary, Binary}; +use cosmwasm_std::{to_json_binary, Binary}; /// IBC ACK. See: /// https://github.com/cosmos/cosmos-sdk/blob/f999b1ff05a4db4a338a855713864497bedd4396/proto/ibc/core/channel/v1/channel.proto#L141-L147 @@ -11,10 +11,10 @@ pub enum Ack { pub fn make_ack_success() -> Binary { let res = Ack::Result(b"1".into()); - to_binary(&res).unwrap() + to_json_binary(&res).unwrap() } pub fn make_ack_fail(err: String) -> Binary { let res = Ack::Error(err); - to_binary(&res).unwrap() + to_json_binary(&res).unwrap() } diff --git a/contracts/ics721-base-tester/src/contract.rs b/contracts/ics721-base-tester/src/contract.rs index fa6f9486..e5b7c023 100644 --- a/contracts/ics721-base-tester/src/contract.rs +++ b/contracts/ics721-base-tester/src/contract.rs @@ -1,7 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_binary, Binary, Deps, DepsMut, Env, IbcMsg, IbcTimeout, MessageInfo, Response, StdResult, + to_json_binary, Binary, Deps, DepsMut, Env, IbcMsg, IbcTimeout, MessageInfo, Response, + StdResult, }; use cw2::set_contract_version; use ics721::ibc::NonFungibleTokenPacketData; @@ -54,7 +55,7 @@ fn execute_send_packet( .add_attribute("method", "send_packet") .add_message(IbcMsg::SendPacket { channel_id, - data: to_binary(&data)?, + data: to_json_binary(&data)?, timeout, })) } @@ -71,7 +72,7 @@ fn execute_set_ack_mode(deps: DepsMut, ack_mode: AckMode) -> Result StdResult { match msg { - QueryMsg::AckMode {} => to_binary(&ACK_MODE.load(deps.storage)?), - QueryMsg::LastAck {} => to_binary(&LAST_ACK.load(deps.storage)?), + QueryMsg::AckMode {} => to_json_binary(&ACK_MODE.load(deps.storage)?), + QueryMsg::LastAck {} => to_json_binary(&LAST_ACK.load(deps.storage)?), } } diff --git a/contracts/ics721-base/src/lib.rs b/contracts/ics721-base/src/lib.rs index d20fd7f9..2e383748 100644 --- a/contracts/ics721-base/src/lib.rs +++ b/contracts/ics721-base/src/lib.rs @@ -8,11 +8,11 @@ use cosmwasm_std::entry_point; use cosmwasm_std::{ Binary, Deps, DepsMut, Env, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcPacketAckMsg, IbcPacketReceiveMsg, - IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Reply, Response, StdResult, + IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Never, Reply, Response, StdResult, }; use cw2::set_contract_version; use ics721::{ - error::{ContractError, Never}, + error::ContractError, execute::Ics721Execute, ibc::Ics721Ibc, msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, diff --git a/contracts/sg-ics721/Cargo.toml b/contracts/sg-ics721/Cargo.toml index 635146af..3bf2602e 100644 --- a/contracts/sg-ics721/Cargo.toml +++ b/contracts/sg-ics721/Cargo.toml @@ -32,5 +32,4 @@ cw-storage-plus = { workspace = true } cw721 = { workspace = true} cw721-rate-limited-proxy = { workspace = true } cw721-base = { workspace = true} -sg721-240 = { workspace = true} -sg721-base-240 = { workspace = true, features = ["library"] } +sha2 = { workspace = true } diff --git a/contracts/sg-ics721/src/execute.rs b/contracts/sg-ics721/src/execute.rs index fb7a7cba..b4ce4d6e 100644 --- a/contracts/sg-ics721/src/execute.rs +++ b/contracts/sg-ics721/src/execute.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{from_binary, to_binary, Addr, Binary, Deps, DepsMut, Env, StdResult}; +use cosmwasm_std::{from_json, to_json_binary, Addr, Binary, Deps, DepsMut, Env, StdResult}; use ics721::{ execute::Ics721Execute, state::CollectionData, @@ -36,38 +36,18 @@ impl Ics721Execute for SgIcs721Contract { } fn init_msg(&self, deps: Deps, env: &Env, class: &Class) -> StdResult { - let creator = match class.data.clone() { - None => { - // in case no class data is provided (e.g. due to nft-transfer module), ics721 creator is used. - let contract_info = deps - .querier - .query_wasm_contract_info(env.contract.address.to_string())?; - contract_info.creator - } - Some(data) => { - // class data may be any custom type. Check whether it is `ics721::state::CollectionData` or not. - let class_data_result: StdResult = from_binary(&data); - if class_data_result.is_err() { - // this happens only for unknown class data, like source chain uses nft-transfer module - env.contract.address.to_string() - } else { - let class_data = class_data_result?; - - match class_data.owner { - Some(owner) => convert_owner_chain_address(env, owner.as_str())?, - None => env.contract.address.to_string(), - } - } - } - }; - to_binary(&sg721::InstantiateMsg { - // Name of the collection MUST be class_id as this is how - // we create a map entry on reply. + // ics721 creator is used, in case no source owner in class data is provided (e.g. due to nft-transfer module). + let ics721_contract_info = deps + .querier + .query_wasm_contract_info(env.contract.address.to_string())?; + let mut instantiate_msg = sg721::InstantiateMsg { + // source chain may not send optional collection data + // if not, by default class id is used for name and symbol name: class.id.clone().into(), symbol: class.id.clone().into(), minter: env.contract.address.to_string(), collection_info: sg721::CollectionInfo { - creator, + creator: ics721_contract_info.creator, description: "".to_string(), image: "https://arkprotocol.io".to_string(), external_link: None, @@ -75,6 +55,35 @@ impl Ics721Execute for SgIcs721Contract { start_trading_time: None, royalty_info: None, }, - }) + }; + + // unwrapped to collection data and in case of success, set creator, name and symbol + if let Some(binary) = class.data.clone() { + let class_data_result: StdResult = from_json(binary); + if class_data_result.is_ok() { + let class_data = class_data_result?; + match class_data.owner { + Some(owner) => + // owner from source chain is used + { + instantiate_msg.collection_info.creator = + convert_owner_chain_address(env, owner.as_str())? + } + None => + // ics721 creator is used, in case of none + { + let ics721_contract_info = deps + .querier + .query_wasm_contract_info(env.contract.address.to_string())?; + instantiate_msg.collection_info.creator = ics721_contract_info.creator; + } + } + // set name and symbol + instantiate_msg.symbol = class_data.symbol; + instantiate_msg.name = class_data.name; + } + } + + to_json_binary(&instantiate_msg) } } diff --git a/contracts/sg-ics721/src/lib.rs b/contracts/sg-ics721/src/lib.rs index f129c10e..91ffdf59 100644 --- a/contracts/sg-ics721/src/lib.rs +++ b/contracts/sg-ics721/src/lib.rs @@ -8,11 +8,11 @@ use cosmwasm_std::entry_point; use cosmwasm_std::{ Binary, Deps, DepsMut, Env, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcPacketAckMsg, IbcPacketReceiveMsg, - IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Reply, Response, StdResult, + IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Never, Reply, Response, StdResult, }; use cw2::set_contract_version; use ics721::{ - error::{ContractError, Never}, + error::ContractError, execute::Ics721Execute, ibc::Ics721Ibc, msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, diff --git a/contracts/sg-ics721/src/testing/integration_tests.rs b/contracts/sg-ics721/src/testing/integration_tests.rs index 3aa0e4aa..376261d9 100644 --- a/contracts/sg-ics721/src/testing/integration_tests.rs +++ b/contracts/sg-ics721/src/testing/integration_tests.rs @@ -1,10 +1,10 @@ -use bech32::Variant; +use anyhow::Result; +use bech32::{decode, encode, FromBase32, ToBase32, Variant}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - from_binary, - testing::{mock_env, MockApi}, - to_binary, Addr, Api, Binary, Deps, DepsMut, Empty, Env, GovMsg, IbcTimeout, IbcTimeoutBlock, - MemoryStorage, MessageInfo, Reply, Response, StdResult, Storage, WasmMsg, + from_json, instantiate2_address, to_json_binary, Addr, Api, Binary, CanonicalAddr, Deps, + DepsMut, Empty, Env, GovMsg, IbcTimeout, IbcTimeoutBlock, MemoryStorage, MessageInfo, + RecoverPubkeyError, Reply, Response, StdError, StdResult, Storage, VerificationError, WasmMsg, }; use cw2::set_contract_version; use cw721_base::msg::QueryMsg as Cw721QueryMsg; @@ -14,7 +14,6 @@ use cw_multi_test::{ Executor, FailingModule, IbcAcceptingModule, Router, StakeKeeper, WasmKeeper, }; use cw_pause_once::PauseError; -use cw_storage_plus::Item; use ics721::{ execute::Ics721Execute, ibc::Ics721Ibc, @@ -25,6 +24,7 @@ use ics721::{ }; use sg721::InstantiateMsg as Sg721InstantiateMsg; use sg721_base::msg::{CollectionInfoResponse, QueryMsg as Sg721QueryMsg}; +use sha2::{digest::Update, Digest, Sha256}; use crate::{state::SgCollectionData, ContractError, SgIcs721Contract}; @@ -32,8 +32,14 @@ const ICS721_CREATOR: &str = "ics721-creator"; const CONTRACT_NAME: &str = "crates.io:sg-ics721"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -const OWNER_SOURCE_CHAIN: &str = "juno1ke55z7catvdvnhvyyh0pkvs30t09me72vcxkh5"; -const TARGET_HRP: &str = "stars"; +// owner, aka "minter" +const COLLECTION_OWNER_TARGET_CHAIN: &str = "collection-minter-target-chain"; +const COLLECTION_OWNER_SOURCE_CHAIN: &str = "collection-minter-source-chain"; +const COLLECTION_CONTRACT_SOURCE_CHAIN: &str = "collection-contract-source-chain"; +const CHANNEL_TARGET_CHAIN: &str = "channel-1"; +const BECH32_PREFIX_HRP: &str = "stars"; +const NFT_OWNER_TARGET_CHAIN: &str = "nft-owner-target-chain"; +const ICS721_ADMIN_AND_PAUSER: &str = "ics721-pauser"; // copy of cosmwasm_std::ContractInfoResponse (marked as non-exhaustive) #[cw_serde] @@ -91,42 +97,162 @@ fn no_init( ) { } -#[derive(Debug)] -struct Bech32AddressGenerator { - pub hrp: String, +#[derive(Default)] +pub struct MockAddressGenerator; + +impl AddressGenerator for MockAddressGenerator { + fn contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + code_id: u64, + instance_id: u64, + ) -> Result { + let canonical_addr = Self::instantiate_address(code_id, instance_id); + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } + + fn predictable_contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + _code_id: u64, + _instance_id: u64, + checksum: &[u8], + creator: &CanonicalAddr, + salt: &[u8], + ) -> Result { + let canonical_addr = instantiate2_address(checksum, creator, salt)?; + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } } -const COUNT: Item = Item::new("count"); +impl MockAddressGenerator { + // non-predictable contract address generator, see `BuildContractAddressClassic` + // implementation in wasmd: https://github.com/CosmWasm/wasmd/blob/main/x/wasm/keeper/addresses.go#L35-L42 + fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { + let mut key = Vec::::new(); + key.extend_from_slice(b"wasm\0"); + key.extend_from_slice(&code_id.to_be_bytes()); + key.extend_from_slice(&instance_id.to_be_bytes()); + let module = Sha256::digest("module".as_bytes()); + let result = Sha256::new() + .chain(module) + .chain(key) + .finalize() + .to_vec() + .into(); + return result; + } +} +pub struct MockApiBech32 { + prefix: &'static str, +} -impl Bech32AddressGenerator { - pub const fn new(hrp: String) -> Self { - Self { hrp } +impl MockApiBech32 { + pub fn new(prefix: &'static str) -> Self { + Self { prefix } } } -#[cw_serde] -pub struct CustomClassData { - pub foo: Option, +impl Api for MockApiBech32 { + fn addr_validate(&self, input: &str) -> StdResult { + let canonical = self.addr_canonicalize(input)?; + let normalized = self.addr_humanize(&canonical)?; + if input != normalized { + Err(StdError::generic_err( + "Invalid input: address not normalized", + )) + } else { + Ok(Addr::unchecked(input)) + } + } + + fn addr_canonicalize(&self, input: &str) -> StdResult { + if let Ok((prefix, decoded, Variant::Bech32)) = decode(input) { + if prefix == self.prefix { + if let Ok(bytes) = Vec::::from_base32(&decoded) { + return Ok(bytes.into()); + } + } + } + Err(StdError::generic_err(format!("Invalid input: {}", input))) + } + + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + if let Ok(encoded) = encode( + self.prefix, + canonical.as_slice().to_base32(), + Variant::Bech32, + ) { + Ok(Addr::unchecked(encoded)) + } else { + Err(StdError::generic_err("Invalid canonical address")) + } + } + + fn secp256k1_verify( + &self, + _message_hash: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn secp256k1_recover_pubkey( + &self, + _message_hash: &[u8], + _signature: &[u8], + _recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + unimplemented!() + } + + fn ed25519_verify( + &self, + _message: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn ed25519_batch_verify( + &self, + _messages: &[&[u8]], + _signatures: &[&[u8]], + _public_keys: &[&[u8]], + ) -> Result { + unimplemented!() + } + + fn debug(&self, _message: &str) { + unimplemented!() + } } -impl AddressGenerator for Bech32AddressGenerator { - fn next_address(&self, storage: &mut dyn Storage) -> Addr { - let count = match COUNT.may_load(storage) { - Ok(Some(count)) => count, - _ => 0, - }; - let data = bech32::u5::try_from_u8(count).unwrap(); - let encoded_addr = bech32::encode(self.hrp.as_str(), vec![data], Variant::Bech32).unwrap(); - let addr = Addr::unchecked(encoded_addr); - COUNT.save(storage, &(count + 1)).unwrap(); - addr +impl MockApiBech32 { + pub fn addr_make(&self, input: &str) -> Addr { + let digest = Sha256::digest(input).to_vec(); + match encode(self.prefix, digest.to_base32(), Variant::Bech32) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {reason}"), + } } } +#[cw_serde] +pub struct CustomClassData { + pub foo: Option, + // even there is collection name, but it doesn't apply to CollectionData type + pub name: String, +} + struct Test { app: App< BankKeeper, - MockApi, + MockApiBech32, MemoryStorage, FailingModule, WasmKeeper, @@ -134,25 +260,30 @@ struct Test { DistributionKeeper, IbcAcceptingModule, >, - minter: Addr, - cw721_id: u64, - cw721: Addr, + // origin cw721 contract on source chain for interchain transfers to other target chains + source_cw721_owner: Addr, + source_cw721_id: u64, + source_cw721: Addr, + // depending on test cast, it is ics721 either source or target chain ics721_id: u64, ics721: Addr, nfts_minted: usize, } impl Test { - fn new(proxy: bool, pauser: Option, cw721_code: Box>) -> Self { + fn new( + proxy: bool, + admin_and_pauser: Option, + cw721_code: Box>, + ) -> Self { let mut app = AppBuilder::new() - .with_wasm::, WasmKeeper>( - WasmKeeper::new_with_custom_address_generator(Bech32AddressGenerator::new( - TARGET_HRP.to_string(), - )), + .with_wasm::>( + WasmKeeper::new().with_address_generator(MockAddressGenerator), ) - .with_ibc(IbcAcceptingModule) + .with_ibc(IbcAcceptingModule::default()) + .with_api(MockApiBech32::new(BECH32_PREFIX_HRP)) .build(no_init); - let cw721_id = app.store_code(cw721_code); + let source_cw721_id = app.store_code(cw721_code); let ics721_id = app.store_code(ics721_contract()); use cw721_rate_limited_proxy as rlp; @@ -161,7 +292,7 @@ impl Test { let proxy_id = app.store_code(proxy_contract()); Some(ContractInstantiateInfo { code_id: proxy_id, - msg: to_binary(&rlp::msg::InstantiateMsg { + msg: to_json_binary(&rlp::msg::InstantiateMsg { rate_limit: rlp::Rate::PerBlock(10), origin: None, }) @@ -176,30 +307,34 @@ impl Test { let ics721 = app .instantiate_contract( ics721_id, - Addr::unchecked(ICS721_CREATOR), + app.api().addr_make(ICS721_CREATOR), &InstantiateMsg { - cw721_base_code_id: cw721_id, + cw721_base_code_id: source_cw721_id, proxy: proxy.clone(), - pauser: pauser.clone(), + pauser: admin_and_pauser + .clone() + .and_then(|p| Some(app.api().addr_make(&p).to_string())), }, &[], "sg-ics721", - pauser.clone(), + admin_and_pauser + .clone() + .and_then(|p| Some(app.api().addr_make(&p).to_string())), ) .unwrap(); // minter of sg721-base must be a contract! - let minter = ics721.clone(); - let cw721 = app + let source_cw721_owner = ics721.clone(); + let source_cw721 = app .instantiate_contract( - cw721_id, - minter.clone(), + source_cw721_id, + source_cw721_owner.clone(), &Sg721InstantiateMsg { name: "name".to_string(), symbol: "symbol".to_string(), - minter: minter.to_string(), + minter: source_cw721_owner.to_string(), collection_info: sg721::CollectionInfo { - creator: minter.to_string(), + creator: source_cw721_owner.to_string(), description: "".to_string(), image: "https://arkprotocol.io".to_string(), external_link: None, @@ -216,9 +351,9 @@ impl Test { Self { app, - minter, - cw721_id, - cw721, + source_cw721_owner, + source_cw721_id, + source_cw721, ics721_id, ics721, nfts_minted: 0, @@ -321,8 +456,8 @@ impl Test { self.app .execute_contract( - self.minter.clone(), - self.cw721.clone(), + self.source_cw721_owner.clone(), + self.source_cw721.clone(), &cw721_base::msg::ExecuteMsg::::Mint { token_id: self.nfts_minted.to_string(), owner: owner.to_string(), @@ -361,38 +496,10 @@ fn sg721_base_contract() -> Box> { Box::new(contract) } -fn sg721_v240_base_contract() -> Box> { - // sg721_base's execute and instantiate function deals Response - // but App multi test deals Response - // so we need to wrap sg721_base's execute and instantiate function - fn exececute_fn( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: sg721_240::ExecuteMsg, Empty>, - ) -> Result { - sg721_base_240::entry::execute(deps, env, info, msg) - .and_then(|_| Ok::(Response::default())) - } - fn instantiate_fn( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: sg721_240::InstantiateMsg, - ) -> Result { - sg721_base_240::entry::instantiate(deps, env, info, msg) - .and_then(|_| Ok::(Response::default())) - } - let contract = ContractWrapper::new(exececute_fn, instantiate_fn, sg721_base_240::entry::query); - Box::new(contract) -} - fn ics721_contract() -> Box> { // need to wrap method in function for testing fn ibc_reply(deps: DepsMut, env: Env, reply: Reply) -> Result { - SgIcs721Contract::default() - .reply(deps, env, reply) - .and_then(|_| Ok(Response::default())) + SgIcs721Contract::default().reply(deps, env, reply) } let contract = ContractWrapper::new(execute, instantiate, query) @@ -418,7 +525,7 @@ fn test_instantiate() { // check stores are properly initialized let cw721_id = test.query_cw721_id(); - assert_eq!(cw721_id, test.cw721_id); + assert_eq!(cw721_id, test.source_cw721_id); let nft_contracts: Vec<(String, Addr)> = test.query_nft_contracts(); assert_eq!(nft_contracts, Vec::<(String, Addr)>::new()); let outgoing_channels = test.query_outgoing_channels(); @@ -430,21 +537,32 @@ fn test_instantiate() { #[test] fn test_do_instantiate_and_mint_weird_data() { let mut test = Test::new(false, None, sg721_base_contract()); - + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), - test.ics721.clone(), + test.ics721, &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "mr-t".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id), uri: None, data: Some( // data comes from source chain, so it can't be SgCollectionData - to_binary(&CollectionData { - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + // incoming collection data from source chain + owner: Some( + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), name: "name".to_string(), symbol: "symbol".to_string(), @@ -468,19 +586,24 @@ fn test_do_instantiate_and_mint_weird_data() { #[test] fn test_do_instantiate_and_mint() { - // test case: instantiate cw721 with no ClassData + // test case: instantiate cw721 with no ClassData (without owner, name, and symbol) { let mut test = Test::new(false, None, sg721_base_contract()); - + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "mr-t".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), data: None, // no class data }, @@ -492,7 +615,7 @@ fn test_do_instantiate_and_mint() { }, Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }, ], @@ -504,30 +627,33 @@ fn test_do_instantiate_and_mint() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let nft_contracts = test.query_nft_contracts(); assert_eq!(nft_contracts.len(), 1); - assert_eq!(nft_contracts[0].0, "bad kids"); + assert_eq!(nft_contracts[0].0, class_id.to_string()); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( test.ics721.clone(), &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - // check contract info is properly set + // check name and symbol contains class id for instantiated nft contract let contract_info: cw721::ContractInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Cw721QueryMsg::::ContractInfo {}) + .query_wasm_smart( + nft_contract.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) .unwrap(); assert_eq!( contract_info, cw721::ContractInfoResponse { - name: "bad kids".to_string(), - symbol: "bad kids".to_string() + name: class_id.to_string(), // name is set to class_id + symbol: class_id.to_string() // symbol is set to class_id } ); @@ -535,14 +661,14 @@ fn test_do_instantiate_and_mint() { let collection_info: CollectionInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Sg721QueryMsg::CollectionInfo {}) + .query_wasm_smart(nft_contract.clone(), &Sg721QueryMsg::CollectionInfo {}) .unwrap(); assert_eq!( collection_info, CollectionInfoResponse { // creator of ics721 contract is also creator of collection, since no owner in ClassData provided - creator: ICS721_CREATOR.to_string(), + creator: test.app.api().addr_make(ICS721_CREATOR).to_string(), description: "".to_string(), image: "https://arkprotocol.io".to_string(), external_link: None, @@ -557,13 +683,12 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "1".to_string(), }, ) .unwrap(); - assert_eq!( token_info.token_uri, Some("https://moonphase.is/image.svg".to_string()) @@ -572,31 +697,28 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "2".to_string(), }, ) .unwrap(); + assert_eq!(token_info.token_uri, Some("https://foo.bar".to_string())); - assert_eq!( - token_info.token_uri, - Some("https://moonphase.is/image.svg".to_string()) - ); - - // Check that we can transfer the NFT via the ICS721 interface. + // After transfer to target, test owner can do any action, like transfer, on collection test.app .execute_contract( - Addr::unchecked("mr-t"), - nft.clone(), + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract.clone(), &cw721_base::msg::ExecuteMsg::::TransferNft { - recipient: nft.to_string(), + recipient: nft_contract.to_string(), token_id: "1".to_string(), }, &[], ) .unwrap(); + // ics721 owner query and check nft contract owns it let owner: cw721::OwnerOfResponse = test .app .wrap() @@ -604,51 +726,58 @@ fn test_do_instantiate_and_mint() { test.ics721, &QueryMsg::Owner { token_id: "1".to_string(), - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); + assert_eq!(owner.owner, nft_contract.to_string()); - assert_eq!(owner.owner, nft.to_string()); - - // Check that this state matches the state of the underlying - // cw721. + // check cw721 owner query matches ics721 owner query let base_owner: cw721::OwnerOfResponse = test .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::OwnerOf { token_id: "1".to_string(), include_expired: None, }, ) .unwrap(); - assert_eq!(base_owner, owner); } - // test case: instantiate cw721 with ClassData containing owner + // test case: instantiate cw721 with ClassData containing owner, name, and symbol { let mut test = Test::new(false, None, sg721_base_contract()); - + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "mr-t".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), data: Some( // data comes from source chain, so it can't be SgCollectionData - to_binary(&CollectionData { - // owner as defined by collection in source chain - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + owner: Some( + // incoming collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), - name: "name".to_string(), - symbol: "symbol".to_string(), + name: "ark".to_string(), + symbol: "protocol".to_string(), num_tokens: 1, }) .unwrap(), @@ -662,7 +791,7 @@ fn test_do_instantiate_and_mint() { }, Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }, ], @@ -674,30 +803,33 @@ fn test_do_instantiate_and_mint() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let nft_contracts = test.query_nft_contracts(); assert_eq!(nft_contracts.len(), 1); - assert_eq!(nft_contracts[0].0, "bad kids"); + assert_eq!(nft_contracts[0].0, class_id.to_string()); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( test.ics721.clone(), &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - // check contract info is properly set + // check name and symbol is using class data for instantiated nft contract let contract_info: cw721::ContractInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Cw721QueryMsg::::ContractInfo {}) + .query_wasm_smart( + nft_contract.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) .unwrap(); assert_eq!( contract_info, cw721::ContractInfoResponse { - name: "bad kids".to_string(), - symbol: "bad kids".to_string() + name: "ark".to_string(), + symbol: "protocol".to_string() } ); @@ -705,11 +837,16 @@ fn test_do_instantiate_and_mint() { let collection_info: CollectionInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Sg721QueryMsg::CollectionInfo {}) + .query_wasm_smart(nft_contract.clone(), &Sg721QueryMsg::CollectionInfo {}) .unwrap(); - let (_source_hrp, source_data, source_variant) = - bech32::decode(OWNER_SOURCE_CHAIN).unwrap(); - let target_owner = bech32::encode(TARGET_HRP, source_data, source_variant).unwrap(); + let (_source_hrp, source_data, source_variant) = bech32::decode( + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .as_str(), + ) + .unwrap(); + let target_owner = bech32::encode(BECH32_PREFIX_HRP, source_data, source_variant).unwrap(); assert_eq!( collection_info, @@ -730,13 +867,12 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "1".to_string(), }, ) .unwrap(); - assert_eq!( token_info.token_uri, Some("https://moonphase.is/image.svg".to_string()) @@ -745,31 +881,28 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "2".to_string(), }, ) .unwrap(); + assert_eq!(token_info.token_uri, Some("https://foo.bar".to_string())); - assert_eq!( - token_info.token_uri, - Some("https://moonphase.is/image.svg".to_string()) - ); - - // Check that we can transfer the NFT via the ICS721 interface. + // After transfer to target, test owner can do any action, like transfer, on collection test.app .execute_contract( - Addr::unchecked("mr-t"), - nft.clone(), + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract.clone(), // new recipient &cw721_base::msg::ExecuteMsg::::TransferNft { - recipient: nft.to_string(), + recipient: nft_contract.to_string(), token_id: "1".to_string(), }, &[], ) .unwrap(); + // ics721 owner query and check nft contract owns it let owner: cw721::OwnerOfResponse = test .app .wrap() @@ -777,47 +910,56 @@ fn test_do_instantiate_and_mint() { test.ics721, &QueryMsg::Owner { token_id: "1".to_string(), - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); + assert_eq!(owner.owner, nft_contract.to_string()); - assert_eq!(owner.owner, nft.to_string()); - - // Check that this state matches the state of the underlying - // cw721. + // check cw721 owner query matches ics721 owner query let base_owner: cw721::OwnerOfResponse = test .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::OwnerOf { token_id: "1".to_string(), include_expired: None, }, ) .unwrap(); - assert_eq!(base_owner, owner); } - // test case: instantiate cw721 with different CustomClassData with no owner info + // test case: instantiate cw721 with CustomClassData (without owner, name, and symbol) { let mut test = Test::new(false, None, sg721_base_contract()); - + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "mr-t".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), - // CustomClassData with no owner info data: Some( - to_binary(&CustomClassData { - foo: Some(OWNER_SOURCE_CHAIN.to_string()), + // CustomClassData doesn't apply to CollectionData type and won't be considered + // collection name wont be transferred to instantiated nft contract + to_json_binary(&CustomClassData { + foo: Some( + test.app + .api() + .addr_make(COLLECTION_OWNER_TARGET_CHAIN) + .to_string(), + ), + name: "colection-name".to_string(), }) .unwrap(), ), @@ -830,7 +972,7 @@ fn test_do_instantiate_and_mint() { }, Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }, ], @@ -842,30 +984,33 @@ fn test_do_instantiate_and_mint() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let nft_contracts = test.query_nft_contracts(); assert_eq!(nft_contracts.len(), 1); - assert_eq!(nft_contracts[0].0, "bad kids"); + assert_eq!(nft_contracts[0].0, class_id.to_string()); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( test.ics721.clone(), &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - // check contract info is properly set + // check name and symbol contains class id for instantiated nft contract let contract_info: cw721::ContractInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Cw721QueryMsg::::ContractInfo {}) + .query_wasm_smart( + nft_contract.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) .unwrap(); assert_eq!( contract_info, cw721::ContractInfoResponse { - name: "bad kids".to_string(), - symbol: "bad kids".to_string() + name: class_id.to_string(), + symbol: class_id.to_string() } ); @@ -873,14 +1018,14 @@ fn test_do_instantiate_and_mint() { let collection_info: CollectionInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Sg721QueryMsg::CollectionInfo {}) + .query_wasm_smart(nft_contract.clone(), &Sg721QueryMsg::CollectionInfo {}) .unwrap(); assert_eq!( collection_info, CollectionInfoResponse { - // creator is ics721 contract, since no owner in ClassData provided - creator: test.ics721.to_string(), + // creator of ics721 contract is creator of nft contract, since no owner in ClassData provided + creator: test.app.api().addr_make(ICS721_CREATOR).to_string(), description: "".to_string(), image: "https://arkprotocol.io".to_string(), external_link: None, @@ -895,13 +1040,12 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "1".to_string(), }, ) .unwrap(); - assert_eq!( token_info.token_uri, Some("https://moonphase.is/image.svg".to_string()) @@ -910,31 +1054,28 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "2".to_string(), }, ) .unwrap(); + assert_eq!(token_info.token_uri, Some("https://foo.bar".to_string())); - assert_eq!( - token_info.token_uri, - Some("https://moonphase.is/image.svg".to_string()) - ); - - // Check that we can transfer the NFT via the ICS721 interface. + // After transfer to target, test owner can do any action, like transfer, on collection test.app .execute_contract( - Addr::unchecked("mr-t"), - nft.clone(), + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract.clone(), &cw721_base::msg::ExecuteMsg::::TransferNft { - recipient: nft.to_string(), + recipient: nft_contract.to_string(), // new owner token_id: "1".to_string(), }, &[], ) .unwrap(); + // ics721 owner query and check nft contract owns it let owner: cw721::OwnerOfResponse = test .app .wrap() @@ -942,52 +1083,369 @@ fn test_do_instantiate_and_mint() { test.ics721, &QueryMsg::Owner { token_id: "1".to_string(), - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - assert_eq!(owner.owner, nft.to_string()); + assert_eq!(owner.owner, nft_contract.to_string()); - // Check that this state matches the state of the underlying - // cw721. + // check cw721 owner query matches ics721 owner query let base_owner: cw721::OwnerOfResponse = test .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::OwnerOf { token_id: "1".to_string(), include_expired: None, }, ) .unwrap(); - assert_eq!(base_owner, owner); } } +#[test] +fn test_do_instantiate_and_mint_2_different_collections() { + // test case: instantiate two cw721 contracts with different class id and make sure instantiate2 creates 2 different, predictable contracts + { + let mut test = Test::new(false, None, sg721_base_contract()); + let collection_contract_source_chain_1 = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id_1 = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain_1 + ); + let collection_contract_source_chain_2 = ClassId::new(test.app.api().addr_make("other")); + let class_id_2 = format!( + "wasm.{}/{}/{}", + test.ics721, "channel-123567890", collection_contract_source_chain_2 + ); + + // create contract 1 + test.app + .execute_contract( + test.ics721.clone(), + test.ics721.clone(), + &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), + create: VoucherCreation { + class: Class { + id: ClassId::new(class_id_1.clone()), + uri: Some("https://moonphase.is".to_string()), + data: None, // no class data + }, + tokens: vec![ + Token { + id: TokenId::new("1"), + uri: Some("https://moonphase.is/image.svg".to_string()), + data: None, + }, + Token { + id: TokenId::new("2"), + uri: Some("https://foo.bar".to_string()), + data: None, + }, + ], + }, + }), + &[], + ) + .unwrap(); + // create contract 2 + test.app + .execute_contract( + test.ics721.clone(), + test.ics721.clone(), + &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), + create: VoucherCreation { + class: Class { + id: ClassId::new(class_id_2.clone()), + uri: Some("https://moonphase.is".to_string()), + data: None, // no class data + }, + tokens: vec![ + Token { + id: TokenId::new("1"), + uri: Some("https://mr.t".to_string()), + data: None, + }, + Token { + id: TokenId::new("2"), + uri: Some("https://ark.protocol".to_string()), + data: None, + }, + ], + }, + }), + &[], + ) + .unwrap(); + // Check entry added in CLASS_ID_TO_NFT_CONTRACT + let nft_contracts = test.query_nft_contracts(); + assert_eq!(nft_contracts.len(), 2); + assert_eq!(nft_contracts[0].0, class_id_1.to_string()); + assert_eq!(nft_contracts[1].0, class_id_2.to_string()); + // Get the address of the instantiated NFT. + let nft_contract_1: Addr = test + .app + .wrap() + .query_wasm_smart( + test.ics721.clone(), + &QueryMsg::NftContract { + class_id: class_id_1.to_string(), + }, + ) + .unwrap(); + let nft_contract_2: Addr = test + .app + .wrap() + .query_wasm_smart( + test.ics721.clone(), + &QueryMsg::NftContract { + class_id: class_id_2.to_string(), + }, + ) + .unwrap(); + + // check name and symbol contains class id for instantiated nft contract + let contract_info_1: cw721::ContractInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) + .unwrap(); + let contract_info_2: cw721::ContractInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) + .unwrap(); + assert_eq!( + contract_info_1, + cw721::ContractInfoResponse { + name: class_id_1.to_string(), // name is set to class_id + symbol: class_id_1.to_string() // symbol is set to class_id + } + ); + assert_eq!( + contract_info_2, + cw721::ContractInfoResponse { + name: class_id_2.to_string(), // name is set to class_id + symbol: class_id_2.to_string() // symbol is set to class_id + } + ); + + // check collection info is properly set + let collection_info_1: CollectionInfoResponse = test + .app + .wrap() + .query_wasm_smart(nft_contract_1.clone(), &Sg721QueryMsg::CollectionInfo {}) + .unwrap(); + let collection_info_2: CollectionInfoResponse = test + .app + .wrap() + .query_wasm_smart(nft_contract_2.clone(), &Sg721QueryMsg::CollectionInfo {}) + .unwrap(); + assert_eq!( + collection_info_1, + CollectionInfoResponse { + // creator of ics721 contract is also creator of collection, since no owner in ClassData provided + creator: test.app.api().addr_make(ICS721_CREATOR).to_string(), + description: "".to_string(), + image: "https://arkprotocol.io".to_string(), + external_link: None, + explicit_content: None, + start_trading_time: None, + royalty_info: None, + } + ); + assert_eq!( + collection_info_2, + CollectionInfoResponse { + // creator of ics721 contract is also creator of collection, since no owner in ClassData provided + creator: test.app.api().addr_make(ICS721_CREATOR).to_string(), + description: "".to_string(), + image: "https://arkprotocol.io".to_string(), + external_link: None, + explicit_content: None, + start_trading_time: None, + royalty_info: None, + } + ); + + // Check that token_uri was set properly. + let token_info_1_1: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "1".to_string(), + }, + ) + .unwrap(); + let token_info_2_1: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "1".to_string(), + }, + ) + .unwrap(); + assert_eq!( + token_info_1_1.token_uri, + Some("https://moonphase.is/image.svg".to_string()) + ); + assert_eq!(token_info_2_1.token_uri, Some("https://mr.t".to_string())); + let token_info_1_2: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "2".to_string(), + }, + ) + .unwrap(); + let token_info_2_2: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "2".to_string(), + }, + ) + .unwrap(); + assert_eq!( + token_info_1_2.token_uri, + Some("https://foo.bar".to_string()) + ); + assert_eq!( + token_info_2_2.token_uri, + Some("https://ark.protocol".to_string()) + ); + + // After transfer to target, test owner can do any action, like transfer, on collection + test.app + .execute_contract( + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract_1.clone(), + &cw721_base::msg::ExecuteMsg::::TransferNft { + recipient: nft_contract_1.to_string(), + token_id: "1".to_string(), + }, + &[], + ) + .unwrap(); + test.app + .execute_contract( + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract_2.clone(), + &cw721_base::msg::ExecuteMsg::::TransferNft { + recipient: nft_contract_2.to_string(), + token_id: "1".to_string(), + }, + &[], + ) + .unwrap(); + + // ics721 owner query and check nft contract owns it + let owner_1: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + test.ics721.clone(), + &QueryMsg::Owner { + token_id: "1".to_string(), + class_id: class_id_1.to_string(), + }, + ) + .unwrap(); + let owner_2: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + test.ics721, + &QueryMsg::Owner { + token_id: "1".to_string(), + class_id: class_id_2.to_string(), + }, + ) + .unwrap(); + assert_eq!(owner_1.owner, nft_contract_1.to_string()); + assert_eq!(owner_2.owner, nft_contract_2.to_string()); + + // check cw721 owner query matches ics721 owner query + let base_owner_1: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1, + &cw721::Cw721QueryMsg::OwnerOf { + token_id: "1".to_string(), + include_expired: None, + }, + ) + .unwrap(); + let base_owner_2: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2, + &cw721::Cw721QueryMsg::OwnerOf { + token_id: "1".to_string(), + include_expired: None, + }, + ) + .unwrap(); + assert_eq!(base_owner_1, owner_1); + assert_eq!(base_owner_2, owner_2); + } +} + #[test] fn test_do_instantiate_and_mint_no_instantiate() { let mut test = Test::new(false, None, sg721_base_contract()); - - // This will instantiate a new contract for the class ID and then - // do a mint. + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); + // Check calling CreateVouchers twice with same class id + // on 2nd call it will not instantiate a new contract, + // instead it will just mint the token on existing contract test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "mr-t".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), data: Some( // data comes from source chain, so it can't be SgCollectionData // owner as defined by collection in source chain - to_binary(&CollectionData { - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + owner: Some( + // incoming collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), name: "name".to_string(), symbol: "symbol".to_string(), @@ -1010,19 +1468,19 @@ fn test_do_instantiate_and_mint_no_instantiate() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let class_id_to_nft_contract = test.query_nft_contracts(); assert_eq!(class_id_to_nft_contract.len(), 1); - assert_eq!(class_id_to_nft_contract[0].0, "bad kids"); + assert_eq!(class_id_to_nft_contract[0].0, class_id.to_string()); - // This will only do a mint as the contract for the class ID has + // 2nd call will only do a mint as the contract for the class ID has // already been instantiated. test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "mr-t".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), // unlike above in 1st transfer, here on 2nd transfer no classdata is provided! // this won't affect collection since it's already instantiated @@ -1030,7 +1488,7 @@ fn test_do_instantiate_and_mint_no_instantiate() { }, tokens: vec![Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }], }, @@ -1044,13 +1502,13 @@ fn test_do_instantiate_and_mint_no_instantiate() { assert_eq!(class_id_to_nft_contract.len(), 1); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( - test.ics721.clone(), + test.ics721, &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); @@ -1059,10 +1517,16 @@ fn test_do_instantiate_and_mint_no_instantiate() { let collection_info: CollectionInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Sg721QueryMsg::CollectionInfo {}) + .query_wasm_smart(nft_contract.clone(), &Sg721QueryMsg::CollectionInfo {}) .unwrap(); - let (_source_hrp, source_data, source_variant) = bech32::decode(OWNER_SOURCE_CHAIN).unwrap(); - let target_owner = bech32::encode(TARGET_HRP, source_data, source_variant).unwrap(); + let (_source_hrp, source_data, source_variant) = bech32::decode( + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .as_str(), + ) + .unwrap(); + let target_owner = bech32::encode(BECH32_PREFIX_HRP, source_data, source_variant).unwrap(); assert_eq!( collection_info, @@ -1083,36 +1547,46 @@ fn test_do_instantiate_and_mint_no_instantiate() { .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::AllTokens { start_after: None, limit: None, }, ) .unwrap(); - assert_eq!(tokens.tokens, vec!["1".to_string(), "2".to_string()]) } #[test] fn test_do_instantiate_and_mint_permissions() { let mut test = Test::new(false, None, sg721_base_contract()); - + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); // Method is only callable by the contract itself. let err: ContractError = test .app .execute_contract( - Addr::unchecked("notIcs721"), - test.ics721.clone(), + test.app.api().addr_make("notIcs721"), + test.ics721, &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "mr-t".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id), uri: Some("https://moonphase.is".to_string()), data: Some( - to_binary(&CollectionData { - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + owner: Some( + // incoming collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), name: "name".to_string(), symbol: "symbol".to_string(), @@ -1133,7 +1607,6 @@ fn test_do_instantiate_and_mint_permissions() { .unwrap_err() .downcast() .unwrap(); - assert_eq!(err, ContractError::Unauthorized {}); } @@ -1141,18 +1614,17 @@ fn test_do_instantiate_and_mint_permissions() { #[test] fn test_no_proxy_unauthorized() { let mut test = Test::new(false, None, sg721_base_contract()); - let err: ContractError = test .app .execute_contract( - Addr::unchecked("proxy"), + test.app.api().addr_make("proxy"), test.ics721, &ExecuteMsg::ReceiveProxyNft { eyeball: "nft".to_string(), msg: cw721::Cw721ReceiveMsg { - sender: "mr-t".to_string(), + sender: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), token_id: "1".to_string(), - msg: to_binary("").unwrap(), + msg: to_json_binary("").unwrap(), }, }, &[], @@ -1160,33 +1632,41 @@ fn test_no_proxy_unauthorized() { .unwrap_err() .downcast() .unwrap(); - assert_eq!(err, ContractError::Unauthorized {}); } #[test] fn test_proxy_authorized() { let mut test = Test::new(true, None, sg721_base_contract()); - let proxy_address: Option = test .app .wrap() .query_wasm_smart(&test.ics721, &QueryMsg::Proxy {}) .unwrap(); + // check proxy is set let proxy_address = proxy_address.expect("expected a proxy"); - let cw721_id = test.app.store_code(sg721_base_contract()); - let cw721 = test + // create collection and mint NFT for sending to proxy + let source_cw721_id = test.app.store_code(sg721_base_contract()); + let source_cw721 = test .app .instantiate_contract( - cw721_id, + source_cw721_id, test.ics721.clone(), // sg721 contract can only be instantiated by a contract, not user (unauthorized) &sg721::InstantiateMsg { name: "token".to_string(), symbol: "nonfungible".to_string(), - minter: "mr-t".to_string(), + minter: test + .app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), collection_info: sg721::CollectionInfo { - creator: mock_env().contract.address.to_string(), + creator: test + .app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), description: "".to_string(), image: "https://arkprotocol.io".to_string(), external_link: None, @@ -1200,10 +1680,12 @@ fn test_proxy_authorized() { None, ) .unwrap(); + // simplify: instead of `send_nft` to proxy, and proxy transfer NFT to ics721 and call receiveproy, + // here it is directly transfer to ics721 and then call receiveproxy test.app .execute_contract( - Addr::unchecked("mr-t"), - cw721.clone(), + test.app.api().addr_make(COLLECTION_OWNER_SOURCE_CHAIN), + source_cw721.clone(), &cw721_base::ExecuteMsg::::Mint { token_id: "1".to_string(), owner: test.ics721.to_string(), @@ -1214,17 +1696,24 @@ fn test_proxy_authorized() { ) .unwrap(); + // ics721 receives NFT from proxy, + // if - and only if - nft is escrowed by ics721, ics721 will interchain transfer NFT! + // otherwise proxy is unauthorised to transfer NFT test.app .execute_contract( proxy_address, test.ics721, &ExecuteMsg::ReceiveProxyNft { - eyeball: cw721.into_string(), + eyeball: source_cw721.into_string(), msg: cw721::Cw721ReceiveMsg { - sender: "mr-t".to_string(), + sender: test + .app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), token_id: "1".to_string(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "mr-t".to_string(), + msg: to_json_binary(&IbcOutgoingMsg { + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), channel_id: "channel-0".to_string(), timeout: IbcTimeout::with_block(IbcTimeoutBlock { revision: 0, @@ -1245,19 +1734,21 @@ fn test_receive_nft() { // test case: receive nft from sg721-base { let mut test = Test::new(false, None, sg721_base_contract()); - // mint and escrowed/owned by ics721 + // simplify: mint and escrowed/owned by ics721, as a precondition for receive nft let token_id = test.execute_cw721_mint(test.ics721.clone()).unwrap(); - + // ics721 receives NFT from sender/collection contract, + // if - and only if - nft is escrowed by ics721, ics721 will interchain transfer NFT! + // otherwise proxy is unauthorised to transfer NFT let res = test .app .execute_contract( - test.cw721.clone(), + test.source_cw721.clone(), test.ics721.clone(), &ExecuteMsg::ReceiveNft(cw721::Cw721ReceiveMsg { - sender: test.minter.to_string(), + sender: test.source_cw721_owner.to_string(), token_id: token_id.clone(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "mr-t".to_string(), + msg: to_json_binary(&IbcOutgoingMsg { + receiver: NFT_OWNER_TARGET_CHAIN.to_string(), // nft owner for other chain, on this chain ics721 is owner channel_id: "channel-0".to_string(), timeout: IbcTimeout::with_block(IbcTimeoutBlock { revision: 0, @@ -1270,83 +1761,21 @@ fn test_receive_nft() { &[], ) .unwrap(); - let event = res.events.into_iter().find(|e| e.ty == "wasm").unwrap(); - let class_data_attribute = event - .attributes - .into_iter() - .find(|a| a.key == "class_data") - .unwrap(); - let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_binary( - &to_binary(&ContractInfoResponse { - code_id: test.cw721_id, - creator: test.minter.to_string(), - admin: None, - pinned: false, - ibc_port: None, - }) - .unwrap(), - ) - .unwrap(); - let expected_collection_data = to_binary(&SgCollectionData { - owner: Some(test.minter.to_string()), - contract_info: expected_contract_info, - name: "name".to_string(), - symbol: "symbol".to_string(), - num_tokens: 1, - collection_info: CollectionInfoResponse { - creator: test.ics721.to_string(), - description: "".to_string(), - image: "https://arkprotocol.io".to_string(), - external_link: None, - explicit_content: None, - start_trading_time: None, - royalty_info: None, - }, - }) - .unwrap(); - assert_eq!( - class_data_attribute.value, - format!("{:?}", expected_collection_data) - ); - } - // test case: receive nft from old/v240 sg721-base - { - let mut test = Test::new(false, None, sg721_v240_base_contract()); - // mint and escrowed/owned by ics721 - let token_id = test.execute_cw721_mint(test.ics721.clone()).unwrap(); - let res = test - .app - .execute_contract( - test.cw721.clone(), - test.ics721.clone(), - &ExecuteMsg::ReceiveNft(cw721::Cw721ReceiveMsg { - sender: test.minter.to_string(), - token_id: token_id.clone(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "mr-t".to_string(), - channel_id: "channel-0".to_string(), - timeout: IbcTimeout::with_block(IbcTimeoutBlock { - revision: 0, - height: 10, - }), - memo: None, - }) - .unwrap(), - }), - &[], - ) - .unwrap(); + // get class data (containing collection data) from response let event = res.events.into_iter().find(|e| e.ty == "wasm").unwrap(); let class_data_attribute = event .attributes .into_iter() .find(|a| a.key == "class_data") .unwrap(); - let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_binary( - &to_binary(&ContractInfoResponse { - code_id: test.cw721_id, - creator: test.minter.to_string(), + // check collection data matches with data from source nft contract + let expected_contract_info: cosmwasm_std::ContractInfoResponse = + // workaround using from_json/to_json_binary since ContractInfoResponse is non-exhaustive, can't be created directly + from_json( + &to_json_binary(&ContractInfoResponse { + code_id: test.source_cw721_id, + creator: test.source_cw721_owner.to_string(), admin: None, pinned: false, ibc_port: None, @@ -1354,8 +1783,11 @@ fn test_receive_nft() { .unwrap(), ) .unwrap(); - let expected_collection_data = to_binary(&SgCollectionData { - owner: Some(test.minter.to_string()), + let expected_collection_data = to_json_binary(&SgCollectionData { + owner: Some( + // collection data from source chain + test.source_cw721_owner.to_string(), + ), contract_info: expected_contract_info, name: "name".to_string(), symbol: "symbol".to_string(), @@ -1378,22 +1810,21 @@ fn test_receive_nft() { } } -/// Tests that receiving a NFT via a regular receive fails when a -/// proxy is installed. +/// In case proxy for ICS721 is defined, ICS721 only accepts receival from proxy - not from nft contract! #[test] fn test_no_receive_with_proxy() { let mut test = Test::new(true, None, sg721_base_contract()); - + // unauthorized to receive nft from nft contract let err: ContractError = test .app .execute_contract( - Addr::unchecked("cw721"), + test.app.api().addr_make("cw721"), test.ics721, &ExecuteMsg::ReceiveNft(cw721::Cw721ReceiveMsg { - sender: "mr-t".to_string(), + sender: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), token_id: "1".to_string(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "mr-t".to_string(), + msg: to_json_binary(&IbcOutgoingMsg { + receiver: NFT_OWNER_TARGET_CHAIN.to_string(), // nft owner for other chain, on this chain ics721 is owner channel_id: "channel-0".to_string(), timeout: IbcTimeout::with_block(IbcTimeoutBlock { revision: 0, @@ -1408,38 +1839,43 @@ fn test_no_receive_with_proxy() { .unwrap_err() .downcast() .unwrap(); - assert_eq!(err, ContractError::Unauthorized {}) } /// Tests the contract's pause behavior. #[test] fn test_pause() { - let mut test = Test::new(true, Some("mr-t".to_string()), sg721_base_contract()); - + let mut test = Test::new( + true, + Some(ICS721_ADMIN_AND_PAUSER.to_string()), + sg721_base_contract(), + ); // Should start unpaused. let (paused, pauser) = test.query_pause_info(); assert!(!paused); - assert_eq!(pauser, Some(Addr::unchecked("mr-t"))); + assert_eq!( + pauser, + Some(test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER)) + ); // Non-pauser may not pause. - let err = test.pause_ics721_should_fail("zeke"); + let err = test.pause_ics721_should_fail(test.app.api().addr_make("zeke").as_str()); assert_eq!( err, ContractError::Pause(PauseError::Unauthorized { - sender: Addr::unchecked("zeke") + sender: test.app.api().addr_make("zeke") }) ); // Pause the ICS721 contract. - test.pause_ics721("mr-t"); + test.pause_ics721(test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER).as_str()); // Pausing should remove the pauser. let (paused, pauser) = test.query_pause_info(); assert!(paused); assert_eq!(pauser, None); // Pausing fails. - let err = test.pause_ics721_should_fail("mr-t"); + let err = test.pause_ics721_should_fail(test.app.api().addr_make("mr-t").as_str()); assert_eq!(err, ContractError::Pause(PauseError::Paused {})); // Even something like executing a callback on ourselves will be @@ -1457,16 +1893,16 @@ fn test_pause() { .unwrap(); assert_eq!(err, ContractError::Pause(PauseError::Paused {})); - // Set a new pauser. + // Pauser can pause only once, for another pause, a new pauser needs to be set via migration let ics721_id = test.app.store_code(ics721_contract()); test.app .execute( - Addr::unchecked("mr-t"), + test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER), WasmMsg::Migrate { contract_addr: test.ics721.to_string(), new_code_id: ics721_id, - msg: to_binary(&MigrateMsg::WithUpdate { - pauser: Some("zeke".to_string()), + msg: to_json_binary(&MigrateMsg::WithUpdate { + pauser: Some(test.app.api().addr_make("new_pauser").to_string()), proxy: None, cw721_base_code_id: None, }) @@ -1479,10 +1915,10 @@ fn test_pause() { // Setting new pauser should unpause. let (paused, pauser) = test.query_pause_info(); assert!(!paused); - assert_eq!(pauser, Some(Addr::unchecked("zeke"))); + assert_eq!(pauser, Some(test.app.api().addr_make("new_pauser"))); // One more pause for posterity sake. - test.pause_ics721("zeke"); + test.pause_ics721(test.app.api().addr_make("new_pauser").as_str()); let (paused, pauser) = test.query_pause_info(); assert!(paused); assert_eq!(pauser, None); @@ -1491,23 +1927,30 @@ fn test_pause() { /// Tests migration. #[test] fn test_migration() { - let mut test = Test::new(true, Some("mr-t".to_string()), sg721_base_contract()); + let mut test = Test::new( + true, + Some(ICS721_ADMIN_AND_PAUSER.to_string()), + sg721_base_contract(), + ); // assert instantiation worked let (_, pauser) = test.query_pause_info(); - assert_eq!(pauser, Some(Addr::unchecked("mr-t"))); + assert_eq!( + pauser, + Some(test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER)) + ); let proxy = test.query_proxy(); assert!(proxy.is_some()); let cw721_code_id = test.query_cw721_id(); - assert_eq!(cw721_code_id, test.cw721_id); + assert_eq!(cw721_code_id, test.source_cw721_id); // migrate changes test.app .execute( - Addr::unchecked("mr-t"), + test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER), WasmMsg::Migrate { contract_addr: test.ics721.to_string(), new_code_id: test.ics721_id, - msg: to_binary(&MigrateMsg::WithUpdate { + msg: to_json_binary(&MigrateMsg::WithUpdate { pauser: None, proxy: None, cw721_base_code_id: Some(12345678), @@ -1528,11 +1971,11 @@ fn test_migration() { // migrate without changing code id test.app .execute( - Addr::unchecked("mr-t"), + test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER), WasmMsg::Migrate { contract_addr: test.ics721.to_string(), new_code_id: test.ics721_id, - msg: to_binary(&MigrateMsg::WithUpdate { + msg: to_json_binary(&MigrateMsg::WithUpdate { pauser: None, proxy: None, cw721_base_code_id: None, diff --git a/e2e/suite_test.go b/e2e/suite_test.go index 80dcf7df..8fb014f0 100644 --- a/e2e/suite_test.go +++ b/e2e/suite_test.go @@ -203,8 +203,8 @@ func (suite *TransferTestSuite) TestIBCSendNFT() { err = suite.chainB.SmartQuery(chainBCw721, contractInfoQuery, &contractInfo) require.NoError(suite.T(), err) require.Equal(suite.T(), ContractInfoResponse{ - Name: chainBClassID, - Symbol: chainBClassID, + Name: "bad/kids", + Symbol: "bad/kids", }, contractInfo) // Send the NFT back! diff --git a/packages/cw-cii/src/lib.rs b/packages/cw-cii/src/lib.rs index 7b60020b..103aa5c7 100644 --- a/packages/cw-cii/src/lib.rs +++ b/packages/cw-cii/src/lib.rs @@ -32,7 +32,7 @@ impl ContractInstantiateInfo { #[cfg(test)] mod tests { - use cosmwasm_std::{to_binary, Addr, WasmMsg}; + use cosmwasm_std::{to_json_binary, Addr, WasmMsg}; use super::*; @@ -40,7 +40,7 @@ mod tests { fn test_instantiate_admin_none() { let no_admin = ContractInstantiateInfo { code_id: 42, - msg: to_binary("foo").unwrap(), + msg: to_json_binary("foo").unwrap(), admin: None, label: "bar".to_string(), }; @@ -49,7 +49,7 @@ mod tests { WasmMsg::Instantiate { admin: None, code_id: 42, - msg: to_binary("foo").unwrap(), + msg: to_json_binary("foo").unwrap(), funds: vec![], label: "bar".to_string() } @@ -60,7 +60,7 @@ mod tests { fn test_instantiate_admin_addr() { let no_admin = ContractInstantiateInfo { code_id: 42, - msg: to_binary("foo").unwrap(), + msg: to_json_binary("foo").unwrap(), admin: Some(Admin::Address { addr: "core".to_string(), }), @@ -71,7 +71,7 @@ mod tests { WasmMsg::Instantiate { admin: Some("core".to_string()), code_id: 42, - msg: to_binary("foo").unwrap(), + msg: to_json_binary("foo").unwrap(), funds: vec![], label: "bar".to_string() } @@ -82,7 +82,7 @@ mod tests { fn test_instantiate_instantiator_addr() { let no_admin = ContractInstantiateInfo { code_id: 42, - msg: to_binary("foo").unwrap(), + msg: to_json_binary("foo").unwrap(), admin: Some(Admin::Instantiator {}), label: "bar".to_string(), }; @@ -91,7 +91,7 @@ mod tests { WasmMsg::Instantiate { admin: Some("ekez".to_string()), code_id: 42, - msg: to_binary("foo").unwrap(), + msg: to_json_binary("foo").unwrap(), funds: vec![], label: "bar".to_string() } diff --git a/packages/ics721/Cargo.toml b/packages/ics721/Cargo.toml index 56f33f67..3f9d7519 100644 --- a/packages/ics721/Cargo.toml +++ b/packages/ics721/Cargo.toml @@ -7,7 +7,7 @@ description = "an implementation of the ICS721 specification for transfering NFT [dependencies] bech32 = { workspace = true } -cosmwasm-std = { workspace = true, features = ["ibc3"] } +cosmwasm-std = { workspace = true, features = ["cosmwasm_1_2"] } cosmwasm-schema = { workspace = true } cw-ownable = { workspace = true } cw-storage-plus = { workspace = true } @@ -21,6 +21,7 @@ cw-paginate-storage = { workspace = true } cw721-proxy-derive = { workspace = true } cw-pause-once = { workspace = true } cw-cii = { workspace = true } +sha2 = { workspace = true } zip-optional = { workspace = true } [dev-dependencies] diff --git a/packages/ics721/src/error.rs b/packages/ics721/src/error.rs index 26ec9a1c..7dbb11fa 100644 --- a/packages/ics721/src/error.rs +++ b/packages/ics721/src/error.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::StdError; +use cosmwasm_std::{Instantiate2AddressError, StdError}; use cw_pause_once::PauseError; use cw_utils::ParseReplyError; use thiserror::Error; @@ -11,6 +11,9 @@ pub enum ContractError { #[error(transparent)] Pause(#[from] PauseError), + #[error(transparent)] + Instantiate2Error(#[from] Instantiate2AddressError), + #[error("unauthorized")] Unauthorized {}, @@ -57,8 +60,3 @@ pub enum ContractError { #[error("tokenIds, tokenUris, and tokenData must have the same length")] TokenInfoLenMissmatch {}, } - -/// Enum that can never be constructed. Used as an error type where we -/// can not error. -#[derive(Error, Debug)] -pub enum Never {} diff --git a/packages/ics721/src/execute.rs b/packages/ics721/src/execute.rs index 072c1aab..79c6c3e3 100644 --- a/packages/ics721/src/execute.rs +++ b/packages/ics721/src/execute.rs @@ -1,17 +1,19 @@ use std::fmt::Debug; use cosmwasm_std::{ - from_binary, to_binary, Addr, Binary, Deps, DepsMut, Empty, Env, IbcMsg, MessageInfo, Response, - StdResult, SubMsg, WasmMsg, + from_json, instantiate2_address, to_json_binary, Addr, Binary, CodeInfoResponse, Deps, DepsMut, + Empty, Env, IbcMsg, MessageInfo, Response, StdResult, SubMsg, WasmMsg, }; use serde::{de::DeserializeOwned, Serialize}; +use sha2::{Digest, Sha256}; use crate::{ ibc::{NonFungibleTokenPacketData, INSTANTIATE_CW721_REPLY_ID, INSTANTIATE_PROXY_REPLY_ID}, msg::{CallbackMsg, ExecuteMsg, IbcOutgoingMsg, InstantiateMsg, MigrateMsg}, state::{ - UniversalAllNftInfoResponse, CLASS_ID_TO_CLASS, CLASS_ID_TO_NFT_CONTRACT, CW721_CODE_ID, - NFT_CONTRACT_TO_CLASS_ID, OUTGOING_CLASS_TOKEN_TO_CHANNEL, PO, PROXY, TOKEN_METADATA, + CollectionData, UniversalAllNftInfoResponse, CLASS_ID_TO_CLASS, CLASS_ID_TO_NFT_CONTRACT, + CW721_CODE_ID, NFT_CONTRACT_TO_CLASS_ID, OUTGOING_CLASS_TOKEN_TO_CHANNEL, PO, PROXY, + TOKEN_METADATA, }, token_types::{Class, ClassId, Token, TokenId, VoucherCreation, VoucherRedemption}, ContractError, @@ -122,7 +124,7 @@ where msg: Binary, ) -> Result, ContractError> { let sender = deps.api.addr_validate(&sender)?; - let msg: IbcOutgoingMsg = from_binary(&msg)?; + let msg: IbcOutgoingMsg = from_json(msg)?; let class = match NFT_CONTRACT_TO_CLASS_ID.may_load(deps.storage, info.sender.clone())? { Some(class_id) => CLASS_ID_TO_CLASS.load(deps.storage, class_id)?, @@ -130,7 +132,7 @@ where // that has never been sent out of this contract. None => { let class_data = self.get_class_data(&deps, &info.sender)?; - let data = class_data.as_ref().map(to_binary).transpose()?; + let data = class_data.as_ref().map(to_json_binary).transpose()?; let class = Class { id: ClassId::new(info.sender.to_string()), // There is no collection-level uri nor data in the @@ -150,6 +152,7 @@ where } }; + // make sure NFT is escrowed by ics721 let UniversalAllNftInfoResponse { access, info } = deps.querier.query_wasm_smart( info.sender, &cw721::Cw721QueryMsg::AllNftInfo { @@ -157,11 +160,13 @@ where include_expired: None, }, )?; - // make sure NFT is escrowed by ics721 if access.owner != env.contract.address { return Err(ContractError::Unauthorized {}); } + // cw721 doesn't support on-chain metadata yet + // here NFT is transferred to another chain, NFT itself may have been transferred to his chain before + // in this case ICS721 may have metadata stored let token_metadata = TOKEN_METADATA .may_load(deps.storage, (class.id.clone(), token_id.clone()))? .flatten(); @@ -181,7 +186,7 @@ where }; let ibc_message = IbcMsg::SendPacket { channel_id: msg.channel_id.clone(), - data: to_binary(&ibc_message)?, + data: to_json_binary(&ibc_message)?, timeout: msg.timeout, }; @@ -258,8 +263,28 @@ where let instantiate = if CLASS_ID_TO_NFT_CONTRACT.has(deps.storage, class.id.clone()) { vec![] } else { + let class_id = ClassId::new(class.id.clone()); + // for creating a predictable nft contract using, using instantiate2, we need: checksum, creator, and salt: + // - using class id as salt for instantiating nft contract guarantees a) predictable address and b) uniqueness + // for this salt must be of length 32 bytes, so we use sha256 to hash class id + let mut hasher = Sha256::new(); + hasher.update(class_id.as_bytes()); + let salt = hasher.finalize().to_vec(); + // Get the canonical address of the contract creator + let canonical_creator = deps.api.addr_canonicalize(env.contract.address.as_str())?; + // get the checksum of the contract we're going to instantiate + let CodeInfoResponse { checksum, .. } = deps + .querier + .query_wasm_code_info(CW721_CODE_ID.load(deps.storage)?)?; + let canonical_cw721_addr = instantiate2_address(&checksum, &canonical_creator, &salt)?; + let cw721_addr = deps.api.addr_humanize(&canonical_cw721_addr)?; + + // Save classId <-> contract mappings. + CLASS_ID_TO_NFT_CONTRACT.save(deps.storage, class_id.clone(), &cw721_addr)?; + NFT_CONTRACT_TO_CLASS_ID.save(deps.storage, cw721_addr.clone(), &class_id)?; + let message = SubMsg::::reply_on_success( - WasmMsg::Instantiate { + WasmMsg::Instantiate2 { admin: None, code_id: CW721_CODE_ID.load(deps.storage)?, msg: self.init_msg(deps.as_ref(), &env, &class)?, @@ -268,6 +293,7 @@ where // can make this field too long which causes data // errors in the SDK. label: "ics-721 debt-voucher cw-721".to_string(), + salt: salt.into(), }, INSTANTIATE_CW721_REPLY_ID, ); @@ -283,7 +309,7 @@ where let mint = WasmMsg::Execute { contract_addr: env.contract.address.into_string(), - msg: to_binary(&ExecuteMsg::Callback(CallbackMsg::Mint { + msg: to_json_binary(&ExecuteMsg::Callback(CallbackMsg::Mint { class_id: class.id, receiver, tokens, @@ -299,13 +325,24 @@ where /// Default implementation using `cw721_base::msg::InstantiateMsg` fn init_msg(&self, _deps: Deps, env: &Env, class: &Class) -> StdResult { - to_binary(&cw721_base::msg::InstantiateMsg { - // Name of the collection MUST be class_id as this is how - // we create a map entry on reply. + // use by default ClassId, in case there's no class data with name and symbol + let mut instantiate_msg = cw721_base::msg::InstantiateMsg { name: class.id.clone().into(), symbol: class.id.clone().into(), minter: env.contract.address.to_string(), - }) + }; + + // unwrapped to collection data and in case of success, set name and symbol + if let Some(binary) = class.data.clone() { + let class_data_result: StdResult = from_json(binary); + if class_data_result.is_ok() { + let class_data = class_data_result?; + instantiate_msg.symbol = class_data.symbol; + instantiate_msg.name = class_data.name; + } + } + + to_json_binary(&instantiate_msg) } /// Performs a recemption of debt vouchers returning the corresponding @@ -327,7 +364,7 @@ where .map(|token_id| { Ok(WasmMsg::Execute { contract_addr: nft_contract.to_string(), - msg: to_binary(&cw721::Cw721ExecuteMsg::TransferNft { + msg: to_json_binary(&cw721::Cw721ExecuteMsg::TransferNft { recipient: receiver.to_string(), token_id: token_id.into(), })?, @@ -351,10 +388,10 @@ where let mint = tokens .into_iter() .map(|Token { id, uri, data }| { - // We save token metadata here as, ideally, once cw721 - // supports on-chain metadata, this is where we will set - // that value on the debt-voucher token. Note that this is - // set for every token, regardless of if data is None. + // Source chain may have provided token metadata, so we save token metadata here + // Note, once cw721 doesn't support on-chain metadata yet - but this is where we will set + // that value on the debt-voucher token once it is supported. + // Also note that this is set for every token, regardless of if data is None. TOKEN_METADATA.save(deps.storage, (class_id.clone(), id.clone()), &data)?; let msg = cw721_base::msg::ExecuteMsg::::Mint { @@ -365,7 +402,7 @@ where }; Ok(WasmMsg::Execute { contract_addr: cw721_addr.to_string(), - msg: to_binary(&msg)?, + msg: to_json_binary(&msg)?, funds: vec![], }) }) diff --git a/packages/ics721/src/ibc.rs b/packages/ics721/src/ibc.rs index 99c30df3..e316cf0b 100644 --- a/packages/ics721/src/ibc.rs +++ b/packages/ics721/src/ibc.rs @@ -1,15 +1,14 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - from_binary, to_binary, Binary, DepsMut, Empty, Env, IbcBasicResponse, IbcChannelCloseMsg, + from_json, to_json_binary, Binary, DepsMut, Empty, Env, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcPacket, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, Reply, Response, StdResult, - SubMsgResult, WasmMsg, + IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, Never, Reply, Response, + StdResult, SubMsgResult, WasmMsg, }; use cw_utils::parse_reply_instantiate_data; use serde::{de::DeserializeOwned, Serialize}; use crate::{ - error::Never, ibc_helpers::{ack_fail, ack_success, try_get_ack_error, validate_order_and_version}, ibc_packet_receive::receive_ibc_packet, state::{ @@ -151,7 +150,7 @@ where if let Some(error) = try_get_ack_error(&ack.acknowledgement) { self.handle_packet_fail(deps, ack.original_packet, &error) } else { - let msg: NonFungibleTokenPacketData = from_binary(&ack.original_packet.data)?; + let msg: NonFungibleTokenPacketData = from_json(&ack.original_packet.data)?; let nft_contract = CLASS_ID_TO_NFT_CONTRACT.load(deps.storage, msg.class_id.clone())?; // Burn all of the tokens being transfered out that were @@ -172,7 +171,7 @@ where messages.push(WasmMsg::Execute { contract_addr: nft_contract.to_string(), - msg: to_binary(&cw721::Cw721ExecuteMsg::Burn { + msg: to_json_binary(&cw721::Cw721ExecuteMsg::Burn { token_id: token.into(), })?, funds: vec![], @@ -208,7 +207,7 @@ where packet: IbcPacket, error: &str, ) -> Result { - let message: NonFungibleTokenPacketData = from_binary(&packet.data)?; + let message: NonFungibleTokenPacketData = from_json(&packet.data)?; let nft_address = CLASS_ID_TO_NFT_CONTRACT.load(deps.storage, message.class_id.clone())?; let sender = deps.api.addr_validate(&message.sender)?; @@ -221,7 +220,7 @@ where .remove(deps.storage, (message.class_id.clone(), token_id.clone())); Ok(WasmMsg::Execute { contract_addr: nft_address.to_string(), - msg: to_binary(&cw721::Cw721ExecuteMsg::TransferNft { + msg: to_json_binary(&cw721::Cw721ExecuteMsg::TransferNft { recipient: sender.to_string(), token_id: token_id.into(), })?, @@ -253,17 +252,8 @@ where let res = parse_reply_instantiate_data(reply)?; let cw721_addr = deps.api.addr_validate(&res.contract_address)?; - // We need to map this address back to a class - // ID. Fourtunately, we set the name of the new NFT - // contract to the class ID. - let cw721::ContractInfoResponse { name, .. } = deps - .querier - .query_wasm_smart(cw721_addr.clone(), &cw721::Cw721QueryMsg::ContractInfo {})?; - let class_id = ClassId::new(name); - - // Save classId <-> contract mappings. - CLASS_ID_TO_NFT_CONTRACT.save(deps.storage, class_id.clone(), &cw721_addr)?; - NFT_CONTRACT_TO_CLASS_ID.save(deps.storage, cw721_addr.clone(), &class_id)?; + // cw721 addr has already been stored, here just check whether it exists, otherwise a NotFound error is thrown + let class_id = NFT_CONTRACT_TO_CLASS_ID.load(deps.storage, cw721_addr.clone())?; Ok(Response::default() .add_attribute("method", "instantiate_cw721_reply") diff --git a/packages/ics721/src/ibc_helpers.rs b/packages/ics721/src/ibc_helpers.rs index f136bf7c..98f8e9d2 100644 --- a/packages/ics721/src/ibc_helpers.rs +++ b/packages/ics721/src/ibc_helpers.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - from_binary, to_binary, Binary, IbcAcknowledgement, IbcChannel, IbcEndpoint, IbcOrder, + from_json, to_json_binary, Binary, IbcAcknowledgement, IbcChannel, IbcEndpoint, IbcOrder, }; use serde::{Deserialize, Serialize}; @@ -44,12 +44,12 @@ pub enum Ics721Ack { pub fn ack_success() -> Binary { let res = Ics721Ack::Result(b"1".into()); - to_binary(&res).unwrap() + to_json_binary(&res).unwrap() } pub fn ack_fail(err: String) -> Binary { let res = Ics721Ack::Error(err); - to_binary(&res).unwrap() + to_json_binary(&res).unwrap() } /// Tries to get the error from an ACK. If an error exists, returns @@ -76,7 +76,7 @@ pub fn ack_fail(err: String) -> Binary { pub fn try_get_ack_error(ack: &IbcAcknowledgement) -> Option { let ack: Ics721Ack = // What we can not parse is an ACK fail. - from_binary(&ack.data).unwrap_or_else(|_| Ics721Ack::Error(ack.data.to_base64())); + from_json(&ack.data).unwrap_or_else(|_| Ics721Ack::Error(ack.data.to_base64())); match ack { Ics721Ack::Error(e) => Some(e), _ => None, diff --git a/packages/ics721/src/ibc_packet_receive.rs b/packages/ics721/src/ibc_packet_receive.rs index 0e59a7e6..b6acceb4 100644 --- a/packages/ics721/src/ibc_packet_receive.rs +++ b/packages/ics721/src/ibc_packet_receive.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - from_binary, to_binary, Addr, Binary, DepsMut, Empty, Env, IbcPacket, IbcReceiveResponse, + from_json, to_json_binary, Addr, Binary, DepsMut, Empty, Env, IbcPacket, IbcReceiveResponse, StdResult, SubMsg, WasmMsg, }; use zip_optional::Zippable; @@ -48,7 +48,7 @@ pub(crate) fn receive_ibc_packet( ) -> Result { PO.error_if_paused(deps.storage)?; - let data: NonFungibleTokenPacketData = from_binary(&packet.data)?; + let data: NonFungibleTokenPacketData = from_json(&packet.data)?; data.validate()?; let local_class_id = try_pop_source_prefix(&packet.src, &data.class_id); @@ -236,7 +236,7 @@ impl ActionAggregator { } else { WasmMsg::Execute { contract_addr: contract.into_string(), - msg: to_binary(&ExecuteMsg::Callback(CallbackMsg::Conjunction { + msg: to_json_binary(&ExecuteMsg::Callback(CallbackMsg::Conjunction { operands: m, }))?, funds: vec![], diff --git a/packages/ics721/src/lib.rs b/packages/ics721/src/lib.rs index e9e2c5d4..80aa05a3 100644 --- a/packages/ics721/src/lib.rs +++ b/packages/ics721/src/lib.rs @@ -12,4 +12,4 @@ pub mod utils; pub use crate::error::ContractError; #[cfg(test)] -mod testing; +pub mod testing; diff --git a/packages/ics721/src/query.rs b/packages/ics721/src/query.rs index 73068948..408220c9 100644 --- a/packages/ics721/src/query.rs +++ b/packages/ics721/src/query.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{to_binary, Addr, Binary, Deps, Env, Order, StdResult}; +use cosmwasm_std::{to_json_binary, Addr, Binary, Deps, Env, Order, StdResult}; use cw_storage_plus::Map; use crate::{ @@ -15,34 +15,34 @@ pub trait Ics721Query { fn query(&self, deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { QueryMsg::ClassId { contract } => { - to_binary(&self.query_class_id_for_nft_contract(deps, contract)?) + to_json_binary(&self.query_class_id_for_nft_contract(deps, contract)?) } QueryMsg::NftContract { class_id } => { - to_binary(&self.query_nft_contract_for_class_id(deps, class_id)?) + to_json_binary(&self.query_nft_contract_for_class_id(deps, class_id)?) } QueryMsg::ClassMetadata { class_id } => { - to_binary(&self.query_class_metadata(deps, class_id)?) + to_json_binary(&self.query_class_metadata(deps, class_id)?) } QueryMsg::TokenMetadata { class_id, token_id } => { - to_binary(&self.query_token_metadata(deps, class_id, token_id)?) + to_json_binary(&self.query_token_metadata(deps, class_id, token_id)?) } QueryMsg::Owner { class_id, token_id } => { - to_binary(&self.query_owner(deps, class_id, token_id)?) + to_json_binary(&self.query_owner(deps, class_id, token_id)?) } - QueryMsg::Pauser {} => to_binary(&PO.query_pauser(deps.storage)?), - QueryMsg::Paused {} => to_binary(&PO.query_paused(deps.storage)?), - QueryMsg::Proxy {} => to_binary(&PROXY.load(deps.storage)?), - QueryMsg::Cw721CodeId {} => to_binary(&self.query_cw721_code_id(deps)?), + QueryMsg::Pauser {} => to_json_binary(&PO.query_pauser(deps.storage)?), + QueryMsg::Paused {} => to_json_binary(&PO.query_paused(deps.storage)?), + QueryMsg::Proxy {} => to_json_binary(&PROXY.load(deps.storage)?), + QueryMsg::Cw721CodeId {} => to_json_binary(&self.query_cw721_code_id(deps)?), QueryMsg::NftContracts { start_after, limit } => { - to_binary(&self.query_nft_contracts(deps, start_after, limit)?) + to_json_binary(&self.query_nft_contracts(deps, start_after, limit)?) } - QueryMsg::OutgoingChannels { start_after, limit } => to_binary(&query_channels( + QueryMsg::OutgoingChannels { start_after, limit } => to_json_binary(&query_channels( deps, &OUTGOING_CLASS_TOKEN_TO_CHANNEL, start_after, limit, )?), - QueryMsg::IncomingChannels { start_after, limit } => to_binary(&query_channels( + QueryMsg::IncomingChannels { start_after, limit } => to_json_binary(&query_channels( deps, &INCOMING_CLASS_TOKEN_TO_CHANNEL, start_after, @@ -81,20 +81,17 @@ pub trait Ics721Query { let token_id = TokenId::new(token_id); let class_id = ClassId::new(class_id); - let Some(token_metadata) = TOKEN_METADATA.may_load( - deps.storage, - (class_id.clone(), token_id.clone()), - )? else { - // Token metadata is set unconditionaly on mint. If we have no - // metadata entry, we have no entry for this token at all. - return Ok(None) + let Some(token_metadata) = + TOKEN_METADATA.may_load(deps.storage, (class_id.clone(), token_id.clone()))? + else { + // Token metadata is set unconditionaly on mint. If we have no + // metadata entry, we have no entry for this token at all. + return Ok(None); }; - let Some(token_contract) = CLASS_ID_TO_NFT_CONTRACT.may_load( - deps.storage, - class_id - )? else { - debug_assert!(false, "token_metadata != None => token_contract != None"); - return Ok(None) + let Some(token_contract) = CLASS_ID_TO_NFT_CONTRACT.may_load(deps.storage, class_id)? + else { + debug_assert!(false, "token_metadata != None => token_contract != None"); + return Ok(None); }; let UniversalAllNftInfoResponse { info, .. } = deps.querier.query_wasm_smart( token_contract, diff --git a/packages/ics721/src/state.rs b/packages/ics721/src/state.rs index d092ca55..beae865e 100644 --- a/packages/ics721/src/state.rs +++ b/packages/ics721/src/state.rs @@ -72,7 +72,7 @@ pub struct UniversalOwnerOfResponse { #[cfg(test)] mod tests { - use cosmwasm_std::{from_binary, to_binary, Coin, Empty}; + use cosmwasm_std::{from_json, to_json_binary, Coin, Empty}; use super::UniversalAllNftInfoResponse; @@ -88,8 +88,8 @@ mod tests { extension: Coin::new(100, "ujuno"), }, }; - let start = to_binary(&start).unwrap(); - let end: UniversalAllNftInfoResponse = from_binary(&start).unwrap(); + let start = to_json_binary(&start).unwrap(); + let end: UniversalAllNftInfoResponse = from_json(&start).unwrap(); assert_eq!(end.access.owner, "foo".to_string()); assert_eq!(end.access.approvals, vec![]); assert_eq!(end.info.token_uri, None); diff --git a/packages/ics721/src/testing/contract.rs b/packages/ics721/src/testing/contract.rs index c65daf83..766bd25e 100644 --- a/packages/ics721/src/testing/contract.rs +++ b/packages/ics721/src/testing/contract.rs @@ -1,8 +1,8 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - from_binary, + from_json, testing::{mock_dependencies, mock_env, mock_info, MockQuerier, MOCK_CONTRACT_ADDR}, - to_binary, Addr, ContractResult, CosmosMsg, DepsMut, Empty, IbcMsg, IbcTimeout, Order, + to_json_binary, Addr, ContractResult, CosmosMsg, DepsMut, Empty, IbcMsg, IbcTimeout, Order, QuerierResult, StdResult, SubMsg, Timestamp, WasmQuery, }; use cw721::{AllNftInfoResponse, NftInfoResponse, NumTokensResponse}; @@ -69,9 +69,9 @@ fn mock_querier(query: &WasmQuery) -> QuerierResult { cosmwasm_std::WasmQuery::Smart { contract_addr: _, msg, - } => match from_binary::>(&msg).unwrap() { + } => match from_json::>(&msg).unwrap() { QueryMsg::Ownership {} => QuerierResult::Ok(ContractResult::Ok( - to_binary(&Ownership:: { + to_json_binary(&Ownership:: { owner: Some(Addr::unchecked(OWNER)), pending_owner: None, pending_expiry: None, @@ -79,7 +79,7 @@ fn mock_querier(query: &WasmQuery) -> QuerierResult { .unwrap(), )), QueryMsg::AllNftInfo { .. } => QuerierResult::Ok(ContractResult::Ok( - to_binary(&AllNftInfoResponse::> { + to_json_binary(&AllNftInfoResponse::> { access: cw721::OwnerOfResponse { owner: MOCK_CONTRACT_ADDR.to_string(), approvals: vec![], @@ -92,19 +92,19 @@ fn mock_querier(query: &WasmQuery) -> QuerierResult { .unwrap(), )), QueryMsg::ContractInfo {} => QuerierResult::Ok(ContractResult::Ok( - to_binary(&cw721::ContractInfoResponse { + to_json_binary(&cw721::ContractInfoResponse { name: "name".to_string(), symbol: "symbol".to_string(), }) .unwrap(), )), QueryMsg::NumTokens {} => QuerierResult::Ok(ContractResult::Ok( - to_binary(&NumTokensResponse { count: 1 }).unwrap(), + to_json_binary(&NumTokensResponse { count: 1 }).unwrap(), )), _ => unimplemented!(), }, cosmwasm_std::WasmQuery::ContractInfo { .. } => QuerierResult::Ok(ContractResult::Ok( - to_binary(&ContractInfoResponse { + to_json_binary(&ContractInfoResponse { code_id: 0, creator: "creator".to_string(), admin: None, @@ -122,10 +122,10 @@ fn mock_querier_v016(query: &WasmQuery) -> QuerierResult { cosmwasm_std::WasmQuery::Smart { contract_addr: _, msg, - } => match from_binary::>(&msg).unwrap() { + } => match from_json::>(&msg).unwrap() { // unwrap using latest (not old) cw721-base, since it is backwards compatible cw721_base::msg::QueryMsg::Minter {} => QuerierResult::Ok(ContractResult::Ok( - to_binary( + to_json_binary( // return v016 response &cw721_base_016::msg::MinterResponse { minter: OWNER.to_string(), @@ -134,7 +134,7 @@ fn mock_querier_v016(query: &WasmQuery) -> QuerierResult { .unwrap(), )), cw721_base::msg::QueryMsg::AllNftInfo { .. } => QuerierResult::Ok(ContractResult::Ok( - to_binary( + to_json_binary( // return v016 response &cw721_016::AllNftInfoResponse::> { access: cw721_016::OwnerOfResponse { @@ -150,19 +150,19 @@ fn mock_querier_v016(query: &WasmQuery) -> QuerierResult { .unwrap(), )), QueryMsg::ContractInfo {} => QuerierResult::Ok(ContractResult::Ok( - to_binary(&cw721_016::ContractInfoResponse { + to_json_binary(&cw721_016::ContractInfoResponse { name: "name".to_string(), symbol: "symbol".to_string(), }) .unwrap(), )), QueryMsg::NumTokens {} => QuerierResult::Ok(ContractResult::Ok( - to_binary(&cw721_016::NumTokensResponse { count: 1 }).unwrap(), + to_json_binary(&cw721_016::NumTokensResponse { count: 1 }).unwrap(), )), _ => QuerierResult::Err(cosmwasm_std::SystemError::Unknown {}), // throws error for Ownership query }, cosmwasm_std::WasmQuery::ContractInfo { .. } => QuerierResult::Ok(ContractResult::Ok( - to_binary(&ContractInfoResponse { + to_json_binary(&ContractInfoResponse { code_id: 0, creator: "creator".to_string(), admin: None, @@ -178,8 +178,8 @@ fn mock_querier_v016(query: &WasmQuery) -> QuerierResult { #[test] fn test_receive_nft() { // test case: receive nft from cw721-base - let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_binary( - &to_binary(&ContractInfoResponse { + let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_json( + &to_json_binary(&ContractInfoResponse { code_id: 0, creator: "creator".to_string(), admin: None, @@ -200,7 +200,7 @@ fn test_receive_nft() { let info = mock_info(NFT_ADDR, &[]); let token_id = "1"; let sender = "ekez".to_string(); - let msg = to_binary(&IbcOutgoingMsg { + let msg = to_json_binary(&IbcOutgoingMsg { receiver: "callum".to_string(), channel_id: "channel-1".to_string(), timeout: IbcTimeout::with_timestamp(Timestamp::from_seconds(42)), @@ -226,11 +226,11 @@ fn test_receive_nft() { SubMsg::new(CosmosMsg::::Ibc(IbcMsg::SendPacket { channel_id: channel_id.clone(), timeout: IbcTimeout::with_timestamp(Timestamp::from_seconds(42)), - data: to_binary(&NonFungibleTokenPacketData { + data: to_json_binary(&NonFungibleTokenPacketData { class_id: ClassId::new(NFT_ADDR), class_uri: None, class_data: Some( - to_binary(&CollectionData { + to_json_binary(&CollectionData { owner: Some(OWNER.to_string()), contract_info: expected_contract_info.clone(), name: "name".to_string(), @@ -282,7 +282,7 @@ fn test_receive_nft() { let info = mock_info(NFT_ADDR, &[]); let token_id = "1"; let sender = "ekez".to_string(); - let msg = to_binary(&IbcOutgoingMsg { + let msg = to_json_binary(&IbcOutgoingMsg { receiver: "callum".to_string(), channel_id: "channel-1".to_string(), timeout: IbcTimeout::with_timestamp(Timestamp::from_seconds(42)), @@ -308,11 +308,11 @@ fn test_receive_nft() { SubMsg::new(CosmosMsg::::Ibc(IbcMsg::SendPacket { channel_id: channel_id.clone(), timeout: IbcTimeout::with_timestamp(Timestamp::from_seconds(42)), - data: to_binary(&NonFungibleTokenPacketData { + data: to_json_binary(&NonFungibleTokenPacketData { class_id: ClassId::new(NFT_ADDR), class_uri: None, class_data: Some( - to_binary(&CollectionData { + to_json_binary(&CollectionData { owner: Some(OWNER.to_string()), contract_info: expected_contract_info, name: "name".to_string(), @@ -364,7 +364,7 @@ fn test_receive_nft() { let info = mock_info(NFT_ADDR, &[]); let token_id = "1"; let sender = "ekez".to_string(); - let msg = to_binary(&IbcOutgoingMsg { + let msg = to_json_binary(&IbcOutgoingMsg { receiver: "callum".to_string(), channel_id: "channel-1".to_string(), timeout: IbcTimeout::with_timestamp(Timestamp::from_seconds(42)), @@ -390,7 +390,7 @@ fn test_receive_nft() { SubMsg::new(CosmosMsg::::Ibc(IbcMsg::SendPacket { channel_id: channel_id.clone(), timeout: IbcTimeout::with_timestamp(Timestamp::from_seconds(42)), - data: to_binary(&NonFungibleTokenPacketData { + data: to_json_binary(&NonFungibleTokenPacketData { class_id: ClassId::new(NFT_ADDR), class_uri: None, class_data: None, @@ -439,7 +439,7 @@ fn test_receive_sets_uri() { let info = mock_info(NFT_ADDR, &[]); let token_id = TokenId::new("1"); let sender = "ekez".to_string(); - let msg = to_binary(&IbcOutgoingMsg { + let msg = to_json_binary(&IbcOutgoingMsg { receiver: "ekez".to_string(), channel_id: "channel-1".to_string(), timeout: IbcTimeout::with_timestamp(Timestamp::from_nanos(42)), @@ -455,8 +455,8 @@ fn test_receive_sets_uri() { .load(deps.as_ref().storage, ClassId::new(NFT_ADDR)) .unwrap(); assert_eq!(class.uri, None); - let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_binary( - &to_binary(&ContractInfoResponse { + let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_json( + &to_json_binary(&ContractInfoResponse { code_id: 0, creator: "creator".to_string(), admin: None, @@ -469,7 +469,7 @@ fn test_receive_sets_uri() { assert_eq!( class.data, Some( - to_binary(&CollectionData { + to_json_binary(&CollectionData { owner: Some(OWNER.to_string()), contract_info: expected_contract_info, name: "name".to_string(), diff --git a/packages/ics721/src/testing/ibc_tests.rs b/packages/ics721/src/testing/ibc_tests.rs index 555165da..3448c7a3 100644 --- a/packages/ics721/src/testing/ibc_tests.rs +++ b/packages/ics721/src/testing/ibc_tests.rs @@ -1,10 +1,10 @@ use cosmwasm_std::{ attr, - testing::{mock_dependencies, mock_env, mock_info, MockQuerier}, - to_binary, to_vec, Addr, Attribute, Binary, ContractResult, DepsMut, Empty, Env, - IbcAcknowledgement, IbcChannel, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcEndpoint, IbcOrder, - IbcPacket, IbcPacketReceiveMsg, IbcTimeout, Order, QuerierResult, Reply, Response, StdResult, - SubMsgResponse, SubMsgResult, Timestamp, WasmQuery, + testing::{mock_dependencies, mock_env, mock_info}, + to_json_binary, to_json_vec, Addr, Attribute, Binary, DepsMut, Empty, Env, IbcAcknowledgement, + IbcChannel, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcEndpoint, IbcOrder, IbcPacket, + IbcPacketReceiveMsg, IbcTimeout, Order, Reply, Response, StdResult, SubMsgResponse, + SubMsgResult, Timestamp, }; use crate::{ @@ -16,10 +16,7 @@ use crate::{ ibc_helpers::{ack_fail, ack_success, try_get_ack_error}, msg::{InstantiateMsg, QueryMsg}, query::Ics721Query, - state::{ - CollectionData, CLASS_ID_TO_NFT_CONTRACT, INCOMING_CLASS_TOKEN_TO_CHANNEL, - NFT_CONTRACT_TO_CLASS_ID, PO, - }, + state::{CollectionData, INCOMING_CLASS_TOKEN_TO_CHANNEL, NFT_CONTRACT_TO_CLASS_ID, PO}, token_types::{ClassId, TokenId}, utils::get_collection_data, ContractError, @@ -139,34 +136,13 @@ fn build_ics_packet( #[test] fn test_reply_cw721() { - let mut querier = MockQuerier::default(); - querier.update_wasm(|query| -> QuerierResult { - match query { - WasmQuery::Smart { - contract_addr: _, - msg: _, - } => QuerierResult::Ok(ContractResult::Ok( - to_binary(&cw721::ContractInfoResponse { - name: "wasm.address1/channel-10/address2".to_string(), - symbol: "wasm.address1/channel-10/address2".to_string(), - }) - .unwrap(), - )), - WasmQuery::Raw { .. } => QuerierResult::Ok(ContractResult::Ok(Binary::default())), - WasmQuery::ContractInfo { .. } => { - QuerierResult::Ok(ContractResult::Ok(Binary::default())) - } - _ => QuerierResult::Ok(ContractResult::Ok(Binary::default())), - } - }); let mut deps = mock_dependencies(); - deps.querier = querier; // This is a pre encoded message with the contract address // cosmos2contract // TODO: Can we form this via a function instead of hardcoding // So we can have different contract addresses - let reply_resp = "Cg9jb3Ntb3MyY29udHJhY3QSAA=="; + let reply_resp = "Cg9jb3Ntb3MyY29udHJhY3QSAA=="; // cosmos2contract let rep = Reply { id: INSTANTIATE_CW721_REPLY_ID, result: SubMsgResult::Ok(SubMsgResponse { @@ -175,6 +151,13 @@ fn test_reply_cw721() { }), }; + // save the class_id and cw721_addr, since reply assumes it has been stored before + let cw721_addr = Addr::unchecked("cosmos2contract"); + let class_id = ClassId::new("wasm.address1/channel-10/address2"); + NFT_CONTRACT_TO_CLASS_ID + .save(deps.as_mut().storage, cw721_addr.clone(), &class_id) + .unwrap(); + let res = Ics721Contract::default() .reply(deps.as_mut(), mock_env(), rep) .unwrap(); @@ -187,16 +170,6 @@ fn test_reply_cw721() { attr("cw721_addr", "cosmos2contract") ] ); - - let class_id = NFT_CONTRACT_TO_CLASS_ID - .load(deps.as_ref().storage, Addr::unchecked("cosmos2contract")) - .unwrap(); - let nft = CLASS_ID_TO_NFT_CONTRACT - .load(deps.as_ref().storage, class_id.clone()) - .unwrap(); - - assert_eq!(nft, Addr::unchecked("cosmos2contract")); - assert_eq!(class_id.to_string(), "wasm.address1/channel-10/address2"); } #[test] @@ -453,7 +426,7 @@ fn test_ibc_channel_connect_invalid_version_counterparty() { #[test] fn test_ibc_packet_receive() { - let data = to_binary(&NonFungibleTokenPacketData { + let data = to_json_binary(&NonFungibleTokenPacketData { class_id: ClassId::new("id"), class_uri: None, class_data: None, @@ -504,7 +477,7 @@ fn test_ibc_packet_receive_invalid_packet_data() { // the actual message used here is unimportant. this just // constructs a valud JSON blob that is not a valid ICS-721 // packet. - let data = to_binary(&QueryMsg::ClassMetadata { + let data = to_json_binary(&QueryMsg::ClassMetadata { class_id: "foobar".to_string(), }) .unwrap(); @@ -527,7 +500,7 @@ fn test_ibc_packet_receive_invalid_packet_data() { #[test] fn test_ibc_packet_receive_emits_memo() { - let data = to_binary(&NonFungibleTokenPacketData { + let data = to_json_binary(&NonFungibleTokenPacketData { class_id: ClassId::new("id"), class_uri: None, class_data: None, @@ -572,7 +545,7 @@ fn test_ibc_packet_receive_missmatched_lengths() { ); let packet = IbcPacketReceiveMsg::new( - mock_packet(to_binary(&data).unwrap()), + mock_packet(to_json_binary(&data).unwrap()), Addr::unchecked(RELAYER_ADDR), ); @@ -588,8 +561,8 @@ fn test_ibc_packet_receive_missmatched_lengths() { // More token data are provided than tokens. let token_data = Some(vec![ - to_binary("some_data_1").unwrap(), - to_binary("some_data_2").unwrap(), + to_json_binary("some_data_1").unwrap(), + to_json_binary("some_data_2").unwrap(), ]); let data = build_ics_packet( "bad kids", @@ -604,7 +577,7 @@ fn test_ibc_packet_receive_missmatched_lengths() { ); let packet = IbcPacketReceiveMsg::new( - mock_packet(to_binary(&data).unwrap()), + mock_packet(to_json_binary(&data).unwrap()), Addr::unchecked(RELAYER_ADDR), ); @@ -621,13 +594,13 @@ fn test_ibc_packet_receive_missmatched_lengths() { #[test] fn test_packet_json() { - let class_data = to_binary("some_class_data").unwrap(); // InNvbWVfY2xhc3NfZGF0YSI= + let class_data = to_json_binary("some_class_data").unwrap(); // InNvbWVfY2xhc3NfZGF0YSI= let token_data = vec![ // ["InNvbWVfdG9rZW5fZGF0YV8xIg==","InNvbWVfdG9rZW5fZGF0YV8yIg=="," // InNvbWVfdG9rZW5fZGF0YV8zIg=="] - to_binary("some_token_data_1").unwrap(), - to_binary("some_token_data_2").unwrap(), - to_binary("some_token_data_3").unwrap(), + to_json_binary("some_token_data_1").unwrap(), + to_json_binary("some_token_data_2").unwrap(), + to_json_binary("some_token_data_3").unwrap(), ]; let packet = build_ics_packet( "stars1zedxv25ah8fksmg2lzrndrpkvsjqgk4zt5ff7n", @@ -648,7 +621,7 @@ fn test_packet_json() { // TODO: test with non-null tokenData and classData. let expected = r#"{"classId":"stars1zedxv25ah8fksmg2lzrndrpkvsjqgk4zt5ff7n","classUri":"https://metadata-url.com/my-metadata","classData":"InNvbWVfY2xhc3NfZGF0YSI=","tokenIds":["1","2","3"],"tokenUris":["https://metadata-url.com/my-metadata1","https://metadata-url.com/my-metadata2","https://metadata-url.com/my-metadata3"],"tokenData":["InNvbWVfdG9rZW5fZGF0YV8xIg==","InNvbWVfdG9rZW5fZGF0YV8yIg==","InNvbWVfdG9rZW5fZGF0YV8zIg=="],"sender":"stars1zedxv25ah8fksmg2lzrndrpkvsjqgk4zt5ff7n","receiver":"wasm1fucynrfkrt684pm8jrt8la5h2csvs5cnldcgqc","memo":"some_memo"}"#; - let encdoded = String::from_utf8(to_vec(&packet).unwrap()).unwrap(); + let encdoded = String::from_utf8(to_json_vec(&packet).unwrap()).unwrap(); assert_eq!(expected, encdoded.as_str()); } @@ -656,7 +629,7 @@ fn test_packet_json() { fn test_no_receive_when_paused() { // Valid JSON, invalid ICS-721 packet. Tests that we check for // pause status before attempting validation. - let data = to_binary(&QueryMsg::ClassMetadata { + let data = to_json_binary(&QueryMsg::ClassMetadata { class_id: "foobar".to_string(), }) .unwrap(); diff --git a/packages/ics721/src/testing/integration_tests.rs b/packages/ics721/src/testing/integration_tests.rs index 25d8ace4..2a4d75f1 100644 --- a/packages/ics721/src/testing/integration_tests.rs +++ b/packages/ics721/src/testing/integration_tests.rs @@ -1,9 +1,10 @@ -use bech32::Variant; +use anyhow::Result; +use bech32::{decode, encode, FromBase32, ToBase32, Variant}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - from_binary, testing::MockApi, to_binary, Addr, Api, Binary, Deps, DepsMut, Empty, Env, GovMsg, - IbcTimeout, IbcTimeoutBlock, MemoryStorage, MessageInfo, Reply, Response, StdResult, Storage, - WasmMsg, + from_json, instantiate2_address, to_json_binary, Addr, Api, Binary, CanonicalAddr, Deps, + DepsMut, Empty, Env, GovMsg, IbcTimeout, IbcTimeoutBlock, MemoryStorage, MessageInfo, + RecoverPubkeyError, Reply, Response, StdError, StdResult, Storage, VerificationError, WasmMsg, }; use cw2::set_contract_version; use cw721_base::msg::{InstantiateMsg as Cw721InstantiateMsg, QueryMsg as Cw721QueryMsg}; @@ -13,7 +14,7 @@ use cw_multi_test::{ Executor, FailingModule, IbcAcceptingModule, Router, StakeKeeper, WasmKeeper, }; use cw_pause_once::PauseError; -use cw_storage_plus::Item; +use sha2::{digest::Update, Digest, Sha256}; use crate::{ execute::Ics721Execute, @@ -31,8 +32,14 @@ const ICS721_CREATOR: &str = "ics721-creator"; const CONTRACT_NAME: &str = "crates.io:ics721-base"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -const OWNER_SOURCE_CHAIN: &str = "juno1ke55z7catvdvnhvyyh0pkvs30t09me72vcxkh5"; -const TARGET_HRP: &str = "stars"; +// owner, aka "minter" +const COLLECTION_OWNER_TARGET_CHAIN: &str = "collection-minter-target-chain"; +const COLLECTION_OWNER_SOURCE_CHAIN: &str = "collection-minter-source-chain"; +const COLLECTION_CONTRACT_SOURCE_CHAIN: &str = "collection-contract-source-chain"; +const CHANNEL_TARGET_CHAIN: &str = "channel-1"; +const BECH32_PREFIX_HRP: &str = "stars"; +const NFT_OWNER_TARGET_CHAIN: &str = "nft-owner-target-chain"; +const ICS721_ADMIN_AND_PAUSER: &str = "ics721-pauser"; // copy of cosmwasm_std::ContractInfoResponse (marked as non-exhaustive) #[cw_serde] @@ -90,42 +97,162 @@ fn no_init( ) { } -#[derive(Debug)] -struct Bech32AddressGenerator { - pub hrp: String, +#[derive(Default)] +pub struct MockAddressGenerator; + +impl AddressGenerator for MockAddressGenerator { + fn contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + code_id: u64, + instance_id: u64, + ) -> Result { + let canonical_addr = Self::instantiate_address(code_id, instance_id); + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } + + fn predictable_contract_address( + &self, + api: &dyn Api, + _storage: &mut dyn Storage, + _code_id: u64, + _instance_id: u64, + checksum: &[u8], + creator: &CanonicalAddr, + salt: &[u8], + ) -> Result { + let canonical_addr = instantiate2_address(checksum, creator, salt)?; + Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?)) + } } -const COUNT: Item = Item::new("count"); +impl MockAddressGenerator { + // non-predictable contract address generator, see `BuildContractAddressClassic` + // implementation in wasmd: https://github.com/CosmWasm/wasmd/blob/main/x/wasm/keeper/addresses.go#L35-L42 + fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr { + let mut key = Vec::::new(); + key.extend_from_slice(b"wasm\0"); + key.extend_from_slice(&code_id.to_be_bytes()); + key.extend_from_slice(&instance_id.to_be_bytes()); + let module = Sha256::digest("module".as_bytes()); + let result = Sha256::new() + .chain(module) + .chain(key) + .finalize() + .to_vec() + .into(); + return result; + } +} +pub struct MockApiBech32 { + prefix: &'static str, +} -impl Bech32AddressGenerator { - pub const fn new(hrp: String) -> Self { - Self { hrp } +impl MockApiBech32 { + pub fn new(prefix: &'static str) -> Self { + Self { prefix } } } -#[cw_serde] -pub struct CustomClassData { - pub foo: Option, +impl Api for MockApiBech32 { + fn addr_validate(&self, input: &str) -> StdResult { + let canonical = self.addr_canonicalize(input)?; + let normalized = self.addr_humanize(&canonical)?; + if input != normalized { + Err(StdError::generic_err( + "Invalid input: address not normalized", + )) + } else { + Ok(Addr::unchecked(input)) + } + } + + fn addr_canonicalize(&self, input: &str) -> StdResult { + if let Ok((prefix, decoded, Variant::Bech32)) = decode(input) { + if prefix == self.prefix { + if let Ok(bytes) = Vec::::from_base32(&decoded) { + return Ok(bytes.into()); + } + } + } + Err(StdError::generic_err(format!("Invalid input: {}", input))) + } + + fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { + if let Ok(encoded) = encode( + self.prefix, + canonical.as_slice().to_base32(), + Variant::Bech32, + ) { + Ok(Addr::unchecked(encoded)) + } else { + Err(StdError::generic_err("Invalid canonical address")) + } + } + + fn secp256k1_verify( + &self, + _message_hash: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn secp256k1_recover_pubkey( + &self, + _message_hash: &[u8], + _signature: &[u8], + _recovery_param: u8, + ) -> Result, RecoverPubkeyError> { + unimplemented!() + } + + fn ed25519_verify( + &self, + _message: &[u8], + _signature: &[u8], + _public_key: &[u8], + ) -> Result { + unimplemented!() + } + + fn ed25519_batch_verify( + &self, + _messages: &[&[u8]], + _signatures: &[&[u8]], + _public_keys: &[&[u8]], + ) -> Result { + unimplemented!() + } + + fn debug(&self, _message: &str) { + unimplemented!() + } } -impl AddressGenerator for Bech32AddressGenerator { - fn next_address(&self, storage: &mut dyn Storage) -> Addr { - let count = match COUNT.may_load(storage) { - Ok(Some(count)) => count, - _ => 0, - }; - let data = bech32::u5::try_from_u8(count).unwrap(); - let encoded_addr = bech32::encode(self.hrp.as_str(), vec![data], Variant::Bech32).unwrap(); - let addr = Addr::unchecked(encoded_addr); - COUNT.save(storage, &(count + 1)).unwrap(); - addr +impl MockApiBech32 { + pub fn addr_make(&self, input: &str) -> Addr { + let digest = Sha256::digest(input).to_vec(); + match encode(self.prefix, digest.to_base32(), Variant::Bech32) { + Ok(address) => Addr::unchecked(address), + Err(reason) => panic!("Generating address failed with reason: {reason}"), + } } } +#[cw_serde] +pub struct CustomClassData { + pub foo: Option, + // even there is collection name, but it doesn't apply to CollectionData type + pub name: String, +} + struct Test { app: App< BankKeeper, - MockApi, + MockApiBech32, MemoryStorage, FailingModule, WasmKeeper, @@ -133,25 +260,30 @@ struct Test { DistributionKeeper, IbcAcceptingModule, >, - minter: Addr, - cw721_id: u64, - cw721: Addr, + // origin cw721 contract on source chain for interchain transfers to other target chains + source_cw721_owner: Addr, + source_cw721_id: u64, + source_cw721: Addr, + // depending on test cast, it is ics721 either source or target chain ics721_id: u64, ics721: Addr, nfts_minted: usize, } impl Test { - fn new(proxy: bool, pauser: Option, cw721_code: Box>) -> Self { + fn new( + proxy: bool, + admin_and_pauser: Option, + cw721_code: Box>, + ) -> Self { let mut app = AppBuilder::new() - .with_wasm::, WasmKeeper>( - WasmKeeper::new_with_custom_address_generator(Bech32AddressGenerator::new( - TARGET_HRP.to_string(), - )), + .with_wasm::>( + WasmKeeper::new().with_address_generator(MockAddressGenerator), ) - .with_ibc(IbcAcceptingModule) + .with_ibc(IbcAcceptingModule::default()) + .with_api(MockApiBech32::new(BECH32_PREFIX_HRP)) .build(no_init); - let cw721_id = app.store_code(cw721_code); + let source_cw721_id = app.store_code(cw721_code); let ics721_id = app.store_code(ics721_contract()); use cw721_rate_limited_proxy as rlp; @@ -160,7 +292,7 @@ impl Test { let proxy_id = app.store_code(proxy_contract()); Some(ContractInstantiateInfo { code_id: proxy_id, - msg: to_binary(&rlp::msg::InstantiateMsg { + msg: to_json_binary(&rlp::msg::InstantiateMsg { rate_limit: rlp::Rate::PerBlock(10), origin: None, }) @@ -175,27 +307,31 @@ impl Test { let ics721 = app .instantiate_contract( ics721_id, - Addr::unchecked(ICS721_CREATOR), + app.api().addr_make(ICS721_CREATOR), &InstantiateMsg { - cw721_base_code_id: cw721_id, + cw721_base_code_id: source_cw721_id, proxy: proxy.clone(), - pauser: pauser.clone(), + pauser: admin_and_pauser + .clone() + .and_then(|p| Some(app.api().addr_make(&p).to_string())), }, &[], "ics721-base", - pauser.clone(), + admin_and_pauser + .clone() + .and_then(|p| Some(app.api().addr_make(&p).to_string())), ) .unwrap(); - let minter = Addr::unchecked("minter"); - let cw721 = app + let source_cw721_owner = app.api().addr_make(COLLECTION_OWNER_SOURCE_CHAIN); + let source_cw721 = app .instantiate_contract( - cw721_id, - minter.clone(), + source_cw721_id, + source_cw721_owner.clone(), &Cw721InstantiateMsg { name: "name".to_string(), symbol: "symbol".to_string(), - minter: minter.to_string(), + minter: source_cw721_owner.to_string(), }, &[], "cw721-base", @@ -205,9 +341,9 @@ impl Test { Self { app, - minter, - cw721_id, - cw721, + source_cw721_owner, + source_cw721_id, + source_cw721, ics721_id, ics721, nfts_minted: 0, @@ -310,8 +446,8 @@ impl Test { self.app .execute_contract( - self.minter.clone(), - self.cw721.clone(), + self.source_cw721_owner.clone(), + self.source_cw721.clone(), &cw721_base::msg::ExecuteMsg::::Mint { token_id: self.nfts_minted.to_string(), owner: owner.to_string(), @@ -370,7 +506,7 @@ fn test_instantiate() { // check stores are properly initialized let cw721_id = test.query_cw721_id(); - assert_eq!(cw721_id, test.cw721_id); + assert_eq!(cw721_id, test.source_cw721_id); let nft_contracts: Vec<(String, Addr)> = test.query_nft_contracts(); assert_eq!(nft_contracts, Vec::<(String, Addr)>::new()); let outgoing_channels = test.query_outgoing_channels(); @@ -382,20 +518,31 @@ fn test_instantiate() { #[test] fn test_do_instantiate_and_mint_weird_data() { let mut test = Test::new(false, None, cw721_base_contract()); - + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), test.ics721, &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "ekez".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id), uri: None, data: Some( - to_binary(&CollectionData { - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + owner: Some( + // incoming collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), name: "name".to_string(), symbol: "symbol".to_string(), @@ -419,18 +566,24 @@ fn test_do_instantiate_and_mint_weird_data() { #[test] fn test_do_instantiate_and_mint() { - // test case: instantiate cw721 with no ClassData + // test case: instantiate cw721 with no ClassData (without owner, name, and symbol) { let mut test = Test::new(false, None, cw721_base_contract()); + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "ekez".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), data: None, // no class data }, @@ -442,7 +595,7 @@ fn test_do_instantiate_and_mint() { }, Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }, ], @@ -454,30 +607,33 @@ fn test_do_instantiate_and_mint() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let nft_contracts = test.query_nft_contracts(); assert_eq!(nft_contracts.len(), 1); - assert_eq!(nft_contracts[0].0, "bad kids"); + assert_eq!(nft_contracts[0].0, class_id.to_string()); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( test.ics721.clone(), &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - // check contract info is properly set + // check name and symbol contains class id for instantiated nft contract let contract_info: cw721::ContractInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Cw721QueryMsg::::ContractInfo {}) + .query_wasm_smart( + nft_contract.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) .unwrap(); assert_eq!( contract_info, cw721::ContractInfoResponse { - name: "bad kids".to_string(), - symbol: "bad kids".to_string() + name: class_id.to_string(), // name is set to class_id + symbol: class_id.to_string() // symbol is set to class_id } ); @@ -486,13 +642,12 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "1".to_string(), }, ) .unwrap(); - assert_eq!( token_info.token_uri, Some("https://moonphase.is/image.svg".to_string()) @@ -501,31 +656,28 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "2".to_string(), }, ) .unwrap(); + assert_eq!(token_info.token_uri, Some("https://foo.bar".to_string())); - assert_eq!( - token_info.token_uri, - Some("https://moonphase.is/image.svg".to_string()) - ); - - // Check that we can transfer the NFT via the ICS721 interface. + // After transfer to target, test owner can do any action, like transfer, on collection test.app .execute_contract( - Addr::unchecked("ekez"), - nft.clone(), + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract.clone(), &cw721_base::msg::ExecuteMsg::::TransferNft { - recipient: nft.to_string(), + recipient: nft_contract.to_string(), token_id: "1".to_string(), }, &[], ) .unwrap(); + // ics721 owner query and check nft contract owns it let owner: cw721::OwnerOfResponse = test .app .wrap() @@ -533,48 +685,57 @@ fn test_do_instantiate_and_mint() { test.ics721, &QueryMsg::Owner { token_id: "1".to_string(), - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); + assert_eq!(owner.owner, nft_contract.to_string()); - assert_eq!(owner.owner, nft.to_string()); - - // Check that this state matches the state of the underlying - // cw721. + // check cw721 owner query matches ics721 owner query let base_owner: cw721::OwnerOfResponse = test .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::OwnerOf { token_id: "1".to_string(), include_expired: None, }, ) .unwrap(); - assert_eq!(base_owner, owner); } - // test case: instantiate cw721 with ClassData containing owner + // test case: instantiate cw721 with ClassData containing owner, name, and symbol { let mut test = Test::new(false, None, cw721_base_contract()); + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "ekez".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), data: Some( - to_binary(&CollectionData { - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + owner: Some( + // incoming collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), - name: "name".to_string(), - symbol: "symbol".to_string(), + name: "ark".to_string(), + symbol: "protocol".to_string(), num_tokens: 1, }) .unwrap(), @@ -588,7 +749,7 @@ fn test_do_instantiate_and_mint() { }, Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }, ], @@ -600,30 +761,33 @@ fn test_do_instantiate_and_mint() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let nft_contracts = test.query_nft_contracts(); assert_eq!(nft_contracts.len(), 1); - assert_eq!(nft_contracts[0].0, "bad kids"); + assert_eq!(nft_contracts[0].0, class_id.to_string()); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( test.ics721.clone(), &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - // check contract info is properly set + // check name and symbol is using class data for instantiated nft contract let contract_info: cw721::ContractInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Cw721QueryMsg::::ContractInfo {}) + .query_wasm_smart( + nft_contract.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) .unwrap(); assert_eq!( contract_info, cw721::ContractInfoResponse { - name: "bad kids".to_string(), - symbol: "bad kids".to_string() + name: "ark".to_string(), + symbol: "protocol".to_string() } ); @@ -632,13 +796,12 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "1".to_string(), }, ) .unwrap(); - assert_eq!( token_info.token_uri, Some("https://moonphase.is/image.svg".to_string()) @@ -647,31 +810,28 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "2".to_string(), }, ) .unwrap(); + assert_eq!(token_info.token_uri, Some("https://foo.bar".to_string())); - assert_eq!( - token_info.token_uri, - Some("https://moonphase.is/image.svg".to_string()) - ); - - // Check that we can transfer the NFT via the ICS721 interface. + // After transfer to target, test owner can do any action, like transfer, on collection test.app .execute_contract( - Addr::unchecked("ekez"), - nft.clone(), + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract.clone(), // new recipient &cw721_base::msg::ExecuteMsg::::TransferNft { - recipient: nft.to_string(), + recipient: nft_contract.to_string(), token_id: "1".to_string(), }, &[], ) .unwrap(); + // ics721 owner query and check nft contract owns it let owner: cw721::OwnerOfResponse = test .app .wrap() @@ -679,45 +839,56 @@ fn test_do_instantiate_and_mint() { test.ics721, &QueryMsg::Owner { token_id: "1".to_string(), - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); + assert_eq!(owner.owner, nft_contract.to_string()); - assert_eq!(owner.owner, nft.to_string()); - - // Check that this state matches the state of the underlying - // cw721. + // check cw721 owner query matches ics721 owner query let base_owner: cw721::OwnerOfResponse = test .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::OwnerOf { token_id: "1".to_string(), include_expired: None, }, ) .unwrap(); - assert_eq!(base_owner, owner); } - // test case: instantiate cw721 with different CustomClassData with no owner info + // test case: instantiate cw721 with CustomClassData (without owner, name, and symbol) { let mut test = Test::new(false, None, cw721_base_contract()); + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "ekez".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), data: Some( - to_binary(&CustomClassData { - foo: Some(OWNER_SOURCE_CHAIN.to_string()), + // CustomClassData doesn't apply to CollectionData type and won't be considered + // collection name wont be transferred to instantiated nft contract + to_json_binary(&CustomClassData { + foo: Some( + test.app + .api() + .addr_make(COLLECTION_OWNER_TARGET_CHAIN) + .to_string(), + ), + name: "colection-name".to_string(), }) .unwrap(), ), @@ -730,7 +901,7 @@ fn test_do_instantiate_and_mint() { }, Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }, ], @@ -742,30 +913,33 @@ fn test_do_instantiate_and_mint() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let nft_contracts = test.query_nft_contracts(); assert_eq!(nft_contracts.len(), 1); - assert_eq!(nft_contracts[0].0, "bad kids"); + assert_eq!(nft_contracts[0].0, class_id.to_string()); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( test.ics721.clone(), &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - // check contract info is properly set + // check name and symbol contains class id for instantiated nft contract let contract_info: cw721::ContractInfoResponse = test .app .wrap() - .query_wasm_smart(nft.clone(), &Cw721QueryMsg::::ContractInfo {}) + .query_wasm_smart( + nft_contract.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) .unwrap(); assert_eq!( contract_info, cw721::ContractInfoResponse { - name: "bad kids".to_string(), - symbol: "bad kids".to_string() + name: class_id.to_string(), + symbol: class_id.to_string() } ); @@ -774,13 +948,12 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "1".to_string(), }, ) .unwrap(); - assert_eq!( token_info.token_uri, Some("https://moonphase.is/image.svg".to_string()) @@ -789,31 +962,28 @@ fn test_do_instantiate_and_mint() { .app .wrap() .query_wasm_smart( - nft.clone(), + nft_contract.clone(), &cw721::Cw721QueryMsg::NftInfo { token_id: "2".to_string(), }, ) .unwrap(); + assert_eq!(token_info.token_uri, Some("https://foo.bar".to_string())); - assert_eq!( - token_info.token_uri, - Some("https://moonphase.is/image.svg".to_string()) - ); - - // Check that we can transfer the NFT via the ICS721 interface. + // After transfer to target, test owner can do any action, like transfer, on collection test.app .execute_contract( - Addr::unchecked("ekez"), - nft.clone(), + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract.clone(), &cw721_base::msg::ExecuteMsg::::TransferNft { - recipient: nft.to_string(), + recipient: nft_contract.to_string(), // new owner token_id: "1".to_string(), }, &[], ) .unwrap(); + // ics721 owner query and check nft contract owns it let owner: cw721::OwnerOfResponse = test .app .wrap() @@ -821,50 +991,329 @@ fn test_do_instantiate_and_mint() { test.ics721, &QueryMsg::Owner { token_id: "1".to_string(), - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); - assert_eq!(owner.owner, nft.to_string()); + assert_eq!(owner.owner, nft_contract.to_string()); - // Check that this state matches the state of the underlying - // cw721. + // check cw721 owner query matches ics721 owner query let base_owner: cw721::OwnerOfResponse = test .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::OwnerOf { token_id: "1".to_string(), include_expired: None, }, ) .unwrap(); - assert_eq!(base_owner, owner); } } +#[test] +fn test_do_instantiate_and_mint_2_different_collections() { + // test case: instantiate two cw721 contracts with different class id and make sure instantiate2 creates 2 different, predictable contracts + { + let mut test = Test::new(false, None, cw721_base_contract()); + let collection_contract_source_chain_1 = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id_1 = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain_1 + ); + let collection_contract_source_chain_2 = ClassId::new(test.app.api().addr_make("other")); + let class_id_2 = format!( + "wasm.{}/{}/{}", + test.ics721, "channel-123567890", collection_contract_source_chain_2 + ); + + // create contract 1 + test.app + .execute_contract( + test.ics721.clone(), + test.ics721.clone(), + &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), + create: VoucherCreation { + class: Class { + id: ClassId::new(class_id_1.clone()), + uri: Some("https://moonphase.is".to_string()), + data: None, // no class data + }, + tokens: vec![ + Token { + id: TokenId::new("1"), + uri: Some("https://moonphase.is/image.svg".to_string()), + data: None, + }, + Token { + id: TokenId::new("2"), + uri: Some("https://foo.bar".to_string()), + data: None, + }, + ], + }, + }), + &[], + ) + .unwrap(); + // create contract 2 + test.app + .execute_contract( + test.ics721.clone(), + test.ics721.clone(), + &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), + create: VoucherCreation { + class: Class { + id: ClassId::new(class_id_2.clone()), + uri: Some("https://moonphase.is".to_string()), + data: None, // no class data + }, + tokens: vec![ + Token { + id: TokenId::new("1"), + uri: Some("https://mr.t".to_string()), + data: None, + }, + Token { + id: TokenId::new("2"), + uri: Some("https://ark.protocol".to_string()), + data: None, + }, + ], + }, + }), + &[], + ) + .unwrap(); + // Check entry added in CLASS_ID_TO_NFT_CONTRACT + let nft_contracts = test.query_nft_contracts(); + assert_eq!(nft_contracts.len(), 2); + assert_eq!(nft_contracts[0].0, class_id_1.to_string()); + assert_eq!(nft_contracts[1].0, class_id_2.to_string()); + // Get the address of the instantiated NFT. + let nft_contract_1: Addr = test + .app + .wrap() + .query_wasm_smart( + test.ics721.clone(), + &QueryMsg::NftContract { + class_id: class_id_1.to_string(), + }, + ) + .unwrap(); + let nft_contract_2: Addr = test + .app + .wrap() + .query_wasm_smart( + test.ics721.clone(), + &QueryMsg::NftContract { + class_id: class_id_2.to_string(), + }, + ) + .unwrap(); + + // check name and symbol contains class id for instantiated nft contract + let contract_info_1: cw721::ContractInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) + .unwrap(); + let contract_info_2: cw721::ContractInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2.clone(), + &Cw721QueryMsg::::ContractInfo {}, + ) + .unwrap(); + assert_eq!( + contract_info_1, + cw721::ContractInfoResponse { + name: class_id_1.to_string(), // name is set to class_id + symbol: class_id_1.to_string() // symbol is set to class_id + } + ); + assert_eq!( + contract_info_2, + cw721::ContractInfoResponse { + name: class_id_2.to_string(), // name is set to class_id + symbol: class_id_2.to_string() // symbol is set to class_id + } + ); + + // Check that token_uri was set properly. + let token_info_1_1: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "1".to_string(), + }, + ) + .unwrap(); + let token_info_2_1: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "1".to_string(), + }, + ) + .unwrap(); + assert_eq!( + token_info_1_1.token_uri, + Some("https://moonphase.is/image.svg".to_string()) + ); + assert_eq!(token_info_2_1.token_uri, Some("https://mr.t".to_string())); + let token_info_1_2: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "2".to_string(), + }, + ) + .unwrap(); + let token_info_2_2: cw721::NftInfoResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2.clone(), + &cw721::Cw721QueryMsg::NftInfo { + token_id: "2".to_string(), + }, + ) + .unwrap(); + assert_eq!( + token_info_1_2.token_uri, + Some("https://foo.bar".to_string()) + ); + assert_eq!( + token_info_2_2.token_uri, + Some("https://ark.protocol".to_string()) + ); + + // After transfer to target, test owner can do any action, like transfer, on collection + test.app + .execute_contract( + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract_1.clone(), + &cw721_base::msg::ExecuteMsg::::TransferNft { + recipient: nft_contract_1.to_string(), + token_id: "1".to_string(), + }, + &[], + ) + .unwrap(); + test.app + .execute_contract( + test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN), + nft_contract_2.clone(), + &cw721_base::msg::ExecuteMsg::::TransferNft { + recipient: nft_contract_2.to_string(), + token_id: "1".to_string(), + }, + &[], + ) + .unwrap(); + + // ics721 owner query and check nft contract owns it + let owner_1: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + test.ics721.clone(), + &QueryMsg::Owner { + token_id: "1".to_string(), + class_id: class_id_1.to_string(), + }, + ) + .unwrap(); + let owner_2: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + test.ics721, + &QueryMsg::Owner { + token_id: "1".to_string(), + class_id: class_id_2.to_string(), + }, + ) + .unwrap(); + assert_eq!(owner_1.owner, nft_contract_1.to_string()); + assert_eq!(owner_2.owner, nft_contract_2.to_string()); + + // check cw721 owner query matches ics721 owner query + let base_owner_1: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_1, + &cw721::Cw721QueryMsg::OwnerOf { + token_id: "1".to_string(), + include_expired: None, + }, + ) + .unwrap(); + let base_owner_2: cw721::OwnerOfResponse = test + .app + .wrap() + .query_wasm_smart( + nft_contract_2, + &cw721::Cw721QueryMsg::OwnerOf { + token_id: "1".to_string(), + include_expired: None, + }, + ) + .unwrap(); + assert_eq!(base_owner_1, owner_1); + assert_eq!(base_owner_2, owner_2); + } +} + #[test] fn test_do_instantiate_and_mint_no_instantiate() { let mut test = Test::new(false, None, cw721_base_contract()); - - // This will instantiate a new contract for the class ID and then - // do a mint. + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); + // Check calling CreateVouchers twice with same class id + // on 2nd call it will not instantiate a new contract, + // instead it will just mint the token on existing contract test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "ekez".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), data: Some( - to_binary(&CollectionData { - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + owner: Some( + // incoming collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), name: "name".to_string(), symbol: "symbol".to_string(), @@ -887,19 +1336,19 @@ fn test_do_instantiate_and_mint_no_instantiate() { // Check entry added in CLASS_ID_TO_NFT_CONTRACT let class_id_to_nft_contract = test.query_nft_contracts(); assert_eq!(class_id_to_nft_contract.len(), 1); - assert_eq!(class_id_to_nft_contract[0].0, "bad kids"); + assert_eq!(class_id_to_nft_contract[0].0, class_id.to_string()); - // This will only do a mint as the contract for the class ID has + // 2nd call will only do a mint as the contract for the class ID has // already been instantiated. test.app .execute_contract( test.ics721.clone(), test.ics721.clone(), &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "ekez".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id.clone()), uri: Some("https://moonphase.is".to_string()), // unlike above in 1st transfer, here on 2nd transfer no classdata is provided! // this won't affect collection since it's already instantiated @@ -907,7 +1356,7 @@ fn test_do_instantiate_and_mint_no_instantiate() { }, tokens: vec![Token { id: TokenId::new("2"), - uri: Some("https://moonphase.is/image.svg".to_string()), + uri: Some("https://foo.bar".to_string()), data: None, }], }, @@ -921,13 +1370,13 @@ fn test_do_instantiate_and_mint_no_instantiate() { assert_eq!(class_id_to_nft_contract.len(), 1); // Get the address of the instantiated NFT. - let nft: Addr = test + let nft_contract: Addr = test .app .wrap() .query_wasm_smart( test.ics721, &QueryMsg::NftContract { - class_id: "bad kids".to_string(), + class_id: class_id.to_string(), }, ) .unwrap(); @@ -937,36 +1386,46 @@ fn test_do_instantiate_and_mint_no_instantiate() { .app .wrap() .query_wasm_smart( - nft, + nft_contract, &cw721::Cw721QueryMsg::AllTokens { start_after: None, limit: None, }, ) .unwrap(); - assert_eq!(tokens.tokens, vec!["1".to_string(), "2".to_string()]) } #[test] fn test_do_instantiate_and_mint_permissions() { let mut test = Test::new(false, None, cw721_base_contract()); - + let collection_contract_source_chain = + ClassId::new(test.app.api().addr_make(COLLECTION_CONTRACT_SOURCE_CHAIN)); + let class_id = format!( + "wasm.{}/{}/{}", + test.ics721, CHANNEL_TARGET_CHAIN, collection_contract_source_chain + ); // Method is only callable by the contract itself. let err: ContractError = test .app .execute_contract( - Addr::unchecked("notIcs721"), + test.app.api().addr_make("notIcs721"), test.ics721, &ExecuteMsg::Callback(CallbackMsg::CreateVouchers { - receiver: "ekez".to_string(), + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), create: VoucherCreation { class: Class { - id: ClassId::new("bad kids"), + id: ClassId::new(class_id), uri: Some("https://moonphase.is".to_string()), data: Some( - to_binary(&CollectionData { - owner: Some(OWNER_SOURCE_CHAIN.to_string()), + to_json_binary(&CollectionData { + owner: Some( + // incoming collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: Default::default(), name: "name".to_string(), symbol: "symbol".to_string(), @@ -987,7 +1446,6 @@ fn test_do_instantiate_and_mint_permissions() { .unwrap_err() .downcast() .unwrap(); - assert_eq!(err, ContractError::Unauthorized {}); } @@ -995,18 +1453,17 @@ fn test_do_instantiate_and_mint_permissions() { #[test] fn test_no_proxy_unauthorized() { let mut test = Test::new(false, None, cw721_base_contract()); - let err: ContractError = test .app .execute_contract( - Addr::unchecked("proxy"), + test.app.api().addr_make("proxy"), test.ics721, &ExecuteMsg::ReceiveProxyNft { eyeball: "nft".to_string(), msg: cw721::Cw721ReceiveMsg { - sender: "ekez".to_string(), + sender: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), token_id: "1".to_string(), - msg: to_binary("").unwrap(), + msg: to_json_binary("").unwrap(), }, }, &[], @@ -1014,41 +1471,47 @@ fn test_no_proxy_unauthorized() { .unwrap_err() .downcast() .unwrap(); - assert_eq!(err, ContractError::Unauthorized {}); } #[test] fn test_proxy_authorized() { let mut test = Test::new(true, None, cw721_base_contract()); - let proxy_address: Option = test .app .wrap() .query_wasm_smart(&test.ics721, &QueryMsg::Proxy {}) .unwrap(); + // check proxy is set let proxy_address = proxy_address.expect("expected a proxy"); - let cw721_id = test.app.store_code(cw721_base_contract()); - let cw721 = test + // create collection and mint NFT for sending to proxy + let source_cw721_id = test.app.store_code(cw721_base_contract()); + let source_cw721 = test .app .instantiate_contract( - cw721_id, - Addr::unchecked("ekez"), + source_cw721_id, + test.app.api().addr_make("ekez"), &cw721_base::InstantiateMsg { name: "token".to_string(), symbol: "nonfungible".to_string(), - minter: "ekez".to_string(), + minter: test + .app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), }, &[], "label cw721", None, ) .unwrap(); + // simplify: instead of `send_nft` to proxy, and proxy transfer NFT to ics721 and call receiveproy, + // here it is directly transfer to ics721 and then call receiveproxy test.app .execute_contract( - Addr::unchecked("ekez"), - cw721.clone(), + test.app.api().addr_make(COLLECTION_OWNER_SOURCE_CHAIN), + source_cw721.clone(), &cw721_base::ExecuteMsg::::Mint { token_id: "1".to_string(), owner: test.ics721.to_string(), @@ -1059,17 +1522,24 @@ fn test_proxy_authorized() { ) .unwrap(); + // ics721 receives NFT from proxy, + // if - and only if - nft is escrowed by ics721, ics721 will interchain transfer NFT! + // otherwise proxy is unauthorised to transfer NFT test.app .execute_contract( proxy_address, test.ics721, &ExecuteMsg::ReceiveProxyNft { - eyeball: cw721.into_string(), + eyeball: source_cw721.into_string(), msg: cw721::Cw721ReceiveMsg { - sender: "ekez".to_string(), + sender: test + .app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), token_id: "1".to_string(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "ekez".to_string(), + msg: to_json_binary(&IbcOutgoingMsg { + receiver: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), channel_id: "channel-0".to_string(), timeout: IbcTimeout::with_block(IbcTimeoutBlock { revision: 0, @@ -1090,19 +1560,21 @@ fn test_receive_nft() { // test case: receive nft from cw721-base { let mut test = Test::new(false, None, cw721_base_contract()); - // mint and escrowed/owned by ics721 + // simplify: mint and escrowed/owned by ics721, as a precondition for receive nft let token_id = test.execute_cw721_mint(test.ics721.clone()).unwrap(); - + // ics721 receives NFT from sender/collection contract, + // if - and only if - nft is escrowed by ics721, ics721 will interchain transfer NFT! + // otherwise proxy is unauthorised to transfer NFT let res = test .app .execute_contract( - test.cw721.clone(), + test.source_cw721.clone(), test.ics721, &ExecuteMsg::ReceiveNft(cw721::Cw721ReceiveMsg { - sender: test.minter.to_string(), + sender: test.source_cw721_owner.to_string(), token_id: token_id.clone(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "mr-t".to_string(), + msg: to_json_binary(&IbcOutgoingMsg { + receiver: NFT_OWNER_TARGET_CHAIN.to_string(), // nft owner for other chain, on this chain ics721 is owner channel_id: "channel-0".to_string(), timeout: IbcTimeout::with_block(IbcTimeoutBlock { revision: 0, @@ -1115,16 +1587,21 @@ fn test_receive_nft() { &[], ) .unwrap(); + + // get class data (containing collection data) from response let event = res.events.into_iter().find(|e| e.ty == "wasm").unwrap(); let class_data_attribute = event .attributes .into_iter() .find(|a| a.key == "class_data") .unwrap(); - let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_binary( - &to_binary(&ContractInfoResponse { - code_id: test.cw721_id, - creator: test.minter.to_string(), + // check collection data matches with data from source nft contract + let expected_contract_info: cosmwasm_std::ContractInfoResponse = + // workaround using from_json/to_json_binary since ContractInfoResponse is non-exhaustive, can't be created directly + from_json( + &to_json_binary(&ContractInfoResponse { + code_id: test.source_cw721_id, + creator: test.source_cw721_owner.to_string(), admin: None, pinned: false, ibc_port: None, @@ -1132,8 +1609,11 @@ fn test_receive_nft() { .unwrap(), ) .unwrap(); - let expected_collection_data = to_binary(&CollectionData { - owner: Some(test.minter.to_string()), + let expected_collection_data = to_json_binary(&CollectionData { + owner: Some( + // collection data from source chain + test.source_cw721_owner.to_string(), + ), contract_info: expected_contract_info, name: "name".to_string(), symbol: "symbol".to_string(), @@ -1145,22 +1625,24 @@ fn test_receive_nft() { format!("{:?}", expected_collection_data) ); } - // test case: receive nft from old/v016 cw721-base + // test case: backward compatibility - receive nft also works for old/v016 cw721-base { let mut test = Test::new(false, None, cw721_v016_base_contract()); - // mint and escrowed/owned by ics721 + // simplify: mint and escrowed/owned by ics721, as a precondition for receive nft let token_id = test.execute_cw721_mint(test.ics721.clone()).unwrap(); - + // ics721 receives NFT from sender/collection contract, + // if - and only if - nft is escrowed by ics721, ics721 will interchain transfer NFT! + // otherwise proxy is unauthorised to transfer NFT let res = test .app .execute_contract( - test.cw721.clone(), + test.source_cw721.clone(), test.ics721, &ExecuteMsg::ReceiveNft(cw721::Cw721ReceiveMsg { - sender: test.minter.to_string(), + sender: test.source_cw721_owner.to_string(), token_id: token_id.clone(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "mr-t".to_string(), + msg: to_json_binary(&IbcOutgoingMsg { + receiver: NFT_OWNER_TARGET_CHAIN.to_string(), // nft owner for other chain, on this chain ics721 is owner channel_id: "channel-0".to_string(), timeout: IbcTimeout::with_block(IbcTimeoutBlock { revision: 0, @@ -1173,16 +1655,21 @@ fn test_receive_nft() { &[], ) .unwrap(); + + // get class data (containing collection data) from response let event = res.events.into_iter().find(|e| e.ty == "wasm").unwrap(); let class_data_attribute = event .attributes .into_iter() .find(|a| a.key == "class_data") .unwrap(); - let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_binary( - &to_binary(&ContractInfoResponse { - code_id: test.cw721_id, - creator: test.minter.to_string(), + // check collection data matches with data from source nft contract + let expected_contract_info: cosmwasm_std::ContractInfoResponse = + // workaround using from_json/to_json_binary since ContractInfoResponse is non-exhaustive, can't be created directly + from_json( + &to_json_binary(&ContractInfoResponse { + code_id: test.source_cw721_id, + creator: test.source_cw721_owner.to_string(), admin: None, pinned: false, ibc_port: None, @@ -1190,8 +1677,14 @@ fn test_receive_nft() { .unwrap(), ) .unwrap(); - let expected_collection_data = to_binary(&CollectionData { - owner: Some(test.minter.to_string()), + let expected_collection_data = to_json_binary(&CollectionData { + owner: Some( + // collection data from source chain + test.app + .api() + .addr_make(COLLECTION_OWNER_SOURCE_CHAIN) + .to_string(), + ), contract_info: expected_contract_info, name: "name".to_string(), symbol: "symbol".to_string(), @@ -1205,22 +1698,21 @@ fn test_receive_nft() { } } -/// Tests that receiving a NFT via a regular receive fails when a -/// proxy is installed. +/// In case proxy for ICS721 is defined, ICS721 only accepts receival from proxy - not from nft contract! #[test] fn test_no_receive_with_proxy() { let mut test = Test::new(true, None, cw721_base_contract()); - + // unauthorized to receive nft from nft contract let err: ContractError = test .app .execute_contract( - Addr::unchecked("cw721"), + test.app.api().addr_make("cw721"), test.ics721, &ExecuteMsg::ReceiveNft(cw721::Cw721ReceiveMsg { - sender: "ekez".to_string(), + sender: test.app.api().addr_make(NFT_OWNER_TARGET_CHAIN).to_string(), token_id: "1".to_string(), - msg: to_binary(&IbcOutgoingMsg { - receiver: "ekez".to_string(), + msg: to_json_binary(&IbcOutgoingMsg { + receiver: NFT_OWNER_TARGET_CHAIN.to_string(), // nft owner for other chain, on this chain ics721 is owner channel_id: "channel-0".to_string(), timeout: IbcTimeout::with_block(IbcTimeoutBlock { revision: 0, @@ -1235,38 +1727,43 @@ fn test_no_receive_with_proxy() { .unwrap_err() .downcast() .unwrap(); - assert_eq!(err, ContractError::Unauthorized {}) } /// Tests the contract's pause behavior. #[test] fn test_pause() { - let mut test = Test::new(true, Some("ekez".to_string()), cw721_base_contract()); - + let mut test = Test::new( + true, + Some(ICS721_ADMIN_AND_PAUSER.to_string()), + cw721_base_contract(), + ); // Should start unpaused. let (paused, pauser) = test.query_pause_info(); assert!(!paused); - assert_eq!(pauser, Some(Addr::unchecked("ekez"))); + assert_eq!( + pauser, + Some(test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER)) + ); // Non-pauser may not pause. - let err = test.pause_ics721_should_fail("zeke"); + let err = test.pause_ics721_should_fail(test.app.api().addr_make("zeke").as_str()); assert_eq!( err, ContractError::Pause(PauseError::Unauthorized { - sender: Addr::unchecked("zeke") + sender: test.app.api().addr_make("zeke") }) ); // Pause the ICS721 contract. - test.pause_ics721("ekez"); + test.pause_ics721(test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER).as_str()); // Pausing should remove the pauser. let (paused, pauser) = test.query_pause_info(); assert!(paused); assert_eq!(pauser, None); // Pausing fails. - let err = test.pause_ics721_should_fail("ekez"); + let err = test.pause_ics721_should_fail(test.app.api().addr_make("ekez").as_str()); assert_eq!(err, ContractError::Pause(PauseError::Paused {})); // Even something like executing a callback on ourselves will be @@ -1284,16 +1781,16 @@ fn test_pause() { .unwrap(); assert_eq!(err, ContractError::Pause(PauseError::Paused {})); - // Set a new pauser. + // Pauser can pause only once, for another pause, a new pauser needs to be set via migration let ics721_id = test.app.store_code(ics721_contract()); test.app .execute( - Addr::unchecked("ekez"), + test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER), WasmMsg::Migrate { contract_addr: test.ics721.to_string(), new_code_id: ics721_id, - msg: to_binary(&MigrateMsg::WithUpdate { - pauser: Some("zeke".to_string()), + msg: to_json_binary(&MigrateMsg::WithUpdate { + pauser: Some(test.app.api().addr_make("new_pauser").to_string()), proxy: None, cw721_base_code_id: None, }) @@ -1306,10 +1803,10 @@ fn test_pause() { // Setting new pauser should unpause. let (paused, pauser) = test.query_pause_info(); assert!(!paused); - assert_eq!(pauser, Some(Addr::unchecked("zeke"))); + assert_eq!(pauser, Some(test.app.api().addr_make("new_pauser"))); // One more pause for posterity sake. - test.pause_ics721("zeke"); + test.pause_ics721(test.app.api().addr_make("new_pauser").as_str()); let (paused, pauser) = test.query_pause_info(); assert!(paused); assert_eq!(pauser, None); @@ -1318,23 +1815,30 @@ fn test_pause() { /// Tests migration. #[test] fn test_migration() { - let mut test = Test::new(true, Some("ekez".to_string()), cw721_base_contract()); + let mut test = Test::new( + true, + Some(ICS721_ADMIN_AND_PAUSER.to_string()), + cw721_base_contract(), + ); // assert instantiation worked let (_, pauser) = test.query_pause_info(); - assert_eq!(pauser, Some(Addr::unchecked("ekez"))); + assert_eq!( + pauser, + Some(test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER)) + ); let proxy = test.query_proxy(); assert!(proxy.is_some()); let cw721_code_id = test.query_cw721_id(); - assert_eq!(cw721_code_id, test.cw721_id); + assert_eq!(cw721_code_id, test.source_cw721_id); // migrate changes test.app .execute( - Addr::unchecked("ekez"), + test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER), WasmMsg::Migrate { contract_addr: test.ics721.to_string(), new_code_id: test.ics721_id, - msg: to_binary(&MigrateMsg::WithUpdate { + msg: to_json_binary(&MigrateMsg::WithUpdate { pauser: None, proxy: None, cw721_base_code_id: Some(12345678), @@ -1355,11 +1859,11 @@ fn test_migration() { // migrate without changing code id test.app .execute( - Addr::unchecked("ekez"), + test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER), WasmMsg::Migrate { contract_addr: test.ics721.to_string(), new_code_id: test.ics721_id, - msg: to_binary(&MigrateMsg::WithUpdate { + msg: to_json_binary(&MigrateMsg::WithUpdate { pauser: None, proxy: None, cw721_base_code_id: None, diff --git a/packages/ics721/src/testing/mod.rs b/packages/ics721/src/testing/mod.rs index 606643c2..7d31de9a 100644 --- a/packages/ics721/src/testing/mod.rs +++ b/packages/ics721/src/testing/mod.rs @@ -1,3 +1,3 @@ mod contract; mod ibc_tests; -mod integration_tests; +pub mod integration_tests; diff --git a/packages/ics721/src/token_types.rs b/packages/ics721/src/token_types.rs index 127a9804..8ddc16a5 100644 --- a/packages/ics721/src/token_types.rs +++ b/packages/ics721/src/token_types.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use cosmwasm_schema::cw_serde; -use cosmwasm_std::{to_binary, Addr, Binary, StdResult, WasmMsg}; +use cosmwasm_std::{to_json_binary, Addr, Binary, StdResult, WasmMsg}; use cw_storage_plus::{Bound, Bounder, Key, KeyDeserialize, Prefixer, PrimaryKey}; use crate::msg::{CallbackMsg, ExecuteMsg}; @@ -97,7 +97,7 @@ impl VoucherRedemption { pub(crate) fn into_wasm_msg(self, contract: Addr, receiver: String) -> StdResult { Ok(WasmMsg::Execute { contract_addr: contract.into_string(), - msg: to_binary(&ExecuteMsg::Callback(CallbackMsg::RedeemVouchers { + msg: to_json_binary(&ExecuteMsg::Callback(CallbackMsg::RedeemVouchers { receiver, redeem: self, }))?, @@ -119,7 +119,7 @@ impl VoucherCreation { pub(crate) fn into_wasm_msg(self, contract: Addr, receiver: String) -> StdResult { Ok(WasmMsg::Execute { contract_addr: contract.into_string(), - msg: to_binary(&ExecuteMsg::Callback(CallbackMsg::CreateVouchers { + msg: to_json_binary(&ExecuteMsg::Callback(CallbackMsg::CreateVouchers { receiver, create: self, }))?, diff --git a/packages/ics721/src/utils.rs b/packages/ics721/src/utils.rs index 406207e2..e4ca737c 100644 --- a/packages/ics721/src/utils.rs +++ b/packages/ics721/src/utils.rs @@ -44,7 +44,7 @@ pub fn convert_owner_chain_address(env: &Env, source_owner: &str) -> StdResult: to Tendermint RPC interface for this chain node = "tcp://localhost:26657" -# Transaction broadcasting mode (sync|async|block) + +# Transaction broadcasting mode (sync|async) broadcast-mode = "sync" + +# Human-readable denoms: Input +# If enabled, when using CLI, user can input 0 exponent denoms (atom, scrt, avax, wbtc, etc.) instead of their ibc equivalents. +# Note, this will also change the coin's value to it's base value if the input or flag is a coin. +# Example: +# * 10.45atom input will automatically change to 10450000ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 +# * uakt will change to ibc/1480B8FD20AD5FCAE81EA87584D269547DD4D436843C1D20F15E00EB64743EF4 +# * 12000000uscrt will change to 12000000ibc/0954E1C28EB7AF5B72D24F3BC2B47BBB2FDF91BDDFD57B74B99E133AED40972A +# This feature isn't stable yet, and outputs will change in subsequent releases +human-readable-denoms-input = false + +# Human-readable denoms: Output +# If enabled, CLI response return base denoms (uatom, uscrt, wavax-wei, wbtc-satoshi, etc.) instead of their ibc equivalents. +# This feature isn't stable yet, and outputs will change in subsequent releases +human-readable-denoms-output = false + + +############################################################################### +### Osmosis Tx Configuration ### +############################################################################### +# Amount of gas per transaction +gas = "" +# Price per unit of gas (ex: 0.005uosmo) +gas-prices = "" +gas-adjustment = "" +fees = "" diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/config.toml b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/config.toml index 195084a3..3059521c 100755 --- a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/config.toml +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/config.toml @@ -209,7 +209,7 @@ laddr = "tcp://0.0.0.0:26656" external_address = "" # Comma separated list of seed nodes to connect to -seeds = "21d7539792ee2e0d650b199bf742c56ae0cf499e@162.55.132.230:2000,44ff091135ef2c69421eacfa136860472ac26e60@65.21.141.212:2000,ec4d3571bf709ab78df61716e47b5ac03d077a1a@65.108.43.26:2000,4cb8e1e089bdf44741b32638591944dc15b7cce3@65.108.73.18:2000,f515a8599b40f0e84dfad935ba414674ab11a668@osmosis.blockpane.com:26656,6bcdbcfd5d2c6ba58460f10dbcfde58278212833@osmosis.artifact-staking.io:26656,24841abfc8fbd401d8c86747eec375649a2e8a7e@osmosis.pbcups.org:26656,77bb5fb9b6964d6e861e91c1d55cf82b67d838b5@bd-osmosis-seed-mainnet-us-01.bdnodes.net:26656,3243426ab56b67f794fa60a79cc7f11bc7aa752d@bd-osmosis-seed-mainnet-eu-02.bdnodes.net:26656,6fc23ee451a5969853825d861532676b84d7bf0c@osmosis.mainnet.seed.blockngine.io:26716,7c66126b64cd66bafd9ccfc721f068df451d31a3@osmosis-seed.sunshinevalidation.io:9393" +seeds = "21d7539792ee2e0d650b199bf742c56ae0cf499e@162.55.132.230:2000,44ff091135ef2c69421eacfa136860472ac26e60@65.21.141.212:2000,ec4d3571bf709ab78df61716e47b5ac03d077a1a@65.108.43.26:2000,4cb8e1e089bdf44741b32638591944dc15b7cce3@65.108.73.18:2000,f515a8599b40f0e84dfad935ba414674ab11a668@osmosis.blockpane.com:26656,6bcdbcfd5d2c6ba58460f10dbcfde58278212833@osmosis.artifact-staking.io:26656,24841abfc8fbd401d8c86747eec375649a2e8a7e@osmosis.pbcups.org:26656,77bb5fb9b6964d6e861e91c1d55cf82b67d838b5@bd-osmosis-seed-mainnet-us-01.bdnodes.net:26656,3243426ab56b67f794fa60a79cc7f11bc7aa752d@bd-osmosis-seed-mainnet-eu-02.bdnodes.net:26656,ebc272824924ea1a27ea3183dd0b9ba713494f83@osmosis-mainnet-seed.autostake.com:26716,7c66126b64cd66bafd9ccfc721f068df451d31a3@osmosis-seed.sunshinevalidation.io:9393" # Comma separated list of nodes to keep persistent connections to persistent_peers = "" @@ -225,10 +225,10 @@ addr_book_file = "config/addrbook.json" addr_book_strict = true # Maximum number of inbound peers -max_num_inbound_peers = 320 +max_num_inbound_peers = 80 # Maximum number of outbound peers to connect to, excluding persistent peers -max_num_outbound_peers = 40 +max_num_outbound_peers = 60 # List of node IDs, to which a connection will be (re)established ignoring any existing limits unconditional_peer_ids = "" @@ -272,6 +272,11 @@ dial_timeout = "3s" ####################################################### [mempool] +# Mempool version to use: +# 1) "v0" - (default) FIFO mempool. +# 2) "v1" - prioritized mempool. +version = "v0" + recheck = true broadcast = true wal_dir = "" @@ -301,6 +306,22 @@ max_tx_bytes = 1048576 # XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 max_batch_bytes = 0 +# ttl-duration, if non-zero, defines the maximum amount of time a transaction +# can exist for in the mempool. +# +# Note, if ttl-num-blocks is also defined, a transaction will be removed if it +# has existed in the mempool at least ttl-num-blocks number of blocks or if it's +# insertion time into the mempool is beyond ttl-duration. +ttl-duration = "0s" + +# ttl-num-blocks, if non-zero, defines the maximum number of blocks a transaction +# can exist for in the mempool. +# +# Note, if ttl-duration is also defined, a transaction will be removed if it +# has existed in the mempool at least ttl-num-blocks number of blocks or if +# it's insertion time into the mempool is beyond ttl-duration. +ttl-num-blocks = 0 + ####################################################### ### State Sync Configuration Options ### ####################################################### @@ -389,6 +410,17 @@ create_empty_blocks_interval = "0s" peer_gossip_sleep_duration = "100ms" peer_query_maj23_sleep_duration = "2s" +####################################################### +### Storage Configuration Options ### +####################################################### +[storage] + +# Set to true to discard ABCI responses from the state store, which can save a +# considerable amount of disk space. Set to false to ensure ABCI responses are +# persisted. ABCI responses are required for /block_results RPC queries, and to +# reindex events in the command-line tool. +discard_abci_responses = false + ####################################################### ### Transaction Indexer Configuration Options ### ####################################################### @@ -403,8 +435,14 @@ peer_query_maj23_sleep_duration = "2s" # 1) "null" # 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). # - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. +# 3) "psql" - the indexer services backed by PostgreSQL. +# When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed. indexer = "kv" +# The PostgreSQL connection configuration, the connection format: +# postgresql://:@:/? +psql-conn = "" + ####################################################### ### Instrumentation Configuration Options ### ####################################################### diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/genesis.json b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/genesis.json index 2ca5b191..42dc38ed 100755 --- a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/genesis.json +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/genesis.json @@ -6,7 +6,7 @@ { "@type": "/cosmos.auth.v1beta1.BaseAccount", "account_number": "0", - "address": "osmo1dlz93eutqz6skqf6p7s3kt27rlwvgq5up9xma3", + "address": "osmo1untdrukxu7rst0a0sysxhkzksylpwka4aa3glv", "pub_key": null, "sequence": "0" }, @@ -32,7 +32,7 @@ "bank": { "balances": [ { - "address": "osmo1dlz93eutqz6skqf6p7s3kt27rlwvgq5up9xma3", + "address": "osmo1untdrukxu7rst0a0sysxhkzksylpwka4aa3glv", "coins": [ { "amount": "1000000000", @@ -55,16 +55,55 @@ "default_send_enabled": true, "send_enabled": [] }, - "supply": [] - }, - "bech32ibc": { - "hrpIBCRecords": [], - "nativeHRP": "osmo" + "supply": [], + "supply_offsets": [] }, "capability": { "index": "1", "owners": [] }, + "concentratedliquidity": { + "next_incentive_record_id": "1", + "next_position_id": "1", + "params": { + "authorized_quote_denoms": [ + "uosmo", + "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2", + "ibc/0CD3A0285E1341859B5E86B6AB7682F023D03E97607CCC1DC95706411D866DF7", + "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858" + ], + "authorized_spread_factors": [ + "0.000000000000000000", + "0.000100000000000000", + "0.000500000000000000", + "0.001000000000000000", + "0.002000000000000000", + "0.003000000000000000", + "0.005000000000000000" + ], + "authorized_tick_spacing": [ + "1", + "10", + "100", + "1000" + ], + "authorized_uptimes": [ + "0.000000001s" + ], + "balancer_shares_reward_discount": "0.050000000000000000", + "is_permissionless_pool_creation_enabled": false, + "unrestricted_pool_creator_whitelist": [] + }, + "pool_data": [], + "position_data": [] + }, + "cosmwasmpool": { + "params": { + "code_id_whitelist": [], + "pool_migration_limit": "20" + }, + "pools": [] + }, "crisis": { "constant_fee": { "amount": "1000", @@ -90,24 +129,138 @@ "validator_historical_rewards": [], "validator_slash_events": [] }, + "downtimedetector": { + "downtimes": [ + { + "duration": "DURATION_30S", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_1M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_2M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_3M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_4M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_5M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_10M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_20M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_30M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_40M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_50M", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_1H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_1_5H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_2H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_2_5H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_3H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_4H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_5H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_6H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_9H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_12H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_18H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_24H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_36H", + "last_downtime": "1970-01-01T00:00:00Z" + }, + { + "duration": "DURATION_48H", + "last_downtime": "1970-01-01T00:00:00Z" + } + ], + "last_block_time": "1970-01-01T00:00:00Z" + }, "epochs": { "epochs": [ { "current_epoch": "0", "current_epoch_start_height": "0", "current_epoch_start_time": "0001-01-01T00:00:00Z", - "duration": "604800s", + "duration": "86400s", "epoch_counting_started": false, - "identifier": "week", + "identifier": "day", "start_time": "0001-01-01T00:00:00Z" }, { "current_epoch": "0", "current_epoch_start_height": "0", "current_epoch_start_time": "0001-01-01T00:00:00Z", - "duration": "86400s", + "duration": "3600s", "epoch_counting_started": false, - "identifier": "day", + "identifier": "hour", + "start_time": "0001-01-01T00:00:00Z" + }, + { + "current_epoch": "0", + "current_epoch_start_height": "0", + "current_epoch_start_time": "0001-01-01T00:00:00Z", + "duration": "604800s", + "epoch_counting_started": false, + "identifier": "week", "start_time": "0001-01-01T00:00:00Z" } ] @@ -116,6 +269,9 @@ "evidence": [] }, "gamm": { + "migration_records": { + "balancer_to_concentrated_pool_links": [] + }, "next_pool_number": "1", "params": { "pool_creation_fee": [ @@ -146,7 +302,7 @@ }, "public_key": { "@type": "/cosmos.crypto.secp256k1.PubKey", - "key": "A+WeeHXm8WuDNWQ21OorfzGpIvGOqLYFlEYS+niPO7Gx" + "key": "A5wtqfF9uSmJ3ZKBeWBOfeHhxt59miwigH96iG1K3/eZ" }, "sequence": "0" } @@ -154,7 +310,7 @@ }, "body": { "extension_options": [], - "memo": "8c3f5817e96cc2a75d729f89a8ddfe23883f6c34@172.17.0.2:26656", + "memo": "354120fcf0599533b560eab967482a7d2a5fa5db@172.17.0.3:26656", "messages": [ { "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", @@ -163,7 +319,7 @@ "max_rate": "0.200000000000000000", "rate": "0.100000000000000000" }, - "delegator_address": "osmo1dlz93eutqz6skqf6p7s3kt27rlwvgq5up9xma3", + "delegator_address": "osmo1untdrukxu7rst0a0sysxhkzksylpwka4aa3glv", "description": { "details": "", "identity": "", @@ -174,9 +330,9 @@ "min_self_delegation": "1", "pubkey": { "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "SqQYMs5aVi4XUZP2Pet4YnhVQFWsWGpZZzewg1fLUjg=" + "key": "ahG9X+ofRvIsrijyWTQCPf1lXIwEjg3zeQxdcSvU9pE=" }, - "validator_address": "osmovaloper1dlz93eutqz6skqf6p7s3kt27rlwvgq5umjwc2k", + "validator_address": "osmovaloper1untdrukxu7rst0a0sysxhkzksylpwka482etgt", "value": { "amount": "3000000", "denom": "uosmo" @@ -187,7 +343,7 @@ "timeout_height": "0" }, "signatures": [ - "jniNpsTjH5FtktRzMt91mhHZPfwYxRG3Hy4ITNQX0I49oX8nQ1NNbR2vmyebZwWLORrkoy9mvXBpMLtNZqyebQ==" + "lEn4KbGyzh3ZRHnVANciy595rwMQW88MsX5NEekCioViU0Pfm0p/70HdB6xp6H1Kk+lGJpKMHAlk8IqzM0wMiw==" ] } ] @@ -200,18 +356,29 @@ "amount": "10000000", "denom": "uosmo" } - ] + ], + "min_expedited_deposit": [ + { + "amount": "50000000", + "denom": "uosmo" + } + ], + "min_initial_deposit_ratio": "0.000000000000000000" }, "deposits": [], "proposals": [], "starting_proposal_id": "1", "tally_params": { + "expedited_quorum": "0.667000000000000000", + "expedited_threshold": "0.667000000000000000", "quorum": "0.334000000000000000", "threshold": "0.500000000000000000", "veto_threshold": "0.334000000000000000" }, "votes": [], "voting_params": { + "expedited_voting_period": "86400s", + "proposal_voting_periods": [], "voting_period": "172800s" } }, @@ -248,8 +415,15 @@ } } }, + "ibchooks": { + "params": { + "allowed_async_ack_contracts": [] + } + }, "incentives": { "gauges": [], + "group_gauges": [], + "groups": [], "last_gauge_id": "0", "lockable_durations": [ "1s", @@ -258,7 +432,40 @@ "25200s" ], "params": { - "distr_epoch_identifier": "week" + "distr_epoch_identifier": "week", + "group_creation_fee": [ + { + "amount": "100000000", + "denom": "uosmo" + } + ], + "unrestricted_creator_whitelist": [] + } + }, + "interchainaccounts": { + "controller_genesis_state": { + "active_channels": [], + "interchain_accounts": [], + "params": { + "controller_enabled": true + }, + "ports": [] + }, + "host_genesis_state": { + "active_channels": [], + "interchain_accounts": [], + "params": { + "allow_messages": [], + "host_enabled": true + }, + "port": "icahost" + } + }, + "interchainquery": { + "host_port": "icqhost", + "params": { + "allow_queries": [], + "host_enabled": true } }, "lockup": { @@ -267,7 +474,6 @@ "synthetic_locks": [] }, "mint": { - "halven_started_epoch": "0", "minter": { "epoch_provisions": "0.000000000000000000" }, @@ -285,10 +491,19 @@ "reduction_factor": "0.500000000000000000", "reduction_period_in_epochs": "156", "weighted_developer_rewards_receivers": [] + }, + "reduction_started_epoch": "0" + }, + "packetfowardmiddleware": { + "in_flight_packets": {}, + "params": { + "fee_percentage": "0.000000000000000000" } }, "params": null, "poolincentives": { + "any_pool_to_internal_gauges": null, + "concentrated_pool_to_no_lock_gauges": null, "distr_info": { "records": [], "total_weight": "0" @@ -302,6 +517,85 @@ "minted_denom": "uosmo" } }, + "poolmanager": { + "next_pool_id": "1", + "params": { + "authorized_quote_denoms": [ + "uosmo", + "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2", + "ibc/0CD3A0285E1341859B5E86B6AB7682F023D03E97607CCC1DC95706411D866DF7", + "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858" + ], + "pool_creation_fee": [ + { + "amount": "1000000000", + "denom": "uosmo" + } + ], + "taker_fee_params": { + "admin_addresses": [], + "community_pool_denom_to_swap_non_whitelisted_assets_to": "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", + "default_taker_fee": "0.000000000000000000", + "non_osmo_taker_fee_distribution": { + "community_pool": "0.330000000000000000", + "staking_rewards": "0.670000000000000000" + }, + "osmo_taker_fee_distribution": { + "community_pool": "0.000000000000000000", + "staking_rewards": "1.000000000000000000" + }, + "reduced_fee_whitelist": [] + } + }, + "pool_routes": [] + }, + "protorev": { + "base_denoms": [ + { + "denom": "uosmo", + "step_size": "1000000" + } + ], + "days_since_module_genesis": "0", + "developer_address": "", + "developer_fees": [], + "info_by_pool_type": { + "balancer": { + "weight": "2" + }, + "concentrated": { + "max_ticks_crossed": "5", + "weight": "7" + }, + "cosmwasm": { + "weight_maps": [] + }, + "stable": { + "weight": "5" + } + }, + "latest_block_height": "0", + "max_pool_points_per_block": "100", + "max_pool_points_per_tx": "18", + "params": { + "admin": "osmo17nv67dvc7f8yr00rhgxd688gcn9t9wvhn783z4", + "enabled": true + }, + "point_count_for_block": "0", + "pool_weights": { + "balancer_weight": "0", + "concentrated_weight": "0", + "cosmwasm_weight": "0", + "stable_weight": "0" + }, + "profits": [], + "token_pair_arb_routes": [] + }, + "rate-limited-ibc": { + "params": { + "contract_address": "" + } + }, "slashing": { "missed_blocks": [], "params": { @@ -324,6 +618,7 @@ "max_entries": 7, "max_validators": 100, "min_commission_rate": "0.000000000000000000", + "min_self_delegation": "0", "unbonding_time": "1814400s" }, "redelegations": [], @@ -342,12 +637,8 @@ "tokenfactory": { "factory_denoms": [], "params": { - "denom_creation_fee": [ - { - "amount": "10000000", - "denom": "uosmo" - } - ] + "denom_creation_fee": [], + "denom_creation_gas_consume": "1000000" } }, "transfer": { @@ -358,19 +649,27 @@ }, "port_id": "transfer" }, + "twap": { + "params": { + "prune_epoch_identifier": "day", + "record_history_keep_period": "172800s" + }, + "twaps": [] + }, "txfees": { "basedenom": "uosmo", "feetokens": [] }, "upgrade": {}, + "valsetpref": null, "vesting": {}, "wasm": { "codes": [], "contracts": [], - "gen_msgs": [], "params": { "code_upload_access": { "address": "", + "addresses": [], "permission": "Everybody" }, "instantiate_default_permission": "Everybody" @@ -397,6 +696,6 @@ }, "version": {} }, - "genesis_time": "2022-07-20T19:45:11.178239638Z", + "genesis_time": "2023-11-14T15:03:55.734464042Z", "initial_height": "1" } diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/gentx/gentx-354120fcf0599533b560eab967482a7d2a5fa5db.json b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/gentx/gentx-354120fcf0599533b560eab967482a7d2a5fa5db.json new file mode 100755 index 00000000..61d8c529 --- /dev/null +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/gentx/gentx-354120fcf0599533b560eab967482a7d2a5fa5db.json @@ -0,0 +1 @@ +{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"osmo-moniker","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"osmo1untdrukxu7rst0a0sysxhkzksylpwka4aa3glv","validator_address":"osmovaloper1untdrukxu7rst0a0sysxhkzksylpwka482etgt","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"ahG9X+ofRvIsrijyWTQCPf1lXIwEjg3zeQxdcSvU9pE="},"value":{"denom":"uosmo","amount":"3000000"}}],"memo":"354120fcf0599533b560eab967482a7d2a5fa5db@172.17.0.3:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A5wtqfF9uSmJ3ZKBeWBOfeHhxt59miwigH96iG1K3/eZ"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"350000","payer":"","granter":""}},"signatures":["lEn4KbGyzh3ZRHnVANciy595rwMQW88MsX5NEekCioViU0Pfm0p/70HdB6xp6H1Kk+lGJpKMHAlk8IqzM0wMiw=="]} diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/gentx/gentx-8c3f5817e96cc2a75d729f89a8ddfe23883f6c34.json b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/gentx/gentx-8c3f5817e96cc2a75d729f89a8ddfe23883f6c34.json deleted file mode 100755 index e8d877a5..00000000 --- a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/gentx/gentx-8c3f5817e96cc2a75d729f89a8ddfe23883f6c34.json +++ /dev/null @@ -1 +0,0 @@ -{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"osmo-moniker","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"osmo1dlz93eutqz6skqf6p7s3kt27rlwvgq5up9xma3","validator_address":"osmovaloper1dlz93eutqz6skqf6p7s3kt27rlwvgq5umjwc2k","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"SqQYMs5aVi4XUZP2Pet4YnhVQFWsWGpZZzewg1fLUjg="},"value":{"denom":"uosmo","amount":"3000000"}}],"memo":"8c3f5817e96cc2a75d729f89a8ddfe23883f6c34@172.17.0.2:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A+WeeHXm8WuDNWQ21OorfzGpIvGOqLYFlEYS+niPO7Gx"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"350000","payer":"","granter":""}},"signatures":["jniNpsTjH5FtktRzMt91mhHZPfwYxRG3Hy4ITNQX0I49oX8nQ1NNbR2vmyebZwWLORrkoy9mvXBpMLtNZqyebQ=="]} diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/node_key.json b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/node_key.json index c24fb309..cd9668a7 100755 --- a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/node_key.json +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/node_key.json @@ -1 +1 @@ -{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"lI+YR/HllQTo92S583RbyRGyCJQvib+v+OqK8Dxss0oeE7Ga7gljmq2xmWgfK2E48SV3Eae9aG3xgjl9+D5f/A=="}} \ No newline at end of file +{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"SJSKPv9f+MVSIkS3EKV3iMwZfgyyBjFMEeoKScXvQPpYcH2H35y5ymkWxw3cipTeeh70AkQGM0mnNFEOcyAn+A=="}} \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/priv_validator_key.json b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/priv_validator_key.json index 95372a5d..87badd62 100755 --- a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/priv_validator_key.json +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/config/priv_validator_key.json @@ -1,11 +1,11 @@ { - "address": "0303542D813398A9F452F249A60016FC1DC4A79F", + "address": "06F0BC478365E7EDDE8411733E52BD410ACE3A3E", "pub_key": { "type": "tendermint/PubKeyEd25519", - "value": "SqQYMs5aVi4XUZP2Pet4YnhVQFWsWGpZZzewg1fLUjg=" + "value": "ahG9X+ofRvIsrijyWTQCPf1lXIwEjg3zeQxdcSvU9pE=" }, "priv_key": { "type": "tendermint/PrivKeyEd25519", - "value": "wlDNMiFw0gTVGgBdb5jZs8ShXi8gHTKKx1J/9q8YECNKpBgyzlpWLhdRk/Y963hieFVAVaxYallnN7CDV8tSOA==" + "value": "Z9hEbPMBleBwxLhNbZnUvucBKPRJMNrHIIkokM+lVh9qEb1f6h9G8iyuKPJZNAI9/WVcjASODfN5DF1xK9T2kQ==" } } \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/e4d6d1f2c6e78705bfaf81206bd856813e175bb5.address b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/e4d6d1f2c6e78705bfaf81206bd856813e175bb5.address new file mode 100755 index 00000000..46d6f5c4 --- /dev/null +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/e4d6d1f2c6e78705bfaf81206bd856813e175bb5.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMy0xMS0xNCAxNTowMzo1NS45NDQwMzM3MDkgKzAwMDAgVVRDIG09KzAuMTI2ODg2NTA5IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiRVVHdkl4d1JUR2lRNGEtbiJ9.fIie7OPfwfpyaz8TGMHmhDaCf64SD3e3fP5LQJw8yGdnmjYf_Ioz7Q.LU2jeFJ4SbhE92db.ZcP4-JY7BFJtoLt1GvGheU0CHATfSwcgBvrB25Y7OULdttbjkXYY14-VJ0rIgcKtqj0nvAQPDoYKKBF_E1e0drxywq7ciaJnoF2lEXvMR25JBDcARr1pcXPI59Hst1k_TQwOpAGSHNxQyQFqTDR7bYNaKo7_59dFK-M-jHUpw0NyZoaMgzQurYbzeLu4hlFEm8p1Yw8h5wsVTDqkcUqxk4n-uoOL2hRqNRR72d5uU0cjG1jxPKAV7Lbv.lInI-NpoSOtRjNCgcgEvVA \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/keyhash b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/keyhash index 1abe6138..c92eec36 100755 --- a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/keyhash +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/keyhash @@ -1 +1 @@ -$2a$10$bNpXDhTBeAqVzaTC4MIsXeltpKG1V2OpNSINs6ql5WIrYRGXv9HWm \ No newline at end of file +$2a$10$Nlzpr9C8uMZCKYMYrDxK2u5ZhOgzr1./MG4egQwfY4aRiJQzI6M9y \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/validator.info b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/validator.info index 1ff04099..d0dd4aeb 100755 --- a/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/validator.info +++ b/ts-relayer-tests/ci-scripts/osmosis/template/.osmosisd/validator.info @@ -1 +1 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMi0wNy0yMCAxOTo0NToxMi41MjMwMjk4NDcgKzAwMDAgVVRDIG09KzAuNjE2MjgzMzc2IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiLWJrVDlya1ZmRFQ0T0owLSJ9.WpY0n05cm3Git29URAKchjmjZpE6U5VirwEFAjGjkU98M8Yvj5-bGQ.AZkszDfiWhrd0Pwo.pmKQTCy5V68XO7X9mRBMZqZkexzjaBiAMJrgjJoOqABbeinY-RXsvcVKizXNSeKmWhV3OjNPqm1yoWMcXAo3uhjlxH6VEZhRM_khsufQm5__XtJpoDM_frZFprpapxWZX9B3RHBxqjZMeSzi0UvvawFqvRPxQFZg6En1mmnCpyto2_1dnpKOQ-QO74DbALF3bTJk088-dxttzMw_uaAbADatOqCcC3LAoteSoOeuaCqT_ckfUVHaKggr4H2W6e0Er6wTI9oHMD5odGCvYRZgjWuOhQOfbaAE7lTIWSpd7ZZn7BGrtiGu-3Ur4LaH6l4FPkqVxJ2AdKBk__zx2T8RnO49AdvM0lGcMJmhEMxXH5d7g6uq.YSUMG1-dEGKZAwiK-y34iQ \ No newline at end of file +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMy0xMS0xNCAxNTowMzo1NS45Mzk3MDkyOTQgKzAwMDAgVVRDIG09KzAuMTIyNTYyMDg0IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiU3NTUHlpTzRCcFloZWtmUiJ9.Wq2uS_WWmjVu22rbtqCFum8RnIHwUyFuKh2rG5g6l_KbtpDUj-Dbcw.qBectrwtiRH6W-3M.es3a0hSo4GPpuUBZqDLqRscZRn8v64EJ6Q4seosrPRbeuI73lOWI-Bhp7Wngj2OWv4RHXEHoDpwN5AnP_0yF8JL-v7nss-QXYOJrLzWzw8LDByh6uGoQogSVLHf_tbDcCAMElEJ0PqvCyxHNmRxSKbeJgjCmKez02B3Ng9OrmkYbTV0MLUNSzY8aUyGgyZLBIQ3fFGGdDyGuAPEBqcHC_7iLPtz7thUXs-pZ8-IlrvNptw1F-uk5FP1EPWrMf5Hgpv-asbm_THlZFHHvCprrZ6sPWvjt8BYhg0PIzL74R5klSX8Z1Z8TxaUd1mfGC2eMwYO4seNOL3rjIKXDNxXbDRWiPZwB19fLdgcnEyvLlPCtq4Uv.RiuaI0CQpNxzY6gHyWaHIA \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/wasmd/env b/ts-relayer-tests/ci-scripts/wasmd/env index f811ff8c..2d1afa13 100644 --- a/ts-relayer-tests/ci-scripts/wasmd/env +++ b/ts-relayer-tests/ci-scripts/wasmd/env @@ -1,4 +1,6 @@ -REPOSITORY="confio/wasm-ci" +# TODO change this back to confio/wasm-ci once it has been updated +# Until then this forked repo is used: https://github.com/arkprotocol/relayer-ci-images +REPOSITORY="arkprotocol/wasmd-ci" # This should be pinned to the newest version we support -VERSION="0.27.0" +VERSION="v0.0.1" CONTAINER_NAME="wasmd" diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/463643aef9b66adcd69f5c001c06cdb86ff1d98b.address b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/463643aef9b66adcd69f5c001c06cdb86ff1d98b.address new file mode 100755 index 00000000..8500183f --- /dev/null +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/463643aef9b66adcd69f5c001c06cdb86ff1d98b.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMy0xMS0xNCAxNTowMzoxNS42NTk0NjQ5NjQgKzAwMDAgVVRDIG09KzAuMDk4MjAxODM5IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoieE16elFBZlJ4RmdLN01EVCJ9.TJx-nGUUfoRHFsU0_D5qW69NLGu9L6p1yi9ZNtYVXYHOQM-PMNgZrw.yh3_KIVkznmqxIYj.HHNSfcoGKA6nmK_vXl1QkH7In4scKv3jgBv_4NnjYb0PGm2cngPhGdrQsUn-TcAO74AQlfcwaglTWFvoLkmgW2bZbPmHuU0aIQAbX-Z2Q-jJkEqgdIAyjtHVpEU9-2KVEmfF_uJROh25pG2cDPpFWa9_m7Em0haTOQnS45j9dsPxa3m-LXg4pnb2H8V-WNIUUqUg5bN4A9xCCxoSw7YI6h5BGTRQJxBJEBYukPhRV_uhnANA3klUBuhO.QsYQK29NmDImsC2BqTe1SA \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/app.toml b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/app.toml index 5ff2008f..583ddc02 100755 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/app.toml +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/app.toml @@ -64,6 +64,10 @@ index-events = [] # Default cache size is 50mb. iavl-cache-size = 781250 +# IAVLDisableFastNode enables or disables the fast node feature of IAVL. +# Default is true. +iavl-disable-fastnode = true + ############################################################################### ### Telemetry Configuration ### ############################################################################### @@ -194,3 +198,26 @@ snapshot-interval = 0 # snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). snapshot-keep-recent = 2 + +############################################################################### +### Store / State Streaming ### +############################################################################### + +[store] +streamers = [] + +[streamers] +[streamers.file] +keys = ["*", ] +write_dir = "" +prefix = "" + +# output-metadata specifies if output the metadata file which includes the abci request/responses +# during processing the block. +output-metadata = "true" + +# stop-node-on-error specifies if propagate the file streamer errors to consensus state machine. +stop-node-on-error = "true" + +# fsync specifies if call fsync after writing the files. +fsync = "false" diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/config.toml b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/config.toml index 65ae7788..6e621bd8 100755 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/config.toml +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/config.toml @@ -272,6 +272,11 @@ dial_timeout = "3s" ####################################################### [mempool] +# Mempool version to use: +# 1) "v0" - (default) FIFO mempool. +# 2) "v1" - prioritized mempool. +version = "v0" + recheck = true broadcast = true wal_dir = "" @@ -301,6 +306,22 @@ max_tx_bytes = 1048576 # XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 max_batch_bytes = 0 +# ttl-duration, if non-zero, defines the maximum amount of time a transaction +# can exist for in the mempool. +# +# Note, if ttl-num-blocks is also defined, a transaction will be removed if it +# has existed in the mempool at least ttl-num-blocks number of blocks or if it's +# insertion time into the mempool is beyond ttl-duration. +ttl-duration = "0s" + +# ttl-num-blocks, if non-zero, defines the maximum number of blocks a transaction +# can exist for in the mempool. +# +# Note, if ttl-duration is also defined, a transaction will be removed if it +# has existed in the mempool at least ttl-num-blocks number of blocks or if +# it's insertion time into the mempool is beyond ttl-duration. +ttl-num-blocks = 0 + ####################################################### ### State Sync Configuration Options ### ####################################################### @@ -389,6 +410,17 @@ create_empty_blocks_interval = "0s" peer_gossip_sleep_duration = "100ms" peer_query_maj23_sleep_duration = "2s" +####################################################### +### Storage Configuration Options ### +####################################################### +[storage] + +# Set to true to discard ABCI responses from the state store, which can save a +# considerable amount of disk space. Set to false to ensure ABCI responses are +# persisted. ABCI responses are required for /block_results RPC queries, and to +# reindex events in the command-line tool. +discard_abci_responses = false + ####################################################### ### Transaction Indexer Configuration Options ### ####################################################### @@ -403,8 +435,14 @@ peer_query_maj23_sleep_duration = "2s" # 1) "null" # 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). # - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. +# 3) "psql" - the indexer services backed by PostgreSQL. +# When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed. indexer = "kv" +# The PostgreSQL connection configuration, the connection format: +# postgresql://:@:/? +psql-conn = "" + ####################################################### ### Instrumentation Configuration Options ### ####################################################### diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/genesis.json b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/genesis.json index 702df913..b113cbb0 100755 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/genesis.json +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/genesis.json @@ -6,7 +6,7 @@ { "@type": "/cosmos.auth.v1beta1.BaseAccount", "account_number": "0", - "address": "wasm17e5l4ggxlyjf7k5scnas2zflwmnj9gjg54kce7", + "address": "wasm1gcmy8theke4de45ltsqpcpkdhphlrkvt58h4c7", "pub_key": null, "sequence": "0" }, @@ -32,7 +32,7 @@ "bank": { "balances": [ { - "address": "wasm14qemq0vw6y3gc3u3e0aty2e764u4gs5lndxgyk", + "address": "wasm1gcmy8theke4de45ltsqpcpkdhphlrkvt58h4c7", "coins": [ { "amount": "1000000000", @@ -45,7 +45,7 @@ ] }, { - "address": "wasm17e5l4ggxlyjf7k5scnas2zflwmnj9gjg54kce7", + "address": "wasm14qemq0vw6y3gc3u3e0aty2e764u4gs5lndxgyk", "coins": [ { "amount": "1000000000", @@ -109,6 +109,13 @@ "feegrant": { "allowances": [] }, + "feeibc": { + "fee_enabled_channels": [], + "forward_relayers": [], + "identified_fees": [], + "registered_counterparty_payees": [], + "registered_payees": [] + }, "genutil": { "gen_txs": [ { @@ -128,7 +135,7 @@ }, "public_key": { "@type": "/cosmos.crypto.secp256k1.PubKey", - "key": "A+Mv0AWmUlfsrAvrUCYB2wOxnlBXzjFkAHXmUMalA50y" + "key": "A3gUaZlQt3T09/j1BI4p7LntVZ2yglOmBsd6Vd4YO2Gq" }, "sequence": "0" } @@ -136,7 +143,7 @@ }, "body": { "extension_options": [], - "memo": "e00476a52bbadced4266814cee02b61c4cbdb860@172.17.0.2:26656", + "memo": "26c7c817ace009a62fb1d738da5306a0b26da118@172.17.0.2:26656", "messages": [ { "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", @@ -145,7 +152,7 @@ "max_rate": "0.200000000000000000", "rate": "0.100000000000000000" }, - "delegator_address": "wasm17e5l4ggxlyjf7k5scnas2zflwmnj9gjg54kce7", + "delegator_address": "wasm1gcmy8theke4de45ltsqpcpkdhphlrkvt58h4c7", "description": { "details": "", "identity": "", @@ -156,9 +163,9 @@ "min_self_delegation": "1", "pubkey": { "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "pbhQLheUqr0nbaNZ7z1wzAsXjLRilfq4xbcaMN2XRUY=" + "key": "ANnDt7akCVJA5ZfjN6JS30pAMqSji5H0iYQJYAVyxg4=" }, - "validator_address": "wasmvaloper17e5l4ggxlyjf7k5scnas2zflwmnj9gjgpfryhy", + "validator_address": "wasmvaloper1gcmy8theke4de45ltsqpcpkdhphlrkvtpmzfky", "value": { "amount": "3000000", "denom": "ustake" @@ -169,7 +176,7 @@ "timeout_height": "0" }, "signatures": [ - "oHhjuBqgpc8xV6SZu5v8E0Bf653PPRPvqYjsI+6l1ht1aeGF8f+ym+UynVvQj9mHc0EXlts23dN9Ht7/jm2WEA==" + "RrDjxSJ54Usm7baq8THVMsXqODAbf2FWBrF94lZNLLM4T6g8Q+ye2QJOQxELLmMBZQ5ma38/LAOe9JgV98Brug==" ] } ] @@ -305,10 +312,10 @@ "wasm": { "codes": [], "contracts": [], - "gen_msgs": [], "params": { "code_upload_access": { "address": "", + "addresses": [], "permission": "Everybody" }, "instantiate_default_permission": "Everybody" @@ -335,6 +342,6 @@ }, "version": {} }, - "genesis_time": "2022-07-20T20:02:34.612004135Z", + "genesis_time": "2023-11-14T15:03:15.461504699Z", "initial_height": "1" } diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/gentx/gentx-26c7c817ace009a62fb1d738da5306a0b26da118.json b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/gentx/gentx-26c7c817ace009a62fb1d738da5306a0b26da118.json new file mode 100755 index 00000000..2058b137 --- /dev/null +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/gentx/gentx-26c7c817ace009a62fb1d738da5306a0b26da118.json @@ -0,0 +1 @@ +{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"wasm-moniker","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"wasm1gcmy8theke4de45ltsqpcpkdhphlrkvt58h4c7","validator_address":"wasmvaloper1gcmy8theke4de45ltsqpcpkdhphlrkvtpmzfky","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"ANnDt7akCVJA5ZfjN6JS30pAMqSji5H0iYQJYAVyxg4="},"value":{"denom":"ustake","amount":"3000000"}}],"memo":"26c7c817ace009a62fb1d738da5306a0b26da118@172.17.0.2:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A3gUaZlQt3T09/j1BI4p7LntVZ2yglOmBsd6Vd4YO2Gq"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":["RrDjxSJ54Usm7baq8THVMsXqODAbf2FWBrF94lZNLLM4T6g8Q+ye2QJOQxELLmMBZQ5ma38/LAOe9JgV98Brug=="]} diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/gentx/gentx-e00476a52bbadced4266814cee02b61c4cbdb860.json b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/gentx/gentx-e00476a52bbadced4266814cee02b61c4cbdb860.json deleted file mode 100755 index 402ce16f..00000000 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/gentx/gentx-e00476a52bbadced4266814cee02b61c4cbdb860.json +++ /dev/null @@ -1 +0,0 @@ -{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"wasm-moniker","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"wasm17e5l4ggxlyjf7k5scnas2zflwmnj9gjg54kce7","validator_address":"wasmvaloper17e5l4ggxlyjf7k5scnas2zflwmnj9gjgpfryhy","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"pbhQLheUqr0nbaNZ7z1wzAsXjLRilfq4xbcaMN2XRUY="},"value":{"denom":"ustake","amount":"3000000"}}],"memo":"e00476a52bbadced4266814cee02b61c4cbdb860@172.17.0.2:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A+Mv0AWmUlfsrAvrUCYB2wOxnlBXzjFkAHXmUMalA50y"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":["oHhjuBqgpc8xV6SZu5v8E0Bf653PPRPvqYjsI+6l1ht1aeGF8f+ym+UynVvQj9mHc0EXlts23dN9Ht7/jm2WEA=="]} diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/node_key.json b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/node_key.json index 1ecb9bad..2bbac6ad 100755 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/node_key.json +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/node_key.json @@ -1 +1 @@ -{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"n9jWRTekT/X5IxciXaXt7tNkVqvnrz74shUX9CctXsJp7wZeMgedPT4DvASVkJz1EkF0v/yU40ePH7AwL4IlQg=="}} \ No newline at end of file +{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"aCfvBT1RzaaSADHLp44Gw7LJUhlFCcqyApG6F9OWL8kM4ES+PCDGBxXq8hz7r+MYFioVF57XCEFuAPypUVhMUw=="}} \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/priv_validator_key.json b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/priv_validator_key.json index ecb598da..81cdaf34 100755 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/priv_validator_key.json +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/config/priv_validator_key.json @@ -1,11 +1,11 @@ { - "address": "DB364DA3F19040792740269C079AB040D0ACC9B2", + "address": "B5C997507B4C1DAB75EC641810E92288E5060BBD", "pub_key": { "type": "tendermint/PubKeyEd25519", - "value": "pbhQLheUqr0nbaNZ7z1wzAsXjLRilfq4xbcaMN2XRUY=" + "value": "ANnDt7akCVJA5ZfjN6JS30pAMqSji5H0iYQJYAVyxg4=" }, "priv_key": { "type": "tendermint/PrivKeyEd25519", - "value": "8+09drNpixEZe/Dbfm+0x46hD/8jZS5c3NLLt6UmmJGluFAuF5SqvSdto1nvPXDMCxeMtGKV+rjFtxow3ZdFRg==" + "value": "IQhl9yQ752Iu3r+c4cx7ujHOhCROCw04O1/+72dyHpcA2cO3tqQJUkDll+M3olLfSkAypKOLkfSJhAlgBXLGDg==" } } \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/f669faa106f9249f5a90c4fb05093f76e722a248.address b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/f669faa106f9249f5a90c4fb05093f76e722a248.address deleted file mode 100755 index d2e278f0..00000000 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/f669faa106f9249f5a90c4fb05093f76e722a248.address +++ /dev/null @@ -1 +0,0 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMi0wNy0yMCAyMDowMjozNS45NTM2Nzg1OTQgKzAwMDAgVVRDIG09KzAuNjM3NzgyNzEwIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiZ25rZXlFR19hUnN3YTZJUiJ9.AoopwzMV7GLdqWwAkZK3MM3PEIwYCTdmeUtx15k5GqLVjoKHUFb0uw.hbxwFa3kKKGwXpAi.en1eHLJPI3FBMlNd5wI894HgHQV_EqRjFnS3ou9BuGESqbZUrvCNyCfJBP3tRGhnkSrUCvFuDiUolNd69o83QtThNK8BFRRbQVyHGaJPI5ZuhuaF_kt3FYmp7UrfVlumUve6Lx4_WY9aBN46MvRF3y5E49Qjer6Y8kqx61F23ag7NJ3ZHYhfRjbV6FyLcH-pSAjmIjLIqxIoLQOvZTWfg8z5aRhGIbRG9D_OCUjRX6-0jensqZVo9AJP.RWSTQClG4C9PalvJuBGJcA \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/keyhash b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/keyhash index 38ea506b..f653b402 100755 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/keyhash +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/keyhash @@ -1 +1 @@ -$2a$10$nL84R.qjyT23fDjFWaNZPOp8DBiOoQRsZmDwXy65PfKoh7uWNz6OW \ No newline at end of file +$2a$10$GDGCUnze67O.aM2H10FDceluDNDR3a2QnKgrw3E0cAee0en/bf162 \ No newline at end of file diff --git a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/validator.info b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/validator.info index 6d575220..13e0c288 100755 --- a/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/validator.info +++ b/ts-relayer-tests/ci-scripts/wasmd/template/.wasmd/validator.info @@ -1 +1 @@ -eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMi0wNy0yMCAyMDowMjozNS45MTY2MTYxMzUgKzAwMDAgVVRDIG09KzAuNjAwNzIwMzM1IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoieU50NHRidGt6TUFZUVhOUyJ9.An0WIFG-o5_GHSfxTVs_PBVXKUHAlWjRdtLdKLbvDFqZ8GAPKebQSA.D0iZKIsCrLxx2zei.V9Zu-tGT9ULjYDu9pwwnjT5bJ7UidmTC4JbEKgac_GryRCfhy9Lmvumqyb38EbGGkAich27ZUHASLzWEC7clh3Z9_e70WQNsTqegoKdG_IG9YOa0-rC2eW_JGfnI-WSpE80tF7foA2sXBtug7YAfQL4JSyfIASbuc4odtTb_Vs0GhfPNS4cQSu0Z2GfT6WEgfPYnE7xU6nPAe39wiZDDgXPhB_TZZrLqMqycHYrYiIo4IwLwHDGlERjXnyh1KFOz0w0yRpl666HyUMAgkM7BR6D6_FXipr1g5d7ngfj4FWoAKjoxtq6vA2IjcWqGV1vSMC7ZbkXwr8M4Fqs0L3SYBYRqfWSMQEkMi3p0geKn74wOsMvg.a5z4pZrwHtY5USo8fj8UeA \ No newline at end of file +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMy0xMS0xNCAxNTowMzoxNS42NTUxNjc4ODcgKzAwMDAgVVRDIG09KzAuMDkzOTA0NzYyIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoibmM5QXJmMU1JMWtjWkZ6bSJ9.JwCDFhkgY-YRDdCgShPsOdpViD8tHDHwj9y65aR4gLaNcsOMF_Pisg.RnUrk71vZ7GnPZeB.99yx-kS7p_obKtohMDljJcJuKZZ4D1t27wMaE8xCI2fam1VYD7wqiCPBZvsm-s91Bk5BEqJgnxlPMApGe3ZadTc7dSKS1mSUyDELeW6zF7sggfJlFfiqFCiuTKk-2K421u8A0U_DPuC7qpnXIt1ubSVtGNbR1lrcZlC5u8CbzRvLygcLhTjVWIGFrN-XOwUT9A9I_wvfMNta4H7iQoR6q6Nr1-5ByUFWrvwK7neLQWyFhf4tkqI9dweaA55jBWcRLRbboxmXPpdioOsPnc05Sm7iWmHFPc9yGkmfDHuaDSqaaC0La0KHS6CpyM40G1RSZvLKgJ-VHz6GPNTXgMLFAazenfqTqvhr-sd1GJO8gQjb2CjE.c3hM-DJoMDHmswbsL3KgEQ \ No newline at end of file diff --git a/ts-relayer-tests/package-lock.json b/ts-relayer-tests/package-lock.json index d746d6b3..50588877 100644 --- a/ts-relayer-tests/package-lock.json +++ b/ts-relayer-tests/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { - "@confio/relayer": "^0.5.1" + "@confio/relayer": "^0.10" }, "devDependencies": { "@ava/typescript": "^3.0.1", @@ -449,24 +449,24 @@ } }, "node_modules/@confio/relayer": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@confio/relayer/-/relayer-0.5.1.tgz", - "integrity": "sha512-SvUYFze9Mgvj/pjAfhPQXtGw0jd2hE8m1LlRvX/iw2ndkWyHcp2WsgqJosCqDZcuBUrgW0KgqgvwPUv3bKJqbQ==", - "dependencies": { - "@cosmjs/cosmwasm-stargate": "^0.28.9", - "@cosmjs/crypto": "^0.28.9", - "@cosmjs/encoding": "^0.28.9", - "@cosmjs/faucet-client": "^0.28.9", - "@cosmjs/math": "^0.28.9", - "@cosmjs/proto-signing": "^0.28.9", - "@cosmjs/stargate": "^0.28.9", - "@cosmjs/stream": "^0.28.9", - "@cosmjs/tendermint-rpc": "^0.28.9", - "@cosmjs/utils": "^0.28.9", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@confio/relayer/-/relayer-0.10.0.tgz", + "integrity": "sha512-/WW5Eyfgylby9u0wz6XakA7yo5hamdWh6pxkOYHPz0ls7ikd7Ld+c2fpRbL0Qg5wZn9+9P+Uhfj4l0pVl3WPgw==", + "dependencies": { + "@cosmjs/cosmwasm-stargate": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/faucet-client": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/proto-signing": "^0.31.0", + "@cosmjs/stargate": "^0.31.0", + "@cosmjs/stream": "^0.31.0", + "@cosmjs/tendermint-rpc": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "ajv": "7.1.1", "axios": "0.21.4", "commander": "7.1.0", - "cosmjs-types": "^0.4.0", + "cosmjs-types": "^0.8.0", "fast-safe-stringify": "2.0.4", "js-yaml": "4.0.0", "lodash": "4.17.21", @@ -485,52 +485,52 @@ } }, "node_modules/@cosmjs/amino": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.28.11.tgz", - "integrity": "sha512-WJkQQq8gbk5doJJ/3Gcax26I+VC4HdbbSlNdyT5hc6T+U2Jmyry9RLSE+wEZyFMgEabhr43SbIxf64gWZeR8YA==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.3.tgz", + "integrity": "sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==", "dependencies": { - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/utils": "0.28.11" + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3" } }, "node_modules/@cosmjs/cosmwasm-stargate": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.28.11.tgz", - "integrity": "sha512-sZ04c9ZvwAC7IngNeOhTnHJLBu7PXX3QfWM2vCVGd9puP9f3Hj3nbre75WKjHZ3DDVvxfS3u3JUJ6LjVWeIRuQ==", - "dependencies": { - "@cosmjs/amino": "0.28.11", - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/proto-signing": "0.28.11", - "@cosmjs/stargate": "0.28.11", - "@cosmjs/tendermint-rpc": "0.28.11", - "@cosmjs/utils": "0.28.11", - "cosmjs-types": "^0.4.0", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.31.3.tgz", + "integrity": "sha512-Uv9TmCn3650gdFeZm7SEfUZF3uX3lfJfFhXOk6I2ZLr/FrKximnlb+vwAfZaZnWYvlA7qrKtHIjeRNHvT23zcw==", + "dependencies": { + "@cosmjs/amino": "^0.31.3", + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/proto-signing": "^0.31.3", + "@cosmjs/stargate": "^0.31.3", + "@cosmjs/tendermint-rpc": "^0.31.3", + "@cosmjs/utils": "^0.31.3", + "cosmjs-types": "^0.8.0", "long": "^4.0.0", "pako": "^2.0.2" } }, "node_modules/@cosmjs/crypto": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.28.11.tgz", - "integrity": "sha512-oJXOeBX4FP8bp0ZVydJFcRplErHp8cC6vNoULRck+7hcLuvp9tyv3SBOkBkwxTv81VcQyGCgn7WE0NYEKrpUbw==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.3.tgz", + "integrity": "sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==", "dependencies": { - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/utils": "0.28.11", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3", "@noble/hashes": "^1", "bn.js": "^5.2.0", - "elliptic": "^6.5.3", - "libsodium-wrappers": "^0.7.6" + "elliptic": "^6.5.4", + "libsodium-wrappers-sumo": "^0.7.11" } }, "node_modules/@cosmjs/encoding": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.28.11.tgz", - "integrity": "sha512-J7pvlzAt8hBZn316wGRmUlK3xwMgNXUvj4v56DK4fA0fv6VfGwMvVtHCXaqNQtzOGkC6EQcshzA/fL5MBIwu6A==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.3.tgz", + "integrity": "sha512-6IRtG0fiVYwyP7n+8e54uTx2pLYijO48V3t9TLiROERm5aUAIzIlz6Wp0NYaI5he9nh1lcEGJ1lkquVKFw3sUg==", "dependencies": { "base64-js": "^1.3.0", "bech32": "^1.1.4", @@ -538,103 +538,103 @@ } }, "node_modules/@cosmjs/faucet-client": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/faucet-client/-/faucet-client-0.28.11.tgz", - "integrity": "sha512-alQGznExoZKTFWrA7ejyCVWa3t2VI162MY9uDlV0MbeGOcS9GgAtapHUlapd4q1Ynq6PQ35tlLEITpsBR4VJoQ==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/faucet-client/-/faucet-client-0.31.3.tgz", + "integrity": "sha512-gsVD/UD1R2k00iRVcBwXRgTkwzsnapfw8n1eWfc7o44xg0aVG8YL84ntj2YmjC9+NHCp2rmK9xndQeUOFIszOA==", "dependencies": { "axios": "^0.21.2" } }, "node_modules/@cosmjs/json-rpc": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.28.11.tgz", - "integrity": "sha512-YNZTozu5yWHyGGet5Wfc0CcxQezkMr37YaeU9elCaa11ClHlYAQ2NrPpPBOmgnJKsMhzfiKcAE9Sf6f4a0hCxA==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.31.3.tgz", + "integrity": "sha512-7LVYerXjnm69qqYR3uA6LGCrBW2EO5/F7lfJxAmY+iII2C7xO3a0vAjMSt5zBBh29PXrJVS6c2qRP22W1Le2Wg==", "dependencies": { - "@cosmjs/stream": "0.28.11", + "@cosmjs/stream": "^0.31.3", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/math": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.28.11.tgz", - "integrity": "sha512-MyhPnC4sYu86c2/0PpEeynaPl4nvAmLZH3acPh96SzcjERONbGZjjKtBFPq1avBrev2CCSPrZ4O8u9xpQ4aSvg==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.3.tgz", + "integrity": "sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==", "dependencies": { "bn.js": "^5.2.0" } }, "node_modules/@cosmjs/proto-signing": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.28.11.tgz", - "integrity": "sha512-ym0DpLff+0RBkD/mtFf6wrzyuGhcbcjuDMEdcUWOrJTo6n8DXeRmHkJkyy/mrG3QC4tQX/A81+DhfkANQmgcxw==", - "dependencies": { - "@cosmjs/amino": "0.28.11", - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/utils": "0.28.11", - "cosmjs-types": "^0.4.0", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.3.tgz", + "integrity": "sha512-24+10/cGl6lLS4VCrGTCJeDRPQTn1K5JfknzXzDIHOx8THR31JxA7/HV5eWGHqWgAbudA7ccdSvEK08lEHHtLA==", + "dependencies": { + "@cosmjs/amino": "^0.31.3", + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3", + "cosmjs-types": "^0.8.0", "long": "^4.0.0" } }, "node_modules/@cosmjs/socket": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.28.11.tgz", - "integrity": "sha512-4BhsWN984SLBhwPCD89riQ3SEJzJ1RLJPeP6apIGjhh6pguQZmwa2U/TZjnEUOGnJkUG2FZUH99jRGSTYaIvZg==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.31.3.tgz", + "integrity": "sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==", "dependencies": { - "@cosmjs/stream": "0.28.11", + "@cosmjs/stream": "^0.31.3", "isomorphic-ws": "^4.0.1", "ws": "^7", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/stargate": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.28.11.tgz", - "integrity": "sha512-UyFH/mTNNKTZohVhj+SmjCRv/xopqU/UinGedmWzs4MqEZteX9xs6D3HTmRCgpmBQ03lpbTslE/FhhT9Hkl9KQ==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.31.3.tgz", + "integrity": "sha512-53NxnzmB9FfXpG4KjOUAYAvWLYKdEmZKsutcat/u2BrDXNZ7BN8jim/ENcpwXfs9/Og0K24lEIdvA4gsq3JDQw==", "dependencies": { "@confio/ics23": "^0.6.8", - "@cosmjs/amino": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/proto-signing": "0.28.11", - "@cosmjs/stream": "0.28.11", - "@cosmjs/tendermint-rpc": "0.28.11", - "@cosmjs/utils": "0.28.11", - "cosmjs-types": "^0.4.0", + "@cosmjs/amino": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/proto-signing": "^0.31.3", + "@cosmjs/stream": "^0.31.3", + "@cosmjs/tendermint-rpc": "^0.31.3", + "@cosmjs/utils": "^0.31.3", + "cosmjs-types": "^0.8.0", "long": "^4.0.0", "protobufjs": "~6.11.3", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/stream": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.28.11.tgz", - "integrity": "sha512-3b6P4Il8mYzvY2bvEQyzgP+cm0HIGSpHNtuGjiWsQF3Wtp450iVRfEJqdt4+91vvxzfdjQEkQOLMaymnswX3sw==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.31.3.tgz", + "integrity": "sha512-8keYyI7X0RjsLyVcZuBeNjSv5FA4IHwbFKx7H60NHFXszN8/MvXL6aZbNIvxtcIHHsW7K9QSQos26eoEWlAd+w==", "dependencies": { "xstream": "^11.14.0" } }, "node_modules/@cosmjs/tendermint-rpc": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.28.11.tgz", - "integrity": "sha512-TUhWsUYxbKftQmHQK5TBH62vNaKB1ybxoFZ2uJtGMVvY3jcBux7P0Ll/u5nwrM0ETAeo2RjucehJUpGBy9q+HQ==", - "dependencies": { - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/json-rpc": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/socket": "0.28.11", - "@cosmjs/stream": "0.28.11", - "@cosmjs/utils": "0.28.11", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.3.tgz", + "integrity": "sha512-s3TiWkPCW4QceTQjpYqn4xttUJH36mTPqplMl+qyocdqk5+X5mergzExU/pHZRWQ4pbby8bnR7kMvG4OC1aZ8g==", + "dependencies": { + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/json-rpc": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/socket": "^0.31.3", + "@cosmjs/stream": "^0.31.3", + "@cosmjs/utils": "^0.31.3", "axios": "^0.21.2", "readonly-date": "^1.0.0", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/utils": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.28.11.tgz", - "integrity": "sha512-FXVEr7Pg6MX9VbY5NemuKbtFVabSlUlArWIV+R74FQg5LIuSa+0QkxSpNldCuOLBEU4/GlrzybT4uEl338vSzg==" + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.3.tgz", + "integrity": "sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==" }, "node_modules/@dabh/diagnostics": { "version": "2.0.3", @@ -909,15 +909,15 @@ } }, "node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -2053,9 +2053,9 @@ } }, "node_modules/cosmjs-types": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.4.1.tgz", - "integrity": "sha512-I7E/cHkIgoJzMNQdFF0YVqPlaTqrqKHrskuSTIqlEyxfB5Lf3WKCajSXVK2yHOfOFfSux/RxEdpMzw/eO4DIog==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.8.0.tgz", + "integrity": "sha512-Q2Mj95Fl0PYMWEhA2LuGEIhipF7mQwd9gTQ85DdP9jjjopeoGaDxvmPa5nakNzsq7FnO1DMTatXTAx6bxMH7Lg==", "dependencies": { "long": "^4.0.0", "protobufjs": "~6.11.2" @@ -3072,9 +3072,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "node_modules/follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", @@ -4117,17 +4117,17 @@ "node": ">= 0.8.0" } }, - "node_modules/libsodium": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", - "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" + "node_modules/libsodium-sumo": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.13.tgz", + "integrity": "sha512-zTGdLu4b9zSNLfovImpBCbdAA4xkpkZbMnSQjP8HShyOutnGjRHmSOKlsylh1okao6QhLiz7nG98EGn+04cZjQ==" }, - "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==", + "node_modules/libsodium-wrappers-sumo": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.13.tgz", + "integrity": "sha512-lz4YdplzDRh6AhnLGF2Dj2IUj94xRN6Bh8T0HLNwzYGwPehQJX6c7iYVrFUPZ3QqxE0bqC+K0IIqqZJYWumwSQ==", "dependencies": { - "libsodium": "^0.7.0" + "libsodium-sumo": "^0.7.13" } }, "node_modules/load-json-file": { @@ -5137,9 +5137,9 @@ } }, "node_modules/pako": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz", - "integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" }, "node_modules/parent-module": { "version": "1.0.1", @@ -5520,9 +5520,9 @@ } }, "node_modules/protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -7317,24 +7317,24 @@ } }, "@confio/relayer": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@confio/relayer/-/relayer-0.5.1.tgz", - "integrity": "sha512-SvUYFze9Mgvj/pjAfhPQXtGw0jd2hE8m1LlRvX/iw2ndkWyHcp2WsgqJosCqDZcuBUrgW0KgqgvwPUv3bKJqbQ==", - "requires": { - "@cosmjs/cosmwasm-stargate": "^0.28.9", - "@cosmjs/crypto": "^0.28.9", - "@cosmjs/encoding": "^0.28.9", - "@cosmjs/faucet-client": "^0.28.9", - "@cosmjs/math": "^0.28.9", - "@cosmjs/proto-signing": "^0.28.9", - "@cosmjs/stargate": "^0.28.9", - "@cosmjs/stream": "^0.28.9", - "@cosmjs/tendermint-rpc": "^0.28.9", - "@cosmjs/utils": "^0.28.9", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@confio/relayer/-/relayer-0.10.0.tgz", + "integrity": "sha512-/WW5Eyfgylby9u0wz6XakA7yo5hamdWh6pxkOYHPz0ls7ikd7Ld+c2fpRbL0Qg5wZn9+9P+Uhfj4l0pVl3WPgw==", + "requires": { + "@cosmjs/cosmwasm-stargate": "^0.31.0", + "@cosmjs/crypto": "^0.31.0", + "@cosmjs/encoding": "^0.31.0", + "@cosmjs/faucet-client": "^0.31.0", + "@cosmjs/math": "^0.31.0", + "@cosmjs/proto-signing": "^0.31.0", + "@cosmjs/stargate": "^0.31.0", + "@cosmjs/stream": "^0.31.0", + "@cosmjs/tendermint-rpc": "^0.31.0", + "@cosmjs/utils": "^0.31.0", "ajv": "7.1.1", "axios": "0.21.4", "commander": "7.1.0", - "cosmjs-types": "^0.4.0", + "cosmjs-types": "^0.8.0", "fast-safe-stringify": "2.0.4", "js-yaml": "4.0.0", "lodash": "4.17.21", @@ -7346,52 +7346,52 @@ } }, "@cosmjs/amino": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.28.11.tgz", - "integrity": "sha512-WJkQQq8gbk5doJJ/3Gcax26I+VC4HdbbSlNdyT5hc6T+U2Jmyry9RLSE+wEZyFMgEabhr43SbIxf64gWZeR8YA==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.31.3.tgz", + "integrity": "sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==", "requires": { - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/utils": "0.28.11" + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3" } }, "@cosmjs/cosmwasm-stargate": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.28.11.tgz", - "integrity": "sha512-sZ04c9ZvwAC7IngNeOhTnHJLBu7PXX3QfWM2vCVGd9puP9f3Hj3nbre75WKjHZ3DDVvxfS3u3JUJ6LjVWeIRuQ==", - "requires": { - "@cosmjs/amino": "0.28.11", - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/proto-signing": "0.28.11", - "@cosmjs/stargate": "0.28.11", - "@cosmjs/tendermint-rpc": "0.28.11", - "@cosmjs/utils": "0.28.11", - "cosmjs-types": "^0.4.0", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.31.3.tgz", + "integrity": "sha512-Uv9TmCn3650gdFeZm7SEfUZF3uX3lfJfFhXOk6I2ZLr/FrKximnlb+vwAfZaZnWYvlA7qrKtHIjeRNHvT23zcw==", + "requires": { + "@cosmjs/amino": "^0.31.3", + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/proto-signing": "^0.31.3", + "@cosmjs/stargate": "^0.31.3", + "@cosmjs/tendermint-rpc": "^0.31.3", + "@cosmjs/utils": "^0.31.3", + "cosmjs-types": "^0.8.0", "long": "^4.0.0", "pako": "^2.0.2" } }, "@cosmjs/crypto": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.28.11.tgz", - "integrity": "sha512-oJXOeBX4FP8bp0ZVydJFcRplErHp8cC6vNoULRck+7hcLuvp9tyv3SBOkBkwxTv81VcQyGCgn7WE0NYEKrpUbw==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.31.3.tgz", + "integrity": "sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==", "requires": { - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/utils": "0.28.11", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3", "@noble/hashes": "^1", "bn.js": "^5.2.0", - "elliptic": "^6.5.3", - "libsodium-wrappers": "^0.7.6" + "elliptic": "^6.5.4", + "libsodium-wrappers-sumo": "^0.7.11" } }, "@cosmjs/encoding": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.28.11.tgz", - "integrity": "sha512-J7pvlzAt8hBZn316wGRmUlK3xwMgNXUvj4v56DK4fA0fv6VfGwMvVtHCXaqNQtzOGkC6EQcshzA/fL5MBIwu6A==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.31.3.tgz", + "integrity": "sha512-6IRtG0fiVYwyP7n+8e54uTx2pLYijO48V3t9TLiROERm5aUAIzIlz6Wp0NYaI5he9nh1lcEGJ1lkquVKFw3sUg==", "requires": { "base64-js": "^1.3.0", "bech32": "^1.1.4", @@ -7399,103 +7399,103 @@ } }, "@cosmjs/faucet-client": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/faucet-client/-/faucet-client-0.28.11.tgz", - "integrity": "sha512-alQGznExoZKTFWrA7ejyCVWa3t2VI162MY9uDlV0MbeGOcS9GgAtapHUlapd4q1Ynq6PQ35tlLEITpsBR4VJoQ==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/faucet-client/-/faucet-client-0.31.3.tgz", + "integrity": "sha512-gsVD/UD1R2k00iRVcBwXRgTkwzsnapfw8n1eWfc7o44xg0aVG8YL84ntj2YmjC9+NHCp2rmK9xndQeUOFIszOA==", "requires": { "axios": "^0.21.2" } }, "@cosmjs/json-rpc": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.28.11.tgz", - "integrity": "sha512-YNZTozu5yWHyGGet5Wfc0CcxQezkMr37YaeU9elCaa11ClHlYAQ2NrPpPBOmgnJKsMhzfiKcAE9Sf6f4a0hCxA==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.31.3.tgz", + "integrity": "sha512-7LVYerXjnm69qqYR3uA6LGCrBW2EO5/F7lfJxAmY+iII2C7xO3a0vAjMSt5zBBh29PXrJVS6c2qRP22W1Le2Wg==", "requires": { - "@cosmjs/stream": "0.28.11", + "@cosmjs/stream": "^0.31.3", "xstream": "^11.14.0" } }, "@cosmjs/math": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.28.11.tgz", - "integrity": "sha512-MyhPnC4sYu86c2/0PpEeynaPl4nvAmLZH3acPh96SzcjERONbGZjjKtBFPq1avBrev2CCSPrZ4O8u9xpQ4aSvg==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.31.3.tgz", + "integrity": "sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==", "requires": { "bn.js": "^5.2.0" } }, "@cosmjs/proto-signing": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.28.11.tgz", - "integrity": "sha512-ym0DpLff+0RBkD/mtFf6wrzyuGhcbcjuDMEdcUWOrJTo6n8DXeRmHkJkyy/mrG3QC4tQX/A81+DhfkANQmgcxw==", - "requires": { - "@cosmjs/amino": "0.28.11", - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/utils": "0.28.11", - "cosmjs-types": "^0.4.0", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.31.3.tgz", + "integrity": "sha512-24+10/cGl6lLS4VCrGTCJeDRPQTn1K5JfknzXzDIHOx8THR31JxA7/HV5eWGHqWgAbudA7ccdSvEK08lEHHtLA==", + "requires": { + "@cosmjs/amino": "^0.31.3", + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/utils": "^0.31.3", + "cosmjs-types": "^0.8.0", "long": "^4.0.0" } }, "@cosmjs/socket": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.28.11.tgz", - "integrity": "sha512-4BhsWN984SLBhwPCD89riQ3SEJzJ1RLJPeP6apIGjhh6pguQZmwa2U/TZjnEUOGnJkUG2FZUH99jRGSTYaIvZg==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.31.3.tgz", + "integrity": "sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==", "requires": { - "@cosmjs/stream": "0.28.11", + "@cosmjs/stream": "^0.31.3", "isomorphic-ws": "^4.0.1", "ws": "^7", "xstream": "^11.14.0" } }, "@cosmjs/stargate": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.28.11.tgz", - "integrity": "sha512-UyFH/mTNNKTZohVhj+SmjCRv/xopqU/UinGedmWzs4MqEZteX9xs6D3HTmRCgpmBQ03lpbTslE/FhhT9Hkl9KQ==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.31.3.tgz", + "integrity": "sha512-53NxnzmB9FfXpG4KjOUAYAvWLYKdEmZKsutcat/u2BrDXNZ7BN8jim/ENcpwXfs9/Og0K24lEIdvA4gsq3JDQw==", "requires": { "@confio/ics23": "^0.6.8", - "@cosmjs/amino": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/proto-signing": "0.28.11", - "@cosmjs/stream": "0.28.11", - "@cosmjs/tendermint-rpc": "0.28.11", - "@cosmjs/utils": "0.28.11", - "cosmjs-types": "^0.4.0", + "@cosmjs/amino": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/proto-signing": "^0.31.3", + "@cosmjs/stream": "^0.31.3", + "@cosmjs/tendermint-rpc": "^0.31.3", + "@cosmjs/utils": "^0.31.3", + "cosmjs-types": "^0.8.0", "long": "^4.0.0", "protobufjs": "~6.11.3", "xstream": "^11.14.0" } }, "@cosmjs/stream": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.28.11.tgz", - "integrity": "sha512-3b6P4Il8mYzvY2bvEQyzgP+cm0HIGSpHNtuGjiWsQF3Wtp450iVRfEJqdt4+91vvxzfdjQEkQOLMaymnswX3sw==", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.31.3.tgz", + "integrity": "sha512-8keYyI7X0RjsLyVcZuBeNjSv5FA4IHwbFKx7H60NHFXszN8/MvXL6aZbNIvxtcIHHsW7K9QSQos26eoEWlAd+w==", "requires": { "xstream": "^11.14.0" } }, "@cosmjs/tendermint-rpc": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.28.11.tgz", - "integrity": "sha512-TUhWsUYxbKftQmHQK5TBH62vNaKB1ybxoFZ2uJtGMVvY3jcBux7P0Ll/u5nwrM0ETAeo2RjucehJUpGBy9q+HQ==", - "requires": { - "@cosmjs/crypto": "0.28.11", - "@cosmjs/encoding": "0.28.11", - "@cosmjs/json-rpc": "0.28.11", - "@cosmjs/math": "0.28.11", - "@cosmjs/socket": "0.28.11", - "@cosmjs/stream": "0.28.11", - "@cosmjs/utils": "0.28.11", + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.3.tgz", + "integrity": "sha512-s3TiWkPCW4QceTQjpYqn4xttUJH36mTPqplMl+qyocdqk5+X5mergzExU/pHZRWQ4pbby8bnR7kMvG4OC1aZ8g==", + "requires": { + "@cosmjs/crypto": "^0.31.3", + "@cosmjs/encoding": "^0.31.3", + "@cosmjs/json-rpc": "^0.31.3", + "@cosmjs/math": "^0.31.3", + "@cosmjs/socket": "^0.31.3", + "@cosmjs/stream": "^0.31.3", + "@cosmjs/utils": "^0.31.3", "axios": "^0.21.2", "readonly-date": "^1.0.0", "xstream": "^11.14.0" } }, "@cosmjs/utils": { - "version": "0.28.11", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.28.11.tgz", - "integrity": "sha512-FXVEr7Pg6MX9VbY5NemuKbtFVabSlUlArWIV+R74FQg5LIuSa+0QkxSpNldCuOLBEU4/GlrzybT4uEl338vSzg==" + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.31.3.tgz", + "integrity": "sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==" }, "@dabh/diagnostics": { "version": "2.0.3", @@ -7713,9 +7713,9 @@ } }, "@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==" + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==" }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -8546,9 +8546,9 @@ "dev": true }, "cosmjs-types": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.4.1.tgz", - "integrity": "sha512-I7E/cHkIgoJzMNQdFF0YVqPlaTqrqKHrskuSTIqlEyxfB5Lf3WKCajSXVK2yHOfOFfSux/RxEdpMzw/eO4DIog==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.8.0.tgz", + "integrity": "sha512-Q2Mj95Fl0PYMWEhA2LuGEIhipF7mQwd9gTQ85DdP9jjjopeoGaDxvmPa5nakNzsq7FnO1DMTatXTAx6bxMH7Lg==", "requires": { "long": "^4.0.0", "protobufjs": "~6.11.2" @@ -9343,9 +9343,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" }, "foreground-child": { "version": "2.0.0", @@ -10072,17 +10072,17 @@ "type-check": "~0.4.0" } }, - "libsodium": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", - "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" + "libsodium-sumo": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.13.tgz", + "integrity": "sha512-zTGdLu4b9zSNLfovImpBCbdAA4xkpkZbMnSQjP8HShyOutnGjRHmSOKlsylh1okao6QhLiz7nG98EGn+04cZjQ==" }, - "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==", + "libsodium-wrappers-sumo": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.13.tgz", + "integrity": "sha512-lz4YdplzDRh6AhnLGF2Dj2IUj94xRN6Bh8T0HLNwzYGwPehQJX6c7iYVrFUPZ3QqxE0bqC+K0IIqqZJYWumwSQ==", "requires": { - "libsodium": "^0.7.0" + "libsodium-sumo": "^0.7.13" } }, "load-json-file": { @@ -10854,9 +10854,9 @@ } }, "pako": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz", - "integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" }, "parent-module": { "version": "1.0.1", @@ -11117,9 +11117,9 @@ } }, "protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", diff --git a/ts-relayer-tests/package.json b/ts-relayer-tests/package.json index a8043062..2718a8a3 100644 --- a/ts-relayer-tests/package.json +++ b/ts-relayer-tests/package.json @@ -20,7 +20,7 @@ "test:unit": "nyc --silent ava --serial" }, "dependencies": { - "@confio/relayer": "^0.5.1" + "@confio/relayer": "^0.10" }, "devDependencies": { "@ava/typescript": "^3.0.1",