diff --git a/Cargo.lock b/Cargo.lock index abeb3c37e1..ac352c58c6 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,6 +60,23 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.11" @@ -164,9 +181,9 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "atomic-waker" @@ -190,7 +207,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -201,6 +218,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "basic-features" version = "0.0.0" @@ -243,9 +266,9 @@ dependencies = [ [[package]] name = "bech32" -version = "0.9.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "benchmark-common" @@ -279,8 +302,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", - "rand_core 0.6.4", + "rand", + "rand_core", "serde", "unicode-normalization", ] @@ -291,27 +314,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -378,15 +386,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.7" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -429,11 +440,21 @@ dependencies = [ "multiversx-sc-meta-lib", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" -version = "4.5.11" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", "clap_derive", @@ -441,9 +462,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.11" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -453,9 +474,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.11" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", @@ -509,6 +530,12 @@ dependencies = [ "vault", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "convert_case" version = "0.6.0" @@ -539,15 +566,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -664,24 +691,36 @@ dependencies = [ "multiversx-sc-meta-lib", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", "subtle", "zeroize", ] [[package]] -name = "derive_arbitrary" -version = "1.3.2" +name = "curve25519-dalek-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", @@ -689,12 +728,24 @@ dependencies = [ ] [[package]] -name = "digest" -version = "0.9.0" +name = "der" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ - "generic-array", + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -703,7 +754,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "crypto-common", "subtle", ] @@ -737,24 +788,25 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.3" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ + "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", "serde", - "sha2 0.9.9", + "sha2", + "subtle", "zeroize", ] @@ -1001,9 +1053,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "first-contract" @@ -1024,12 +1082,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -1260,17 +1318,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -1280,7 +1327,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1305,9 +1352,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -1362,7 +1409,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] @@ -1466,9 +1513,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", @@ -1512,15 +1559,24 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", "serde", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "interact" version = "0.0.0" @@ -1561,9 +1617,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1664,9 +1720,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "linked-list-repeat" @@ -1817,15 +1873,24 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.52.0", ] @@ -1899,7 +1964,7 @@ dependencies = [ name = "multiversx-chain-vm" version = "0.9.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "colored", "ed25519-dalek", "hex", @@ -1908,9 +1973,9 @@ dependencies = [ "multiversx-chain-vm-executor", "num-bigint", "num-traits", - "rand 0.8.5", + "rand", "rand_seeder", - "sha2 0.10.8", + "sha2", "sha3", ] @@ -1925,11 +1990,11 @@ name = "multiversx-price-aggregator-sc" version = "0.52.3" dependencies = [ "arrayvec", - "getrandom 0.2.15", + "getrandom", "multiversx-sc", "multiversx-sc-modules", "multiversx-sc-scenario", - "rand 0.8.5", + "rand", ] [[package]] @@ -1945,7 +2010,7 @@ dependencies = [ name = "multiversx-sc" version = "0.52.3" dependencies = [ - "bitflags 2.6.0", + "bitflags", "hex-literal", "multiversx-sc-codec", "multiversx-sc-derive", @@ -1988,6 +2053,7 @@ dependencies = [ name = "multiversx-sc-meta" version = "0.52.3" dependencies = [ + "bip39", "clap", "colored", "common-path", @@ -2053,7 +2119,7 @@ dependencies = [ "pathdiff", "serde", "serde_json", - "sha2 0.10.8", + "sha2", "unwrap-infallible", ] @@ -2084,24 +2150,28 @@ dependencies = [ name = "multiversx-sdk" version = "0.5.0" dependencies = [ + "aes", "anyhow", "base64", "bech32", "bip39", + "ctr", "hex", "hmac", "itertools", "log", "pbkdf2", "pem", - "rand 0.8.5", + "rand", "reqwest", + "scrypt", "serde", "serde_json", "serde_repr", - "sha2 0.10.8", + "sha2", "sha3", "tokio", + "uuid", "zeroize", ] @@ -2239,9 +2309,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -2252,19 +2322,13 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl" version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -2382,6 +2446,17 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "pathdiff" version = "0.2.1" @@ -2414,7 +2489,8 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest 0.10.7", + "digest", + "hmac", ] [[package]] @@ -2481,6 +2557,16 @@ dependencies = [ "ping-pong-egld", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -2489,12 +2575,11 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "ppv-lite86" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2288c0e17cc8d342c712bb43a257a80ebffce59cdb33d5000d8348f3ec02528b" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", - "zerocopy-derive", ] [[package]] @@ -2590,9 +2675,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2607,19 +2692,6 @@ dependencies = [ "nibble_vec", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -2627,18 +2699,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -2648,16 +2710,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -2666,25 +2719,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] name = "rand_seeder" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" +checksum = "4a9febe641d2842ffc76ee962668a17578767c4e01735e4802b21ed9a24b2e4e" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -2717,14 +2761,14 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -2751,9 +2795,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64", "bytes", @@ -2790,7 +2834,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "windows-registry", ] [[package]] @@ -2818,7 +2862,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", "spin", "untrusted", @@ -2899,7 +2943,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -2921,9 +2965,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64", "rustls-pki-types", @@ -2931,9 +2975,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -2952,6 +2996,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -2992,6 +3045,18 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "password-hash", + "pbkdf2", + "salsa20", + "sha2", +] + [[package]] name = "second-contract" version = "0.0.0" @@ -3015,7 +3080,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -3073,18 +3138,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", @@ -3093,9 +3158,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.121" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ "indexmap", "itoa", @@ -3153,19 +3218,6 @@ dependencies = [ "set-repeat", ] -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.8" @@ -3174,7 +3226,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -3183,10 +3235,16 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.7", + "digest", "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3198,9 +3256,12 @@ dependencies = [ [[package]] name = "signature" -version = "1.6.4" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core", +] [[package]] name = "simd-adler32" @@ -3256,6 +3317,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "str-repeat" version = "0.0.0" @@ -3286,9 +3357,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.72" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -3300,23 +3371,26 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "system-configuration" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" dependencies = [ "core-foundation-sys", "libc", @@ -3324,14 +3398,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3396,9 +3471,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.2" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", @@ -3459,9 +3534,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.17" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a44eede9b727419af8095cb2d72fab15487a541f54647ad4414b34096ee4631" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "indexmap", "serde", @@ -3481,9 +3556,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.18" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1490595c74d930da779e944f5ba2ecdf538af67df1a9848cbd156af43c1b7cf0" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "serde", @@ -3509,15 +3584,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -3642,6 +3717,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", +] + [[package]] name = "vault" version = "0.0.0" @@ -3706,12 +3790,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3720,19 +3798,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -3745,9 +3824,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -3757,9 +3836,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3767,9 +3846,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -3780,18 +3859,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasmparser" -version = "0.214.0" +version = "0.216.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5309c1090e3e84dad0d382f42064e9933fdaedb87e468cc239f0eabea73ddcb6" +checksum = "bcdee6bea3619d311fb4b299721e89a986c3470f804b6d534340e412589028e3" dependencies = [ "ahash", - "bitflags 2.6.0", + "bitflags", "hashbrown", "indexmap", "semver", @@ -3800,9 +3879,9 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.214.0" +version = "0.216.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58d4f2b3f7bd2ba10f99e03f885ff90d5db3455e163bccecebbbf60406bd8980" +checksum = "8f82916f3892e53620639217d6ec78fe15c678352a3fbf3f3745b6417d0bd70f" dependencies = [ "anyhow", "termcolor", @@ -3811,9 +3890,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -3821,11 +3900,41 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -3846,6 +3955,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3969,23 +4087,13 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.16" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "zerocopy" version = "0.7.35" @@ -4012,26 +4120,12 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "zip" -version = "2.1.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b895748a3ebcb69b9d38dcfdf21760859a4b0d0b0015277640c2ef4c69640e6f" +checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" dependencies = [ "arbitrary", "crc32fast", diff --git a/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs b/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs index b0e1f54455..a312b0ca1f 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs @@ -1,6 +1,6 @@ use multiversx_price_aggregator_sc::{ price_aggregator_data::{OracleStatus, TimestampedPrice, TokenPair}, - ContractObj, PriceAggregator, MAX_ROUND_DURATION_SECONDS, + PriceAggregator, MAX_ROUND_DURATION_SECONDS, }; use multiversx_sc_scenario::imports::*; @@ -35,7 +35,6 @@ fn world() -> ScenarioWorld { struct PriceAggregatorTestState { world: ScenarioWorld, oracles: Vec, - price_aggregator_whitebox: WhiteboxContract>, } impl PriceAggregatorTestState { @@ -57,16 +56,7 @@ impl PriceAggregatorTestState { oracles.push(address_value); } - let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS, - multiversx_price_aggregator_sc::contract_obj, - ); - - Self { - world, - oracles, - price_aggregator_whitebox, - } + Self { world, oracles } } fn deploy(&mut self) -> &mut Self { @@ -203,9 +193,10 @@ fn test_price_aggregator_submit() { state.submit(&state.oracles[0].clone(), 95, 100); let current_timestamp = 100; - state - .world - .whitebox_query(&state.price_aggregator_whitebox, |sc| { + + state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { let token_pair = TokenPair { from: managed_buffer!(EGLD_TICKER), to: managed_buffer!(USD_TICKER), @@ -237,14 +228,15 @@ fn test_price_aggregator_submit() { accepted_submissions: 1 } ); - }); + }, + ); // first oracle submit again - submission not accepted state.submit(&state.oracles[0].clone(), 95, 100); - state - .world - .whitebox_query(&state.price_aggregator_whitebox, |sc| { + state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { assert_eq!( sc.oracle_status() .get(&managed_address!(&state.oracles[0].to_address())) @@ -254,7 +246,8 @@ fn test_price_aggregator_submit() { accepted_submissions: 1 } ); - }); + }, + ); } #[test] @@ -283,9 +276,9 @@ fn test_price_aggregator_submit_round_ok() { // submit third state.submit(&state.oracles[2].clone(), 105, 12_000); - state - .world - .whitebox_query(&state.price_aggregator_whitebox, |sc| { + state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { let result = sc.latest_price_feed(managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER)); @@ -312,7 +305,8 @@ fn test_price_aggregator_submit_round_ok() { decimals } ); - }); + }, + ); } #[test] @@ -338,9 +332,9 @@ fn test_price_aggregator_discarded_round() { // submit second - this will discard the previous submission state.submit(&state.oracles[1].clone(), current_timestamp - 1, 11_000); - state - .world - .whitebox_query(&state.price_aggregator_whitebox, |sc| { + state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { let token_pair = TokenPair { from: managed_buffer!(EGLD_TICKER), to: managed_buffer!(USD_TICKER), @@ -353,7 +347,8 @@ fn test_price_aggregator_discarded_round() { .unwrap(), managed_biguint!(11_000) ); - }); + }, + ); } #[test] diff --git a/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs b/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs index 660bbf1dda..be457448b5 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs @@ -1,6 +1,6 @@ use multiversx_price_aggregator_sc::{ price_aggregator_data::{OracleStatus, TokenPair}, - ContractObj, PriceAggregator, + PriceAggregator, }; use multiversx_sc_scenario::imports::*; @@ -34,7 +34,6 @@ fn world() -> ScenarioWorld { struct PriceAggregatorTestState { world: ScenarioWorld, oracles: Vec, - price_aggregator_whitebox: WhiteboxContract>, } impl PriceAggregatorTestState { @@ -60,16 +59,7 @@ impl PriceAggregatorTestState { oracles.push(address_value); } - let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS, - multiversx_price_aggregator_sc::contract_obj, - ); - - Self { - world, - oracles, - price_aggregator_whitebox, - } + Self { world, oracles } } fn deploy(&mut self) -> &mut Self { @@ -170,9 +160,9 @@ fn test_price_aggregator_submit() { } let current_timestamp = 100; - state - .world - .whitebox_query(&state.price_aggregator_whitebox, |sc| { + state.world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { let blockchain_timestamp = sc.blockchain().get_block_timestamp(); let token_pair = TokenPair { @@ -207,7 +197,8 @@ fn test_price_aggregator_submit() { } ); } - }); + }, + ); // submit last that resets the round state.submit( diff --git a/contracts/core/price-aggregator/tests/price_aggregator_whitebox_test.rs b/contracts/core/price-aggregator/tests/price_aggregator_whitebox_test.rs index 180301b610..46ce6f52c3 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_whitebox_test.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_whitebox_test.rs @@ -4,7 +4,7 @@ use multiversx_price_aggregator_sc::{ }; use multiversx_sc_modules::{ pause::EndpointWrappers as PauseEndpointWrappers, - staking::EndpointWrappers as StakingEndpointWrappers, + staking::{EndpointWrappers as StakingEndpointWrappers, StakingModule}, }; use multiversx_sc_scenario::imports::*; @@ -17,9 +17,10 @@ pub const STAKE_AMOUNT: u64 = 20; pub const SUBMISSION_COUNT: usize = 3; pub const USD_TICKER: &[u8] = b"USDC"; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const PRICE_AGGREGATOR_ADDRESS_EXPR: &str = "sc:price-aggregator"; -const PRICE_AGGREGATOR_PATH_EXPR: &str = "mxsc:output/multiversx-price-aggregator-sc.mxsc.json"; +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const PRICE_AGGREGATOR_ADDRESS: TestSCAddress = TestSCAddress::new("price-aggregator"); +const PRICE_AGGREGATOR_PATH_EXPR: MxscPath = + MxscPath::new("mxsc:output/multiversx-price-aggregator-sc.mxsc.json"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); @@ -35,31 +36,27 @@ fn world() -> ScenarioWorld { #[test] fn test_price_aggregator_submit() { let (mut world, oracles) = setup(); - let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS_EXPR, - multiversx_price_aggregator_sc::contract_obj, - ); // configure the number of decimals - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.set_pair_decimals( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), DECIMALS, ) - }, - ); + }); // try submit while paused - world.whitebox_call_check( - &price_aggregator_whitebox, - ScCallStep::new() - .from(&oracles[0]) - .expect(TxExpect::user_error("str:Contract is paused")), - |sc| { + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .returns(ExpectError(4u64, "Contract is paused")) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -67,22 +64,24 @@ fn test_price_aggregator_submit() { managed_biguint!(100), DECIMALS, ) - }, - |r| r.assert_user_error("Contract is paused"), - ); + }); // unpause - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| sc.call_unpause_endpoint(), - ); + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.call_unpause_endpoint(); + }); // submit first timestamp too old - world.whitebox_call_check( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[0]).no_expect(), - |sc| { + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .returns(ExpectError(4u64, "First submission too old")) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -90,17 +89,14 @@ fn test_price_aggregator_submit() { managed_biguint!(100), DECIMALS, ) - }, - |r| { - r.assert_user_error("First submission too old"); - }, - ); + }); // submit ok - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[0]), - |sc| { + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -108,49 +104,50 @@ fn test_price_aggregator_submit() { managed_biguint!(100), DECIMALS, ) - }, - ); + }); let current_timestamp = 100; - world.whitebox_query(&price_aggregator_whitebox, |sc| { - let token_pair = TokenPair { - from: managed_buffer!(EGLD_TICKER), - to: managed_buffer!(USD_TICKER), - }; - assert_eq!( - sc.first_submission_timestamp(&token_pair).get(), - current_timestamp - ); - assert_eq!( - sc.last_submission_timestamp(&token_pair).get(), - current_timestamp - ); - - let submissions = sc.submissions().get(&token_pair).unwrap(); - assert_eq!(submissions.len(), 1); - assert_eq!( - submissions - .get(&managed_address!(&oracles[0].to_address())) - .unwrap(), - managed_biguint!(100) - ); - - assert_eq!( - sc.oracle_status() - .get(&managed_address!(&oracles[0].to_address())) - .unwrap(), - OracleStatus { - total_submissions: 1, - accepted_submissions: 1 - } - ); - }); + world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { + let token_pair = TokenPair { + from: managed_buffer!(EGLD_TICKER), + to: managed_buffer!(USD_TICKER), + }; + assert_eq!( + sc.first_submission_timestamp(&token_pair).get(), + current_timestamp + ); + assert_eq!( + sc.last_submission_timestamp(&token_pair).get(), + current_timestamp + ); + + let submissions = sc.submissions().get(&token_pair).unwrap(); + assert_eq!(submissions.len(), 1); + assert_eq!( + submissions.get(&ManagedAddress::from(&oracles[0])).unwrap(), + managed_biguint!(100) + ); + + assert_eq!( + sc.oracle_status() + .get(&ManagedAddress::from(&oracles[0])) + .unwrap(), + OracleStatus { + total_submissions: 1, + accepted_submissions: 1 + } + ); + }, + ); // first oracle submit again - submission not accepted - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[0]), - |sc| { + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -158,55 +155,56 @@ fn test_price_aggregator_submit() { managed_biguint!(100), DECIMALS, ) + }); + + world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { + assert_eq!( + sc.oracle_status() + .get(&ManagedAddress::from(&oracles[0])) + .unwrap(), + OracleStatus { + total_submissions: 2, + accepted_submissions: 1 + } + ); }, ); - - world.whitebox_query(&price_aggregator_whitebox, |sc| { - assert_eq!( - sc.oracle_status() - .get(&managed_address!(&oracles[0].to_address())) - .unwrap(), - OracleStatus { - total_submissions: 2, - accepted_submissions: 1 - } - ); - }); } #[test] fn test_price_aggregator_submit_round_ok() { let (mut world, oracles) = setup(); - let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS_EXPR, - multiversx_price_aggregator_sc::contract_obj, - ); // configure the number of decimals - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.set_pair_decimals( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), DECIMALS, ) - }, - ); + }); // unpause - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| sc.call_unpause_endpoint(), - ); + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.call_unpause_endpoint(); + }); // submit first - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[0]), - |sc| { + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -214,17 +212,17 @@ fn test_price_aggregator_submit_round_ok() { managed_biguint!(10_000), DECIMALS, ) - }, - ); + }); let current_timestamp = 110; - world.set_state_step(SetStateStep::new().block_timestamp(current_timestamp)); + world.current_block().block_timestamp(current_timestamp); // submit second - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[1]), - |sc| { + world + .tx() + .from(&oracles[1]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -232,14 +230,14 @@ fn test_price_aggregator_submit_round_ok() { managed_biguint!(11_000), DECIMALS, ) - }, - ); + }); // submit third - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[2]), - |sc| { + world + .tx() + .from(&oracles[2]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -247,72 +245,73 @@ fn test_price_aggregator_submit_round_ok() { managed_biguint!(12_000), DECIMALS, ) + }); + + world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { + let result = + sc.latest_price_feed(managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER)); + + let (round_id, from, to, timestamp, price, decimals) = result.into_tuple(); + assert_eq!(round_id, 1); + assert_eq!(from, managed_buffer!(EGLD_TICKER)); + assert_eq!(to, managed_buffer!(USD_TICKER)); + assert_eq!(timestamp, current_timestamp); + assert_eq!(price, managed_biguint!(11_000)); + assert_eq!(decimals, DECIMALS); + + // submissions are deleted after round is created + let token_pair = TokenPair { from, to }; + let submissions = sc.submissions().get(&token_pair).unwrap(); + assert_eq!(submissions.len(), 0); + + let rounds = sc.rounds().get(&token_pair).unwrap(); + assert_eq!(rounds.len(), 1); + assert_eq!( + rounds.get(1), + TimestampedPrice { + timestamp, + price, + decimals + } + ); }, ); - - world.whitebox_query(&price_aggregator_whitebox, |sc| { - let result = - sc.latest_price_feed(managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER)); - - let (round_id, from, to, timestamp, price, decimals) = result.into_tuple(); - assert_eq!(round_id, 1); - assert_eq!(from, managed_buffer!(EGLD_TICKER)); - assert_eq!(to, managed_buffer!(USD_TICKER)); - assert_eq!(timestamp, current_timestamp); - assert_eq!(price, managed_biguint!(11_000)); - assert_eq!(decimals, DECIMALS); - - // submissions are deleted after round is created - let token_pair = TokenPair { from, to }; - let submissions = sc.submissions().get(&token_pair).unwrap(); - assert_eq!(submissions.len(), 0); - - let rounds = sc.rounds().get(&token_pair).unwrap(); - assert_eq!(rounds.len(), 1); - assert_eq!( - rounds.get(1), - TimestampedPrice { - timestamp, - price, - decimals - } - ); - }); } #[test] fn test_price_aggregator_discarded_round() { let (mut world, oracles) = setup(); - let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS_EXPR, - multiversx_price_aggregator_sc::contract_obj, - ); // configure the number of decimals - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.set_pair_decimals( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), DECIMALS, ) - }, - ); + }); // unpause - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| sc.call_unpause_endpoint(), - ); + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.call_unpause_endpoint(); + }); // submit first - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[0]), - |sc| { + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -320,17 +319,17 @@ fn test_price_aggregator_discarded_round() { managed_biguint!(10_000), DECIMALS, ) - }, - ); + }); let current_timestamp = 100 + MAX_ROUND_DURATION_SECONDS + 1; - world.set_state_step(SetStateStep::new().block_timestamp(current_timestamp)); + world.current_block().block_timestamp(current_timestamp); // submit second - this will discard the previous submission - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[1]), - |sc| { + world + .tx() + .from(&oracles[1]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -338,77 +337,100 @@ fn test_price_aggregator_discarded_round() { managed_biguint!(11_000), DECIMALS, ) + }); + + world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { + let token_pair = TokenPair { + from: managed_buffer!(EGLD_TICKER), + to: managed_buffer!(USD_TICKER), + }; + let submissions = sc.submissions().get(&token_pair).unwrap(); + assert_eq!(submissions.len(), 1); + assert_eq!( + submissions.get(&managed_address!(&oracles[1])).unwrap(), + managed_biguint!(11_000) + ); }, ); - - world.whitebox_query(&price_aggregator_whitebox, |sc| { - let token_pair = TokenPair { - from: managed_buffer!(EGLD_TICKER), - to: managed_buffer!(USD_TICKER), - }; - let submissions = sc.submissions().get(&token_pair).unwrap(); - assert_eq!(submissions.len(), 1); - assert_eq!( - submissions - .get(&managed_address!(&oracles[1].to_address())) - .unwrap(), - managed_biguint!(11_000) - ); - }); } #[test] fn test_price_aggregator_slashing() { let (mut world, oracles) = setup(); - let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS_EXPR, - multiversx_price_aggregator_sc::contract_obj, - ); - // unpause - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| sc.call_unpause_endpoint(), - ); - - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new() - .from(&oracles[0]) - .argument(BytesValue::from(oracles[1].to_address().as_bytes())), - |sc| sc.call_vote_slash_member(), - ); - - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new() - .from(&oracles[2]) - .argument(BytesValue::from(oracles[1].to_address().as_bytes())), - |sc| sc.call_vote_slash_member(), - ); + // configure the number of decimals + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.set_pair_decimals( + managed_buffer!(EGLD_TICKER), + managed_buffer!(USD_TICKER), + DECIMALS, + ) + }); - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new() - .from(&oracles[3]) - .argument(BytesValue::from(oracles[1].to_address().as_bytes())), - |sc| sc.call_vote_slash_member(), + // unpause + world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.call_unpause_endpoint(); + }); + + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.vote_slash_member(ManagedAddress::from(&oracles[1])); + }); + + world + .tx() + .from(&oracles[2]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.vote_slash_member(ManagedAddress::from(&oracles[1])) + }); + + world + .tx() + .from(&oracles[3]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.vote_slash_member(ManagedAddress::from(&oracles[1])); + }); + + world.query().to(PRICE_AGGREGATOR_ADDRESS).whitebox( + multiversx_price_aggregator_sc::contract_obj, + |sc| { + let list = sc.slashing_proposal_voters(&ManagedAddress::from(&oracles[1])); + assert!(list.contains(&ManagedAddress::from(&oracles[0]))); + assert!(list.contains(&ManagedAddress::from(&oracles[2]))); + assert!(list.contains(&ManagedAddress::from(&oracles[3]))); + }, ); - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new() - .from(&oracles[0]) - .argument(BytesValue::from(oracles[1].to_address().as_bytes())), - |sc| sc.call_slash_member(), - ); + world + .tx() + .from(&oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.slash_member(ManagedAddress::from(&oracles[1])); + }); // oracle 1 try submit after slashing - world.whitebox_call_check( - &price_aggregator_whitebox, - ScCallStep::new().from(&oracles[1]).no_expect(), - |sc| { + world + .tx() + .from(&oracles[1]) + .to(PRICE_AGGREGATOR_ADDRESS) + .returns(ExpectError(4u64, "only oracles allowed")) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { sc.submit( managed_buffer!(EGLD_TICKER), managed_buffer!(USD_TICKER), @@ -416,49 +438,37 @@ fn test_price_aggregator_slashing() { managed_biguint!(10_000), DECIMALS, ) - }, - |r| { - r.assert_user_error("only oracles allowed"); - }, - ); + }); } -fn setup() -> (ScenarioWorld, Vec) { +fn setup() -> (ScenarioWorld, Vec
) { // setup let mut world = world(); - let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS_EXPR, - multiversx_price_aggregator_sc::contract_obj, - ); - let price_aggregator_code = world.code_expression(PRICE_AGGREGATOR_PATH_EXPR); - let mut set_state_step = SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(OWNER_ADDRESS_EXPR, 1, PRICE_AGGREGATOR_ADDRESS_EXPR) - .block_timestamp(100); + world.account(OWNER_ADDRESS).nonce(1); + world.current_block().block_timestamp(100); let mut oracles = Vec::new(); for i in 1..=NR_ORACLES { - let oracle_address_expr = format!("address:oracle{i}"); - let oracle_address = AddressValue::from(oracle_address_expr.as_str()); - - set_state_step = set_state_step.put_account( - oracle_address_expr.as_str(), - Account::new().nonce(1).balance(STAKE_AMOUNT), - ); - oracles.push(oracle_address); + let oracle_address_expr = format!("oracle{i}"); + let oracle_address = TestAddress::new(&oracle_address_expr); + + world.account(oracle_address).nonce(1).balance(STAKE_AMOUNT); + + oracles.push(oracle_address.to_address()); } // init price aggregator - world.set_state_step(set_state_step).whitebox_deploy( - &price_aggregator_whitebox, - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(price_aggregator_code), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .raw_deploy() + .code(PRICE_AGGREGATOR_PATH_EXPR) + .new_address(PRICE_AGGREGATOR_ADDRESS) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { let mut oracle_args = MultiValueEncoded::new(); for oracle_address in &oracles { - oracle_args.push(managed_address!(&oracle_address.to_address())); + oracle_args.push(ManagedAddress::from(oracle_address)); } sc.init( @@ -469,17 +479,17 @@ fn setup() -> (ScenarioWorld, Vec) { SUBMISSION_COUNT, oracle_args, ) - }, - ); + }); for oracle_address in &oracles { - world.whitebox_call( - &price_aggregator_whitebox, - ScCallStep::new() - .from(oracle_address) - .egld_value(STAKE_AMOUNT), - |sc| sc.call_stake(), - ); + world + .tx() + .from(oracle_address) + .to(PRICE_AGGREGATOR_ADDRESS) + .egld(STAKE_AMOUNT) + .whitebox(multiversx_price_aggregator_sc::contract_obj, |sc| { + sc.call_stake(); + }); } (world, oracles) diff --git a/contracts/examples/adder/tests/adder_whitebox_test.rs b/contracts/examples/adder/tests/adder_whitebox_test.rs index 9e7abe4a51..c609b08302 100644 --- a/contracts/examples/adder/tests/adder_whitebox_test.rs +++ b/contracts/examples/adder/tests/adder_whitebox_test.rs @@ -1,49 +1,50 @@ use adder::*; use multiversx_sc_scenario::imports::*; -const ADDER_PATH_EXPR: &str = "mxsc:output/adder.mxsc.json"; +const OWNER: TestAddress = TestAddress::new("owner"); +const ADDER_ADDRESS: TestSCAddress = TestSCAddress::new("adder"); +const CODE_PATH: MxscPath = MxscPath::new("mxsc:output/adder.mxsc.json"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.register_contract("mxsc:output/adder.mxsc.json", adder::ContractBuilder); + blockchain.register_contract(CODE_PATH, adder::ContractBuilder); blockchain } #[test] fn adder_whitebox() { let mut world = world(); - let adder_whitebox = WhiteboxContract::new("sc:adder", adder::contract_obj); - let adder_code = world.code_expression(ADDER_PATH_EXPR); + + world.account(OWNER).nonce(1); + + let new_address = world + .tx() + .from(OWNER) + .raw_deploy() + .code(CODE_PATH) + .new_address(ADDER_ADDRESS) + .returns(ReturnsNewBech32Address) + .whitebox(adder::contract_obj, |sc| { + sc.init(BigUint::from(3u64)); + }); + + assert_eq!(new_address, ADDER_ADDRESS.to_address().into()); world - .set_state_step( - SetStateStep::new() - .put_account("address:owner", Account::new().nonce(1)) - .new_address("address:owner", 1, "sc:adder"), - ) - .whitebox_deploy( - &adder_whitebox, - ScDeployStep::new().from("address:owner").code(adder_code), - |sc| { - sc.init(5u32.into()); - }, - ) - .whitebox_query(&adder_whitebox, |sc| { - let sum_value = sc.sum(); - assert_eq!(sum_value.get(), 5u32); - }) - .whitebox_call( - &adder_whitebox, - ScCallStep::new().from("address:owner"), - |sc| sc.add(3u32.into()), - ) - .check_state_step( - CheckStateStep::new() - .put_account("address:owner", CheckAccount::new()) - .put_account( - "sc:adder", - CheckAccount::new().check_storage("str:sum", "8"), - ), - ); + .tx() + .from(OWNER) + .to(ADDER_ADDRESS) + .whitebox(adder::contract_obj, |sc| { + sc.add(BigUint::from(5u64)); + }); + + let _raw_response = world + .query() + .to(ADDER_ADDRESS) + .returns(ReturnsRawResult) + .whitebox(adder::contract_obj, |sc| { + let sum = sc.sum().get(); + assert_eq!(sum, BigUint::from(8u64)); + }); } diff --git a/contracts/examples/multisig/tests/multisig_whitebox_test.rs b/contracts/examples/multisig/tests/multisig_whitebox_test.rs index 904a03c7e0..5e1347d82b 100644 --- a/contracts/examples/multisig/tests/multisig_whitebox_test.rs +++ b/contracts/examples/multisig/tests/multisig_whitebox_test.rs @@ -10,11 +10,11 @@ use multisig::{ user_role::UserRole, Multisig, }; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const PROPOSER_ADDRESS_EXPR: &str = "address:proposer"; -const BOARD_MEMBER_ADDRESS_EXPR: &str = "address:board-member"; -const MULTISIG_ADDRESS_EXPR: &str = "sc:multisig"; -const MULTISIG_PATH_EXPR: &str = "mxsc:output/multisig.mxsc.json"; +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const PROPOSER_ADDRESS: TestAddress = TestAddress::new("proposer"); +const BOARD_MEMBER_ADDRESS: TestAddress = TestAddress::new("board-member"); +const MULTISIG_ADDRESS: TestSCAddress = TestSCAddress::new("multisig"); +const MULTISIG_PATH_EXPR: MxscPath = MxscPath::new("mxsc:output/multisig.mxsc.json"); const QUORUM_SIZE: usize = 1; type RustBigUint = num_bigint::BigUint; @@ -59,40 +59,28 @@ fn world() -> ScenarioWorld { fn setup() -> ScenarioWorld { // setup let mut world = world(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - let multisig_code = world.code_expression(MULTISIG_PATH_EXPR); - - world.set_state_step( - SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(OWNER_ADDRESS_EXPR, 1, MULTISIG_ADDRESS_EXPR) - .put_account( - PROPOSER_ADDRESS_EXPR, - Account::new().nonce(1).balance(100_000_000u64), - ) - .put_account(BOARD_MEMBER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + + world.account(OWNER_ADDRESS).nonce(1); + world + .account(PROPOSER_ADDRESS) + .nonce(1) + .balance(100_000_000u64); + world.account(BOARD_MEMBER_ADDRESS).nonce(1); // init multisig - world.whitebox_deploy( - &multisig_whitebox, - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(multisig_code), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .raw_deploy() + .code(MULTISIG_PATH_EXPR) + .new_address(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let mut board_members = ManagedVec::new(); - board_members.push(managed_address!(&address_expr_to_address( - BOARD_MEMBER_ADDRESS_EXPR - ))); + board_members.push(BOARD_MEMBER_ADDRESS.to_managed_address()); sc.init(QUORUM_SIZE, board_members.into()); - sc.change_user_role( - 0, - managed_address!(&address_expr_to_address(PROPOSER_ADDRESS_EXPR)), - UserRole::Proposer, - ); - }, - ); + sc.change_user_role(0, PROPOSER_ADDRESS.to_managed_address(), UserRole::Proposer); + }); world } @@ -119,70 +107,66 @@ fn call_propose( let mut action_id = 0; - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - - world.whitebox_call_check( - &multisig_whitebox, - ScCallStep::new() - .from(PROPOSER_ADDRESS_EXPR) - .egld_value(amount_rust_biguint) - .no_expect(), - |sc| { - action_id = match action { - ActionRaw::_Nothing => panic!("Invalid action"), - ActionRaw::AddBoardMember(addr) => { - sc.propose_add_board_member(managed_address!(&addr)) + let mut transaction = world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .egld(BigUint::from(egld_amount)); + + let mut transaction_with_err = match expected_message { + Some(message) => transaction.returns(ExpectError(4u64, message)), + None => transaction.returns(ExpectError(0u64, "")), + }; + + transaction_with_err.whitebox(multisig::contract_obj, |sc| { + action_id = match action { + ActionRaw::_Nothing => panic!("Invalid action"), + ActionRaw::AddBoardMember(addr) => sc.propose_add_board_member(managed_address!(&addr)), + ActionRaw::AddProposer(addr) => sc.propose_add_proposer(managed_address!(&addr)), + ActionRaw::RemoveUser(addr) => sc.propose_remove_user(managed_address!(&addr)), + ActionRaw::ChangeQuorum(new_size) => sc.propose_change_quorum(new_size), + ActionRaw::SendTransferExecute(call_data) => sc.propose_transfer_execute( + managed_address!(&call_data.to), + call_data.egld_amount.into(), + FunctionCall { + function_name: call_data.endpoint_name.into(), + arg_buffer: call_data.arguments.into(), }, - ActionRaw::AddProposer(addr) => sc.propose_add_proposer(managed_address!(&addr)), - ActionRaw::RemoveUser(addr) => sc.propose_remove_user(managed_address!(&addr)), - ActionRaw::ChangeQuorum(new_size) => sc.propose_change_quorum(new_size), - ActionRaw::SendTransferExecute(call_data) => sc.propose_transfer_execute( - managed_address!(&call_data.to), - BigUint::from_bytes_be(&call_data.egld_amount.to_bytes_be()), - FunctionCall { - function_name: call_data.endpoint_name.into(), - arg_buffer: call_data.arguments.into(), - }, - ), - ActionRaw::SendAsyncCall(call_data) => sc.propose_async_call( - managed_address!(&call_data.to), - BigUint::from_bytes_be(&call_data.egld_amount.to_bytes_be()), - FunctionCall { - function_name: call_data.endpoint_name.into(), - arg_buffer: call_data.arguments.into(), - }, - ), - ActionRaw::SCDeployFromSource { - amount, - source, - code_metadata, - arguments, - } => sc.propose_sc_deploy_from_source( - BigUint::from_bytes_be(&amount.to_bytes_be()), - managed_address!(&source), - code_metadata, - boxed_bytes_vec_to_managed(arguments).into(), - ), - ActionRaw::SCUpgradeFromSource { - sc_address, - amount, - source, - code_metadata, - arguments, - } => sc.propose_sc_upgrade_from_source( - managed_address!(&sc_address), - BigUint::from_bytes_be(&amount.to_bytes_be()), - managed_address!(&source), - code_metadata, - boxed_bytes_vec_to_managed(arguments).into(), - ), - } - }, - |r| match expected_message { - Some(msg) => r.assert_user_error(msg), - None => r.assert_ok(), - }, - ); + ), + ActionRaw::SendAsyncCall(call_data) => sc.propose_async_call( + managed_address!(&call_data.to), + call_data.egld_amount.into(), + FunctionCall { + function_name: call_data.endpoint_name.into(), + arg_buffer: call_data.arguments.into(), + }, + ), + ActionRaw::SCDeployFromSource { + amount, + source, + code_metadata, + arguments, + } => sc.propose_sc_deploy_from_source( + amount.into(), + managed_address!(&source), + code_metadata, + boxed_bytes_vec_to_managed(arguments).into(), + ), + ActionRaw::SCUpgradeFromSource { + sc_address, + amount, + source, + code_metadata, + arguments, + } => sc.propose_sc_upgrade_from_source( + managed_address!(&sc_address), + amount.into(), + managed_address!(&source), + code_metadata, + boxed_bytes_vec_to_managed(arguments).into(), + ), + } + }); action_id } @@ -190,341 +174,300 @@ fn call_propose( #[test] fn test_add_board_member() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - const NEW_BOARD_MEMBER_ADDRESS_EXPR: &str = "address:new-board-member"; - world.set_state_step( - SetStateStep::new().put_account(NEW_BOARD_MEMBER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + const NEW_BOARD_MEMBER_ADDRESS: TestAddress = TestAddress::new("new-board-member"); + world.account(NEW_BOARD_MEMBER_ADDRESS).nonce(1); - world.whitebox_query(&multisig_whitebox, |sc| { - // check role before - let user_role = sc.user_role(managed_address!(&address_expr_to_address( - NEW_BOARD_MEMBER_ADDRESS_EXPR - ))); - assert_eq!(user_role, UserRole::None); - }); + world + .query() + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { + // check role before + let user_role = sc.user_role(NEW_BOARD_MEMBER_ADDRESS.to_managed_address()); + assert_eq!(user_role, UserRole::None); + }); let action_id = call_propose( &mut world, - ActionRaw::AddBoardMember(address_expr_to_address(NEW_BOARD_MEMBER_ADDRESS_EXPR)), + ActionRaw::AddBoardMember(NEW_BOARD_MEMBER_ADDRESS.to_address()), None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); - world.whitebox_query(&multisig_whitebox, |sc| { - // check role after - let user_role = sc.user_role(managed_address!(&address_expr_to_address( - NEW_BOARD_MEMBER_ADDRESS_EXPR - ))); - assert_eq!(user_role, UserRole::BoardMember); - - let board_members = sc.get_all_board_members().to_vec(); - assert_eq!( - (board_members.get(0).borrow() as &ManagedAddress).clone(), - managed_address!(&address_expr_to_address(BOARD_MEMBER_ADDRESS_EXPR)) - ); - assert_eq!( - (board_members.get(1).borrow() as &ManagedAddress).clone(), - managed_address!(&address_expr_to_address(NEW_BOARD_MEMBER_ADDRESS_EXPR)) - ); - }); + world + .query() + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { + // check role after + let user_role = sc.user_role(NEW_BOARD_MEMBER_ADDRESS.to_managed_address()); + assert_eq!(user_role, UserRole::BoardMember); + + let board_members = sc.get_all_board_members().to_vec(); + assert_eq!(*board_members.get(0), BOARD_MEMBER_ADDRESS); + assert_eq!(*board_members.get(1), NEW_BOARD_MEMBER_ADDRESS); + }); } #[test] fn test_add_proposer() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - const NEW_PROPOSER_ADDRESS_EXPR: &str = "address:new-proposer"; - world.set_state_step( - SetStateStep::new().put_account(NEW_PROPOSER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + const NEW_PROPOSER_ADDRESS: TestAddress = TestAddress::new("new-proposer"); + world.account(NEW_PROPOSER_ADDRESS).nonce(1); - world.whitebox_query(&multisig_whitebox, |sc| { - // check role before - let user_role = sc.user_role(managed_address!(&address_expr_to_address( - NEW_PROPOSER_ADDRESS_EXPR - ))); - assert_eq!(user_role, UserRole::None); - }); + world + .query() + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { + // check role before + let user_role = sc.user_role(NEW_PROPOSER_ADDRESS.to_managed_address()); + assert_eq!(user_role, UserRole::None); + }); let action_id = call_propose( &mut world, - ActionRaw::AddProposer(address_expr_to_address(NEW_PROPOSER_ADDRESS_EXPR)), + ActionRaw::AddProposer(NEW_PROPOSER_ADDRESS.to_address()), None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); - world.whitebox_query(&multisig_whitebox, |sc| { - // check role after - let user_role = sc.user_role(managed_address!(&address_expr_to_address( - NEW_PROPOSER_ADDRESS_EXPR - ))); - assert_eq!(user_role, UserRole::Proposer); - - let proposers = sc.get_all_proposers().to_vec(); - assert_eq!( - (proposers.get(0).borrow() as &ManagedAddress).clone(), - managed_address!(&address_expr_to_address(PROPOSER_ADDRESS_EXPR)) - ); - assert_eq!( - (proposers.get(1).borrow() as &ManagedAddress).clone(), - managed_address!(&address_expr_to_address(NEW_PROPOSER_ADDRESS_EXPR)) - ); - }); + world + .query() + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { + // check role after + let user_role = sc.user_role(NEW_PROPOSER_ADDRESS.to_managed_address()); + assert_eq!(user_role, UserRole::Proposer); + + let proposers = sc.get_all_proposers().to_vec(); + assert_eq!(*proposers.get(0), PROPOSER_ADDRESS); + assert_eq!(*proposers.get(1), NEW_PROPOSER_ADDRESS); + }); } #[test] fn test_remove_proposer() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - - world.whitebox_query(&multisig_whitebox, |sc| { - // check role before - let user_role = sc.user_role(managed_address!(&address_expr_to_address( - PROPOSER_ADDRESS_EXPR - ))); - assert_eq!(user_role, UserRole::Proposer); - }); + + world + .query() + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { + // check role before + let user_role = sc.user_role(PROPOSER_ADDRESS.to_managed_address()); + assert_eq!(user_role, UserRole::Proposer); + }); let action_id = call_propose( &mut world, - ActionRaw::RemoveUser(address_expr_to_address(PROPOSER_ADDRESS_EXPR)), + ActionRaw::RemoveUser(PROPOSER_ADDRESS.to_address()), None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); - world.whitebox_query(&multisig_whitebox, |sc| { - // check role after - let user_role = sc.user_role(managed_address!(&address_expr_to_address( - PROPOSER_ADDRESS_EXPR - ))); - assert_eq!(user_role, UserRole::None); - - let proposers = sc.get_all_proposers().to_vec(); - assert!(proposers.is_empty()); - }); + world + .query() + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { + // check role after + let user_role = sc.user_role(PROPOSER_ADDRESS.to_managed_address()); + assert_eq!(user_role, UserRole::None); + + let proposers = sc.get_all_proposers(); + assert!(proposers.is_empty()); + }); } #[test] fn test_try_remove_all_board_members() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); let action_id = call_propose( &mut world, - ActionRaw::RemoveUser(address_expr_to_address(BOARD_MEMBER_ADDRESS_EXPR)), + ActionRaw::RemoveUser(BOARD_MEMBER_ADDRESS.to_address()), None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call_check( - &multisig_whitebox, - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .no_expect(), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .returns(ExpectError(4u64, "quorum cannot exceed board size")) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - |r| { - r.assert_user_error("quorum cannot exceed board size"); - }, - ); + }); } #[test] fn test_change_quorum() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); let new_quorum_size = 2; // try change quorum > board size let action_id = call_propose(&mut world, ActionRaw::ChangeQuorum(new_quorum_size), None); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call_check( - &multisig_whitebox, - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .no_expect(), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .returns(ExpectError(4u64, "quorum cannot exceed board size")) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - |r| { - r.assert_user_error("quorum cannot exceed board size"); - }, - ); + }); // try discard before unsigning - world.whitebox_call_check( - &multisig_whitebox, - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .no_expect(), - |sc| { - sc.discard_action(action_id); - }, - |r| { - r.assert_user_error("cannot discard action with valid signatures"); - }, - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .returns(ExpectError( + 4u64, + "cannot discard action with valid signatures", + )) + .whitebox(multisig::contract_obj, |sc| sc.discard_action(action_id)); // unsign and discard action - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.unsign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.unsign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { - sc.discard_action(action_id); - }, - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.discard_action(action_id)); // try sign discarded action - world.whitebox_call_check( - &multisig_whitebox, - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .no_expect(), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .returns(ExpectError(4u64, "action does not exist")) + .whitebox(multisig::contract_obj, |sc| { sc.sign(action_id); - }, - |r| { - r.assert_user_error("action does not exist"); - }, - ); + }); // add another board member - const NEW_BOARD_MEMBER_ADDRESS_EXPR: &str = "address:new-board-member"; - world.set_state_step( - SetStateStep::new().put_account(NEW_BOARD_MEMBER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + const NEW_BOARD_MEMBER_ADDRESS: TestAddress = TestAddress::new("new-board-member"); + world.account(NEW_BOARD_MEMBER_ADDRESS).nonce(1); let action_id = call_propose( &mut world, - ActionRaw::AddBoardMember(address_expr_to_address(NEW_BOARD_MEMBER_ADDRESS_EXPR)), + ActionRaw::AddBoardMember(NEW_BOARD_MEMBER_ADDRESS.to_address()), None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); // change quorum to 2 let action_id = call_propose(&mut world, ActionRaw::ChangeQuorum(new_quorum_size), None); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); } #[test] fn test_transfer_execute_to_user() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - const NEW_USER_ADDRESS_EXPR: &str = "address:new-user"; - world.set_state_step( - SetStateStep::new().put_account(NEW_USER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + const NEW_USER_ADDRESS: TestAddress = TestAddress::new("new-user"); + world.account(NEW_USER_ADDRESS).nonce(1); const EGLD_AMOUNT: u64 = 100; - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new() - .from(PROPOSER_ADDRESS_EXPR) - .egld_value(EGLD_AMOUNT), - |sc| { + world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .egld(EGLD_AMOUNT) + .whitebox(multisig::contract_obj, |sc| { sc.deposit(); - }, - ); + }); - world.check_state_step(CheckStateStep::new().put_account( - MULTISIG_ADDRESS_EXPR, - CheckAccount::new().balance(EGLD_AMOUNT.to_string().as_str()), - )); + world.check_account(MULTISIG_ADDRESS).balance(EGLD_AMOUNT); // failed attempt let action_id = call_propose( &mut world, ActionRaw::SendTransferExecute(CallActionDataRaw { - to: address_expr_to_address(NEW_USER_ADDRESS_EXPR), + to: NEW_USER_ADDRESS.to_address(), egld_amount: rust_biguint!(0), endpoint_name: BoxedBytes::empty(), arguments: Vec::new(), @@ -536,7 +479,7 @@ fn test_transfer_execute_to_user() { let action_id = call_propose( &mut world, ActionRaw::SendTransferExecute(CallActionDataRaw { - to: address_expr_to_address(NEW_USER_ADDRESS_EXPR), + to: NEW_USER_ADDRESS.to_address(), egld_amount: rust_biguint!(EGLD_AMOUNT), endpoint_name: BoxedBytes::empty(), arguments: Vec::new(), @@ -544,59 +487,48 @@ fn test_transfer_execute_to_user() { None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); - world.check_state_step(CheckStateStep::new().put_account( - NEW_USER_ADDRESS_EXPR, - CheckAccount::new().balance(EGLD_AMOUNT.to_string().as_str()), - )); + world.check_account(NEW_USER_ADDRESS).balance(EGLD_AMOUNT); } #[test] fn test_transfer_execute_sc_all() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - - let adder_whitebox = WhiteboxContract::new(ADDER_ADDRESS_EXPR, adder::contract_obj); - let adder_code = world.code_expression(ADDER_PATH_EXPR); - const ADDER_OWNER_ADDRESS_EXPR: &str = "address:adder-owner"; - const ADDER_ADDRESS_EXPR: &str = "sc:adder"; - const ADDER_PATH_EXPR: &str = "mxsc:test-contracts/adder.mxsc.json"; + const ADDER_OWNER_ADDRESS: TestAddress = TestAddress::new("adder-owner"); + const ADDER_ADDRESS: TestSCAddress = TestSCAddress::new("adder"); + const ADDER_PATH_EXPR: MxscPath = MxscPath::new("mxsc:test-contracts/adder.mxsc.json"); world.register_contract(ADDER_PATH_EXPR, adder::ContractBuilder); - world.set_state_step( - SetStateStep::new() - .put_account(ADDER_OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(ADDER_OWNER_ADDRESS_EXPR, 1, ADDER_ADDRESS_EXPR), - ); + world.account(ADDER_OWNER_ADDRESS).nonce(1); - world.whitebox_deploy( - &adder_whitebox, - ScDeployStep::new() - .from(ADDER_OWNER_ADDRESS_EXPR) - .code(adder_code), - |sc| { - sc.init(managed_biguint!(5)); - }, - ); + world + .tx() + .raw_deploy() + .from(ADDER_OWNER_ADDRESS) + .code(ADDER_PATH_EXPR) + .new_address(ADDER_ADDRESS) + .whitebox(adder::contract_obj, |sc| { + sc.init(BigUint::from(5u64)); + }); let action_id = call_propose( &mut world, ActionRaw::SendTransferExecute(CallActionDataRaw { - to: address_expr_to_address(ADDER_ADDRESS_EXPR), + to: ADDER_ADDRESS.to_address(), egld_amount: 0u64.into(), endpoint_name: BoxedBytes::from(&b"add"[..]), arguments: vec![BoxedBytes::from(&[5u8][..])], @@ -604,60 +536,55 @@ fn test_transfer_execute_sc_all() { None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); - world.whitebox_query(&adder_whitebox, |sc| { - let actual_sum = sc.sum().get(); - let expected_sum = managed_biguint!(10); - assert_eq!(actual_sum, expected_sum); - }); + world + .query() + .to(ADDER_ADDRESS) + .whitebox(adder::contract_obj, |sc| { + let actual_sum = sc.sum().get(); + let expected_sum = managed_biguint!(10); + assert_eq!(actual_sum, expected_sum); + }); } #[test] fn test_async_call_to_sc() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); - - let adder_whitebox = WhiteboxContract::new(ADDER_ADDRESS_EXPR, adder::contract_obj); - let adder_code = world.code_expression(ADDER_PATH_EXPR); - const ADDER_OWNER_ADDRESS_EXPR: &str = "address:adder-owner"; - const ADDER_ADDRESS_EXPR: &str = "sc:adder"; - const ADDER_PATH_EXPR: &str = "mxsc:test-contracts/adder.mxsc.json"; + const ADDER_OWNER_ADDRESS: TestAddress = TestAddress::new("adder-owner"); + const ADDER_ADDRESS: TestSCAddress = TestSCAddress::new("adder"); + const ADDER_PATH_EXPR: MxscPath = MxscPath::new("mxsc:test-contracts/adder.mxsc.json"); world.register_contract(ADDER_PATH_EXPR, adder::ContractBuilder); - world.set_state_step( - SetStateStep::new() - .put_account(ADDER_OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(ADDER_OWNER_ADDRESS_EXPR, 1, ADDER_ADDRESS_EXPR), - ); + world.account(ADDER_OWNER_ADDRESS).nonce(1); - world.whitebox_deploy( - &adder_whitebox, - ScDeployStep::new() - .from(ADDER_OWNER_ADDRESS_EXPR) - .code(adder_code), - |sc| { - sc.init(managed_biguint!(5)); - }, - ); + world + .tx() + .raw_deploy() + .from(ADDER_OWNER_ADDRESS) + .code(ADDER_PATH_EXPR) + .new_address(ADDER_ADDRESS) + .whitebox(adder::contract_obj, |sc| { + sc.init(BigUint::from(5u64)); + }); let action_id = call_propose( &mut world, ActionRaw::SendAsyncCall(CallActionDataRaw { - to: address_expr_to_address(ADDER_ADDRESS_EXPR), + to: ADDER_ADDRESS.to_address(), egld_amount: 0u64.into(), endpoint_name: BoxedBytes::from(&b"add"[..]), arguments: vec![BoxedBytes::from(&[5u8][..])], @@ -665,93 +592,90 @@ fn test_async_call_to_sc() { None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); - world.whitebox_query(&adder_whitebox, |sc| { - let actual_sum = sc.sum().get(); - let expected_sum = managed_biguint!(10); - assert_eq!(actual_sum, expected_sum); - }); + world + .query() + .to(ADDER_ADDRESS) + .whitebox(adder::contract_obj, |sc| { + let actual_sum = sc.sum().get(); + let expected_sum = managed_biguint!(10); + assert_eq!(actual_sum, expected_sum); + }); } #[test] fn test_deploy_and_upgrade_from_source() { let mut world = setup(); - let multisig_whitebox = WhiteboxContract::new(MULTISIG_ADDRESS_EXPR, multisig::contract_obj); + const NEW_ADDER_ADDRESS: TestSCAddress = TestSCAddress::new("new-adder"); - let adder_whitebox = WhiteboxContract::new(ADDER_ADDRESS_EXPR, adder::contract_obj); - let adder_code = world.code_expression(ADDER_PATH_EXPR); - - let new_adder_whitebox = WhiteboxContract::new(NEW_ADDER_ADDRESS_EXPR, adder::contract_obj); - - const ADDER_OWNER_ADDRESS_EXPR: &str = "address:adder-owner"; - const ADDER_ADDRESS_EXPR: &str = "sc:adder"; - const NEW_ADDER_ADDRESS_EXPR: &str = "sc:new-adder"; - const ADDER_PATH_EXPR: &str = "mxsc:test-contracts/adder.mxsc.json"; + const ADDER_OWNER_ADDRESS: TestAddress = TestAddress::new("adder-owner"); + const ADDER_ADDRESS: TestSCAddress = TestSCAddress::new("adder"); + const ADDER_PATH_EXPR: MxscPath = MxscPath::new("mxsc:test-contracts/adder.mxsc.json"); world.register_contract(ADDER_PATH_EXPR, adder::ContractBuilder); - world.set_state_step( - SetStateStep::new() - .put_account(ADDER_OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(ADDER_OWNER_ADDRESS_EXPR, 1, ADDER_ADDRESS_EXPR) - .new_address(MULTISIG_ADDRESS_EXPR, 0, NEW_ADDER_ADDRESS_EXPR), - ); + world.set_state_step(SetStateStep::new().new_address( + MULTISIG_ADDRESS.eval_to_expr().as_str(), + 0, + NEW_ADDER_ADDRESS.eval_to_expr().as_str(), + )); - world.whitebox_deploy( - &adder_whitebox, - ScDeployStep::new() - .from(ADDER_OWNER_ADDRESS_EXPR) - .code(adder_code), - |sc| { - sc.init(managed_biguint!(5)); - }, - ); + world.account(ADDER_OWNER_ADDRESS).nonce(1); + + world + .tx() + .raw_deploy() + .from(ADDER_OWNER_ADDRESS) + .code(ADDER_PATH_EXPR) + .new_address(ADDER_ADDRESS) + .whitebox(adder::contract_obj, |sc| { + sc.init(BigUint::from(5u64)); + }); let action_id = call_propose( &mut world, ActionRaw::SCDeployFromSource { amount: 0u64.into(), - source: address_expr_to_address(ADDER_ADDRESS_EXPR), + source: ADDER_ADDRESS.to_address(), code_metadata: CodeMetadata::all(), arguments: vec![BoxedBytes::from(&[5u8][..])], }, None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - let mut addr = Address::zero(); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let opt_address = sc.perform_action_endpoint(action_id); - addr = opt_address.into_option().unwrap().to_address(); - }, - ); + let addr = opt_address.into_option().unwrap().to_address(); - assert_eq!(address_expr_to_address(NEW_ADDER_ADDRESS_EXPR), addr); + assert_eq!(NEW_ADDER_ADDRESS.to_address(), addr); + }); let action_id = call_propose( &mut world, ActionRaw::SendTransferExecute(CallActionDataRaw { - to: address_expr_to_address(NEW_ADDER_ADDRESS_EXPR), + to: NEW_ADDER_ADDRESS.to_address(), egld_amount: 0u64.into(), endpoint_name: BoxedBytes::from(&b"add"[..]), arguments: vec![BoxedBytes::from(&[5u8][..])], @@ -759,71 +683,70 @@ fn test_deploy_and_upgrade_from_source() { None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); + }); - world.whitebox_query(&new_adder_whitebox, |sc| { - let actual_sum = sc.sum().get(); - let expected_sum = managed_biguint!(10); - assert_eq!(actual_sum, expected_sum); - }); - - let factorial_code = world.code_expression(FACTORIAL_PATH_EXPR); + world + .query() + .to(NEW_ADDER_ADDRESS) + .whitebox(adder::contract_obj, |sc| { + let actual_sum = sc.sum().get(); + let expected_sum = managed_biguint!(10); + assert_eq!(actual_sum, expected_sum); + }); - const FACTORIAL_ADDRESS_EXPR: &str = "sc:factorial"; - const FACTORIAL_PATH_EXPR: &str = "mxsc:test-contracts/factorial.mxsc.json"; + const FACTORIAL_ADDRESS: TestSCAddress = TestSCAddress::new("factorial"); + const FACTORIAL_PATH_EXPR: MxscPath = MxscPath::new("mxsc:test-contracts/factorial.mxsc.json"); world.register_contract(FACTORIAL_PATH_EXPR, factorial::ContractBuilder); - world.set_state_step(SetStateStep::new().put_account( - FACTORIAL_ADDRESS_EXPR, - Account::new().nonce(1).code(factorial_code.clone()), - )); + world + .tx() + .raw_deploy() + .from(OWNER_ADDRESS) + .code(FACTORIAL_PATH_EXPR) + .new_address(FACTORIAL_ADDRESS) + .whitebox(factorial::contract_obj, |sc| { + sc.init(); + }); let action_id = call_propose( &mut world, ActionRaw::SCUpgradeFromSource { - source: address_expr_to_address(FACTORIAL_ADDRESS_EXPR), + source: FACTORIAL_ADDRESS.to_address(), amount: 0u64.into(), code_metadata: CodeMetadata::all(), arguments: Vec::new(), - sc_address: address_expr_to_address(ADDER_ADDRESS_EXPR), + sc_address: ADDER_ADDRESS.to_address(), }, None, ); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| sc.sign(action_id), - ); + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| sc.sign(action_id)); - world.whitebox_call( - &multisig_whitebox, - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .whitebox(multisig::contract_obj, |sc| { let _ = sc.perform_action_endpoint(action_id); - }, - ); - - world.check_state_step( - CheckStateStep::new() - .put_account(ADDER_ADDRESS_EXPR, CheckAccount::new().code(factorial_code)), - ); -} + }); -fn address_expr_to_address(address_expr: &str) -> Address { - AddressValue::from(address_expr).to_address() + world.check_account(ADDER_ADDRESS).code(FACTORIAL_PATH_EXPR); } fn boxed_bytes_vec_to_managed( diff --git a/contracts/examples/nft-minter/src/nft_module.rs b/contracts/examples/nft-minter/src/nft_module.rs index da97c0d171..66f50ea958 100644 --- a/contracts/examples/nft-minter/src/nft_module.rs +++ b/contracts/examples/nft-minter/src/nft_module.rs @@ -123,7 +123,7 @@ pub trait NftModule { ) { match result { ManagedAsyncCallResult::Ok(token_id) => { - self.nft_token_id().set(&token_id.unwrap_esdt()); + self.nft_token_id().set(token_id.unwrap_esdt()); }, ManagedAsyncCallResult::Err(_) => { let returned = self.call_value().egld_or_single_esdt(); diff --git a/contracts/examples/rewards-distribution/tests/rewards_distribution_integration_test.rs b/contracts/examples/rewards-distribution/tests/rewards_distribution_integration_test.rs index be3a4cb788..f9b64545bd 100644 --- a/contracts/examples/rewards-distribution/tests/rewards_distribution_integration_test.rs +++ b/contracts/examples/rewards-distribution/tests/rewards_distribution_integration_test.rs @@ -6,7 +6,7 @@ use multiversx_sc_scenario::imports::*; use std::iter::zip; use rewards_distribution::{ - rewards_distribution_proxy, ContractObj, RewardsDistribution, DIVISION_SAFETY_CONSTANT, + rewards_distribution_proxy, RewardsDistribution, DIVISION_SAFETY_CONSTANT, }; const ALICE_ADDRESS: TestAddress = TestAddress::new("alice"); @@ -31,7 +31,6 @@ fn world() -> ScenarioWorld { struct RewardsDistributionTestState { world: ScenarioWorld, - rewards_distribution_whitebox: WhiteboxContract>, } impl RewardsDistributionTestState { @@ -40,15 +39,7 @@ impl RewardsDistributionTestState { world.account(OWNER_ADDRESS).nonce(1); - let rewards_distribution_whitebox = WhiteboxContract::new( - REWARDS_DISTRIBUTION_ADDRESS, - rewards_distribution::contract_obj, - ); - - Self { - world, - rewards_distribution_whitebox, - } + Self { world } } fn deploy_seed_nft_minter_contract(&mut self) -> &mut Self { @@ -110,10 +101,12 @@ fn test_compute_brackets() { .owner(OWNER_ADDRESS) .code(REWARDS_DISTRIBUTION_PATH); - state.world.whitebox_call( - &state.rewards_distribution_whitebox, - ScCallStep::new().from(OWNER_ADDRESS), - |sc| { + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(REWARDS_DISTRIBUTION_ADDRESS) + .whitebox(rewards_distribution::contract_obj, |sc| { let brackets = utils::to_brackets(&[ (10, 2_000), (90, 6_000), @@ -140,8 +133,7 @@ fn test_compute_brackets() { assert_eq!(computed.end_index, expected_end_index); assert_eq!(computed.nft_reward_percent, expected_reward_percent); } - }, - ); + }); } #[test] diff --git a/contracts/feature-tests/basic-features/sc-config.toml b/contracts/feature-tests/basic-features/sc-config.toml index 82698d1dab..42c4880f67 100644 --- a/contracts/feature-tests/basic-features/sc-config.toml +++ b/contracts/feature-tests/basic-features/sc-config.toml @@ -1,6 +1,8 @@ [settings] main = "basic-features" +[contracts.basic-features] + [contracts.basic-features.profile] overflow-checks = true # needed for overflow tests @@ -9,6 +11,13 @@ add-unlabelled = false add-endpoints = ["init", "load_bytes", "store_bytes"] kill_legacy_callback = true +[contracts.basic-features-crypto] +ei = "1.4" +add-unlabelled = false +add-endpoints = ["init"] +add-labels = ["crypto-ei-1.4"] +kill_legacy_callback = true + [[proxy]] path = "src/basic_features_proxy.rs" add-unlabelled = false diff --git a/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls.scen.json b/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls.scen.json index ead18354dc..fc67a3745b 100644 --- a/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls.scen.json +++ b/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls.scen.json @@ -19,7 +19,7 @@ }, { "step": "scCall", - "id": "3", + "id": "verify_bls_signature - Ok", "tx": { "from": "address:an_account", "to": "sc:basic-features", @@ -33,14 +33,36 @@ "gasPrice": "0" }, "expect": { - "out": [ - "0x01" - ], + "out": [], "status": "", "logs": "*", "gas": "*", "refund": "*" } + }, + { + "step": "scCall", + "id": "verify_bls_signature - Fail", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "verify_bls_signature", + "arguments": [ + "0xb5823f6e564251cc03ce7bad3da83e72576e92795d3500bba1acb30ec9a94dce87bb8aa794d67b2d61d15c33f28f6c0c23ba1dfcbf21e8f8b46286ff871afabac925303ddcaddce6254fcff6d3155797db40b3d3b5865e8fc0bd770b3d79b381", + "0x6d65737361676520746f206265207369676e6564", + "0x0032a2ddf341c08d1eb7232f05dc34e4454155e676b58c40fddf9a036562ac2c01533d2d557cb49d73aa9d7a89744696" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "10", + "message": "str:err blsSignatureDeserialize 0032a2ddf341c08d1eb7232f05dc34e4454155e676b58c40fddf9a036562ac2c01533d2d557cb49d73aa9d7a89744696", + "logs": "*", + "gas": "*", + "refund": "*" + } } ] } diff --git a/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls_aggregated_signature.scen.json b/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls_aggregated_signature.scen.json new file mode 100644 index 0000000000..546c0d4c9f --- /dev/null +++ b/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls_aggregated_signature.scen.json @@ -0,0 +1,80 @@ +{ + "name": "crypto", + "comment": "does not currently work with scenarios-rs, because verify_bls function is not yet mocked", + "gasSchedule": "v3", + "steps": [ + { + "step": "setState", + "accounts": { + "sc:basic-features-crypto": { + "nonce": "0", + "balance": "0", + "code": "mxsc:../output/basic-features-crypto.mxsc.json" + }, + "address:an_account": { + "nonce": "0", + "balance": "0" + } + } + }, + { + "step": "scCall", + "id": "bls multi - ok", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features-crypto", + "function": "verify_bls_aggregated_signature", + "arguments": [ + [ + "nested:0x95f1d96b582f35294eb7dd4589b158e108e1d94cd0dd71ef16140e9b37126ec52dac6f57397f1e041acd7bb77df1d214f9f894e3b7fbf7abeaabc9fab8ff5c2ef05f9841322f301fdb900ac59479c334ac76a2d4ff992cd49bc9b530c25ee293", + "nested:0x97aa2862418eb4ea74fddcb511eef9b771e07ff901e7e6abb35847a4bb81e58f189fc9bce4186c6129014fb43002300e959702ef4b9d0c32ebe4d795457095d65b5414efb36edbb8dc66d84a445a92472d4a31cedd4700d5ebb885eb11d3430b", + "nested:0x37b73265936a2aaafe652a4dd451a1851c2dbbb32208604787479b31033e2a354615562ea2a5488f9134843362477a139050a0e798dd5ce0f01b35b8d473454ae99633aadde9237f84c87eb366144cca4de3d2cc6acc35e522a3294bf1186800", + "nested:0xf46c10d114dcd3019dd4bcd4152fda678c56144eb177c67a6411213b86e206e4e56a9aad1eab0313b13031fda046d715ec4a02612b083dfae0d82a23b643e1a89756c0df3d65c27e87a9c1289628d1a8404f0668a3d87c7451ba1c78fc452693", + "nested:0xaa0a97917df9240c537c89e873d7baa5ce1796e8fedfb23cf682b80fa19b8baae35af3754f9b8149985cb2a1fbda0f02c2942d2c99d9af556c9a5e90b8170e6a96379a45dd69351abfb814a16b5665abb7ddb8b096ee9f273de81845cda9728a" + ], + "str:message0", + "0xae12858363e8caa5b398d3febdd7bc01bc2fae1fef8f486ff4d84a5f3342f2d38085904eb10b73c0879a45d23585ce8f" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "", + "logs": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "id": "bls multi - fail", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features-crypto", + "function": "verify_bls_aggregated_signature", + "arguments": [ + [ + "nested:0x95f1d96b582f35294eb7dd4589b158e108e1d94cd0dd71ef16140e9b37126ec52dac6f57397f1e041acd7bb77df1d214f9f894e3b7fbf7abeaabc9fab8ff5c2ef05f9841322f301fdb900ac59479c334ac76a2d4ff992cd49bc9b530c25ee293", + "nested:0x97aa2862418eb4ea74fddcb511eef9b771e07ff901e7e6abb35847a4bb81e58f189fc9bce4186c6129014fb43002300e959702ef4b9d0c32ebe4d795457095d65b5414efb36edbb8dc66d84a445a92472d4a31cedd4700d5ebb885eb11d3430b", + "nested:0x37b73265936a2aaafe652a4dd451a1851c2dbbb32208604787479b31033e2a354615562ea2a5488f9134843362477a139050a0e798dd5ce0f01b35b8d473454ae99633aadde9237f84c87eb366144cca4de3d2cc6acc35e522a3294bf1186800", + "nested:0xf46c10d114dcd3019dd4bcd4152fda678c56144eb177c67a6411213b86e206e4e56a9aad1eab0313b13031fda046d715ec4a02612b083dfae0d82a23b643e1a89756c0df3d65c27e87a9c1289628d1a8404f0668a3d87c7451ba1c78fc452693", + "nested:0xaa0a97917df9240c537c89e873d7baa5ce1796e8fedfb23cf682b80fa19b8baae35af3754f9b8149985cb2a1fbda0f02c2942d2c99d9af556c9a5e90b8170e6a96379a45dd69351abfb814a16b5665abb7ddb8b096ee9f273de81845cda9728a" + ], + "str:message0", + "0x0012858363e8caa5b398d3febdd7bc01bc2fae1fef8f486ff4d84a5f3342f2d38085904eb10b73c0879a45d23585ce8f" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "10", + "message": "str:err blsSignatureDeserialize 0012858363e8caa5b398d3febdd7bc01bc2fae1fef8f486ff4d84a5f3342f2d38085904eb10b73c0879a45d23585ce8f", + "logs": "*", + "gas": "*", + "refund": "*" + } + } + ] +} diff --git a/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls_share.scen.json b/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls_share.scen.json new file mode 100644 index 0000000000..fa7c21611b --- /dev/null +++ b/contracts/feature-tests/basic-features/scenarios/crypto_verify_bls_share.scen.json @@ -0,0 +1,68 @@ +{ + "name": "crypto", + "comment": "does not currently work with scenarios-rs, because function is not yet mocked", + "gasSchedule": "v3", + "steps": [ + { + "step": "setState", + "accounts": { + "sc:basic-features-crypto": { + "nonce": "0", + "balance": "0", + "code": "mxsc:../output/basic-features-crypto.mxsc.json" + }, + "address:an_account": { + "nonce": "0", + "balance": "0" + } + } + }, + { + "step": "scCall", + "id": "verify_bls_signature_share - Ok", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features-crypto", + "function": "verify_bls_signature_share", + "arguments": [ + "0x3e886a4c6e109a151f4105aee65a5192d150ef1fa68d3cd76964a0b086006dbe4324c989deb0e4416c6d6706db1b1910eb2732f08842fb4886067b9ed191109ac2188d76002d2e11da80a3f0ea89fee6b59c834cc478a6bd49cb8a193b1abb16", + "0xe96bd0f36b70c5ccc0c4396343bd7d8255b8a526c55fa1e218511fafe6539b8e", + "0x04725db195e37aa237cdbbda76270d4a229b6e7a3651104dc58c4349c0388e8546976fe54a04240530b99064e434c90f" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "", + "logs": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "id": "verify_bls_signature_share - Fail", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features-crypto", + "function": "verify_bls_signature_share", + "arguments": [ + "0x3e886a4c6e109a151f4105aee65a5192d150ef1fa68d3cd76964a0b086006dbe4324c989deb0e4416c6d6706db1b1910eb2732f08842fb4886067b9ed191109ac2188d76002d2e11da80a3f0ea89fee6b59c834cc478a6bd49cb8a193b1abb16", + "0xe96bd0f36b70c5ccc0c4396343bd7d8255b8a526c55fa1e218511fafe6539b8e", + "0xff725db195e37aa237cdbbda76270d4a229b6e7a3651104dc58c4349c0388e8546976fe54a04240530b99064e434c90f" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "10", + "message": "str:err blsSignatureDeserialize ff725db195e37aa237cdbbda76270d4a229b6e7a3651104dc58c4349c0388e8546976fe54a04240530b99064e434c90f", + "logs": "*", + "gas": "*", + "refund": "*" + } + } + ] +} diff --git a/contracts/feature-tests/basic-features/scenarios/crypto_verify_secp256r1.scen.json b/contracts/feature-tests/basic-features/scenarios/crypto_verify_secp256r1.scen.json new file mode 100644 index 0000000000..1c35b46271 --- /dev/null +++ b/contracts/feature-tests/basic-features/scenarios/crypto_verify_secp256r1.scen.json @@ -0,0 +1,67 @@ +{ + "name": "crypto", + "gasSchedule": "v3", + "steps": [ + { + "step": "setState", + "accounts": { + "sc:basic-features-crypto": { + "nonce": "0", + "balance": "0", + "code": "mxsc:../output/basic-features-crypto.mxsc.json" + }, + "address:an_account": { + "nonce": "0", + "balance": "0" + } + } + }, + { + "step": "scCall", + "id": "secp256r1 - ok", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features-crypto", + "function": "verify_secp256r1_signature", + "arguments": [ + "0x02bc52274edebbef8878eacc4d1e0ed4fb213e5b0737389701ae8d59c403325720", + "0xbf9facf48b2219db73b50c7ff59ceef2ada56632c71afc555d6bb4072d7634d1d9353acd53517ffb9a06935a89a6454fcaa40c69becf9f8029a271fd252ea55307d00d6e97a30719d48d6b7f993af24e9c54381cba02a113238eaee9d741cababeb21aaf", + "0xc7877497444274267a4ea6f42deefde23a12e44f1ec1b437018e5c0e2834ce376dec1b81ebeacf5fbc6882e69af7cafad47bbb96cfb09e8d77d12afff7543052" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "", + "logs": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "id": "secp256r1 - fail", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features-crypto", + "function": "verify_secp256r1_signature", + "arguments": [ + "0x02bc52274edebbef8878eacc4d1e0ed4fb213e5b0737389701ae8d59c403325720", + "0xbf9facf48b2219db73b50c7ff59ceef2ada56632c71afc555d6bb4072d7634d1d9353acd53517ffb9a06935a89a6454fcaa40c69becf9f8029a271fd252ea55307d00d6e97a30719d48d6b7f993af24e9c54381cba02a113238eaee9d741cababeb21aaf", + "0x00877497444274267a4ea6f42deefde23a12e44f1ec1b437018e5c0e2834ce376dec1b81ebeacf5fbc6882e69af7cafad47bbb96cfb09e8d77d12afff7543052" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "10", + "message": "str:signature verification failed", + "logs": "*", + "gas": "*", + "refund": "*" + } + } + ] +} diff --git a/contracts/feature-tests/basic-features/scenarios/managed_decimal.scen.json b/contracts/feature-tests/basic-features/scenarios/managed_decimal.scen.json index e19612ae29..b723c07b6d 100644 --- a/contracts/feature-tests/basic-features/scenarios/managed_decimal.scen.json +++ b/contracts/feature-tests/basic-features/scenarios/managed_decimal.scen.json @@ -143,4 +143,4 @@ } } ] -} \ No newline at end of file +} diff --git a/contracts/feature-tests/basic-features/scenarios/managed_decimal_logarithm.scen.json b/contracts/feature-tests/basic-features/scenarios/managed_decimal_logarithm.scen.json index da54f8ccec..193517275c 100644 --- a/contracts/feature-tests/basic-features/scenarios/managed_decimal_logarithm.scen.json +++ b/contracts/feature-tests/basic-features/scenarios/managed_decimal_logarithm.scen.json @@ -24,7 +24,7 @@ "arguments": [ "23,000000000" ], - "gasLimit": "9,000,000", + "gasLimit": "25,000,000", "gasPrice": "0" }, "expect": { @@ -107,4 +107,4 @@ } } ] -} \ No newline at end of file +} diff --git a/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address.scen.json b/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address.scen.json index 77ffdda1ee..2a0ff501a8 100644 --- a/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address.scen.json +++ b/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address.scen.json @@ -372,4 +372,4 @@ } } ] -} \ No newline at end of file +} diff --git a/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address_extra_key.scen.json b/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address_extra_key.scen.json index e124fd7e1a..d2802f41d2 100644 --- a/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address_extra_key.scen.json +++ b/contracts/feature-tests/basic-features/scenarios/storage_mapper_get_at_address_extra_key.scen.json @@ -87,4 +87,4 @@ } } ] -} \ No newline at end of file +} diff --git a/contracts/feature-tests/basic-features/src/crypto_features.rs b/contracts/feature-tests/basic-features/src/crypto_features.rs index 56c543163c..0588146780 100644 --- a/contracts/feature-tests/basic-features/src/crypto_features.rs +++ b/contracts/feature-tests/basic-features/src/crypto_features.rs @@ -24,7 +24,7 @@ pub trait CryptoFeatures { key: ManagedBuffer, message: ManagedBuffer, signature: ManagedBuffer, - ) -> bool { + ) { self.crypto().verify_bls(&key, &message, &signature) } @@ -64,4 +64,39 @@ pub trait CryptoFeatures { fn compute_secp256k1_der_signature(&self, r: ManagedBuffer, s: ManagedBuffer) -> ManagedBuffer { self.crypto().encode_secp256k1_der_signature(&r, &s) } + + #[endpoint] + #[label("crypto-ei-1.4")] + fn verify_secp256r1_signature( + &self, + key: ManagedBuffer, + message: ManagedBuffer, + signature: ManagedBuffer, + ) { + self.crypto().verify_secp256r1(&key, &message, &signature) + } + + #[endpoint] + #[label("crypto-ei-1.4")] + fn verify_bls_signature_share( + &self, + key: ManagedBuffer, + message: ManagedBuffer, + signature: ManagedBuffer, + ) { + self.crypto() + .verify_bls_signature_share(&key, &message, &signature) + } + + #[endpoint] + #[label("crypto-ei-1.4")] + fn verify_bls_aggregated_signature( + &self, + key: ManagedVec, + message: ManagedBuffer, + signature: ManagedBuffer, + ) { + self.crypto() + .verify_bls_aggregated_signature(&key, &message, &signature) + } } diff --git a/contracts/feature-tests/basic-features/tests/basic_features_scenario_go_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_scenario_go_test.rs index 9c39d06ae5..58bee7c1da 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_scenario_go_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_scenario_go_test.rs @@ -84,6 +84,18 @@ fn crypto_verify_bls_go() { world().run("scenarios/crypto_verify_bls.scen.json"); } +#[test] +#[ignore = "requires EI 1.4 in mx-scenario-go"] +fn crypto_verify_bls_share_go() { + world().run("scenarios/crypto_verify_bls_share.scen.json"); +} + +#[test] +#[ignore = "requires EI 1.4 in mx-scenario-go"] +fn crypto_verify_bls_aggregated_go() { + world().run("scenarios/crypto_verify_bls_aggregated_signature.scen.json"); +} + #[test] fn crypto_verify_ed_25519_go() { world().run("scenarios/crypto_verify_ed25519.scen.json"); @@ -94,6 +106,12 @@ fn crypto_verify_secp_256_k_1_go() { world().run("scenarios/crypto_verify_secp256k1.scen.json"); } +#[test] +#[ignore = "requires EI 1.4 in mx-scenario-go"] +fn crypto_verify_secp_256_r_1_go() { + world().run("scenarios/crypto_verify_secp256r1.scen.json"); +} + #[test] fn echo_array_u_8_go() { world().run("scenarios/echo_array_u8.scen.json"); diff --git a/contracts/feature-tests/basic-features/tests/basic_features_scenario_rs_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_scenario_rs_test.rs index f35c4779e6..2689d7f3ec 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_scenario_rs_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_scenario_rs_test.rs @@ -11,6 +11,10 @@ fn world() -> ScenarioWorld { "mxsc:../esdt-system-sc-mock/output/esdt-system-sc-mock.mxsc.json", esdt_system_sc_mock::ContractBuilder, ); + blockchain.register_contract( + "mxsc:output/basic-features-crypto.mxsc.json", + basic_features::ContractBuilder, + ); blockchain } @@ -98,6 +102,18 @@ fn crypto_verify_bls_rs() { world().run("scenarios/crypto_verify_bls.scen.json"); } +#[test] +#[ignore] +fn crypto_verify_bls_share_rs() { + world().run("scenarios/crypto_verify_bls_share.scen.json"); +} + +#[test] +#[ignore] +fn crypto_verify_bls_aggregated_rs() { + world().run("scenarios/crypto_verify_bls_aggregated_signature.scen.json"); +} + #[test] fn crypto_verify_ed_25519_rs() { world().run("scenarios/crypto_verify_ed25519.scen.json"); @@ -109,6 +125,12 @@ fn crypto_verify_secp_256_k_1_rs() { world().run("scenarios/crypto_verify_secp256k1.scen.json"); } +#[test] +#[ignore] +fn crypto_verify_secp_256_r_1_rs() { + world().run("scenarios/crypto_verify_secp256r1.scen.json"); +} + #[test] fn echo_array_u_8_rs() { world().run("scenarios/echo_array_u8.scen.json"); diff --git a/contracts/feature-tests/basic-features/wasm-basic-features-crypto/Cargo.lock b/contracts/feature-tests/basic-features/wasm-basic-features-crypto/Cargo.lock new file mode 100644 index 0000000000..1666820785 --- /dev/null +++ b/contracts/feature-tests/basic-features/wasm-basic-features-crypto/Cargo.lock @@ -0,0 +1,186 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "basic-features" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + +[[package]] +name = "basic-features-crypto-wasm" +version = "0.0.0" +dependencies = [ + "basic-features", + "multiversx-sc-wasm-adapter", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "multiversx-sc" +version = "0.52.3" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.20.1" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.20.1" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.52.3" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.52.3" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.52.3" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" diff --git a/contracts/feature-tests/basic-features/wasm-basic-features-crypto/Cargo.toml b/contracts/feature-tests/basic-features/wasm-basic-features-crypto/Cargo.toml new file mode 100644 index 0000000000..46f40289e3 --- /dev/null +++ b/contracts/feature-tests/basic-features/wasm-basic-features-crypto/Cargo.toml @@ -0,0 +1,35 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "basic-features-crypto-wasm" +version = "0.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" +overflow-checks = false + +[profile.dev] +panic = "abort" + +[dependencies.basic-features] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.52.3" +path = "../../../../framework/wasm-adapter" + +[workspace] +members = ["."] diff --git a/contracts/feature-tests/basic-features/wasm-basic-features-crypto/src/lib.rs b/contracts/feature-tests/basic-features/wasm-basic-features-crypto/src/lib.rs new file mode 100644 index 0000000000..134138a65f --- /dev/null +++ b/contracts/feature-tests/basic-features/wasm-basic-features-crypto/src/lib.rs @@ -0,0 +1,27 @@ +// Code generated by the multiversx-sc build system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Endpoints: 3 +// Async Callback (empty): 1 +// Total number of exported functions: 5 + +#![no_std] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + basic_features + ( + init => init + verify_secp256r1_signature => verify_secp256r1_signature + verify_bls_signature_share => verify_bls_signature_share + verify_bls_aggregated_signature => verify_bls_aggregated_signature + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/fwd_esdt_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/fwd_esdt_legacy.rs index b56db69bb8..6fa20793d8 100644 --- a/contracts/feature-tests/composability/forwarder-legacy/src/fwd_esdt_legacy.rs +++ b/contracts/feature-tests/composability/forwarder-legacy/src/fwd_esdt_legacy.rs @@ -128,8 +128,7 @@ pub trait ForwarderEsdtModule: fwd_storage_legacy::ForwarderStorageModule { // so we can get the token identifier and amount from the call data match result { ManagedAsyncCallResult::Ok(()) => { - self.last_issued_token() - .set(&token_identifier.unwrap_esdt()); + self.last_issued_token().set(token_identifier.unwrap_esdt()); self.last_error_message().clear(); }, ManagedAsyncCallResult::Err(message) => { diff --git a/contracts/feature-tests/composability/forwarder/src/fwd_esdt.rs b/contracts/feature-tests/composability/forwarder/src/fwd_esdt.rs index fcc3912ecc..a4dbaa28b1 100644 --- a/contracts/feature-tests/composability/forwarder/src/fwd_esdt.rs +++ b/contracts/feature-tests/composability/forwarder/src/fwd_esdt.rs @@ -132,8 +132,7 @@ pub trait ForwarderEsdtModule: fwd_storage::ForwarderStorageModule { // so we can get the token identifier and amount from the call data match result { ManagedAsyncCallResult::Ok(()) => { - self.last_issued_token() - .set(&token_identifier.unwrap_esdt()); + self.last_issued_token().set(token_identifier.unwrap_esdt()); self.last_error_message().clear(); }, ManagedAsyncCallResult::Err(message) => { diff --git a/contracts/feature-tests/composability/local-esdt-and-nft/src/lib.rs b/contracts/feature-tests/composability/local-esdt-and-nft/src/lib.rs index 55f0577795..0291d36131 100644 --- a/contracts/feature-tests/composability/local-esdt-and-nft/src/lib.rs +++ b/contracts/feature-tests/composability/local-esdt-and-nft/src/lib.rs @@ -276,8 +276,7 @@ pub trait LocalEsdtAndEsdtNft { // so we can get the token identifier and amount from the call data match result { ManagedAsyncCallResult::Ok(()) => { - self.last_issued_token() - .set(&token_identifier.unwrap_esdt()); + self.last_issued_token().set(token_identifier.unwrap_esdt()); self.last_error_message().clear(); }, ManagedAsyncCallResult::Err(message) => { diff --git a/contracts/feature-tests/composability/tests/forwarder_whitebox_legacy_test.rs b/contracts/feature-tests/composability/tests/forwarder_whitebox_legacy_test.rs index 8766bfa174..424c1508a4 100644 --- a/contracts/feature-tests/composability/tests/forwarder_whitebox_legacy_test.rs +++ b/contracts/feature-tests/composability/tests/forwarder_whitebox_legacy_test.rs @@ -1,24 +1,16 @@ use forwarder_legacy::fwd_nft_legacy::{Color, ForwarderNftModule}; -use multiversx_sc::{contract_base::ContractBase, types::Address}; -use multiversx_sc_scenario::{ - managed_address, managed_biguint, managed_token_id, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, SetStateStep, - }, - ScenarioWorld, WhiteboxContract, -}; -const USER_ADDRESS_EXPR: &str = "address:user"; -const FORWARDER_ADDRESS_EXPR: &str = "sc:forwarder_legacy"; -const FORWARDER_PATH_EXPR: &str = "mxsc:output/forwarder_legacy.mxsc.json"; +use multiversx_sc_scenario::imports::*; -const NFT_TOKEN_ID_EXPR: &str = "str:COOL-123456"; -const NFT_TOKEN_ID: &[u8] = b"COOL-123456"; +const USER_ADDRESS: TestAddress = TestAddress::new("user"); +const FORWARDER_ADDRESS: TestSCAddress = TestSCAddress::new("forwarder_legacy"); +const FORWARDER_PATH: MxscPath = MxscPath::new("output/forwarder_legacy.mxsc.json"); +const NFT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("COOL-123456"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.register_contract(FORWARDER_PATH_EXPR, forwarder_legacy::ContractBuilder); + blockchain.register_contract(FORWARDER_PATH, forwarder_legacy::ContractBuilder); blockchain } @@ -26,57 +18,40 @@ fn world() -> ScenarioWorld { fn test_nft_update_attributes_and_send() { let mut world = world(); - let forwarder_legacy_code = world.code_expression(FORWARDER_PATH_EXPR); let roles = vec![ "ESDTRoleNFTCreate".to_string(), "ESDTRoleNFTUpdateAttributes".to_string(), ]; - world.set_state_step( - SetStateStep::new() - .put_account(USER_ADDRESS_EXPR, Account::new().nonce(1)) - .put_account( - FORWARDER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .code(forwarder_legacy_code) - .esdt_roles(NFT_TOKEN_ID_EXPR, roles), - ), - ); - - let forwarder_legacy_whitebox = - WhiteboxContract::new(FORWARDER_ADDRESS_EXPR, forwarder_legacy::contract_obj); + world.account(USER_ADDRESS).nonce(1); + world + .account(FORWARDER_ADDRESS) + .nonce(1) + .code(FORWARDER_PATH) + .esdt_roles(NFT_TOKEN_ID, roles); let original_attributes = Color { r: 0, g: 0, b: 0 }; - world.whitebox_call( - &forwarder_legacy_whitebox, - ScCallStep::new().from(USER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(USER_ADDRESS) + .to(FORWARDER_ADDRESS) + .whitebox(forwarder_legacy::contract_obj, |sc| { sc.nft_create_compact( - managed_token_id!(NFT_TOKEN_ID), + NFT_TOKEN_ID.to_token_identifier(), managed_biguint!(1), original_attributes, ); - sc.send().direct_esdt( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(NFT_TOKEN_ID), - 1, - &managed_biguint!(1), - ); - }, - ); + sc.tx() + .to(USER_ADDRESS) + .esdt((NFT_TOKEN_ID.to_token_identifier(), 1, 1u32.into())) + .transfer(); + }); - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - NFT_TOKEN_ID_EXPR, - 1, - "1", - Some(original_attributes), - ), - )); + world + .check_account(USER_ADDRESS) + .esdt_nft_balance_and_attributes(NFT_TOKEN_ID, 1, 1, original_attributes); let new_attributes = Color { r: 255, @@ -84,34 +59,21 @@ fn test_nft_update_attributes_and_send() { b: 255, }; - world.whitebox_call( - &forwarder_legacy_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .esdt_transfer(NFT_TOKEN_ID, 1, "1"), - |sc| { - sc.nft_update_attributes(managed_token_id!(NFT_TOKEN_ID), 1, new_attributes); - - sc.send().direct_esdt( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(NFT_TOKEN_ID), - 1, - &managed_biguint!(1), - ); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - NFT_TOKEN_ID_EXPR, - 1, - "1", - Some(new_attributes), - ), - )); -} - -fn address_expr_to_address(address_expr: &str) -> Address { - AddressValue::from(address_expr).to_address() + world + .tx() + .from(USER_ADDRESS) + .to(FORWARDER_ADDRESS) + .payment(TestEsdtTransfer(NFT_TOKEN_ID, 1, 1)) + .whitebox(forwarder_legacy::contract_obj, |sc| { + sc.nft_update_attributes(NFT_TOKEN_ID.to_token_identifier(), 1, new_attributes); + + sc.tx() + .to(USER_ADDRESS) + .esdt((NFT_TOKEN_ID.to_token_identifier(), 1, 1u32.into())) + .transfer(); + }); + + world + .check_account(USER_ADDRESS) + .esdt_nft_balance_and_attributes(NFT_TOKEN_ID, 1, 1, new_attributes); } diff --git a/contracts/feature-tests/composability/tests/forwarder_whitebox_test.rs b/contracts/feature-tests/composability/tests/forwarder_whitebox_test.rs index 1dbf3952f2..c6f2b54a78 100644 --- a/contracts/feature-tests/composability/tests/forwarder_whitebox_test.rs +++ b/contracts/feature-tests/composability/tests/forwarder_whitebox_test.rs @@ -1,17 +1,15 @@ use forwarder::fwd_nft::{Color, ForwarderNftModule}; use multiversx_sc_scenario::imports::*; -const USER_ADDRESS_EXPR: &str = "address:user"; -const FORWARDER_ADDRESS_EXPR: &str = "sc:forwarder"; -const FORWARDER_PATH_EXPR: &str = "mxsc:output/forwarder.mxsc.json"; - -const NFT_TOKEN_ID_EXPR: &str = "str:COOL-123456"; -const NFT_TOKEN_ID: &[u8] = b"COOL-123456"; +const USER_ADDRESS: TestAddress = TestAddress::new("user"); +const FORWARDER_ADDRESS: TestSCAddress = TestSCAddress::new("forwarder"); +const FORWARDER_PATH: MxscPath = MxscPath::new("output/forwarder.mxsc.json"); +const NFT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("COOL-123456"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.register_contract(FORWARDER_PATH_EXPR, forwarder::ContractBuilder); + blockchain.register_contract(FORWARDER_PATH, forwarder::ContractBuilder); blockchain } @@ -19,56 +17,40 @@ fn world() -> ScenarioWorld { fn test_nft_update_attributes_and_send() { let mut world = world(); - let forwarder_code = world.code_expression(FORWARDER_PATH_EXPR); let roles = vec![ "ESDTRoleNFTCreate".to_string(), "ESDTRoleNFTUpdateAttributes".to_string(), ]; - world.set_state_step( - SetStateStep::new() - .put_account(USER_ADDRESS_EXPR, Account::new().nonce(1)) - .put_account( - FORWARDER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .code(forwarder_code) - .esdt_roles(NFT_TOKEN_ID_EXPR, roles), - ), - ); - - let forwarder_whitebox = WhiteboxContract::new(FORWARDER_ADDRESS_EXPR, forwarder::contract_obj); + world.account(USER_ADDRESS).nonce(1); + world + .account(FORWARDER_ADDRESS) + .nonce(1) + .code(FORWARDER_PATH) + .esdt_roles(NFT_TOKEN_ID, roles); let original_attributes = Color { r: 0, g: 0, b: 0 }; - world.whitebox_call( - &forwarder_whitebox, - ScCallStep::new().from(USER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(USER_ADDRESS) + .to(FORWARDER_ADDRESS) + .whitebox(forwarder::contract_obj, |sc| { sc.nft_create_compact( - managed_token_id!(NFT_TOKEN_ID), + NFT_TOKEN_ID.to_token_identifier(), managed_biguint!(1), original_attributes, ); - sc.send().direct_esdt( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(NFT_TOKEN_ID), - 1, - &managed_biguint!(1), - ); - }, - ); + sc.tx() + .to(USER_ADDRESS) + .esdt((NFT_TOKEN_ID.to_token_identifier(), 1, 1u32.into())) + .transfer(); + }); - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - NFT_TOKEN_ID_EXPR, - 1, - "1", - Some(original_attributes), - ), - )); + world + .check_account(USER_ADDRESS) + .esdt_nft_balance_and_attributes(NFT_TOKEN_ID, 1, 1, original_attributes); let new_attributes = Color { r: 255, @@ -76,34 +58,21 @@ fn test_nft_update_attributes_and_send() { b: 255, }; - world.whitebox_call( - &forwarder_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .esdt_transfer(NFT_TOKEN_ID, 1, "1"), - |sc| { - sc.nft_update_attributes(managed_token_id!(NFT_TOKEN_ID), 1, new_attributes); - - sc.send().direct_esdt( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(NFT_TOKEN_ID), - 1, - &managed_biguint!(1), - ); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - NFT_TOKEN_ID_EXPR, - 1, - "1", - Some(new_attributes), - ), - )); -} - -fn address_expr_to_address(address_expr: &str) -> Address { - AddressValue::from(address_expr).to_address() + world + .tx() + .from(USER_ADDRESS) + .to(FORWARDER_ADDRESS) + .payment(TestEsdtTransfer(NFT_TOKEN_ID, 1, 1)) + .whitebox(forwarder::contract_obj, |sc| { + sc.nft_update_attributes(NFT_TOKEN_ID.to_token_identifier(), 1, new_attributes); + + sc.tx() + .to(USER_ADDRESS) + .esdt((NFT_TOKEN_ID.to_token_identifier(), 1, 1u32.into())) + .transfer(); + }); + + world + .check_account(USER_ADDRESS) + .esdt_nft_balance_and_attributes(NFT_TOKEN_ID, 1, 1, new_attributes); } diff --git a/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_whitebox_test.rs b/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_whitebox_test.rs index adf9582982..5ed03c38bc 100644 --- a/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_whitebox_test.rs +++ b/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_whitebox_test.rs @@ -1,15 +1,17 @@ use multiversx_sc_modules::transfer_role_proxy::TransferRoleProxyModule; use multiversx_sc_scenario::imports::*; use transfer_role_features::TransferRoleFeatures; +use vault::Vault; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const USER_ADDRESS_EXPR: &str = "address:user"; +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const USER_ADDRESS: TestAddress = TestAddress::new("user"); -const TRANSFER_ROLE_FEATURES_ADDRESS_EXPR: &str = "sc:transfer-role-features"; -const TRANSFER_ROLE_FEATURES_PATH_EXPR: &str = "mxsc:output/transfer-role-features.mxsc.json"; +const TRANSFER_ROLE_FEATURES_ADDRESS: TestSCAddress = TestSCAddress::new("transfer-role-features"); +const TRANSFER_ROLE_FEATURES_PATH_EXPR: MxscPath = + MxscPath::new("mxsc:output/transfer-role-features.mxsc.json"); -const TRANSFER_TOKEN_ID_EXPR: &str = "str:TRANSFER-123456"; -const TRANSFER_TOKEN_ID: &[u8] = b"TRANSFER-123456"; +const TRANSFER_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("TRANSFER-123456"); +const TRANSFER_TOKEN_ID_EXPR: &[u8] = b"TRANSFER-123456"; const ACCEPT_FUNDS_FUNC_NAME: &[u8] = b"accept_funds"; const REJECT_FUNDS_FUNC_NAME: &[u8] = b"reject_funds"; @@ -27,175 +29,145 @@ fn world() -> ScenarioWorld { fn test_transfer_role() { let mut world = world(); - world.set_state_step( - SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(OWNER_ADDRESS_EXPR, 1, TRANSFER_ROLE_FEATURES_ADDRESS_EXPR) - .put_account( - USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(TRANSFER_TOKEN_ID_EXPR, 1_000u64), - ), - ); + world.account(OWNER_ADDRESS).nonce(1); + world + .account(USER_ADDRESS) + .nonce(1) + .esdt_balance(TRANSFER_TOKEN_ID, BigUint::from(1_000u64)); // vault - let vault_code = world.code_expression(VAULT_PATH_EXPR); - - const VAULT_ADDRESS_EXPR: &str = "sc:vault"; - const VAULT_PATH_EXPR: &str = "mxsc:../vault/output/vault.mxsc.json"; + const VAULT_ADDRESS: TestSCAddress = TestSCAddress::new("vault"); + const VAULT_PATH_EXPR: MxscPath = MxscPath::new("mxsc:../vault/output/vault.mxsc.json"); world.register_contract(VAULT_PATH_EXPR, vault::ContractBuilder); - world.set_state_step( - SetStateStep::new() - .put_account(VAULT_ADDRESS_EXPR, Account::new().nonce(1).code(vault_code)), - ); - - let transfer_role_features_whitebox = WhiteboxContract::new( - TRANSFER_ROLE_FEATURES_ADDRESS_EXPR, - transfer_role_features::contract_obj, - ); - let transfer_role_features_code = world.code_expression(TRANSFER_ROLE_FEATURES_PATH_EXPR); + world + .tx() + .from(OWNER_ADDRESS) + .raw_deploy() + .new_address(VAULT_ADDRESS) + .code(VAULT_PATH_EXPR) + .whitebox(vault::contract_obj, |sc| { + let _ = sc.init(OptionalValue::None); + }); // init - world.whitebox_deploy( - &transfer_role_features_whitebox, - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(transfer_role_features_code), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .raw_deploy() + .new_address(TRANSFER_ROLE_FEATURES_ADDRESS) + .code(TRANSFER_ROLE_FEATURES_PATH_EXPR) + .whitebox(transfer_role_features::contract_obj, |sc| { let mut whitelist = MultiValueEncoded::new(); - whitelist.push(managed_address!(&address_expr_to_address( - OWNER_ADDRESS_EXPR - ))); - whitelist.push(managed_address!(&address_expr_to_address( - VAULT_ADDRESS_EXPR - ))); + whitelist.push(OWNER_ADDRESS.to_managed_address()); + whitelist.push(VAULT_ADDRESS.to_managed_address()); sc.init(whitelist); - }, - ); + }); // transfer to user - ok - world.whitebox_call( - &transfer_role_features_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .esdt_transfer(TRANSFER_TOKEN_ID, 0, "100"), - |sc| { + world + .tx() + .from(USER_ADDRESS) + .to(TRANSFER_ROLE_FEATURES_ADDRESS) + .payment(TestEsdtTransfer(TRANSFER_TOKEN_ID, 0, 100)) + .whitebox(transfer_role_features::contract_obj, |sc| { let payments = ManagedVec::from_single_item(EsdtTokenPayment::new( - managed_token_id!(TRANSFER_TOKEN_ID), + managed_token_id!(TRANSFER_TOKEN_ID_EXPR), 0, managed_biguint!(100), )); sc.transfer_to_user( - managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - managed_address!(&address_expr_to_address(OWNER_ADDRESS_EXPR)), + USER_ADDRESS.to_managed_address(), + OWNER_ADDRESS.to_managed_address(), &payments, managed_buffer!(b"enjoy"), ); - }, - ); + }); - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(TRANSFER_TOKEN_ID_EXPR, "900"), - )); - world.check_state_step(CheckStateStep::new().put_account( - OWNER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(TRANSFER_TOKEN_ID_EXPR, "100"), - )); + world + .check_account(USER_ADDRESS) + .esdt_balance(TRANSFER_TOKEN_ID, BigUint::from(900u64)); + world + .check_account(OWNER_ADDRESS) + .esdt_balance(TRANSFER_TOKEN_ID, BigUint::from(100u64)); // transfer to user - err, not whitelisted - world.whitebox_call_check( - &transfer_role_features_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .esdt_transfer(TRANSFER_TOKEN_ID, 0, "100") - .no_expect(), - |sc| { + world + .tx() + .from(USER_ADDRESS) + .to(TRANSFER_ROLE_FEATURES_ADDRESS) + .payment(TestEsdtTransfer(TRANSFER_TOKEN_ID, 0, 100)) + .returns(ExpectError(4u64, "Destination address not whitelisted")) + .whitebox(transfer_role_features::contract_obj, |sc| { let payments = ManagedVec::from_single_item(EsdtTokenPayment::new( - managed_token_id!(TRANSFER_TOKEN_ID), + managed_token_id!(TRANSFER_TOKEN_ID_EXPR), 0, managed_biguint!(100), )); sc.transfer_to_user( - managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), + USER_ADDRESS.to_managed_address(), managed_address!(&Address::zero()), &payments, managed_buffer!(b"enjoy"), ); - }, - |r| { - r.assert_user_error("Destination address not whitelisted"); - }, - ); + }); // transfer to sc - ok - world.whitebox_call( - &transfer_role_features_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .esdt_transfer(TRANSFER_TOKEN_ID, 0, "100"), - |sc| { + world + .tx() + .from(USER_ADDRESS) + .to(TRANSFER_ROLE_FEATURES_ADDRESS) + .payment(TestEsdtTransfer(TRANSFER_TOKEN_ID, 0, 100)) + .whitebox(transfer_role_features::contract_obj, |sc| { let payments = ManagedVec::from_single_item(EsdtTokenPayment::new( - managed_token_id!(TRANSFER_TOKEN_ID), + managed_token_id!(TRANSFER_TOKEN_ID_EXPR), 0, managed_biguint!(100), )); sc.transfer_to_contract_raw( - managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - managed_address!(&address_expr_to_address(VAULT_ADDRESS_EXPR)), + USER_ADDRESS.to_managed_address(), + VAULT_ADDRESS.to_managed_address(), &payments, managed_buffer!(ACCEPT_FUNDS_FUNC_NAME), ManagedArgBuffer::new(), None, ); - }, - ); + }); - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(TRANSFER_TOKEN_ID_EXPR, "800"), - )); - world.check_state_step(CheckStateStep::new().put_account( - VAULT_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(TRANSFER_TOKEN_ID_EXPR, "100"), - )); + world + .check_account(USER_ADDRESS) + .esdt_balance(TRANSFER_TOKEN_ID, BigUint::from(800u64)); + world + .check_account(VAULT_ADDRESS) + .esdt_balance(TRANSFER_TOKEN_ID, BigUint::from(100u64)); // transfer to sc - reject - world.whitebox_call( - &transfer_role_features_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .esdt_transfer(TRANSFER_TOKEN_ID, 0, "100"), - |sc| { + world + .tx() + .from(USER_ADDRESS) + .to(TRANSFER_ROLE_FEATURES_ADDRESS) + .payment(TestEsdtTransfer(TRANSFER_TOKEN_ID, 0, 100)) + .whitebox(transfer_role_features::contract_obj, |sc| { let payments = ManagedVec::from_single_item(EsdtTokenPayment::new( - managed_token_id!(TRANSFER_TOKEN_ID), + managed_token_id!(TRANSFER_TOKEN_ID_EXPR), 0, managed_biguint!(100), )); sc.transfer_to_contract_raw( - managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - managed_address!(&address_expr_to_address(VAULT_ADDRESS_EXPR)), + USER_ADDRESS.to_managed_address(), + VAULT_ADDRESS.to_managed_address(), &payments, managed_buffer!(REJECT_FUNDS_FUNC_NAME), ManagedArgBuffer::new(), None, ); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(TRANSFER_TOKEN_ID_EXPR, "800"), - )); - world.check_state_step(CheckStateStep::new().put_account( - VAULT_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(TRANSFER_TOKEN_ID_EXPR, "100"), - )); -} - -fn address_expr_to_address(address_expr: &str) -> Address { - AddressValue::from(address_expr).to_address() + }); + + world + .check_account(USER_ADDRESS) + .esdt_balance(TRANSFER_TOKEN_ID, BigUint::from(800u64)); + world + .check_account(VAULT_ADDRESS) + .esdt_balance(TRANSFER_TOKEN_ID, BigUint::from(100u64)); } diff --git a/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155.rs b/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155.rs index 725cff90de..b4d8acc941 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155.rs +++ b/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155.rs @@ -160,7 +160,7 @@ pub trait Erc1155 { self.token_owner(type_id, nft_id).set(to); } else { self.token_owner(type_id, nft_id) - .set(&ManagedAddress::zero()); + .set(ManagedAddress::zero()); } } @@ -320,7 +320,7 @@ pub trait Erc1155 { let amount = BigUint::from(1u32); self.decrease_balance(owner, type_id, &amount); self.token_owner(type_id, nft_id) - .set(&ManagedAddress::zero()); + .set(ManagedAddress::zero()); } /// Range is inclusive for both `start` and `end` diff --git a/contracts/feature-tests/rust-testing-framework-tester/sc-config.toml b/contracts/feature-tests/rust-testing-framework-tester/sc-config.toml index 330cdda658..b8c5b739dc 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/sc-config.toml +++ b/contracts/feature-tests/rust-testing-framework-tester/sc-config.toml @@ -4,3 +4,8 @@ main = "rust-testing-framework-tester" # the only purpose of this config is to specify the allocator [contracts.rust-testing-framework-tester] allocator = "static64k" + +[[proxy]] +path = "src/rust_testing_framework_tester_proxy.rs" +add-unlabelled = false +add-endpoints = ["init"] diff --git a/contracts/feature-tests/rust-testing-framework-tester/src/dummy_module.rs b/contracts/feature-tests/rust-testing-framework-tester/src/dummy_module.rs index 76721a8fc4..7db5c9379d 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/src/dummy_module.rs +++ b/contracts/feature-tests/rust-testing-framework-tester/src/dummy_module.rs @@ -1,5 +1,3 @@ -multiversx_sc::imports!(); - #[multiversx_sc::module] pub trait DummyModule { fn some_function(&self) -> BigUint { diff --git a/contracts/feature-tests/rust-testing-framework-tester/src/lib.rs b/contracts/feature-tests/rust-testing-framework-tester/src/lib.rs index 4133f3f039..ffc411dad0 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/src/lib.rs +++ b/contracts/feature-tests/rust-testing-framework-tester/src/lib.rs @@ -1,11 +1,12 @@ #![no_std] -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::proxy_imports::*; pub mod dummy_module; +pub mod rust_testing_framework_tester_proxy; -#[derive(TopEncode, TopDecode, TypeAbi, Clone, Debug, PartialEq, Eq)] +#[type_abi] +#[derive(TopEncode, TopDecode, Clone, Debug, PartialEq, Eq)] pub struct NftDummyAttributes { pub creation_epoch: u64, pub cool_factor: u8, @@ -20,7 +21,7 @@ pub struct StructWithManagedTypes { pub trait RustTestingFrameworkTester: dummy_module::DummyModule { #[init] fn init(&self) -> ManagedBuffer { - self.total_value().set(&BigUint::from(1u32)); + self.total_value().set(BigUint::from(1u32)); b"constructor-result".into() } diff --git a/contracts/feature-tests/rust-testing-framework-tester/src/rust_testing_framework_tester_proxy.rs b/contracts/feature-tests/rust-testing-framework-tester/src/rust_testing_framework_tester_proxy.rs new file mode 100644 index 0000000000..6a42d7e5b3 --- /dev/null +++ b/contracts/feature-tests/rust-testing-framework-tester/src/rust_testing_framework_tester_proxy.rs @@ -0,0 +1,61 @@ +// Code generated by the multiversx-sc proxy generator. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +#![allow(dead_code)] +#![allow(clippy::all)] + +use multiversx_sc::proxy_imports::*; + +pub struct RustTestingFrameworkTesterProxy; + +impl TxProxyTrait for RustTestingFrameworkTesterProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = RustTestingFrameworkTesterProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + RustTestingFrameworkTesterProxyMethods { wrapped_tx: tx } + } +} + +pub struct RustTestingFrameworkTesterProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl RustTestingFrameworkTesterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxTypedDeploy> { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Clone, Debug, PartialEq, Eq)] +pub struct NftDummyAttributes { + pub creation_epoch: u64, + pub cool_factor: u8, +} diff --git a/contracts/feature-tests/rust-testing-framework-tester/tests/tester_blackbox_test.rs b/contracts/feature-tests/rust-testing-framework-tester/tests/tester_blackbox_test.rs index afdabb5199..a426721718 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/tests/tester_blackbox_test.rs +++ b/contracts/feature-tests/rust-testing-framework-tester/tests/tester_blackbox_test.rs @@ -1,77 +1,50 @@ use multiversx_sc_scenario::imports::*; use rust_testing_framework_tester::*; -const WASM_PATH_EXPR: &str = "mxsc:output/rust-testing-framework-tester.mxsc.json"; +const CODE_PATH: MxscPath = MxscPath::new("output/rust-testing-framework-tester.mxsc.json"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const RUST_TESTING_FRAMEWORK_TESTER_ADDRESS: TestSCAddress = + TestSCAddress::new("rust-testing-framework-tester"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.register_contract( - WASM_PATH_EXPR, - rust_testing_framework_tester::ContractBuilder, - ); + blockchain.register_contract(CODE_PATH, rust_testing_framework_tester::ContractBuilder); + blockchain } #[test] -#[allow(deprecated)] fn tester_deploy_test() { let mut world = world(); - let code = world.code_expression(WASM_PATH_EXPR); - let owner_address = "address:owner"; - let mut adder_contract = - ContractInfo::>::new("sc:contract"); + world.start_trace(); + + world.account(OWNER_ADDRESS).new_address( + OWNER_ADDRESS, + 0, + RUST_TESTING_FRAMEWORK_TESTER_ADDRESS, + ); - world - .start_trace() - .set_state_step( - SetStateStep::new() - .put_account(owner_address, Account::new()) - .new_address(owner_address, 0, &adder_contract), - ) - .sc_deploy_use_result( - ScDeployStep::new() - .from(owner_address) - .code(code) - .call(adder_contract.init()), - |address, tr: TypedResponse| { - assert_eq!(address, adder_contract.to_address()); - assert_eq!(tr.result.unwrap(), "constructor-result"); - }, - ) - .write_scenario_trace("scenarios/trace-deploy.scen.json"); + let (returned_value, contract_address) = world + .tx() + .from(OWNER_ADDRESS) + .typed(rust_testing_framework_tester_proxy::RustTestingFrameworkTesterProxy) + .init() + .code(CODE_PATH) + .returns(ReturnsResult) + .new_address(RUST_TESTING_FRAMEWORK_TESTER_ADDRESS) + .returns(ReturnsNewAddress) + .run(); + + assert_eq!(returned_value.to_string(), "constructor-result"); + assert_eq!(contract_address, RUST_TESTING_FRAMEWORK_TESTER_ADDRESS); + + world.write_scenario_trace("scenarios/trace-deploy.scen.json"); } #[test] -#[allow(deprecated)] fn tester_deploy_test_spawned_thread() { - let handler = std::thread::spawn(|| { - let mut world = world(); - let code = world.code_expression(WASM_PATH_EXPR); - - let owner_address = "address:owner"; - let mut adder_contract = - ContractInfo::>::new("sc:contract"); - - world - .start_trace() - .set_state_step( - SetStateStep::new() - .put_account(owner_address, Account::new()) - .new_address(owner_address, 0, &adder_contract), - ) - .sc_deploy_use_result( - ScDeployStep::new() - .from(owner_address) - .code(code) - .call(adder_contract.init()), - |address, tr: TypedResponse| { - assert_eq!(address, adder_contract.to_address()); - assert_eq!(tr.result.unwrap(), "constructor-result"); - }, - ) - .write_scenario_trace("scenarios/trace-deploy.scen.json"); - }); + let handler = std::thread::spawn(tester_deploy_test); handler.join().unwrap(); } diff --git a/contracts/feature-tests/scenario-tester/tests/st_whitebox_deprecated_test.rs b/contracts/feature-tests/scenario-tester/tests/st_whitebox_deprecated_test.rs new file mode 100644 index 0000000000..e67fd8cacf --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_whitebox_deprecated_test.rs @@ -0,0 +1,54 @@ +#![allow(deprecated)] + +use multiversx_sc_scenario::imports::*; +use scenario_tester::*; + +const ADDER_PATH_EXPR: &str = "mxsc:output/scenario-tester.mxsc.json"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract( + "mxsc:output/scenario-tester.mxsc.json", + scenario_tester::ContractBuilder, + ); + blockchain +} + +#[test] +fn st_whitebox() { + let mut world = world(); + let st_whitebox = WhiteboxContract::new("sc:adder", scenario_tester::contract_obj); + let st_code = world.code_expression(ADDER_PATH_EXPR); + + world + .set_state_step( + SetStateStep::new() + .put_account("address:owner", Account::new().nonce(1)) + .new_address("address:owner", 1, "sc:adder"), + ) + .whitebox_deploy( + &st_whitebox, + ScDeployStep::new().from("address:owner").code(st_code), + |sc| { + sc.init(5u32.into()); + }, + ) + .whitebox_query(&st_whitebox, |sc| { + let sum_value = sc.sum(); + assert_eq!(sum_value.get(), 5u32); + }) + .whitebox_call( + &st_whitebox, + ScCallStep::new().from("address:owner"), + |sc| sc.add(3u32.into()), + ) + .check_state_step( + CheckStateStep::new() + .put_account("address:owner", CheckAccount::new()) + .put_account( + "sc:adder", + CheckAccount::new().check_storage("str:sum", "8"), + ), + ); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs index a6318b1f7f..61dd6cdc2d 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs @@ -1,7 +1,9 @@ use multiversx_sc_scenario::imports::*; use scenario_tester::*; -const ADDER_PATH_EXPR: &str = "mxsc:output/scenario-tester.mxsc.json"; +const ST_PATH_EXPR: MxscPath = MxscPath::new("mxsc:output/scenario-tester.mxsc.json"); +const OWNER: TestAddress = TestAddress::new("owner"); +const SCENARIO_TESTER: TestSCAddress = TestSCAddress::new("scenario-tester"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); @@ -16,37 +18,37 @@ fn world() -> ScenarioWorld { #[test] fn st_whitebox() { let mut world = world(); - let st_whitebox = WhiteboxContract::new("sc:adder", scenario_tester::contract_obj); - let st_code = world.code_expression(ADDER_PATH_EXPR); + + world.account(OWNER).nonce(1); + + let new_address = world + .tx() + .from(OWNER) + .raw_deploy() + .code(ST_PATH_EXPR) + .new_address(SCENARIO_TESTER) + .returns(ReturnsNewBech32Address) + .whitebox(scenario_tester::contract_obj, |sc| { + sc.init(BigUint::from(5u64)); + }); + + assert_eq!(new_address.to_address(), SCENARIO_TESTER.to_address()); world - .set_state_step( - SetStateStep::new() - .put_account("address:owner", Account::new().nonce(1)) - .new_address("address:owner", 1, "sc:adder"), - ) - .whitebox_deploy( - &st_whitebox, - ScDeployStep::new().from("address:owner").code(st_code), - |sc| { - sc.init(5u32.into()); - }, - ) - .whitebox_query(&st_whitebox, |sc| { + .query() + .to(SCENARIO_TESTER) + .whitebox(scenario_tester::contract_obj, |sc| { let sum_value = sc.sum(); - assert_eq!(sum_value.get(), 5u32); - }) - .whitebox_call( - &st_whitebox, - ScCallStep::new().from("address:owner"), - |sc| sc.add(3u32.into()), - ) - .check_state_step( - CheckStateStep::new() - .put_account("address:owner", CheckAccount::new()) - .put_account( - "sc:adder", - CheckAccount::new().check_storage("str:sum", "8"), - ), - ); + assert_eq!(sum_value.get(), BigUint::from(5u32)); + }); + + world + .tx() + .from(OWNER) + .to(SCENARIO_TESTER) + .whitebox(scenario_tester::contract_obj, |sc| sc.add(3u32.into())); + + world + .check_account(SCENARIO_TESTER) + .check_storage("str:sum", "8"); } diff --git a/contracts/feature-tests/use-module/tests/gov_module_whitebox_test.rs b/contracts/feature-tests/use-module/tests/gov_module_whitebox_test.rs index 72b15aac66..800797024b 100644 --- a/contracts/feature-tests/use-module/tests/gov_module_whitebox_test.rs +++ b/contracts/feature-tests/use-module/tests/gov_module_whitebox_test.rs @@ -4,8 +4,7 @@ use multiversx_sc_modules::governance::{ }; use multiversx_sc_scenario::imports::*; -const GOV_TOKEN_ID_EXPR: &str = "str:GOV-123456"; -const GOV_TOKEN_ID: &[u8] = b"GOV-123456"; +const GOV_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("GOV-123456"); const QUORUM: u64 = 1_500; const MIN_BALANCE_PROPOSAL: u64 = 500; const VOTING_DELAY_BLOCKS: u64 = 10; @@ -15,13 +14,13 @@ const LOCKING_PERIOD_BLOCKS: u64 = 30; const INITIAL_GOV_TOKEN_BALANCE: u64 = 1_000; const GAS_LIMIT: u64 = 1_000_000; -const USE_MODULE_ADDRESS_EXPR: &str = "sc:use-module"; -const USE_MODULE_PATH_EXPR: &str = "mxsc:output/use-module.mxsc.json"; +const USE_MODULE_ADDRESS: TestSCAddress = TestSCAddress::new("use-module"); +const USE_MODULE_PATH_EXPR: MxscPath = MxscPath::new("mxsc:output/use-module.mxsc.json"); -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const FIRST_USER_ADDRESS_EXPR: &str = "address:first-user"; -const SECOND_USER_ADDRESS_EXPR: &str = "address:second-user"; -const THIRD_USER_ADDRESS_EXPR: &str = "address:third-user"; +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const FIRST_USER_ADDRESS: TestAddress = TestAddress::new("first-user"); +const SECOND_USER_ADDRESS: TestAddress = TestAddress::new("second-user"); +const THIRD_USER_ADDRESS: TestAddress = TestAddress::new("third-user"); pub struct Payment { pub token: Vec, @@ -39,58 +38,45 @@ fn world() -> ScenarioWorld { fn setup() -> ScenarioWorld { let mut world = world(); - world.set_state_step( - SetStateStep::new() - .put_account( - OWNER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(GOV_TOKEN_ID_EXPR, INITIAL_GOV_TOKEN_BALANCE), - ) - .new_address(OWNER_ADDRESS_EXPR, 1, USE_MODULE_ADDRESS_EXPR) - .put_account( - FIRST_USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(GOV_TOKEN_ID_EXPR, INITIAL_GOV_TOKEN_BALANCE), - ) - .put_account( - SECOND_USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(GOV_TOKEN_ID_EXPR, INITIAL_GOV_TOKEN_BALANCE), - ) - .put_account( - THIRD_USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(GOV_TOKEN_ID_EXPR, INITIAL_GOV_TOKEN_BALANCE), - ), - ); + world + .account(OWNER_ADDRESS) + .nonce(1) + .esdt_balance(GOV_TOKEN_ID, INITIAL_GOV_TOKEN_BALANCE); + world + .account(FIRST_USER_ADDRESS) + .nonce(1) + .esdt_balance(GOV_TOKEN_ID, INITIAL_GOV_TOKEN_BALANCE); + world + .account(SECOND_USER_ADDRESS) + .nonce(1) + .esdt_balance(GOV_TOKEN_ID, INITIAL_GOV_TOKEN_BALANCE); + world + .account(THIRD_USER_ADDRESS) + .nonce(1) + .esdt_balance(GOV_TOKEN_ID, INITIAL_GOV_TOKEN_BALANCE); // init - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); - let use_module_code = world.code_expression(USE_MODULE_PATH_EXPR); - - world.whitebox_deploy( - &use_module_whitebox, - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(use_module_code), - |sc| { + let new_address = world + .tx() + .from(OWNER_ADDRESS) + .raw_deploy() + .code(USE_MODULE_PATH_EXPR) + .new_address(USE_MODULE_ADDRESS) + .returns(ReturnsNewBech32Address) + .whitebox(use_module::contract_obj, |sc| { sc.init_governance_module( - managed_token_id!(GOV_TOKEN_ID), - managed_biguint!(QUORUM), - managed_biguint!(MIN_BALANCE_PROPOSAL), + TokenIdentifier::from(GOV_TOKEN_ID), + BigUint::from(QUORUM), + BigUint::from(MIN_BALANCE_PROPOSAL), VOTING_DELAY_BLOCKS, VOTING_PERIOD_BLOCKS, LOCKING_PERIOD_BLOCKS, ); - }, - ); + }); - world.set_state_step(SetStateStep::new().block_nonce(10)); + assert_eq!(new_address.to_address(), USE_MODULE_ADDRESS.to_address()); + + world.current_block().block_nonce(10); world } @@ -103,17 +89,14 @@ pub fn propose( endpoint_name: &[u8], args: Vec>, ) -> usize { - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); - let mut proposal_id = 0; - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(proposer) - .esdt_transfer(GOV_TOKEN_ID, 0, gov_token_amount), - |sc| { + world + .tx() + .from(proposer) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, gov_token_amount)) + .whitebox(use_module::contract_obj, |sc| { let mut args_managed = ManagedVec::new(); for arg in args { args_managed.push(managed_buffer!(&arg)); @@ -131,8 +114,7 @@ pub fn propose( ); proposal_id = sc.propose(managed_buffer!(b"change quorum"), actions); - }, - ); + }); proposal_id } @@ -145,16 +127,14 @@ fn test_init() { #[test] fn test_change_gov_config() { let mut world = setup(); - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); let mut current_block_nonce = 10; let proposal_id = propose( &mut world, - &address_expr_to_address(FIRST_USER_ADDRESS_EXPR), + &FIRST_USER_ADDRESS.to_address(), 500, - &address_expr_to_address(USE_MODULE_ADDRESS_EXPR), + &USE_MODULE_ADDRESS.to_address(), b"changeQuorum", vec![1_000u64.to_be_bytes().to_vec()], ); @@ -162,209 +142,188 @@ fn test_change_gov_config() { assert_eq!(proposal_id, 1); // vote too early - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new() - .from(SECOND_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "999") - .no_expect(), - |sc| { + world + .tx() + .from(SECOND_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 999)) + .returns(ExpectError(4u64, "Proposal is not active")) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - |r| { - r.assert_user_error("Proposal is not active"); - }, - ); + }); current_block_nonce += VOTING_DELAY_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(SECOND_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "999"), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(SECOND_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 999)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - ); + }); // try execute before queue - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Can only execute queued proposals")) + .whitebox(use_module::contract_obj, |sc| { sc.execute(proposal_id); - }, - |r| { - r.assert_user_error("Can only execute queued proposals"); - }, - ); + }); // try queue before voting ends - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Can only queue succeeded proposals")) + .whitebox(use_module::contract_obj, |sc| { sc.queue(proposal_id); - }, - |r| { - r.assert_user_error("Can only queue succeeded proposals"); - }, - ); + }); current_block_nonce += VOTING_PERIOD_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); + world.current_block().block_nonce(current_block_nonce); // try queue not enough votes - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Can only queue succeeded proposals")) + .whitebox(use_module::contract_obj, |sc| { sc.queue(proposal_id); - }, - |r| { - r.assert_user_error("Can only queue succeeded proposals"); - }, - ); + }); // user 1 vote again current_block_nonce = 20; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(FIRST_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "200"), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 200)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - ); + }); // owner downvote - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(OWNER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "200"), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 200)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::DownVote); - }, - ); + }); // try queue too many downvotes current_block_nonce = 45; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Can only queue succeeded proposals")) + .whitebox(use_module::contract_obj, |sc| { sc.queue(proposal_id); - }, - |r| { - r.assert_user_error("Can only queue succeeded proposals"); - }, - ); + }); // user 1 vote again current_block_nonce = 20; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new() - .from(FIRST_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "200") - .no_expect(), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 200)) + .returns(ExpectError(4u64, "Already voted for this proposal")) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - |r| { - r.assert_user_error("Already voted for this proposal"); - }, - ); + }); // user 3 vote again - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(THIRD_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "200"), - |sc| { + world + .tx() + .from(THIRD_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 200)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - ); + }); // queue ok current_block_nonce = 45; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { sc.queue(proposal_id); - }, - ); + }); // try execute too early - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { - sc.execute(proposal_id); - }, - |r| { - r.assert_user_error("Proposal is in timelock status. Try again later"); - }, - ); + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError( + 4u64, + "Proposal is in timelock status. Try again later", + )) + .whitebox(use_module::contract_obj, |sc| sc.execute(proposal_id)); // execute ok current_block_nonce += LOCKING_PERIOD_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { - sc.execute(proposal_id); - }, - ); + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| sc.execute(proposal_id)); // after execution, quorum changed from 1_500 to the proposed 1_000 - world.whitebox_query(&use_module_whitebox, |sc| { - assert_eq!(sc.quorum().get(), managed_biguint!(1_000)); - assert!(sc.proposals().item_is_empty(1)); - }); - - world.check_state_step(CheckStateStep::new().put_account( - FIRST_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "300"), - )); - world.check_state_step(CheckStateStep::new().put_account( - SECOND_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "1"), - )); - world.check_state_step(CheckStateStep::new().put_account( - THIRD_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "800"), - )); - world.check_state_step(CheckStateStep::new().put_account( - OWNER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "800"), - )); + world + .query() + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + assert_eq!(sc.quorum().get(), managed_biguint!(1_000)); + assert!(sc.proposals().item_is_empty(1)); + }); + + world + .check_account(FIRST_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(300u64)); + world + .check_account(SECOND_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(1u64)); + world + .check_account(THIRD_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(800u64)); + world + .check_account(OWNER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(800u64)); } #[test] fn test_down_veto_gov_config() { let mut world = setup(); - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); let mut current_block_nonce = 10; let proposal_id = propose( &mut world, - &address_expr_to_address(FIRST_USER_ADDRESS_EXPR), + &FIRST_USER_ADDRESS.to_address(), 500, - &address_expr_to_address(USE_MODULE_ADDRESS_EXPR), + &USE_MODULE_ADDRESS.to_address(), b"changeQuorum", vec![1_000u64.to_be_bytes().to_vec()], ); @@ -372,81 +331,75 @@ fn test_down_veto_gov_config() { assert_eq!(proposal_id, 1); current_block_nonce += VOTING_DELAY_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(FIRST_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "300"), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 300)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - ); + }); current_block_nonce = 20; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(SECOND_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "200"), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(SECOND_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 200)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - ); + }); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(THIRD_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "200"), - |sc| { - sc.vote(proposal_id, VoteType::DownVetoVote); - }, - ); + world + .tx() + .from(THIRD_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 200)) + .whitebox(use_module::contract_obj, |sc| { + sc.vote(proposal_id, VoteType::DownVetoVote) + }); // Vote didn't succeed; current_block_nonce = 45; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world.current_block().block_epoch(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Can only queue succeeded proposals")) + .whitebox(use_module::contract_obj, |sc| { sc.queue(proposal_id); - }, - |r| { - r.assert_user_error("Can only queue succeeded proposals"); - }, - ); + }); + + world + .check_account(FIRST_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(200u64)); - world.check_state_step(CheckStateStep::new().put_account( - FIRST_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "200"), - )); - world.check_state_step(CheckStateStep::new().put_account( - SECOND_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "800"), - )); - world.check_state_step(CheckStateStep::new().put_account( - THIRD_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "800"), - )); + world + .check_account(SECOND_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(800u64)); + + world + .check_account(THIRD_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(800u64)); } #[test] fn test_abstain_vote_gov_config() { let mut world = setup(); - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); let mut current_block_nonce = 10; let proposal_id = propose( &mut world, - &address_expr_to_address(FIRST_USER_ADDRESS_EXPR), + &FIRST_USER_ADDRESS.to_address(), 500, - &address_expr_to_address(USE_MODULE_ADDRESS_EXPR), + &USE_MODULE_ADDRESS.to_address(), b"changeQuorum", vec![1_000u64.to_be_bytes().to_vec()], ); @@ -454,95 +407,93 @@ fn test_abstain_vote_gov_config() { assert_eq!(proposal_id, 1); current_block_nonce += VOTING_DELAY_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(FIRST_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "500"), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 500)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::UpVote); - }, - ); + }); current_block_nonce = 20; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(SECOND_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "400"), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(SECOND_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 400)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::DownVote); - }, - ); + }); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(THIRD_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "600"), - |sc| { + world + .tx() + .from(THIRD_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 600)) + .whitebox(use_module::contract_obj, |sc| { sc.vote(proposal_id, VoteType::AbstainVote); - }, - ); + }); // Vote didn't succeed; current_block_nonce = 45; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { sc.queue(proposal_id); - }, - ); + }); // execute ok current_block_nonce += LOCKING_PERIOD_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(FIRST_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(FIRST_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { sc.execute(proposal_id); - }, - ); + }); // after execution, quorum changed from 1_500 to the proposed 1_000 - world.whitebox_query(&use_module_whitebox, |sc| { - assert_eq!(sc.quorum().get(), managed_biguint!(1_000)); - assert!(sc.proposals().item_is_empty(1)); - }); - - world.check_state_step(CheckStateStep::new().put_account( - FIRST_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "0"), - )); - world.check_state_step(CheckStateStep::new().put_account( - SECOND_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "600"), - )); - world.check_state_step(CheckStateStep::new().put_account( - THIRD_USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(GOV_TOKEN_ID_EXPR, "400"), - )); + world + .query() + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + assert_eq!(sc.quorum().get(), managed_biguint!(1_000)); + assert!(sc.proposals().item_is_empty(1)); + }); + + world + .check_account(FIRST_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::zero()); + world + .check_account(SECOND_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(600u64)); + world + .check_account(THIRD_USER_ADDRESS) + .esdt_balance(GOV_TOKEN_ID, BigUint::from(400u64)); } #[test] fn test_gov_cancel_defeated_proposal() { let mut world = setup(); - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); let mut current_block_nonce = 10; let proposal_id = propose( &mut world, - &address_expr_to_address(FIRST_USER_ADDRESS_EXPR), + &FIRST_USER_ADDRESS.to_address(), 500, - &address_expr_to_address(USE_MODULE_ADDRESS_EXPR), + &USE_MODULE_ADDRESS.to_address(), b"changeQuorum", vec![1_000u64.to_be_bytes().to_vec()], ); @@ -550,42 +501,33 @@ fn test_gov_cancel_defeated_proposal() { assert_eq!(proposal_id, 1); current_block_nonce += VOTING_DELAY_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(SECOND_USER_ADDRESS_EXPR) - .esdt_transfer(GOV_TOKEN_ID, 0, "999"), - |sc| { - sc.vote(proposal_id, VoteType::DownVote); - }, - ); + world.current_block().block_nonce(current_block_nonce); + + world + .tx() + .from(SECOND_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(GOV_TOKEN_ID, 0, 999)) + .whitebox(use_module::contract_obj, |sc| { + sc.vote(proposal_id, VoteType::DownVote) + }); // try cancel too early - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(SECOND_USER_ADDRESS_EXPR).no_expect(), - |sc| { + world + .tx() + .from(SECOND_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Action may not be cancelled")) + .whitebox(use_module::contract_obj, |sc| { sc.cancel(proposal_id); - }, - |r| { - r.assert_user_error("Action may not be cancelled"); - }, - ); + }); current_block_nonce += VOTING_PERIOD_BLOCKS; - world.set_state_step(SetStateStep::new().block_nonce(current_block_nonce)); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(SECOND_USER_ADDRESS_EXPR).no_expect(), - |sc| { - sc.cancel(proposal_id); - }, - ); -} + world.current_block().block_nonce(current_block_nonce); -fn address_expr_to_address(address_expr: &str) -> Address { - AddressValue::from(address_expr).to_address() + world + .tx() + .from(SECOND_USER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| sc.cancel(proposal_id)); } diff --git a/contracts/feature-tests/use-module/tests/staking_module_whitebox_test.rs b/contracts/feature-tests/use-module/tests/staking_module_whitebox_test.rs index 612fa725df..643387b634 100644 --- a/contracts/feature-tests/use-module/tests/staking_module_whitebox_test.rs +++ b/contracts/feature-tests/use-module/tests/staking_module_whitebox_test.rs @@ -1,23 +1,22 @@ use multiversx_sc_modules::staking::StakingModule; use multiversx_sc_scenario::imports::*; -const STAKING_TOKEN_ID_EXPR: &str = "str:STAKE-123456"; -const STAKING_TOKEN_ID: &[u8] = b"STAKE-123456"; +const STAKING_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("STAKE-123456"); const INITIAL_BALANCE: u64 = 2_000_000; const REQUIRED_STAKE_AMOUNT: u64 = 1_000_000; const SLASH_AMOUNT: u64 = 600_000; const QUORUM: usize = 3; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const ALICE_ADDRESS_EXPR: &str = "address:alice"; -const BOB_ADDRESS_EXPR: &str = "address:bob"; -const CAROL_ADDRESS_EXPR: &str = "address:carol"; -const EVE_ADDRESS_EXPR: &str = "address:eve"; -const PAUL_ADDRESS_EXPR: &str = "address:paul"; -const SALLY_ADDRESS_EXPR: &str = "address:sally"; +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const ALICE_ADDRESS: TestAddress = TestAddress::new("alice"); +const BOB_ADDRESS: TestAddress = TestAddress::new("bob"); +const CAROL_ADDRESS: TestAddress = TestAddress::new("carol"); +const EVE_ADDRESS: TestAddress = TestAddress::new("eve"); +const PAUL_ADDRESS: TestAddress = TestAddress::new("paul"); +const SALLY_ADDRESS: TestAddress = TestAddress::new("sally"); -const USE_MODULE_ADDRESS_EXPR: &str = "sc:use-module"; -const USE_MODULE_PATH_EXPR: &str = "mxsc:output/use-module.mxsc.json"; +const USE_MODULE_ADDRESS: TestSCAddress = TestSCAddress::new("use-module"); +const USE_MODULE_PATH_EXPR: MxscPath = MxscPath::new("mxsc:output/use-module.mxsc.json"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); @@ -30,447 +29,339 @@ fn world() -> ScenarioWorld { fn test_staking_module() { let mut world = world(); - world.set_state_step( - SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(OWNER_ADDRESS_EXPR, 1, USE_MODULE_ADDRESS_EXPR) - .put_account( - ALICE_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(STAKING_TOKEN_ID_EXPR, INITIAL_BALANCE), - ) - .put_account( - BOB_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(STAKING_TOKEN_ID_EXPR, INITIAL_BALANCE), - ) - .put_account( - CAROL_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(STAKING_TOKEN_ID_EXPR, INITIAL_BALANCE), - ) - .put_account( - EVE_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(STAKING_TOKEN_ID_EXPR, INITIAL_BALANCE), - ) - .put_account( - PAUL_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(STAKING_TOKEN_ID_EXPR, INITIAL_BALANCE), - ) - .put_account( - SALLY_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(STAKING_TOKEN_ID_EXPR, INITIAL_BALANCE), - ), - ); + world.account(OWNER_ADDRESS).nonce(1); + world + .account(ALICE_ADDRESS) + .nonce(1) + .esdt_balance(STAKING_TOKEN_ID, INITIAL_BALANCE); + world + .account(BOB_ADDRESS) + .nonce(1) + .esdt_balance(STAKING_TOKEN_ID, INITIAL_BALANCE); + world + .account(CAROL_ADDRESS) + .nonce(1) + .esdt_balance(STAKING_TOKEN_ID, INITIAL_BALANCE); + world + .account(EVE_ADDRESS) + .nonce(1) + .esdt_balance(STAKING_TOKEN_ID, INITIAL_BALANCE); + world + .account(PAUL_ADDRESS) + .nonce(1) + .esdt_balance(STAKING_TOKEN_ID, INITIAL_BALANCE); + world + .account(SALLY_ADDRESS) + .nonce(1) + .esdt_balance(STAKING_TOKEN_ID, INITIAL_BALANCE); // init - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); - let use_module_code = world.code_expression(USE_MODULE_PATH_EXPR); - - world.whitebox_deploy( - &use_module_whitebox, - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(use_module_code), - |sc| { + let new_address = world + .tx() + .from(OWNER_ADDRESS) + .raw_deploy() + .code(USE_MODULE_PATH_EXPR) + .new_address(USE_MODULE_ADDRESS) + .returns(ReturnsNewBech32Address) + .whitebox(use_module::contract_obj, |sc| { let mut whitelist = ManagedVec::new(); - whitelist.push(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); - whitelist.push(managed_address!(&address_expr_to_address(BOB_ADDRESS_EXPR))); - whitelist.push(managed_address!(&address_expr_to_address( - CAROL_ADDRESS_EXPR - ))); - whitelist.push(managed_address!(&address_expr_to_address( - PAUL_ADDRESS_EXPR - ))); - whitelist.push(managed_address!(&address_expr_to_address( - SALLY_ADDRESS_EXPR - ))); + whitelist.push(ALICE_ADDRESS.to_managed_address()); + whitelist.push(BOB_ADDRESS.to_managed_address()); + whitelist.push(CAROL_ADDRESS.to_managed_address()); + whitelist.push(PAUL_ADDRESS.to_managed_address()); + whitelist.push(SALLY_ADDRESS.to_managed_address()); sc.init_staking_module( - &EgldOrEsdtTokenIdentifier::esdt(managed_token_id!(STAKING_TOKEN_ID)), - &managed_biguint!(REQUIRED_STAKE_AMOUNT), - &managed_biguint!(SLASH_AMOUNT), + &EgldOrEsdtTokenIdentifier::esdt(STAKING_TOKEN_ID.to_token_identifier()), + &BigUint::from(REQUIRED_STAKE_AMOUNT), + &BigUint::from(SLASH_AMOUNT), QUORUM, &whitelist, ); - }, - ); + }); + + assert_eq!(new_address.to_address(), USE_MODULE_ADDRESS.to_address()); // try stake - not a board member - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new() - .from(EVE_ADDRESS_EXPR) - .esdt_transfer(STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT) - .no_expect(), - |sc| sc.stake(), - |r| { - r.assert_user_error("Only whitelisted members can stake"); - }, - ); + world + .tx() + .from(EVE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT)) + .returns(ExpectError(4u64, "Only whitelisted members can stake")) + .whitebox(use_module::contract_obj, |sc| { + sc.stake(); + }); // stake half and try unstake - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR).esdt_transfer( + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer( STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT / 2, - ), - |sc| sc.stake(), - ); - - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR).no_expect(), - |sc| sc.unstake(managed_biguint!(REQUIRED_STAKE_AMOUNT / 4)), - |r| { - r.assert_user_error("Not enough stake"); - }, - ); + )) + .whitebox(use_module::contract_obj, |sc| { + sc.stake(); + }); + + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Not enough stake")) + .whitebox(use_module::contract_obj, |sc| { + sc.unstake(BigUint::from(REQUIRED_STAKE_AMOUNT / 4)); + }); // bob and carol stake - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(BOB_ADDRESS_EXPR).esdt_transfer( - STAKING_TOKEN_ID, - 0, - REQUIRED_STAKE_AMOUNT, - ), - |sc| sc.stake(), - ); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(CAROL_ADDRESS_EXPR).esdt_transfer( - STAKING_TOKEN_ID, - 0, - REQUIRED_STAKE_AMOUNT, - ), - |sc| sc.stake(), - ); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(PAUL_ADDRESS_EXPR).esdt_transfer( - STAKING_TOKEN_ID, - 0, - REQUIRED_STAKE_AMOUNT, - ), - |sc| sc.stake(), - ); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(SALLY_ADDRESS_EXPR).esdt_transfer( - STAKING_TOKEN_ID, - 0, - REQUIRED_STAKE_AMOUNT, - ), - |sc| sc.stake(), - ); + world + .tx() + .from(BOB_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { + sc.stake(); + }); + + world + .tx() + .from(CAROL_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { + sc.stake(); + }); + + world + .tx() + .from(PAUL_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { + sc.stake(); + }); + + world + .tx() + .from(SALLY_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { + sc.stake(); + }); // try vote slash, not enough stake - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR).no_expect(), - |sc| sc.vote_slash_member(managed_address!(&address_expr_to_address(BOB_ADDRESS_EXPR))), - |r| { - r.assert_user_error("Not enough stake"); - }, - ); + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Not enough stake")) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(BOB_ADDRESS.to_managed_address()); + }); // try vote slash, slashed address not a board member - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR).no_expect(), - |sc| sc.vote_slash_member(managed_address!(&address_expr_to_address(EVE_ADDRESS_EXPR))), - |r| { - r.assert_user_error("Voted user is not a staked board member"); - }, - ); + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Voted user is not a staked board member")) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(EVE_ADDRESS.to_managed_address()); + }); // alice stake over max amount and withdraw surplus - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR).esdt_transfer( - STAKING_TOKEN_ID, - 0, - REQUIRED_STAKE_AMOUNT, - ), - |sc| { + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .payment(TestEsdtTransfer(STAKING_TOKEN_ID, 0, REQUIRED_STAKE_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { sc.stake(); - let alice_staked_amount = sc - .staked_amount(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .get(); - assert_eq!(alice_staked_amount, managed_biguint!(1_500_000)); - }, - ); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR), - |sc| { - sc.unstake(managed_biguint!(500_000)); - - let alice_staked_amount = sc - .staked_amount(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .get(); - assert_eq!(alice_staked_amount, managed_biguint!(1_000_000)); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - ALICE_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(STAKING_TOKEN_ID_EXPR, "1_000_000"), - )); + let alice_staked_amount = sc.staked_amount(&ALICE_ADDRESS.to_managed_address()).get(); + assert_eq!(alice_staked_amount, BigUint::from(1_500_000u64)); + }); + + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.unstake(BigUint::from(500_000u64)); + let alice_staked_amount = sc.staked_amount(&ALICE_ADDRESS.to_managed_address()).get(); + assert_eq!(alice_staked_amount, BigUint::from(1_000_000u64)); + }); + + world + .check_account(ALICE_ADDRESS) + .esdt_balance(STAKING_TOKEN_ID, BigUint::from(1_000_000u64)); // alice vote to slash bob - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR), - |sc| { - sc.vote_slash_member(managed_address!(&address_expr_to_address(BOB_ADDRESS_EXPR))); + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(BOB_ADDRESS.to_managed_address()); assert_eq!( - sc.slashing_proposal_voters(&managed_address!(&address_expr_to_address( - BOB_ADDRESS_EXPR - ))) - .len(), + sc.slashing_proposal_voters(&BOB_ADDRESS.to_managed_address()) + .len(), 1 ); assert!(sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - BOB_ADDRESS_EXPR - ))) - .contains(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - )))); - }, - ); + .slashing_proposal_voters(&BOB_ADDRESS.to_managed_address()) + .contains(&ALICE_ADDRESS.to_managed_address())); + }); // bob vote to slash alice - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(BOB_ADDRESS_EXPR), - |sc| { - sc.vote_slash_member(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); - }, - ); + world + .tx() + .from(BOB_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(ALICE_ADDRESS.to_managed_address()); + }); // try slash before quorum reached - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(BOB_ADDRESS_EXPR).no_expect(), - |sc| { - sc.slash_member(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); - }, - |r| { - r.assert_user_error("Quorum not reached"); - }, - ); + world + .tx() + .from(BOB_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Quorum not reached")) + .whitebox(use_module::contract_obj, |sc| { + sc.slash_member(ALICE_ADDRESS.to_managed_address()); + }); // paul vote to slash alice - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(PAUL_ADDRESS_EXPR), - |sc| { - sc.vote_slash_member(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); - }, - ); + world + .tx() + .from(PAUL_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(ALICE_ADDRESS.to_managed_address()); + }); // sally vote to slash alice - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(SALLY_ADDRESS_EXPR), - |sc| { - sc.vote_slash_member(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); - }, - ); + world + .tx() + .from(SALLY_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(ALICE_ADDRESS.to_managed_address()); + }); // sally cancels vote to slash alice - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(SALLY_ADDRESS_EXPR), - |sc| { - sc.cancel_vote_slash_member(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); - }, - ); + world + .tx() + .from(SALLY_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.cancel_vote_slash_member(ALICE_ADDRESS.to_managed_address()); + }); // carol vote - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(CAROL_ADDRESS_EXPR), - |sc| { - sc.vote_slash_member(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); + world + .tx() + .from(CAROL_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(ALICE_ADDRESS.to_managed_address()); assert_eq!( - sc.slashing_proposal_voters(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .len(), + sc.slashing_proposal_voters(&ALICE_ADDRESS.to_managed_address()) + .len(), 3 ); assert!(sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .contains(&managed_address!(&address_expr_to_address( - BOB_ADDRESS_EXPR - )))); + .slashing_proposal_voters(&ALICE_ADDRESS.to_managed_address()) + .contains(&BOB_ADDRESS.to_managed_address())); assert!(sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .contains(&managed_address!(&address_expr_to_address( - CAROL_ADDRESS_EXPR - )))); + .slashing_proposal_voters(&ALICE_ADDRESS.to_managed_address()) + .contains(&CAROL_ADDRESS.to_managed_address())); assert!(sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .contains(&managed_address!(&address_expr_to_address( - PAUL_ADDRESS_EXPR - )))); + .slashing_proposal_voters(&ALICE_ADDRESS.to_managed_address()) + .contains(&PAUL_ADDRESS.to_managed_address())); assert!(!sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .contains(&managed_address!(&address_expr_to_address( - SALLY_ADDRESS_EXPR - )))); - }, - ); + .slashing_proposal_voters(&ALICE_ADDRESS.to_managed_address()) + .contains(&SALLY_ADDRESS.to_managed_address())); + }); // slash alice - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(BOB_ADDRESS_EXPR), - |sc| { - sc.slash_member(managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); + world + .tx() + .from(BOB_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.slash_member(ALICE_ADDRESS.to_managed_address()); assert_eq!( - sc.staked_amount(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) - .get(), - managed_biguint!(REQUIRED_STAKE_AMOUNT - SLASH_AMOUNT) - ); - assert_eq!( - sc.total_slashed_amount().get(), - managed_biguint!(SLASH_AMOUNT) + sc.staked_amount(&ALICE_ADDRESS.to_managed_address()).get(), + BigUint::from(REQUIRED_STAKE_AMOUNT - SLASH_AMOUNT) ); + assert_eq!(sc.total_slashed_amount().get(), BigUint::from(SLASH_AMOUNT)); assert!(sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))) + .slashing_proposal_voters(&ALICE_ADDRESS.to_managed_address()) .is_empty()); - }, - ); + }); // alice try vote after slash - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR).no_expect(), - |sc| { - sc.vote_slash_member(managed_address!(&address_expr_to_address(BOB_ADDRESS_EXPR))); - }, - |r| { - r.assert_user_error("Not enough stake"); - }, - ); + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Not enough stake")) + .whitebox(use_module::contract_obj, |sc| { + sc.vote_slash_member(BOB_ADDRESS.to_managed_address()); + }); // alice try unstake the remaining tokens - world.whitebox_call_check( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR).no_expect(), - |sc| { - sc.unstake(managed_biguint!(400_000)); - }, - |r| { - r.assert_user_error("Not enough stake"); - }, - ); + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .returns(ExpectError(4u64, "Not enough stake")) + .whitebox(use_module::contract_obj, |sc| { + sc.unstake(BigUint::from(400_000u64)); + }); // alice remove from board members - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { + world + .tx() + .from(OWNER_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { // check alice's votes before slash assert!(sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - BOB_ADDRESS_EXPR - ))) - .contains(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - )))); + .slashing_proposal_voters(&BOB_ADDRESS.to_managed_address()) + .contains(&ALICE_ADDRESS.to_managed_address())); - sc.remove_board_member(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - ))); + sc.remove_board_member(&ALICE_ADDRESS.to_managed_address()); assert_eq!(sc.user_whitelist().len(), 4); assert!(!sc .user_whitelist() - .contains(&managed_address!(&address_expr_to_address( - ALICE_ADDRESS_EXPR - )))); + .contains(&ALICE_ADDRESS.to_managed_address())); // alice's vote gets removed assert!(sc - .slashing_proposal_voters(&managed_address!(&address_expr_to_address( - BOB_ADDRESS_EXPR - ))) + .slashing_proposal_voters(&BOB_ADDRESS.to_managed_address()) .is_empty()); - }, - ); + }); // alice unstake ok - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(ALICE_ADDRESS_EXPR), - |sc| { - sc.unstake(managed_biguint!(400_000)); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - ALICE_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(STAKING_TOKEN_ID_EXPR, INITIAL_BALANCE - SLASH_AMOUNT), - )); -} - -fn address_expr_to_address(address_expr: &str) -> Address { - AddressValue::from(address_expr).to_address() + world + .tx() + .from(ALICE_ADDRESS) + .to(USE_MODULE_ADDRESS) + .whitebox(use_module::contract_obj, |sc| { + sc.unstake(BigUint::from(400_000u64)); + }); + + world + .check_account(ALICE_ADDRESS) + .esdt_balance(STAKING_TOKEN_ID, INITIAL_BALANCE - SLASH_AMOUNT); } diff --git a/contracts/feature-tests/use-module/tests/token_merge_module_whitebox_test.rs b/contracts/feature-tests/use-module/tests/token_merge_module_whitebox_test.rs index 803992d49b..4b40f656c9 100644 --- a/contracts/feature-tests/use-module/tests/token_merge_module_whitebox_test.rs +++ b/contracts/feature-tests/use-module/tests/token_merge_module_whitebox_test.rs @@ -5,18 +5,15 @@ use multiversx_sc_modules::token_merge::{ }; use use_module::token_merge_mod_impl::{CustomAttributes, TokenMergeModImpl}; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const USER_ADDRESS_EXPR: &str = "address:user"; +const OWNER_ADDRESS_EXPR: TestAddress = TestAddress::new("owner"); +const USER_ADDRESS_EXPR: TestAddress = TestAddress::new("user"); -const USE_MODULE_ADDRESS_EXPR: &str = "sc:use-module"; -const USE_MODULE_PATH_EXPR: &str = "mxsc:output/use-module.mxsc.json"; +const USE_MODULE_ADDRESS_EXPR: TestSCAddress = TestSCAddress::new("use-module"); +const USE_MODULE_PATH_EXPR: MxscPath = MxscPath::new("mxsc:output/use-module.mxsc.json"); -const MERGED_TOKEN_ID_EXPR: &str = "str:MERGED-123456"; -const MERGED_TOKEN_ID: &[u8] = b"MERGED-123456"; -const NFT_TOKEN_ID_EXPR: &str = "str:NFT-123456"; -const NFT_TOKEN_ID: &[u8] = b"NFT-123456"; -const FUNGIBLE_TOKEN_ID_EXPR: &str = "str:FUN-123456"; -const FUNGIBLE_TOKEN_ID: &[u8] = b"FUN-123456"; +const MERGED_TOKEN_ID_EXPR: TestTokenIdentifier = TestTokenIdentifier::new("MERGED-123456"); +const NFT_TOKEN_ID_EXPR: TestTokenIdentifier = TestTokenIdentifier::new("NFT-123456"); +const FUNGIBLE_TOKEN_ID_EXPR: TestTokenIdentifier = TestTokenIdentifier::new("FUN-123456"); const NFT_AMOUNT: u64 = 1; const FUNGIBLE_AMOUNT: u64 = 100; @@ -41,561 +38,465 @@ fn world() -> ScenarioWorld { fn test_token_merge() { let mut world = world(); - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); - let use_module_code = world.code_expression(USE_MODULE_PATH_EXPR); - let roles = vec![ "ESDTRoleNFTCreate".to_string(), "ESDTRoleNFTBurn".to_string(), ]; - - world.set_state_step( - SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .put_account( - USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT) - .esdt_nft_all_properties( - NFT_TOKEN_ID_EXPR, - FIRST_NFT_NONCE, - NFT_AMOUNT, - Some(FIRST_ATTRIBUTES), - FIRST_ROYALTIES, - None::, - None, - Vec::from(FIRST_URIS), - ) - .esdt_nft_all_properties( - NFT_TOKEN_ID_EXPR, - SECOND_NFT_NONCE, - NFT_AMOUNT, - Some(SECOND_ATTRIBUTES), - SECOND_ROYALTIES, - None::, - None, - Vec::from(SECOND_URIS), - ), - ) - .put_account( - USE_MODULE_ADDRESS_EXPR, - Account::new() - .nonce(1) - .code(use_module_code) - .owner(OWNER_ADDRESS_EXPR) - .esdt_roles(MERGED_TOKEN_ID_EXPR, roles), - ), - ); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { + let first_uris = FIRST_URIS + .iter() + .map(|first_uri| managed_buffer!(first_uri)) + .collect(); + let second_uris = SECOND_URIS + .iter() + .map(|second_uri| managed_buffer!(second_uri)) + .collect(); + + world.account(OWNER_ADDRESS_EXPR).nonce(1); + world + .account(USER_ADDRESS_EXPR) + .nonce(1) + .esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT) + .esdt_nft_all_properties( + NFT_TOKEN_ID_EXPR, + FIRST_NFT_NONCE, + NFT_AMOUNT, + managed_buffer!(FIRST_ATTRIBUTES), + FIRST_ROYALTIES, + None::
, + (), + first_uris, + ) + .esdt_nft_all_properties( + NFT_TOKEN_ID_EXPR, + SECOND_NFT_NONCE, + NFT_AMOUNT, + managed_buffer!(SECOND_ATTRIBUTES), + SECOND_ROYALTIES, + None::
, + (), + second_uris, + ); + + world + .account(USE_MODULE_ADDRESS_EXPR) + .nonce(1) + .code(USE_MODULE_PATH_EXPR) + .owner(OWNER_ADDRESS_EXPR) + .esdt_roles(MERGED_TOKEN_ID_EXPR, roles); + + world + .tx() + .from(OWNER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .whitebox(use_module::contract_obj, |sc| { sc.merged_token() - .set_token_id(managed_token_id!(MERGED_TOKEN_ID)); + .set_token_id(MERGED_TOKEN_ID_EXPR.to_token_identifier()); let _ = sc .mergeable_tokens_whitelist() - .insert(managed_token_id!(NFT_TOKEN_ID)); + .insert(NFT_TOKEN_ID_EXPR.to_token_identifier()); let _ = sc .mergeable_tokens_whitelist() - .insert(managed_token_id!(FUNGIBLE_TOKEN_ID)); - }, - ); + .insert(FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier()); + }); // merge two NFTs let nft_transfers = vec![ - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: FIRST_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: SECOND_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT), ]; - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .multi_esdt_transfer(nft_transfers), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .multi_esdt(nft_transfers) + .whitebox(use_module::contract_obj, |sc| { let merged_token = sc.merge_tokens_endpoint(); assert_eq!( merged_token.token_identifier, - managed_token_id!(MERGED_TOKEN_ID) + MERGED_TOKEN_ID_EXPR.to_token_identifier() ); assert_eq!(merged_token.token_nonce, 1); assert_eq!(merged_token.amount, managed_biguint!(NFT_AMOUNT)); let merged_token_data = sc.blockchain().get_esdt_token_data( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(MERGED_TOKEN_ID), + &USER_ADDRESS_EXPR.to_managed_address(), + &MERGED_TOKEN_ID_EXPR.to_token_identifier(), 1, ); - let mut expected_uri = ArrayVec::new(); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - FIRST_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - SECOND_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); + let expected_uri = ArrayVec::from([ + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + FIRST_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + SECOND_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + ]); let actual_uri = MergedTokenInstances::decode_from_first_uri(&merged_token_data.uris); - assert_eq!(expected_uri, actual_uri.into_instances()); + assert_eq!(expected_uri, *actual_uri.into_instances()); assert_eq!( merged_token_data.royalties, managed_biguint!(SECOND_ROYALTIES) ); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - MERGED_TOKEN_ID_EXPR, - 1, - NFT_AMOUNT, - Option::<&Empty>::None, - ), - )); + }); + + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes(MERGED_TOKEN_ID_EXPR, 1, NFT_AMOUNT, &Empty); - world.check_state_step(CheckStateStep::new().put_account( - USE_MODULE_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + world + .check_account(USE_MODULE_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT, - Some(FIRST_ATTRIBUTES), - ), - )); + FIRST_ATTRIBUTES, + ); - world.check_state_step(CheckStateStep::new().put_account( - USE_MODULE_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + world + .check_account(USE_MODULE_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT, - Some(SECOND_ATTRIBUTES), - ), - )); + SECOND_ATTRIBUTES, + ); // split nfts - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(USER_ADDRESS_EXPR).esdt_transfer( - MERGED_TOKEN_ID_EXPR, - 1, - NFT_AMOUNT, - ), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .payment(TestEsdtTransfer(MERGED_TOKEN_ID_EXPR, 1, NFT_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { let output_tokens = sc.split_tokens_endpoint(); - let mut expected_output_tokens = ManagedVec::new(); - expected_output_tokens.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - FIRST_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_output_tokens.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - SECOND_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - assert_eq!(output_tokens, expected_output_tokens); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + let expected_output_tokens = vec![ + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT), + ]; + assert_eq!(output_tokens, expected_output_tokens.into()); + }); + + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT, - Some(FIRST_ATTRIBUTES), - ), - )); + FIRST_ATTRIBUTES, + ); - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT, - Some(SECOND_ATTRIBUTES), - ), - )); + SECOND_ATTRIBUTES, + ); // merge the NFT with fungible let esdt_transfers = vec![ - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: FIRST_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, - TxESDT { - esdt_token_identifier: FUNGIBLE_TOKEN_ID.into(), - nonce: 0u64.into(), - esdt_value: FUNGIBLE_AMOUNT.into(), - }, + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(FUNGIBLE_TOKEN_ID_EXPR, 0u64, FUNGIBLE_AMOUNT), ]; - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .multi_esdt_transfer(esdt_transfers), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .multi_esdt(esdt_transfers) + .whitebox(use_module::contract_obj, |sc| { let merged_token = sc.merge_tokens_endpoint(); assert_eq!( merged_token.token_identifier, - managed_token_id!(MERGED_TOKEN_ID) + MERGED_TOKEN_ID_EXPR.to_token_identifier() ); assert_eq!(merged_token.token_nonce, 2); assert_eq!(merged_token.amount, managed_biguint!(NFT_AMOUNT)); let merged_token_data = sc.blockchain().get_esdt_token_data( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(MERGED_TOKEN_ID), + &USER_ADDRESS_EXPR.to_managed_address(), + &MERGED_TOKEN_ID_EXPR.to_token_identifier(), 2, ); - let mut expected_uri = ArrayVec::new(); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - FIRST_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(FUNGIBLE_TOKEN_ID), - 0, - managed_biguint!(FUNGIBLE_AMOUNT), - )); + let expected_uri = ArrayVec::from([ + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + FIRST_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + EsdtTokenPayment::new( + FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier(), + 0, + managed_biguint!(FUNGIBLE_AMOUNT), + ), + ]); let actual_uri = MergedTokenInstances::decode_from_first_uri(&merged_token_data.uris); - assert_eq!(expected_uri, actual_uri.into_instances()); + assert_eq!(expected_uri, *actual_uri.into_instances()); assert_eq!( merged_token_data.royalties, managed_biguint!(FIRST_ROYALTIES) ); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - MERGED_TOKEN_ID_EXPR, - 2, - NFT_AMOUNT, - Option::<&Empty>::None, - ), - )); + }); + + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes(MERGED_TOKEN_ID_EXPR, 2, NFT_AMOUNT, &Empty); // merge NFT with an already merged token let combined_transfers = vec![ - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: SECOND_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, - TxESDT { - esdt_token_identifier: MERGED_TOKEN_ID.into(), - nonce: 2u64.into(), - esdt_value: NFT_AMOUNT.into(), - }, + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(MERGED_TOKEN_ID_EXPR, 2u64, NFT_AMOUNT), ]; - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .multi_esdt_transfer(combined_transfers), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .multi_esdt(combined_transfers) + .whitebox(use_module::contract_obj, |sc| { let merged_token = sc.merge_tokens_endpoint(); assert_eq!( merged_token.token_identifier, - managed_token_id!(MERGED_TOKEN_ID) + MERGED_TOKEN_ID_EXPR.to_token_identifier() ); assert_eq!(merged_token.token_nonce, 3); assert_eq!(merged_token.amount, managed_biguint!(NFT_AMOUNT)); let merged_token_data = sc.blockchain().get_esdt_token_data( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(MERGED_TOKEN_ID), + &USER_ADDRESS_EXPR.to_managed_address(), + &MERGED_TOKEN_ID_EXPR.into(), 3, ); - let mut expected_uri = ArrayVec::new(); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - FIRST_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(FUNGIBLE_TOKEN_ID), - 0, - managed_biguint!(FUNGIBLE_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - SECOND_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); + let expected_uri = ArrayVec::from([ + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + FIRST_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + EsdtTokenPayment::new( + FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier(), + 0, + managed_biguint!(FUNGIBLE_AMOUNT), + ), + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + SECOND_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + ]); let actual_uri = MergedTokenInstances::decode_from_first_uri(&merged_token_data.uris); - assert_eq!(expected_uri, actual_uri.into_instances()); + assert_eq!(expected_uri, *actual_uri.into_instances()); assert_eq!( merged_token_data.royalties, managed_biguint!(SECOND_ROYALTIES) ); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - MERGED_TOKEN_ID_EXPR, - 3, - NFT_AMOUNT, - Option::<&Empty>::None, - ), - )); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(USER_ADDRESS_EXPR).esdt_transfer( - MERGED_TOKEN_ID_EXPR, - 3, - NFT_AMOUNT, - ), - |sc| { + }); + + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes(MERGED_TOKEN_ID_EXPR, 3, NFT_AMOUNT, &Empty); + + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .payment(TestEsdtTransfer(MERGED_TOKEN_ID_EXPR, 3, NFT_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { let output_tokens = sc.split_tokens_endpoint(); - let mut expected_output_tokens = ManagedVec::new(); - expected_output_tokens.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - FIRST_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_output_tokens.push(EsdtTokenPayment::new( - managed_token_id!(FUNGIBLE_TOKEN_ID), - 0, - managed_biguint!(FUNGIBLE_AMOUNT), - )); - expected_output_tokens.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - SECOND_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - - assert_eq!(output_tokens, expected_output_tokens); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + let expected_output_tokens = vec![ + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(FUNGIBLE_TOKEN_ID_EXPR, 0, FUNGIBLE_AMOUNT), + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT), + ]; + + assert_eq!(output_tokens, expected_output_tokens.into()); + }); + + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT, - Some(FIRST_ATTRIBUTES), - ), - )); + FIRST_ATTRIBUTES, + ); - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT, - Some(SECOND_ATTRIBUTES), - ), - )); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT), - )); + SECOND_ATTRIBUTES, + ); + + world + .check_account(USER_ADDRESS_EXPR) + .esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT); } #[test] fn test_partial_split() { let mut world = world(); - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); - let use_module_code = world.code_expression(USE_MODULE_PATH_EXPR); - let roles = vec![ "ESDTRoleNFTCreate".to_string(), "ESDTRoleNFTBurn".to_string(), ]; - - world.set_state_step( - SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .put_account( - USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT) - .esdt_nft_all_properties( - NFT_TOKEN_ID_EXPR, - FIRST_NFT_NONCE, - NFT_AMOUNT, - Some(FIRST_ATTRIBUTES), - FIRST_ROYALTIES, - None::, - None, - Vec::from(FIRST_URIS), - ) - .esdt_nft_all_properties( - NFT_TOKEN_ID_EXPR, - SECOND_NFT_NONCE, - NFT_AMOUNT, - Some(SECOND_ATTRIBUTES), - SECOND_ROYALTIES, - None::, - None, - Vec::from(SECOND_URIS), - ), - ) - .put_account( - USE_MODULE_ADDRESS_EXPR, - Account::new() - .nonce(1) - .code(use_module_code) - .owner(OWNER_ADDRESS_EXPR) - .esdt_roles(MERGED_TOKEN_ID_EXPR, roles), - ), - ); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { + let first_uris = FIRST_URIS + .iter() + .map(|first_uri| managed_buffer!(first_uri)) + .collect(); + let second_uris = SECOND_URIS + .iter() + .map(|second_uri| managed_buffer!(second_uri)) + .collect(); + + world.account(OWNER_ADDRESS_EXPR).nonce(1); + world + .account(USER_ADDRESS_EXPR) + .nonce(1) + .esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT) + .esdt_nft_all_properties( + NFT_TOKEN_ID_EXPR, + FIRST_NFT_NONCE, + NFT_AMOUNT, + managed_buffer!(FIRST_ATTRIBUTES), + FIRST_ROYALTIES, + None::, + (), + first_uris, + ) + .esdt_nft_all_properties( + NFT_TOKEN_ID_EXPR, + SECOND_NFT_NONCE, + NFT_AMOUNT, + managed_buffer!(SECOND_ATTRIBUTES), + SECOND_ROYALTIES, + None::, + (), + second_uris, + ); + + world + .account(USE_MODULE_ADDRESS_EXPR) + .nonce(1) + .code(USE_MODULE_PATH_EXPR) + .owner(OWNER_ADDRESS_EXPR) + .esdt_roles(MERGED_TOKEN_ID_EXPR, roles); + + world + .tx() + .from(OWNER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .whitebox(use_module::contract_obj, |sc| { sc.merged_token() - .set_token_id(managed_token_id!(MERGED_TOKEN_ID)); - let _ = sc - .mergeable_tokens_whitelist() - .insert(managed_token_id!(NFT_TOKEN_ID)); - let _ = sc - .mergeable_tokens_whitelist() - .insert(managed_token_id!(FUNGIBLE_TOKEN_ID)); - }, - ); + .set_token_id(MERGED_TOKEN_ID_EXPR.to_token_identifier()); + sc.mergeable_tokens_whitelist() + .insert(NFT_TOKEN_ID_EXPR.to_token_identifier()); + sc.mergeable_tokens_whitelist() + .insert(FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier()); + }); // merge 2 NFTs and a fungible token let esdt_transfers = vec![ - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: FIRST_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: SECOND_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, - TxESDT { - esdt_token_identifier: FUNGIBLE_TOKEN_ID.into(), - nonce: 0u64.into(), - esdt_value: FUNGIBLE_AMOUNT.into(), - }, + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(FUNGIBLE_TOKEN_ID_EXPR, 0u64, FUNGIBLE_AMOUNT), ]; - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .multi_esdt_transfer(esdt_transfers), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .multi_esdt(esdt_transfers) + .whitebox(use_module::contract_obj, |sc| { let merged_token = sc.merge_tokens_endpoint(); assert_eq!( merged_token.token_identifier, - managed_token_id!(MERGED_TOKEN_ID) + MERGED_TOKEN_ID_EXPR.to_token_identifier() ); assert_eq!(merged_token.token_nonce, 1); assert_eq!(merged_token.amount, managed_biguint!(NFT_AMOUNT)); let merged_token_data = sc.blockchain().get_esdt_token_data( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(MERGED_TOKEN_ID), + &USER_ADDRESS_EXPR.to_managed_address(), + &MERGED_TOKEN_ID_EXPR.to_token_identifier(), 1, ); - let mut expected_uri = ArrayVec::new(); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - FIRST_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - SECOND_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(FUNGIBLE_TOKEN_ID), - 0, - managed_biguint!(FUNGIBLE_AMOUNT), - )); + let expected_uri = ArrayVec::from([ + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + FIRST_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + SECOND_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + EsdtTokenPayment::new( + FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier(), + 0, + managed_biguint!(FUNGIBLE_AMOUNT), + ), + ]); let actual_uri = MergedTokenInstances::decode_from_first_uri(&merged_token_data.uris); - assert_eq!(expected_uri, actual_uri.into_instances()); - }, - ); + assert_eq!(expected_uri, *actual_uri.into_instances()); + }); // split part of the fungible token - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(USER_ADDRESS_EXPR).esdt_transfer( - MERGED_TOKEN_ID_EXPR, - 1, - NFT_AMOUNT, - ), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .payment(TestEsdtTransfer(MERGED_TOKEN_ID_EXPR, 1, NFT_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { let mut tokens_to_remove = ManagedVec::new(); tokens_to_remove.push(EsdtTokenPayment::new( - managed_token_id!(FUNGIBLE_TOKEN_ID), + FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier(), 0, managed_biguint!(40), )); - let output_payments = sc.split_token_partial_endpoint(tokens_to_remove); + let output_payments = sc.split_token_partial_endpoint(tokens_to_remove); let mut expected_output_payments = ManagedVec::new(); expected_output_payments.push(EsdtTokenPayment::new( - managed_token_id!(FUNGIBLE_TOKEN_ID), + FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier(), 0, managed_biguint!(40), )); expected_output_payments.push(EsdtTokenPayment::new( - managed_token_id!(MERGED_TOKEN_ID), + MERGED_TOKEN_ID_EXPR.to_token_identifier(), 2, managed_biguint!(NFT_AMOUNT), )); assert_eq!(output_payments, expected_output_payments); - }, - ); + }); // fully remove instance - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(USER_ADDRESS_EXPR).esdt_transfer( - MERGED_TOKEN_ID_EXPR, - 2, - NFT_AMOUNT, - ), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .payment(TestEsdtTransfer(MERGED_TOKEN_ID_EXPR, 2, NFT_AMOUNT)) + .whitebox(use_module::contract_obj, |sc| { let mut tokens_to_remove = ManagedVec::new(); tokens_to_remove.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), + NFT_TOKEN_ID_EXPR.to_token_identifier(), FIRST_NFT_NONCE, managed_biguint!(NFT_AMOUNT), )); @@ -603,12 +504,12 @@ fn test_partial_split() { let mut expected_output_payments = ManagedVec::new(); expected_output_payments.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), + NFT_TOKEN_ID_EXPR.to_token_identifier(), FIRST_NFT_NONCE, managed_biguint!(NFT_AMOUNT), )); expected_output_payments.push(EsdtTokenPayment::new( - managed_token_id!(MERGED_TOKEN_ID), + MERGED_TOKEN_ID_EXPR.to_token_identifier(), 3, managed_biguint!(NFT_AMOUNT), )); @@ -616,112 +517,101 @@ fn test_partial_split() { // check newest token attributes let merged_token_data = sc.blockchain().get_esdt_token_data( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(MERGED_TOKEN_ID), + &USER_ADDRESS_EXPR.to_managed_address(), + &MERGED_TOKEN_ID_EXPR.to_token_identifier(), 3, ); - let mut expected_uri = ArrayVec::new(); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - SECOND_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(FUNGIBLE_TOKEN_ID), - 0, - managed_biguint!(FUNGIBLE_AMOUNT - 40), - )); + let expected_uri = ArrayVec::from([ + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + SECOND_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + EsdtTokenPayment::new( + FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier(), + 0, + managed_biguint!(FUNGIBLE_AMOUNT - 40), + ), + ]); let actual_uri = MergedTokenInstances::decode_from_first_uri(&merged_token_data.uris); - assert_eq!(expected_uri, actual_uri.into_instances()); + assert_eq!(expected_uri, *actual_uri.into_instances()); assert_eq!( merged_token_data.royalties, managed_biguint!(SECOND_ROYALTIES) ); - }, - ); + }); } #[test] fn test_custom_attributes() { let mut world = world(); - let use_module_whitebox = - WhiteboxContract::new(USE_MODULE_ADDRESS_EXPR, use_module::contract_obj); - let use_module_code = world.code_expression(USE_MODULE_PATH_EXPR); - let roles = vec![ "ESDTRoleNFTCreate".to_string(), "ESDTRoleNFTBurn".to_string(), ]; - world.set_state_step( - SetStateStep::new() - .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .put_account( - USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT) - .esdt_nft_all_properties( - NFT_TOKEN_ID_EXPR, - FIRST_NFT_NONCE, - NFT_AMOUNT, - Some(FIRST_ATTRIBUTES), - FIRST_ROYALTIES, - None::, - None, - Vec::from(FIRST_URIS), - ) - .esdt_nft_all_properties( - NFT_TOKEN_ID_EXPR, - SECOND_NFT_NONCE, - NFT_AMOUNT, - Some(SECOND_ATTRIBUTES), - SECOND_ROYALTIES, - None::, - None, - Vec::from(SECOND_URIS), - ), - ) - .put_account( - USE_MODULE_ADDRESS_EXPR, - Account::new() - .nonce(1) - .code(use_module_code) - .owner(OWNER_ADDRESS_EXPR) - .esdt_roles(MERGED_TOKEN_ID_EXPR, roles), - ), - ); - - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { + let first_uris = FIRST_URIS + .iter() + .map(|first_uri| managed_buffer!(first_uri)) + .collect(); + let second_uris = SECOND_URIS + .iter() + .map(|second_uri| managed_buffer!(second_uri)) + .collect(); + world.account(OWNER_ADDRESS_EXPR).nonce(1); + world + .account(USER_ADDRESS_EXPR) + .nonce(1) + .esdt_balance(FUNGIBLE_TOKEN_ID_EXPR, FUNGIBLE_AMOUNT) + .esdt_nft_all_properties( + NFT_TOKEN_ID_EXPR, + FIRST_NFT_NONCE, + NFT_AMOUNT, + managed_buffer!(FIRST_ATTRIBUTES), + FIRST_ROYALTIES, + None::, + (), + first_uris, + ) + .esdt_nft_all_properties( + NFT_TOKEN_ID_EXPR, + SECOND_NFT_NONCE, + NFT_AMOUNT, + managed_buffer!(SECOND_ATTRIBUTES), + SECOND_ROYALTIES, + None::, + (), + second_uris, + ); + world + .account(USE_MODULE_ADDRESS_EXPR) + .nonce(1) + .code(USE_MODULE_PATH_EXPR) + .owner(OWNER_ADDRESS_EXPR) + .esdt_roles(MERGED_TOKEN_ID_EXPR, roles); + + world + .tx() + .from(OWNER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .whitebox(use_module::contract_obj, |sc| { sc.merged_token() - .set_token_id(managed_token_id!(MERGED_TOKEN_ID)); + .set_token_id(MERGED_TOKEN_ID_EXPR.to_token_identifier()); let _ = sc .mergeable_tokens_whitelist() - .insert(managed_token_id!(NFT_TOKEN_ID)); + .insert(NFT_TOKEN_ID_EXPR.to_token_identifier()); let _ = sc .mergeable_tokens_whitelist() - .insert(managed_token_id!(FUNGIBLE_TOKEN_ID)); - }, - ); + .insert(FUNGIBLE_TOKEN_ID_EXPR.to_token_identifier()); + }); // merge two NFTs let nft_transfers = vec![ - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: FIRST_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, - TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: SECOND_NFT_NONCE.into(), - esdt_value: NFT_AMOUNT.into(), - }, + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT), + TestEsdtTransfer(NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT), ]; let expected_attributes = CustomAttributes { @@ -729,39 +619,39 @@ fn test_custom_attributes() { second: 10u64, }; - world.whitebox_call( - &use_module_whitebox, - ScCallStep::new() - .from(USER_ADDRESS_EXPR) - .multi_esdt_transfer(nft_transfers), - |sc| { + world + .tx() + .from(USER_ADDRESS_EXPR) + .to(USE_MODULE_ADDRESS_EXPR) + .multi_esdt(nft_transfers) + .whitebox(use_module::contract_obj, |sc| { let merged_token = sc.merge_tokens_custom_attributes_endpoint(); assert_eq!( merged_token.token_identifier, - managed_token_id!(MERGED_TOKEN_ID) + MERGED_TOKEN_ID_EXPR.to_token_identifier() ); assert_eq!(merged_token.token_nonce, 1); assert_eq!(merged_token.amount, managed_biguint!(NFT_AMOUNT)); let merged_token_data = sc.blockchain().get_esdt_token_data( - &managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), - &managed_token_id!(MERGED_TOKEN_ID), + &USER_ADDRESS_EXPR.to_managed_address(), + &MERGED_TOKEN_ID_EXPR.to_token_identifier(), 1, ); - let mut expected_uri = ArrayVec::new(); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - FIRST_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - expected_uri.push(EsdtTokenPayment::new( - managed_token_id!(NFT_TOKEN_ID), - SECOND_NFT_NONCE, - managed_biguint!(NFT_AMOUNT), - )); - + let expected_uri = ArrayVec::from([ + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + FIRST_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + EsdtTokenPayment::new( + NFT_TOKEN_ID_EXPR.to_token_identifier(), + SECOND_NFT_NONCE, + managed_biguint!(NFT_AMOUNT), + ), + ]); let actual_uri = MergedTokenInstances::decode_from_first_uri(&merged_token_data.uris); - assert_eq!(expected_uri, actual_uri.into_instances()); + assert_eq!(expected_uri, *actual_uri.into_instances()); let actual_attributes: CustomAttributes = merged_token_data.decode_attributes(); assert_eq!(expected_attributes, actual_attributes); @@ -770,40 +660,26 @@ fn test_custom_attributes() { merged_token_data.royalties, managed_biguint!(SECOND_ROYALTIES) ); - }, - ); - - world.check_state_step(CheckStateStep::new().put_account( - USER_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( - MERGED_TOKEN_ID_EXPR, - 1, - NFT_AMOUNT, - Some(top_encode_to_vec_u8_or_panic(&expected_attributes)), - ), - )); + }); + + world + .check_account(USER_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes(MERGED_TOKEN_ID_EXPR, 1, NFT_AMOUNT, expected_attributes); - world.check_state_step(CheckStateStep::new().put_account( - USE_MODULE_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + world + .check_account(USE_MODULE_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, FIRST_NFT_NONCE, NFT_AMOUNT, - Some(FIRST_ATTRIBUTES), - ), - )); - - world.check_state_step(CheckStateStep::new().put_account( - USE_MODULE_ADDRESS_EXPR, - CheckAccount::new().esdt_nft_balance_and_attributes( + FIRST_ATTRIBUTES, + ); + world + .check_account(USE_MODULE_ADDRESS_EXPR) + .esdt_nft_balance_and_attributes( NFT_TOKEN_ID_EXPR, SECOND_NFT_NONCE, NFT_AMOUNT, - Some(SECOND_ATTRIBUTES), - ), - )); -} - -fn address_expr_to_address(address_expr: &str) -> Address { - AddressValue::from(address_expr).to_address() + SECOND_ATTRIBUTES, + ); } diff --git a/data/codec-derive/Cargo.toml b/data/codec-derive/Cargo.toml index 934b041232..707de3c33a 100644 --- a/data/codec-derive/Cargo.toml +++ b/data/codec-derive/Cargo.toml @@ -22,6 +22,6 @@ default = ["syn/full", "syn/parsing", "syn/extra-traits"] [dependencies] proc-macro2 = "=1.0.86" -quote = "=1.0.36" -syn = "=2.0.72" +quote = "=1.0.37" +syn = "=2.0.76" hex = "=0.4.3" diff --git a/data/codec/Cargo.toml b/data/codec/Cargo.toml index b09697b84c..be2e7f39f4 100644 --- a/data/codec/Cargo.toml +++ b/data/codec/Cargo.toml @@ -22,7 +22,7 @@ version = "=0.20.1" optional = true [dependencies] -arrayvec = { version = "=0.7.4", default-features = false } +arrayvec = { version = "=0.7.6", default-features = false } num-bigint = { version = "0.4", optional = true } # can only be used in std contexts unwrap-infallible = "0.1.5" diff --git a/framework/base/src/api/crypto_api.rs b/framework/base/src/api/crypto_api.rs index 3c5c374a87..f6eaf80fe4 100644 --- a/framework/base/src/api/crypto_api.rs +++ b/framework/base/src/api/crypto_api.rs @@ -44,7 +44,7 @@ pub trait CryptoApiImpl: ManagedTypeApiImpl { key: Self::ManagedBufferHandle, message: Self::ManagedBufferHandle, signature: Self::ManagedBufferHandle, - ) -> bool; + ); fn verify_ed25519_managed( &self, @@ -76,4 +76,25 @@ pub trait CryptoApiImpl: ManagedTypeApiImpl { s: Self::ManagedBufferHandle, dest: Self::ManagedBufferHandle, ); + + fn verify_secp256r1_managed( + &self, + key: Self::ManagedBufferHandle, + message: Self::ManagedBufferHandle, + signature: Self::ManagedBufferHandle, + ); + + fn verify_bls_signature_share_managed( + &self, + key: Self::ManagedBufferHandle, + message: Self::ManagedBufferHandle, + signature: Self::ManagedBufferHandle, + ); + + fn verify_bls_aggregated_signature_managed( + &self, + key: Self::ManagedBufferHandle, + message: Self::ManagedBufferHandle, + signature: Self::ManagedBufferHandle, + ); } diff --git a/framework/base/src/api/uncallable/crypto_api_uncallable.rs b/framework/base/src/api/uncallable/crypto_api_uncallable.rs index 59195618c9..fe0547c5d7 100644 --- a/framework/base/src/api/uncallable/crypto_api_uncallable.rs +++ b/framework/base/src/api/uncallable/crypto_api_uncallable.rs @@ -42,7 +42,7 @@ impl CryptoApiImpl for UncallableApi { _key: Self::ManagedBufferHandle, _message: Self::ManagedBufferHandle, _signature: Self::ManagedBufferHandle, - ) -> bool { + ) { unreachable!() } @@ -82,4 +82,31 @@ impl CryptoApiImpl for UncallableApi { ) { unreachable!() } + + fn verify_secp256r1_managed( + &self, + _key: Self::ManagedBufferHandle, + _message: Self::ManagedBufferHandle, + _signature: Self::ManagedBufferHandle, + ) { + unreachable!() + } + + fn verify_bls_signature_share_managed( + &self, + _key: Self::ManagedBufferHandle, + _message: Self::ManagedBufferHandle, + _signature: Self::ManagedBufferHandle, + ) { + unreachable!() + } + + fn verify_bls_aggregated_signature_managed( + &self, + _key: Self::ManagedBufferHandle, + _message: Self::ManagedBufferHandle, + _signature: Self::ManagedBufferHandle, + ) { + unreachable!() + } } diff --git a/framework/base/src/contract_base/wrappers/crypto_wrapper.rs b/framework/base/src/contract_base/wrappers/crypto_wrapper.rs index c314899eaa..369cca1a63 100644 --- a/framework/base/src/contract_base/wrappers/crypto_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/crypto_wrapper.rs @@ -5,7 +5,7 @@ use crate::{ use_raw_handle, CryptoApi, CryptoApiImpl, StaticVarApiImpl, KECCAK256_RESULT_LEN, SHA256_RESULT_LEN, }, - types::{ManagedBuffer, ManagedByteArray, ManagedType, MessageHashType}, + types::{ManagedBuffer, ManagedByteArray, ManagedType, ManagedVec, MessageHashType}, }; #[derive(Default)] @@ -61,7 +61,7 @@ where key: &ManagedBuffer, message: &ManagedBuffer, signature: &ManagedBuffer, - ) -> bool { + ) { A::crypto_api_impl().verify_bls_managed( key.get_handle(), message.get_handle(), @@ -69,7 +69,9 @@ where ) } - /// Will crash if the verification fails. + /// Calls the Vm to verify ed25519 signature. + /// + /// Does not return result, will fail tx directly! /// /// The error comes straight form the VM, the message is "invalid signature". pub fn verify_ed25519( @@ -129,4 +131,52 @@ where ); ManagedBuffer::from_handle(new_handle) } + + /// Calls the Vm to verify secp256r1 signature. + /// + /// Does not return result, will fail tx directly! + pub fn verify_secp256r1( + &self, + key: &ManagedBuffer, + message: &ManagedBuffer, + signature: &ManagedBuffer, + ) { + A::crypto_api_impl().verify_secp256r1_managed( + key.get_handle(), + message.get_handle(), + signature.get_handle(), + ) + } + + /// Calls the Vm to verify BLS signature share. + /// + /// Does not return result, will fail tx directly! + pub fn verify_bls_signature_share( + &self, + key: &ManagedBuffer, + message: &ManagedBuffer, + signature: &ManagedBuffer, + ) { + A::crypto_api_impl().verify_bls_signature_share_managed( + key.get_handle(), + message.get_handle(), + signature.get_handle(), + ) + } + + /// Calls the Vm to verify BLS aggregated signature. + /// + /// Does not return result, will fail tx directly! + pub fn verify_bls_aggregated_signature( + &self, + keys: &ManagedVec>, + message: &ManagedBuffer, + signature: &ManagedBuffer, + ) { + A::crypto_api_impl().verify_bls_aggregated_signature_managed( + keys.get_handle(), + message.get_handle(), + signature.get_handle(), + ) + } } diff --git a/framework/base/src/storage/mappers/ordered_binary_tree_mapper.rs b/framework/base/src/storage/mappers/ordered_binary_tree_mapper.rs index 064e90551c..2425c59049 100644 --- a/framework/base/src/storage/mappers/ordered_binary_tree_mapper.rs +++ b/framework/base/src/storage/mappers/ordered_binary_tree_mapper.rs @@ -232,7 +232,7 @@ where opt_predecessor } - pub fn insert_element(&mut self, new_data: T) { + pub fn insert_element(&mut self, new_data: T) -> u64 { let new_node_id = self.get_and_increment_last_id(); let mut new_node = OrderedBinaryTreeNode::new(new_node_id, new_data); @@ -243,7 +243,7 @@ where let current_node = unsafe { opt_current_node.unwrap_unchecked() }; if new_node.data == current_node.data { - return; + return 0u64; } if new_node.data < current_node.data { @@ -266,7 +266,7 @@ where let root_key = self.build_root_key(); storage_set(root_key.as_ref(), &new_node); - return; + return 0u64; } let mut new_node_parent = unsafe { opt_new_node_parent.unwrap_unchecked() }; @@ -278,6 +278,8 @@ where self.set_item(new_node_id, &new_node); self.set_item(new_node_parent.current_node_id, &new_node_parent); + + new_node_id } pub fn delete_node(&mut self, data: T) { diff --git a/framework/base/src/types/interaction/expr/test_token_identifier.rs b/framework/base/src/types/interaction/expr/test_token_identifier.rs index 47568b37ba..68865d8fbc 100644 --- a/framework/base/src/types/interaction/expr/test_token_identifier.rs +++ b/framework/base/src/types/interaction/expr/test_token_identifier.rs @@ -26,6 +26,18 @@ impl<'a> TestTokenIdentifier<'a> { pub fn eval_to_expr(&self) -> alloc::string::String { alloc::format!("{STR_PREFIX}{}", self.name) } + + pub fn to_token_identifier(&self) -> TokenIdentifier { + self.name.into() + } + + pub fn as_str(&self) -> &str { + self.name + } + + pub fn as_bytes(&self) -> &[u8] { + self.name.as_bytes() + } } impl<'a, Env> AnnotatedValue> for TestTokenIdentifier<'a> diff --git a/framework/base/src/types/interaction/tx_payment.rs b/framework/base/src/types/interaction/tx_payment.rs index c5bcc10637..bed41cc775 100644 --- a/framework/base/src/types/interaction/tx_payment.rs +++ b/framework/base/src/types/interaction/tx_payment.rs @@ -1,3 +1,4 @@ +mod test_esdt_transfer; mod tx_payment_egld; mod tx_payment_egld_or_esdt; mod tx_payment_egld_or_esdt_refs; @@ -11,6 +12,7 @@ mod tx_payment_single_esdt; mod tx_payment_single_esdt_ref; mod tx_payment_single_esdt_triple; +pub use test_esdt_transfer::TestEsdtTransfer; pub use tx_payment_egld::{Egld, EgldPayment}; pub use tx_payment_egld_value::TxEgldValue; pub use tx_payment_multi_esdt::TxPaymentMultiEsdt; diff --git a/framework/base/src/types/interaction/tx_payment/test_esdt_transfer.rs b/framework/base/src/types/interaction/tx_payment/test_esdt_transfer.rs new file mode 100644 index 0000000000..99d00a219e --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/test_esdt_transfer.rs @@ -0,0 +1,69 @@ +use crate::{ + api::ManagedTypeApi, + types::{ + BigUint, EsdtTokenPayment, FullPaymentData, FunctionCall, ManagedAddress, + TestTokenIdentifier, TxEnv, TxFrom, TxPayment, TxToSpecified, + }, +}; + +/// Syntactic sugar for quickly writing ESDT transfers in tests. +/// +/// The fields are: +/// 1. token identifier, as TestTokenIdentifier +/// 2. nonce +/// 3. amount +/// +/// The amount is represented as u64, since for most tests it is enough. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TestEsdtTransfer<'a>(pub TestTokenIdentifier<'a>, pub u64, pub u64); + +impl<'a, Api> From> for EsdtTokenPayment +where + Api: ManagedTypeApi, +{ + fn from(value: TestEsdtTransfer<'a>) -> Self { + EsdtTokenPayment::new(value.0.to_token_identifier(), value.1, value.2.into()) + } +} + +impl<'a, Env> TxPayment for TestEsdtTransfer<'a> +where + Env: TxEnv, +{ + #[inline] + fn is_no_payment(&self, _env: &Env) -> bool { + self.2 == 0 + } + + #[inline] + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + EsdtTokenPayment::from(self).perform_transfer_execute(env, to, gas_limit, fc); + } + + #[inline] + fn with_normalized( + self, + env: &Env, + from: &From, + to: To, + fc: FunctionCall, + f: F, + ) -> R + where + From: TxFrom, + To: TxToSpecified, + F: FnOnce(&ManagedAddress, &BigUint, FunctionCall) -> R, + { + EsdtTokenPayment::from(self).with_normalized(env, from, to, fc, f) + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + EsdtTokenPayment::from(self).into_full_payment_data(env) + } +} diff --git a/framework/base/src/types/managed/wrapped/managed_vec_item.rs b/framework/base/src/types/managed/wrapped/managed_vec_item.rs index 648635e143..9f21a13de4 100644 --- a/framework/base/src/types/managed/wrapped/managed_vec_item.rs +++ b/framework/base/src/types/managed/wrapped/managed_vec_item.rs @@ -31,6 +31,7 @@ pub trait ManagedVecItem: 'static { /// - For items with Copy semantics, it should be the type itself. /// - For managed types, ManagedRef does the job. /// - For any other types, `Self` is currently used, although this is technically unsafe. + /// /// TODO: wrap other types in readonly wrapper. type Ref<'a>: Borrow; diff --git a/framework/derive/Cargo.toml b/framework/derive/Cargo.toml index 50f6ef6dd0..d4246c314b 100644 --- a/framework/derive/Cargo.toml +++ b/framework/derive/Cargo.toml @@ -15,8 +15,8 @@ categories = ["cryptography::cryptocurrencies", "development-tools::procedural-m [dependencies] proc-macro2 = "=1.0.86" -quote = "=1.0.36" -syn = "=2.0.72" +quote = "=1.0.37" +syn = "=2.0.76" hex = "=0.4.3" radix_trie = "=0.2.1" diff --git a/framework/meta-lib/Cargo.toml b/framework/meta-lib/Cargo.toml index f3149ee0c8..484e9034cb 100644 --- a/framework/meta-lib/Cargo.toml +++ b/framework/meta-lib/Cargo.toml @@ -26,8 +26,8 @@ colored = "2.0" lazy_static = "1.4.0" convert_case = "0.6.0" hex = "0.4" -wasmparser = "0.214" -wasmprinter = "0.214" +wasmparser = "0.216" +wasmprinter = "0.216" semver = "1.0.20" [dependencies.multiversx-sc] diff --git a/framework/meta/Cargo.toml b/framework/meta/Cargo.toml index bd6775ed1a..fba796a3d0 100644 --- a/framework/meta/Cargo.toml +++ b/framework/meta/Cargo.toml @@ -39,6 +39,7 @@ zip = { version = "2.1", features = ["deflate"], default-features = false } copy_dir = "0.1.2" pathdiff = "0.2.1" common-path = "1.0.0" +bip39 = "2.0.0" [dependencies.multiversx-sc-meta-lib] version = "=0.52.3" diff --git a/framework/meta/src/cli/cli_args_standalone.rs b/framework/meta/src/cli/cli_args_standalone.rs index 0be68d805f..ce2c3b66a6 100644 --- a/framework/meta/src/cli/cli_args_standalone.rs +++ b/framework/meta/src/cli/cli_args_standalone.rs @@ -78,6 +78,12 @@ pub enum StandaloneCliAction { about = "Generates a report on the local depedencies of contract crates. Will explore indirect depdencies too." )] LocalDeps(LocalDepsArgs), + + #[command( + name = "wallet", + about = "Generates a new wallet or performs actions on an existing wallet." + )] + Wallet(WalletArgs), } #[derive(Default, Clone, PartialEq, Eq, Debug, Args)] @@ -411,3 +417,58 @@ pub struct AccountArgs { #[arg(long = "address", verbatim_doc_comment)] pub address: String, } + +#[derive(Clone, PartialEq, Eq, Debug, Subcommand)] +pub enum WalletAction { + #[command(name = "new", about = "Creates a new wallet")] + New(WalletNewArgs), + + #[command( + name = "bech32", + about = "Encodes/decodes a bech32 address to/from hex" + )] + Bech32(WalletBech32Args), + #[command(name = "convert", about = "Converts a wallet")] + Convert(WalletConvertArgs), +} + +#[derive(Clone, PartialEq, Eq, Debug, Parser)] +#[command(propagate_version = true)] +pub struct WalletArgs { + #[command(subcommand)] + pub command: WalletAction, +} + +#[derive(Default, Clone, PartialEq, Eq, Debug, Args)] +pub struct WalletNewArgs { + /// The type of wallet to create. + #[arg(long = "format", verbatim_doc_comment)] + pub wallet_format: Option, + + /// The name of the wallet to create. + #[arg(long = "outfile", verbatim_doc_comment)] + pub outfile: Option, +} + +#[derive(Default, Clone, PartialEq, Eq, Debug, Args)] +pub struct WalletConvertArgs { + #[arg(long = "in-format", verbatim_doc_comment)] + pub from: String, + + #[arg(long = "out-format", verbatim_doc_comment)] + pub to: String, + + #[arg(long = "infile", verbatim_doc_comment)] + pub infile: Option, + + #[arg(long = "outfile", verbatim_doc_comment)] + pub outfile: Option, +} + +#[derive(Default, Clone, PartialEq, Eq, Debug, Args)] +pub struct WalletBech32Args { + #[arg(long = "encode", verbatim_doc_comment)] + pub hex_address: Option, + #[arg(long = "decode", verbatim_doc_comment)] + pub bech32_address: Option, +} diff --git a/framework/meta/src/cli/cli_standalone_main.rs b/framework/meta/src/cli/cli_standalone_main.rs index 9a8e065627..c749ff0056 100644 --- a/framework/meta/src/cli/cli_standalone_main.rs +++ b/framework/meta/src/cli/cli_standalone_main.rs @@ -1,5 +1,6 @@ use crate::cli::{StandaloneCliAction, StandaloneCliArgs}; use crate::cmd::retrieve_address::retrieve_address; +use crate::cmd::wallet::wallet; use clap::Parser; use crate::cmd::all::call_all_meta; @@ -46,6 +47,9 @@ pub async fn cli_main_standalone() { Some(StandaloneCliAction::LocalDeps(args)) => { local_deps(args); }, + Some(StandaloneCliAction::Wallet(args)) => { + wallet(args); + }, None => {}, } } diff --git a/framework/meta/src/cmd.rs b/framework/meta/src/cmd.rs index 2a3ebe65cd..3263d36688 100644 --- a/framework/meta/src/cmd.rs +++ b/framework/meta/src/cmd.rs @@ -10,3 +10,4 @@ pub mod template; pub mod test; pub mod test_coverage; pub mod upgrade; +pub mod wallet; diff --git a/framework/meta/src/cmd/wallet.rs b/framework/meta/src/cmd/wallet.rs new file mode 100644 index 0000000000..b3833da517 --- /dev/null +++ b/framework/meta/src/cmd/wallet.rs @@ -0,0 +1,176 @@ +use core::str; + +use crate::cli::{WalletAction, WalletArgs, WalletBech32Args, WalletConvertArgs, WalletNewArgs}; +use multiversx_sc::types::{self}; +use multiversx_sc_snippets::sdk::{ + crypto::public_key::PublicKey, data::address::Address, wallet::Wallet, +}; +use multiversx_sc_snippets::{hex, imports::Bech32Address}; +use std::{ + fs::{self, File}, + io::{self, Read, Write}, +}; + +pub fn wallet(args: &WalletArgs) { + let command = &args.command; + match command { + WalletAction::New(new_args) => new(new_args), + WalletAction::Bech32(bech32_args) => bech32_conversion(bech32_args), + WalletAction::Convert(convert_args) => convert(convert_args), + } +} + +fn convert(convert_args: &WalletConvertArgs) { + let infile = convert_args.infile.as_ref(); + let outfile = convert_args.outfile.as_ref(); + let in_format = &convert_args.from; + let out_format = &convert_args.to; + + let mut mnemonic_str = String::new(); + let private_key_str: String; + let public_key_str: String; + + match (in_format.as_str(), out_format.as_str()) { + ("mnemonic", "pem") => match infile { + Some(file) => { + mnemonic_str = fs::read_to_string(file).unwrap(); + (private_key_str, public_key_str) = Wallet::get_wallet_keys_mnemonic(mnemonic_str); + write_resulted_pem(&public_key_str, &private_key_str, outfile); + }, + None => { + println!("Insert text below. Press 'Ctrl-D' (Linux / MacOS) or 'Ctrl-Z' (Windows) when done."); + _ = io::stdin().read_to_string(&mut mnemonic_str).unwrap(); + (private_key_str, public_key_str) = Wallet::get_wallet_keys_mnemonic(mnemonic_str); + write_resulted_pem(&public_key_str, &private_key_str, outfile); + }, + }, + ("keystore-secret", "pem") => match infile { + Some(file) => { + let private_key = Wallet::get_private_key_from_keystore_secret( + file, + &Wallet::get_keystore_password(), + ) + .unwrap(); + private_key_str = private_key.to_string(); + let public_key = PublicKey::from(&private_key); + public_key_str = public_key.to_string(); + write_resulted_pem(&public_key_str, &private_key_str, outfile); + }, + None => { + panic!("Input file is required for keystore-secret format"); + }, + }, + ("pem", "keystore-secret") => match infile { + Some(file) => { + let pem_decoded_keys = Wallet::get_pem_decoded_content(file); + (private_key_str, public_key_str) = Wallet::get_wallet_keys_pem(file); + + let address = get_wallet_address(&private_key_str); + let hex_decoded_keys = hex::decode(pem_decoded_keys).unwrap(); + + let json_result = Wallet::encrypt_keystore( + hex_decoded_keys.as_slice(), + &address, + &public_key_str, + &Wallet::get_keystore_password(), + ); + write_resulted_keystore(json_result, outfile); + }, + None => { + panic!("Input file is required for pem format"); + }, + }, + _ => { + println!("Unsupported conversion"); + }, + } +} + +fn write_resulted_pem(public_key: &str, private_key: &str, outfile: Option<&String>) { + let address = get_wallet_address(private_key); + match outfile { + Some(outfile) => { + let pem_content = Wallet::generate_pem_content(&address, private_key, public_key); + let mut file = File::create(outfile).unwrap(); + file.write_all(pem_content.as_bytes()).unwrap(); + }, + None => { + let pem_content = Wallet::generate_pem_content(&address, private_key, public_key); + print!("{}", pem_content); + }, + } +} + +fn write_resulted_keystore(json_result: String, outfile: Option<&String>) { + match outfile { + Some(outfile) => { + let mut file = File::create(outfile).unwrap(); + file.write_all(json_result.as_bytes()).unwrap(); + }, + None => { + println!("{}", json_result); + }, + } +} + +fn bech32_conversion(bech32_args: &WalletBech32Args) { + let encode_address = bech32_args.hex_address.as_ref(); + let decode_address = bech32_args.bech32_address.as_ref(); + + match (encode_address, decode_address) { + (Some(hex), None) => { + let bytes_from_hex = hex::decode(hex).unwrap(); + let bytes_arr: [u8; 32] = bytes_from_hex.try_into().unwrap(); + + let addr = types::Address::from(&bytes_arr); + let bech32_addr = Bech32Address::from(addr).to_bech32_str().to_string(); + println!("{}", bech32_addr); + }, + (None, Some(bech32)) => { + let hex_addr = Bech32Address::from_bech32_string(bech32.to_string()).to_hex(); + println!("{}", hex_addr); + }, + (Some(_), Some(_)) => { + println!("error: only one of --encode or --decode can be used in the same command"); + }, + _ => {}, + } +} + +fn get_wallet_address(private_key: &str) -> Address { + let wallet = Wallet::from_private_key(private_key).unwrap(); + wallet.address() +} + +fn new(new_args: &WalletNewArgs) { + let format = new_args.wallet_format.as_deref(); + let outfile = new_args.outfile.as_ref(); // Handle outfile as Option<&str> if it's an Option + let mnemonic = Wallet::generate_mnemonic(); + println!("Mnemonic: {}", mnemonic); + + let (private_key_str, public_key_str) = Wallet::get_wallet_keys_mnemonic(mnemonic.to_string()); + let address = get_wallet_address(private_key_str.as_str()); + + println!("Wallet address: {}", address); + + match format { + Some("pem") => { + write_resulted_pem(public_key_str.as_str(), private_key_str.as_str(), outfile); + }, + Some("keystore-secret") => { + let concatenated_keys = format!("{}{}", private_key_str, public_key_str); + let hex_decoded_keys = hex::decode(concatenated_keys).unwrap(); + let json_result = Wallet::encrypt_keystore( + hex_decoded_keys.as_slice(), + &address, + &public_key_str, + &Wallet::get_keystore_password(), + ); + write_resulted_keystore(json_result, outfile); + }, + Some(_) => { + println!("Unsupported format"); + }, + None => {}, + } +} diff --git a/framework/scenario/Cargo.toml b/framework/scenario/Cargo.toml index 9cf7f2a553..796ab19bf0 100644 --- a/framework/scenario/Cargo.toml +++ b/framework/scenario/Cargo.toml @@ -21,7 +21,7 @@ base64 = "0.22" num-bigint = "0.4" num-traits = "0.2" hex = "0.4" -bech32 = "0.9" +bech32 = "0.11" log = "0.4.17" sha2 = "0.10.6" serde = "1.0" @@ -32,8 +32,8 @@ colored = "2.0" unwrap-infallible = "0.1.5" [features] -default = ["wasm-incopatible"] -wasm-incopatible = ["multiversx-chain-vm/wasm-incopatible"] +default = ["wasm-incompatible"] +wasm-incompatible = ["multiversx-chain-vm/wasm-incompatible"] run-go-tests = [] [dependencies.multiversx-sc] diff --git a/framework/scenario/src/api/core_api_vh/crypto_api_vh.rs b/framework/scenario/src/api/core_api_vh/crypto_api_vh.rs index f3789181e7..305b3d6be9 100644 --- a/framework/scenario/src/api/core_api_vh/crypto_api_vh.rs +++ b/framework/scenario/src/api/core_api_vh/crypto_api_vh.rs @@ -53,7 +53,7 @@ impl CryptoApiImpl for VMHooksApi { _key: Self::ManagedBufferHandle, _message: Self::ManagedBufferHandle, _signature: Self::ManagedBufferHandle, - ) -> bool { + ) { panic!("verify_bls not implemented yet!") } @@ -99,4 +99,31 @@ impl CryptoApiImpl for VMHooksApi { ) { panic!("encode_secp256k1_signature not implemented yet!") } + + fn verify_secp256r1_managed( + &self, + _key: Self::ManagedBufferHandle, + _message: Self::ManagedBufferHandle, + _signature: Self::ManagedBufferHandle, + ) { + panic!("verify_secp256r1 not implemented yet!") + } + + fn verify_bls_signature_share_managed( + &self, + _key: Self::ManagedBufferHandle, + _message: Self::ManagedBufferHandle, + _signature: Self::ManagedBufferHandle, + ) { + panic!("verify_bls_signature_share not implemented yet!") + } + + fn verify_bls_aggregated_signature_managed( + &self, + _key: Self::ManagedBufferHandle, + _message: Self::ManagedBufferHandle, + _signature: Self::ManagedBufferHandle, + ) { + panic!("verify_bls_aggregated_signature not implemented yet!") + } } diff --git a/framework/scenario/src/bech32.rs b/framework/scenario/src/bech32.rs index aa224cee95..ef934cf225 100644 --- a/framework/scenario/src/bech32.rs +++ b/framework/scenario/src/bech32.rs @@ -1,10 +1,9 @@ -use bech32::{FromBase32, ToBase32, Variant}; +use bech32::{Bech32, Hrp}; use multiversx_sc::types::heap::Address; pub fn decode(bech32_address: &str) -> Address { - let (_, dest_address_bytes_u5, _) = bech32::decode(bech32_address) + let (_hrp, dest_address_bytes) = bech32::decode(bech32_address) .unwrap_or_else(|err| panic!("bech32 decode error for {bech32_address}: {err}")); - let dest_address_bytes = Vec::::from_base32(&dest_address_bytes_u5).unwrap(); if dest_address_bytes.len() != 32 { panic!("Invalid address length after decoding") } @@ -13,6 +12,6 @@ pub fn decode(bech32_address: &str) -> Address { } pub fn encode(address: &Address) -> String { - bech32::encode("erd", address.as_bytes().to_base32(), Variant::Bech32) - .expect("bech32 encode error") + let hrp = Hrp::parse("erd").expect("invalid hrp"); + bech32::encode::(hrp, address.as_bytes()).expect("bech32 encode error") } diff --git a/framework/scenario/src/facade/scenario_world_whitebox.rs b/framework/scenario/src/facade/scenario_world_whitebox.rs index 32a148ad0a..542e0fe0b2 100644 --- a/framework/scenario/src/facade/scenario_world_whitebox.rs +++ b/framework/scenario/src/facade/scenario_world_whitebox.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use multiversx_chain_vm::tx_mock::{TxFunctionName, TxResult}; use multiversx_sc::contract_base::{CallableContract, ContractBase}; @@ -10,6 +12,10 @@ use crate::{ use super::whitebox_contract::WhiteboxContract; impl ScenarioWorld { + #[deprecated( + since = "0.53.0", + note = "Please use method `whitebox`, as part of the unified transaction syntax." + )] pub fn whitebox_query( &mut self, whitebox_contract: &WhiteboxContract, @@ -24,6 +30,10 @@ impl ScenarioWorld { }) } + #[deprecated( + since = "0.53.0", + note = "Please use method `whitebox`, as part of the unified transaction syntax." + )] pub fn whitebox_query_check( &mut self, whitebox_contract: &WhiteboxContract, @@ -50,6 +60,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.53.0", + note = "Please use method `whitebox`, as part of the unified transaction syntax." + )] pub fn whitebox_call( &mut self, whitebox_contract: &WhiteboxContract, @@ -65,6 +79,10 @@ impl ScenarioWorld { }) } + #[deprecated( + since = "0.53.0", + note = "Please use method `whitebox`, as part of the unified transaction syntax." + )] pub fn whitebox_call_check( &mut self, whitebox_contract: &WhiteboxContract, @@ -99,6 +117,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.53.0", + note = "Please use method `whitebox`, as part of the unified transaction syntax." + )] pub fn whitebox_deploy( &mut self, whitebox_contract: &WhiteboxContract, @@ -114,6 +136,10 @@ impl ScenarioWorld { }) } + #[deprecated( + since = "0.53.0", + note = "Please use method `whitebox`, as part of the unified transaction syntax." + )] pub fn whitebox_deploy_check( &mut self, whitebox_contract: &WhiteboxContract, diff --git a/framework/scenario/src/facade/world_tx.rs b/framework/scenario/src/facade/world_tx.rs index a2d7373a42..d052614297 100644 --- a/framework/scenario/src/facade/world_tx.rs +++ b/framework/scenario/src/facade/world_tx.rs @@ -5,7 +5,9 @@ mod scenario_query_call; mod scenario_rh_impl; mod scenario_set_state; mod scenario_tx_env; +mod scenario_tx_whitebox; pub use scenario_exec_call::ScenarioEnvExec; pub use scenario_query_call::ScenarioEnvQuery; pub use scenario_tx_env::{ScenarioTxEnv, ScenarioTxEnvData, ScenarioTxRun}; +pub use scenario_tx_whitebox::ScenarioTxWhitebox; diff --git a/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs new file mode 100644 index 0000000000..62842a6e25 --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs @@ -0,0 +1,217 @@ +use crate::debug_executor::contract_instance_wrapped_execution; +use crate::scenario::tx_to_step::TxToQueryStep; +use crate::{ + imports::StaticApi, scenario::tx_to_step::TxToStep, scenario_model::TxResponse, ScenarioEnvExec, +}; +use crate::{DebugApi, ScenarioEnvQuery}; +use multiversx_chain_vm::tx_mock::TxFunctionName; +use multiversx_sc::contract_base::ContractBase; +use multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + Code, DeployCall, FunctionCall, RHListExec, Tx, TxCodeValue, TxFromSpecified, TxNoPayment, + TxPayment, TxToSpecified, + }, +}; + +pub trait ScenarioTxWhitebox { + type Returns; + + /// Runs a lambda function in the name of a smart contract, with the configured transaction context. + fn whitebox(self, contract_obj: fn() -> ContractObj, f: F) -> Self::Returns + where + ContractObj: ContractBase + 'static, + F: FnOnce(ContractObj); +} + +impl<'w, From, Payment, CodeValue, RH> ScenarioTxWhitebox + for Tx< + ScenarioEnvExec<'w>, + From, + (), + Payment, + (), + DeployCall, Code>, + RH, + > +where + From: TxFromSpecified>, + Payment: TxNoPayment>, + CodeValue: TxCodeValue>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn whitebox( + self, + contract_obj_builder: fn() -> ContractObj, + f: F, + ) -> Self::Returns + where + ContractObj: ContractBase + 'static, + F: FnOnce(ContractObj), + { + let contract_obj = contract_obj_builder(); + + let mut step_wrapper = self.tx_to_step(); + let (new_address, tx_result) = step_wrapper + .env + .world + .get_mut_debugger_backend() + .vm_runner + .perform_sc_deploy_lambda(&step_wrapper.step, || { + contract_instance_wrapped_execution(true, || { + f(contract_obj); + Ok(()) + }); + }); + + let mut response = TxResponse::from_tx_result(tx_result); + response.new_deployed_address = Some(new_address); + step_wrapper.step.save_response(response); + step_wrapper.process_result() + } +} + +impl<'w, From, To, Payment, RH> ScenarioTxWhitebox + for Tx, From, To, Payment, (), (), RH> +where + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn whitebox( + self, + contract_obj_builder: fn() -> ContractObj, + f: F, + ) -> Self::Returns + where + ContractObj: ContractBase + 'static, + F: FnOnce(ContractObj), + { + self.raw_call(TxFunctionName::WHITEBOX_CALL.as_str()) + .whitebox(contract_obj_builder, f) + } +} + +impl<'w, From, To, Payment, RH> ScenarioTxWhitebox + for Tx, From, To, Payment, (), FunctionCall, RH> +where + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn whitebox( + self, + contract_obj_builder: fn() -> ContractObj, + f: F, + ) -> Self::Returns + where + ContractObj: ContractBase + 'static, + F: FnOnce(ContractObj), + { + let contract_obj = contract_obj_builder(); + + let mut step_wrapper = self.tx_to_step(); + + // no endpoint is called per se, but if it is empty, the VM thinks it is a simple transfer of value + if step_wrapper.step.tx.function.is_empty() { + step_wrapper.step.tx.function = TxFunctionName::WHITEBOX_CALL.to_string(); + } + + let tx_result = step_wrapper + .env + .world + .get_mut_debugger_backend() + .vm_runner + .perform_sc_call_lambda(&step_wrapper.step, || { + contract_instance_wrapped_execution(true, || { + f(contract_obj); + Ok(()) + }); + }); + + let response = TxResponse::from_tx_result(tx_result); + step_wrapper.step.save_response(response); + step_wrapper.process_result() + } +} + +impl<'w, To, Payment, RH> ScenarioTxWhitebox + for Tx, (), To, Payment, (), (), RH> +where + To: TxToSpecified>, + Payment: TxNoPayment>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn whitebox( + self, + contract_obj_builder: fn() -> ContractObj, + f: F, + ) -> Self::Returns + where + ContractObj: ContractBase + 'static, + F: FnOnce(ContractObj), + { + self.raw_call(TxFunctionName::WHITEBOX_CALL.as_str()) + .whitebox(contract_obj_builder, f) + } +} + +impl<'w, To, Payment, RH> ScenarioTxWhitebox + for Tx, (), To, Payment, (), FunctionCall, RH> +where + To: TxToSpecified>, + Payment: TxNoPayment>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn whitebox( + self, + contract_obj_builder: fn() -> ContractObj, + f: F, + ) -> Self::Returns + where + ContractObj: ContractBase + 'static, + F: FnOnce(ContractObj), + { + let contract_obj = contract_obj_builder(); + + let mut step_wrapper = self.tx_to_query_step(); + + // no endpoint is called per se, but if it is empty, the VM thinks it is a simple transfer of value + if step_wrapper.step.tx.function.is_empty() { + step_wrapper.step.tx.function = TxFunctionName::WHITEBOX_CALL.to_string(); + } + + let tx_result = step_wrapper + .env + .world + .get_mut_debugger_backend() + .vm_runner + .perform_sc_query_lambda(&step_wrapper.step, || { + contract_instance_wrapped_execution(true, || { + f(contract_obj); + Ok(()) + }); + }); + + let response = TxResponse::from_tx_result(tx_result); + step_wrapper.step.save_response(response); + step_wrapper.process_result() + } +} diff --git a/framework/snippets/src/network_response.rs b/framework/snippets/src/network_response.rs index d505e7a525..4d828e12c7 100644 --- a/framework/snippets/src/network_response.rs +++ b/framework/snippets/src/network_response.rs @@ -103,25 +103,31 @@ fn process_new_deployed_address(tx: &TransactionOnNetwork) -> Option
{ } fn process_new_issued_token_identifier(tx: &TransactionOnNetwork) -> Option { + let original_tx_data = String::from_utf8(base64_decode(tx.data.as_ref().unwrap())).unwrap(); + for scr in tx.smart_contract_results.iter() { if scr.sender.to_bech32_string().unwrap() != ESDTSystemSCAddress.to_bech32_string() { continue; } - let Some(prev_tx) = tx + let prev_tx_data: &str = if let Some(prev_tx) = tx .smart_contract_results .iter() .find(|e| e.hash == scr.prev_tx_hash) - else { + { + prev_tx.data.as_ref() + } else if &scr.prev_tx_hash == tx.hash.as_ref().unwrap() { + &original_tx_data + } else { continue; }; - let is_issue_fungible = prev_tx.data.starts_with("issue@"); - let is_issue_semi_fungible = prev_tx.data.starts_with("issueSemiFungible@"); - let is_issue_non_fungible = prev_tx.data.starts_with("issueNonFungible@"); - let is_register_meta_esdt = prev_tx.data.starts_with("registerMetaESDT@"); + let is_issue_fungible = prev_tx_data.starts_with("issue@"); + let is_issue_semi_fungible = prev_tx_data.starts_with("issueSemiFungible@"); + let is_issue_non_fungible = prev_tx_data.starts_with("issueNonFungible@"); + let is_register_meta_esdt = prev_tx_data.starts_with("registerMetaESDT@"); let is_register_and_set_all_roles_esdt = - prev_tx.data.starts_with("registerAndSetAllRoles@"); + prev_tx_data.starts_with("registerAndSetAllRoles@"); if !is_issue_fungible && !is_issue_semi_fungible @@ -135,12 +141,11 @@ fn process_new_issued_token_identifier(tx: &TransactionOnNetwork) -> Option i32; fn managedEncodeSecp256k1DerSignature(rHandle: i32, sHandle: i32, sigHandle: i32) -> i32; + + fn managedVerifySecp256r1(keyHandle: i32, messageHandle: i32, sigHandle: i32) -> i32; + + fn managedVerifyBLSSignatureShare(keyHandle: i32, messageHandle: i32, sigHandle: i32) -> i32; + + fn managedVerifyBLSAggregatedSignature( + keyHandle: i32, + messageHandle: i32, + sigHandle: i32, + ) -> i32; } impl CryptoApi for VmApiImpl { @@ -74,8 +84,10 @@ impl CryptoApiImpl for VmApiImpl { key: Self::ManagedBufferHandle, message: Self::ManagedBufferHandle, signature: Self::ManagedBufferHandle, - ) -> bool { - unsafe { managedVerifyBLS(key, message, signature) == 0 } + ) { + unsafe { + let _ = managedVerifyBLS(key, message, signature); + } } #[inline] @@ -123,4 +135,37 @@ impl CryptoApiImpl for VmApiImpl { let _ = managedEncodeSecp256k1DerSignature(r, s, dest_sig_handle); } } + + fn verify_secp256r1_managed( + &self, + key: Self::ManagedBufferHandle, + message: Self::ManagedBufferHandle, + signature: Self::ManagedBufferHandle, + ) { + unsafe { + let _ = managedVerifySecp256r1(key, message, signature); + } + } + + fn verify_bls_signature_share_managed( + &self, + key: Self::ManagedBufferHandle, + message: Self::ManagedBufferHandle, + signature: Self::ManagedBufferHandle, + ) { + unsafe { + let _ = managedVerifyBLSSignatureShare(key, message, signature); + } + } + + fn verify_bls_aggregated_signature_managed( + &self, + key: Self::ManagedBufferHandle, + message: Self::ManagedBufferHandle, + signature: Self::ManagedBufferHandle, + ) { + unsafe { + let _ = managedVerifyBLSAggregatedSignature(key, message, signature); + } + } } diff --git a/sdk/core/Cargo.toml b/sdk/core/Cargo.toml index 463b4ce130..2387e4cce8 100644 --- a/sdk/core/Cargo.toml +++ b/sdk/core/Cargo.toml @@ -31,7 +31,11 @@ hex = "0.4.3" base64 = "0.22" pbkdf2 = { version = "0.12.2", default-features = false } zeroize = "1.4.2" -bech32 = "0.9" +bech32 = "0.11" itertools = "0.13.0" pem = "3.0.2" log = "0.4.17" +scrypt = "0.11" +aes = "0.8" +ctr = "0.9.2" +uuid = {version = "1.10.0", features = ["v4"]} \ No newline at end of file diff --git a/sdk/core/src/crypto/public_key.rs b/sdk/core/src/crypto/public_key.rs index 89b5211262..473a0388fe 100644 --- a/sdk/core/src/crypto/public_key.rs +++ b/sdk/core/src/crypto/public_key.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use super::private_key::PrivateKey; use anyhow::Result; -use bech32::{self, ToBase32, Variant}; +use bech32::{self, Bech32, Hrp}; use serde::{ de::{Deserialize, Deserializer}, ser::{Serialize, Serializer}, @@ -23,7 +23,8 @@ impl PublicKey { } pub fn to_address(&self) -> Result { - let address = bech32::encode("erd", self.0.to_base32(), Variant::Bech32)?; + let hrp = Hrp::parse("erd")?; + let address = bech32::encode::(hrp, &self.0)?; Ok(address) } diff --git a/sdk/core/src/data/address.rs b/sdk/core/src/data/address.rs index f8ac4212c3..49d92ea608 100644 --- a/sdk/core/src/data/address.rs +++ b/sdk/core/src/data/address.rs @@ -2,7 +2,7 @@ use std::fmt::{Debug, Display}; use crate::crypto::public_key::PublicKey; use anyhow::Result; -use bech32::{FromBase32, ToBase32, Variant}; +use bech32::{Bech32, Hrp}; use serde::{ de::{Deserialize, Deserializer}, ser::{Serialize, Serializer}, @@ -21,8 +21,7 @@ impl Address { } pub fn from_bech32_string(bech32: &str) -> Result { - let (_, data, _) = bech32::decode(bech32)?; - let data = Vec::::from_base32(&data)?; + let (_hrp, data) = bech32::decode(bech32)?; let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&data); @@ -31,7 +30,8 @@ impl Address { } pub fn to_bech32_string(&self) -> Result { - let address = bech32::encode("erd", self.0.to_base32(), Variant::Bech32)?; + let hrp = Hrp::parse("erd")?; + let address = bech32::encode::(hrp, &self.0)?; Ok(address) } diff --git a/sdk/core/src/data/keystore.rs b/sdk/core/src/data/keystore.rs new file mode 100644 index 0000000000..1b3c656ef1 --- /dev/null +++ b/sdk/core/src/data/keystore.rs @@ -0,0 +1,54 @@ +use serde::{Deserialize, Serialize}; + +pub const KDF_N: u32 = 4096; +pub const KDF_R: u32 = 8; +pub const KDF_P: u32 = 1; +pub const KDF_DKLEN: usize = 32; +pub const KEYSTORE_VERSION: u32 = 4; + +#[derive(Debug)] +pub enum WalletError { + InvalidPassword, + InvalidKdf, + InvalidCipher, +} +#[derive(Debug, Serialize, Deserialize)] +pub struct CryptoParams { + pub iv: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct KdfParams { + pub dklen: u32, + pub salt: String, + pub n: u32, + pub r: u32, + pub p: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Crypto { + pub ciphertext: String, + pub cipherparams: CryptoParams, + pub cipher: String, + pub kdf: String, + pub kdfparams: KdfParams, + pub mac: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Keystore { + pub version: u32, + pub kind: String, + pub id: String, + pub address: String, + pub bech32: String, + pub crypto: Crypto, +} + +#[derive(Clone, Debug)] +pub struct DecryptionParams { + pub derived_key_first_half: Vec, + pub iv: Vec, + pub data: Vec, +} diff --git a/sdk/core/src/data/mod.rs b/sdk/core/src/data/mod.rs index 797ec6e1ce..9a270211df 100644 --- a/sdk/core/src/data/mod.rs +++ b/sdk/core/src/data/mod.rs @@ -3,6 +3,7 @@ pub mod account_storage; pub mod address; pub mod esdt; pub mod hyperblock; +pub mod keystore; pub mod network_config; pub mod network_economics; pub mod network_status; diff --git a/sdk/core/src/gateway/gateway_tx_retrieve.rs b/sdk/core/src/gateway/gateway_tx_retrieve.rs index 4d781b6118..193e1daa8b 100644 --- a/sdk/core/src/gateway/gateway_tx_retrieve.rs +++ b/sdk/core/src/gateway/gateway_tx_retrieve.rs @@ -14,6 +14,7 @@ impl GatewayProxy { let mut retries = 0; let mut backoff_delay = Duration::from_secs_f32(INITIAL_BACKOFF_DELAY); let start_time = Instant::now(); + let mut issue_found = false; loop { match self.get_transaction_process_status(&tx_hash).await { @@ -26,6 +27,22 @@ impl GatewayProxy { .get_transaction_info_with_results(&tx_hash) .await .unwrap(); + + if !transaction_info_with_results + .smart_contract_results + .is_empty() + && !issue_found + { + let first_scr = + &transaction_info_with_results.smart_contract_results[0]; + + if GatewayProxy::is_issue_tx(&first_scr.data) { + issue_found = true; + tokio::time::sleep(Duration::from_secs(30)).await; + continue; + } + } + info!( "Transaction retrieved successfully, with status {}: {:#?}", status, transaction_info_with_results @@ -60,4 +77,12 @@ impl GatewayProxy { ); TransactionOnNetwork::default() } + + fn is_issue_tx(data: &str) -> bool { + data.starts_with("issue@") + || data.starts_with("issueSemiFungible@") + || data.starts_with("issueNonFungible@") + || data.starts_with("registerMetaESDT@") + || data.starts_with("registerAndSetAllRoles@") + } } diff --git a/sdk/core/src/wallet.rs b/sdk/core/src/wallet.rs index ab1b0a2f37..bf1362a314 100644 --- a/sdk/core/src/wallet.rs +++ b/sdk/core/src/wallet.rs @@ -1,11 +1,21 @@ extern crate rand; +use core::str; +use std::{ + fs::{self}, + io::{self, Read}, +}; + +use aes::{cipher::KeyIvInit, Aes128}; use anyhow::Result; use bip39::{Language, Mnemonic}; +use ctr::{cipher::StreamCipher, Ctr128BE}; use hmac::{Hmac, Mac}; use pbkdf2::pbkdf2; +use rand::RngCore; +use scrypt::{scrypt, Params}; use serde_json::json; -use sha2::{Digest, Sha512}; +use sha2::{Digest, Sha256, Sha512}; use sha3::Keccak256; use zeroize::Zeroize; @@ -14,13 +24,19 @@ use crate::{ private_key::{PrivateKey, PRIVATE_KEY_LENGTH}, public_key::PublicKey, }, - data::{address::Address, transaction::Transaction}, + data::{address::Address, keystore::*, transaction::Transaction}, + utils::*, }; +use uuid::Uuid; + const EGLD_COIN_TYPE: u32 = 508; const HARDENED: u32 = 0x80000000; +const CIPHER_ALGORITHM_AES_128_CTR: &str = "aes-128-ctr"; +const KDF_SCRYPT: &str = "scrypt"; -type HmacSha521 = Hmac; +type HmacSha512 = Hmac; +type HmacSha256 = Hmac; #[derive(Copy, Clone, Debug)] pub struct Wallet { @@ -63,7 +79,8 @@ impl Wallet { let hardened_child_padding: u8 = 0; let mut digest = - HmacSha521::new_from_slice(b"ed25519 seed").expect("HMAC can take key of any size"); + HmacSha512::new_from_slice(b"ed25519 seed").expect("HMAC can take key of any size"); + HmacSha512::new_from_slice(b"ed25519 seed").expect("HMAC can take key of any size"); digest.update(&seed); let intermediary: Vec = digest.finalize().into_bytes().into_iter().collect(); let mut key = intermediary[..serialized_key_len].to_vec(); @@ -83,7 +100,8 @@ impl Wallet { buff.push(child_idx as u8); digest = - HmacSha521::new_from_slice(&chain_code).expect("HMAC can take key of any size"); + HmacSha512::new_from_slice(&chain_code).expect("HMAC can take key of any size"); + HmacSha512::new_from_slice(&chain_code).expect("HMAC can take key of any size"); digest.update(&buff); let intermediary: Vec = digest.finalize().into_bytes().into_iter().collect(); key = intermediary[..serialized_key_len].to_vec(); @@ -93,9 +111,20 @@ impl Wallet { PrivateKey::from_bytes(key.as_slice()).unwrap() } + pub fn get_wallet_keys_mnemonic(mnemonic_str: String) -> (String, String) { + let mnemonic = Mnemonic::parse(mnemonic_str.replace('\n', "")).unwrap(); + let private_key = Self::get_private_key_from_mnemonic(mnemonic, 0u32, 0u32); + let public_key = PublicKey::from(&private_key); + + let public_key_str: &str = &public_key.to_string(); + let private_key_str: &str = &private_key.to_string(); + + (private_key_str.to_string(), public_key_str.to_string()) + } + pub fn from_private_key(priv_key: &str) -> Result { - let pri_key = PrivateKey::from_hex_str(priv_key)?; - Ok(Self { priv_key: pri_key }) + let priv_key = PrivateKey::from_hex_str(priv_key)?; + Ok(Self { priv_key }) } pub fn from_pem_file(file_path: &str) -> Result { @@ -111,6 +140,48 @@ impl Wallet { Ok(Self { priv_key: pri_key }) } + pub fn get_pem_decoded_content(file: &str) -> Vec { + let pem_content = fs::read_to_string(file).unwrap(); + let lines: Vec<&str> = pem_content.split('\n').collect(); + let pem_encoded_keys = format!("{}{}{}", lines[1], lines[2], lines[3]); + base64_decode(pem_encoded_keys) + } + + pub fn get_wallet_keys_pem(file: &str) -> (String, String) { + let pem_decoded_keys = Self::get_pem_decoded_content(file); + let (private_key, public_key) = pem_decoded_keys.split_at(pem_decoded_keys.len() / 2); + let private_key_str = String::from_utf8(private_key.to_vec()).unwrap(); + let public_key_str = String::from_utf8(public_key.to_vec()).unwrap(); + + (private_key_str, public_key_str) + } + + pub fn from_keystore_secret(file_path: &str) -> Result { + let decyption_params = + Self::validate_keystore_password(file_path, Self::get_keystore_password()) + .unwrap_or_else(|e| { + panic!("Error: {:?}", e); + }); + let priv_key = PrivateKey::from_hex_str( + hex::encode(Self::decrypt_secret_key(decyption_params)).as_str(), + )?; + Ok(Self { priv_key }) + } + + pub fn get_private_key_from_keystore_secret( + file_path: &str, + password: &str, + ) -> Result { + let decyption_params = Self::validate_keystore_password(file_path, password.to_string()) + .unwrap_or_else(|e| { + panic!("Error: {:?}", e); + }); + let priv_key = PrivateKey::from_hex_str( + hex::encode(Self::decrypt_secret_key(decyption_params)).as_str(), + )?; + Ok(priv_key) + } + pub fn address(&self) -> Address { let public_key = PublicKey::from(&self.priv_key); Address::from(&public_key) @@ -131,4 +202,157 @@ impl Wallet { self.priv_key.sign(tx_bytes) } + + pub fn get_keystore_password() -> String { + println!( + "Insert password. Press 'Ctrl-D' (Linux / MacOS) or 'Ctrl-Z' (Windows) when done." + ); + let mut password = String::new(); + io::stdin().read_to_string(&mut password).unwrap(); + password = password.trim().to_string(); + password + } + + pub fn validate_keystore_password( + path: &str, + password: String, + ) -> Result { + let json_body = fs::read_to_string(path).unwrap(); + let keystore: Keystore = serde_json::from_str(&json_body).unwrap(); + let ciphertext = hex::decode(&keystore.crypto.ciphertext).unwrap(); + + let cipher = &keystore.crypto.cipher; + if cipher != CIPHER_ALGORITHM_AES_128_CTR { + return Err(WalletError::InvalidCipher); + } + + let iv = hex::decode(&keystore.crypto.cipherparams.iv).unwrap(); + let salt = hex::decode(&keystore.crypto.kdfparams.salt).unwrap(); + let json_mac = hex::decode(&keystore.crypto.mac).unwrap(); + + let kdf = &keystore.crypto.kdf; + if kdf != KDF_SCRYPT { + return Err(WalletError::InvalidKdf); + } + let n = keystore.crypto.kdfparams.n as f64; + let r = keystore.crypto.kdfparams.r as u64; + let p = keystore.crypto.kdfparams.p as u64; + let dklen = keystore.crypto.kdfparams.dklen as usize; + + let params = Params::new(n.log2() as u8, r as u32, p as u32, dklen).unwrap(); + + let mut derived_key = vec![0u8; 32]; + scrypt(password.as_bytes(), &salt, ¶ms, &mut derived_key).unwrap(); + + let derived_key_first_half = derived_key[0..16].to_vec(); + let derived_key_second_half = derived_key[16..32].to_vec(); + + let mut input_mac = HmacSha256::new_from_slice(&derived_key_second_half).unwrap(); + input_mac.update(&ciphertext); + let computed_mac = input_mac.finalize().into_bytes(); + + if computed_mac.as_slice() == json_mac.as_slice() { + println!("Password is correct"); + Ok(DecryptionParams { + derived_key_first_half, + iv, + data: ciphertext, + }) + } else { + println!("Password is incorrect"); + Err(WalletError::InvalidPassword) + } + } + + pub fn decrypt_secret_key(decryption_params: DecryptionParams) -> Vec { + let mut cipher = Ctr128BE::::new( + decryption_params.derived_key_first_half.as_slice().into(), + decryption_params.iv.as_slice().into(), + ); + let mut decrypted = decryption_params.data.to_vec(); + cipher.apply_keystream(&mut decrypted); + + decrypted + } + + pub fn encrypt_keystore( + data: &[u8], + address: &Address, + public_key: &str, + password: &str, + ) -> String { + let params = Params::new((KDF_N as f64).log2() as u8, KDF_R, KDF_P, KDF_DKLEN).unwrap(); + let mut rand_salt: [u8; 32] = [0u8; 32]; + rand::thread_rng().fill_bytes(&mut rand_salt); + let salt_hex = hex::encode(rand_salt); + + let mut rand_iv: [u8; 16] = [0u8; 16]; + rand::thread_rng().fill_bytes(&mut rand_iv); + let iv_hex = hex::encode(rand_iv); + + let mut derived_key = vec![0u8; 32]; + scrypt(password.as_bytes(), &rand_salt, ¶ms, &mut derived_key).unwrap(); + + let derived_key_first_half = derived_key[0..16].to_vec(); + let derived_key_second_half = derived_key[16..32].to_vec(); + + let decryption_params = DecryptionParams { + derived_key_first_half, + iv: rand_iv.to_vec(), + data: data.to_vec(), + }; + + let ciphertext = Self::decrypt_secret_key(decryption_params); + + let mut h = HmacSha256::new_from_slice(&derived_key_second_half).unwrap(); + h.update(&ciphertext); + let mac = h.finalize().into_bytes(); + let keystore = Keystore { + crypto: Crypto { + cipher: CIPHER_ALGORITHM_AES_128_CTR.to_string(), + cipherparams: CryptoParams { iv: iv_hex }, + ciphertext: hex::encode(&ciphertext), + kdf: KDF_SCRYPT.to_string(), + kdfparams: KdfParams { + salt: salt_hex, + n: KDF_N, + r: KDF_R, + p: KDF_P, + dklen: KDF_DKLEN as u32, + }, + mac: hex::encode(mac), + }, + id: Uuid::new_v4().to_string(), + version: KEYSTORE_VERSION, + kind: "secretKey".to_string(), + address: public_key.to_string(), + bech32: address.to_string(), + }; + + let mut keystore_json: String = serde_json::to_string_pretty(&keystore).unwrap(); + keystore_json.push('\n'); + keystore_json + } + + pub fn generate_pem_content(address: &Address, private_key: &str, public_key: &str) -> String { + let concat_keys = format!("{}{}", private_key, public_key); + let concat_keys_b64 = base64_encode(concat_keys); + + // Split the base64 string into 64-character lines + let formatted_key = concat_keys_b64 + .as_bytes() + .chunks(64) + .map(|chunk| std::str::from_utf8(chunk).unwrap()) + .collect::>() + .join("\n"); + + let pem_content = format!( + "-----BEGIN PRIVATE KEY for {}-----\n{}\n-----END PRIVATE KEY for {}-----\n", + address.to_bech32_string().unwrap(), + formatted_key, + address.to_bech32_string().unwrap() + ); + + pem_content + } } diff --git a/sdk/core/tests/wallet_test.rs b/sdk/core/tests/wallet_test.rs index d076980084..103166e430 100644 --- a/sdk/core/tests/wallet_test.rs +++ b/sdk/core/tests/wallet_test.rs @@ -1,6 +1,16 @@ use bip39::Mnemonic; use multiversx_sdk::{crypto::public_key::PublicKey, data::address::Address, wallet::Wallet}; +use std::fs::{self, File}; +use std::io::Write; + +const ALICE_PEM_PATH: &str = "tests/alice.pem"; +const ALICE_KEYSTORE_PATH_TEST_1: &str = "tests/alice1.json"; +const ALICE_KEYSTORE_PATH_TEST_2: &str = "tests/alice2.json"; +const ALICE_PEM_PATH_TEST: &str = "tests/alice_test.pem"; +const KEYSTORE_PASSWORD: &str = "abcd"; +const ALICE_PUBLIC_KEY: &str = "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1"; +const ALICE_PRIVATE_KEY: &str = "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9"; #[test] fn test_private_key_from_mnemonic() { @@ -48,3 +58,59 @@ fn test_load_from_pem() { "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" ); } + +fn write_to_file(content: &str, file: &str) { + let mut file = File::create(file).unwrap(); + file.write_all(content.as_bytes()).unwrap(); +} + +fn create_keystore_file_from_scratch(file: &str) -> Address { + let wallet = Wallet::from_private_key(ALICE_PRIVATE_KEY).unwrap(); + let address = wallet.address(); + + let concatenated_keys = format!("{}{}", ALICE_PRIVATE_KEY, ALICE_PUBLIC_KEY); + let hex_decoded_keys = hex::decode(concatenated_keys).unwrap(); + let json_result = Wallet::encrypt_keystore( + hex_decoded_keys.as_slice(), + &address, + ALICE_PUBLIC_KEY, + KEYSTORE_PASSWORD, + ); + write_to_file(&json_result, file); + address +} + +#[test] +fn test_wallet_convert_pem_to_keystore() { + let _ = create_keystore_file_from_scratch(ALICE_KEYSTORE_PATH_TEST_1); + let (private_key_pem, _public_key_pem) = Wallet::get_wallet_keys_pem(ALICE_PEM_PATH); + assert_eq!( + Wallet::get_private_key_from_keystore_secret(ALICE_KEYSTORE_PATH_TEST_1, KEYSTORE_PASSWORD) + .unwrap() + .to_string(), + private_key_pem + ); + fs::remove_file(ALICE_KEYSTORE_PATH_TEST_1).unwrap(); +} + +#[test] +fn test_wallet_convert_keystore_to_pem() { + let address = create_keystore_file_from_scratch(ALICE_KEYSTORE_PATH_TEST_2); + + let private_key = + Wallet::get_private_key_from_keystore_secret(ALICE_KEYSTORE_PATH_TEST_2, KEYSTORE_PASSWORD) + .unwrap(); + let private_key_str = private_key.to_string(); + let public_key = PublicKey::from(&private_key); + let public_key_str = public_key.to_string(); + + let pem_content = Wallet::generate_pem_content(&address, &private_key_str, &public_key_str); + write_to_file(&pem_content, ALICE_PEM_PATH_TEST); + assert_eq!( + private_key_str, + Wallet::get_wallet_keys_pem(ALICE_PEM_PATH_TEST).0 + ); + + fs::remove_file(ALICE_PEM_PATH_TEST).unwrap(); + fs::remove_file(ALICE_KEYSTORE_PATH_TEST_2).unwrap(); +} diff --git a/sdk/scenario-format/Cargo.toml b/sdk/scenario-format/Cargo.toml index b66e3403ce..a79c6c31a7 100644 --- a/sdk/scenario-format/Cargo.toml +++ b/sdk/scenario-format/Cargo.toml @@ -20,4 +20,4 @@ num-bigint = "0.4" num-traits = "0.2" hex = "0.4" sha3 = "0.10.8" -bech32 = "0.9.0" +bech32 = "0.11.0" diff --git a/sdk/scenario-format/src/value_interpreter/functions.rs b/sdk/scenario-format/src/value_interpreter/functions.rs index 32895e84d7..b4ce547ad7 100644 --- a/sdk/scenario-format/src/value_interpreter/functions.rs +++ b/sdk/scenario-format/src/value_interpreter/functions.rs @@ -1,5 +1,4 @@ use crate::value_interpreter::*; -use bech32::FromBase32; use sha3::{Digest, Keccak256}; pub const SC_ADDRESS_NUM_LEADING_ZEROS: usize = 8; @@ -71,6 +70,6 @@ pub(crate) fn sc_address_expression(input: &str, vm_type: &VMIdentifier) -> Vec< } pub(crate) fn bech32(input: &str) -> Vec { - let (_, decoded, _) = bech32::decode(input).expect("bech32 decode error"); - Vec::::from_base32(&decoded).expect("bech32 base64 decode error") + let (_hrp, decoded) = bech32::decode(input).expect("bech32 decode error"); + decoded } diff --git a/tools/mxpy-snippet-generator/Cargo.toml b/tools/mxpy-snippet-generator/Cargo.toml index 58236c7f78..838f8a1dc2 100644 --- a/tools/mxpy-snippet-generator/Cargo.toml +++ b/tools/mxpy-snippet-generator/Cargo.toml @@ -14,7 +14,7 @@ version = "0.52.3" path = "../../framework/base" [dependencies] -bech32 = "0.9" +bech32 = "0.11" num-bigint = "0.4" num-traits = "0.2" hex = "0.4" diff --git a/tools/mxpy-snippet-generator/src/helper_types.rs b/tools/mxpy-snippet-generator/src/helper_types.rs index d2cb746a51..e012ef2cb6 100644 --- a/tools/mxpy-snippet-generator/src/helper_types.rs +++ b/tools/mxpy-snippet-generator/src/helper_types.rs @@ -1,4 +1,3 @@ -use bech32::FromBase32; use multiversx_sc::types::heap::Address; use crate::constants::*; @@ -79,8 +78,7 @@ impl TransactionType { } pub fn bech32_to_bytes(bech32_address: &str) -> Address { - let (_, dest_address_bytes_u5, _) = bech32::decode(bech32_address).unwrap(); - let dest_address_bytes = Vec::::from_base32(&dest_address_bytes_u5).unwrap(); + let (_hrp, dest_address_bytes) = bech32::decode(bech32_address).unwrap(); if dest_address_bytes.len() != ADDRESS_LEN { panic!("Invalid address length after decoding") } diff --git a/vm/Cargo.toml b/vm/Cargo.toml index baf8ec3894..7e5349688d 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -18,7 +18,7 @@ categories = ["cryptography::cryptocurrencies", "development-tools::debugging"] [features] # not supported when compiling to wasm -wasm-incopatible = ["rand", "rand_seeder", "ed25519-dalek"] +wasm-incompatible = ["rand"] [dependencies] num-bigint = "0.4" @@ -31,8 +31,8 @@ hex-literal = "=0.4.1" bitflags = "=2.6.0" colored = "2.1.0" rand = { version= "0.8.5", optional = true } -rand_seeder = { version= "0.2.2", optional = true } -ed25519-dalek = { version = "1.0.1" , optional = true } +rand_seeder = "0.3.0" +ed25519-dalek = "2.1.0" [dependencies.multiversx-chain-vm-executor] version = "0.2.0" diff --git a/vm/src/crypto_functions.rs b/vm/src/crypto_functions.rs index 9d61e9ccc9..3dae63aad7 100644 --- a/vm/src/crypto_functions.rs +++ b/vm/src/crypto_functions.rs @@ -16,24 +16,29 @@ pub fn keccak256(data: &[u8]) -> [u8; KECCAK256_RESULT_LEN] { hasher.finalize().into() } -#[cfg(feature = "wasm-incopatible")] pub fn verify_ed25519(key: &[u8], message: &[u8], signature: &[u8]) -> bool { - use ed25519_dalek::*; + use ed25519_dalek::{Signature, Verifier, VerifyingKey}; - let public = PublicKey::from_bytes(key); - if public.is_err() { + let key_32: [u8; 32] = if let Ok(key_32) = key.try_into() { + key_32 + } else { return false; - } + }; + let signature_64: [u8; 64] = if let Ok(signature_64) = signature.try_into() { + signature_64 + } else { + return false; + }; - let sig = Signature::from_bytes(signature); - if sig.is_err() { + let verifying_key_result = VerifyingKey::from_bytes(&key_32); + let verifying_key = if let Ok(verifying_key) = verifying_key_result { + verifying_key + } else { return false; - } + }; - public.unwrap().verify(message, &sig.unwrap()).is_ok() -} + let sig = Signature::from_bytes(&signature_64); -#[cfg(not(feature = "wasm-incopatible"))] -pub fn verify_ed25519(_key: &[u8], _message: &[u8], _signature: &[u8]) -> bool { - panic!("verify_ed25519 not supported for wasm builds, feature `wasm-incopatible` needs to be enabled") + let result = verifying_key.verify(message, &sig); + result.is_ok() } diff --git a/vm/src/tx_mock.rs b/vm/src/tx_mock.rs index bd508d569e..ce63ddfe7a 100644 --- a/vm/src/tx_mock.rs +++ b/vm/src/tx_mock.rs @@ -37,12 +37,12 @@ pub use tx_panic::*; pub use tx_result::*; pub use tx_result_calls::*; -#[cfg(feature = "wasm-incopatible")] +#[cfg(feature = "wasm-incompatible")] mod blockchain_rng; -#[cfg(feature = "wasm-incopatible")] +#[cfg(feature = "wasm-incompatible")] pub use blockchain_rng::BlockchainRng; -#[cfg(not(feature = "wasm-incopatible"))] +#[cfg(not(feature = "wasm-incompatible"))] mod blockchain_rng_unsupported; -#[cfg(not(feature = "wasm-incopatible"))] +#[cfg(not(feature = "wasm-incompatible"))] pub use blockchain_rng_unsupported::BlockchainRng; diff --git a/vm/src/tx_mock/blockchain_rng_unsupported.rs b/vm/src/tx_mock/blockchain_rng_unsupported.rs index 698be4ac11..6339cbaffc 100644 --- a/vm/src/tx_mock/blockchain_rng_unsupported.rs +++ b/vm/src/tx_mock/blockchain_rng_unsupported.rs @@ -9,6 +9,6 @@ impl BlockchainRng { } pub fn next_bytes(&mut self, _length: usize) -> Vec { - panic!("BlockchainRng not supported for wasm builds, feature `wasm-incopatible` needs to be enabled") + panic!("BlockchainRng not supported for wasm builds, feature `wasm-incompatible` needs to be enabled") } }