diff --git a/Cargo.lock b/Cargo.lock index abeb3c37e1..19a7d86bac 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.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +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 = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +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.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" 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.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" 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", @@ -2886,20 +2930,20 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" 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,15 +2975,15 @@ 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" -version = "0.102.6" +version = "0.102.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" dependencies = [ "ring", "rustls-pki-types", @@ -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.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -3300,38 +3371,52 @@ 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", ] +[[package]] +name = "system-sc-interact" +version = "0.0.0" +dependencies = [ + "clap", + "multiversx-sc-snippets", + "serde", + "toml", +] + [[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 +3481,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.2" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -3459,9 +3544,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 +3566,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 +3594,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 +3727,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 +3800,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 +3808,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 +3834,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 +3846,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 +3856,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 +3869,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 +3889,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 +3900,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 +3910,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 +3965,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 +4097,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 +4130,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/Cargo.toml b/Cargo.toml index 2f599c6e03..651456eebd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "tools/mxpy-snippet-generator", "tools/payload-macro-generator", # "tools/plotter", + "tools/interactor-system-func-calls/", "vm", 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/Cargo.toml b/contracts/examples/adder/Cargo.toml index 422164f2b7..ed73efa416 100644 --- a/contracts/examples/adder/Cargo.toml +++ b/contracts/examples/adder/Cargo.toml @@ -14,4 +14,4 @@ path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] version = "0.52.3" -path = "../../../framework/scenario" +path = "../../../framework/scenario" \ No newline at end of file diff --git a/contracts/examples/adder/interact/.gitignore b/contracts/examples/adder/interact/.gitignore index b2630809de..336fa10df0 100644 --- a/contracts/examples/adder/interact/.gitignore +++ b/contracts/examples/adder/interact/.gitignore @@ -1,5 +1,6 @@ # Pem files are used for interactions, but shouldn't be committed *.pem +*.json !adder-owner.pem # Temporary storage of deployed contract address, so we can preserve the context between executions. diff --git a/contracts/examples/adder/interact/alice.json b/contracts/examples/adder/interact/alice.json new file mode 100644 index 0000000000..8f1a81514e --- /dev/null +++ b/contracts/examples/adder/interact/alice.json @@ -0,0 +1,23 @@ +{ + "version": 4, + "kind": "secretKey", + "id": "f2c5e236-9039-46cd-8df5-1efcd9466ead", + "address": "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", + "bech32": "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + "crypto": { + "ciphertext": "45de5198c6c477725abc17d26c6b5fc88b1ff22a67a8c4784b297d426d351cf5c891a4c92d63e04cf23f602f660b7b606ed1c5293c85ff40216d9e53c9a07c23", + "cipherparams": { + "iv": "d6442fb1d4c49106152baeb3c539ed2c" + }, + "cipher": "aes-128-ctr", + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "salt": "dd69d88742b9d27a0438a4554d4180b070d9af224ea8ff8225fdf74c8e272adb", + "n": 4096, + "r": 8, + "p": 1 + }, + "mac": "b277984f71d0e9b4a6597911775c0ee6d598002645b29f22021e595c2725d204" + } +} diff --git a/contracts/examples/adder/interact/src/basic_interact.rs b/contracts/examples/adder/interact/src/basic_interact.rs index 262eb13631..454060eb0d 100644 --- a/contracts/examples/adder/interact/src/basic_interact.rs +++ b/contracts/examples/adder/interact/src/basic_interact.rs @@ -41,7 +41,10 @@ async fn main() { basic_interact.print_sum().await; }, Some(basic_interact_cli::InteractCliCommand::Upgrade(args)) => { - basic_interact.upgrade(args.value).await + let owner_address = basic_interact.adder_owner_address.clone(); + basic_interact + .upgrade(args.value, &owner_address, None) + .await }, None => {}, } @@ -65,7 +68,15 @@ impl AdderInteract { let adder_owner_address = interactor.register_wallet(Wallet::from_pem_file("adder-owner.pem").unwrap()); - let wallet_address = interactor.register_wallet(test_wallets::mike()); + // PASSWORD: "alice" + // InsertPassword::Plaintext("alice".to_string()) || InsertPassword::StandardInput + let wallet_address = interactor.register_wallet( + Wallet::from_keystore_secret( + "alice.json", + InsertPassword::Plaintext("alice".to_string()), + ) + .unwrap(), + ); Self { interactor, @@ -93,7 +104,7 @@ impl AdderInteract { .interactor .tx() .from(&self.adder_owner_address) - .gas(3_000_000) + .gas(6_000_000) .typed(adder_proxy::AdderProxy) .init(0u32) .code(ADDER_CODE_PATH) @@ -123,7 +134,7 @@ impl AdderInteract { .typed(adder_proxy::AdderProxy) .init(0u32) .code(ADDER_CODE_PATH) - .gas(3_000_000) + .gas(6_000_000) .returns(ReturnsNewBech32Address) }); } @@ -151,7 +162,7 @@ impl AdderInteract { .to(self.state.current_adder_address()) .typed(adder_proxy::AdderProxy) .add(value) - .gas(3_000_000) + .gas(6_000_000) }); } @@ -176,7 +187,7 @@ impl AdderInteract { .tx() .from(&self.wallet_address) .to(self.state.current_adder_address()) - .gas(3_000_000) + .gas(6_000_000) .typed(adder_proxy::AdderProxy) .add(value) .prepare_async() @@ -201,45 +212,87 @@ impl AdderInteract { println!("sum: {sum}"); } - async fn upgrade(&mut self, new_value: u32) { - let response = self - .interactor - .tx() - .from(&self.wallet_address) - .to(self.state.current_adder_address()) - .gas(3_000_000) - .typed(adder_proxy::AdderProxy) - .upgrade(BigUint::from(new_value)) - .code_metadata(CodeMetadata::UPGRADEABLE) - .code(ADDER_CODE_PATH) - .returns(ReturnsResultUnmanaged) - .prepare_async() - .run() - .await; - - let sum = self - .interactor - .query() - .to(self.state.current_adder_address()) - .typed(adder_proxy::AdderProxy) - .sum() - .returns(ReturnsResultUnmanaged) - .prepare_async() - .run() - .await; - assert_eq!(sum, RustBigUint::from(new_value)); + async fn upgrade( + &mut self, + new_value: u32, + sender: &Bech32Address, + expected_result: Option<(u64, &str)>, + ) { + match expected_result { + Some((code, msg)) => { + let response = self + .interactor + .tx() + .from(sender) + .to(self.state.current_adder_address()) + .gas(6_000_000) + .typed(adder_proxy::AdderProxy) + .upgrade(new_value) + .code_metadata(CodeMetadata::UPGRADEABLE) + .code(ADDER_CODE_PATH) + .returns(ExpectError(code, msg)) + .prepare_async() + .run() + .await; + + println!("response: {response:?}"); + }, + None => { + self.interactor + .tx() + .from(sender) + .to(self.state.current_adder_address()) + .gas(6_000_000) + .typed(adder_proxy::AdderProxy) + .upgrade(new_value) + .code_metadata(CodeMetadata::UPGRADEABLE) + .code(ADDER_CODE_PATH) + .prepare_async() + .run() + .await; - println!("response: {response:?}"); + let sum = self + .interactor + .query() + .to(self.state.current_adder_address()) + .typed(adder_proxy::AdderProxy) + .sum() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() + .await; + + assert_eq!(sum, RustBigUint::from(new_value)); + }, + } } } #[tokio::test] #[ignore = "run on demand"] -async fn test() { +async fn upgrade_test() { let mut basic_interact = AdderInteract::init().await; + let wallet_address = basic_interact.wallet_address.clone(); + let adder_owner_address = basic_interact.adder_owner_address.clone(); + let error_not_owner = (4, "upgrade is allowed only for owner"); basic_interact.deploy().await; basic_interact.add(1u32).await; - basic_interact.upgrade(7u32).await; + // Sum will be 1 + basic_interact.print_sum().await; + + basic_interact + .upgrade(7u32, &adder_owner_address, None) + .await; + + // Sum will be the updated value of 7 + basic_interact.print_sum().await; + + basic_interact + .upgrade(10u32, &wallet_address, Some(error_not_owner)) + .await; + + // Sum will remain 7 + basic_interact.print_sum().await; } 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 a2bf2ec189..cdba7ce722 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..479b8931c3 100644 --- a/contracts/feature-tests/basic-features/scenarios/managed_decimal.scen.json +++ b/contracts/feature-tests/basic-features/scenarios/managed_decimal.scen.json @@ -141,6 +141,92 @@ "gas": "*", "refund": "*" } + }, + { + "step": "scCall", + "id": "6", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_addition_var", + "arguments": [ + "biguint:4|u32:2", + "biguint:5|u32:2" + ], + "gasLimit": "1,000,000,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [ + "biguint:9|u32:2" + ] + } + }, + { + "step": "scCall", + "id": "7", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_subtraction_var", + "arguments": [ + "biguint:9|u32:2", + "biguint:4|u32:2" + ], + "gasLimit": "1,000,000,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [ + "biguint:5|u32:2" + ] + } + }, + { + "step": "scCall", + "id": "8", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_subtraction_var", + "arguments": [ + "biguint:2|u32:2", + "biguint:8|u32:2" + ], + "gasLimit": "1,000,000,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "4", + "message": "str:cannot subtract because result would be negative", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "id": "9", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_eq_var", + "arguments": [ + "biguint:11|u32:2", + "biguint:11|u32:2" + ], + "gasLimit": "1,000,000,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [ + "true" + ], + "status": "", + "message": "*", + "gas": "*", + "refund": "*" + } } ] } \ 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..6ee41eaa4d 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": { @@ -105,6 +105,98 @@ "gas": "*", "refund": "*" } + }, + { + "step": "scCall", + "id": "managed_decimal_log2_var(23)", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_log2_var", + "arguments": [ + "0x00000005055ae8260000000009" + ], + "gasLimit": "1,000,000,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [ + "4,523648008" + ], + "status": "", + "message": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "id": "managed_decimal_ln_var(23)", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_ln_var", + "arguments": [ + "0x00000005055ae8260000000009" + ], + "gasLimit": "25,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [ + "+3,135553845" + ], + "status": "", + "message": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "id": "managed_decimal_ln_var(378,298)", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_ln_var", + "arguments": [ + "0x00000005581451628000000009" + ], + "gasLimit": "1,000,000,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [ + "0x0161cc16aa" + ], + "status": "", + "message": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "id": "managed_decimal_log2_var(218,345)", + "tx": { + "from": "address:an_account", + "to": "sc:basic-features", + "function": "managed_decimal_log2_var", + "arguments": [ + "0x0000000532d6604c4000000009" + ], + "gasLimit": "1,000,000,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [ + "7,770385327" + ], + "status": "", + "message": "*", + "gas": "*", + "refund": "*" + } } ] } \ 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/src/managed_decimal_features.rs b/contracts/feature-tests/basic-features/src/managed_decimal_features.rs index 556641cdc9..4bb3233c70 100644 --- a/contracts/feature-tests/basic-features/src/managed_decimal_features.rs +++ b/contracts/feature-tests/basic-features/src/managed_decimal_features.rs @@ -56,4 +56,47 @@ pub trait ManagedDecimalFeatures { ) -> ManagedDecimalSigned> { x.log2().unwrap_or_else(|| sc_panic!("cannot be zero")) } + + #[endpoint] + fn managed_decimal_addition_var( + &self, + first: ManagedDecimal, + second: ManagedDecimal, + ) -> ManagedDecimal { + first + second + } + + #[endpoint] + fn managed_decimal_subtraction_var( + &self, + first: ManagedDecimal, + second: ManagedDecimal, + ) -> ManagedDecimal { + first - second + } + + #[endpoint] + fn managed_decimal_eq_var( + &self, + first: ManagedDecimal, + second: ManagedDecimal, + ) -> bool { + first.eq(&second) + } + + #[endpoint] + fn managed_decimal_ln_var( + &self, + x: ManagedDecimal, + ) -> ManagedDecimalSigned> { + x.ln().unwrap_or_else(|| sc_panic!("cannot be zero")) + } + + #[endpoint] + fn managed_decimal_log2_var( + &self, + x: ManagedDecimal, + ) -> ManagedDecimalSigned> { + x.log2().unwrap_or_else(|| sc_panic!("cannot be zero")) + } } diff --git a/contracts/feature-tests/basic-features/tests/basic_features_managed_decimal_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_managed_decimal_test.rs index d4257fe078..238e4f0f4e 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_managed_decimal_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_managed_decimal_test.rs @@ -13,3 +13,8 @@ fn world() -> ScenarioWorld { fn managed_decimal_test() { world().run("scenarios/managed_decimal.scen.json"); } + +#[test] +fn managed_decimal_logarithm_test() { + world().run("scenarios/managed_decimal_logarithm.scen.json"); +} 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/basic-features/wasm/src/lib.rs b/contracts/feature-tests/basic-features/wasm/src/lib.rs index 18cd29cd68..b4501a4450 100644 --- a/contracts/feature-tests/basic-features/wasm/src/lib.rs +++ b/contracts/feature-tests/basic-features/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 404 +// Endpoints: 408 // Async Callback: 1 -// Total number of exported functions: 406 +// Total number of exported functions: 410 #![no_std] @@ -422,6 +422,11 @@ multiversx_sc_wasm_adapter::endpoints! { managed_decimal_into_raw_units => managed_decimal_into_raw_units managed_decimal_ln => managed_decimal_ln managed_decimal_log2 => managed_decimal_log2 + managed_decimal_addition_var => managed_decimal_addition_var + managed_decimal_subtraction_var => managed_decimal_subtraction_var + managed_decimal_eq_var => managed_decimal_eq_var + managed_decimal_ln_var => managed_decimal_ln_var + managed_decimal_log2_var => managed_decimal_log2_var ) } 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/tests/promises_feature_blackbox_test.rs b/contracts/feature-tests/composability/tests/promises_feature_blackbox_test.rs index 4fd4f4d1cc..2eb20508f8 100644 --- a/contracts/feature-tests/composability/tests/promises_feature_blackbox_test.rs +++ b/contracts/feature-tests/composability/tests/promises_feature_blackbox_test.rs @@ -85,3 +85,44 @@ fn test_multi_call_back_transfers() { .check_account(PROMISES_FEATURE_ADDRESS) .esdt_balance(TOKEN_ID_EXPR, token_amount); } + +#[test] +fn test_back_transfers_logs() { + let mut state = PromisesFeaturesTestState::new(); + let token_amount = BigUint::from(1000u64); + + let logs = state + .world + .tx() + .from(USER_ADDRESS) + .to(PROMISES_FEATURE_ADDRESS) + .typed(promises_feature_proxy::PromisesFeaturesProxy) + .forward_sync_retrieve_funds_bt(VAULT_ADDRESS, TOKEN_ID, 0u64, &token_amount) + .returns(ReturnsLogs) + .run(); + + assert!(!logs.is_empty() && !logs[0].topics.is_empty()); + assert_eq!(logs[0].address, PROMISES_FEATURE_ADDRESS); + assert_eq!(logs[0].endpoint, "transferValueOnly"); +} + +#[test] +fn test_multi_call_back_transfers_logs() { + let mut state = PromisesFeaturesTestState::new(); + let token_amount = BigUint::from(1000u64); + let half_token_amount = token_amount.clone() / 2u64; + + let logs = state + .world + .tx() + .from(USER_ADDRESS) + .to(PROMISES_FEATURE_ADDRESS) + .typed(promises_feature_proxy::PromisesFeaturesProxy) + .forward_sync_retrieve_funds_bt_twice(VAULT_ADDRESS, TOKEN_ID, 0u64, &half_token_amount) + .returns(ReturnsLogs) + .run(); + + assert!(!logs.is_empty() && !logs[0].topics.is_empty()); + assert_eq!(logs[0].address, PROMISES_FEATURE_ADDRESS); + assert_eq!(logs[0].endpoint, "transferValueOnly"); +} 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..a738579380 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.77" 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/markers/esdt_system_sc_address.rs b/framework/base/src/types/interaction/markers/esdt_system_sc_address.rs index b7b646ae16..e422553ca4 100644 --- a/framework/base/src/types/interaction/markers/esdt_system_sc_address.rs +++ b/framework/base/src/types/interaction/markers/esdt_system_sc_address.rs @@ -3,8 +3,8 @@ use multiversx_sc_codec::{EncodeErrorHandler, TopEncode, TopEncodeOutput}; use crate::{ abi::TypeAbiFrom, - api::{CallTypeApi, ManagedTypeApi}, - types::{AnnotatedValue, ManagedAddress, ManagedBuffer, TxScEnv, TxTo, TxToSpecified}, + api::ManagedTypeApi, + types::{AnnotatedValue, ManagedAddress, ManagedBuffer, TxEnv, TxTo, TxToSpecified}, }; /// Address of the system smart contract that manages ESDT. @@ -35,21 +35,21 @@ impl ESDTSystemSCAddress { } } -impl AnnotatedValue, ManagedAddress> for ESDTSystemSCAddress +impl AnnotatedValue> for ESDTSystemSCAddress where - Api: CallTypeApi, + Env: TxEnv, { - fn annotation(&self, _env: &TxScEnv) -> ManagedBuffer { + fn annotation(&self, _env: &Env) -> ManagedBuffer { ManagedBuffer::from(SYSTEM_SC_ADDRESS_ANNOTATION) } - fn to_value(&self, _env: &TxScEnv) -> ManagedAddress { + fn to_value(&self, _env: &Env) -> ManagedAddress { ESDTSystemSCAddress.to_managed_address() } } -impl TxTo> for ESDTSystemSCAddress where Api: CallTypeApi {} -impl TxToSpecified> for ESDTSystemSCAddress where Api: CallTypeApi {} +impl TxTo for ESDTSystemSCAddress where Env: TxEnv {} +impl TxToSpecified for ESDTSystemSCAddress where Env: TxEnv {} impl TopEncode for ESDTSystemSCAddress { fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> diff --git a/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs b/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs index 7b5e2fefb2..6e4978980a 100644 --- a/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs +++ b/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs @@ -82,11 +82,14 @@ where .original_result() } - pub fn esdt_local_burn( + pub fn esdt_local_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token: &TokenIdentifier, + token: &Arg0, nonce: u64, - amount: &BigUint, + amount: &Arg1, ) -> TxTypedCall { if nonce == 0 { return self @@ -107,11 +110,14 @@ where .original_result() } - pub fn esdt_local_mint( + pub fn esdt_local_mint< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token: &TokenIdentifier, + token: &Arg0, nonce: u64, - amount: &BigUint, + amount: &Arg1, ) -> TxTypedCall { if nonce == 0 { return self @@ -131,9 +137,9 @@ where .original_result() } - pub fn nft_add_multiple_uri( + pub fn nft_add_multiple_uri>>( self, - token_id: &TokenIdentifier, + token_id: &Arg0, nft_nonce: u64, new_uris: &ManagedVec>, ) -> TxTypedCall { @@ -151,9 +157,9 @@ where tx.original_result() } - pub fn nft_update_attributes( + pub fn nft_update_attributes>>( self, - token_id: &TokenIdentifier, + token_id: &Arg0, nft_nonce: u64, new_attributes: &T, ) -> TxTypedCall { @@ -167,13 +173,20 @@ where } #[allow(clippy::too_many_arguments)] - pub fn esdt_nft_create( + pub fn esdt_nft_create< + T: TopEncode, + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + >( self, - token: &TokenIdentifier, - amount: &BigUint, - name: &ManagedBuffer, - royalties: &BigUint, - hash: &ManagedBuffer, + token: &Arg0, + amount: &Arg1, + name: &Arg2, + royalties: &Arg3, + hash: &Arg4, attributes: &T, uris: &ManagedVec>, ) -> TxTypedCall { diff --git a/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs b/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs index 50325ed78d..10730ff0fc 100644 --- a/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs +++ b/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs @@ -4,8 +4,8 @@ use crate::{ api::CallTypeApi, types::{ BigUint, EgldPayment, EsdtLocalRole, EsdtTokenType, FunctionCall, ManagedAddress, - ManagedBuffer, NotPayable, OriginalResultMarker, TokenIdentifier, Tx, TxEnv, TxFrom, TxGas, - TxProxyTrait, TxTo, TxTypedCall, + ManagedBuffer, NotPayable, OriginalResultMarker, ProxyArg, TokenIdentifier, Tx, TxEnv, + TxFrom, TxGas, TxProxyTrait, TxTo, TxTypedCall, }, }; @@ -63,12 +63,16 @@ where { /// Produces a contract call to the ESDT system SC, /// which causes it to issue a new fungible ESDT token. - pub fn issue_fungible( + pub fn issue_fungible< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( self, issue_cost: BigUint, - token_display_name: &ManagedBuffer, - token_ticker: &ManagedBuffer, - initial_supply: &BigUint, + token_display_name: &Arg0, + token_ticker: &Arg1, + initial_supply: &Arg2, properties: FungibleTokenProperties, ) -> IssueCall { self.issue( @@ -94,20 +98,23 @@ where /// Produces a contract call to the ESDT system SC, /// which causes it to issue a new non-fungible ESDT token. - pub fn issue_non_fungible( + pub fn issue_non_fungible< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, issue_cost: BigUint, - token_display_name: &ManagedBuffer, - token_ticker: &ManagedBuffer, + token_display_name: &Arg0, + token_ticker: &Arg1, properties: NonFungibleTokenProperties, ) -> IssueCall { - let zero = BigUint::zero_ref(); + let zero = &BigUint::zero(); self.issue( issue_cost, EsdtTokenType::NonFungible, token_display_name, token_ticker, - &zero, + zero, TokenProperties { num_decimals: 0, can_freeze: properties.can_freeze, @@ -125,11 +132,14 @@ where /// Produces a contract call to the ESDT system SC, /// which causes it to issue a new semi-fungible ESDT token. - pub fn issue_semi_fungible( + pub fn issue_semi_fungible< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, issue_cost: BigUint, - token_display_name: &ManagedBuffer, - token_ticker: &ManagedBuffer, + token_display_name: &Arg0, + token_ticker: &Arg1, properties: SemiFungibleTokenProperties, ) -> IssueCall { let zero = BigUint::zero(); @@ -156,20 +166,23 @@ where /// Produces a contract call to the ESDT system SC, /// which causes it to register a new Meta ESDT token. - pub fn register_meta_esdt( + pub fn register_meta_esdt< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, issue_cost: BigUint, - token_display_name: &ManagedBuffer, - token_ticker: &ManagedBuffer, + token_display_name: &Arg0, + token_ticker: &Arg1, properties: MetaTokenProperties, ) -> IssueCall { - let zero = BigUint::zero(); + let zero = &BigUint::zero(); self.issue( issue_cost, EsdtTokenType::Meta, token_display_name, token_ticker, - &zero, + zero, TokenProperties { num_decimals: properties.num_decimals, can_freeze: properties.can_freeze, @@ -185,11 +198,14 @@ where ) } - pub fn issue_and_set_all_roles( + pub fn issue_and_set_all_roles< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, issue_cost: BigUint, - token_display_name: ManagedBuffer, - token_ticker: ManagedBuffer, + token_display_name: Arg0, + token_ticker: Arg1, token_type: EsdtTokenType, num_decimals: usize, ) -> IssueCall { @@ -212,13 +228,17 @@ where } /// Deduplicates code from all the possible issue functions - fn issue( + fn issue< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( self, issue_cost: BigUint, token_type: EsdtTokenType, - token_display_name: &ManagedBuffer, - token_ticker: &ManagedBuffer, - initial_supply: &BigUint, + token_display_name: &Arg0, + token_ticker: &Arg1, + initial_supply: &Arg2, properties: TokenProperties, ) -> IssueCall { let endpoint_name = match token_type { @@ -268,10 +288,10 @@ where /// Produces a contract call to the ESDT system SC, /// which causes it to mint more fungible ESDT tokens. /// It will fail if the SC is not the owner of the token. - pub fn mint( + pub fn mint>, Arg1: ProxyArg>>( self, - token_identifier: &TokenIdentifier, - amount: &BigUint, + token_identifier: &Arg0, + amount: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -283,10 +303,10 @@ where /// Produces a contract call to the ESDT system SC, /// which causes it to burn fungible ESDT tokens owned by the SC. - pub fn burn( + pub fn burn>, Arg1: ProxyArg>>( self, - token_identifier: &TokenIdentifier, - amount: &BigUint, + token_identifier: &Arg0, + amount: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -298,9 +318,9 @@ where /// The manager of an ESDT token may choose to suspend all transactions of the token, /// except minting, freezing/unfreezing and wiping. - pub fn pause( + pub fn pause>>( self, - token_identifier: &TokenIdentifier, + token_identifier: &Arg0, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -310,9 +330,9 @@ where } /// The reverse operation of `pause`. - pub fn unpause( + pub fn unpause>>( self, - token_identifier: &TokenIdentifier, + token_identifier: &Arg0, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -324,10 +344,13 @@ where /// The manager of an ESDT token may freeze the tokens held by a specific account. /// As a consequence, no tokens may be transferred to or from the frozen account. /// Freezing and unfreezing the tokens of an account are operations designed to help token managers to comply with regulations. - pub fn freeze( + pub fn freeze< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, - address: &ManagedAddress, + token_identifier: &Arg0, + address: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -338,10 +361,13 @@ where } /// The reverse operation of `freeze`, unfreezing, will allow further transfers to and from the account. - pub fn unfreeze( + pub fn unfreeze< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, - address: &ManagedAddress, + token_identifier: &Arg0, + address: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -355,10 +381,13 @@ where /// This operation is similar to burning the tokens, but the account must have been frozen beforehand, /// and it must be done by the token manager. /// Wiping the tokens of an account is an operation designed to help token managers to comply with regulations. - pub fn wipe( + pub fn wipe< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, - address: &ManagedAddress, + token_identifier: &Arg0, + address: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -371,11 +400,14 @@ where /// The manager of an ESDT token may freeze the NFT held by a specific Account. /// As a consequence, no NFT can be transferred to or from the frozen Account. /// Freezing and unfreezing a single NFT of an Account are operations designed to help token managers to comply with regulations. - pub fn freeze_nft( + pub fn freeze_nft< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, + token_identifier: &Arg0, nft_nonce: u64, - address: &ManagedAddress, + address: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -387,11 +419,14 @@ where } /// The reverse operation of `freeze`, unfreezing, will allow further transfers to and from the account. - pub fn unfreeze_nft( + pub fn unfreeze_nft< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, + token_identifier: &Arg0, nft_nonce: u64, - address: &ManagedAddress, + address: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -406,11 +441,14 @@ where /// This operation is similar to burning the quantity, but the Account must have been frozen beforehand, /// and it must be done by the token manager. /// Wiping the tokens of an Account is an operation designed to help token managers to comply with regulations. - pub fn wipe_nft( + pub fn wipe_nft< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, + token_identifier: &Arg0, nft_nonce: u64, - address: &ManagedAddress, + address: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -423,15 +461,15 @@ where /// This function converts an SFT to a metaESDT by adding decimals to its structure in the metachain ESDT System SC. /// This function as almost all in case of ESDT can be called only by the owner. - pub fn change_sft_to_meta_esdt( + pub fn change_sft_to_meta_esdt>>( self, - token_identifier: &TokenIdentifier, + token_identifier: &Arg0, num_decimals: usize, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) .raw_call("changeSFTToMetaESDT") - .argument(&token_identifier) + .argument(token_identifier) .argument(&num_decimals) .original_result() } @@ -440,10 +478,14 @@ where /// The metachain system SC will evaluate the arguments and call “ESDTSetRole@tokenId@listOfRoles” for the given address. /// This will be actually a cross shard call. /// This function as almost all in case of ESDT can be called only by the owner. - pub fn set_special_roles>( + pub fn set_special_roles< + RoleIter: Iterator, + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - address: &ManagedAddress, - token_identifier: &TokenIdentifier, + address: &Arg0, + token_identifier: &Arg1, roles_iter: RoleIter, ) -> TxTypedCall { let mut tx = self @@ -465,10 +507,14 @@ where /// The metachain system SC will evaluate the arguments and call “ESDTUnsetRole@tokenId@listOfRoles” for the given address. /// This will be actually a cross shard call. /// This function as almost all in case of ESDT can be called only by the owner. - pub fn unset_special_roles>( + pub fn unset_special_roles< + RoleIter: Iterator, + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - address: &ManagedAddress, - token_identifier: &TokenIdentifier, + address: &Arg0, + token_identifier: &Arg1, roles_iter: RoleIter, ) -> TxTypedCall { let mut tx = self @@ -486,10 +532,13 @@ where tx.original_result() } - pub fn transfer_ownership( + pub fn transfer_ownership< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, - new_owner: &ManagedAddress, + token_identifier: &Arg0, + new_owner: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -499,11 +548,14 @@ where .original_result() } - pub fn transfer_nft_create_role( + pub fn transfer_nft_create_role< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( self, - token_identifier: &TokenIdentifier, - old_creator: &ManagedAddress, - new_creator: &ManagedAddress, + token_identifier: &Arg0, + old_creator: &Arg1, + new_creator: &Arg1, ) -> TxTypedCall { self.wrapped_tx .payment(NotPayable) @@ -514,9 +566,9 @@ where .original_result() } - pub fn control_changes( + pub fn control_changes>>( self, - token_identifier: &TokenIdentifier, + token_identifier: &Arg0, property_arguments: &TokenPropertyArguments, ) -> TxTypedCall { let mut tx = self 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..111a7447c7 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.77" 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/result_handlers.rs b/framework/scenario/src/facade/result_handlers.rs index 1893647b45..33b5b1a495 100644 --- a/framework/scenario/src/facade/result_handlers.rs +++ b/framework/scenario/src/facade/result_handlers.rs @@ -2,6 +2,7 @@ mod expect_error; mod expect_message; mod expect_status; mod expect_value; +mod returns_logs; mod returns_message; mod returns_new_bech32_address; mod returns_new_token_identifier; @@ -12,6 +13,7 @@ pub use expect_error::ExpectError; pub use expect_message::ExpectMessage; pub use expect_status::ExpectStatus; pub use expect_value::ExpectValue; +pub use returns_logs::ReturnsLogs; pub use returns_message::ReturnsMessage; pub use returns_new_bech32_address::ReturnsNewBech32Address; pub use returns_new_token_identifier::ReturnsNewTokenIdentifier; diff --git a/framework/scenario/src/facade/result_handlers/returns_logs.rs b/framework/scenario/src/facade/result_handlers/returns_logs.rs new file mode 100644 index 0000000000..7aa4292fa2 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_logs.rs @@ -0,0 +1,24 @@ +use multiversx_sc::types::RHListItemExec; + +use crate::{ + multiversx_sc::types::{RHListItem, TxEnv}, + scenario_model::{Log, TxResponse}, +}; + +pub struct ReturnsLogs; + +impl RHListItem for ReturnsLogs +where + Env: TxEnv, +{ + type Returns = Vec; +} + +impl RHListItemExec for ReturnsLogs +where + Env: TxEnv, +{ + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + raw_result.logs.clone() + } +} 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/scenario/src/scenario/model/transaction/log.rs b/framework/scenario/src/scenario/model/transaction/log.rs index 27ebccfd08..803c521bbf 100644 --- a/framework/scenario/src/scenario/model/transaction/log.rs +++ b/framework/scenario/src/scenario/model/transaction/log.rs @@ -1,9 +1,9 @@ -use crate::scenario_model::BytesValue; +use multiversx_sc::types::Address; #[derive(Debug, Clone)] pub struct Log { - pub address: BytesValue, - pub endpoint: BytesValue, - pub topics: Vec, - pub data: BytesValue, + pub address: Address, + pub endpoint: String, + pub topics: Vec>, + pub data: Vec>, } diff --git a/framework/scenario/src/scenario/model/transaction/tx_response.rs b/framework/scenario/src/scenario/model/transaction/tx_response.rs index fd9721721f..8a7a5c4bf9 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_response.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_response.rs @@ -31,6 +31,16 @@ impl TxResponse { status: tx_result.result_status, message: tx_result.result_message, }, + logs: tx_result + .result_logs + .iter() + .map(|tx_log| Log { + address: Address::from_slice(tx_log.address.as_bytes()), + endpoint: tx_log.endpoint.to_string(), + topics: tx_log.topics.clone(), + data: tx_log.data.clone(), + }) + .collect(), ..Default::default() } } diff --git a/framework/scenario/src/scenario/tx_to_step/tx_to_step_transfer.rs b/framework/scenario/src/scenario/tx_to_step/tx_to_step_transfer.rs index d2bf9636c9..d2baa6bc6c 100644 --- a/framework/scenario/src/scenario/tx_to_step/tx_to_step_transfer.rs +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_transfer.rs @@ -1,6 +1,6 @@ use multiversx_sc::types::{Tx, TxEnv, TxFromSpecified, TxGas, TxPayment, TxToSpecified}; -use crate::scenario_model::TransferStep; +use crate::{imports::TxESDT, scenario_model::TransferStep}; use super::{address_annotated, gas_annotated, StepWrapper, TxToStep}; @@ -48,6 +48,12 @@ where let full_payment_data = payment.into_full_payment_data(env); if let Some(annotated_egld_payment) = full_payment_data.egld { step.tx.egld_value = annotated_egld_payment.into(); + } else { + step.tx.esdt_value = full_payment_data + .multi_esdt + .iter() + .map(TxESDT::from) + .collect(); } step diff --git a/framework/snippets/src/imports.rs b/framework/snippets/src/imports.rs index d416955e4c..a22c969887 100644 --- a/framework/snippets/src/imports.rs +++ b/framework/snippets/src/imports.rs @@ -4,7 +4,7 @@ pub use crate::{ dns_address_for_name, test_wallets, Interactor, InteractorPrepareAsync, StepBuffer, }; -pub use multiversx_sdk::wallet::Wallet; +pub use multiversx_sdk::{data::keystore::InsertPassword, wallet::Wallet}; pub use env_logger; pub use tokio; diff --git a/framework/snippets/src/network_response.rs b/framework/snippets/src/network_response.rs index d505e7a525..0140dd839e 100644 --- a/framework/snippets/src/network_response.rs +++ b/framework/snippets/src/network_response.rs @@ -1,7 +1,7 @@ use multiversx_sc_scenario::{ imports::{Address, ESDTSystemSCAddress}, multiversx_chain_vm::crypto_functions::keccak256, - scenario_model::{TxResponse, TxResponseStatus}, + scenario_model::{Log, TxResponse, TxResponseStatus}, }; use multiversx_sdk::{ data::transaction::{ApiSmartContractResult, Events, TransactionOnNetwork}, @@ -44,6 +44,7 @@ fn process_success(tx: &TransactionOnNetwork) -> TxResponse { out: process_out(tx), new_deployed_address: process_new_deployed_address(tx), new_issued_token_identifier: process_new_issued_token_identifier(tx), + logs: process_logs(tx), ..Default::default() } } @@ -58,18 +59,55 @@ fn process_out(tx: &TransactionOnNetwork) -> Vec> { } } +fn process_logs(tx: &TransactionOnNetwork) -> Vec { + if let Some(api_logs) = &tx.logs { + return api_logs + .events + .iter() + .map(|event| Log { + address: Address::from_slice(&event.address.to_bytes()), + endpoint: event.identifier.clone(), + topics: extract_topics(event), + data: extract_data(event), + }) + .collect::>(); + } + + Vec::new() +} + +fn extract_data(event: &Events) -> Vec> { + let mut out: Vec> = Vec::new(); + event + .data + .for_each(|data_field| out.push(data_field.clone().into_bytes())); + out +} + +fn extract_topics(event: &Events) -> Vec> { + event + .topics + .clone() + .unwrap_or_default() + .into_iter() + .map(|s| s.into_bytes()) + .collect() +} + fn process_out_from_log(tx: &TransactionOnNetwork) -> Option>> { if let Some(logs) = &tx.logs { logs.events.iter().rev().find_map(|event| { if event.identifier == "writeLog" { - if let Some(data) = &event.data { - let decoded_data = String::from_utf8(base64_decode(data)).unwrap(); + let mut out = Vec::new(); + event.data.for_each(|data_member| { + let decoded_data = String::from_utf8(base64_decode(data_member)).unwrap(); if decoded_data.starts_with('@') { - let out = decode_scr_data_or_panic(decoded_data.as_str()); - return Some(out); + let out_content = decode_scr_data_or_panic(decoded_data.as_str()); + out.extend(out_content); } - } + }); + return Some(out); } None @@ -103,25 +141,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 +179,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..31e6b6538a --- /dev/null +++ b/sdk/core/src/data/keystore.rs @@ -0,0 +1,61 @@ +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)] +pub enum InsertPassword { + Plaintext(String), + StandardInput, +} + +#[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/data/transaction.rs b/sdk/core/src/data/transaction.rs index 3ee2f25684..664ea3a08e 100644 --- a/sdk/core/src/data/transaction.rs +++ b/sdk/core/src/data/transaction.rs @@ -92,7 +92,27 @@ pub struct Events { pub address: Address, pub identifier: String, pub topics: Option>, - pub data: Option, + #[serde(default)] + pub data: LogData, +} + +#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(untagged)] +pub enum LogData { + #[default] + Empty, + String(String), + Vec(Vec), +} + +impl LogData { + pub fn for_each(&self, mut f: F) { + match self { + LogData::Empty => {}, + LogData::String(s) => f(s), + LogData::Vec(v) => v.iter().for_each(f), + } + } } // ApiLogs represents logs with changed fields' types in order to make it friendly for API's json @@ -152,6 +172,20 @@ pub struct TransactionStatus { pub data: Option, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TransactionProcessStatusData { + pub reason: String, + pub status: String, +} + +// TransactionProcessStatus holds a transaction's status response from the network obtained through the process-status API +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TransactionProcessStatus { + pub error: String, + pub code: String, + pub data: Option, +} + // ArgCreateTransaction will hold the transaction fields #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ArgCreateTransaction { @@ -197,3 +231,62 @@ pub struct SendTransactionsResponse { pub code: String, pub data: Option, } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn parse_event_log_0() { + let data = r#" +{ + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "completedTxEvent", + "topics": [], + "data": null, + "additionalData": null +} + "#; + + let event_log = serde_json::from_str::(data).unwrap(); + assert_eq!(event_log.data, LogData::Empty); + } + + #[test] + fn parse_event_log_1() { + let data = r#" +{ + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "completedTxEvent", + "topics": [], + "data": "data-string", + "additionalData": null +} + "#; + + let event_log = serde_json::from_str::(data).unwrap(); + assert_eq!(event_log.data, LogData::String("data-string".to_owned())); + } + + #[test] + fn parse_event_log_2() { + let data = r#" +{ + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "completedTxEvent", + "topics": [], + "data": [ + "data1", + "data2" + ], + "additionalData": null +} + "#; + + let event_log = serde_json::from_str::(data).unwrap(); + assert_eq!( + event_log.data, + LogData::Vec(vec!["data1".to_owned(), "data2".to_owned()]) + ); + } +} diff --git a/sdk/core/src/gateway/gateway_tx.rs b/sdk/core/src/gateway/gateway_tx.rs index 47aa8b5a83..88d9cd4ece 100644 --- a/sdk/core/src/gateway/gateway_tx.rs +++ b/sdk/core/src/gateway/gateway_tx.rs @@ -3,7 +3,8 @@ use crate::data::{ network_config::NetworkConfig, transaction::{ ArgCreateTransaction, ResponseTxCost, SendTransactionResponse, SendTransactionsResponse, - Transaction, TransactionInfo, TransactionOnNetwork, TransactionStatus, TxCostResponseData, + Transaction, TransactionInfo, TransactionOnNetwork, TransactionProcessStatus, + TransactionStatus, TxCostResponseData, }, vm::{ResponseVmValue, VmValueRequest, VmValuesResponseData}, }; @@ -96,6 +97,25 @@ impl GatewayProxy { } } + // get_transaction_process_status retrieves a transaction's status from the network using process-status API + pub async fn get_transaction_process_status(&self, hash: &str) -> Result<(String, String)> { + let endpoint = format!("transaction/{hash}/process-status"); + let endpoint = self.get_endpoint(endpoint.as_str()); + + let resp = self + .client + .get(endpoint) + .send() + .await? + .json::() + .await?; + + match resp.data { + None => Err(anyhow!("{}", resp.error)), + Some(b) => Ok((b.status, b.reason)), + } + } + // get_default_transaction_arguments will prepare the transaction creation argument by querying the account's info pub async fn get_default_transaction_arguments( &self, diff --git a/sdk/core/src/gateway/gateway_tx_retrieve.rs b/sdk/core/src/gateway/gateway_tx_retrieve.rs index 821713f972..61ba080430 100644 --- a/sdk/core/src/gateway/gateway_tx_retrieve.rs +++ b/sdk/core/src/gateway/gateway_tx_retrieve.rs @@ -16,22 +16,43 @@ impl GatewayProxy { let start_time = Instant::now(); loop { - match self.get_transaction_status(&tx_hash).await { - Ok(status) => { + match self.get_transaction_process_status(&tx_hash).await { + Ok((status, reason)) => { // checks if transaction status is final match status.as_str() { - "success" | "fail" => { + "success" => { // retrieve transaction info with results let transaction_info_with_results = self .get_transaction_info_with_results(&tx_hash) .await .unwrap(); + info!( "Transaction retrieved successfully, with status {}: {:#?}", status, transaction_info_with_results ); return transaction_info_with_results; }, + "fail" => { + // status failed and no reason means invalid transaction + if reason.is_empty() { + info!("Transaction failed. Invalid transaction: {tx_hash}"); + panic!("Transaction failed. Invalid transaction: {tx_hash}"); + } + + let result = parse_reason(&reason); + + match result { + Ok((code, err)) => { + info!("Transaction failed. Code: {code}, message: {err}"); + panic!("Transaction failed. Code: {code}, message: {err}") + }, + Err(err) => { + info!("Reason parsing error for failed transaction: {err}"); + panic!("Reason parsing error for failed transaction: {err}") + }, + } + }, _ => { continue; }, @@ -61,3 +82,23 @@ impl GatewayProxy { TransactionOnNetwork::default() } } + +pub fn parse_reason(reason: &str) -> Result<(u64, String), String> { + let parts: Vec<&str> = reason.split('@').collect(); + + if parts.len() < 2 { + return Err("Invalid reason format".to_string()); + } + + let error_code_hex = parts[1]; + let error_message_hex = parts[2]; + + let error_code = + u64::from_str_radix(error_code_hex, 16).expect("Failed to decode error code as u64"); + + let error_message = + String::from_utf8(hex::decode(error_message_hex).expect("Failed to decode error message")) + .expect("Failed to decode error message as UTF-8"); + + Ok((error_code, error_message)) +} diff --git a/sdk/core/src/wallet.rs b/sdk/core/src/wallet.rs index ab1b0a2f37..df9b9dc43a 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,58 @@ 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, insert_password: InsertPassword) -> Result { + let decryption_params = match insert_password { + InsertPassword::Plaintext(password) => { + Self::validate_keystore_password(file_path, password.to_string()).unwrap_or_else( + |e| { + panic!("Error: {:?}", e); + }, + ) + }, + InsertPassword::StandardInput => { + 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(decryption_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 +212,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/interactor-system-func-calls/.gitignore b/tools/interactor-system-func-calls/.gitignore new file mode 100644 index 0000000000..ae87d15dcd --- /dev/null +++ b/tools/interactor-system-func-calls/.gitignore @@ -0,0 +1,9 @@ +# Pem files are used for interactions, but shouldn't be committed +*.pem +!adder-owner.pem + +# Temporary storage of deployed contract address, so we can preserve the context between executions. +state.toml + +# Trace file of interactor tooling +interactor_trace.scen.json \ No newline at end of file diff --git a/tools/interactor-system-func-calls/Cargo.toml b/tools/interactor-system-func-calls/Cargo.toml new file mode 100644 index 0000000000..1cfd20f282 --- /dev/null +++ b/tools/interactor-system-func-calls/Cargo.toml @@ -0,0 +1,25 @@ +[[bin]] +name = "system-sc-interact" +path = "src/system_sc_interact.rs" + +[package] +name = "system-sc-interact" +version = "0.0.0" +publish = false +edition = "2021" +authors = ["you"] + +[dependencies] +toml = "0.8.6" + +[dependencies.clap] +version = "4.4.7" +features = ["derive"] + +[dependencies.serde] +version = "1.0" +features = ["derive"] + +[dependencies.multiversx-sc-snippets] +version = "=0.52.3" +path = "../../framework/snippets" diff --git a/tools/interactor-system-func-calls/README.md b/tools/interactor-system-func-calls/README.md new file mode 100644 index 0000000000..18d1501cf7 --- /dev/null +++ b/tools/interactor-system-func-calls/README.md @@ -0,0 +1,75 @@ +# System SC function calls interactor + +Fungible Tokens docs: https://docs.multiversx.com/tokens/fungible-tokens/ +NFT/SFT/Meta-ESDT docs: https://docs.multiversx.com/tokens/nft-tokens/ + +### Functions: + +- `issue_fungible_token`: Issues a fungible token, it registers the token and sends the initial supply to your wallet +- `issue_non_fungible_collection`: Issues an NFT Collection +- `issue_semi_fungible_collection`: Issues an SFT Collection +- `issue_token`: Registers any kind of token (Fungible/NFT/SFT/Meta-ESDT) and sets all the roles for it. This function doesn't transfer any tokens to your wallet +- `set_roles`: Sets the roles for your address over a specified token ID +- `mint_sft`: Mints an SFT/Meta-ESDT corresponding to a collection +- `register_meta_esdt`: Registers a Meta-ESDT token +- `change_sft_meta_esdt`: Changes an SFT to a Meta-ESDT +- `mint_token`: Mints a fungible token +- `burn_token`: Burns a token +- `pause_token`: Pauses all the transfers for a token +- `unpause_token`: Reverse function of `pause_token` +- `freeze_token`: Freezes a token for an address +- `unfreeze_token`: Reverse function of `freeze_token` +- `freeze_nft`: Freezes an NFT/SFT/Meta-ESDT token for an address +- `unfreeze_nft`: Reverse function of `freeze_nft` +- `wipe_token`: Wipes a token from an address +- `wipe_nft`: Wipes an NFT/SFT/Meta-ESDT token from an address +- `mint_nft`: Mints an NFT corresponding to a collection +- `unset roles`: Unsets the roles for an address over a specified tokenID +- `transfer_ownership`: Transfers the ownership of your token to another address +- `transfer_nft_create_role`: Transfers the NFT Create role to a new address +- `control_changes`: Sets/Unsets properties of a specified tokenID + +### How to use tips + +#### Token types for `issue_token` function + +For CLI use, insert one of the numbers below for the `token-type` parameter + +- 0 => `Fungible` +- 1 => `NonFungible` +- 2 => `SemiFungible` +- 3 => `Meta` +- any other number => `Invalid` + +#### Set/Unset roles + +Before trying to make any kind of interaction with a token (e.g. Mint, Burn, Transfer) you should set the neccessary roles, even if you are the owner of the token. For CLI use, insert one or more numbers from below for the `roles` parameter, each corresponding to a role, each separated by one comma `e.g. --roles 1,2,8` + +- 1 => `Mint` +- 2 => `Burn` +- 3 => `NftCreate` +- 4 => `NftAddQuantity` +- 5 => `NftBurn` +- 6 => `NftAddUri` +- 7 => `NftUpdateAttributes` +- 8 => `Transfer` +- any other number => `None` + +#### Issue fungible token + +- Method 1: `issue_fungible_token` (set the token properties inside the function) +- Method 2: `issue_token`-> `set_roles` (**Mint** role needed for minting the tokens) -> `mint_token` to receive the tokens in your wallet + +#### Issue NFT Collection + Mint an NFT + +- `issue_non_fungible_collection`/`issue_token` -> `set_roles` (**NFTCreate** role needed for minting) -> Mint an NFT by calling `mint_nft` + +#### Issue SFT Collection + +- Issue Collection: `issue_semi_fungible_collection`/`issue_token` -> `set_roles` (**NFTCreate** role needed for minting) -> Mint the amount of SFTs wantes by calling `mint_sft` + +### Register a Meta-ESDT + +- `register_meta_esdt` -> `set_roles`(**NFTCreate**) -> `mint_sft` to mint the Meta-ESDT + +By using `set_roles`(**NFTAddQuantity**) -> `mint_token` you can add quantity to a Meta-ESDT/SFT with a specified nonce diff --git a/tools/interactor-system-func-calls/config.toml b/tools/interactor-system-func-calls/config.toml new file mode 100644 index 0000000000..61ac8dbf87 --- /dev/null +++ b/tools/interactor-system-func-calls/config.toml @@ -0,0 +1 @@ +gateway = 'https://devnet-gateway.multiversx.com' diff --git a/tools/interactor-system-func-calls/src/system_sc_interact.rs b/tools/interactor-system-func-calls/src/system_sc_interact.rs new file mode 100644 index 0000000000..0558eba3c1 --- /dev/null +++ b/tools/interactor-system-func-calls/src/system_sc_interact.rs @@ -0,0 +1,761 @@ +mod system_sc_interact_cli; +mod system_sc_interact_config; +mod system_sc_interact_state; + +use clap::Parser; +use system_sc_interact_cli::NftDummyAttributes; +use system_sc_interact_config::Config; +use system_sc_interact_state::State; + +use multiversx_sc_snippets::imports::*; + +#[tokio::main] +async fn main() { + env_logger::init(); + + let mut basic_interact = SysFuncCallsInteract::init().await; + + let cli = system_sc_interact_cli::InteractCli::parse(); + match &cli.command { + Some(system_sc_interact_cli::InteractCliCommand::IssueToken(args)) => { + basic_interact + .issue_token( + args.cost.clone(), + args.display_name.as_bytes(), + args.ticker.as_bytes(), + args.num_decimals, + args.token_type.into(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::Mint(args)) => { + basic_interact + .mint_token( + args.token_id.clone().as_bytes(), + args.nonce, + args.amount.clone(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::SetRoles(args)) => { + basic_interact + .set_roles( + args.token_id.as_bytes(), + args.roles + .clone() + .into_iter() + .map(EsdtLocalRole::from) + .collect(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::Burn(args)) => { + basic_interact + .burn_token(args.token_id.as_bytes(), args.nonce, args.amount.clone()) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::PauseToken(args)) => { + basic_interact.pause_token(args.token_id.as_bytes()).await; + }, + Some(system_sc_interact_cli::InteractCliCommand::UnpauseToken(args)) => { + basic_interact.unpause_token(args.token_id.as_bytes()).await; + }, + Some(system_sc_interact_cli::InteractCliCommand::FreezeToken(args)) => { + basic_interact + .freeze_token( + args.token_id.as_bytes(), + &Bech32Address::from_bech32_string(args.address.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::UnfreezeToken(args)) => { + basic_interact + .unfreeze_token( + args.token_id.as_bytes(), + &Bech32Address::from_bech32_string(args.address.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::FreezeNFT(args)) => { + basic_interact + .freeze_nft( + args.token_id.as_bytes(), + args.nft_nonce, + &Bech32Address::from_bech32_string(args.address.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::UnfreezeNFT(args)) => { + basic_interact + .unfreeze_nft( + args.token_id.as_bytes(), + args.nft_nonce, + &Bech32Address::from_bech32_string(args.address.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::WipeToken(args)) => { + basic_interact + .wipe_token( + args.token_id.as_bytes(), + &Bech32Address::from_bech32_string(args.address.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::WipeNFT(args)) => { + basic_interact + .wipe_nft( + args.token_id.as_bytes(), + args.nft_nonce, + &Bech32Address::from_bech32_string(args.address.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::IssueNFTCollection(args)) => { + basic_interact + .issue_non_fungible_collection( + args.cost.clone(), + args.display_name.as_bytes(), + args.ticker.as_bytes(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::CreateNFT(args)) => { + basic_interact + .mint_nft( + args.token_id.as_bytes(), + args.amount.clone(), + args.name.as_bytes(), + args.royalties, + args.hash.as_bytes(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::IssueFungible(args)) => { + basic_interact + .issue_fungible_token( + args.cost.clone(), + args.display_name.as_bytes(), + args.ticker.as_bytes(), + args.supply.clone(), + args.num_decimals, + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::IssueSftCollection(args)) => { + basic_interact + .issue_semi_fungible_collection( + args.cost.clone(), + args.display_name.as_bytes(), + args.ticker.as_bytes(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::MintSft(args)) => { + basic_interact + .mint_sft( + args.token_id.as_bytes(), + args.amount.clone(), + args.name.as_bytes(), + args.royalties, + args.hash.as_bytes(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::RegisterMetaEsdt(args)) => { + basic_interact + .register_meta_esdt( + args.cost.clone(), + args.display_name.as_bytes(), + args.ticker.as_bytes(), + args.num_decimals, + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::ChangeSftMetaEsdt(args)) => { + basic_interact + .change_sft_meta_esdt(args.token_id.as_bytes(), args.num_decimals) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::UnsetRoles(args)) => { + basic_interact + .unset_roles( + &Bech32Address::from_bech32_string(args.address.clone()), + args.token_id.as_bytes(), + args.roles + .clone() + .into_iter() + .map(EsdtLocalRole::from) + .collect(), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::TransferOwnership(args)) => { + basic_interact + .transfer_ownership( + args.token_id.as_bytes(), + &Bech32Address::from_bech32_string(args.new_owner.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::TransferNftCreateRole(args)) => { + basic_interact + .transfer_nft_create_role( + args.token_id.as_bytes(), + &Bech32Address::from_bech32_string(args.old_owner.clone()), + &Bech32Address::from_bech32_string(args.new_owner.clone()), + ) + .await; + }, + Some(system_sc_interact_cli::InteractCliCommand::ControlChanges(args)) => { + basic_interact + .control_changes(args.token_id.as_bytes()) + .await; + }, + + None => {}, + } +} + +#[allow(unused)] +struct SysFuncCallsInteract { + interactor: Interactor, + wallet_address: Bech32Address, + state: State, +} + +impl SysFuncCallsInteract { + async fn init() -> Self { + let config = Config::load_config(); + let mut interactor = Interactor::new(config.gateway()).await; + + let wallet_address = interactor.register_wallet(test_wallets::alice()); + + Self { + interactor, + wallet_address: wallet_address.into(), + state: State::load_state(), + } + } + + async fn issue_fungible_token( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + initial_supply: RustBigUint, + num_decimals: usize, + ) { + println!("Issuing fungible token..."); + + let res = self + .interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .issue_fungible( + issue_cost.into(), + &token_display_name, + &token_ticker, + &initial_supply, + FungibleTokenProperties { + num_decimals, + can_freeze: true, + can_wipe: true, + can_pause: true, + can_mint: true, + can_burn: true, + can_change_owner: true, + can_upgrade: true, + can_add_special_roles: true, + }, + ) + .returns(ReturnsNewTokenIdentifier) + .prepare_async() + .run() + .await; + + println!("TOKEN ID: {:?}", res); + } + + async fn issue_non_fungible_collection( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + ) { + println!("Issuing NFT Collection..."); + + let nft_collection_id = self + .interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .issue_non_fungible( + issue_cost.into(), + &token_display_name, + &token_ticker, + NonFungibleTokenProperties { + can_freeze: true, + can_wipe: true, + can_pause: true, + can_transfer_create_role: true, + can_change_owner: true, + can_upgrade: true, + can_add_special_roles: true, + }, + ) + .returns(ReturnsNewTokenIdentifier) + .prepare_async() + .run() + .await; + + println!("NFT Collection ID: {:?}", nft_collection_id); + } + + async fn issue_semi_fungible_collection( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + ) { + println!("Issuing SFT Collection..."); + + let sft_collection_id = self + .interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .issue_semi_fungible( + issue_cost.into(), + &token_display_name, + &token_ticker, + SemiFungibleTokenProperties { + can_freeze: true, + can_wipe: true, + can_pause: true, + can_transfer_create_role: true, + can_change_owner: true, + can_upgrade: true, + can_add_special_roles: true, + }, + ) + .returns(ReturnsNewTokenIdentifier) + .prepare_async() + .run() + .await; + + println!("SFT Collection ID: {:?}", sft_collection_id); + } + + async fn issue_token( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + num_decimals: usize, + token_type: EsdtTokenType, + ) { + println!("Registering token..."); + + let token_id = self + .interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .issue_and_set_all_roles( + issue_cost.into(), + token_display_name, + token_ticker, + token_type, + num_decimals, + ) + .returns(ReturnsNewTokenIdentifier) + .prepare_async() + .run() + .await; + + println!("TOKEN ID: {:?}", token_id); + } + + async fn set_roles(&mut self, token_id: &[u8], roles: Vec) { + let wallet_address = &self.wallet_address.clone().into_address(); + println!("Setting the following roles: {:?}", roles); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .set_special_roles( + &ManagedAddress::from_address(wallet_address), + &TokenIdentifier::from(token_id), + roles.into_iter(), + ) + .prepare_async() + .run() + .await; + } + + async fn mint_sft( + &mut self, + token_id: &[u8], + amount: RustBigUint, + name: &[u8], + royalties: u64, + hash: &[u8], + ) { + println!("Minting SFT..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_nft_create( + &token_id, + &amount, + &name, + &royalties, + &hash, + &NftDummyAttributes { + creation_epoch: 2104, + cool_factor: 5, + }, + &ManagedVec::new(), + ) + .prepare_async() + .run() + .await; + } + + async fn register_meta_esdt( + &mut self, + issue_cost: RustBigUint, + token_display_name: &[u8], + token_ticker: &[u8], + num_decimals: usize, + ) { + println!("Registering meta ESDT..."); + + let meta_esdt = self + .interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .register_meta_esdt( + issue_cost.into(), + &token_display_name, + &token_ticker, + MetaTokenProperties { + num_decimals, + can_freeze: true, + can_wipe: true, + can_transfer_create_role: true, + can_change_owner: true, + can_upgrade: true, + can_pause: true, + can_add_special_roles: true, + }, + ) + .returns(ReturnsNewTokenIdentifier) + .prepare_async() + .run() + .await; + + println!("Meta-ESDT ID: {:?}", meta_esdt); + } + + async fn change_sft_meta_esdt(&mut self, token_id: &[u8], num_decimals: usize) { + println!("Changing SFT to Meta-ESDT..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .change_sft_to_meta_esdt(&token_id, num_decimals) + .prepare_async() + .run() + .await; + } + + async fn mint_token(&mut self, token_id: &[u8], nonce: u64, amount: RustBigUint) { + println!("Minting tokens..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_local_mint(&token_id, nonce, &amount) + .prepare_async() + .run() + .await; + } + + async fn burn_token(&mut self, token_id: &[u8], nonce: u64, amount: RustBigUint) { + println!("Burning tokens..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_local_burn(&token_id, nonce, &amount) + .prepare_async() + .run() + .await; + } + + async fn pause_token(&mut self, token_id: &[u8]) { + println!("Pausing token..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .pause(&token_id) + .prepare_async() + .run() + .await; + } + + async fn unpause_token(&mut self, token_id: &[u8]) { + println!("Unpausing token..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .unpause(&token_id) + .prepare_async() + .run() + .await; + } + + async fn freeze_token(&mut self, token_id: &[u8], address: &Bech32Address) { + println!("Freezing token..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .freeze(&token_id, &address) + .prepare_async() + .run() + .await; + } + + async fn unfreeze_token(&mut self, token_id: &[u8], address: &Bech32Address) { + println!("Unfreezing token..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .unfreeze(&token_id, &address) + .prepare_async() + .run() + .await; + } + + async fn freeze_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { + println!("Freezing NFT/SFT/Meta-ESDT..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .freeze_nft(&token_id, nonce, &address) + .prepare_async() + .run() + .await; + } + + async fn unfreeze_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { + println!("Unfreezing NFT/SFT/Meta-ESDT..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .unfreeze_nft(&token_id, nonce, &address) + .prepare_async() + .run() + .await; + } + + async fn wipe_token(&mut self, token_id: &[u8], address: &Bech32Address) { + println!("Wiping token..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .wipe(&token_id, &address) + .prepare_async() + .run() + .await; + } + + async fn wipe_nft(&mut self, token_id: &[u8], nonce: u64, address: &Bech32Address) { + println!("Wiping NFT/SFT/Meta-ESDT..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .wipe_nft(&token_id, nonce, &address) + .prepare_async() + .run() + .await; + } + + async fn mint_nft( + &mut self, + token_id: &[u8], + amount: RustBigUint, + name: &[u8], + royalties: u64, + hash: &[u8], + ) { + println!("Minting NFT..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(&self.wallet_address) + .gas(100_000_000u64) + .typed(UserBuiltinProxy) + .esdt_nft_create( + &token_id, + &amount, + &name, + &royalties, + &hash, + &NftDummyAttributes { + creation_epoch: 2104, + cool_factor: 5, + }, + &ManagedVec::new(), + ) + .prepare_async() + .run() + .await; + } + + async fn unset_roles( + &mut self, + address: &Bech32Address, + token_id: &[u8], + roles: Vec, + ) { + println!("Unsetting the following roles: {:?}", roles); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .unset_special_roles(&address, &token_id, roles.into_iter()) + .prepare_async() + .run() + .await; + } + + async fn transfer_ownership(&mut self, token_id: &[u8], new_owner: &Bech32Address) { + println!("Transferring token ownership..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .transfer_ownership(&token_id, &new_owner) + .prepare_async() + .run() + .await; + } + + async fn transfer_nft_create_role( + &mut self, + token_id: &[u8], + old_owner: &Bech32Address, + new_owner: &Bech32Address, + ) { + println!("Transferring NFT create role..."); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .transfer_nft_create_role(&token_id, &old_owner, &new_owner) + .prepare_async() + .run() + .await; + } + + async fn control_changes(&mut self, token_id: &[u8]) { + println!("Control changes"); + + self.interactor + .tx() + .from(&self.wallet_address) + .to(ESDTSystemSCAddress) + .gas(100_000_000u64) + .typed(ESDTSystemSCProxy) + .control_changes( + &token_id, + &TokenPropertyArguments { + can_freeze: Some(true), + can_wipe: Some(true), + can_pause: Some(true), + can_transfer_create_role: Some(true), + can_mint: Some(true), + can_burn: Some(true), + can_change_owner: Some(true), + can_upgrade: Some(true), + can_add_special_roles: Some(true), + }, + ) + .prepare_async() + .run() + .await; + } +} diff --git a/tools/interactor-system-func-calls/src/system_sc_interact_cli.rs b/tools/interactor-system-func-calls/src/system_sc_interact_cli.rs new file mode 100644 index 0000000000..6e958fbdb3 --- /dev/null +++ b/tools/interactor-system-func-calls/src/system_sc_interact_cli.rs @@ -0,0 +1,286 @@ +use clap::{Args, Parser, Subcommand}; +use multiversx_sc_snippets::{imports::*, multiversx_sc::proxy_imports::*}; + +/// SysFuncCalls Interact CLI +#[derive(Default, PartialEq, Eq, Debug, Parser)] +#[command(version, about)] +#[command(propagate_version = true)] +pub struct InteractCli { + #[command(subcommand)] + pub command: Option, +} + +/// SysFuncCalls Interact CLI Commands +#[derive(Clone, PartialEq, Eq, Debug, Subcommand)] +pub enum InteractCliCommand { + #[command(name = "issue-token", about = "Issues a token")] + IssueToken(IssueTokenArgs), + #[command(name = "mint", about = "Mints fungible tokens")] + Mint(MintArgs), + #[command(name = "set-roles", about = "Sets roles")] + SetRoles(SetRolesArgs), + #[command(name = "burn", about = "Burns fungible tokens")] + Burn(BurnArgs), + #[command(name = "pause-token", about = "Pauses a fungible token")] + PauseToken(PauseTokenArgs), + #[command(name = "unpause-token", about = "Unpauses a fungible token")] + UnpauseToken(PauseTokenArgs), + #[command( + name = "freeze-token", + about = "Freezes a fungible token for an address" + )] + FreezeToken(FreezeTokenArgs), + #[command( + name = "unfreeze-token", + about = "Unfreezes a fungible token for an address" + )] + UnfreezeToken(FreezeTokenArgs), + #[command( + name = "freeze-nft", + about = "Freezes a non-fungible token for an address" + )] + FreezeNFT(FreezeNFTArgs), + #[command( + name = "unfreeze-nft", + about = "Unfreezes a non-fungible token for an address" + )] + UnfreezeNFT(FreezeNFTArgs), + #[command(name = "wipe-token", about = "Wipes a fungible token for an address")] + WipeToken(WipeTokenArgs), + #[command( + name = "wipe-nft", + about = "Freezes a non-fungible token for an address" + )] + WipeNFT(WipeNFTArgs), + #[command(name = "issue-nft-collection", about = "Create a NFT Collection")] + IssueNFTCollection(IssueNftCollectionArgs), + #[command(name = "create-nft", about = "Issue a NFT")] + CreateNFT(CreateNFTArgs), + #[command( + name = "issue-fungible", + about = "Issues fungible tokens and sends them to your wallet" + )] + IssueFungible(IssueFungibleArgs), + #[command(name = "issue-sft-collection", about = "Issues a SFT")] + IssueSftCollection(IssueSftArgs), + #[command(name = "mint-sft", about = "Mints a SFT")] + MintSft(MintSFTArgs), + #[command(name = "register-meta-esdt", about = "Registers a meta ESDT")] + RegisterMetaEsdt(RegisterMetaEsdtArgs), + #[command(name = "change-sft-meta-esdt", about = "Changes a SFT to a Meta ESDT")] + ChangeSftMetaEsdt(ChangeSftMetaEsdtArgs), + #[command(name = "unset-roles", about = "Unsets the roles of a token")] + UnsetRoles(UnsetRolesArgs), + #[command(name = "transfer-ownership", about = "Transfers ownership of a token")] + TransferOwnership(TransferOwnershipArgs), + #[command(name = "transfer-nft-create-role", about = "Transfers NFT create role")] + TransferNftCreateRole(TransferNftCreateRoleArgs), + #[command(name = "control-changes", about = "Controls changes")] + ControlChanges(ControlChangesArgs), +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct IssueTokenArgs { + #[arg(short = 'c', long = "cost", default_value = "50000000000000000")] + pub cost: RustBigUint, + #[arg(short = 'd', long = "display-name")] + pub display_name: String, + #[arg(long = "token-ticker")] + pub ticker: String, + #[arg(long = "token-type")] + pub token_type: u8, + #[arg(long = "num-decimals")] + pub num_decimals: usize, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct MintArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(short = 'n', long = "nonce")] + pub nonce: u64, + #[arg(long = "amount")] + pub amount: RustBigUint, +} + +#[derive(Clone, Debug, PartialEq, Eq, Parser)] +pub struct SetRolesArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(long = "roles", value_delimiter = ',')] + pub roles: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct BurnArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(short = 'n', long = "nonce")] + pub nonce: u64, + #[arg(long = "amount")] + pub amount: RustBigUint, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct IssueFungibleArgs { + #[arg(short = 'c', long = "cost", default_value = "50000000000000000")] + pub cost: RustBigUint, + #[arg(long = "display-name")] + pub display_name: String, + #[arg(long = "token-ticker")] + pub ticker: String, + #[arg(long = "num-decimals")] + pub num_decimals: usize, + #[arg(short = 's', long = "supply")] + pub supply: RustBigUint, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct IssueNftCollectionArgs { + #[arg(short = 'c', long = "cost", default_value = "50000000000000000")] + pub cost: RustBigUint, + #[arg(short = 'd', long = "display-name")] + pub display_name: String, + #[arg(long = "token-ticker")] + pub ticker: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct IssueSftArgs { + #[arg(short = 'c', long = "cost", default_value = "50000000000000000")] + pub cost: RustBigUint, + #[arg(short = 'd', long = "display-name")] + pub display_name: String, + #[arg(long = "token-ticker")] + pub ticker: String, +} + +#[derive(TopEncode, Clone, Debug, PartialEq, Eq)] +pub struct NftDummyAttributes { + pub creation_epoch: u64, + pub cool_factor: u8, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct MintSFTArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(short = 'a', long = "amount")] + pub amount: RustBigUint, + #[arg(short = 'n', long = "name")] + pub name: String, + #[arg(short = 'r', long = "royalties")] + pub royalties: u64, + #[arg(long = "hash")] + pub hash: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct RegisterMetaEsdtArgs { + #[arg(short = 'c', long = "cost", default_value = "50000000000000000")] + pub cost: RustBigUint, + #[arg(short = 'd', long = "display-name")] + pub display_name: String, + #[arg(long = "token-ticker")] + pub ticker: String, + #[arg(long = "num-decimals")] + pub num_decimals: usize, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct ChangeSftMetaEsdtArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(long = "num-decimals")] + pub num_decimals: usize, +} + +#[derive(Clone, Debug, PartialEq, Eq, Parser)] +pub struct UnsetRolesArgs { + #[arg(short = 'a', long = "address")] + pub address: String, + #[arg(long = "token-id")] + pub token_id: String, + #[arg(long = "roles", value_delimiter = ',')] + pub roles: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct TransferOwnershipArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(long = "new-owner")] + pub new_owner: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct TransferNftCreateRoleArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(long = "old-owner")] + pub old_owner: String, + #[arg(long = "new-owner")] + pub new_owner: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct PauseTokenArgs { + #[arg(long = "token-id", default_value = "")] + pub token_id: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct FreezeTokenArgs { + #[arg(long = "token-id", default_value = "")] + pub token_id: String, + #[arg(short = 'a', long = "address")] + pub address: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct FreezeNFTArgs { + #[arg(long = "token-id", default_value = "")] + pub token_id: String, + #[arg(long = "nonce")] + pub nft_nonce: u64, + #[arg(short = 'a', long = "address")] + pub address: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct WipeTokenArgs { + #[arg(long = "token-id", default_value = "")] + pub token_id: String, + #[arg(short = 'a', long = "address")] + pub address: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct WipeNFTArgs { + #[arg(long = "token-id", default_value = "")] + pub token_id: String, + #[arg(long = "nonce")] + pub nft_nonce: u64, + #[arg(short = 'a', long = "address")] + pub address: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct CreateNFTArgs { + #[arg(long = "token-id")] + pub token_id: String, + #[arg(short = 'a', long = "amount")] + pub amount: RustBigUint, + #[arg(short = 'n', long = "name")] + pub name: String, + #[arg(long = "hash")] + pub hash: String, + #[arg(short = 'r', long = "royalities")] + pub royalties: u64, +} + +#[derive(Clone, Debug, PartialEq, Eq, Args)] +pub struct ControlChangesArgs { + #[arg(long = "token-id")] + pub token_id: String, +} diff --git a/tools/interactor-system-func-calls/src/system_sc_interact_config.rs b/tools/interactor-system-func-calls/src/system_sc_interact_config.rs new file mode 100644 index 0000000000..4495f069b8 --- /dev/null +++ b/tools/interactor-system-func-calls/src/system_sc_interact_config.rs @@ -0,0 +1,26 @@ +use serde::Deserialize; +use std::io::Read; + +/// Config file +const CONFIG_FILE: &str = "../config.toml"; + +/// SysFuncCalls Interact configuration +#[derive(Debug, Deserialize)] +pub struct Config { + gateway: String, +} + +impl Config { + // Deserializes config from file + pub fn load_config() -> Self { + let mut file = std::fs::File::open(CONFIG_FILE).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + toml::from_str(&content).unwrap() + } + + // Returns the gateway + pub fn gateway(&self) -> &str { + &self.gateway + } +} diff --git a/tools/interactor-system-func-calls/src/system_sc_interact_state.rs b/tools/interactor-system-func-calls/src/system_sc_interact_state.rs new file mode 100644 index 0000000000..459b6f0bf5 --- /dev/null +++ b/tools/interactor-system-func-calls/src/system_sc_interact_state.rs @@ -0,0 +1,38 @@ +use multiversx_sc_snippets::imports::*; +use serde::{Deserialize, Serialize}; +use std::{ + io::{Read, Write}, + path::Path, +}; + +/// State file +const STATE_FILE: &str = "state.toml"; + +/// Multisig Interact state +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct State { + adder_address: Option, +} + +impl State { + // Deserializes state from file + pub fn load_state() -> Self { + if Path::new(STATE_FILE).exists() { + let mut file = std::fs::File::open(STATE_FILE).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + toml::from_str(&content).unwrap() + } else { + Self::default() + } + } +} + +impl Drop for State { + // Serializes state to file + fn drop(&mut self) { + let mut file = std::fs::File::create(STATE_FILE).unwrap(); + file.write_all(toml::to_string(self).unwrap().as_bytes()) + .unwrap(); + } +} 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") } }