diff --git a/.gitignore b/.gitignore index 7c530277be..8295450d89 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ # The root Cargo.lock is kept for dependabot. contracts/**/Cargo.lock !contracts/**/wasm*/Cargo.lock +contracts/**/output*/ data/**/Cargo.lock framework/**/Cargo.lock sdk/**/Cargo.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index df6d26af07..382ea1f2f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,15 +26,29 @@ They are: - `multiversx-chain-scenario-format`, in short `scenario-format`, scenario JSON serializer/deserializer, 1 crate. - `multiversx-sdk`, in short `sdk`, allows communication with the chain(s), 1 crate. + ## [sc 0.48.1, codec 0.18.7] - 2024-04-30 - Simplified decoding of small numbers (i64/u64). - Manual reset of the `StaticApi`, in order to free memory for long-running tasks. +## [sc 0.49.0-alpha.4, sdk 0.4.0-alpha.4] - 2024-04-23 +Fourth pre-release, contains many interactor improvements, including improved tx polling. + +## [sc 0.49.0-alpha.3] - 2024-04-13 +Third pre-release of the unified syntax, includes backwards compatibility fixes and testing set state/check state. + +## [sc 0.49.0-alpha.2] - 2024-04-09 +Second pre-release of the unified syntax. Most features done, including fully featured interactors. +Still missing: set state/check state in tests. + ## [sc 0.48.0] - 2024-04-09 - When serializing to a managed buffer, static buffer caching is disabled by default. - `sc-meta:` - installers for wasm32 target and wasm-opt. - Integrated traits for token management: `FixedSupplyToken`, `Mergeable`. +## [sc 0.48.0-alpha.1] - 2024-03-27 (actually alpha release of 0.49.0) +First pre-release of the unified syntax. Syntax not yet stabilized, should only be used for experimenting with various smart contracts. + ## [sc 0.47.8] - 2024-03-22 - Test coverage functionality in sc-meta. - Removed deprecation from legacy whitebox testing framework, since it is still used extensively. diff --git a/Cargo.lock b/Cargo.lock index c7f8875a89..4c2fff583b 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,6 +475,7 @@ version = "0.0.0" dependencies = [ "builtin-func-features", "forwarder", + "forwarder-legacy", "forwarder-queue", "forwarder-raw", "multiversx-sc", @@ -629,6 +630,7 @@ dependencies = [ name = "crypto-zombies" version = "0.0.0" dependencies = [ + "kitty", "multiversx-sc", "multiversx-sc-scenario", ] @@ -1036,12 +1038,28 @@ dependencies = [ [[package]] name = "forwarder" version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-scenario", +] + +[[package]] +name = "forwarder-legacy" +version = "0.0.0" dependencies = [ "multiversx-sc", "multiversx-sc-scenario", "vault", ] +[[package]] +name = "forwarder-legacy-meta" +version = "0.0.0" +dependencies = [ + "forwarder-legacy", + "multiversx-sc-meta", +] + [[package]] name = "forwarder-meta" version = "0.0.0" @@ -1057,7 +1075,6 @@ dependencies = [ "multiversx-sc", "multiversx-sc-scenario", "multiversx-sc-wasm-adapter", - "vault", ] [[package]] @@ -1804,7 +1821,7 @@ checksum = "b59072fa0624b55ae5ae3fa6bfa91515bbeb4ac440214bc4a509e2c8806d6e9f" [[package]] name = "multiversx-price-aggregator-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "arrayvec", "getrandom 0.2.14", @@ -1825,7 +1842,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags 2.4.2", "hex-literal", @@ -1855,7 +1872,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -1866,7 +1883,7 @@ dependencies = [ [[package]] name = "multiversx-sc-meta" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "clap", "colored", @@ -1892,14 +1909,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-scenario" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "base64 0.21.7", "bech32", @@ -1925,7 +1942,7 @@ dependencies = [ [[package]] name = "multiversx-sc-snippets" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "base64 0.21.7", "env_logger", @@ -1934,19 +1951,20 @@ dependencies = [ "log", "multiversx-sc-scenario", "multiversx-sdk", + "rand 0.8.5", "tokio", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sdk" -version = "0.3.2" +version = "0.4.0-alpha.4" dependencies = [ "anyhow", "base64 0.21.7", @@ -1970,7 +1988,7 @@ dependencies = [ [[package]] name = "multiversx-wegld-swap-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", "multiversx-sc-modules", @@ -2221,7 +2239,6 @@ dependencies = [ name = "parent" version = "0.0.0" dependencies = [ - "child", "multiversx-sc", "multiversx-sc-scenario", ] @@ -2359,7 +2376,6 @@ name = "promises-features" version = "0.0.0" dependencies = [ "multiversx-sc", - "vault", ] [[package]] @@ -2760,6 +2776,22 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scenario-tester" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-scenario", +] + +[[package]] +name = "scenario-tester-meta" +version = "0.0.0" +dependencies = [ + "multiversx-sc-meta", + "scenario-tester", +] + [[package]] name = "schannel" version = "0.1.23" diff --git a/Cargo.toml b/Cargo.toml index d97f1292e0..8554af9b00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,6 +125,8 @@ members = [ "contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/meta", "contracts/feature-tests/composability/forwarder", "contracts/feature-tests/composability/forwarder/meta", + "contracts/feature-tests/composability/forwarder-legacy", + "contracts/feature-tests/composability/forwarder-legacy/meta", "contracts/feature-tests/composability/forwarder-queue", "contracts/feature-tests/composability/forwarder-queue/meta", "contracts/feature-tests/composability/forwarder-raw", @@ -159,6 +161,8 @@ members = [ "contracts/feature-tests/erc-style-contracts/lottery-erc20/meta", "contracts/feature-tests/esdt-system-sc-mock", "contracts/feature-tests/esdt-system-sc-mock/meta", + "contracts/feature-tests/exchange-features", + "contracts/feature-tests/exchange-features/meta", "contracts/feature-tests/formatted-message-features", "contracts/feature-tests/formatted-message-features/meta", "contracts/feature-tests/managed-map-features", @@ -173,9 +177,8 @@ members = [ "contracts/feature-tests/rust-snippets-generator-test/meta", "contracts/feature-tests/rust-testing-framework-tester", "contracts/feature-tests/rust-testing-framework-tester/meta", + "contracts/feature-tests/scenario-tester", + "contracts/feature-tests/scenario-tester/meta", "contracts/feature-tests/use-module", "contracts/feature-tests/use-module/meta", - "contracts/feature-tests/exchange-features", - "contracts/feature-tests/exchange-features/meta", - ] diff --git a/contracts/benchmarks/large-storage/Cargo.toml b/contracts/benchmarks/large-storage/Cargo.toml index 5b6fa96682..238cfc0286 100644 --- a/contracts/benchmarks/large-storage/Cargo.toml +++ b/contracts/benchmarks/large-storage/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/large_storage.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/benchmarks/large-storage/meta/Cargo.toml b/contracts/benchmarks/large-storage/meta/Cargo.toml index 629989c496..5ab3b3f4ea 100644 --- a/contracts/benchmarks/large-storage/meta/Cargo.toml +++ b/contracts/benchmarks/large-storage/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/large-storage/wasm/Cargo.lock b/contracts/benchmarks/large-storage/wasm/Cargo.lock index d99eb1d8e8..b662f443d9 100755 --- a/contracts/benchmarks/large-storage/wasm/Cargo.lock +++ b/contracts/benchmarks/large-storage/wasm/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/large-storage/wasm/Cargo.toml b/contracts/benchmarks/large-storage/wasm/Cargo.toml index 1fea846894..ee513468bf 100644 --- a/contracts/benchmarks/large-storage/wasm/Cargo.toml +++ b/contracts/benchmarks/large-storage/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/mappers/benchmark-common/Cargo.toml b/contracts/benchmarks/mappers/benchmark-common/Cargo.toml index 3e2b4677ac..3143c4c059 100644 --- a/contracts/benchmarks/mappers/benchmark-common/Cargo.toml +++ b/contracts/benchmarks/mappers/benchmark-common/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/benchmarks/mappers/linked-list-repeat/Cargo.toml b/contracts/benchmarks/mappers/linked-list-repeat/Cargo.toml index 369f30eec7..390e9c729a 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/Cargo.toml +++ b/contracts/benchmarks/mappers/linked-list-repeat/Cargo.toml @@ -13,9 +13,9 @@ path = "../benchmark-common" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/benchmarks/mappers/linked-list-repeat/meta/Cargo.toml b/contracts/benchmarks/mappers/linked-list-repeat/meta/Cargo.toml index b20ce94c64..f719432fba 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/mappers/linked-list-repeat/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/mappers/linked-list-repeat/tests/linked_list_repeat_blackbox_test.rs b/contracts/benchmarks/mappers/linked-list-repeat/tests/linked_list_repeat_blackbox_test.rs index 47af800bb8..bd5a4198e3 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/tests/linked_list_repeat_blackbox_test.rs +++ b/contracts/benchmarks/mappers/linked-list-repeat/tests/linked_list_repeat_blackbox_test.rs @@ -1,7 +1,8 @@ +#![allow(deprecated)] // TODO: unified syntax + use benchmark_common::ExampleStruct; use linked_list_repeat::ProxyTrait; -use multiversx_sc::types::{MultiValueEncoded, TokenIdentifier}; -use multiversx_sc_scenario::{api::StaticApi, scenario_model::*, *}; +use multiversx_sc_scenario::imports::*; const WASM_PATH_EXPR: &str = "mxsc:output/linked-list-repeat.mxsc.json"; diff --git a/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.lock b/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.lock index 66f592dee9..7e08a995d1 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.lock @@ -63,7 +63,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -103,7 +103,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.toml b/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.toml index a75a75c4a5..5218df0664 100644 --- a/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/mappers/linked-list-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/mappers/map-repeat/Cargo.toml b/contracts/benchmarks/mappers/map-repeat/Cargo.toml index 0aea4b42cd..53a9c8cb30 100644 --- a/contracts/benchmarks/mappers/map-repeat/Cargo.toml +++ b/contracts/benchmarks/mappers/map-repeat/Cargo.toml @@ -13,9 +13,9 @@ path = "../benchmark-common" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/benchmarks/mappers/map-repeat/meta/Cargo.toml b/contracts/benchmarks/mappers/map-repeat/meta/Cargo.toml index 5db6649fca..b8d61cf474 100644 --- a/contracts/benchmarks/mappers/map-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/mappers/map-repeat/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.lock b/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.lock index a6551181e2..1c21676a00 100644 --- a/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.lock @@ -63,7 +63,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -103,7 +103,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.toml b/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.toml index 796574dd80..6153f35d8f 100644 --- a/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/mappers/map-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/mappers/queue-repeat/Cargo.toml b/contracts/benchmarks/mappers/queue-repeat/Cargo.toml index 95beb1f2a7..7eae0e8177 100644 --- a/contracts/benchmarks/mappers/queue-repeat/Cargo.toml +++ b/contracts/benchmarks/mappers/queue-repeat/Cargo.toml @@ -13,9 +13,9 @@ path = "../benchmark-common" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/benchmarks/mappers/queue-repeat/meta/Cargo.toml b/contracts/benchmarks/mappers/queue-repeat/meta/Cargo.toml index c9f6ae7228..ef5d420e27 100644 --- a/contracts/benchmarks/mappers/queue-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/mappers/queue-repeat/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.lock b/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.lock index eaf6a5d673..ad70d21672 100644 --- a/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.lock @@ -47,7 +47,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.toml b/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.toml index 47fc1790b6..2ebeda1f2e 100644 --- a/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/mappers/queue-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/mappers/set-repeat/Cargo.toml b/contracts/benchmarks/mappers/set-repeat/Cargo.toml index 888f905fe0..ebf2958e90 100644 --- a/contracts/benchmarks/mappers/set-repeat/Cargo.toml +++ b/contracts/benchmarks/mappers/set-repeat/Cargo.toml @@ -13,9 +13,9 @@ path = "../benchmark-common" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/benchmarks/mappers/set-repeat/meta/Cargo.toml b/contracts/benchmarks/mappers/set-repeat/meta/Cargo.toml index a8b03b8e47..269df5be03 100644 --- a/contracts/benchmarks/mappers/set-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/mappers/set-repeat/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.lock b/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.lock index d6813d0757..1cee879d4d 100644 --- a/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.lock @@ -47,7 +47,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.toml b/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.toml index 81af5ada3c..aa37b34c3e 100644 --- a/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/mappers/set-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/mappers/single-value-repeat/Cargo.toml b/contracts/benchmarks/mappers/single-value-repeat/Cargo.toml index c94dd28a88..34e3426254 100644 --- a/contracts/benchmarks/mappers/single-value-repeat/Cargo.toml +++ b/contracts/benchmarks/mappers/single-value-repeat/Cargo.toml @@ -13,9 +13,9 @@ path = "../benchmark-common" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/benchmarks/mappers/single-value-repeat/meta/Cargo.toml b/contracts/benchmarks/mappers/single-value-repeat/meta/Cargo.toml index c988d432eb..8487ef015b 100644 --- a/contracts/benchmarks/mappers/single-value-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/mappers/single-value-repeat/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.lock b/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.lock index a3d214535d..dbb15cc548 100644 --- a/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.lock @@ -47,7 +47,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.toml b/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.toml index b562ace439..3ac2ae3b96 100644 --- a/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/mappers/single-value-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/mappers/vec-repeat/Cargo.toml b/contracts/benchmarks/mappers/vec-repeat/Cargo.toml index 08bdce3673..8c7b4a9d8e 100644 --- a/contracts/benchmarks/mappers/vec-repeat/Cargo.toml +++ b/contracts/benchmarks/mappers/vec-repeat/Cargo.toml @@ -13,9 +13,9 @@ path = "../benchmark-common" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/benchmarks/mappers/vec-repeat/meta/Cargo.toml b/contracts/benchmarks/mappers/vec-repeat/meta/Cargo.toml index 4cfcc8a955..fc6c8ebd33 100644 --- a/contracts/benchmarks/mappers/vec-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/mappers/vec-repeat/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.lock b/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.lock index 3bd814698b..b212e81e0d 100644 --- a/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.lock @@ -47,7 +47,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.toml b/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.toml index a7079ec058..8779eaa521 100644 --- a/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/mappers/vec-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/send-tx-repeat/Cargo.toml b/contracts/benchmarks/send-tx-repeat/Cargo.toml index 64db88c52c..440bfa0946 100644 --- a/contracts/benchmarks/send-tx-repeat/Cargo.toml +++ b/contracts/benchmarks/send-tx-repeat/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/send_tx_repeat.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/benchmarks/send-tx-repeat/meta/Cargo.toml b/contracts/benchmarks/send-tx-repeat/meta/Cargo.toml index 2ceb7301ac..fb2c8f50cf 100644 --- a/contracts/benchmarks/send-tx-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/send-tx-repeat/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/send-tx-repeat/src/send_tx_repeat.rs b/contracts/benchmarks/send-tx-repeat/src/send_tx_repeat.rs index da74343a01..ade5321f68 100644 --- a/contracts/benchmarks/send-tx-repeat/src/send_tx_repeat.rs +++ b/contracts/benchmarks/send-tx-repeat/src/send_tx_repeat.rs @@ -11,7 +11,7 @@ pub trait SendTxRepeat { #[endpoint] fn repeat(&self, to: ManagedAddress, amount: BigUint, times: usize) { for _ in 0..times { - self.send().direct_egld(&to, &amount); + self.tx().to(&to).egld(&amount).transfer(); } } } diff --git a/contracts/benchmarks/send-tx-repeat/wasm/Cargo.lock b/contracts/benchmarks/send-tx-repeat/wasm/Cargo.lock index 7127d940de..5dca9592c8 100755 --- a/contracts/benchmarks/send-tx-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/send-tx-repeat/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/send-tx-repeat/wasm/Cargo.toml b/contracts/benchmarks/send-tx-repeat/wasm/Cargo.toml index 17ac4aa9b8..f42955ebbd 100644 --- a/contracts/benchmarks/send-tx-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/send-tx-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/str-repeat/Cargo.toml b/contracts/benchmarks/str-repeat/Cargo.toml index d38f7d8513..0d46d631dd 100644 --- a/contracts/benchmarks/str-repeat/Cargo.toml +++ b/contracts/benchmarks/str-repeat/Cargo.toml @@ -12,10 +12,10 @@ path = "src/str_repeat.rs" managed-buffer-builder-cached = ["multiversx-sc/managed-buffer-builder-cached"] [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/benchmarks/str-repeat/meta/Cargo.toml b/contracts/benchmarks/str-repeat/meta/Cargo.toml index 8f451d4a6d..dbf074583d 100644 --- a/contracts/benchmarks/str-repeat/meta/Cargo.toml +++ b/contracts/benchmarks/str-repeat/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.lock b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.lock index f16e8c090b..e33366ed86 100644 --- a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.lock +++ b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.toml b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.toml index 193814ec43..b840dd0a3b 100644 --- a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.toml +++ b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-basic/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.lock b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.lock index 3f0656d631..6ccbcbaadd 100644 --- a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.lock +++ b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.toml b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.toml index 7f20111eda..53db7f0b4a 100644 --- a/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.toml +++ b/contracts/benchmarks/str-repeat/wasm-str-repeat-mb-builder-cached/Cargo.toml @@ -26,7 +26,7 @@ path = ".." features = ["managed-buffer-builder-cached"] [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/benchmarks/str-repeat/wasm/Cargo.lock b/contracts/benchmarks/str-repeat/wasm/Cargo.lock index 17fc991178..39020dc5b8 100755 --- a/contracts/benchmarks/str-repeat/wasm/Cargo.lock +++ b/contracts/benchmarks/str-repeat/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/benchmarks/str-repeat/wasm/Cargo.toml b/contracts/benchmarks/str-repeat/wasm/Cargo.toml index 0683f552a1..fa54772480 100644 --- a/contracts/benchmarks/str-repeat/wasm/Cargo.toml +++ b/contracts/benchmarks/str-repeat/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/core/price-aggregator/Cargo.toml b/contracts/core/price-aggregator/Cargo.toml index 2e66481485..aad9c4ce9c 100644 --- a/contracts/core/price-aggregator/Cargo.toml +++ b/contracts/core/price-aggregator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-price-aggregator-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" authors = [ "Claudiu-Marcel Bruda ", "MultiversX ", @@ -19,15 +19,15 @@ edition = "2021" path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dependencies] diff --git a/contracts/core/price-aggregator/meta/Cargo.toml b/contracts/core/price-aggregator/meta/Cargo.toml index 46bfa8d5b9..5b01eac017 100644 --- a/contracts/core/price-aggregator/meta/Cargo.toml +++ b/contracts/core/price-aggregator/meta/Cargo.toml @@ -8,10 +8,10 @@ publish = false path = ".." [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/core/price-aggregator/sc-config.toml b/contracts/core/price-aggregator/sc-config.toml new file mode 100644 index 0000000000..56b3e816a6 --- /dev/null +++ b/contracts/core/price-aggregator/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "tests/price_aggregator_proxy.rs" \ No newline at end of file diff --git a/contracts/core/price-aggregator/scenarios/stress_submit_test.scen.json b/contracts/core/price-aggregator/scenarios/stress_submit_test.scen.json index 6ed4ec81ac..e2b19c9966 100644 --- a/contracts/core/price-aggregator/scenarios/stress_submit_test.scen.json +++ b/contracts/core/price-aggregator/scenarios/stress_submit_test.scen.json @@ -1133,7 +1133,7 @@ "0x45474c44", "0x55534443", "0x5f", - "0x7e73f7325747f41e", + "0xd7fd71920be3e621", "0x" ], "gasLimit": "7,000,000" @@ -1154,7 +1154,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x67da5ce3a07967b4", + "0x5a032236cff2ff06", "0x" ], "gasLimit": "7,000,000" @@ -1175,7 +1175,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x42345d9c03249906", + "0x2e874347688dffa1", "0x" ], "gasLimit": "7,000,000" @@ -1196,7 +1196,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x729cbab7559d2418", + "0x4c94033d5e15a73a", "0x" ], "gasLimit": "7,000,000" @@ -1217,7 +1217,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x4b1f1fb91704289a", + "0x2bd5b88173750be6", "0x" ], "gasLimit": "7,000,000" @@ -1238,7 +1238,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x9041a66f9a8eddd3", + "0xe4cb406e5f95d9d7", "0x" ], "gasLimit": "7,000,000" @@ -1259,7 +1259,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x119426970178f4e8", + "0xfd4dd723ed0b256e", "0x" ], "gasLimit": "7,000,000" @@ -1280,7 +1280,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xa4a00453870b1413", + "0x66b6bfe973064cfd", "0x" ], "gasLimit": "7,000,000" @@ -1301,7 +1301,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x506335784433b85b", + "0xbc6a51b940c5c479", "0x" ], "gasLimit": "7,000,000" @@ -1322,7 +1322,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xa272188ead522f3c", + "0x47ca1962093887df", "0x" ], "gasLimit": "7,000,000" @@ -1343,7 +1343,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x899a358acd3a916d", + "0xa9657f2b7c255e3c", "0x" ], "gasLimit": "7,000,000" @@ -1364,7 +1364,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xa72819f377890189", + "0xadaf4aaa5e63f2e5", "0x" ], "gasLimit": "7,000,000" @@ -1385,7 +1385,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x67c7c355dbf99be8", + "0x153a1384b3d68656", "0x" ], "gasLimit": "7,000,000" @@ -1406,7 +1406,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xfbb7382befbf0ba3", + "0x4ba5dda59b2ba4e9", "0x" ], "gasLimit": "7,000,000" @@ -1427,7 +1427,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x3b6e67573e4e3f73", + "0x973e0d62157afb51", "0x" ], "gasLimit": "7,000,000" @@ -1448,7 +1448,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xf1cad9d61b5dea8e", + "0xe18cb77b44399b45", "0x" ], "gasLimit": "7,000,000" @@ -1469,7 +1469,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x0f125f34c142d4dd", + "0x30a1ed7ed6069074", "0x" ], "gasLimit": "7,000,000" @@ -1490,7 +1490,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xe78b1d333ef1d9cb", + "0xfbd288d325739548", "0x" ], "gasLimit": "7,000,000" @@ -1511,7 +1511,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x2d95a8f7484f98c5", + "0x83ad3ad74745e6f5", "0x" ], "gasLimit": "7,000,000" @@ -1532,7 +1532,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x7a97d84d6b233203", + "0x0cc85234d5ea00b2", "0x" ], "gasLimit": "7,000,000" @@ -1553,7 +1553,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xb874fdc44ac92cff", + "0x8dae036c75e9a62c", "0x" ], "gasLimit": "7,000,000" @@ -1574,7 +1574,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x8cb05ff6dcfb459f", + "0x31549118c983eaa0", "0x" ], "gasLimit": "7,000,000" @@ -1595,7 +1595,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xa402f6a3b4ee09e7", + "0x8228096b6388b4bd", "0x" ], "gasLimit": "7,000,000" @@ -1616,7 +1616,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x24f913b5c6d6d687", + "0x2dc8b16251c44710", "0x" ], "gasLimit": "7,000,000" @@ -1637,7 +1637,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x601430ad5b35c7b2", + "0xbc66b6f85858d98c", "0x" ], "gasLimit": "7,000,000" @@ -1658,7 +1658,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xa66e3496b143093d", + "0x2937c9b0c1073c0b", "0x" ], "gasLimit": "7,000,000" @@ -1679,7 +1679,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x10fbd80dee58e58c", + "0xa2b7bd06214aabc4", "0x" ], "gasLimit": "7,000,000" @@ -1700,7 +1700,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xdbe95503112f8855", + "0x61ae8ac001144476", "0x" ], "gasLimit": "7,000,000" @@ -1721,7 +1721,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x799a64362d43ecb5", + "0x5f6de265c643495f", "0x" ], "gasLimit": "7,000,000" @@ -1742,7 +1742,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xc4040f7c568dfe5f", + "0x67430307e2f864f0", "0x" ], "gasLimit": "7,000,000" @@ -1763,7 +1763,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x5f0934092a3b285e", + "0x7de010a49d52cd3f", "0x" ], "gasLimit": "7,000,000" @@ -1784,7 +1784,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xbab97635db0333b2", + "0xb27799264f3b84ec", "0x" ], "gasLimit": "7,000,000" @@ -1805,7 +1805,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x3a540081e9ccd62e", + "0x53d7a1ade83e0f2e", "0x" ], "gasLimit": "7,000,000" @@ -1826,7 +1826,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x05bea873f4825a82", + "0x2ec40e01673b8ad7", "0x" ], "gasLimit": "7,000,000" @@ -1847,7 +1847,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x67d016dd357634ca", + "0xfb616537f76f8ffb", "0x" ], "gasLimit": "7,000,000" @@ -1868,7 +1868,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x4d6b5212f854c77d", + "0x387268d229f4ec9a", "0x" ], "gasLimit": "7,000,000" @@ -1889,7 +1889,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x7c62a09f1a3336c8", + "0xdea0f1c84325ea3a", "0x" ], "gasLimit": "7,000,000" @@ -1910,7 +1910,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x21c179faeb48f1d7", + "0x12eb7cb637de6e86", "0x" ], "gasLimit": "7,000,000" @@ -1931,7 +1931,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xe7f11437e10fa779", + "0x5f6b1784511d622d", "0x" ], "gasLimit": "7,000,000" @@ -1952,7 +1952,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xb06dea0282c5fa22", + "0x1a41106366209d8d", "0x" ], "gasLimit": "7,000,000" @@ -1973,7 +1973,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x805ed8f4a0a71cce", + "0x2324bca02526fec9", "0x" ], "gasLimit": "7,000,000" @@ -1994,7 +1994,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x483ef0b2517c0915", + "0xccf33fc47ef34300", "0x" ], "gasLimit": "7,000,000" @@ -2015,7 +2015,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x45e24c96cc048c8e", + "0xebfab26bff9c74a3", "0x" ], "gasLimit": "7,000,000" @@ -2036,7 +2036,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x2c9cfe97258a6099", + "0x116a45e410db659b", "0x" ], "gasLimit": "7,000,000" @@ -2057,7 +2057,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xf0c3114cbb06b7ac", + "0xc9bddc2b06ba1f1e", "0x" ], "gasLimit": "7,000,000" @@ -2078,7 +2078,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x9400e2a0a2b4c559", + "0xde7473b9bfdfe96c", "0x" ], "gasLimit": "7,000,000" @@ -2099,7 +2099,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x6ff6239cf418528a", + "0x91c2ff3a5c73267e", "0x" ], "gasLimit": "7,000,000" @@ -2120,7 +2120,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x3a1e0de1fb534547", + "0x95bb44dffc62bb47", "0x" ], "gasLimit": "7,000,000" @@ -2141,7 +2141,7 @@ "0x45474c44", "0x55534443", "0x64", - "0x3a549a5c074f3805", + "0x2f28d194b7659f9f", "0x" ], "gasLimit": "7,000,000" @@ -2162,7 +2162,7 @@ "0x45474c44", "0x55534443", "0x64", - "0xaebe838a44d1559e", + "0xc1bd397146f3353e", "0x" ], "gasLimit": "7,000,000" diff --git a/contracts/core/price-aggregator/src/events.rs b/contracts/core/price-aggregator/src/events.rs index f2212815c9..d485e622db 100644 --- a/contracts/core/price-aggregator/src/events.rs +++ b/contracts/core/price-aggregator/src/events.rs @@ -3,7 +3,8 @@ multiversx_sc::derive_imports!(); use crate::price_aggregator_data::{TimestampedPrice, TokenPair}; -#[derive(TypeAbi, TopEncode)] +#[type_abi] +#[derive(TopEncode)] pub struct NewRoundEvent { price: BigUint, timestamp: u64, diff --git a/contracts/core/price-aggregator/src/price_aggregator_data.rs b/contracts/core/price-aggregator/src/price_aggregator_data.rs index 13249216ba..c348b67d22 100644 --- a/contracts/core/price-aggregator/src/price_aggregator_data.rs +++ b/contracts/core/price-aggregator/src/price_aggregator_data.rs @@ -1,13 +1,15 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi, Clone)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone)] pub struct TokenPair { pub from: ManagedBuffer, pub to: ManagedBuffer, } -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct PriceFeed { pub round_id: u32, pub from: ManagedBuffer, @@ -17,14 +19,16 @@ pub struct PriceFeed { pub decimals: u8, } -#[derive(TopEncode, TopDecode, TypeAbi, Debug, PartialEq, Eq)] +#[type_abi] +#[derive(TopEncode, TopDecode, Debug, PartialEq, Eq)] pub struct TimestampedPrice { pub price: BigUint, pub timestamp: u64, pub decimals: u8, } -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi, Debug, PartialEq, Eq)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Debug, PartialEq, Eq)] pub struct OracleStatus { pub accepted_submissions: u64, pub total_submissions: u64, 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 b1b28e4fcf..05c9b161f7 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_blackbox_test.rs @@ -1,39 +1,32 @@ use multiversx_price_aggregator_sc::{ price_aggregator_data::{OracleStatus, TimestampedPrice, TokenPair}, - ContractObj, PriceAggregator, ProxyTrait as _, MAX_ROUND_DURATION_SECONDS, -}; -use multiversx_sc::{ - codec::multi_types::MultiValueVec, - types::{Address, EgldOrEsdtTokenIdentifier}, -}; -use multiversx_sc_modules::{pause::ProxyTrait, staking::ProxyTrait as _}; -use multiversx_sc_scenario::{ - api::StaticApi, - managed_address, managed_biguint, managed_buffer, - scenario_model::{Account, AddressValue, ScCallStep, ScDeployStep, SetStateStep, TxExpect}, - ContractInfo, DebugApi, ScenarioWorld, WhiteboxContract, + ContractObj, PriceAggregator, MAX_ROUND_DURATION_SECONDS, }; +use multiversx_sc_scenario::imports::*; + +mod price_aggregator_proxy; + const DECIMALS: u8 = 0; const EGLD_TICKER: &[u8] = b"EGLD"; const NR_ORACLES: usize = 4; -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 SLASH_AMOUNT: u64 = 10; const SLASH_QUORUM: usize = 3; const STAKE_AMOUNT: u64 = 20; const SUBMISSION_COUNT: usize = 3; const USD_TICKER: &[u8] = b"USDC"; -type PriceAggregatorContract = ContractInfo>; +const PRICE_AGGREGATOR_ADDRESS: TestSCAddress = TestSCAddress::new("price-aggregator"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const PRICE_AGGREGATOR_PATH: MxscPath = + MxscPath::new("output/multiversx-price-aggregator-sc.mxsc.json"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); blockchain.set_current_dir_from_workspace("contracts/core/price-aggregator"); blockchain.register_contract( - PRICE_AGGREGATOR_PATH_EXPR, + PRICE_AGGREGATOR_PATH, multiversx_price_aggregator_sc::ContractBuilder, ); @@ -43,7 +36,6 @@ fn world() -> ScenarioWorld { struct PriceAggregatorTestState { world: ScenarioWorld, oracles: Vec, - price_aggregator_contract: PriceAggregatorContract, price_aggregator_whitebox: WhiteboxContract>, } @@ -51,42 +43,38 @@ impl PriceAggregatorTestState { fn new() -> Self { let mut world = world(); - 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); + + world.set_state_step(SetStateStep::new()).new_address( + OWNER_ADDRESS, + 1, + PRICE_AGGREGATOR_ADDRESS, + ); let mut oracles = Vec::new(); for i in 1..=NR_ORACLES { - let address_expr = format!("address:oracle{}", i); - let address_value = AddressValue::from(address_expr.as_str()); - - set_state_step = set_state_step.put_account( - address_expr.as_str(), - Account::new().nonce(1).balance(STAKE_AMOUNT), - ); + let address_name = format!("oracle{i}"); + let address = TestAddress::new(&address_name); + let address_value = AddressValue::from(address); + world.account(address).nonce(1).balance(STAKE_AMOUNT); oracles.push(address_value); } - world.set_state_step(set_state_step); - let price_aggregator_contract = PriceAggregatorContract::new(PRICE_AGGREGATOR_ADDRESS_EXPR); let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS_EXPR, + PRICE_AGGREGATOR_ADDRESS, multiversx_price_aggregator_sc::contract_obj, ); Self { world, oracles, - price_aggregator_contract, price_aggregator_whitebox, } } fn deploy(&mut self) -> &mut Self { - let price_aggregator_code = self.world.code_expression(PRICE_AGGREGATOR_PATH_EXPR); - let oracles = MultiValueVec::from( self.oracles .iter() @@ -94,59 +82,69 @@ impl PriceAggregatorTestState { .collect::>(), ); - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(price_aggregator_code) - .call(self.price_aggregator_contract.init( - EgldOrEsdtTokenIdentifier::egld(), - STAKE_AMOUNT, - SLASH_AMOUNT, - SLASH_QUORUM, - SUBMISSION_COUNT, - oracles, - )), - ); + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .init( + EgldOrEsdtTokenIdentifier::egld(), + STAKE_AMOUNT, + SLASH_AMOUNT, + SLASH_QUORUM, + SUBMISSION_COUNT, + oracles, + ) + .code(PRICE_AGGREGATOR_PATH) + .run(); for address in self.oracles.iter() { - self.world.sc_call( - ScCallStep::new() - .from(address) - .egld_value(STAKE_AMOUNT) - .call(self.price_aggregator_contract.stake()), - ); + self.world + .tx() + .from(address) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .stake() + .egld(STAKE_AMOUNT) + .run(); } self } fn set_pair_decimals(&mut self) { - self.world.sc_call( - ScCallStep::new().from(OWNER_ADDRESS_EXPR).call( - self.price_aggregator_contract - .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS), - ), - ); + self.world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS) + .run(); } fn unpause_endpoint(&mut self) { - self.world.sc_call( - ScCallStep::new() - .from(OWNER_ADDRESS_EXPR) - .call(self.price_aggregator_contract.unpause_endpoint()), - ); + self.world + .tx() + .from(OWNER_ADDRESS) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .unpause_endpoint() + .run(); } fn submit(&mut self, from: &AddressValue, submission_timestamp: u64, price: u64) { - self.world.sc_call(ScCallStep::new().from(from).call( - self.price_aggregator_contract.submit( + self.world + .tx() + .from(from) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .submit( EGLD_TICKER, USD_TICKER, submission_timestamp, price, DECIMALS, - ), - )); + ) + .run(); } fn submit_and_expect_err( @@ -156,27 +154,31 @@ impl PriceAggregatorTestState { price: u64, err_message: &str, ) { - self.world.sc_call( - ScCallStep::new() - .from(from) - .call(self.price_aggregator_contract.submit( - EGLD_TICKER, - USD_TICKER, - submission_timestamp, - price, - DECIMALS, - )) - .expect(TxExpect::user_error("str:".to_string() + err_message)), - ); + self.world + .tx() + .from(from) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .submit( + EGLD_TICKER, + USD_TICKER, + submission_timestamp, + price, + DECIMALS, + ) + .with_result(ExpectStatus(4)) + .with_result(ExpectMessage(err_message)) + .run(); } fn vote_slash_member(&mut self, from: &AddressValue, member_to_slash: Address) { - self.world.sc_call( - ScCallStep::new().from(from).call( - self.price_aggregator_contract - .vote_slash_member(member_to_slash), - ), - ); + self.world + .tx() + .from(from) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .vote_slash_member(member_to_slash) + .run(); } } @@ -277,7 +279,8 @@ fn test_price_aggregator_submit_round_ok() { let current_timestamp = 110; state .world - .set_state_step(SetStateStep::new().block_timestamp(current_timestamp)); + .current_block() + .block_timestamp(current_timestamp); // submit second state.submit(&state.oracles[1].clone(), 101, 11_000); @@ -334,7 +337,8 @@ fn test_price_aggregator_discarded_round() { let current_timestamp = 100 + MAX_ROUND_DURATION_SECONDS + 1; state .world - .set_state_step(SetStateStep::new().block_timestamp(current_timestamp)); + .current_block() + .block_timestamp(current_timestamp); // submit second - this will discard the previous submission state.submit(&state.oracles[1].clone(), current_timestamp - 1, 11_000); @@ -369,13 +373,14 @@ fn test_price_aggregator_slashing() { state.vote_slash_member(&state.oracles[2].clone(), state.oracles[1].to_address()); state.vote_slash_member(&state.oracles[3].clone(), state.oracles[1].to_address()); - state.world.sc_call( - ScCallStep::new().from(&state.oracles[0]).call( - state - .price_aggregator_contract - .slash_member(state.oracles[1].to_address()), - ), - ); + state + .world + .tx() + .from(&state.oracles[0]) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .slash_member(state.oracles[1].to_address()) + .run(); // oracle 1 try submit after slashing state.submit_and_expect_err( diff --git a/contracts/core/price-aggregator/tests/price_aggregator_proxy.rs b/contracts/core/price-aggregator/tests/price_aggregator_proxy.rs new file mode 100644 index 0000000000..ae5e00c94a --- /dev/null +++ b/contracts/core/price-aggregator/tests/price_aggregator_proxy.rs @@ -0,0 +1,368 @@ +// 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 PriceAggregatorProxy; + +impl TxProxyTrait for PriceAggregatorProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = PriceAggregatorProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + PriceAggregatorProxyMethods { wrapped_tx: tx } + } +} + +pub struct PriceAggregatorProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl PriceAggregatorProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg, + Arg5: ProxyArg>>, + >( + self, + staking_token: Arg0, + staking_amount: Arg1, + slash_amount: Arg2, + slash_quorum: Arg3, + submission_count: Arg4, + oracles: Arg5, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&staking_token) + .argument(&staking_amount) + .argument(&slash_amount) + .argument(&slash_quorum) + .argument(&submission_count) + .argument(&oracles) + .original_result() + } +} + +#[rustfmt::skip] +impl PriceAggregatorProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn change_amounts< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + staking_amount: Arg0, + slash_amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("changeAmounts") + .argument(&staking_amount) + .argument(&slash_amount) + .original_result() + } + + pub fn add_oracles< + Arg0: ProxyArg>>, + >( + self, + oracles: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("addOracles") + .argument(&oracles) + .original_result() + } + + /// Also receives submission count, + /// so the owner does not have to update it manually with setSubmissionCount before this call + pub fn remove_oracles< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + submission_count: Arg0, + oracles: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("removeOracles") + .argument(&submission_count) + .argument(&oracles) + .original_result() + } + + pub fn submit< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + Arg4: ProxyArg, + >( + self, + from: Arg0, + to: Arg1, + submission_timestamp: Arg2, + price: Arg3, + decimals: Arg4, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("submit") + .argument(&from) + .argument(&to) + .argument(&submission_timestamp) + .argument(&price) + .argument(&decimals) + .original_result() + } + + pub fn submit_batch< + Arg0: ProxyArg, ManagedBuffer, u64, BigUint, u8>>>, + >( + self, + submissions: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("submitBatch") + .argument(&submissions) + .original_result() + } + + pub fn latest_round_data( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("latestRoundData") + .original_result() + } + + pub fn latest_price_feed< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxProxyCall, ManagedBuffer, u64, BigUint, u8>> { + self.wrapped_tx + .raw_call("latestPriceFeed") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn latest_price_feed_optional< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxProxyCall, ManagedBuffer, u64, BigUint, u8>>> { + self.wrapped_tx + .raw_call("latestPriceFeedOptional") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn set_submission_count< + Arg0: ProxyArg, + >( + self, + submission_count: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setSubmissionCount") + .argument(&submission_count) + .original_result() + } + + pub fn get_oracles( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getOracles") + .original_result() + } + + pub fn set_pair_decimals< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + from: Arg0, + to: Arg1, + decimals: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setPairDecimals") + .argument(&from) + .argument(&to) + .argument(&decimals) + .original_result() + } + + pub fn get_pair_decimals< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getPairDecimals") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn submission_count( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("submission_count") + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isPaused") + .original_result() + } + + pub fn stake( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("stake") + .original_result() + } + + pub fn unstake< + Arg0: ProxyArg>, + >( + self, + unstake_amount: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unstake") + .argument(&unstake_amount) + .original_result() + } + + pub fn vote_slash_member< + Arg0: ProxyArg>, + >( + self, + member_to_slash: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("voteSlashMember") + .argument(&member_to_slash) + .original_result() + } + + pub fn cancel_vote_slash_member< + Arg0: ProxyArg>, + >( + self, + member_to_slash: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("cancelVoteSlashMember") + .argument(&member_to_slash) + .original_result() + } + + pub fn slash_member< + Arg0: ProxyArg>, + >( + self, + member_to_slash: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("slashMember") + .argument(&member_to_slash) + .original_result() + } +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct PriceFeed +where + Api: ManagedTypeApi, +{ + pub round_id: u32, + pub from: ManagedBuffer, + pub to: ManagedBuffer, + pub timestamp: u64, + pub price: BigUint, + pub decimals: u8, +} + +#[type_abi] +#[derive(TopEncode)] +pub struct NewRoundEvent +where + Api: ManagedTypeApi, +{ + pub price: BigUint, + pub timestamp: u64, + pub decimals: u8, + pub block: u64, + pub epoch: u64, +} 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 1170a4d964..660bbf1dda 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_stress_blackbox.rs @@ -1,39 +1,30 @@ use multiversx_price_aggregator_sc::{ price_aggregator_data::{OracleStatus, TokenPair}, - ContractObj, PriceAggregator, ProxyTrait as _, -}; -use multiversx_sc::{ - codec::multi_types::MultiValueVec, contract_base::ContractBase, - types::EgldOrEsdtTokenIdentifier, -}; -use multiversx_sc_modules::{pause::ProxyTrait, staking::ProxyTrait as _}; -use multiversx_sc_scenario::{ - api::StaticApi, - managed_address, managed_buffer, - scenario_model::{Account, AddressValue, ScCallStep, ScDeployStep, SetStateStep}, - ContractInfo, DebugApi, ScenarioWorld, WhiteboxContract, + ContractObj, PriceAggregator, }; +use multiversx_sc_scenario::imports::*; + const DECIMALS: u8 = 0; const EGLD_TICKER: &[u8] = b"EGLD"; const NR_ORACLES: usize = 50; -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: TestAddress = TestAddress::new("owner"); +const PRICE_AGGREGATOR_ADDRESS: TestSCAddress = TestSCAddress::new("price-aggregator"); +const PRICE_AGGREGATOR_PATH: MxscPath = + MxscPath::new("../output/multiversx-price-aggregator-sc.mxsc.json"); const SLASH_AMOUNT: u64 = 10; const SLASH_QUORUM: usize = 3; const STAKE_AMOUNT: u64 = 20; const SUBMISSION_COUNT: usize = 50; const USD_TICKER: &[u8] = b"USDC"; -type PriceAggregatorContract = ContractInfo>; +mod price_aggregator_proxy; fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.set_current_dir_from_workspace("contracts/core/price-aggregator"); blockchain.register_contract( - PRICE_AGGREGATOR_PATH_EXPR, + PRICE_AGGREGATOR_PATH, multiversx_price_aggregator_sc::ContractBuilder, ); @@ -43,50 +34,45 @@ fn world() -> ScenarioWorld { struct PriceAggregatorTestState { world: ScenarioWorld, oracles: Vec, - price_aggregator_contract: PriceAggregatorContract, price_aggregator_whitebox: WhiteboxContract>, } impl PriceAggregatorTestState { fn new() -> Self { let mut world = world(); + world.start_trace(); - 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) + world + .account(OWNER) + .nonce(1) + .new_address(OWNER, 1, PRICE_AGGREGATOR_ADDRESS) + .current_block() .block_timestamp(100); let mut oracles = Vec::new(); for i in 1..=NR_ORACLES { - let address_expr = format!("address:oracle{}", i); - let address_value = AddressValue::from(address_expr.as_str()); + let address_expr = format!("oracle{}", i); + let address: TestAddress = TestAddress::new(address_expr.as_str()); + let address_value = AddressValue::from(address.eval_to_expr().as_str()); - set_state_step = set_state_step.put_account( - address_expr.as_str(), - Account::new().nonce(1).balance(STAKE_AMOUNT), - ); + world.account(address).nonce(1).balance(STAKE_AMOUNT); oracles.push(address_value); } - world.start_trace().set_state_step(set_state_step); - let price_aggregator_contract = PriceAggregatorContract::new(PRICE_AGGREGATOR_ADDRESS_EXPR); let price_aggregator_whitebox = WhiteboxContract::new( - PRICE_AGGREGATOR_ADDRESS_EXPR, + PRICE_AGGREGATOR_ADDRESS, multiversx_price_aggregator_sc::contract_obj, ); Self { world, oracles, - price_aggregator_contract, price_aggregator_whitebox, } } fn deploy(&mut self) -> &mut Self { - let price_aggregator_code = self.world.code_expression(PRICE_AGGREGATOR_PATH_EXPR); - let oracles = MultiValueVec::from( self.oracles .iter() @@ -94,65 +80,73 @@ impl PriceAggregatorTestState { .collect::>(), ); - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(price_aggregator_code) - .call(self.price_aggregator_contract.init( - EgldOrEsdtTokenIdentifier::egld(), - STAKE_AMOUNT, - SLASH_AMOUNT, - SLASH_QUORUM, - SUBMISSION_COUNT, - oracles, - )) - .gas_limit("120,000,000"), - ); + self.world + .tx() + .from(OWNER) + .gas(120_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .init( + EgldOrEsdtTokenIdentifier::egld(), + STAKE_AMOUNT, + SLASH_AMOUNT, + SLASH_QUORUM, + SUBMISSION_COUNT, + oracles, + ) + .code(PRICE_AGGREGATOR_PATH) + .run(); for address in self.oracles.iter() { - self.world.sc_call( - ScCallStep::new() - .from(address) - .egld_value(STAKE_AMOUNT) - .call(self.price_aggregator_contract.stake()) - .gas_limit("5,000,000"), - ); + self.world + .tx() + .from(&address.to_address()) + .to(PRICE_AGGREGATOR_ADDRESS) + .gas(5_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .stake() + .egld(STAKE_AMOUNT) + .run(); } self } fn set_pair_decimals(&mut self) { - self.world.sc_call( - ScCallStep::new().from(OWNER_ADDRESS_EXPR).call( - self.price_aggregator_contract - .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS), - ), - ); + self.world + .tx() + .from(OWNER) + .to(PRICE_AGGREGATOR_ADDRESS) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .set_pair_decimals(EGLD_TICKER, USD_TICKER, DECIMALS) + .run(); } fn unpause_endpoint(&mut self) { - self.world.sc_call( - ScCallStep::new() - .from(OWNER_ADDRESS_EXPR) - .call(self.price_aggregator_contract.unpause_endpoint()) - .gas_limit("5,000,000"), - ); + self.world + .tx() + .from(OWNER) + .to(PRICE_AGGREGATOR_ADDRESS) + .gas(5_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .unpause_endpoint() + .run(); } fn submit(&mut self, from: &AddressValue, submission_timestamp: u64, price: u64) { - self.world.sc_call( - ScCallStep::new() - .from(from) - .call(self.price_aggregator_contract.submit( - EGLD_TICKER, - USD_TICKER, - submission_timestamp, - price, - DECIMALS, - )) - .gas_limit("7,000,000"), - ); + self.world + .tx() + .from(&from.to_address()) + .to(PRICE_AGGREGATOR_ADDRESS) + .gas(7_000_000u64) + .typed(price_aggregator_proxy::PriceAggregatorProxy) + .submit( + EGLD_TICKER, + USD_TICKER, + submission_timestamp, + price, + DECIMALS, + ) + .run(); } } 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 a2a432127e..50b05a6a41 100644 --- a/contracts/core/price-aggregator/tests/price_aggregator_whitebox_test.rs +++ b/contracts/core/price-aggregator/tests/price_aggregator_whitebox_test.rs @@ -2,14 +2,11 @@ use multiversx_price_aggregator_sc::{ price_aggregator_data::{OracleStatus, TimestampedPrice, TokenPair}, PriceAggregator, MAX_ROUND_DURATION_SECONDS, }; -use multiversx_sc::types::{EgldOrEsdtTokenIdentifier, MultiValueEncoded}; use multiversx_sc_modules::{ pause::EndpointWrappers as PauseEndpointWrappers, staking::EndpointWrappers as StakingEndpointWrappers, }; -use multiversx_sc_scenario::{ - managed_address, managed_biguint, managed_buffer, scenario_model::*, WhiteboxContract, *, -}; +use multiversx_sc_scenario::imports::*; pub const DECIMALS: u8 = 0; pub const EGLD_TICKER: &[u8] = b"EGLD"; diff --git a/contracts/core/price-aggregator/wasm/Cargo.lock b/contracts/core/price-aggregator/wasm/Cargo.lock index e11db402c0..e67c9cc32c 100644 --- a/contracts/core/price-aggregator/wasm/Cargo.lock +++ b/contracts/core/price-aggregator/wasm/Cargo.lock @@ -86,7 +86,7 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "multiversx-price-aggregator-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "arrayvec", "getrandom", @@ -105,7 +105,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -134,7 +134,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -145,14 +145,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/core/price-aggregator/wasm/Cargo.toml b/contracts/core/price-aggregator/wasm/Cargo.toml index 193aa041fe..c4d502a4ca 100644 --- a/contracts/core/price-aggregator/wasm/Cargo.toml +++ b/contracts/core/price-aggregator/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/core/wegld-swap/Cargo.toml b/contracts/core/wegld-swap/Cargo.toml index 3b5e2404d8..d61623cc64 100644 --- a/contracts/core/wegld-swap/Cargo.toml +++ b/contracts/core/wegld-swap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-wegld-swap-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" authors = [ "Dorin Iancu ", @@ -20,13 +20,13 @@ edition = "2021" path = "src/wegld.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/core/wegld-swap/meta/Cargo.toml b/contracts/core/wegld-swap/meta/Cargo.toml index 76b79edf66..2956444fc8 100644 --- a/contracts/core/wegld-swap/meta/Cargo.toml +++ b/contracts/core/wegld-swap/meta/Cargo.toml @@ -11,10 +11,10 @@ publish = false path = ".." [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/core/wegld-swap/src/wegld.rs b/contracts/core/wegld-swap/src/wegld.rs index 4b12bbc80a..4a38cab09e 100644 --- a/contracts/core/wegld-swap/src/wegld.rs +++ b/contracts/core/wegld-swap/src/wegld.rs @@ -23,9 +23,10 @@ pub trait EgldEsdtSwap: multiversx_sc_modules::pause::PauseModule { self.send() .esdt_local_mint(&wrapped_egld_token_id, 0, &payment_amount); - let caller = self.blockchain().get_caller(); - self.send() - .direct_esdt(&caller, &wrapped_egld_token_id, 0, &payment_amount); + self.tx() + .to(ToCaller) + .single_esdt(&wrapped_egld_token_id, 0, &payment_amount) + .transfer(); EsdtTokenPayment::new(wrapped_egld_token_id, 0, payment_amount.clone_value()) } @@ -50,7 +51,7 @@ pub trait EgldEsdtSwap: multiversx_sc_modules::pause::PauseModule { // 1 wrapped eGLD = 1 eGLD, so we pay back the same amount let caller = self.blockchain().get_caller(); - self.send().direct_egld(&caller, &payment_amount); + self.tx().to(&caller).egld(&payment_amount).transfer(); } #[view(getLockedEgldBalance)] diff --git a/contracts/core/wegld-swap/wasm/Cargo.toml b/contracts/core/wegld-swap/wasm/Cargo.toml index 898c67e9f5..f21e9e13cb 100644 --- a/contracts/core/wegld-swap/wasm/Cargo.toml +++ b/contracts/core/wegld-swap/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/adder/Cargo.toml b/contracts/examples/adder/Cargo.toml index fcb4a81614..489904d6d6 100644 --- a/contracts/examples/adder/Cargo.toml +++ b/contracts/examples/adder/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/adder.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/adder/interact/Cargo.toml b/contracts/examples/adder/interact/Cargo.toml index b257e2f0fb..3cd72a5e2b 100644 --- a/contracts/examples/adder/interact/Cargo.toml +++ b/contracts/examples/adder/interact/Cargo.toml @@ -18,5 +18,5 @@ toml = "0.8.6" path = ".." [dependencies.multiversx-sc-snippets] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/snippets" diff --git a/contracts/examples/adder/interact/config.toml b/contracts/examples/adder/interact/config.toml index b7fe10a560..61ac8dbf87 100644 --- a/contracts/examples/adder/interact/config.toml +++ b/contracts/examples/adder/interact/config.toml @@ -1 +1 @@ -gateway = 'https://testnet-gateway.multiversx.com' +gateway = 'https://devnet-gateway.multiversx.com' diff --git a/contracts/examples/adder/interact/src/basic_interact.rs b/contracts/examples/adder/interact/src/basic_interact.rs index 3dd78d048a..ee11ac5844 100644 --- a/contracts/examples/adder/interact/src/basic_interact.rs +++ b/contracts/examples/adder/interact/src/basic_interact.rs @@ -2,27 +2,12 @@ mod basic_interact_cli; mod basic_interact_config; mod basic_interact_state; -use adder::ProxyTrait; +use adder::adder_proxy; use basic_interact_config::Config; use basic_interact_state::State; use clap::Parser; -use multiversx_sc_snippets::{ - env_logger, - multiversx_sc::{storage::mappers::SingleValue, types::Address}, - multiversx_sc_scenario::{ - api::StaticApi, - bech32, - mandos_system::ScenarioRunner, - num_bigint::BigUint, - scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, - scenario_model::{ - BytesValue, ScCallStep, ScDeployStep, ScQueryStep, Scenario, TransferStep, TxExpect, - }, - standalone::retrieve_account_as_scenario_set_state, - test_wallets, ContractInfo, - }, - tokio, Interactor, StepBuffer, -}; + +use multiversx_sc_snippets::imports::*; const INTERACTOR_SCENARIO_TRACE_PATH: &str = "interactor_trace.scen.json"; @@ -56,7 +41,7 @@ async fn main() { #[allow(unused)] struct AdderInteract { interactor: Interactor, - wallet_address: Address, + wallet_address: Bech32Address, adder_code: BytesValue, state: State, } @@ -76,52 +61,37 @@ impl AdderInteract { Self { interactor, - wallet_address, + wallet_address: wallet_address.into(), adder_code, state: State::load_state(), } } async fn set_state(&mut self) { - println!("wallet address: {}", bech32::encode(&self.wallet_address)); - let scenario_raw = retrieve_account_as_scenario_set_state( - Config::load_config().gateway().to_string(), - bech32::encode(&self.wallet_address), - true, - ) - .await; - - let scenario = Scenario::interpret_from(scenario_raw, &InterpreterContext::default()); - - self.interactor.pre_runners.run_scenario(&scenario); - self.interactor.post_runners.run_scenario(&scenario); + println!("wallet address: {}", self.wallet_address); + self.interactor.retrieve_account(&self.wallet_address).await; } async fn deploy(&mut self) { + // warning: multi deploy not yet fully supported + // only works with last deployed address + self.set_state().await; - self.interactor - .sc_deploy_use_result( - ScDeployStep::new() - .call(self.state.default_adder().init(BigUint::from(0u64))) - .from(&self.wallet_address) - .code(&self.adder_code), - |new_address, tr| { - tr.result.unwrap_or_else(|err| { - panic!( - "deploy failed: status: {}, message: {}", - err.status, err.message - ) - }); - - let new_address_bech32 = bech32::encode(&new_address); - println!("new address: {new_address_bech32}"); - - let new_address_expr = format!("bech32:{new_address_bech32}"); - self.state.set_adder_address(&new_address_expr); - }, - ) + let new_address = self + .interactor + .tx() + .from(&self.wallet_address) + .typed(adder_proxy::AdderProxy) + .init(0u32) + .code(&self.adder_code) + .returns(ReturnsNewBech32Address) + .prepare_async() + .run() .await; + + println!("new address: {new_address}"); + self.state.set_adder_address(new_address); } async fn multi_deploy(&mut self, count: &u8) { @@ -133,69 +103,67 @@ impl AdderInteract { self.set_state().await; println!("deploying {count} contracts..."); - let mut steps = Vec::new(); + let mut buffer = self.interactor.homogenous_call_buffer(); for _ in 0..*count { - let typed_sc_deploy = ScDeployStep::new() - .call(self.state.default_adder().init(0u32)) - .from(&self.wallet_address) - .code(&self.adder_code) - .gas_limit("70,000,000"); - - steps.push(typed_sc_deploy); + buffer.push_tx(|tx| { + tx.from(&self.wallet_address) + .typed(adder_proxy::AdderProxy) + .init(0u32) + .code(&self.adder_code) + .gas(NumExpr("70,000,000")) + .returns(ReturnsNewBech32Address) + }); } - self.interactor - .multi_sc_exec(StepBuffer::from_sc_deploy_vec(&mut steps)) - .await; + let results = buffer.run().await; + + // warning: multi deploy not yet fully supported + // only works with last deployed address - for step in steps.iter() { - // warning: multi deploy not yet fully supported - // only works with last deployed address - // will be addressed in future versions - let new_deployed_address = step.response().new_deployed_address.clone(); - if let Some(new_address) = new_deployed_address { - let new_address_bech32 = bech32::encode(&new_address); - println!("new address: {new_address_bech32}"); - } else { - println!("deploy failed"); - return; - } + for new_address in results { + println!("new address: {new_address}"); + + self.state.set_adder_address(new_address); } } async fn feed_contract_egld(&mut self) { - let _ = self - .interactor - .transfer( - TransferStep::new() - .from(&self.wallet_address) - .to(self.state.adder()) - .egld_value("0,050000000000000000"), - ) + self.interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_adder_address()) + .egld(NumExpr("0,050000000000000000")) + .prepare_async() + .run() .await; } async fn add(&mut self, value: u64) { self.interactor - .sc_call( - ScCallStep::new() - .call(self.state.adder().add(value)) - .from(&self.wallet_address) - .expect( - TxExpect::ok().additional_error_message("performing add failed with: "), - ), - ) + .tx() + .from(&self.wallet_address) + .to(self.state.current_adder_address()) + .typed(adder_proxy::AdderProxy) + .add(value) + .prepare_async() + .run() .await; println!("successfully performed add"); } async fn print_sum(&mut self) { - self.interactor - .sc_query_use_result(ScQueryStep::new().call(self.state.adder().sum()), |tr| { - let sum: SingleValue = tr.result.unwrap(); - println!("sum: {}", sum.into()); - }) + let sum = self + .interactor + .query() + .to(self.state.current_adder_address()) + .typed(adder_proxy::AdderProxy) + .sum() + .returns(ReturnsResultUnmanaged) + .prepare_async() + .run() .await; + + println!("sum: {sum}"); } } diff --git a/contracts/examples/adder/interact/src/basic_interact_state.rs b/contracts/examples/adder/interact/src/basic_interact_state.rs index 445eb52075..41453e36fd 100644 --- a/contracts/examples/adder/interact/src/basic_interact_state.rs +++ b/contracts/examples/adder/interact/src/basic_interact_state.rs @@ -1,23 +1,17 @@ -use crate::{ContractInfo, StaticApi}; +use multiversx_sc_snippets::imports::*; use serde::{Deserialize, Serialize}; use std::{ io::{Read, Write}, path::Path, }; -/// Default adder address -const DEFAULT_ADDER_ADDRESS: &str = - "0x0000000000000000000000000000000000000000000000000000000000000000"; - /// State file const STATE_FILE: &str = "state.toml"; -pub type AdderContract = ContractInfo>; - /// Multisig Interact state #[derive(Debug, Default, Serialize, Deserialize)] pub struct State { - adder_address: Option, + adder_address: Option, } impl State { @@ -34,22 +28,15 @@ impl State { } /// Sets the adder address - pub fn set_adder_address(&mut self, address: &str) { - self.adder_address = Some(String::from(address)); + pub fn set_adder_address(&mut self, address: Bech32Address) { + self.adder_address = Some(address); } /// Returns the adder contract - pub fn adder(&self) -> AdderContract { - AdderContract::new( - self.adder_address - .clone() - .expect("no known adder contract, deploy first"), - ) - } - - /// Returns the adder contract with default address - pub fn default_adder(&self) -> AdderContract { - AdderContract::new(DEFAULT_ADDER_ADDRESS) + pub fn current_adder_address(&self) -> &Bech32Address { + self.adder_address + .as_ref() + .expect("no known adder contract, deploy first") } } diff --git a/contracts/examples/adder/meta/Cargo.toml b/contracts/examples/adder/meta/Cargo.toml index c5f828ca1a..3e56ed66d7 100644 --- a/contracts/examples/adder/meta/Cargo.toml +++ b/contracts/examples/adder/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/adder/mxsc-template.toml b/contracts/examples/adder/mxsc-template.toml index 341c2d6cf5..490557cc50 100644 --- a/contracts/examples/adder/mxsc-template.toml +++ b/contracts/examples/adder/mxsc-template.toml @@ -14,6 +14,7 @@ files_include = [ "tests", "Cargo.toml", "README.md", + "sc-config.toml", "multiversx.json", "interact/Cargo.toml", "interact/config.toml", diff --git a/contracts/examples/adder/sc-config.toml b/contracts/examples/adder/sc-config.toml new file mode 100644 index 0000000000..b56f82b429 --- /dev/null +++ b/contracts/examples/adder/sc-config.toml @@ -0,0 +1,4 @@ +[settings] + +[[proxy]] +path = "src/adder_proxy.rs" diff --git a/contracts/examples/adder/src/adder.rs b/contracts/examples/adder/src/adder.rs index ff08501b42..307f4112f5 100644 --- a/contracts/examples/adder/src/adder.rs +++ b/contracts/examples/adder/src/adder.rs @@ -2,6 +2,8 @@ use multiversx_sc::imports::*; +pub mod adder_proxy; + /// One of the simplest smart contracts possible, /// it holds a single variable in storage, which anyone can increment. #[multiversx_sc::contract] diff --git a/contracts/examples/adder/src/adder_proxy.rs b/contracts/examples/adder/src/adder_proxy.rs new file mode 100644 index 0000000000..b7a7025709 --- /dev/null +++ b/contracts/examples/adder/src/adder_proxy.rs @@ -0,0 +1,110 @@ +// 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 AdderProxy; + +impl TxProxyTrait for AdderProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = AdderProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + AdderProxyMethods { wrapped_tx: tx } + } +} + +pub struct AdderProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl AdderProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + >( + self, + initial_value: Arg0, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&initial_value) + .original_result() + } +} + +#[rustfmt::skip] +impl AdderProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>, + >( + self, + initial_value: Arg0, + ) -> TxProxyUpgrade { + self.wrapped_tx + .raw_upgrade() + .argument(&initial_value) + .original_result() + } +} + +#[rustfmt::skip] +impl AdderProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn sum( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getSum") + .original_result() + } + + /// Add desired amount to the storage variable. + pub fn add< + Arg0: ProxyArg>, + >( + self, + value: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("add") + .argument(&value) + .original_result() + } +} diff --git a/contracts/examples/adder/tests/adder_blackbox_test.rs b/contracts/examples/adder/tests/adder_blackbox_test.rs index 92dba83b12..a0064a65d0 100644 --- a/contracts/examples/adder/tests/adder_blackbox_test.rs +++ b/contracts/examples/adder/tests/adder_blackbox_test.rs @@ -1,53 +1,68 @@ -use multiversx_sc_scenario::{scenario_model::*, *}; +use multiversx_sc_scenario::imports::*; -const ADDER_PATH_EXPR: &str = "mxsc:output/adder.mxsc.json"; +use adder::*; + +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const ADDER_ADDRESS: TestSCAddress = TestSCAddress::new("adder"); +const CODE_PATH: MxscPath = MxscPath::new("output/adder.mxsc.json"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); blockchain.set_current_dir_from_workspace("contracts/examples/adder"); - blockchain.register_contract(ADDER_PATH_EXPR, adder::ContractBuilder); + blockchain.register_contract(CODE_PATH, adder::ContractBuilder); blockchain } #[test] -fn adder_blackbox_raw() { +fn adder_blackbox() { let mut world = world(); - let adder_code = world.code_expression(ADDER_PATH_EXPR); + + world.start_trace(); + + world.account(OWNER_ADDRESS).nonce(1); + + let new_address = world + .tx() + .from(OWNER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .init(5u32) + .code(CODE_PATH) + .new_address(ADDER_ADDRESS) + .returns(ReturnsNewAddress) + .run(); + + assert_eq!(new_address, ADDER_ADDRESS.to_address()); + + world + .query() + .to(ADDER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .sum() + .returns(ExpectValue(5u32)) + .run(); world - .set_state_step( - SetStateStep::new() - .put_account("address:owner", Account::new().nonce(1)) - .new_address("address:owner", 1, "sc:adder"), - ) - .sc_deploy( - ScDeployStep::new() - .from("address:owner") - .code(adder_code) - .argument("5") - .expect(TxExpect::ok().no_result()), - ) - .sc_query( - ScQueryStep::new() - .to("sc:adder") - .function("getSum") - .expect(TxExpect::ok().result("5")), - ) - .sc_call( - ScCallStep::new() - .from("address:owner") - .to("sc:adder") - .function("add") - .argument("3") - .expect(TxExpect::ok().no_result()), - ) - .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_ADDRESS) + .to(ADDER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .add(1u32) + .run(); + + world + .query() + .to(ADDER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .sum() + .returns(ExpectValue(6u32)) + .run(); + + world.check_account(OWNER_ADDRESS); + + world + .check_account(ADDER_ADDRESS) + .check_storage("str:sum", "6"); + + world.write_scenario_trace("trace1.scen.json"); } diff --git a/contracts/examples/adder/tests/adder_blackbox_with_values_test.rs b/contracts/examples/adder/tests/adder_blackbox_with_values_test.rs deleted file mode 100644 index 159b71cf14..0000000000 --- a/contracts/examples/adder/tests/adder_blackbox_with_values_test.rs +++ /dev/null @@ -1,59 +0,0 @@ -use adder::*; -use multiversx_sc::storage::mappers::SingleValue; -use multiversx_sc_scenario::{api::StaticApi, num_bigint::BigUint, scenario_model::*, *}; - -const ADDER_PATH_EXPR: &str = "mxsc:output/adder.mxsc.json"; - -fn world() -> ScenarioWorld { - let mut blockchain = ScenarioWorld::new(); - blockchain.set_current_dir_from_workspace("contracts/examples/adder"); - - blockchain.register_contract(ADDER_PATH_EXPR, adder::ContractBuilder); - blockchain -} - -#[test] -fn adder_blackbox_with_values() { - let mut world = world(); - let owner_address = "address:owner"; - let mut adder_contract = ContractInfo::>::new("sc:adder"); - let adder_code = world.code_expression(ADDER_PATH_EXPR); - - world - .start_trace() - .set_state_step( - SetStateStep::new() - .put_account(owner_address, Account::new().nonce(1)) - .new_address(owner_address, 1, "sc:adder"), - ) - .sc_deploy_use_result( - ScDeployStep::new() - .from(owner_address) - .code(adder_code) - .call(adder_contract.init(5u32)), - |new_address, _: TypedResponse<()>| { - assert_eq!(new_address, adder_contract.to_address()); - }, - ) - .sc_query( - ScQueryStep::new() - .to(&adder_contract) - .call(adder_contract.sum()) - .expect_value(SingleValue::from(BigUint::from(5u32))), - ) - .sc_call( - ScCallStep::new() - .from(owner_address) - .to(&adder_contract) - .call(adder_contract.add(3u32)), - ) - .check_state_step( - CheckStateStep::new() - .put_account(owner_address, CheckAccount::new()) - .put_account( - &adder_contract, - CheckAccount::new().check_storage("str:sum", "8"), - ), - ) - .write_scenario_trace("trace1.scen.json"); -} diff --git a/contracts/examples/adder/tests/adder_test.rs b/contracts/examples/adder/tests/adder_unit_test.rs similarity index 100% rename from contracts/examples/adder/tests/adder_test.rs rename to contracts/examples/adder/tests/adder_unit_test.rs diff --git a/contracts/examples/adder/tests/adder_whitebox_test.rs b/contracts/examples/adder/tests/adder_whitebox_test.rs index d068aa1b1d..50ad95faa6 100644 --- a/contracts/examples/adder/tests/adder_whitebox_test.rs +++ b/contracts/examples/adder/tests/adder_whitebox_test.rs @@ -1,5 +1,5 @@ use adder::*; -use multiversx_sc_scenario::{scenario_model::*, *}; +use multiversx_sc_scenario::imports::*; const ADDER_PATH_EXPR: &str = "mxsc:output/adder.mxsc.json"; diff --git a/contracts/examples/adder/wasm/Cargo.lock b/contracts/examples/adder/wasm/Cargo.lock index 08d1e86a84..2773eb0d37 100755 --- a/contracts/examples/adder/wasm/Cargo.lock +++ b/contracts/examples/adder/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/adder/wasm/Cargo.toml b/contracts/examples/adder/wasm/Cargo.toml index 39a90d64f8..a759e0edf8 100644 --- a/contracts/examples/adder/wasm/Cargo.toml +++ b/contracts/examples/adder/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/adder/wasm/src/lib.rs b/contracts/examples/adder/wasm/src/lib.rs index 13bb12ad6e..f5f1d356c2 100644 --- a/contracts/examples/adder/wasm/src/lib.rs +++ b/contracts/examples/adder/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 3 +// Upgrade: 1 +// Endpoints: 2 // Async Callback (empty): 1 // Total number of exported functions: 5 @@ -20,8 +21,8 @@ multiversx_sc_wasm_adapter::endpoints! { adder ( init => init - getSum => sum upgrade => upgrade + getSum => sum add => add ) } diff --git a/contracts/examples/bonding-curve-contract/Cargo.toml b/contracts/examples/bonding-curve-contract/Cargo.toml index ae60af5f8e..4a9d90bddc 100644 --- a/contracts/examples/bonding-curve-contract/Cargo.toml +++ b/contracts/examples/bonding-curve-contract/Cargo.toml @@ -9,14 +9,14 @@ publish = false path = "src/bonding_curve_contract.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/bonding-curve-contract/meta/Cargo.toml b/contracts/examples/bonding-curve-contract/meta/Cargo.toml index f5ab553289..dbcdbc57e0 100644 --- a/contracts/examples/bonding-curve-contract/meta/Cargo.toml +++ b/contracts/examples/bonding-curve-contract/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/bonding-curve-contract/wasm/Cargo.lock b/contracts/examples/bonding-curve-contract/wasm/Cargo.lock index 309cf22a03..698514f67d 100644 --- a/contracts/examples/bonding-curve-contract/wasm/Cargo.lock +++ b/contracts/examples/bonding-curve-contract/wasm/Cargo.lock @@ -56,7 +56,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/bonding-curve-contract/wasm/Cargo.toml b/contracts/examples/bonding-curve-contract/wasm/Cargo.toml index 694f0e06e2..bf4f7f2d5b 100644 --- a/contracts/examples/bonding-curve-contract/wasm/Cargo.toml +++ b/contracts/examples/bonding-curve-contract/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/check-pause/Cargo.toml b/contracts/examples/check-pause/Cargo.toml index cda87d9f27..355224e160 100644 --- a/contracts/examples/check-pause/Cargo.toml +++ b/contracts/examples/check-pause/Cargo.toml @@ -12,14 +12,14 @@ path = "src/check_pause.rs" num-bigint = "0.4" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/check-pause/meta/Cargo.toml b/contracts/examples/check-pause/meta/Cargo.toml index 839f004ce3..21465dc7ed 100644 --- a/contracts/examples/check-pause/meta/Cargo.toml +++ b/contracts/examples/check-pause/meta/Cargo.toml @@ -9,6 +9,6 @@ authors = ["Alin Cruceat "] path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/check-pause/wasm/Cargo.lock b/contracts/examples/check-pause/wasm/Cargo.lock index b21f0ad6d1..814b67a5c7 100644 --- a/contracts/examples/check-pause/wasm/Cargo.lock +++ b/contracts/examples/check-pause/wasm/Cargo.lock @@ -56,7 +56,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/check-pause/wasm/Cargo.toml b/contracts/examples/check-pause/wasm/Cargo.toml index 23d31951b1..0602c3b653 100644 --- a/contracts/examples/check-pause/wasm/Cargo.toml +++ b/contracts/examples/check-pause/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/crowdfunding-esdt/Cargo.toml b/contracts/examples/crowdfunding-esdt/Cargo.toml index e0a91a86d6..498b1999b6 100644 --- a/contracts/examples/crowdfunding-esdt/Cargo.toml +++ b/contracts/examples/crowdfunding-esdt/Cargo.toml @@ -9,11 +9,11 @@ publish = false path = "src/crowdfunding_esdt.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies] diff --git a/contracts/examples/crowdfunding-esdt/meta/Cargo.toml b/contracts/examples/crowdfunding-esdt/meta/Cargo.toml index d2b9ff88fe..191c2d0a28 100644 --- a/contracts/examples/crowdfunding-esdt/meta/Cargo.toml +++ b/contracts/examples/crowdfunding-esdt/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/crowdfunding-esdt/sc-config.toml b/contracts/examples/crowdfunding-esdt/sc-config.toml new file mode 100644 index 0000000000..16f6430728 --- /dev/null +++ b/contracts/examples/crowdfunding-esdt/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "src/crowdfunding_esdt_proxy.rs" diff --git a/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs index 8fa04d2e46..1dea493562 100644 --- a/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs +++ b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs @@ -1,8 +1,10 @@ #![no_std] use multiversx_sc::{derive_imports::*, imports::*}; +pub mod crowdfunding_esdt_proxy; -#[derive(TopEncode, TopDecode, TypeAbi, PartialEq, Eq, Clone, Copy, Debug)] +#[type_abi] +#[derive(TopEncode, TopDecode, PartialEq, Eq, Clone, Copy, Debug)] pub enum Status { FundingPeriod, Successful, @@ -73,8 +75,10 @@ pub trait Crowdfunding { let token_identifier = self.cf_token_identifier().get(); let sc_balance = self.get_current_funds(); - self.send() - .direct(&caller, &token_identifier, 0, &sc_balance); + self.tx() + .to(&caller) + .egld_or_single_esdt(&token_identifier, 0, &sc_balance) + .transfer(); }, Status::Failed => { let caller = self.blockchain().get_caller(); @@ -84,7 +88,10 @@ pub trait Crowdfunding { let token_identifier = self.cf_token_identifier().get(); self.deposit(&caller).clear(); - self.send().direct(&caller, &token_identifier, 0, &deposit); + self.tx() + .to(&caller) + .egld_or_single_esdt(&token_identifier, 0, &deposit) + .transfer(); } }, } diff --git a/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt_proxy.rs b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt_proxy.rs new file mode 100644 index 0000000000..a1fe1dddda --- /dev/null +++ b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt_proxy.rs @@ -0,0 +1,149 @@ +// 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 CrowdfundingProxy; + +impl TxProxyTrait for CrowdfundingProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = CrowdfundingProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + CrowdfundingProxyMethods { wrapped_tx: tx } + } +} + +pub struct CrowdfundingProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl CrowdfundingProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + target: Arg0, + deadline: Arg1, + token_identifier: Arg2, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&target) + .argument(&deadline) + .argument(&token_identifier) + .original_result() + } +} + +#[rustfmt::skip] +impl CrowdfundingProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn fund( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("fund") + .original_result() + } + + pub fn status( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("status") + .original_result() + } + + pub fn get_current_funds( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getCurrentFunds") + .original_result() + } + + pub fn claim( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claim") + .original_result() + } + + pub fn target( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getTarget") + .original_result() + } + + pub fn deadline( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getDeadline") + .original_result() + } + + pub fn deposit< + Arg0: ProxyArg>, + >( + self, + donor: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getDeposit") + .argument(&donor) + .original_result() + } + + pub fn cf_token_identifier( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getCrowdfundingTokenIdentifier") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, PartialEq, Eq, Clone, Copy, Debug)] +pub enum Status { + FundingPeriod, + Successful, + Failed, +} diff --git a/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs b/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs index c6387e5c43..1a07b42101 100644 --- a/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs +++ b/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs @@ -1,157 +1,115 @@ -use crowdfunding_esdt::{ProxyTrait as _, Status}; -use multiversx_sc::{ - storage::mappers::SingleValue, - types::{Address, EgldOrEsdtTokenIdentifier}, -}; -use multiversx_sc_scenario::{ - api::StaticApi, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, ScQueryStep, - SetStateStep, TxExpect, - }, - ContractInfo, ScenarioWorld, -}; -use num_bigint::BigUint; +use crowdfunding_esdt::crowdfunding_esdt_proxy; -const CF_DEADLINE: u64 = 7 * 24 * 60 * 60; // 1 week in seconds -const CF_TOKEN_ID: &[u8] = b"CROWD-123456"; -const CF_TOKEN_ID_EXPR: &str = "str:CROWD-123456"; -const CROWDFUNDING_ESDT_ADDRESS_EXPR: &str = "sc:crowdfunding-esdt"; -const CROWDFUNDING_ESDT_PATH_EXPR: &str = "mxsc:output/crowdfunding-esdt.mxsc.json"; -const FIRST_USER_ADDRESS_EXPR: &str = "address:first-user"; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const SECOND_USER_ADDRESS_EXPR: &str = "address:second-user"; +use multiversx_sc_scenario::imports::*; -type CrowdfundingESDTContract = ContractInfo>; +const CF_DEADLINE: u64 = 7 * 24 * 60 * 60; // 1 week in seconds +const CF_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("CROWD-123456"); +const FIRST_USER_ADDRESS: TestAddress = TestAddress::new("first-user"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const SECOND_USER_ADDRESS: TestAddress = TestAddress::new("second-user"); +const CODE_PATH: MxscPath = MxscPath::new("output/crowdfunding-esdt.mxsc.json"); +const CROWDFUNDING_ADDRESS: TestSCAddress = TestSCAddress::new("crowdfunding-esdt"); fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.set_current_dir_from_workspace("contracts/examples/crowdfunding-esdt"); - blockchain.register_contract( - CROWDFUNDING_ESDT_PATH_EXPR, - crowdfunding_esdt::ContractBuilder, - ); + blockchain.register_contract(CODE_PATH, crowdfunding_esdt::ContractBuilder); blockchain } struct CrowdfundingESDTTestState { world: ScenarioWorld, - crowdfunding_esdt_contract: CrowdfundingESDTContract, - first_user_address: Address, - second_user_address: Address, } impl CrowdfundingESDTTestState { fn new() -> Self { 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, CROWDFUNDING_ESDT_ADDRESS_EXPR) - .put_account( - FIRST_USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .balance("1_000") - .esdt_balance(CF_TOKEN_ID_EXPR, "1_000"), - ) - .put_account( - SECOND_USER_ADDRESS_EXPR, - Account::new() - .nonce(1) - .esdt_balance(CF_TOKEN_ID_EXPR, "1_000"), - ), - ); - - let crowdfunding_esdt_contract = - CrowdfundingESDTContract::new(CROWDFUNDING_ESDT_ADDRESS_EXPR); - - let first_user_address = AddressValue::from(FIRST_USER_ADDRESS_EXPR).to_address(); - let second_user_address = AddressValue::from(SECOND_USER_ADDRESS_EXPR).to_address(); - - Self { - world, - crowdfunding_esdt_contract, - first_user_address, - second_user_address, - } - } + world.account(OWNER_ADDRESS).nonce(1); - fn deploy(&mut self) -> &mut Self { - let crowdfunding_esdt_code = self.world.code_expression(CROWDFUNDING_ESDT_PATH_EXPR); - - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(crowdfunding_esdt_code) - .call(self.crowdfunding_esdt_contract.init( - 2_000u32, - CF_DEADLINE, - EgldOrEsdtTokenIdentifier::esdt(CF_TOKEN_ID), - )), - ); - - self - } + world + .account(FIRST_USER_ADDRESS) + .nonce(1) + .balance(1000) + .esdt_balance(CF_TOKEN_ID, 1000); - fn fund(&mut self, address: &str, amount: &str) -> &mut Self { - self.world.sc_call( - ScCallStep::new() - .from(address) - .esdt_transfer(CF_TOKEN_ID_EXPR, 0, amount) - .call(self.crowdfunding_esdt_contract.fund()), - ); + world + .account(SECOND_USER_ADDRESS) + .nonce(1) + .esdt_balance(CF_TOKEN_ID, 1000); - self + Self { world } } - fn check_deposit(&mut self, donor: Address, amount: u64) -> &mut Self { - self.world.sc_query( - ScQueryStep::new() - .call(self.crowdfunding_esdt_contract.deposit(&donor)) - .expect_value(SingleValue::from(BigUint::from(amount))), - ); - - self + fn deploy(&mut self) { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .init( + 2_000u32, + CF_DEADLINE, + EgldOrEsdtTokenIdentifier::esdt(CF_TOKEN_ID), + ) + .code(CODE_PATH) + .new_address(CROWDFUNDING_ADDRESS) + .run(); } - fn check_status(&mut self, expected_value: Status) -> &mut Self { - self.world.sc_query( - ScQueryStep::new() - .call(self.crowdfunding_esdt_contract.status()) - .expect_value(expected_value), - ); - - self + fn fund(&mut self, address: TestAddress, amount: u64) { + self.world + .tx() + .from(address) + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .fund() + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(CF_TOKEN_ID), + 0u64, + &multiversx_sc::proxy_imports::BigUint::from(amount), + ) + .run(); } - fn claim(&mut self, address: &str) -> &mut Self { - self.world.sc_call( - ScCallStep::new() - .from(address) - .call(self.crowdfunding_esdt_contract.claim()), - ); + fn check_deposit(&mut self, donor: TestAddress, amount: u64) { + self.world + .query() + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .deposit(donor) + .returns(ExpectValue(amount)) + .run(); + } - self + fn check_status(&mut self, expected_value: crowdfunding_esdt_proxy::Status) { + self.world + .query() + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .status() + .returns(ExpectValue(expected_value)) + .run(); } - fn check_esdt_balance(&mut self, address_expr: &str, balance_expr: &str) -> &mut Self { + fn claim(&mut self, address: TestAddress) { self.world - .check_state_step(CheckStateStep::new().put_account( - address_expr, - CheckAccount::new().esdt_balance(CF_TOKEN_ID_EXPR, balance_expr), - )); + .tx() + .from(address) + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .claim() + .run(); + } - self + fn check_esdt_balance(&mut self, address: TestAddress, balance: u64) { + self.world + .check_account(address) + .esdt_balance(CF_TOKEN_ID, balance); } - fn set_block_timestamp(&mut self, block_timestamp_expr: u64) -> &mut Self { + fn set_block_timestamp(&mut self, block_timestamp_expr: u64) { self.world .set_state_step(SetStateStep::new().block_timestamp(block_timestamp_expr)); - - self } } @@ -160,8 +118,8 @@ fn test_fund() { let mut state = CrowdfundingESDTTestState::new(); state.deploy(); - state.fund(FIRST_USER_ADDRESS_EXPR, "1000"); - state.check_deposit(state.first_user_address.clone(), 1_000); + state.fund(FIRST_USER_ADDRESS, 1_000u64); + state.check_deposit(FIRST_USER_ADDRESS, 1_000u64); } #[test] @@ -169,7 +127,7 @@ fn test_status() { let mut state = CrowdfundingESDTTestState::new(); state.deploy(); - state.check_status(Status::FundingPeriod); + state.check_status(crowdfunding_esdt_proxy::Status::FundingPeriod); } #[test] @@ -177,22 +135,18 @@ fn test_sc_error() { let mut state = CrowdfundingESDTTestState::new(); state.deploy(); - state.world.sc_call( - ScCallStep::new() - .from(FIRST_USER_ADDRESS_EXPR) - .egld_value("1_000") - .call(state.crowdfunding_esdt_contract.fund()) - .expect(TxExpect::user_error("str:wrong token")), - ); - state.world.sc_query( - ScQueryStep::new() - .call( - state - .crowdfunding_esdt_contract - .deposit(&state.first_user_address), - ) - .expect(TxExpect::ok().result("0x")), - ); + state + .world + .tx() + .from(FIRST_USER_ADDRESS) + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .fund() + .egld(1000) + .with_result(ExpectError(4, "wrong token")) + .run(); + + state.check_deposit(FIRST_USER_ADDRESS, 0); } #[test] @@ -201,35 +155,35 @@ fn test_successful_cf() { state.deploy(); // first user fund - state.fund(FIRST_USER_ADDRESS_EXPR, "1_000"); - state.check_deposit(state.first_user_address.clone(), 1_000); + state.fund(FIRST_USER_ADDRESS, 1_000u64); + state.check_deposit(FIRST_USER_ADDRESS, 1_000); // second user fund - state.fund(SECOND_USER_ADDRESS_EXPR, "1_000"); - state.check_deposit(state.second_user_address.clone(), 1_000); + state.fund(SECOND_USER_ADDRESS, 1000); + state.check_deposit(SECOND_USER_ADDRESS, 1_000); // set block timestamp after deadline state.set_block_timestamp(CF_DEADLINE + 1); // check status successful - state.check_status(Status::Successful); - - // user try claim - state.world.sc_call( - ScCallStep::new() - .from(FIRST_USER_ADDRESS_EXPR) - .call(state.crowdfunding_esdt_contract.claim()) - .expect(TxExpect::user_error( - "str:only owner can claim successful funding", - )), - ); + state.check_status(crowdfunding_esdt_proxy::Status::Successful); + + state + .world + .tx() + .from(FIRST_USER_ADDRESS) + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .claim() + .with_result(ExpectError(4, "only owner can claim successful funding")) + .run(); // owner claim - state.claim(OWNER_ADDRESS_EXPR); + state.claim(OWNER_ADDRESS); - state.check_esdt_balance(OWNER_ADDRESS_EXPR, "2_000"); - state.check_esdt_balance(FIRST_USER_ADDRESS_EXPR, "0"); - state.check_esdt_balance(SECOND_USER_ADDRESS_EXPR, "0"); + state.check_esdt_balance(OWNER_ADDRESS, 2000); + state.check_esdt_balance(FIRST_USER_ADDRESS, 0); + state.check_esdt_balance(SECOND_USER_ADDRESS, 0); } #[test] @@ -238,26 +192,26 @@ fn test_failed_cf() { state.deploy(); // first user fund - state.fund(FIRST_USER_ADDRESS_EXPR, "300"); - state.check_deposit(state.first_user_address.clone(), 300u64); + state.fund(FIRST_USER_ADDRESS, 300); + state.check_deposit(FIRST_USER_ADDRESS, 300u64); // second user fund - state.fund(SECOND_USER_ADDRESS_EXPR, "600"); - state.check_deposit(state.second_user_address.clone(), 600u64); + state.fund(SECOND_USER_ADDRESS, 600); + state.check_deposit(SECOND_USER_ADDRESS, 600u64); // set block timestamp after deadline state.set_block_timestamp(CF_DEADLINE + 1); // check status failed - state.check_status(Status::Failed); + state.check_status(crowdfunding_esdt_proxy::Status::Failed); // first user claim - state.claim(FIRST_USER_ADDRESS_EXPR); + state.claim(FIRST_USER_ADDRESS); // second user claim - state.claim(SECOND_USER_ADDRESS_EXPR); + state.claim(SECOND_USER_ADDRESS); - state.check_esdt_balance(OWNER_ADDRESS_EXPR, "0"); - state.check_esdt_balance(FIRST_USER_ADDRESS_EXPR, "1_000"); - state.check_esdt_balance(SECOND_USER_ADDRESS_EXPR, "1_000"); + state.check_esdt_balance(OWNER_ADDRESS, 0); + state.check_esdt_balance(FIRST_USER_ADDRESS, 1000); + state.check_esdt_balance(SECOND_USER_ADDRESS, 1000); } diff --git a/contracts/examples/crowdfunding-esdt/wasm/Cargo.lock b/contracts/examples/crowdfunding-esdt/wasm/Cargo.lock index d6516b3acf..346820f735 100644 --- a/contracts/examples/crowdfunding-esdt/wasm/Cargo.lock +++ b/contracts/examples/crowdfunding-esdt/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/crowdfunding-esdt/wasm/Cargo.toml b/contracts/examples/crowdfunding-esdt/wasm/Cargo.toml index 80d4c8f4ee..93c39e692f 100644 --- a/contracts/examples/crowdfunding-esdt/wasm/Cargo.toml +++ b/contracts/examples/crowdfunding-esdt/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/crypto-bubbles/Cargo.toml b/contracts/examples/crypto-bubbles/Cargo.toml index 3432fb2fb1..6e841be6b9 100644 --- a/contracts/examples/crypto-bubbles/Cargo.toml +++ b/contracts/examples/crypto-bubbles/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/crypto_bubbles.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/crypto-bubbles/meta/Cargo.toml b/contracts/examples/crypto-bubbles/meta/Cargo.toml index a5a0becbbf..60b167f206 100644 --- a/contracts/examples/crypto-bubbles/meta/Cargo.toml +++ b/contracts/examples/crypto-bubbles/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/crypto-bubbles/src/crypto_bubbles.rs b/contracts/examples/crypto-bubbles/src/crypto_bubbles.rs index da481fd273..35b687f2cc 100644 --- a/contracts/examples/crypto-bubbles/src/crypto_bubbles.rs +++ b/contracts/examples/crypto-bubbles/src/crypto_bubbles.rs @@ -38,7 +38,7 @@ pub trait CryptoBubbles { *balance -= amount; }); - self.send().direct_egld(player, amount); + self.tx().to(player).egld(amount).transfer(); self.withdraw_event(player, amount); } diff --git a/contracts/examples/crypto-bubbles/wasm/Cargo.lock b/contracts/examples/crypto-bubbles/wasm/Cargo.lock index 3a40a41c01..a3381f8c16 100755 --- a/contracts/examples/crypto-bubbles/wasm/Cargo.lock +++ b/contracts/examples/crypto-bubbles/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/crypto-bubbles/wasm/Cargo.toml b/contracts/examples/crypto-bubbles/wasm/Cargo.toml index c3d76936e1..cbfe399baf 100644 --- a/contracts/examples/crypto-bubbles/wasm/Cargo.toml +++ b/contracts/examples/crypto-bubbles/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/crypto-kitties/common/kitty/Cargo.toml b/contracts/examples/crypto-kitties/common/kitty/Cargo.toml index 22ba077695..d83a9fdd5d 100644 --- a/contracts/examples/crypto-kitties/common/kitty/Cargo.toml +++ b/contracts/examples/crypto-kitties/common/kitty/Cargo.toml @@ -9,7 +9,7 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/base" [dependencies.random] diff --git a/contracts/examples/crypto-kitties/common/kitty/src/color.rs b/contracts/examples/crypto-kitties/common/kitty/src/color.rs index 0b02aecf49..37a97b1dfc 100644 --- a/contracts/examples/crypto-kitties/common/kitty/src/color.rs +++ b/contracts/examples/crypto-kitties/common/kitty/src/color.rs @@ -2,7 +2,8 @@ use multiversx_sc::derive_imports::*; use random::*; -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone, TypeAbi, Default)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone, Default)] pub struct Color { pub r: u8, pub g: u8, @@ -36,3 +37,9 @@ impl Randomizeable for Color { } } } + +impl Color { + pub fn as_u64(&self) -> u64 { + ((self.r.to_be() as u64) << 4 | self.r.to_be() as u64) << 4 | self.r.to_be() as u64 + } +} diff --git a/contracts/examples/crypto-kitties/common/kitty/src/kitty.rs b/contracts/examples/crypto-kitties/common/kitty/src/kitty.rs new file mode 100644 index 0000000000..d234cac9f6 --- /dev/null +++ b/contracts/examples/crypto-kitties/common/kitty/src/kitty.rs @@ -0,0 +1,89 @@ +use crate::{Color, KittyGenes}; + +use multiversx_sc::derive_imports::*; + +const SECONDS_PER_MINUTE: u64 = 60; +const MAX_COOLDOWN: u64 = 60 * 60 * 24 * 7; // 7 days +const MAX_TIREDNESS: u16 = 20; + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct Kitty { + pub genes: KittyGenes, + pub birth_time: u64, // timestamp + pub cooldown_end: u64, // timestamp, used for pregnancy timer and siring cooldown + pub matron_id: u32, + pub sire_id: u32, + pub siring_with_id: u32, // for pregnant cats, 0 otherwise + pub nr_children: u16, // cooldown period increases exponentially with every breeding/siring + pub generation: u16, // max(sire_gen, matron_gen) + 1. Generation also influences cooldown. +} + +impl Kitty { + pub fn new( + genes: KittyGenes, + birth_time: u64, + matron_id: u32, + sire_id: u32, + generation: u16, + ) -> Self { + Kitty { + genes, + birth_time, + cooldown_end: 0, + matron_id, + sire_id, + siring_with_id: 0, + nr_children: 0, + generation, + } + } +} + +impl Kitty { + pub fn get_next_cooldown_time(&self) -> u64 { + let tiredness = self.nr_children + self.generation / 2; + if tiredness > MAX_TIREDNESS { + return MAX_COOLDOWN; + } + + let cooldown = SECONDS_PER_MINUTE << tiredness; // 2^(tiredness) minutes + if cooldown > MAX_COOLDOWN { + MAX_COOLDOWN + } else { + cooldown + } + } + + pub fn get_fur_color(&self) -> Color { + self.genes.fur_color.clone() + } + + pub fn get_eye_color(&self) -> Color { + self.genes.eye_color.clone() + } + + pub fn get_meow_power(&self) -> u8 { + self.genes.meow_power + } + + pub fn is_pregnant(&self) -> bool { + self.siring_with_id != 0 + } +} + +// The default Kitty, which is not a valid kitty. Used for Kitty with ID 0 +impl Default for Kitty { + fn default() -> Self { + Kitty { + genes: KittyGenes::default(), + birth_time: 0, + cooldown_end: u64::MAX, + matron_id: 0, + sire_id: 0, + siring_with_id: 0, + nr_children: 0, + generation: 0, + } + } +} diff --git a/contracts/examples/crypto-kitties/common/kitty/src/kitty_genes.rs b/contracts/examples/crypto-kitties/common/kitty/src/kitty_genes.rs index 4deb4100e6..61d6623bf9 100644 --- a/contracts/examples/crypto-kitties/common/kitty/src/kitty_genes.rs +++ b/contracts/examples/crypto-kitties/common/kitty/src/kitty_genes.rs @@ -3,7 +3,8 @@ use multiversx_sc::derive_imports::*; use super::color::*; use random::*; -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone, TypeAbi, Default)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone, Default)] pub struct KittyGenes { pub fur_color: Color, pub eye_color: Color, @@ -19,3 +20,10 @@ impl Randomizeable for KittyGenes { } } } + +impl KittyGenes { + pub fn get_as_u64(&self) -> u64 { + (self.fur_color.as_u64() << 12 | self.eye_color.as_u64()) << 4 + | self.meow_power.to_be() as u64 + } +} diff --git a/contracts/examples/crypto-kitties/common/kitty/src/lib.rs b/contracts/examples/crypto-kitties/common/kitty/src/lib.rs index c06f376e8d..863944215c 100644 --- a/contracts/examples/crypto-kitties/common/kitty/src/lib.rs +++ b/contracts/examples/crypto-kitties/common/kitty/src/lib.rs @@ -1,94 +1,9 @@ #![no_std] -use multiversx_sc::derive_imports::*; +mod color; +mod kitty; +mod kitty_genes; -const SECONDS_PER_MINUTE: u64 = 60; -const MAX_COOLDOWN: u64 = 60 * 60 * 24 * 7; // 7 days -const MAX_TIREDNESS: u16 = 20; - -pub mod color; -pub mod kitty_genes; - -use color::*; -use kitty_genes::*; - -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] -pub struct Kitty { - pub genes: KittyGenes, - pub birth_time: u64, // timestamp - pub cooldown_end: u64, // timestamp, used for pregnancy timer and siring cooldown - pub matron_id: u32, - pub sire_id: u32, - pub siring_with_id: u32, // for pregnant cats, 0 otherwise - pub nr_children: u16, // cooldown period increases exponentially with every breeding/siring - pub generation: u16, // max(sire_gen, matron_gen) + 1. Generation also influences cooldown. -} - -impl Kitty { - pub fn new( - genes: KittyGenes, - birth_time: u64, - matron_id: u32, - sire_id: u32, - generation: u16, - ) -> Self { - Kitty { - genes, - birth_time, - cooldown_end: 0, - matron_id, - sire_id, - siring_with_id: 0, - nr_children: 0, - generation, - } - } -} - -impl Kitty { - pub fn get_next_cooldown_time(&self) -> u64 { - let tiredness = self.nr_children + self.generation / 2; - if tiredness > MAX_TIREDNESS { - return MAX_COOLDOWN; - } - - let cooldown = SECONDS_PER_MINUTE << tiredness; // 2^(tiredness) minutes - if cooldown > MAX_COOLDOWN { - MAX_COOLDOWN - } else { - cooldown - } - } - - pub fn get_fur_color(&self) -> Color { - self.genes.fur_color.clone() - } - - pub fn get_eye_color(&self) -> Color { - self.genes.eye_color.clone() - } - - pub fn get_meow_power(&self) -> u8 { - self.genes.meow_power - } - - pub fn is_pregnant(&self) -> bool { - self.siring_with_id != 0 - } -} - -// The default Kitty, which is not a valid kitty. Used for Kitty with ID 0 -impl Default for Kitty { - fn default() -> Self { - Kitty { - genes: KittyGenes::default(), - birth_time: 0, - cooldown_end: u64::MAX, - matron_id: 0, - sire_id: 0, - siring_with_id: 0, - nr_children: 0, - generation: 0, - } - } -} +pub use color::Color; +pub use kitty::Kitty; +pub use kitty_genes::KittyGenes; diff --git a/contracts/examples/crypto-kitties/common/random/Cargo.toml b/contracts/examples/crypto-kitties/common/random/Cargo.toml index 80fc00284b..bfab4a12d7 100644 --- a/contracts/examples/crypto-kitties/common/random/Cargo.toml +++ b/contracts/examples/crypto-kitties/common/random/Cargo.toml @@ -8,5 +8,5 @@ edition = "2021" path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/base" diff --git a/contracts/examples/crypto-kitties/kitty-auction/Cargo.toml b/contracts/examples/crypto-kitties/kitty-auction/Cargo.toml index 720f88798f..ce7971579f 100644 --- a/contracts/examples/crypto-kitties/kitty-auction/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-auction/Cargo.toml @@ -17,9 +17,9 @@ version = "0.0.0" path = "../kitty-ownership" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/examples/crypto-kitties/kitty-auction/meta/Cargo.toml b/contracts/examples/crypto-kitties/kitty-auction/meta/Cargo.toml index f26826105f..938f83ffd6 100644 --- a/contracts/examples/crypto-kitties/kitty-auction/meta/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-auction/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/examples/crypto-kitties/kitty-auction/src/auction.rs b/contracts/examples/crypto-kitties/kitty-auction/src/auction.rs index fda71eb13d..261def0cf0 100644 --- a/contracts/examples/crypto-kitties/kitty-auction/src/auction.rs +++ b/contracts/examples/crypto-kitties/kitty-auction/src/auction.rs @@ -11,7 +11,8 @@ pub enum AuctionType { Siring, } -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct Auction { pub auction_type: AuctionType, pub starting_price: BigUint, diff --git a/contracts/examples/crypto-kitties/kitty-auction/src/kitty_ownership_proxy.rs b/contracts/examples/crypto-kitties/kitty-auction/src/kitty_ownership_proxy.rs new file mode 100644 index 0000000000..87f5bdb4a2 --- /dev/null +++ b/contracts/examples/crypto-kitties/kitty-auction/src/kitty_ownership_proxy.rs @@ -0,0 +1,339 @@ +// 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 KittyOwnershipProxy; + +impl TxProxyTrait for KittyOwnershipProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = KittyOwnershipProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + KittyOwnershipProxyMethods { wrapped_tx: tx } + } +} + +pub struct KittyOwnershipProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl KittyOwnershipProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + Arg2: ProxyArg>>, + >( + self, + birth_fee: Arg0, + opt_gene_science_contract_address: Arg1, + opt_kitty_auction_contract_address: Arg2, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&birth_fee) + .argument(&opt_gene_science_contract_address) + .argument(&opt_kitty_auction_contract_address) + .original_result() + } +} + +#[rustfmt::skip] +impl KittyOwnershipProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn set_gene_science_contract_address_endpoint< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setGeneScienceContractAddress") + .argument(&address) + .original_result() + } + + pub fn set_kitty_auction_contract_address_endpoint< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setKittyAuctionContractAddress") + .argument(&address) + .original_result() + } + + pub fn claim( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claim") + .original_result() + } + + pub fn total_supply( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("totalSupply") + .original_result() + } + + pub fn balance_of< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("balanceOf") + .argument(&address) + .original_result() + } + + pub fn owner_of< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("ownerOf") + .argument(&kitty_id) + .original_result() + } + + pub fn approve< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + to: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approve") + .argument(&to) + .argument(&kitty_id) + .original_result() + } + + pub fn transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + to: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer") + .argument(&to) + .argument(&kitty_id) + .original_result() + } + + pub fn transfer_from< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + from: Arg0, + to: Arg1, + kitty_id: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer_from") + .argument(&from) + .argument(&to) + .argument(&kitty_id) + .original_result() + } + + pub fn tokens_of_owner< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("tokensOfOwner") + .argument(&address) + .original_result() + } + + pub fn allow_auctioning< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + by: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("allowAuctioning") + .argument(&by) + .argument(&kitty_id) + .original_result() + } + + pub fn approve_siring_and_return_kitty< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + approved_address: Arg0, + kitty_owner: Arg1, + kitty_id: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approveSiringAndReturnKitty") + .argument(&approved_address) + .argument(&kitty_owner) + .argument(&kitty_id) + .original_result() + } + + pub fn create_gen_zero_kitty( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("createGenZeroKitty") + .original_result() + } + + pub fn get_kitty_by_id_endpoint< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getKittyById") + .argument(&kitty_id) + .original_result() + } + + pub fn is_ready_to_breed< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isReadyToBreed") + .argument(&kitty_id) + .original_result() + } + + pub fn is_pregnant< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isPregnant") + .argument(&kitty_id) + .original_result() + } + + pub fn can_breed_with< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + matron_id: Arg0, + sire_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("canBreedWith") + .argument(&matron_id) + .argument(&sire_id) + .original_result() + } + + pub fn approve_siring< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + address: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approveSiring") + .argument(&address) + .argument(&kitty_id) + .original_result() + } + + pub fn breed_with< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + matron_id: Arg0, + sire_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("breedWith") + .argument(&matron_id) + .argument(&sire_id) + .original_result() + } + + pub fn give_birth< + Arg0: ProxyArg, + >( + self, + matron_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("giveBirth") + .argument(&matron_id) + .original_result() + } + + pub fn birth_fee( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("birthFee") + .original_result() + } +} diff --git a/contracts/examples/crypto-kitties/kitty-auction/src/lib.rs b/contracts/examples/crypto-kitties/kitty-auction/src/lib.rs index af7c7c1736..60a30c382e 100644 --- a/contracts/examples/crypto-kitties/kitty-auction/src/lib.rs +++ b/contracts/examples/crypto-kitties/kitty-auction/src/lib.rs @@ -4,6 +4,7 @@ use multiversx_sc::imports::*; pub mod auction; use auction::*; +pub mod kitty_ownership_proxy; #[multiversx_sc::contract] pub trait KittyAuction { @@ -45,11 +46,12 @@ pub trait KittyAuction { "Kitty Ownership contract address not set!" ); - self.kitty_ownership_proxy(kitty_ownership_contract_address) + self.tx() + .to(&kitty_ownership_contract_address) + .typed(kitty_ownership_proxy::KittyOwnershipProxy) .create_gen_zero_kitty() - .async_call() - .with_callback(self.callbacks().create_gen_zero_kitty_callback()) - .call_and_exit() + .callback(self.callbacks().create_gen_zero_kitty_callback()) + .async_call_and_exit(); } // views @@ -183,8 +185,10 @@ pub trait KittyAuction { // refund losing bid if !auction.current_winner.is_zero() { - self.send() - .direct_egld(&auction.current_winner, &auction.current_bid); + self.tx() + .to(&auction.current_winner) + .egld(&auction.current_bid) + .transfer(); } // update auction bid and winner @@ -238,10 +242,11 @@ pub trait KittyAuction { let kitty_ownership_contract_address = self.get_kitty_ownership_contract_address_or_default(); if !kitty_ownership_contract_address.is_zero() { - self.kitty_ownership_proxy(kitty_ownership_contract_address) - .allow_auctioning(caller.clone(), kitty_id) - .async_call() - .with_callback(self.callbacks().allow_auctioning_callback( + self.tx() + .to(&kitty_ownership_contract_address) + .typed(kitty_ownership_proxy::KittyOwnershipProxy) + .allow_auctioning(&caller, kitty_id) + .callback(self.callbacks().allow_auctioning_callback( auction_type, kitty_id, starting_price, @@ -249,7 +254,7 @@ pub trait KittyAuction { deadline, caller, )) - .call_and_exit(); + .async_call_and_exit(); } } @@ -274,11 +279,12 @@ pub trait KittyAuction { let kitty_ownership_contract_address = self.get_kitty_ownership_contract_address_or_default(); if !kitty_ownership_contract_address.is_zero() { - self.kitty_ownership_proxy(kitty_ownership_contract_address) + self.tx() + .to(&kitty_ownership_contract_address) + .typed(kitty_ownership_proxy::KittyOwnershipProxy) .transfer(address, kitty_id) - .async_call() - .with_callback(self.callbacks().transfer_callback(kitty_id)) - .call_and_exit() + .callback(self.callbacks().transfer_callback(kitty_id)) + .async_call_and_exit(); } } @@ -291,12 +297,13 @@ pub trait KittyAuction { let kitty_ownership_contract_address = self.get_kitty_ownership_contract_address_or_default(); if !kitty_ownership_contract_address.is_zero() { - self.kitty_ownership_proxy(kitty_ownership_contract_address) + self.tx() + .to(&kitty_ownership_contract_address) + .typed(kitty_ownership_proxy::KittyOwnershipProxy) .approve_siring_and_return_kitty(approved_address, kitty_owner, kitty_id) // not a mistake, same callback for transfer and approveSiringAndReturnKitty - .async_call() - .with_callback(self.callbacks().transfer_callback(kitty_id)) - .call_and_exit() + .callback(self.callbacks().transfer_callback(kitty_id)) + .async_call_and_exit(); } } @@ -356,8 +363,10 @@ pub trait KittyAuction { if auction.kitty_owner != self.blockchain().get_sc_address() && !auction.current_winner.is_zero() { - self.send() - .direct_egld(&auction.kitty_owner, &auction.current_bid); + self.tx() + .to(&auction.kitty_owner) + .egld(&auction.current_bid) + .transfer(); } }, ManagedAsyncCallResult::Err(_) => { @@ -403,11 +412,6 @@ pub trait KittyAuction { } } - // proxy - - #[proxy] - fn kitty_ownership_proxy(&self, to: ManagedAddress) -> kitty_ownership::Proxy; - // storage // general diff --git a/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.lock b/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.lock index c2ebcc9167..a5bb4027f4 100755 --- a/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.lock +++ b/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.lock @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -113,7 +113,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -124,7 +124,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.toml b/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.toml index e3d1dfa4f3..5234956e51 100644 --- a/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-auction/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/crypto-kitties/kitty-genetic-alg/Cargo.toml b/contracts/examples/crypto-kitties/kitty-genetic-alg/Cargo.toml index 3b68070b25..3027dad875 100644 --- a/contracts/examples/crypto-kitties/kitty-genetic-alg/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-genetic-alg/Cargo.toml @@ -18,9 +18,9 @@ version = "0.0.0" path = "../common/random" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/examples/crypto-kitties/kitty-genetic-alg/meta/Cargo.toml b/contracts/examples/crypto-kitties/kitty-genetic-alg/meta/Cargo.toml index e17aa95b83..c0e781f92f 100644 --- a/contracts/examples/crypto-kitties/kitty-genetic-alg/meta/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-genetic-alg/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/examples/crypto-kitties/kitty-genetic-alg/sc-config.toml b/contracts/examples/crypto-kitties/kitty-genetic-alg/sc-config.toml new file mode 100644 index 0000000000..f18c45d308 --- /dev/null +++ b/contracts/examples/crypto-kitties/kitty-genetic-alg/sc-config.toml @@ -0,0 +1,8 @@ +[[proxy]] +path = "../kitty-ownership/src/kitty_genetic_alg_proxy.rs" +[[proxy.path-rename]] +from = "kitty::kitty" +to = "kitty" +[[proxy.path-rename]] +from = "kitty_genes" +to = "kitty" diff --git a/contracts/examples/crypto-kitties/kitty-genetic-alg/src/lib.rs b/contracts/examples/crypto-kitties/kitty-genetic-alg/src/lib.rs index aab6154cec..adc555585a 100644 --- a/contracts/examples/crypto-kitties/kitty-genetic-alg/src/lib.rs +++ b/contracts/examples/crypto-kitties/kitty-genetic-alg/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use kitty::{kitty_genes::*, Kitty}; +use kitty::{Kitty, KittyGenes}; use random::Random; #[multiversx_sc::contract] diff --git a/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.lock b/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.lock index a96ee69891..264017dfc5 100755 --- a/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.lock +++ b/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.lock @@ -65,7 +65,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -94,7 +94,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -105,7 +105,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.toml b/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.toml index 503d06dc6d..f4a92c4b71 100644 --- a/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-genetic-alg/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/crypto-kitties/kitty-ownership/Cargo.toml b/contracts/examples/crypto-kitties/kitty-ownership/Cargo.toml index fc0688e842..642afa1862 100644 --- a/contracts/examples/crypto-kitties/kitty-ownership/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-ownership/Cargo.toml @@ -21,9 +21,9 @@ version = "0.0.0" path = "../kitty-genetic-alg" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/examples/crypto-kitties/kitty-ownership/meta/Cargo.toml b/contracts/examples/crypto-kitties/kitty-ownership/meta/Cargo.toml index 41ecf9d5c1..8937e968d2 100644 --- a/contracts/examples/crypto-kitties/kitty-ownership/meta/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-ownership/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/examples/crypto-kitties/kitty-ownership/sc-config.toml b/contracts/examples/crypto-kitties/kitty-ownership/sc-config.toml new file mode 100644 index 0000000000..202f19e321 --- /dev/null +++ b/contracts/examples/crypto-kitties/kitty-ownership/sc-config.toml @@ -0,0 +1,11 @@ +[[proxy]] +path = "../kitty-auction/src/kitty_ownership_proxy.rs" +[[proxy.path-rename]] +from = "kitty::kitty" +to = "kitty" + +[[proxy]] +path = "../../crypto-zombies/src/kitty_ownership_proxy.rs" +[[proxy.path-rename]] +from = "kitty::kitty" +to = "kitty" diff --git a/contracts/examples/crypto-kitties/kitty-ownership/src/kitty_genetic_alg_proxy.rs b/contracts/examples/crypto-kitties/kitty-ownership/src/kitty_genetic_alg_proxy.rs new file mode 100644 index 0000000000..1acee7fe43 --- /dev/null +++ b/contracts/examples/crypto-kitties/kitty-ownership/src/kitty_genetic_alg_proxy.rs @@ -0,0 +1,78 @@ +// 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 KittyGeneticAlgProxy; + +impl TxProxyTrait for KittyGeneticAlgProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = KittyGeneticAlgProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + KittyGeneticAlgProxyMethods { wrapped_tx: tx } + } +} + +pub struct KittyGeneticAlgProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl KittyGeneticAlgProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl KittyGeneticAlgProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn generate_kitty_genes< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + matron: Arg0, + sire: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("generateKittyGenes") + .argument(&matron) + .argument(&sire) + .original_result() + } +} diff --git a/contracts/examples/crypto-kitties/kitty-ownership/src/lib.rs b/contracts/examples/crypto-kitties/kitty-ownership/src/lib.rs index 2514592465..dbde8aed52 100644 --- a/contracts/examples/crypto-kitties/kitty-ownership/src/lib.rs +++ b/contracts/examples/crypto-kitties/kitty-ownership/src/lib.rs @@ -1,11 +1,12 @@ #![no_std] #![allow(clippy::suspicious_operation_groupings)] +pub mod kitty_genetic_alg_proxy; +use kitty::{Kitty, KittyGenes}; use multiversx_sc::imports::*; use core::cmp::max; -use kitty::{kitty_genes::*, Kitty}; use random::*; #[multiversx_sc::contract] @@ -52,7 +53,7 @@ pub trait KittyOwnership { .blockchain() .get_sc_balance(&EgldOrEsdtTokenIdentifier::egld(), 0); - self.send().direct_egld(&caller, &egld_balance); + self.tx().to(&caller).egld(&egld_balance).transfer(); } // views/endpoints - ERC721 required @@ -335,14 +336,16 @@ pub trait KittyOwnership { let gene_science_contract_address = self.get_gene_science_contract_address_or_default(); if !gene_science_contract_address.is_zero() { - self.kitty_genetic_alg_proxy(gene_science_contract_address) + let caller = self.blockchain().get_caller(); + self.tx() + .to(&gene_science_contract_address) + .typed(kitty_genetic_alg_proxy::KittyGeneticAlgProxy) .generate_kitty_genes(matron, sire) - .async_call() - .with_callback( + .callback( self.callbacks() - .generate_kitty_genes_callback(matron_id, self.blockchain().get_caller()), + .generate_kitty_genes_callback(matron_id, caller), ) - .call_and_exit() + .async_call_and_exit(); } else { sc_panic!("Gene science contract address not set!") } @@ -569,7 +572,7 @@ pub trait KittyOwnership { // send birth fee to caller let fee = self.birth_fee().get(); - self.send().direct_egld(&original_caller, &fee); + self.tx().to(&original_caller).egld(&fee).transfer(); }, ManagedAsyncCallResult::Err(_) => { // this can only fail if the kitty_genes contract address is invalid @@ -578,11 +581,6 @@ pub trait KittyOwnership { } } - // proxy - - #[proxy] - fn kitty_genetic_alg_proxy(&self, to: ManagedAddress) -> kitty_genetic_alg::Proxy; - // storage - General #[storage_mapper("geneScienceContractAddress")] diff --git a/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.lock b/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.lock index 9e6e06ea1a..69e81a180a 100755 --- a/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.lock +++ b/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.lock @@ -75,7 +75,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -104,7 +104,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -115,7 +115,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.toml b/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.toml index 7713372b52..def5af05df 100644 --- a/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.toml +++ b/contracts/examples/crypto-kitties/kitty-ownership/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/crypto-zombies/Cargo.toml b/contracts/examples/crypto-zombies/Cargo.toml index e269e3ca5b..3888d9ecb7 100644 --- a/contracts/examples/crypto-zombies/Cargo.toml +++ b/contracts/examples/crypto-zombies/Cargo.toml @@ -9,9 +9,13 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" + +[dependencies.kitty] +version = "0.0.0" +path = "../../../contracts/examples/crypto-kitties/common/kitty" diff --git a/contracts/examples/crypto-zombies/meta/Cargo.toml b/contracts/examples/crypto-zombies/meta/Cargo.toml index 7b017c5472..2d94d2d074 100644 --- a/contracts/examples/crypto-zombies/meta/Cargo.toml +++ b/contracts/examples/crypto-zombies/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/crypto-zombies/sc-config.toml b/contracts/examples/crypto-zombies/sc-config.toml new file mode 100644 index 0000000000..d1f317be2c --- /dev/null +++ b/contracts/examples/crypto-zombies/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "src/proxy_crypto_zombies.rs" diff --git a/contracts/examples/crypto-zombies/src/crypto_kitties_proxy.rs b/contracts/examples/crypto-zombies/src/crypto_kitties_proxy.rs deleted file mode 100644 index ea4d366994..0000000000 --- a/contracts/examples/crypto-zombies/src/crypto_kitties_proxy.rs +++ /dev/null @@ -1,46 +0,0 @@ -use multiversx_sc::derive_imports::*; - -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] -pub struct Kitty { - pub genes: KittyGenes, - pub birth_time: u64, // timestamp - pub cooldown_end: u64, // timestamp, used for pregnancy timer and siring cooldown - pub matron_id: u32, - pub sire_id: u32, - pub siring_with_id: u32, // for pregnant cats, 0 otherwise - pub nr_children: u16, // cooldown period increases exponentially with every breeding/siring - pub generation: u16, // max(sire_gen, matron_gen) + 1. Generation also influences cooldown. -} - -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] -pub struct KittyGenes { - pub fur_color: Color, - pub eye_color: Color, - pub meow_power: u8, // the higher the value, the louder the cat -} - -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] -pub struct Color { - pub r: u8, - pub g: u8, - pub b: u8, -} - -#[multiversx_sc::proxy] -pub trait CryptoKitties { - #[endpoint] - fn get_kitty_by_id_endpoint(&self, kitty_id: u32) -> Kitty; -} - -impl KittyGenes { - pub fn get_as_u64(&self) -> u64 { - (self.fur_color.as_u64() << 12 | self.eye_color.as_u64()) << 4 - | self.meow_power.to_be() as u64 - } -} - -impl Color { - pub fn as_u64(&self) -> u64 { - ((self.r.to_be() as u64) << 4 | self.r.to_be() as u64) << 4 | self.r.to_be() as u64 - } -} diff --git a/contracts/examples/crypto-zombies/src/kitty_ownership_proxy.rs b/contracts/examples/crypto-zombies/src/kitty_ownership_proxy.rs new file mode 100644 index 0000000000..87f5bdb4a2 --- /dev/null +++ b/contracts/examples/crypto-zombies/src/kitty_ownership_proxy.rs @@ -0,0 +1,339 @@ +// 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 KittyOwnershipProxy; + +impl TxProxyTrait for KittyOwnershipProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = KittyOwnershipProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + KittyOwnershipProxyMethods { wrapped_tx: tx } + } +} + +pub struct KittyOwnershipProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl KittyOwnershipProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + Arg2: ProxyArg>>, + >( + self, + birth_fee: Arg0, + opt_gene_science_contract_address: Arg1, + opt_kitty_auction_contract_address: Arg2, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&birth_fee) + .argument(&opt_gene_science_contract_address) + .argument(&opt_kitty_auction_contract_address) + .original_result() + } +} + +#[rustfmt::skip] +impl KittyOwnershipProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn set_gene_science_contract_address_endpoint< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setGeneScienceContractAddress") + .argument(&address) + .original_result() + } + + pub fn set_kitty_auction_contract_address_endpoint< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setKittyAuctionContractAddress") + .argument(&address) + .original_result() + } + + pub fn claim( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claim") + .original_result() + } + + pub fn total_supply( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("totalSupply") + .original_result() + } + + pub fn balance_of< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("balanceOf") + .argument(&address) + .original_result() + } + + pub fn owner_of< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("ownerOf") + .argument(&kitty_id) + .original_result() + } + + pub fn approve< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + to: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approve") + .argument(&to) + .argument(&kitty_id) + .original_result() + } + + pub fn transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + to: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer") + .argument(&to) + .argument(&kitty_id) + .original_result() + } + + pub fn transfer_from< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + from: Arg0, + to: Arg1, + kitty_id: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer_from") + .argument(&from) + .argument(&to) + .argument(&kitty_id) + .original_result() + } + + pub fn tokens_of_owner< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("tokensOfOwner") + .argument(&address) + .original_result() + } + + pub fn allow_auctioning< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + by: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("allowAuctioning") + .argument(&by) + .argument(&kitty_id) + .original_result() + } + + pub fn approve_siring_and_return_kitty< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + approved_address: Arg0, + kitty_owner: Arg1, + kitty_id: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approveSiringAndReturnKitty") + .argument(&approved_address) + .argument(&kitty_owner) + .argument(&kitty_id) + .original_result() + } + + pub fn create_gen_zero_kitty( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("createGenZeroKitty") + .original_result() + } + + pub fn get_kitty_by_id_endpoint< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getKittyById") + .argument(&kitty_id) + .original_result() + } + + pub fn is_ready_to_breed< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isReadyToBreed") + .argument(&kitty_id) + .original_result() + } + + pub fn is_pregnant< + Arg0: ProxyArg, + >( + self, + kitty_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isPregnant") + .argument(&kitty_id) + .original_result() + } + + pub fn can_breed_with< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + matron_id: Arg0, + sire_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("canBreedWith") + .argument(&matron_id) + .argument(&sire_id) + .original_result() + } + + pub fn approve_siring< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + address: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approveSiring") + .argument(&address) + .argument(&kitty_id) + .original_result() + } + + pub fn breed_with< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + matron_id: Arg0, + sire_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("breedWith") + .argument(&matron_id) + .argument(&sire_id) + .original_result() + } + + pub fn give_birth< + Arg0: ProxyArg, + >( + self, + matron_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("giveBirth") + .argument(&matron_id) + .original_result() + } + + pub fn birth_fee( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("birthFee") + .original_result() + } +} diff --git a/contracts/examples/crypto-zombies/src/lib.rs b/contracts/examples/crypto-zombies/src/lib.rs index f2f47688ad..9fea3b3099 100644 --- a/contracts/examples/crypto-zombies/src/lib.rs +++ b/contracts/examples/crypto-zombies/src/lib.rs @@ -2,7 +2,8 @@ use multiversx_sc::imports::*; -mod crypto_kitties_proxy; +pub mod kitty_ownership_proxy; +pub mod proxy_crypto_zombies; mod storage; mod zombie; mod zombie_attack; diff --git a/contracts/examples/crypto-zombies/src/proxy_crypto_zombies.rs b/contracts/examples/crypto-zombies/src/proxy_crypto_zombies.rs new file mode 100644 index 0000000000..1e056fee19 --- /dev/null +++ b/contracts/examples/crypto-zombies/src/proxy_crypto_zombies.rs @@ -0,0 +1,287 @@ +// 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 CryptoZombiesProxy; + +impl TxProxyTrait for CryptoZombiesProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = CryptoZombiesProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + CryptoZombiesProxyMethods { wrapped_tx: tx } + } +} + +pub struct CryptoZombiesProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl CryptoZombiesProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl CryptoZombiesProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxProxyUpgrade { + self.wrapped_tx + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl CryptoZombiesProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn set_crypto_kitties_sc_address< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("set_crypto_kitties_sc_address") + .argument(&address) + .original_result() + } + + pub fn generate_random_dna( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("generate_random_dna") + .original_result() + } + + pub fn create_random_zombie< + Arg0: ProxyArg>, + >( + self, + name: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("create_random_zombie") + .argument(&name) + .original_result() + } + + pub fn is_ready< + Arg0: ProxyArg, + >( + self, + zombie_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("is_ready") + .argument(&zombie_id) + .original_result() + } + + pub fn feed_on_kitty< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + zombie_id: Arg0, + kitty_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("feed_on_kitty") + .argument(&zombie_id) + .argument(&kitty_id) + .original_result() + } + + pub fn dna_digits( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("dna_digits") + .original_result() + } + + pub fn zombies_count( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("zombies_count") + .original_result() + } + + pub fn zombies< + Arg0: ProxyArg, + >( + self, + id: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("zombies") + .argument(&id) + .original_result() + } + + pub fn zombie_owner< + Arg0: ProxyArg, + >( + self, + id: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("zombie_owner") + .argument(&id) + .original_result() + } + + pub fn crypto_kitties_sc_address( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("crypto_kitties_sc_address") + .original_result() + } + + pub fn cooldown_time( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("cooldown_time") + .original_result() + } + + pub fn owned_zombies< + Arg0: ProxyArg>, + >( + self, + owner: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("owned_zombies") + .argument(&owner) + .original_result() + } + + pub fn level_up< + Arg0: ProxyArg, + >( + self, + zombie_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("level_up") + .argument(&zombie_id) + .original_result() + } + + pub fn withdraw( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("withdraw") + .original_result() + } + + pub fn change_name< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + zombie_id: Arg0, + name: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("change_name") + .argument(&zombie_id) + .argument(&name) + .original_result() + } + + pub fn change_dna< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + zombie_id: Arg0, + dna: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("change_dna") + .argument(&zombie_id) + .argument(&dna) + .original_result() + } + + pub fn attack< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + zombie_id: Arg0, + target_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("attack") + .argument(&zombie_id) + .argument(&target_id) + .original_result() + } +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct Zombie +where + Api: ManagedTypeApi, +{ + pub name: ManagedBuffer, + pub dna: u64, + pub level: u16, + pub ready_time: u64, + pub win_count: usize, + pub loss_count: usize, +} diff --git a/contracts/examples/crypto-zombies/src/zombie.rs b/contracts/examples/crypto-zombies/src/zombie.rs index 414c343f28..bfe3fd22ad 100644 --- a/contracts/examples/crypto-zombies/src/zombie.rs +++ b/contracts/examples/crypto-zombies/src/zombie.rs @@ -1,6 +1,7 @@ use multiversx_sc::{derive_imports::*, imports::*}; -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct Zombie { pub name: ManagedBuffer, pub dna: u64, diff --git a/contracts/examples/crypto-zombies/src/zombie_feeding.rs b/contracts/examples/crypto-zombies/src/zombie_feeding.rs index e27b3e69ad..56ef89cb7c 100644 --- a/contracts/examples/crypto-zombies/src/zombie_feeding.rs +++ b/contracts/examples/crypto-zombies/src/zombie_feeding.rs @@ -1,9 +1,6 @@ use multiversx_sc::imports::*; -use crate::{ - crypto_kitties_proxy::{self, Kitty}, - storage, zombie_factory, zombie_helper, -}; +use crate::{kitty_ownership_proxy, storage, zombie_factory, zombie_helper}; #[multiversx_sc::module] pub trait ZombieFeeding: @@ -41,7 +38,7 @@ pub trait ZombieFeeding: #[callback] fn get_kitty_callback( &self, - #[call_result] result: ManagedAsyncCallResult, + #[call_result] result: ManagedAsyncCallResult, zombie_id: usize, ) { match result { @@ -56,12 +53,11 @@ pub trait ZombieFeeding: #[endpoint] fn feed_on_kitty(&self, zombie_id: usize, kitty_id: u32) { let crypto_kitties_sc_address = self.crypto_kitties_sc_address().get(); - self.kitty_proxy(crypto_kitties_sc_address) + self.tx() + .to(&crypto_kitties_sc_address) + .typed(kitty_ownership_proxy::KittyOwnershipProxy) .get_kitty_by_id_endpoint(kitty_id) - .async_call() - .with_callback(self.callbacks().get_kitty_callback(zombie_id)) - .call_and_exit(); + .callback(self.callbacks().get_kitty_callback(zombie_id)) + .async_call_and_exit(); } - #[proxy] - fn kitty_proxy(&self, to: ManagedAddress) -> crypto_kitties_proxy::Proxy; } diff --git a/contracts/examples/crypto-zombies/src/zombie_helper.rs b/contracts/examples/crypto-zombies/src/zombie_helper.rs index 000ffda770..c38edc9ea0 100644 --- a/contracts/examples/crypto-zombies/src/zombie_helper.rs +++ b/contracts/examples/crypto-zombies/src/zombie_helper.rs @@ -31,7 +31,10 @@ pub trait ZombieHelper: storage::Storage { fn withdraw(&self) { let caller_address = self.blockchain().get_caller(); let collected_fees = self.collected_fees().get(); - self.send().direct_egld(&caller_address, &collected_fees); + self.tx() + .to(&caller_address) + .egld(&collected_fees) + .transfer(); self.collected_fees().clear(); } diff --git a/contracts/examples/crypto-zombies/wasm/Cargo.lock b/contracts/examples/crypto-zombies/wasm/Cargo.lock index 1bd3e9d974..01b50384d8 100755 --- a/contracts/examples/crypto-zombies/wasm/Cargo.lock +++ b/contracts/examples/crypto-zombies/wasm/Cargo.lock @@ -24,6 +24,7 @@ checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" name = "crypto-zombies" version = "0.0.0" dependencies = [ + "kitty", "multiversx-sc", ] @@ -53,9 +54,17 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "kitty" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "random", +] + [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +93,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +104,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] @@ -146,6 +155,13 @@ dependencies = [ "nibble_vec", ] +[[package]] +name = "random" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "smallvec" version = "1.13.2" diff --git a/contracts/examples/crypto-zombies/wasm/Cargo.toml b/contracts/examples/crypto-zombies/wasm/Cargo.toml index 620c7c5590..d99df32433 100644 --- a/contracts/examples/crypto-zombies/wasm/Cargo.toml +++ b/contracts/examples/crypto-zombies/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/crypto-zombies/wasm/src/lib.rs b/contracts/examples/crypto-zombies/wasm/src/lib.rs index 44f5f426c8..13e3db684c 100644 --- a/contracts/examples/crypto-zombies/wasm/src/lib.rs +++ b/contracts/examples/crypto-zombies/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 18 +// Upgrade: 1 +// Endpoints: 17 // Async Callback: 1 // Total number of exported functions: 20 diff --git a/contracts/examples/digital-cash/Cargo.toml b/contracts/examples/digital-cash/Cargo.toml index 74b47bb738..05df36f381 100644 --- a/contracts/examples/digital-cash/Cargo.toml +++ b/contracts/examples/digital-cash/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/digital_cash.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/digital-cash/meta/Cargo.toml b/contracts/examples/digital-cash/meta/Cargo.toml index e01aa83bcb..a54b5f1ea3 100644 --- a/contracts/examples/digital-cash/meta/Cargo.toml +++ b/contracts/examples/digital-cash/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/digital-cash/sc-config.toml b/contracts/examples/digital-cash/sc-config.toml new file mode 100644 index 0000000000..39234c29d8 --- /dev/null +++ b/contracts/examples/digital-cash/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "src/digital_cash_proxy.rs" diff --git a/contracts/examples/digital-cash/src/deposit_info.rs b/contracts/examples/digital-cash/src/deposit_info.rs index 9fb14661ea..daef136feb 100644 --- a/contracts/examples/digital-cash/src/deposit_info.rs +++ b/contracts/examples/digital-cash/src/deposit_info.rs @@ -1,6 +1,7 @@ use multiversx_sc::{derive_imports::*, imports::*}; -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct DepositInfo { pub depositor_address: ManagedAddress, pub esdt_funds: ManagedVec>, @@ -24,7 +25,8 @@ where } } -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct Fee { pub num_token_to_transfer: usize, pub value: EgldOrEsdtTokenPayment, diff --git a/contracts/examples/digital-cash/src/digital_cash.rs b/contracts/examples/digital-cash/src/digital_cash.rs index b46c2b7331..c1d96c9132 100644 --- a/contracts/examples/digital-cash/src/digital_cash.rs +++ b/contracts/examples/digital-cash/src/digital_cash.rs @@ -5,6 +5,7 @@ use multiversx_sc::imports::*; mod constants; mod deposit_info; +pub mod digital_cash_proxy; mod helpers; mod pay_fee_and_fund; mod signature_operations; @@ -54,15 +55,17 @@ pub trait DigitalCash: continue; } if token == EgldOrEsdtTokenIdentifier::egld() { - self.send().direct_egld(&caller_address, &fee); + self.tx().to(&caller_address).egld(&fee).transfer(); } else { let collected_fee = EsdtTokenPayment::new(token.unwrap_esdt(), 0, fee); collected_esdt_fees.push(collected_fee); } } if !collected_esdt_fees.is_empty() { - self.send() - .direct_multi(&caller_address, &collected_esdt_fees); + self.tx() + .to(&caller_address) + .payment(&collected_esdt_fees) + .transfer(); } } diff --git a/contracts/examples/digital-cash/src/digital_cash_proxy.rs b/contracts/examples/digital-cash/src/digital_cash_proxy.rs new file mode 100644 index 0000000000..85e7dc06ae --- /dev/null +++ b/contracts/examples/digital-cash/src/digital_cash_proxy.rs @@ -0,0 +1,261 @@ +// 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 DigitalCashProxy; + +impl TxProxyTrait for DigitalCashProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = DigitalCashProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + DigitalCashProxyMethods { wrapped_tx: tx } + } +} + +pub struct DigitalCashProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl DigitalCashProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + fee: Arg0, + token: Arg1, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&fee) + .argument(&token) + .original_result() + } +} + +#[rustfmt::skip] +impl DigitalCashProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn whitelist_fee_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + fee: Arg0, + token: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("whitelistFeeToken") + .argument(&fee) + .argument(&token) + .original_result() + } + + pub fn blacklist_fee_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("blacklistFeeToken") + .argument(&token) + .original_result() + } + + pub fn claim_fees( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claimFees") + .original_result() + } + + pub fn get_amount< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + address: Arg0, + token: Arg1, + nonce: Arg2, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getAmount") + .argument(&address) + .argument(&token) + .argument(&nonce) + .original_result() + } + + pub fn pay_fee_and_fund_esdt< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + address: Arg0, + valability: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("payFeeAndFundESDT") + .argument(&address) + .argument(&valability) + .original_result() + } + + pub fn pay_fee_and_fund_egld< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + address: Arg0, + valability: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("payFeeAndFundEGLD") + .argument(&address) + .argument(&valability) + .original_result() + } + + pub fn fund< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + address: Arg0, + valability: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("fund") + .argument(&address) + .argument(&valability) + .original_result() + } + + pub fn deposit_fees< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("depositFees") + .argument(&address) + .original_result() + } + + pub fn withdraw< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("withdraw") + .argument(&address) + .original_result() + } + + pub fn claim< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + address: Arg0, + signature: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claim") + .argument(&address) + .argument(&signature) + .original_result() + } + + pub fn forward< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + address: Arg0, + forward_address: Arg1, + signature: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward") + .argument(&address) + .argument(&forward_address) + .argument(&signature) + .original_result() + } + + pub fn deposit< + Arg0: ProxyArg>, + >( + self, + donor: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("deposit") + .argument(&donor) + .original_result() + } +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct DepositInfo +where + Api: ManagedTypeApi, +{ + pub depositor_address: ManagedAddress, + pub esdt_funds: ManagedVec>, + pub egld_funds: BigUint, + pub valability: u64, + pub expiration_round: u64, + pub fees: Fee, +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct Fee +where + Api: ManagedTypeApi, +{ + pub num_token_to_transfer: usize, + pub value: EgldOrEsdtTokenPayment, +} diff --git a/contracts/examples/digital-cash/src/helpers.rs b/contracts/examples/digital-cash/src/helpers.rs index d300e35d08..aa5c4efadc 100644 --- a/contracts/examples/digital-cash/src/helpers.rs +++ b/contracts/examples/digital-cash/src/helpers.rs @@ -9,11 +9,13 @@ use crate::{ pub trait HelpersModule: storage::StorageModule { fn send_fee_to_address(&self, fee: &EgldOrEsdtTokenPayment, address: &ManagedAddress) { if fee.token_identifier == EgldOrEsdtTokenIdentifier::egld() { - self.send().direct_egld(address, &fee.amount); + self.tx().to(address).egld(&fee.amount).transfer(); } else { let esdt_fee = fee.clone().unwrap_esdt(); - self.send() - .direct_esdt(address, &esdt_fee.token_identifier, 0, &esdt_fee.amount); + self.tx() + .to(address) + .single_esdt(&esdt_fee.token_identifier, 0, &esdt_fee.amount) + .transfer(); } } diff --git a/contracts/examples/digital-cash/src/signature_operations.rs b/contracts/examples/digital-cash/src/signature_operations.rs index 3da7143f88..9c68951f05 100644 --- a/contracts/examples/digital-cash/src/signature_operations.rs +++ b/contracts/examples/digital-cash/src/signature_operations.rs @@ -33,13 +33,17 @@ pub trait SignatureOperationsModule: storage::StorageModule + helpers::HelpersMo } if egld_funds > 0 { - self.send() - .direct_egld(&deposit.depositor_address, &egld_funds); + self.tx() + .to(&deposit.depositor_address) + .egld(&egld_funds) + .transfer(); } if !esdt_funds.is_empty() { - self.send() - .direct_multi(&deposit.depositor_address, &esdt_funds); + self.tx() + .to(&deposit.depositor_address) + .payment(esdt_funds) + .transfer(); } } @@ -71,12 +75,16 @@ pub trait SignatureOperationsModule: storage::StorageModule + helpers::HelpersMo .update(|collected_fees| *collected_fees += fee_cost); if deposit.egld_funds > 0 { - self.send() - .direct_egld(&caller_address, &deposit.egld_funds); + self.tx() + .to(&caller_address) + .egld(&deposit.egld_funds) + .transfer(); } if !deposit.esdt_funds.is_empty() { - self.send() - .direct_multi(&caller_address, &deposit.esdt_funds); + self.tx() + .to(&caller_address) + .payment(&deposit.esdt_funds) + .transfer(); } if deposited_fee.amount > 0 { self.send_fee_to_address(&deposited_fee, &deposit.depositor_address); diff --git a/contracts/examples/digital-cash/wasm/Cargo.lock b/contracts/examples/digital-cash/wasm/Cargo.lock index 1cd77b2d22..db281885ba 100644 --- a/contracts/examples/digital-cash/wasm/Cargo.lock +++ b/contracts/examples/digital-cash/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/digital-cash/wasm/Cargo.toml b/contracts/examples/digital-cash/wasm/Cargo.toml index 64a7cf1dca..fd23cf19e3 100644 --- a/contracts/examples/digital-cash/wasm/Cargo.toml +++ b/contracts/examples/digital-cash/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/empty/Cargo.toml b/contracts/examples/empty/Cargo.toml index 7670b2a2bf..ff22118a94 100644 --- a/contracts/examples/empty/Cargo.toml +++ b/contracts/examples/empty/Cargo.toml @@ -9,11 +9,11 @@ publish = false path = "src/empty.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies] diff --git a/contracts/examples/empty/meta/Cargo.toml b/contracts/examples/empty/meta/Cargo.toml index d981b28a0d..80e2c84bdf 100644 --- a/contracts/examples/empty/meta/Cargo.toml +++ b/contracts/examples/empty/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/empty/wasm/Cargo.lock b/contracts/examples/empty/wasm/Cargo.lock index 4399ff23ef..791a8a78d4 100755 --- a/contracts/examples/empty/wasm/Cargo.lock +++ b/contracts/examples/empty/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/empty/wasm/Cargo.toml b/contracts/examples/empty/wasm/Cargo.toml index 3c188abc8b..61cf8db541 100644 --- a/contracts/examples/empty/wasm/Cargo.toml +++ b/contracts/examples/empty/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/empty/wasm/src/lib.rs b/contracts/examples/empty/wasm/src/lib.rs index 33ca3e1cfd..53a9c2f2f1 100644 --- a/contracts/examples/empty/wasm/src/lib.rs +++ b/contracts/examples/empty/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 1 +// Upgrade: 1 +// Endpoints: 0 // Async Callback (empty): 1 // Total number of exported functions: 3 diff --git a/contracts/examples/esdt-transfer-with-fee/Cargo.toml b/contracts/examples/esdt-transfer-with-fee/Cargo.toml index 2aacb48f36..10ef50f36c 100644 --- a/contracts/examples/esdt-transfer-with-fee/Cargo.toml +++ b/contracts/examples/esdt-transfer-with-fee/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/esdt_transfer_with_fee.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/esdt-transfer-with-fee/meta/Cargo.toml b/contracts/examples/esdt-transfer-with-fee/meta/Cargo.toml index 25339aeff0..a40832325b 100644 --- a/contracts/examples/esdt-transfer-with-fee/meta/Cargo.toml +++ b/contracts/examples/esdt-transfer-with-fee/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/esdt-transfer-with-fee/src/esdt_transfer_with_fee.rs b/contracts/examples/esdt-transfer-with-fee/src/esdt_transfer_with_fee.rs index 6133e5500f..de883ef83a 100644 --- a/contracts/examples/esdt-transfer-with-fee/src/esdt_transfer_with_fee.rs +++ b/contracts/examples/esdt-transfer-with-fee/src/esdt_transfer_with_fee.rs @@ -40,8 +40,7 @@ pub trait EsdtTransferWithFee { } self.paid_fees().clear(); - let caller = self.blockchain().get_caller(); - self.send().direct_multi(&caller, &fees); + self.tx().to(ToCaller).payment(fees).transfer(); } #[payable("*")] @@ -82,7 +81,7 @@ pub trait EsdtTransferWithFee { }, } } - self.send().direct_multi(&address, &new_payments); + self.tx().to(&address).payment(new_payments).transfer(); } fn get_payment_after_fees( diff --git a/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.lock b/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.lock index 56981cfdf1..b18d50c99d 100644 --- a/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.lock +++ b/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.toml b/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.toml index da0a01f1f5..07cb085e0f 100644 --- a/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.toml +++ b/contracts/examples/esdt-transfer-with-fee/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/factorial/Cargo.toml b/contracts/examples/factorial/Cargo.toml index 52524195a5..49724f1760 100644 --- a/contracts/examples/factorial/Cargo.toml +++ b/contracts/examples/factorial/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/factorial.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/factorial/meta/Cargo.toml b/contracts/examples/factorial/meta/Cargo.toml index 27b6c326e7..2a5a7f7a8f 100644 --- a/contracts/examples/factorial/meta/Cargo.toml +++ b/contracts/examples/factorial/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/factorial/wasm/Cargo.lock b/contracts/examples/factorial/wasm/Cargo.lock index b32b28949b..f11e7fea1f 100755 --- a/contracts/examples/factorial/wasm/Cargo.lock +++ b/contracts/examples/factorial/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/factorial/wasm/Cargo.toml b/contracts/examples/factorial/wasm/Cargo.toml index df2ac02176..4625a90cc9 100644 --- a/contracts/examples/factorial/wasm/Cargo.toml +++ b/contracts/examples/factorial/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/factorial/wasm/src/lib.rs b/contracts/examples/factorial/wasm/src/lib.rs index 7819e0b34f..969872f107 100644 --- a/contracts/examples/factorial/wasm/src/lib.rs +++ b/contracts/examples/factorial/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 2 +// Upgrade: 1 +// Endpoints: 1 // Async Callback (empty): 1 // Total number of exported functions: 4 diff --git a/contracts/examples/fractional-nfts/Cargo.toml b/contracts/examples/fractional-nfts/Cargo.toml index 7e056f731a..ec60d9d32a 100644 --- a/contracts/examples/fractional-nfts/Cargo.toml +++ b/contracts/examples/fractional-nfts/Cargo.toml @@ -9,13 +9,13 @@ publish = false path = "src/fractional_nfts.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/fractional-nfts/meta/Cargo.toml b/contracts/examples/fractional-nfts/meta/Cargo.toml index 1abc450067..d7a32ed9b1 100644 --- a/contracts/examples/fractional-nfts/meta/Cargo.toml +++ b/contracts/examples/fractional-nfts/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/fractional-nfts/src/fractional_nfts.rs b/contracts/examples/fractional-nfts/src/fractional_nfts.rs index c715edae82..16f1c87aed 100644 --- a/contracts/examples/fractional-nfts/src/fractional_nfts.rs +++ b/contracts/examples/fractional-nfts/src/fractional_nfts.rs @@ -5,6 +5,7 @@ use multiversx_sc::imports::*; use multiversx_sc_modules::default_issue_callbacks; mod fractional_uri_info; use fractional_uri_info::FractionalUriInfo; +pub mod nft_marketplace_proxy; #[multiversx_sc::contract] pub trait FractionalNfts: default_issue_callbacks::DefaultIssueCallbacksModule { @@ -39,10 +40,11 @@ pub trait FractionalNfts: default_issue_callbacks::DefaultIssueCallbacksModule { token_nonce: u64, ) { let caller = self.blockchain().get_caller(); - self.marketplace_proxy(marketplace_address) + self.tx() + .to(&marketplace_address) + .typed(nft_marketplace_proxy::NftMarketplaceProxy) .claim_tokens(caller, token_id, token_nonce) - .async_call() - .call_and_exit() + .async_call_and_exit(); } #[payable("*")] @@ -85,13 +87,14 @@ pub trait FractionalNfts: default_issue_callbacks::DefaultIssueCallbacksModule { &uris, ); - let caller = self.blockchain().get_caller(); - self.send().direct_esdt( - &caller, - fractional_token, - fractional_nonce, - &initial_fractional_amount, - ); + self.tx() + .to(ToCaller) + .single_esdt( + fractional_token, + fractional_nonce, + &initial_fractional_amount, + ) + .transfer(); } #[payable("*")] @@ -123,37 +126,18 @@ pub trait FractionalNfts: default_issue_callbacks::DefaultIssueCallbacksModule { ); let original = fractional_info.original_payment; - let caller = self.blockchain().get_caller(); - self.send().direct_esdt( - &caller, - &original.token_identifier, - original.token_nonce, - &original.amount, - ); + + self.tx() + .to(ToCaller) + .single_esdt( + &original.token_identifier, + original.token_nonce, + &original.amount, + ) + .transfer(); } #[view(getFractionalToken)] #[storage_mapper("fractional_token")] fn fractional_token(&self) -> NonFungibleTokenMapper; - - #[proxy] - fn marketplace_proxy( - &self, - sc_address: ManagedAddress, - ) -> nft_marketplace_proxy::Proxy; -} - -mod nft_marketplace_proxy { - use multiversx_sc::imports::*; - - #[multiversx_sc::proxy] - pub trait NftMarketplace { - #[endpoint(claimTokens)] - fn claim_tokens( - &self, - claim_destination: &ManagedAddress, - token_id: &EgldOrEsdtTokenIdentifier, - token_nonce: u64, - ) -> MultiValue2>; - } } diff --git a/contracts/examples/fractional-nfts/src/nft_marketplace_proxy.rs b/contracts/examples/fractional-nfts/src/nft_marketplace_proxy.rs new file mode 100644 index 0000000000..b977042583 --- /dev/null +++ b/contracts/examples/fractional-nfts/src/nft_marketplace_proxy.rs @@ -0,0 +1,57 @@ +#![allow(clippy::all)] + +use multiversx_sc::proxy_imports::*; + +pub struct NftMarketplaceProxy; + +impl TxProxyTrait for NftMarketplaceProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = NftMarketplaceProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + NftMarketplaceProxyMethods { wrapped_tx: tx } + } +} + +pub struct NftMarketplaceProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl NftMarketplaceProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn claim_tokens< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + claim_destination: Arg0, + token_id: Arg1, + token_nonce: Arg2, + ) -> TxProxyCall, ManagedVec>>> { + self.wrapped_tx + .raw_call("claimTokens") + .argument(&claim_destination) + .argument(&token_id) + .argument(&token_nonce) + .original_result() + } +} diff --git a/contracts/examples/fractional-nfts/wasm/Cargo.lock b/contracts/examples/fractional-nfts/wasm/Cargo.lock index 0ed6497ed9..5c51eaa65f 100644 --- a/contracts/examples/fractional-nfts/wasm/Cargo.lock +++ b/contracts/examples/fractional-nfts/wasm/Cargo.lock @@ -56,7 +56,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/fractional-nfts/wasm/Cargo.toml b/contracts/examples/fractional-nfts/wasm/Cargo.toml index 8f29fae438..47c9c4a88c 100644 --- a/contracts/examples/fractional-nfts/wasm/Cargo.toml +++ b/contracts/examples/fractional-nfts/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/lottery-esdt/Cargo.toml b/contracts/examples/lottery-esdt/Cargo.toml index 00bbd9121e..c4d7d29cd3 100644 --- a/contracts/examples/lottery-esdt/Cargo.toml +++ b/contracts/examples/lottery-esdt/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/lottery.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/lottery-esdt/meta/Cargo.toml b/contracts/examples/lottery-esdt/meta/Cargo.toml index 67e9e9636a..b2cd28df5c 100644 --- a/contracts/examples/lottery-esdt/meta/Cargo.toml +++ b/contracts/examples/lottery-esdt/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/lottery-esdt/src/lottery.rs b/contracts/examples/lottery-esdt/src/lottery.rs index 48a94b14b2..3c5d9040b1 100644 --- a/contracts/examples/lottery-esdt/src/lottery.rs +++ b/contracts/examples/lottery-esdt/src/lottery.rs @@ -291,19 +291,19 @@ pub trait Lottery { &BigUint::from(info.prize_distribution.get(i)), ); - self.send() - .direct(&winner_address, &info.token_identifier, 0, &prize); + self.tx() + .to(&winner_address) + .egld_or_single_esdt(&info.token_identifier, 0, &prize) + .transfer(); info.prize_pool -= prize; } // send leftover to first place let first_place_winner = ticket_holders_mapper.get(winning_tickets[0]); - self.send().direct( - &first_place_winner, - &info.token_identifier, - 0, - &info.prize_pool, - ); + self.tx() + .to(&first_place_winner) + .egld_or_single_esdt(&info.token_identifier, 0, &info.prize_pool) + .transfer(); } fn clear_storage(&self, lottery_name: &ManagedBuffer) { diff --git a/contracts/examples/lottery-esdt/wasm/Cargo.lock b/contracts/examples/lottery-esdt/wasm/Cargo.lock index 3e13602042..3618971bb7 100755 --- a/contracts/examples/lottery-esdt/wasm/Cargo.lock +++ b/contracts/examples/lottery-esdt/wasm/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/lottery-esdt/wasm/Cargo.toml b/contracts/examples/lottery-esdt/wasm/Cargo.toml index 3c1b5ca468..5da7483f04 100644 --- a/contracts/examples/lottery-esdt/wasm/Cargo.toml +++ b/contracts/examples/lottery-esdt/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/multisig/Cargo.toml b/contracts/examples/multisig/Cargo.toml index 618dae4a5e..035057ec58 100644 --- a/contracts/examples/multisig/Cargo.toml +++ b/contracts/examples/multisig/Cargo.toml @@ -9,15 +9,15 @@ publish = false path = "src/multisig.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies.adder] @@ -27,7 +27,7 @@ path = "../adder" path = "../factorial" [dev-dependencies.multiversx-wegld-swap-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../core/wegld-swap" [dev-dependencies] diff --git a/contracts/examples/multisig/interact/Cargo.toml b/contracts/examples/multisig/interact/Cargo.toml index 3feae5b638..32869be20c 100644 --- a/contracts/examples/multisig/interact/Cargo.toml +++ b/contracts/examples/multisig/interact/Cargo.toml @@ -18,13 +18,13 @@ toml = "0.8.6" path = ".." [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../contracts/modules" [dependencies.multiversx-sc-snippets] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/snippets" [dependencies.multiversx-sc-scenario] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/examples/multisig/interact/config.toml b/contracts/examples/multisig/interact/config.toml index 1a1e45429a..a3b733f73d 100644 --- a/contracts/examples/multisig/interact/config.toml +++ b/contracts/examples/multisig/interact/config.toml @@ -1,2 +1,2 @@ -gateway = 'https://testnet-gateway.multiversx.com' +gateway = 'https://devnet-gateway.multiversx.com' quorum = 2 diff --git a/contracts/examples/multisig/interact/src/multisig_interact.rs b/contracts/examples/multisig/interact/src/multisig_interact.rs index cf679c5a13..eaef5d8448 100644 --- a/contracts/examples/multisig/interact/src/multisig_interact.rs +++ b/contracts/examples/multisig/interact/src/multisig_interact.rs @@ -5,31 +5,12 @@ mod multisig_interact_state; mod multisig_interact_wegld; use clap::Parser; -use multisig::{ - multisig_perform::ProxyTrait as _, multisig_propose::ProxyTrait as _, - multisig_state::ProxyTrait as _, ProxyTrait as _, -}; +use multisig::multisig_proxy; use multisig_interact_config::Config; use multisig_interact_state::State; -use multiversx_sc_modules::dns::ProxyTrait as _; -use multiversx_sc_scenario::{ - mandos_system::ScenarioRunner, multiversx_sc::codec::multi_types::IgnoreValue, - scenario_format::interpret_trait::InterpretableFrom, - standalone::retrieve_account_as_scenario_set_state, test_wallets, -}; -use multiversx_sc_snippets::{ - dns_address_for_name, env_logger, - multiversx_sc::{ - codec::multi_types::MultiValueVec, storage::mappers::SingleValue, types::Address, - }, - multiversx_sc_scenario::{ - api::StaticApi, bech32, scenario_format::interpret_trait::InterpreterContext, - scenario_model::*, ContractInfo, - }, - tokio, Interactor, StepBuffer, -}; - -const SYSTEM_SC_BECH32: &str = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"; + +use multiversx_sc_snippets::imports::*; + const INTERACTOR_SCENARIO_TRACE_PATH: &str = "interactor_trace.scen.json"; #[tokio::main] @@ -94,8 +75,7 @@ async fn main() { struct MultisigInteract { interactor: Interactor, - wallet_address: Address, - system_sc_address: Address, + wallet_address: Bech32Address, collection_token_identifier: String, multisig_code: BytesValue, state: State, @@ -116,8 +96,7 @@ impl MultisigInteract { Self { interactor, - wallet_address, - system_sc_address: bech32::decode(SYSTEM_SC_BECH32), + wallet_address: wallet_address.into(), collection_token_identifier: String::new(), multisig_code, state: State::load_state(), @@ -140,17 +119,9 @@ impl MultisigInteract { "board member address: {}", bech32::encode(board_member_address) ); - let scenario_raw = retrieve_account_as_scenario_set_state( - Config::load_config().gateway().to_string(), - bech32::encode(board_member_address), - true, - ) - .await; - - let scenario = Scenario::interpret_from(scenario_raw, &InterpreterContext::default()); - - self.interactor.pre_runners.run_scenario(&scenario); - self.interactor.post_runners.run_scenario(&scenario); + self.interactor + .retrieve_account(&board_member_address.into()) + .await; } self.wegld_swap_set_state().await; @@ -160,27 +131,24 @@ impl MultisigInteract { self.set_state().await; let board = self.board(); - let (new_address, _) = self + + let quorum = Config::load_config().quorum(); + let new_address = self .interactor - .sc_deploy_get_result::<_, IgnoreValue>( - ScDeployStep::new() - .call( - self.state - .default_multisig() - .init(Config::load_config().quorum(), board), - ) - .from(&self.wallet_address) - .code(&self.multisig_code) - .gas_limit("100,000,000") - .expect(TxExpect::ok().additional_error_message("deploy failed: ")), - ) + .tx() + .from(&self.wallet_address) + .typed(multisig_proxy::MultisigProxy) + .init(quorum, board) + .code(&self.multisig_code) + .gas(NumExpr("100,000,000")) + .returns(ReturnsNewBech32Address) + .prepare_async() + .run() .await; - let new_address_bech32 = bech32::encode(&new_address); - println!("new address: {new_address_bech32}"); + println!("new address: {new_address}"); - let new_address_expr = format!("bech32:{new_address_bech32}"); - self.state.set_multisig_address(&new_address_expr); + self.state.set_multisig_address(new_address); } async fn multi_deploy(&mut self, count: &u8) { @@ -192,40 +160,23 @@ impl MultisigInteract { println!("deploying {count} contracts..."); let board = self.board(); - let mut steps = Vec::new(); + let quorum = Config::load_config().quorum(); + let mut buffer = self.interactor.homogenous_call_buffer(); for _ in 0..*count { - let typed_sc_deploy = ScDeployStep::new() - .call( - self.state - .default_multisig() - .init(Config::load_config().quorum(), board.clone()), - ) - .from(&self.wallet_address) - .code(&self.multisig_code) - .gas_limit("70,000,000"); - - steps.push(typed_sc_deploy); + buffer.push_tx(|tx| { + tx.from(&self.wallet_address) + .typed(multisig_proxy::MultisigProxy) + .init(quorum, board.clone()) + .code(&self.multisig_code) + .gas(NumExpr("70,000,000")) + .returns(ReturnsNewBech32Address) + }); } - self.interactor - .multi_sc_exec(StepBuffer::from_sc_deploy_vec(&mut steps)) - .await; - - for step in steps.iter() { - // warning: multi deploy not yet fully supported - // only works with last deployed address - // will be addressed in future versions - let new_deployed_address = step.response().new_deployed_address.clone(); - if let Some(new_address) = new_deployed_address { - let new_address_bech32 = bech32::encode(&new_address); - println!("new address: {new_address_bech32}"); - - let new_address_expr = format!("bech32:{new_address_bech32}"); - self.state.set_multisig_address(&new_address_expr); - } else { - println!("deploy failed"); - return; - } + let results = buffer.run().await; + for new_address in results { + println!("new address: {new_address}"); + self.state.set_multisig_address(new_address); } } @@ -235,7 +186,7 @@ impl MultisigInteract { let eve = test_wallets::eve(); MultiValueVec::from([ - self.wallet_address.clone(), + self.wallet_address.to_address(), carol.address().to_bytes().into(), dan.address().to_bytes().into(), eve.address().to_bytes().into(), @@ -243,151 +194,183 @@ impl MultisigInteract { } async fn feed_contract_egld(&mut self) { - let _ = self - .interactor - .transfer( - TransferStep::new() - .from(&self.wallet_address) - .to(self.state.multisig()) - .egld_value("0,050000000000000000"), - ) + self.interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .egld(BigUint::from(50_000_000_000_000_000u64)) // 0,05 or 5 * 10^16 + .prepare_async() + .run() .await; } - async fn perform_action(&mut self, action_id: usize, gas_expr: &str) { - if !self.quorum_reached(action_id).await && !self.sign(action_id).await { - return; + async fn perform_action(&mut self, action_id: usize, gas_expr: u64) { + if !self.quorum_reached(action_id).await { + self.sign(&[action_id]).await } println!("quorum reached for action `{action_id}`"); self.interactor - .sc_call( - ScCallStep::new() - .call(self.state.multisig().perform_action_endpoint(action_id)) - .from(&self.wallet_address) - .gas_limit(gas_expr) - .expect(TxExpect::ok().additional_error_message(format!( - "perform action `{action_id}` failed with: " - ))), - ) + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(gas_expr) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(action_id) + .prepare_async() + .run() .await; println!("successfully performed action `{action_id}`"); } - async fn perform_actions(&mut self, actions: Vec, gas_expr: &str) { - let mut steps = Vec::new(); - for action_id in actions.iter() { - if !self.quorum_reached(*action_id).await && !self.sign(*action_id).await { - continue; + async fn perform_actions(&mut self, action_ids: Vec, gas_expr: u64) { + let mut actions_no_quorum_reached = Vec::new(); + for &action_id in &action_ids { + if self.quorum_reached(action_id).await { + println!("quorum reached for action `{action_id}`"); + } else { + actions_no_quorum_reached.push(action_id) } - println!("quorum reached for action `{action_id}`"); - - let typed_sc_call = ScCallStep::new() - .call(self.state.multisig().perform_action_endpoint(action_id)) - .from(&self.wallet_address) - .gas_limit(gas_expr); + } - steps.push(typed_sc_call); + self.sign(&actions_no_quorum_reached).await; + + let from = &self.wallet_address; + let mut buffer = self.interactor.homogenous_call_buffer(); + let multisig_address = self.state.current_multisig_address(); + for action_id in action_ids { + buffer.push_tx(|tx| { + tx.from(from) + .to(multisig_address) + .gas(gas_expr) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(action_id) + .returns(ReturnsResult) + }); } - self.interactor - .multi_sc_exec(StepBuffer::from_sc_call_vec(&mut steps)) - .await; + let deployed_addresses = buffer.run().await; - for (i, action_id) in actions.iter().enumerate() { - if !steps[i].response().is_success() { + for (action_id, address) in deployed_addresses.iter().enumerate() { + println!("successfully performed action `{action_id}`"); + if address.is_some() { println!( - "perform action `{action_id}` failed with: {}", - steps[i].response().tx_error - ); - continue; + "new deployed address for action `{action_id}: {:#?}`", + address.clone().into_option().unwrap() + ) } - - println!("successfully performed action `{action_id}`"); } } async fn quorum_reached(&mut self, action_id: usize) -> bool { self.interactor - .quick_query(self.state.multisig().quorum_reached(action_id)) + .query() + .to(self.state.current_multisig_address()) + .typed(multisig_proxy::MultisigProxy) + .quorum_reached(action_id) + .returns(ReturnsResult) + .prepare_async() + .run() .await } async fn signed(&mut self, signer: &Address, action_id: usize) -> bool { self.interactor - .quick_query(self.state.multisig().signed(signer, action_id)) + .query() + .to(self.state.current_multisig_address()) + .typed(multisig_proxy::MultisigProxy) + .signed(signer, action_id) + .returns(ReturnsResult) + .prepare_async() + .run() .await } - async fn sign(&mut self, action_id: usize) -> bool { - println!("signing action `{action_id}`..."); - let mut steps = Vec::new(); - for signer in self.board().iter() { - if self.signed(signer, action_id).await { - println!( - "{} - already signed action `{action_id}`", - bech32::encode(signer) - ); - continue; + async fn sign(&mut self, action_ids: &[usize]) { + println!("signing actions `{action_ids:?}`..."); + + let mut pending_signers = Vec::<(Address, usize)>::new(); + for &action_id in action_ids { + for signer in self.board().iter() { + if self.signed(signer, action_id).await { + println!( + "{} - already signed action `{action_id}`", + bech32::encode(signer) + ); + } else { + pending_signers.push((signer.clone(), action_id)); + } } + } - let typed_sc_call = ScCallStep::new() - .call(self.state.multisig().sign(action_id)) - .from(signer) - .gas_limit("15,000,000"); - - steps.push(typed_sc_call); + let mut buffer = self.interactor.homogenous_call_buffer(); + let multisig_address = self.state.current_multisig_address(); + for (signer, action_id) in pending_signers { + buffer.push_tx(|tx| { + tx.from(signer) + .to(multisig_address) + .gas(15_000_000u64) + .typed(multisig_proxy::MultisigProxy) + .sign(action_id) + }); } - self.interactor - .multi_sc_exec(StepBuffer::from_sc_call_vec(&mut steps)) - .await; + buffer.run().await; - for step in steps.iter() { - if !step.response().is_success() { - println!( - "perform sign `{action_id}` failed with: {}", - step.response().tx_error - ); - return false; - } - } + println!("successfully performed sign action `{action_ids:?}`"); + } - println!("successfully performed sign action `{action_id}`"); - true + async fn sign_if_quorum_not_reached(&mut self, action_id: usize) { + if !self.quorum_reached(action_id).await { + self.sign(&[action_id]).await; + } + println!("quorum reached for action `{action_id}`"); } async fn dns_register(&mut self, name: &str) { let dns_address = dns_address_for_name(name); self.interactor - .sc_call( - ScCallStep::new() - .call(self.state.multisig().dns_register(dns_address, name)) - .from(&self.wallet_address) - .gas_limit("30,000,000") - .expect(TxExpect::ok().additional_error_message("dns register failed with: ")), - ) + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("30,000,000")) + .typed(multisig_proxy::MultisigProxy) + .dns_register(dns_address, name) + .prepare_async() + .run() .await; println!("successfully registered dns"); } async fn print_quorum(&mut self) { - let quorum: SingleValue = self + let quorum = self .interactor - .quick_query(self.state.multisig().quorum()) + .query() + .to(self.state.current_multisig_address()) + .typed(multisig_proxy::MultisigProxy) + .quorum() + .returns(ReturnsResult) + .prepare_async() + .run() .await; - println!("quorum: {}", quorum.into()); + println!("quorum: {}", quorum); } async fn print_board(&mut self) { - let board: SingleValue = self + let board = self .interactor - .quick_query(self.state.multisig().num_board_members()) + .query() + .to(self.state.current_multisig_address()) + .typed(multisig_proxy::MultisigProxy) + .num_board_members() + .returns(ReturnsResult) + .prepare_async() + .run() .await; - println!("board: {}", board.into()); + println!("board: {}", board); } } diff --git a/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs b/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs index ab8fa001f7..2efda8e4d6 100644 --- a/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs +++ b/contracts/examples/multisig/interact/src/multisig_interact_nfts.rs @@ -1,9 +1,6 @@ use std::time::Duration; -use multiversx_sc_scenario::multiversx_sc::{ - codec::{multi_types::IgnoreValue, Empty}, - types::FunctionCall, -}; +use multiversx_sc_snippets::imports::*; use super::*; @@ -36,29 +33,26 @@ impl MultisigInteract { } pub async fn propose_issue_collection_with_all_roles(&mut self) -> usize { - let system_sc_address = bech32::decode(SYSTEM_SC_BECH32); let action_id = self .interactor - .sc_call_get_result( - ScCallStep::new() - .call( - self.state.multisig().propose_async_call( - system_sc_address, - ISSUE_COST, - FunctionCall::new("registerAndSetAllRoles") - .argument(&COLLECTION_NAME) - .argument(&COLLECTION_TICKER) - .argument(&TOKEN_TYPE) - .argument(&0u32), - ), - ) - .from(&self.wallet_address) - .gas_limit("10,000,000") - .expect(TxExpect::ok().additional_error_message("failed to issue collection")), + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("10,000,000")) + .typed(multisig_proxy::MultisigProxy) + .propose_async_call( + ESDTSystemSCAddress, + ISSUE_COST, + FunctionCall::new("registerAndSetAllRoles") + .argument(&COLLECTION_NAME) + .argument(&COLLECTION_TICKER) + .argument(&TOKEN_TYPE) + .argument(&0u32), ) - .await - .result - .unwrap(); + .returns(ReturnsResult) + .prepare_async() + .run() + .await; println!("successfully proposed issue colllection with roles all action `{action_id}`"); action_id @@ -70,26 +64,22 @@ impl MultisigInteract { println!("perfoming issue collection with all roles action `{action_id}`..."); - if !self.quorum_reached(action_id).await && !self.sign(action_id).await { - return; - } - println!("quorum reached for action `{action_id}`"); + self.sign_if_quorum_not_reached(action_id).await; - let response: TypedResponse = self + let new_token_id = self .interactor - .sc_call_get_result( - ScCallStep::new() - .call(self.state.multisig().perform_action_endpoint(action_id)) - .from(&self.wallet_address) - .gas_limit("80,000,000") - .expect(TxExpect::ok().additional_error_message( - "perform issue collection with all roles failed: ", - )), - ) + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("80,000,000")) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(action_id) + .returns(ReturnsNewTokenIdentifier) + .prepare_async() + .run() .await; - self.collection_token_identifier = response - .new_issued_token_identifier - .expect("new token identifier could not be retrieved"); + self.collection_token_identifier = new_token_id.to_string(); + println!( "collection token identifier: {}", self.collection_token_identifier @@ -97,26 +87,24 @@ impl MultisigInteract { } pub async fn propose_issue_collection(&mut self) -> usize { - let system_sc_address = bech32::decode(SYSTEM_SC_BECH32); let action_id = self .interactor - .sc_call_get_result( - ScCallStep::new() - .call( - self.state.multisig().propose_async_call( - system_sc_address, - ISSUE_COST, - FunctionCall::new("issueNonFungible") - .argument(&COLLECTION_NAME) - .argument(&COLLECTION_TICKER), - ), - ) - .from(&self.wallet_address) - .gas_limit("10,000,000"), + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("10,000,000")) + .typed(multisig_proxy::MultisigProxy) + .propose_async_call( + ESDTSystemSCAddress, + ISSUE_COST, + FunctionCall::new("issueNonFungible") + .argument(&COLLECTION_NAME) + .argument(&COLLECTION_TICKER), ) - .await - .result - .unwrap(); + .returns(ReturnsResult) + .prepare_async() + .run() + .await; println!("successfully proposed issue colllection action `{action_id}`"); action_id @@ -128,26 +116,22 @@ impl MultisigInteract { println!("perfoming issue collection action `{action_id}`..."); - if !self.quorum_reached(action_id).await && !self.sign(action_id).await { - return; - } - println!("quorum reached for action `{action_id}`"); - - let response: TypedResponse = - self.interactor - .sc_call_get_result( - ScCallStep::new() - .call(self.state.multisig().perform_action_endpoint(action_id)) - .from(&self.wallet_address) - .gas_limit("80,000,000") - .expect(TxExpect::ok().additional_error_message( - "perform issue collection with all failed: ", - )), - ) - .await; - self.collection_token_identifier = response - .new_issued_token_identifier - .expect("new token identifier could not be retrieved"); + self.sign_if_quorum_not_reached(action_id).await; + + let new_token_id = self + .interactor + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("80,000,000")) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(action_id) + .returns(ReturnsNewTokenIdentifier) + .prepare_async() + .run() + .await; + self.collection_token_identifier = new_token_id; + println!( "collection token identifier: {}", self.collection_token_identifier @@ -155,27 +139,26 @@ impl MultisigInteract { } pub async fn propose_set_special_role(&mut self) -> usize { - let multisig_address = self.state.multisig().to_address(); + let multisig_address = self.state.current_multisig_address(); let action_id = self .interactor - .sc_call_get_result( - ScCallStep::new() - .call( - self.state.multisig().propose_async_call( - &self.system_sc_address, - 0u64, - FunctionCall::new("setSpecialRole") - .argument(&self.collection_token_identifier) - .argument(&multisig_address) - .argument(&"ESDTRoleNFTCreate"), - ), - ) - .from(&self.wallet_address) - .gas_limit("10,000,000"), + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("10,000,000")) + .typed(multisig_proxy::MultisigProxy) + .propose_async_call( + ESDTSystemSCAddress, + 0u64, + FunctionCall::new("setSpecialRole") + .argument(&self.collection_token_identifier) + .argument(multisig_address) + .argument(&"ESDTRoleNFTCreate"), ) - .await - .result - .unwrap(); + .returns(ReturnsResult) + .prepare_async() + .run() + .await; println!("successfully proposed set special role with action `{action_id}`"); action_id @@ -186,25 +169,27 @@ impl MultisigInteract { let action_id = self.propose_set_special_role().await; println!("performing set special role action `{action_id}`..."); - self.perform_action(action_id, "80,000,000").await; + self.perform_action(action_id, 80_000_000u64).await; } pub async fn create_items(&mut self) { println!("creating items..."); - let multisig_address = self.state.multisig().to_address(); - let mut steps = Vec::new(); - + let mut buffer = self.interactor.homogenous_call_buffer(); + let multisig_address = self.state.current_multisig_address(); for item_index in 0..NUM_ITEMS { let item_name = format!("Test collection item #{item_index}"); let image_cid = format!( "https://ipfs.io/ipfs/QmYyAaEf1phJS5mN6wfou5de5GbpUddBxTY1VekKcjd5PC/nft{item_index:02}.png" ); - let typed_sc_call = ScCallStep::new() - .call( - self.state.multisig().propose_async_call( - &multisig_address, + buffer.push_tx(|tx| { + tx.from(&self.wallet_address) + .to(multisig_address) + .gas(10_000_000u64) + .typed(multisig_proxy::MultisigProxy) + .propose_async_call( + multisig_address, 0u64, FunctionCall::new("ESDTNFTCreate") .argument(&self.collection_token_identifier) @@ -214,34 +199,16 @@ impl MultisigInteract { .argument(&Empty) .argument(&METADATA) .argument(&image_cid), - ), - ) - .from(&self.wallet_address) - .gas_limit("10,000,000"); - - steps.push(typed_sc_call); + ) + .returns(ReturnsResult) + }); } - self.interactor - .multi_sc_exec(StepBuffer::from_sc_call_vec(&mut steps)) - .await; - - let mut actions = Vec::new(); - for step in steps.iter() { - let result = step.result(); - if result.is_err() { - println!( - "propose ESDTNFTCreate failed with: {}", - result.err().unwrap() - ); - return; - } - - let action_id = result.unwrap(); + let action_ids = buffer.run().await; + for action_id in action_ids.iter() { println!("successfully proposed ESDTNFTCreate action `{action_id}`"); - actions.push(action_id); } - self.perform_actions(actions, "30,000,000").await; + self.perform_actions(action_ids, 30_000_000u64).await; } } diff --git a/contracts/examples/multisig/interact/src/multisig_interact_state.rs b/contracts/examples/multisig/interact/src/multisig_interact_state.rs index fef8b8baff..d5ff8bb7c1 100644 --- a/contracts/examples/multisig/interact/src/multisig_interact_state.rs +++ b/contracts/examples/multisig/interact/src/multisig_interact_state.rs @@ -1,23 +1,17 @@ -use crate::{ContractInfo, StaticApi}; +use multiversx_sc_scenario::imports::Bech32Address; use serde::{Deserialize, Serialize}; use std::{ io::{Read, Write}, path::Path, }; -/// Default multisig address -const DEFAULT_MULTISIG_ADDRESS: &str = - "0x0000000000000000000000000000000000000000000000000000000000000000"; - /// State file const STATE_FILE: &str = "state.toml"; -pub type MultisigContract = ContractInfo>; - /// Multisig Interact state #[derive(Debug, Default, Serialize, Deserialize)] pub struct State { - multisig_address: Option, + multisig_address: Option, } impl State { @@ -34,18 +28,14 @@ impl State { } /// Sets the multisig address - pub fn set_multisig_address(&mut self, address: &str) { - self.multisig_address = Some(String::from(address)); - } - - /// Returns the multisig contract - pub fn multisig(&self) -> MultisigContract { - MultisigContract::new(self.multisig_address.clone().unwrap()) + pub fn set_multisig_address(&mut self, address: Bech32Address) { + self.multisig_address = Some(address); } - /// Returns the multisig contract with default address - pub fn default_multisig(&self) -> MultisigContract { - MultisigContract::new(DEFAULT_MULTISIG_ADDRESS) + pub fn current_multisig_address(&self) -> &Bech32Address { + self.multisig_address + .as_ref() + .expect("no known multisig contract, deploy first") } } diff --git a/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs b/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs index a0d105abd9..a59e686e2a 100644 --- a/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs +++ b/contracts/examples/multisig/interact/src/multisig_interact_wegld.rs @@ -1,17 +1,6 @@ use std::time::Duration; -use multiversx_sc_scenario::multiversx_sc::types::FunctionCall; -#[allow(unused_imports)] -use multiversx_sc_snippets::multiversx_sc::types::{ - EsdtTokenPayment, MultiValueEncoded, TokenIdentifier, -}; -use multiversx_sc_snippets::{ - multiversx_sc::types::{ContractCall, ContractCallNoPayment}, - multiversx_sc_scenario::{ - mandos_system::ScenarioRunner, scenario_format::interpret_trait::InterpretableFrom, - standalone::retrieve_account_as_scenario_set_state, - }, -}; +use multiversx_sc_snippets::imports::*; use super::*; @@ -34,7 +23,7 @@ impl MultisigInteract { let action_id = self.propose_wrap_egld().await; println!("perfoming wrap egld action `{action_id}`..."); - self.perform_action(action_id, "15,000,000").await; + self.perform_action(action_id, 15_000_000u64).await; } pub async fn unwrap_egld(&mut self) { @@ -42,71 +31,61 @@ impl MultisigInteract { let action_id = self.propose_unwrap_egld().await; println!("perfoming unwrap egld action `{action_id}`..."); - self.perform_action(action_id, "15,000,000").await; + self.perform_action(action_id, 15_000_000u64).await; } pub async fn wegld_swap_set_state(&mut self) { - let scenario_raw = retrieve_account_as_scenario_set_state( - Config::load_config().gateway().to_string(), - WEGLD_SWAP_SC_BECH32.to_string(), - true, - ) - .await; - - let scenario = Scenario::interpret_from(scenario_raw, &InterpreterContext::default()); - - self.interactor.pre_runners.run_scenario(&scenario); - self.interactor.post_runners.run_scenario(&scenario); + self.interactor + .retrieve_account(&Bech32Address::from_bech32_string( + WEGLD_SWAP_SC_BECH32.to_owned(), + )) + .await; } async fn propose_wrap_egld(&mut self) -> usize { let action_id = self .interactor - .sc_call_get_result( - ScCallStep::new() - .call(self.state.multisig().propose_async_call( - bech32::decode(WEGLD_SWAP_SC_BECH32), - WRAP_AMOUNT, - FunctionCall::new("wrapEgld"), - )) - .from(&self.wallet_address) - .gas_limit("10,000,000"), + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("10,000,000")) + .typed(multisig_proxy::MultisigProxy) + .propose_async_call( + bech32::decode(WEGLD_SWAP_SC_BECH32), + WRAP_AMOUNT, + FunctionCall::new("wrapEgld"), ) - .await - .result - .unwrap(); + .returns(ReturnsResult) + .prepare_async() + .run() + .await; println!("successfully proposed wrap egld action `{action_id}`"); action_id } async fn propose_unwrap_egld(&mut self) -> usize { - let contract_call = ContractCallNoPayment::::new( - bech32::decode(WEGLD_SWAP_SC_BECH32).into(), - "unwrapEgld", - ) - .with_esdt_transfer(EsdtTokenPayment::new( + let to = ManagedAddress::::from(bech32::decode(WEGLD_SWAP_SC_BECH32)); + let payment = EsdtTokenPayment::new( TokenIdentifier::from(WEGLD_TOKEN_IDENTIFIER), 0u64, UNWRAP_AMOUNT.into(), - )) - .into_normalized(); + ); + let function_call = FunctionCall::new("unwrapEgld"); let action_id = self .interactor - .sc_call_get_result( - ScCallStep::new() - .call(self.state.multisig().propose_async_call( - contract_call.basic.to, - 0u64, - contract_call.basic.function_call, - )) - .from(&self.wallet_address) - .gas_limit("10,000,000"), - ) - .await - .result - .unwrap(); + .tx() + .from(&self.wallet_address) + .to(self.state.current_multisig_address()) + .gas(NumExpr("10,000,000")) + .typed(multisig_proxy::MultisigProxy) + .propose_async_call(to, 0u64, function_call) + .esdt(payment) + .returns(ReturnsResult) + .prepare_async() + .run() + .await; println!("successfully proposed unwrap egld action `{action_id}`"); action_id diff --git a/contracts/examples/multisig/meta/Cargo.toml b/contracts/examples/multisig/meta/Cargo.toml index b019bfbb43..0e29c29265 100644 --- a/contracts/examples/multisig/meta/Cargo.toml +++ b/contracts/examples/multisig/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/multisig/sc-config.toml b/contracts/examples/multisig/sc-config.toml index ca6a294c4f..79c3aeaa20 100644 --- a/contracts/examples/multisig/sc-config.toml +++ b/contracts/examples/multisig/sc-config.toml @@ -14,3 +14,6 @@ name = "multisig-view" external-view = true add-unlabelled = false add-labels = ["multisig-external-view"] + +[[proxy]] +path = "src/multisig_proxy.rs" diff --git a/contracts/examples/multisig/src/action.rs b/contracts/examples/multisig/src/action.rs index d36af70f90..c26c83259a 100644 --- a/contracts/examples/multisig/src/action.rs +++ b/contracts/examples/multisig/src/action.rs @@ -5,7 +5,8 @@ use multiversx_sc::{ use multiversx_sc::derive_imports::*; -#[derive(NestedEncode, NestedDecode, TypeAbi, Clone)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, Clone)] pub struct CallActionData { pub to: ManagedAddress, pub egld_amount: BigUint, @@ -13,7 +14,8 @@ pub struct CallActionData { pub arguments: ManagedVec>, } -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi, Clone)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone)] pub enum Action { Nothing, AddBoardMember(ManagedAddress), @@ -47,7 +49,8 @@ impl Action { } /// Not used internally, just to retrieve results via endpoint. -#[derive(TopEncode, TypeAbi)] +#[type_abi] +#[derive(TopEncode)] pub struct ActionFullInfo { pub action_id: usize, pub action_data: Action, diff --git a/contracts/examples/multisig/src/multisig.rs b/contracts/examples/multisig/src/multisig.rs index a3baed53ce..96d3d5cdfa 100644 --- a/contracts/examples/multisig/src/multisig.rs +++ b/contracts/examples/multisig/src/multisig.rs @@ -4,6 +4,7 @@ pub mod action; pub mod multisig_events; pub mod multisig_perform; pub mod multisig_propose; +pub mod multisig_proxy; pub mod multisig_state; pub mod user_role; diff --git a/contracts/examples/multisig/src/multisig_perform.rs b/contracts/examples/multisig/src/multisig_perform.rs index 1912b85321..3024df2696 100644 --- a/contracts/examples/multisig/src/multisig_perform.rs +++ b/contracts/examples/multisig/src/multisig_perform.rs @@ -167,16 +167,13 @@ pub trait MultisigPerformModule: &call_data.endpoint_name, call_data.arguments.as_multi(), ); - let result = self.send_raw().direct_egld_execute( - &call_data.to, - &call_data.egld_amount, - gas, - &call_data.endpoint_name, - &call_data.arguments.into(), - ); - if let Result::Err(e) = result { - sc_panic!(e); - } + self.tx() + .to(call_data.to) + .egld(call_data.egld_amount) + .gas(gas) + .raw_call(call_data.endpoint_name) + .arguments_raw(call_data.arguments.into()) + .transfer_execute(); OptionalValue::None }, Action::SendAsyncCall(call_data) => { @@ -189,13 +186,14 @@ pub trait MultisigPerformModule: &call_data.endpoint_name, call_data.arguments.as_multi(), ); - self.send() - .contract_call::<()>(call_data.to, call_data.endpoint_name) - .with_egld_transfer(call_data.egld_amount) - .with_raw_arguments(call_data.arguments.into()) - .async_call() - .with_callback(self.callbacks().perform_async_call_callback()) - .call_and_exit() + + self.tx() + .to(&call_data.to) + .raw_call(call_data.endpoint_name) + .arguments_raw(call_data.arguments.into()) + .egld(call_data.egld_amount) + .callback(self.callbacks().perform_async_call_callback()) + .async_call_and_exit(); }, Action::SCDeployFromSource { amount, @@ -212,13 +210,16 @@ pub trait MultisigPerformModule: gas_left, arguments.as_multi(), ); - let (new_address, _) = self.send_raw().deploy_from_source_contract( - gas_left, - &amount, - &source, - code_metadata, - &arguments.into(), - ); + let new_address = self + .tx() + .egld(amount) + .gas(gas_left) + .raw_deploy() + .from_source(source) + .code_metadata(code_metadata) + .arguments_raw(arguments.into()) + .returns(ReturnsNewManagedAddress) + .sync_call(); OptionalValue::Some(new_address) }, Action::SCUpgradeFromSource { @@ -238,14 +239,15 @@ pub trait MultisigPerformModule: gas_left, arguments.as_multi(), ); - self.send_raw().upgrade_from_source_contract( - &sc_address, - gas_left, - &amount, - &source, - code_metadata, - &arguments.into(), - ); + self.tx() + .to(sc_address) + .egld(amount) + .gas(gas_left) + .raw_upgrade() + .from_source(source) + .code_metadata(code_metadata) + .arguments_raw(arguments.into()) + .upgrade_async_call_and_exit(); OptionalValue::None }, } diff --git a/contracts/examples/multisig/src/multisig_proxy.rs b/contracts/examples/multisig/src/multisig_proxy.rs new file mode 100644 index 0000000000..6f789f298a --- /dev/null +++ b/contracts/examples/multisig/src/multisig_proxy.rs @@ -0,0 +1,552 @@ +// 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 MultisigProxy; + +impl TxProxyTrait for MultisigProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = MultisigProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + MultisigProxyMethods { wrapped_tx: tx } + } +} + +pub struct MultisigProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl MultisigProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + quorum: Arg0, + board: Arg1, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&quorum) + .argument(&board) + .original_result() + } +} + +#[rustfmt::skip] +impl MultisigProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + quorum: Arg0, + board: Arg1, + ) -> TxProxyUpgrade { + self.wrapped_tx + .raw_upgrade() + .argument(&quorum) + .argument(&board) + .original_result() + } +} + +#[rustfmt::skip] +impl MultisigProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Allows the contract to receive funds even if it is marked as unpayable in the protocol. + pub fn deposit( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("deposit") + .original_result() + } + + /// Iterates through all actions and retrieves those that are still pending. + /// Serialized full action data: + /// - the action id + /// - the serialized action data + /// - (number of signers followed by) list of signer addresses. + pub fn get_pending_action_full_info( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getPendingActionFullInfo") + .original_result() + } + + /// Returns `true` (`1`) if the user has signed the action. + /// Does not check whether or not the user is still a board member and the signature valid. + pub fn signed< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + user: Arg0, + action_id: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("signed") + .argument(&user) + .argument(&action_id) + .original_result() + } + + /// Indicates user rights. + /// `0` = no rights, + /// `1` = can propose, but not sign, + /// `2` = can propose and sign. + pub fn user_role< + Arg0: ProxyArg>, + >( + self, + user: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("userRole") + .argument(&user) + .original_result() + } + + /// Lists all users that can sign actions. + pub fn get_all_board_members( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getAllBoardMembers") + .original_result() + } + + /// Lists all proposers that are not board members. + pub fn get_all_proposers( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getAllProposers") + .original_result() + } + + /// Used by board members to sign actions. + pub fn sign< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("sign") + .argument(&action_id) + .original_result() + } + + /// Board members can withdraw their signatures if they no longer desire for the action to be executed. + /// Actions that are left with no valid signatures can be then deleted to free up storage. + pub fn unsign< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unsign") + .argument(&action_id) + .original_result() + } + + /// Clears storage pertaining to an action that is no longer supposed to be executed. + /// Any signatures that the action received must first be removed, via `unsign`. + /// Otherwise this endpoint would be prone to abuse. + pub fn discard_action< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("discardAction") + .argument(&action_id) + .original_result() + } + + /// Minimum number of signatures needed to perform any action. + pub fn quorum( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getQuorum") + .original_result() + } + + /// Denormalized board member count. + /// It is kept in sync with the user list by the contract. + pub fn num_board_members( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getNumBoardMembers") + .original_result() + } + + /// Denormalized proposer count. + /// It is kept in sync with the user list by the contract. + pub fn num_proposers( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getNumProposers") + .original_result() + } + + /// The index of the last proposed action. + /// 0 means that no action was ever proposed yet. + pub fn get_action_last_index( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getActionLastIndex") + .original_result() + } + + /// Serialized action data of an action with index. + pub fn get_action_data< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getActionData") + .argument(&action_id) + .original_result() + } + + /// Gets addresses of all users who signed an action. + /// Does not check if those users are still board members or not, + /// so the result may contain invalid signers. + pub fn get_action_signers< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getActionSigners") + .argument(&action_id) + .original_result() + } + + /// Gets addresses of all users who signed an action and are still board members. + /// All these signatures are currently valid. + pub fn get_action_signer_count< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getActionSignerCount") + .argument(&action_id) + .original_result() + } + + /// It is possible for board members to lose their role. + /// They are not automatically removed from all actions when doing so, + /// therefore the contract needs to re-check every time when actions are performed. + /// This function is used to validate the signers before performing an action. + /// It also makes it easy to check before performing an action. + pub fn get_action_valid_signer_count< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getActionValidSignerCount") + .argument(&action_id) + .original_result() + } + + /// Initiates board member addition process. + /// Can also be used to promote a proposer to board member. + pub fn propose_add_board_member< + Arg0: ProxyArg>, + >( + self, + board_member_address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeAddBoardMember") + .argument(&board_member_address) + .original_result() + } + + /// Initiates proposer addition process.. + /// Can also be used to demote a board member to proposer. + pub fn propose_add_proposer< + Arg0: ProxyArg>, + >( + self, + proposer_address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeAddProposer") + .argument(&proposer_address) + .original_result() + } + + /// Removes user regardless of whether it is a board member or proposer. + pub fn propose_remove_user< + Arg0: ProxyArg>, + >( + self, + user_address: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeRemoveUser") + .argument(&user_address) + .original_result() + } + + pub fn propose_change_quorum< + Arg0: ProxyArg, + >( + self, + new_quorum: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeChangeQuorum") + .argument(&new_quorum) + .original_result() + } + + /// Propose a transaction in which the contract will perform a transfer-execute call. + /// Can send EGLD without calling anything. + /// Can call smart contract endpoints directly. + /// Doesn't really work with builtin functions. + pub fn propose_transfer_execute< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + egld_amount: Arg1, + function_call: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeTransferExecute") + .argument(&to) + .argument(&egld_amount) + .argument(&function_call) + .original_result() + } + + /// Propose a transaction in which the contract will perform a transfer-execute call. + /// Can call smart contract endpoints directly. + /// Can use ESDTTransfer/ESDTNFTTransfer/MultiESDTTransfer to send tokens, while also optionally calling endpoints. + /// Works well with builtin functions. + /// Cannot simply send EGLD directly without calling anything. + pub fn propose_async_call< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + egld_amount: Arg1, + function_call: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeAsyncCall") + .argument(&to) + .argument(&egld_amount) + .argument(&function_call) + .original_result() + } + + pub fn propose_sc_deploy_from_source< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>>, + >( + self, + amount: Arg0, + source: Arg1, + code_metadata: Arg2, + arguments: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeSCDeployFromSource") + .argument(&amount) + .argument(&source) + .argument(&code_metadata) + .argument(&arguments) + .original_result() + } + + pub fn propose_sc_upgrade_from_source< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg, + Arg4: ProxyArg>>, + >( + self, + sc_address: Arg0, + amount: Arg1, + source: Arg2, + code_metadata: Arg3, + arguments: Arg4, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("proposeSCUpgradeFromSource") + .argument(&sc_address) + .argument(&amount) + .argument(&source) + .argument(&code_metadata) + .argument(&arguments) + .original_result() + } + + /// Returns `true` (`1`) if `getActionValidSignerCount >= getQuorum`. + pub fn quorum_reached< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("quorumReached") + .argument(&action_id) + .original_result() + } + + /// Proposers and board members use this to launch signed actions. + pub fn perform_action_endpoint< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("performAction") + .argument(&action_id) + .original_result() + } + + pub fn dns_register< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + dns_address: Arg0, + name: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("dnsRegister") + .argument(&dns_address) + .argument(&name) + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode)] +pub struct ActionFullInfo +where + Api: ManagedTypeApi, +{ + pub action_id: usize, + pub action_data: Action, + pub signers: ManagedVec>, +} + +#[rustfmt::skip] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone)] +pub enum Action +where + Api: ManagedTypeApi, +{ + Nothing, + AddBoardMember(ManagedAddress), + AddProposer(ManagedAddress), + RemoveUser(ManagedAddress), + ChangeQuorum(usize), + SendTransferExecute(CallActionData), + SendAsyncCall(CallActionData), + SCDeployFromSource { + amount: BigUint, + source: ManagedAddress, + code_metadata: CodeMetadata, + arguments: ManagedVec>, + }, + SCUpgradeFromSource { + sc_address: ManagedAddress, + amount: BigUint, + source: ManagedAddress, + code_metadata: CodeMetadata, + arguments: ManagedVec>, + }, +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, Clone)] +pub struct CallActionData +where + Api: ManagedTypeApi, +{ + pub to: ManagedAddress, + pub egld_amount: BigUint, + pub endpoint_name: ManagedBuffer, + pub arguments: ManagedVec>, +} + +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub enum UserRole { + None, + Proposer, + BoardMember, +} diff --git a/contracts/examples/multisig/tests/multisig_blackbox_test.rs b/contracts/examples/multisig/tests/multisig_blackbox_test.rs index bb8eeff8f4..322abd9348 100644 --- a/contracts/examples/multisig/tests/multisig_blackbox_test.rs +++ b/contracts/examples/multisig/tests/multisig_blackbox_test.rs @@ -1,263 +1,247 @@ -use adder::ProxyTrait as _; -use multisig::{ - multisig_perform::ProxyTrait as _, multisig_propose::ProxyTrait as _, user_role::UserRole, - ProxyTrait as _, -}; -use multiversx_sc::{ - codec::{ - multi_types::{MultiValueVec, OptionalValue}, - test_util::top_encode_to_vec_u8_or_panic, - }, - storage::mappers::SingleValue, - types::{Address, CodeMetadata, ContractCallNoPayment, FunctionCall}, -}; -use multiversx_sc_scenario::{ - api::StaticApi, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, ScQueryStep, - SetStateStep, TxExpect, - }, - ContractInfo, ScenarioWorld, -}; +use multiversx_sc::codec::top_encode_to_vec_u8_or_panic; +use multiversx_sc_scenario::imports::*; + +use adder::adder_proxy; +use multisig::multisig_proxy; use num_bigint::BigUint; -const ADDER_ADDRESS_EXPR: &str = "sc:adder"; -const ADDER_OWNER_ADDRESS_EXPR: &str = "address:adder-owner"; -const ADDER_PATH_EXPR: &str = "mxsc:test-contracts/adder.mxsc.json"; -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_EXPR: &str = "address:owner"; -const PROPOSER_ADDRESS_EXPR: &str = "address:proposer"; -const PROPOSER_BALANCE_EXPR: &str = "100,000,000"; +const ADDER_ADDRESS: TestSCAddress = TestSCAddress::new("adder"); +const ADDER_OWNER_ADDRESS: TestAddress = TestAddress::new("adder-owner"); +const ADDER_CODE_PATH: MxscPath = MxscPath::new("test-contracts/adder.mxsc.json"); +const BOARD_MEMBER_ADDRESS: TestAddress = TestAddress::new("board-member"); +const MULTISIG_ADDRESS: TestSCAddress = TestSCAddress::new("multisig"); +const MULTISIG_CODE_PATH: MxscPath = MxscPath::new("output/multisig.mxsc.json"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const PROPOSER_ADDRESS: TestAddress = TestAddress::new("proposer"); +const PROPOSER_BALANCE: u64 = 100_000_000; const QUORUM_SIZE: usize = 1; -type MultisigContract = ContractInfo>; -type AdderContract = ContractInfo>; - fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); blockchain.set_current_dir_from_workspace("contracts/examples/multisig"); - blockchain.register_contract(MULTISIG_PATH_EXPR, multisig::ContractBuilder); - blockchain.register_contract(ADDER_PATH_EXPR, adder::ContractBuilder); + blockchain.register_contract(MULTISIG_CODE_PATH, multisig::ContractBuilder); + blockchain.register_contract(ADDER_CODE_PATH, adder::ContractBuilder); blockchain } struct MultisigTestState { world: ScenarioWorld, - proposer_address: Address, - board_member_address: Address, - multisig_contract: MultisigContract, - adder_contract: AdderContract, - adder_address: Address, } impl MultisigTestState { fn new() -> Self { 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, MULTISIG_ADDRESS_EXPR) - .put_account( - PROPOSER_ADDRESS_EXPR, - Account::new().nonce(1).balance(PROPOSER_BALANCE_EXPR), - ) - .put_account(BOARD_MEMBER_ADDRESS_EXPR, Account::new().nonce(1)) - .put_account(ADDER_OWNER_ADDRESS_EXPR, Account::new().nonce(1)) - .new_address(ADDER_OWNER_ADDRESS_EXPR, 1, ADDER_ADDRESS_EXPR), - ); - - let proposer_address = AddressValue::from(PROPOSER_ADDRESS_EXPR).to_address(); - let board_member_address = AddressValue::from(BOARD_MEMBER_ADDRESS_EXPR).to_address(); - let multisig_contract = MultisigContract::new(MULTISIG_ADDRESS_EXPR); - let adder_contract = AdderContract::new(ADDER_ADDRESS_EXPR); - let adder_address = AddressValue::from(ADDER_ADDRESS_EXPR).to_address(); - - Self { - world, - proposer_address, - board_member_address, - multisig_contract, - adder_contract, - adder_address, - } + + world + .account(OWNER_ADDRESS) + .nonce(1) + .account(PROPOSER_ADDRESS) + .nonce(1) + .balance(PROPOSER_BALANCE) + .account(BOARD_MEMBER_ADDRESS) + .nonce(1) + .account(ADDER_OWNER_ADDRESS) + .nonce(1); + + Self { world } } fn deploy_multisig_contract(&mut self) -> &mut Self { - let multisig_code = self.world.code_expression(MULTISIG_PATH_EXPR); - let board_members = MultiValueVec::from(vec![self.board_member_address.clone()]); - - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(multisig_code) - .call(self.multisig_contract.init(QUORUM_SIZE, board_members)), - ); - - let action_id: usize = self.world.sc_call_get_result( - ScCallStep::new().from(BOARD_MEMBER_ADDRESS_EXPR).call( - self.multisig_contract - .propose_add_proposer(self.proposer_address.clone()), - ), - ); + let board_members = MultiValueVec::from(vec![BOARD_MEMBER_ADDRESS]); + + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .init(QUORUM_SIZE, board_members) + .code(MULTISIG_CODE_PATH) + .new_address(MULTISIG_ADDRESS) + .run(); + + let action_id: usize = self + .world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_add_proposer(PROPOSER_ADDRESS) + .returns(ReturnsResult) + .run(); + self.sign(action_id); self.perform(action_id); - self.expect_user_role(&self.proposer_address.clone(), UserRole::Proposer); + self.expect_user_role(PROPOSER_ADDRESS, multisig_proxy::UserRole::Proposer); self } - fn deploy_adder_contract(&mut self) -> &mut Self { - let adder_code = self.world.code_expression(ADDER_PATH_EXPR); - - self.world.sc_deploy( - ScDeployStep::new() - .from(ADDER_OWNER_ADDRESS_EXPR) - .code(adder_code) - .call(self.adder_contract.init(5u64)), - ); - - self + fn deploy_adder_contract(&mut self) { + self.world + .tx() + .from(ADDER_OWNER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .init(5u64) + .code(ADDER_CODE_PATH) + .new_address(ADDER_ADDRESS) + .run(); } - fn propose_add_board_member(&mut self, board_member_address: Address) -> usize { - self.world.sc_call_get_result( - ScCallStep::new().from(PROPOSER_ADDRESS_EXPR).call( - self.multisig_contract - .propose_add_board_member(board_member_address), - ), - ) + fn propose_add_board_member(&mut self, board_member_address: TestAddress) -> usize { + self.world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_add_board_member(board_member_address) + .returns(ReturnsResult) + .run() } - fn propose_add_proposer(&mut self, proposer_address: Address) -> usize { - self.world.sc_call_get_result( - ScCallStep::new().from(PROPOSER_ADDRESS_EXPR).call( - self.multisig_contract - .propose_add_proposer(proposer_address), - ), - ) + fn propose_add_proposer(&mut self, proposer_address: TestAddress) -> usize { + self.world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_add_proposer(proposer_address) + .returns(ReturnsResult) + .run() } fn propose_change_quorum(&mut self, new_quorum: usize) -> usize { - self.world.sc_call_get_result( - ScCallStep::new() - .from(PROPOSER_ADDRESS_EXPR) - .call(self.multisig_contract.propose_change_quorum(new_quorum)), - ) + self.world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_change_quorum(new_quorum) + .returns(ReturnsResult) + .run() } fn propose_transfer_execute( &mut self, - to: Address, + to: TestSCAddress, egld_amount: u64, - contract_call: ContractCallNoPayment, + contract_call: FunctionCall, ) -> usize { self.world - .sc_call_get_result(ScCallStep::new().from(PROPOSER_ADDRESS_EXPR).call( - self.multisig_contract.propose_transfer_execute( - to, - egld_amount, - contract_call.into_function_call(), - ), - )) + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_transfer_execute(to, egld_amount, contract_call) + .returns(ReturnsResult) + .run() } fn propose_async_call( &mut self, - to: Address, + to: TestSCAddress, egld_amount: u64, - contract_call: ContractCallNoPayment, + contract_call: FunctionCall, ) -> usize { self.world - .sc_call_get_result(ScCallStep::new().from(PROPOSER_ADDRESS_EXPR).call( - self.multisig_contract.propose_async_call( - to, - egld_amount, - contract_call.into_function_call(), - ), - )) + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_async_call(to, egld_amount, contract_call) + .returns(ReturnsResult) + .run() } - fn propose_remove_user(&mut self, user_address: Address) -> usize { - self.world.sc_call_get_result( - ScCallStep::new() - .from(PROPOSER_ADDRESS_EXPR) - .call(self.multisig_contract.propose_remove_user(user_address)), - ) + fn propose_remove_user(&mut self, user_address: TestAddress) -> usize { + self.world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_remove_user(user_address) + .returns(ReturnsResult) + .run() } fn propose_sc_deploy_from_source( &mut self, amount: u64, - source: Address, + source: TestSCAddress, code_metadata: CodeMetadata, arguments: MultiValueVec>, ) -> usize { self.world - .sc_call_get_result(ScCallStep::new().from(PROPOSER_ADDRESS_EXPR).call( - self.multisig_contract.propose_sc_deploy_from_source( - amount, - source, - code_metadata, - arguments, - ), - )) + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_sc_deploy_from_source(amount, source, code_metadata, arguments) + .returns(ReturnsResult) + .run() } fn propose_sc_upgrade_from_source( &mut self, - sc_address: Address, + sc_address: TestSCAddress, amount: u64, - source: Address, + source: TestSCAddress, code_metadata: CodeMetadata, arguments: MultiValueVec>, ) -> usize { self.world - .sc_call_get_result(ScCallStep::new().from(PROPOSER_ADDRESS_EXPR).call( - self.multisig_contract.propose_sc_upgrade_from_source( - sc_address, - amount, - source, - code_metadata, - arguments, - ), - )) + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_sc_upgrade_from_source(sc_address, amount, source, code_metadata, arguments) + .returns(ReturnsResult) + .run() } fn perform(&mut self, action_id: usize) { - self.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(self.multisig_contract.perform_action_endpoint(action_id)), - ); + self.world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(action_id) + .run(); } fn perform_and_expect_err(&mut self, action_id: usize, err_message: &str) { - self.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(self.multisig_contract.perform_action_endpoint(action_id)) - .expect(TxExpect::user_error("str:".to_string() + err_message)), - ); + self.world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(action_id) + .with_result(ExpectError(4, err_message)) + .run(); } fn sign(&mut self, action_id: usize) { - self.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(self.multisig_contract.sign(action_id)), - ); + self.world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(action_id) + .run(); } - fn expect_user_role(&mut self, user: &Address, expected_user_role: UserRole) { - self.world.sc_query( - ScQueryStep::new() - .call(self.multisig_contract.user_role(user.clone())) - .expect_value(expected_user_role), - ); + fn expect_user_role( + &mut self, + user: TestAddress, + expected_user_role: multisig_proxy::UserRole, + ) { + self.world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .user_role(user) + .returns(ExpectValue(expected_user_role)) + .run(); } } @@ -266,28 +250,27 @@ fn test_add_board_member() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract(); - const NEW_BOARD_MEMBER_ADDRESS_EXPR: &str = "address:new-board-member"; - let new_board_member_address = AddressValue::from(NEW_BOARD_MEMBER_ADDRESS_EXPR).to_address(); + let new_board_member_expr: TestAddress = TestAddress::new("new-board-member"); - state.world.set_state_step( - SetStateStep::new().put_account(NEW_BOARD_MEMBER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + state.world.account(new_board_member_expr).nonce(1); - state.expect_user_role(&new_board_member_address, UserRole::None); + state.expect_user_role(new_board_member_expr, multisig_proxy::UserRole::None); - let action_id = state.propose_add_board_member(new_board_member_address.clone()); + let action_id = state.propose_add_board_member(new_board_member_expr); state.sign(action_id); state.perform(action_id); - state.expect_user_role(&new_board_member_address, UserRole::BoardMember); - state.world.sc_query( - ScQueryStep::new() - .call(state.multisig_contract.get_all_board_members()) - .expect_value(MultiValueVec::
::from(vec![ - state.board_member_address.clone(), - new_board_member_address.clone(), - ])), - ); + let expected_value = MultiValueVec::from(vec![BOARD_MEMBER_ADDRESS, new_board_member_expr]); + + state.expect_user_role(new_board_member_expr, multisig_proxy::UserRole::BoardMember); + state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .get_all_board_members() + .returns(ExpectValue(expected_value)) + .run() } #[test] @@ -295,28 +278,30 @@ fn test_add_proposer() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract(); - const NEW_PROPOSER_ADDRESS_EXPR: &str = "address:new-proposer"; - let new_proposer_address = AddressValue::from(NEW_PROPOSER_ADDRESS_EXPR).to_address(); + let new_proposer_address_expr = TestAddress::new("new-proposer"); - state.world.set_state_step( - SetStateStep::new().put_account(NEW_PROPOSER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + state.world.account(new_proposer_address_expr).nonce(1); - state.expect_user_role(&new_proposer_address, UserRole::None); + state.expect_user_role(new_proposer_address_expr, multisig_proxy::UserRole::None); - let action_id = state.propose_add_proposer(new_proposer_address.clone()); + let action_id = state.propose_add_proposer(new_proposer_address_expr); state.sign(action_id); state.perform(action_id); - state.expect_user_role(&new_proposer_address, UserRole::Proposer); - state.world.sc_query( - ScQueryStep::new() - .call(state.multisig_contract.get_all_proposers()) - .expect_value(MultiValueVec::
::from(vec![ - state.proposer_address.clone(), - new_proposer_address.clone(), - ])), + state.expect_user_role( + new_proposer_address_expr, + multisig_proxy::UserRole::Proposer, ); + + let expected_value = MultiValueVec::from(vec![PROPOSER_ADDRESS, new_proposer_address_expr]); + state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .get_all_proposers() + .returns(ExpectValue(expected_value)) + .run(); } #[test] @@ -324,18 +309,21 @@ fn test_remove_proposer() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract(); - state.expect_user_role(&state.proposer_address.clone(), UserRole::Proposer); + state.expect_user_role(PROPOSER_ADDRESS, multisig_proxy::UserRole::Proposer); - let action_id = state.propose_remove_user(state.proposer_address.clone()); + let action_id = state.propose_remove_user(PROPOSER_ADDRESS); state.sign(action_id); state.perform(action_id); - state.expect_user_role(&state.proposer_address.clone(), UserRole::None); - state.world.sc_query( - ScQueryStep::new() - .call(state.multisig_contract.get_all_proposers()) - .expect_value(MultiValueVec::
::new()), - ); + state.expect_user_role(PROPOSER_ADDRESS, multisig_proxy::UserRole::None); + state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .get_all_proposers() + .returns(ExpectValue(MultiValueVec::
::new())) + .run(); } #[test] @@ -343,7 +331,7 @@ fn test_try_remove_all_board_members() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract(); - let action_id = state.propose_remove_user(state.board_member_address.clone()); + let action_id = state.propose_remove_user(BOARD_MEMBER_ADDRESS); state.sign(action_id); state.perform_and_expect_err(action_id, "quorum cannot exceed board size") } @@ -360,45 +348,55 @@ fn test_change_quorum() { state.perform_and_expect_err(action_id, "quorum cannot exceed board size"); // try discard before unsigning - state.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(state.multisig_contract.discard_action(action_id)) - .expect(TxExpect::user_error( - "str:cannot discard action with valid signatures", - )), - ); + state + .world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .discard_action(action_id) + .with_result(ExpectError( + 4, + "cannot discard action with valid signatures", + )) + .run(); // unsign and discard action - state.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(state.multisig_contract.unsign(action_id)), - ); + state + .world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .unsign(action_id) + .run(); - state.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(state.multisig_contract.discard_action(action_id)), - ); + state + .world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .discard_action(action_id) + .run(); // try sign discarded action - state.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(state.multisig_contract.sign(action_id)) - .expect(TxExpect::user_error("str:action does not exist")), - ); + state + .world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(action_id) + .with_result(ExpectError(4, "action does not exist")) + .run(); // add another board member - const NEW_BOARD_MEMBER_ADDRESS_EXPR: &str = "address:new-board-member"; - let new_board_member_address = AddressValue::from(NEW_BOARD_MEMBER_ADDRESS_EXPR).to_address(); + let new_board_member_address_expr = TestAddress::new("new-board-member"); - state.world.set_state_step( - SetStateStep::new().put_account(NEW_BOARD_MEMBER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + state.world.account(new_board_member_address_expr).nonce(1); - let action_id = state.propose_add_board_member(new_board_member_address); + let action_id = state.propose_add_board_member(new_board_member_address_expr); state.sign(action_id); state.perform(action_id); @@ -413,57 +411,51 @@ fn test_transfer_execute_to_user() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract(); - const NEW_USER_ADDRESS_EXPR: &str = "address:new-user"; - state.world.set_state_step( - SetStateStep::new().put_account(NEW_USER_ADDRESS_EXPR, Account::new().nonce(1)), - ); + let new_user_address_expr = TestAddress::new("new-user"); + state.world.account(new_user_address_expr).nonce(1); - const AMOUNT: &str = "100"; + let amount: u64 = 100; - state.world.sc_call( - ScCallStep::new() - .from(PROPOSER_ADDRESS_EXPR) - .egld_value(AMOUNT) - .call(state.multisig_contract.deposit()), - ); + state + .world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .deposit() + .egld(amount) + .run(); - state.world.check_state_step( - CheckStateStep::new() - .put_account(MULTISIG_ADDRESS_EXPR, CheckAccount::new().balance(AMOUNT)), - ); + state.world.check_account(MULTISIG_ADDRESS).balance(amount); // failed attempt - let new_user_address = AddressValue::from(NEW_USER_ADDRESS_EXPR).to_address(); - - state.world.sc_call( - ScCallStep::new() - .from(PROPOSER_ADDRESS_EXPR) - .call(state.multisig_contract.propose_transfer_execute( - new_user_address.clone(), - 0u64, - FunctionCall::empty(), - )) - .expect(TxExpect::user_error("str:proposed action has no effect")), - ); + state + .world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_transfer_execute(new_user_address_expr, 0u64, FunctionCall::empty()) + .with_result(ExpectError(4, "proposed action has no effect")) + .run(); // propose - let action_id = - state - .world - .sc_call_get_result(ScCallStep::new().from(PROPOSER_ADDRESS_EXPR).call( - state.multisig_contract.propose_transfer_execute( - new_user_address, - AMOUNT.parse::().unwrap(), - FunctionCall::empty(), - ), - )); + let action_id = state + .world + .tx() + .from(PROPOSER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_transfer_execute(new_user_address_expr, amount, FunctionCall::empty()) + .returns(ReturnsResult) + .run(); state.sign(action_id); state.perform(action_id); - state.world.check_state_step( - CheckStateStep::new() - .put_account(NEW_USER_ADDRESS_EXPR, CheckAccount::new().balance(AMOUNT)), - ); + state + .world + .check_account(new_user_address_expr) + .balance(amount); } #[test] @@ -471,17 +463,25 @@ fn test_transfer_execute_sc_all() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract().deploy_adder_contract(); - let adder_call = state.adder_contract.add(5u64); + let adder_call = state + .world + .tx() + .typed(adder_proxy::AdderProxy) + .add(5u64) + .into_function_call(); - let action_id = state.propose_transfer_execute(state.adder_address.clone(), 0u64, adder_call); + let action_id = state.propose_transfer_execute(ADDER_ADDRESS, 0u64, adder_call); state.sign(action_id); state.perform(action_id); - state.world.sc_query( - ScQueryStep::new() - .call(state.adder_contract.sum()) - .expect_value(SingleValue::from(BigUint::from(10u64))), - ); + state + .world + .query() + .to(ADDER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .sum() + .with_result(ExpectValue(BigUint::from(10u64))) + .run(); } #[test] @@ -489,17 +489,25 @@ fn test_async_call_to_sc() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract().deploy_adder_contract(); - let adder_call = state.adder_contract.add(5u64); + let adder_call = state + .world + .tx() + .typed(adder_proxy::AdderProxy) + .add(5u64) + .into_function_call(); - let action_id = state.propose_async_call(state.adder_address.clone(), 0u64, adder_call); + let action_id = state.propose_async_call(ADDER_ADDRESS, 0u64, adder_call); state.sign(action_id); state.perform(action_id); - state.world.sc_query( - ScQueryStep::new() - .call(state.adder_contract.sum()) - .expect_value(SingleValue::from(BigUint::from(10u64))), - ); + state + .world + .query() + .to(ADDER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .sum() + .returns(ExpectValue(10u64)) + .run(); } #[test] @@ -507,59 +515,63 @@ fn test_deploy_and_upgrade_from_source() { let mut state = MultisigTestState::new(); state.deploy_multisig_contract().deploy_adder_contract(); - const NEW_ADDER_ADDRESS_EXPR: &str = "sc:new-adder"; - state.world.set_state_step(SetStateStep::new().new_address( - MULTISIG_ADDRESS_EXPR, - 0, - NEW_ADDER_ADDRESS_EXPR, - )); + let new_adder_address_expr = TestSCAddress::new("new-adder"); - let new_adder_address = AddressValue::from(NEW_ADDER_ADDRESS_EXPR).to_address(); + state + .world + .new_address(MULTISIG_ADDRESS, 0, new_adder_address_expr); let action_id = state.propose_sc_deploy_from_source( 0u64, - state.adder_address.clone(), + ADDER_ADDRESS, CodeMetadata::all(), MultiValueVec::from([top_encode_to_vec_u8_or_panic(&5u64)]), ); state.sign(action_id); - state.world.sc_call( - ScCallStep::new() - .from(BOARD_MEMBER_ADDRESS_EXPR) - .call(state.multisig_contract.perform_action_endpoint(action_id)) - .expect_value(OptionalValue::Some(new_adder_address.clone())), - ); - - let adder_call = state.adder_contract.add(5u64); + state + .world + .tx() + .from(BOARD_MEMBER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(action_id) + .returns(ExpectValue(OptionalValue::Some( + new_adder_address_expr.to_address(), + ))) + .run(); + + let adder_call = state + .world + .tx() + .to(ADDER_ADDRESS) + .typed(adder_proxy::AdderProxy) + .add(5u64) + .into_function_call(); - let action_id = state.propose_transfer_execute(new_adder_address, 0u64, adder_call); + let action_id = state.propose_transfer_execute(new_adder_address_expr, 0u64, adder_call); state.sign(action_id); state.perform(action_id); - let mut new_adder_contract = AdderContract::new(NEW_ADDER_ADDRESS_EXPR); - - state.world.sc_query( - ScQueryStep::new() - .call(new_adder_contract.sum()) - .expect_value(SingleValue::from(BigUint::from(10u64))), - ); - - const FACTORIAL_ADDRESS_EXPR: &str = "sc:factorial"; - const FACTORIAL_PATH_EXPR: &str = "mxsc:test-contracts/factorial.mxsc.json"; + state + .world + .query() + .to(new_adder_address_expr) + .typed(adder_proxy::AdderProxy) + .sum() + .returns(ExpectValue(BigUint::from(10u64))) + .run(); - let factorial_code = state.world.code_expression(FACTORIAL_PATH_EXPR); - let factorial_address = AddressValue::from(FACTORIAL_ADDRESS_EXPR).to_address(); + let factorial_address: TestSCAddress = TestSCAddress::new("factorial"); + let factorial_path: MxscPath = MxscPath::new("test-contracts/factorial.mxsc.json"); state .world - .register_contract(FACTORIAL_PATH_EXPR, factorial::ContractBuilder); - state.world.set_state_step(SetStateStep::new().put_account( - FACTORIAL_ADDRESS_EXPR, - Account::new().nonce(1).code(factorial_code.clone()), - )); + .register_contract(factorial_path, factorial::ContractBuilder); + + state.world.account(factorial_address).code(factorial_path); let action_id = state.propose_sc_upgrade_from_source( - state.adder_address.clone(), + ADDER_ADDRESS, 0u64, factorial_address, CodeMetadata::all(), @@ -568,8 +580,8 @@ fn test_deploy_and_upgrade_from_source() { state.sign(action_id); state.perform(action_id); - state.world.check_state_step( - CheckStateStep::new() - .put_account(ADDER_ADDRESS_EXPR, CheckAccount::new().code(factorial_code)), - ); + state + .world + .check_account(ADDER_ADDRESS) + .code(factorial_path); } diff --git a/contracts/examples/multisig/tests/multisig_whitebox_test.rs b/contracts/examples/multisig/tests/multisig_whitebox_test.rs index 227c012bc7..456fc9f96f 100644 --- a/contracts/examples/multisig/tests/multisig_whitebox_test.rs +++ b/contracts/examples/multisig/tests/multisig_whitebox_test.rs @@ -1,5 +1,6 @@ #![allow(unused)] +use multiversx_sc_scenario::imports::*; use std::borrow::Borrow; use adder::Adder; @@ -8,26 +9,6 @@ use multisig::{ multisig_perform::MultisigPerformModule, multisig_propose::MultisigProposeModule, user_role::UserRole, Multisig, }; -use multiversx_sc::{ - api::ManagedTypeApi, - codec::multi_types::OptionalValue, - storage::mappers::SingleValue, - types::{ - Address, BigUint, BoxedBytes, CodeMetadata, FunctionCall, ManagedAddress, ManagedBuffer, - ManagedVec, - }, -}; -use multiversx_sc_scenario::{ - managed_address, managed_biguint, - multiversx_chain_vm::types::VMAddress, - rust_biguint, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, ScQueryStep, - SetStateStep, TxExpect, TypedScQuery, - }, - testing_framework::TxResult, - DebugApi, ScenarioWorld, WhiteboxContract, -}; const OWNER_ADDRESS_EXPR: &str = "address:owner"; const PROPOSER_ADDRESS_EXPR: &str = "address:proposer"; diff --git a/contracts/examples/multisig/wasm-multisig-full/Cargo.lock b/contracts/examples/multisig/wasm-multisig-full/Cargo.lock index cf567f898e..657d9df054 100644 --- a/contracts/examples/multisig/wasm-multisig-full/Cargo.lock +++ b/contracts/examples/multisig/wasm-multisig-full/Cargo.lock @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/multisig/wasm-multisig-full/Cargo.toml b/contracts/examples/multisig/wasm-multisig-full/Cargo.toml index a36835c83f..a2d98375aa 100644 --- a/contracts/examples/multisig/wasm-multisig-full/Cargo.toml +++ b/contracts/examples/multisig/wasm-multisig-full/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/multisig/wasm-multisig-full/src/lib.rs b/contracts/examples/multisig/wasm-multisig-full/src/lib.rs index b3f9a29bee..254c27444a 100644 --- a/contracts/examples/multisig/wasm-multisig-full/src/lib.rs +++ b/contracts/examples/multisig/wasm-multisig-full/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 29 +// Upgrade: 1 +// Endpoints: 28 // Async Callback: 1 // Total number of exported functions: 31 diff --git a/contracts/examples/multisig/wasm-multisig-view/Cargo.lock b/contracts/examples/multisig/wasm-multisig-view/Cargo.lock index 2ae00e3366..8ad4962469 100644 --- a/contracts/examples/multisig/wasm-multisig-view/Cargo.lock +++ b/contracts/examples/multisig/wasm-multisig-view/Cargo.lock @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/multisig/wasm-multisig-view/Cargo.toml b/contracts/examples/multisig/wasm-multisig-view/Cargo.toml index 02ed495935..2c6a48b470 100644 --- a/contracts/examples/multisig/wasm-multisig-view/Cargo.toml +++ b/contracts/examples/multisig/wasm-multisig-view/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/multisig/wasm/Cargo.lock b/contracts/examples/multisig/wasm/Cargo.lock index dc1fc12b7e..4ca5fcc903 100755 --- a/contracts/examples/multisig/wasm/Cargo.lock +++ b/contracts/examples/multisig/wasm/Cargo.lock @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/multisig/wasm/Cargo.toml b/contracts/examples/multisig/wasm/Cargo.toml index 79597e9a70..f2202ffdb1 100644 --- a/contracts/examples/multisig/wasm/Cargo.toml +++ b/contracts/examples/multisig/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/multisig/wasm/src/lib.rs b/contracts/examples/multisig/wasm/src/lib.rs index 0bb7178ce4..ab19ce2ad3 100644 --- a/contracts/examples/multisig/wasm/src/lib.rs +++ b/contracts/examples/multisig/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 21 +// Upgrade: 1 +// Endpoints: 20 // Async Callback: 1 // Total number of exported functions: 23 diff --git a/contracts/examples/nft-minter/Cargo.toml b/contracts/examples/nft-minter/Cargo.toml index eeaec71e85..eb2ec96156 100644 --- a/contracts/examples/nft-minter/Cargo.toml +++ b/contracts/examples/nft-minter/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/nft-minter/meta/Cargo.toml b/contracts/examples/nft-minter/meta/Cargo.toml index d483bb65f4..cee7821359 100644 --- a/contracts/examples/nft-minter/meta/Cargo.toml +++ b/contracts/examples/nft-minter/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/nft-minter/src/lib.rs b/contracts/examples/nft-minter/src/lib.rs index 5f0a8b3f01..4148f368c2 100644 --- a/contracts/examples/nft-minter/src/lib.rs +++ b/contracts/examples/nft-minter/src/lib.rs @@ -2,6 +2,7 @@ use multiversx_sc::{derive_imports::*, imports::*}; +pub mod nft_marketplace_proxy; mod nft_module; #[derive(TypeAbi, TopEncode, TopDecode)] @@ -72,28 +73,10 @@ pub trait NftMinter: nft_module::NftModule { token_nonce: u64, ) { let caller = self.blockchain().get_caller(); - self.marketplace_proxy(marketplace_address) + self.tx() + .to(&marketplace_address) + .typed(nft_marketplace_proxy::NftMarketplaceProxy) .claim_tokens(token_id, token_nonce, caller) - .async_call() - .call_and_exit() - } - - #[proxy] - fn marketplace_proxy( - &self, - sc_address: ManagedAddress, - ) -> nft_marketplace_proxy::Proxy; -} - -mod nft_marketplace_proxy { - #[multiversx_sc::proxy] - pub trait NftMarketplace { - #[endpoint(claimTokens)] - fn claim_tokens( - &self, - token_id: TokenIdentifier, - token_nonce: u64, - claim_destination: ManagedAddress, - ); + .async_call_and_exit(); } } diff --git a/contracts/examples/nft-minter/src/nft_marketplace_proxy.rs b/contracts/examples/nft-minter/src/nft_marketplace_proxy.rs new file mode 100644 index 0000000000..7c6028d1fd --- /dev/null +++ b/contracts/examples/nft-minter/src/nft_marketplace_proxy.rs @@ -0,0 +1,55 @@ +use multiversx_sc::proxy_imports::*; + +pub struct NftMarketplaceProxy; + +impl TxProxyTrait for NftMarketplaceProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = NftMarketplaceProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + NftMarketplaceProxyMethods { wrapped_tx: tx } + } +} + +pub struct NftMarketplaceProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl NftMarketplaceProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn claim_tokens< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token_id: Arg0, + token_nonce: Arg1, + claim_destination: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claimTokens") + .argument(&token_id) + .argument(&token_nonce) + .argument(&claim_destination) + .original_result() + } +} diff --git a/contracts/examples/nft-minter/src/nft_module.rs b/contracts/examples/nft-minter/src/nft_module.rs index 2b9b73523c..6b324fefee 100644 --- a/contracts/examples/nft-minter/src/nft_module.rs +++ b/contracts/examples/nft-minter/src/nft_module.rs @@ -88,21 +88,14 @@ pub trait NftModule { self.price_tag(nft_nonce).clear(); let nft_token_id = self.nft_token_id().get(); - let caller = self.blockchain().get_caller(); - self.send().direct_esdt( - &caller, - &nft_token_id, - nft_nonce, - &BigUint::from(NFT_AMOUNT), - ); + + self.tx() + .to(ToCaller) + .single_esdt(&nft_token_id, nft_nonce, &BigUint::from(NFT_AMOUNT)) + .transfer(); let owner = self.blockchain().get_owner_address(); - self.send().direct( - &owner, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); + self.tx().to(owner).payment(payment).transfer(); } // views @@ -135,11 +128,9 @@ pub trait NftModule { self.nft_token_id().set(&token_id.unwrap_esdt()); }, ManagedAsyncCallResult::Err(_) => { - let caller = self.blockchain().get_owner_address(); let returned = self.call_value().egld_or_single_esdt(); if returned.token_identifier.is_egld() && returned.amount > 0 { - self.send() - .direct(&caller, &returned.token_identifier, 0, &returned.amount); + self.tx().to(ToCaller).egld(returned.amount).transfer(); } }, } diff --git a/contracts/examples/nft-minter/wasm/Cargo.lock b/contracts/examples/nft-minter/wasm/Cargo.lock index 1da583baee..aac2ace620 100644 --- a/contracts/examples/nft-minter/wasm/Cargo.lock +++ b/contracts/examples/nft-minter/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/nft-minter/wasm/Cargo.toml b/contracts/examples/nft-minter/wasm/Cargo.toml index fd32ff41c5..241a4215e2 100644 --- a/contracts/examples/nft-minter/wasm/Cargo.toml +++ b/contracts/examples/nft-minter/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/nft-storage-prepay/Cargo.toml b/contracts/examples/nft-storage-prepay/Cargo.toml index 142d549a25..136281df96 100644 --- a/contracts/examples/nft-storage-prepay/Cargo.toml +++ b/contracts/examples/nft-storage-prepay/Cargo.toml @@ -10,9 +10,9 @@ path = "src/nft_storage_prepay.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/nft-storage-prepay/meta/Cargo.toml b/contracts/examples/nft-storage-prepay/meta/Cargo.toml index 7a03515dbe..c1ddf2adc1 100644 --- a/contracts/examples/nft-storage-prepay/meta/Cargo.toml +++ b/contracts/examples/nft-storage-prepay/meta/Cargo.toml @@ -11,6 +11,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/nft-storage-prepay/src/nft_storage_prepay.rs b/contracts/examples/nft-storage-prepay/src/nft_storage_prepay.rs index f21dfcb61b..7e1c6115d3 100644 --- a/contracts/examples/nft-storage-prepay/src/nft_storage_prepay.rs +++ b/contracts/examples/nft-storage-prepay/src/nft_storage_prepay.rs @@ -42,7 +42,7 @@ pub trait NftStoragePrepay { self.total_reserved().clear(); let owner = self.blockchain().get_caller(); - self.send().direct_egld(&owner, &total_reserved); + self.tx().to(&owner).egld(&total_reserved).transfer(); } // endpoints @@ -71,7 +71,7 @@ pub trait NftStoragePrepay { user_deposit -= &amount; self.deposit(&caller).set(&user_deposit); - self.send().direct_egld(&caller, &amount); + self.tx().to(&caller).egld(&amount).transfer(); } // views diff --git a/contracts/examples/nft-storage-prepay/wasm/Cargo.lock b/contracts/examples/nft-storage-prepay/wasm/Cargo.lock index a8cf928989..f877f05711 100755 --- a/contracts/examples/nft-storage-prepay/wasm/Cargo.lock +++ b/contracts/examples/nft-storage-prepay/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/nft-storage-prepay/wasm/Cargo.toml b/contracts/examples/nft-storage-prepay/wasm/Cargo.toml index 34df978063..99a5c3c1a6 100644 --- a/contracts/examples/nft-storage-prepay/wasm/Cargo.toml +++ b/contracts/examples/nft-storage-prepay/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/nft-subscription/Cargo.toml b/contracts/examples/nft-subscription/Cargo.toml index 748d63535f..be7a39917e 100644 --- a/contracts/examples/nft-subscription/Cargo.toml +++ b/contracts/examples/nft-subscription/Cargo.toml @@ -9,13 +9,13 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/nft-subscription/meta/Cargo.toml b/contracts/examples/nft-subscription/meta/Cargo.toml index 73b766639d..d122df52df 100644 --- a/contracts/examples/nft-subscription/meta/Cargo.toml +++ b/contracts/examples/nft-subscription/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/nft-subscription/src/lib.rs b/contracts/examples/nft-subscription/src/lib.rs index d291eaf212..7b0b63096e 100644 --- a/contracts/examples/nft-subscription/src/lib.rs +++ b/contracts/examples/nft-subscription/src/lib.rs @@ -35,12 +35,15 @@ pub trait NftSubscription: ManagedBuffer::from(b"common"), &ManagedVec::new(), ); - self.send().direct_esdt( - &self.blockchain().get_caller(), - self.token_id().get_token_id_ref(), - nonce, - &BigUint::from(1u8), - ); + + self.tx() + .to(ToCaller) + .single_esdt( + self.token_id().get_token_id_ref(), + nonce, + &BigUint::from(1u8), + ) + .transfer(); } #[payable("*")] @@ -48,12 +51,10 @@ pub trait NftSubscription: fn update_attributes(&self, attributes: ManagedBuffer) { let (id, nonce, _) = self.call_value().single_esdt().into_tuple(); self.update_subscription_attributes::(&id, nonce, attributes); - self.send().direct_esdt( - &self.blockchain().get_caller(), - &id, - nonce, - &BigUint::from(1u8), - ); + self.tx() + .to(ToCaller) + .single_esdt(&id, nonce, &BigUint::from(1u8)) + .transfer(); } #[payable("*")] @@ -61,12 +62,10 @@ pub trait NftSubscription: fn renew(&self, duration: u64) { let (id, nonce, _) = self.call_value().single_esdt().into_tuple(); self.renew_subscription::(&id, nonce, duration); - self.send().direct_esdt( - &self.blockchain().get_caller(), - &id, - nonce, - &BigUint::from(1u8), - ); + self.tx() + .to(ToCaller) + .single_esdt(&id, nonce, &BigUint::from(1u8)) + .transfer(); } #[payable("*")] @@ -74,12 +73,11 @@ pub trait NftSubscription: fn cancel(&self) { let (id, nonce, _) = self.call_value().single_esdt().into_tuple(); self.cancel_subscription::(&id, nonce); - self.send().direct_esdt( - &self.blockchain().get_caller(), - &id, - nonce, - &BigUint::from(1u8), - ); + + self.tx() + .to(ToCaller) + .single_esdt(&id, nonce, &BigUint::from(1u8)) + .transfer(); } #[storage_mapper("tokenId")] diff --git a/contracts/examples/nft-subscription/wasm/Cargo.lock b/contracts/examples/nft-subscription/wasm/Cargo.lock index 726b01fa88..e8b62546de 100644 --- a/contracts/examples/nft-subscription/wasm/Cargo.lock +++ b/contracts/examples/nft-subscription/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,14 +80,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/nft-subscription/wasm/Cargo.toml b/contracts/examples/nft-subscription/wasm/Cargo.toml index e47d13f71e..532cc400e4 100644 --- a/contracts/examples/nft-subscription/wasm/Cargo.toml +++ b/contracts/examples/nft-subscription/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/order-book/factory/Cargo.toml b/contracts/examples/order-book/factory/Cargo.toml index cc3db5aa7b..9a4978df8a 100644 --- a/contracts/examples/order-book/factory/Cargo.toml +++ b/contracts/examples/order-book/factory/Cargo.toml @@ -8,10 +8,10 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/examples/order-book/factory/meta/Cargo.toml b/contracts/examples/order-book/factory/meta/Cargo.toml index b127392c11..3518de30d2 100644 --- a/contracts/examples/order-book/factory/meta/Cargo.toml +++ b/contracts/examples/order-book/factory/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/examples/order-book/factory/src/lib.rs b/contracts/examples/order-book/factory/src/lib.rs index cac1192361..fb83863ae3 100644 --- a/contracts/examples/order-book/factory/src/lib.rs +++ b/contracts/examples/order-book/factory/src/lib.rs @@ -23,13 +23,19 @@ pub trait Factory { arguments.push_arg(&token_id_pair.first_token_id); arguments.push_arg(&token_id_pair.second_token_id); - let (pair_address, _) = self.send_raw().deploy_from_source_contract( - self.blockchain().get_gas_left(), - &BigUint::zero(), - &self.pair_template_address().get(), - CodeMetadata::DEFAULT, - &arguments, - ); + let gas_left = self.blockchain().get_gas_left(); + let source = self.pair_template_address().get(); + + let pair_address = self + .tx() + .gas(gas_left) + .raw_deploy() + .arguments_raw(arguments) + .from_source(source) + .code_metadata(CodeMetadata::DEFAULT) + .returns(ReturnsNewManagedAddress) + .sync_call(); + self.pairs().insert(token_id_pair, pair_address.clone()); pair_address diff --git a/contracts/examples/order-book/factory/wasm/Cargo.lock b/contracts/examples/order-book/factory/wasm/Cargo.lock index 3f252320b3..7d38576ac4 100644 --- a/contracts/examples/order-book/factory/wasm/Cargo.lock +++ b/contracts/examples/order-book/factory/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/order-book/factory/wasm/Cargo.toml b/contracts/examples/order-book/factory/wasm/Cargo.toml index d4af86c8a5..1ee94f9d8e 100644 --- a/contracts/examples/order-book/factory/wasm/Cargo.toml +++ b/contracts/examples/order-book/factory/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/order-book/pair/Cargo.toml b/contracts/examples/order-book/pair/Cargo.toml index 7f2bbabdd4..a93917179a 100644 --- a/contracts/examples/order-book/pair/Cargo.toml +++ b/contracts/examples/order-book/pair/Cargo.toml @@ -8,9 +8,9 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/examples/order-book/pair/meta/Cargo.toml b/contracts/examples/order-book/pair/meta/Cargo.toml index ceee771510..6f4ba52f4e 100644 --- a/contracts/examples/order-book/pair/meta/Cargo.toml +++ b/contracts/examples/order-book/pair/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/examples/order-book/pair/src/orders.rs b/contracts/examples/order-book/pair/src/orders.rs index 6dd9bdc0bf..1ec11afee4 100644 --- a/contracts/examples/order-book/pair/src/orders.rs +++ b/contracts/examples/order-book/pair/src/orders.rs @@ -353,12 +353,10 @@ pub trait OrdersModule: fn execute_transfers(&self, transfers: ManagedVec>) { for transfer in &transfers { if transfer.payment.amount > 0 { - self.send().direct_esdt( - &transfer.to, - &transfer.payment.token_id, - 0, - &transfer.payment.amount, - ) + self.tx() + .to(&transfer.to) + .single_esdt(&transfer.payment.token_id, 0, &transfer.payment.amount) + .transfer(); } } } diff --git a/contracts/examples/order-book/pair/wasm/Cargo.lock b/contracts/examples/order-book/pair/wasm/Cargo.lock index 21e89dac31..38fbac9a8f 100644 --- a/contracts/examples/order-book/pair/wasm/Cargo.lock +++ b/contracts/examples/order-book/pair/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/order-book/pair/wasm/Cargo.toml b/contracts/examples/order-book/pair/wasm/Cargo.toml index 30f74dee55..dd343a9dfc 100644 --- a/contracts/examples/order-book/pair/wasm/Cargo.toml +++ b/contracts/examples/order-book/pair/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/ping-pong-egld/Cargo.toml b/contracts/examples/ping-pong-egld/Cargo.toml index 1d0209ccf2..fc86298452 100644 --- a/contracts/examples/ping-pong-egld/Cargo.toml +++ b/contracts/examples/ping-pong-egld/Cargo.toml @@ -9,10 +9,10 @@ publish = false path = "src/ping_pong.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/ping-pong-egld/meta/Cargo.toml b/contracts/examples/ping-pong-egld/meta/Cargo.toml index 146b367bd5..a8bc467391 100644 --- a/contracts/examples/ping-pong-egld/meta/Cargo.toml +++ b/contracts/examples/ping-pong-egld/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/ping-pong-egld/src/ping_pong.rs b/contracts/examples/ping-pong-egld/src/ping_pong.rs index d2d84546de..683c2a2ed5 100644 --- a/contracts/examples/ping-pong-egld/src/ping_pong.rs +++ b/contracts/examples/ping-pong-egld/src/ping_pong.rs @@ -107,8 +107,8 @@ pub trait PingPong { UserStatus::Registered => { self.user_status(user_id).set(UserStatus::Withdrawn); if let Some(user_address) = self.user_mapper().get_user_address(user_id) { - self.send() - .direct_egld(&user_address, &self.ping_amount().get()); + let amount = self.ping_amount().get(); + self.tx().to(user_address).egld(amount).transfer(); Result::Ok(()) } else { Result::Err("unknown user") diff --git a/contracts/examples/ping-pong-egld/wasm/Cargo.lock b/contracts/examples/ping-pong-egld/wasm/Cargo.lock index f7ce1b2dd3..a2d0636590 100755 --- a/contracts/examples/ping-pong-egld/wasm/Cargo.lock +++ b/contracts/examples/ping-pong-egld/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/ping-pong-egld/wasm/Cargo.toml b/contracts/examples/ping-pong-egld/wasm/Cargo.toml index 0d14eef644..8438778f1b 100644 --- a/contracts/examples/ping-pong-egld/wasm/Cargo.toml +++ b/contracts/examples/ping-pong-egld/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/ping-pong-egld/wasm/src/lib.rs b/contracts/examples/ping-pong-egld/wasm/src/lib.rs index ec95d16c7e..b3fb0e62cb 100644 --- a/contracts/examples/ping-pong-egld/wasm/src/lib.rs +++ b/contracts/examples/ping-pong-egld/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 11 +// Upgrade: 1 +// Endpoints: 10 // Async Callback (empty): 1 // Total number of exported functions: 13 diff --git a/contracts/examples/proxy-pause/Cargo.toml b/contracts/examples/proxy-pause/Cargo.toml index 50f560d16f..382dfd9f27 100644 --- a/contracts/examples/proxy-pause/Cargo.toml +++ b/contracts/examples/proxy-pause/Cargo.toml @@ -9,11 +9,11 @@ publish = false path = "src/proxy_pause.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies.check-pause] diff --git a/contracts/examples/proxy-pause/meta/Cargo.toml b/contracts/examples/proxy-pause/meta/Cargo.toml index 9c9c54c2bd..4be34a41ba 100644 --- a/contracts/examples/proxy-pause/meta/Cargo.toml +++ b/contracts/examples/proxy-pause/meta/Cargo.toml @@ -11,6 +11,6 @@ authors = [ "you",] path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/proxy-pause/src/pause_sc_proxy.rs b/contracts/examples/proxy-pause/src/pause_sc_proxy.rs new file mode 100644 index 0000000000..6f5fc834b9 --- /dev/null +++ b/contracts/examples/proxy-pause/src/pause_sc_proxy.rs @@ -0,0 +1,53 @@ +use multiversx_sc::proxy_imports::*; + +pub struct PausableProxy; + +impl TxProxyTrait for PausableProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = PausableProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + PausableProxyMethods { wrapped_tx: tx } + } +} + +pub struct PausableProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl PausableProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn pause( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("pause") + .original_result() + } + + pub fn unpause( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unpause") + .original_result() + } +} diff --git a/contracts/examples/proxy-pause/src/proxy_pause.rs b/contracts/examples/proxy-pause/src/proxy_pause.rs index 685a870c7e..aa5f07e7d6 100644 --- a/contracts/examples/proxy-pause/src/proxy_pause.rs +++ b/contracts/examples/proxy-pause/src/proxy_pause.rs @@ -1,17 +1,7 @@ #![no_std] use multiversx_sc::imports::*; - -mod pause_proxy { - #[multiversx_sc::proxy] - pub trait Pausable { - #[endpoint] - fn pause(&self); - - #[endpoint] - fn unpause(&self); - } -} +pub mod pause_sc_proxy; #[multiversx_sc::contract] pub trait PauseProxy { @@ -46,23 +36,26 @@ pub trait PauseProxy { fn for_each_contract(&self, f: F) where - F: Fn(pause_proxy::Proxy), + F: Fn(pause_sc_proxy::PausableProxyMethods, (), &ManagedAddress, ()>), { for contract_address in self.contracts().iter() { - f(self.pausable_contract().contract(contract_address)); + f(self + .tx() + .to(&contract_address) + .typed(pause_sc_proxy::PausableProxy)); } } #[endpoint] fn pause(&self) { self.require_owner(); - self.for_each_contract(|mut contract| contract.pause().execute_on_dest_context()); + self.for_each_contract(|contract| contract.pause().sync_call()); } #[endpoint] fn unpause(&self) { self.require_owner(); - self.for_each_contract(|mut contract| contract.unpause().execute_on_dest_context()); + self.for_each_contract(|contract| contract.unpause().sync_call()); } fn require_owner(&self) { @@ -79,7 +72,4 @@ pub trait PauseProxy { #[view] #[storage_mapper("contracts")] fn contracts(&self) -> SetMapper; - - #[proxy] - fn pausable_contract(&self) -> pause_proxy::Proxy; } diff --git a/contracts/examples/proxy-pause/wasm/Cargo.lock b/contracts/examples/proxy-pause/wasm/Cargo.lock index a1a40ea776..5edbcad6e8 100644 --- a/contracts/examples/proxy-pause/wasm/Cargo.lock +++ b/contracts/examples/proxy-pause/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/proxy-pause/wasm/Cargo.toml b/contracts/examples/proxy-pause/wasm/Cargo.toml index cc1649d595..939f828e70 100644 --- a/contracts/examples/proxy-pause/wasm/Cargo.toml +++ b/contracts/examples/proxy-pause/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/rewards-distribution/Cargo.toml b/contracts/examples/rewards-distribution/Cargo.toml index e2cced12b5..d518ea5586 100644 --- a/contracts/examples/rewards-distribution/Cargo.toml +++ b/contracts/examples/rewards-distribution/Cargo.toml @@ -9,13 +9,13 @@ publish = false path = "src/rewards_distribution.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/rewards-distribution/meta/Cargo.toml b/contracts/examples/rewards-distribution/meta/Cargo.toml index 0225532a08..bfddb43d6f 100644 --- a/contracts/examples/rewards-distribution/meta/Cargo.toml +++ b/contracts/examples/rewards-distribution/meta/Cargo.toml @@ -11,6 +11,6 @@ authors = ["Claudiu-Marcel Bruda "] path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/rewards-distribution/sc-config.toml b/contracts/examples/rewards-distribution/sc-config.toml new file mode 100644 index 0000000000..9661ab3dc5 --- /dev/null +++ b/contracts/examples/rewards-distribution/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "src/rewards_distribution_proxy.rs" diff --git a/contracts/examples/rewards-distribution/src/rewards_distribution.rs b/contracts/examples/rewards-distribution/src/rewards_distribution.rs index cef14e0fef..7300fcaf88 100644 --- a/contracts/examples/rewards-distribution/src/rewards_distribution.rs +++ b/contracts/examples/rewards-distribution/src/rewards_distribution.rs @@ -5,19 +5,23 @@ use multiversx_sc_modules::ongoing_operation::{ CONTINUE_OP, DEFAULT_MIN_GAS_TO_SAVE_PROGRESS, STOP_OP, }; +pub mod rewards_distribution_proxy; +pub mod seed_nft_minter_proxy; type Epoch = u64; pub const EPOCHS_IN_WEEK: Epoch = 7; pub const MAX_PERCENTAGE: u64 = 100_000; // 100% pub const DIVISION_SAFETY_CONSTANT: u64 = 1_000_000_000_000; -#[derive(ManagedVecItem, NestedEncode, NestedDecode, TypeAbi)] +#[type_abi] +#[derive(ManagedVecItem, NestedEncode, NestedDecode)] pub struct Bracket { pub index_percent: u64, pub bracket_reward_percent: u64, } -#[derive(ManagedVecItem, NestedEncode, NestedDecode, TypeAbi)] +#[type_abi] +#[derive(ManagedVecItem, NestedEncode, NestedDecode)] pub struct ComputedBracket { pub end_index: u64, pub nft_reward_percent: BigUint, @@ -39,10 +43,14 @@ pub trait RewardsDistribution: fn init(&self, seed_nft_minter_address: ManagedAddress, brackets: ManagedVec) { self.seed_nft_minter_address().set(&seed_nft_minter_address); - let nft_token_id: TokenIdentifier = self - .seed_nft_minter_proxy(seed_nft_minter_address) - .get_nft_token_id() - .execute_on_dest_context(); + let nft_token_id = self + .tx() + .to(&seed_nft_minter_address) + .typed(seed_nft_minter_proxy::SeedNftMinterProxy) + .nft_token_id() + .returns(ReturnsResult) + .sync_call(); + self.nft_token_id().set(nft_token_id); self.validate_brackets(&brackets); @@ -175,10 +183,15 @@ pub trait RewardsDistribution: }); let seed_nft_minter_address = self.seed_nft_minter_address().get(); - let ticket_count: u64 = self - .seed_nft_minter_proxy(seed_nft_minter_address) - .get_nft_count() - .execute_on_dest_context(); + + let ticket_count = self + .tx() + .to(&seed_nft_minter_address) + .typed(seed_nft_minter_proxy::SeedNftMinterProxy) + .nft_count() + .returns(ReturnsResult) + .sync_call(); + let brackets = self.brackets().get(); let computed_brackets = self.compute_brackets(brackets, ticket_count); @@ -266,10 +279,9 @@ pub trait RewardsDistribution: } } - self.send() - .direct_non_zero_egld(&caller, &total_egld_reward); - self.send().direct_multi(&caller, &rewards); - self.send().direct_multi(&caller, &nfts); + self.tx().to(&caller).egld(total_egld_reward).transfer(); + self.tx().to(&caller).payment(rewards).transfer(); + self.tx().to(&caller).payment(nfts).transfer(); } fn claim_reward_token( @@ -417,9 +429,6 @@ pub trait RewardsDistribution: #[storage_mapper("raffleProgress")] fn raffle_progress(&self) -> SingleValueMapper>>; - - #[proxy] - fn seed_nft_minter_proxy(&self, address: ManagedAddress) -> seed_nft_minter::Proxy; } fn ticket_to_storage(position: u64, ticket_id: u64) -> u64 { @@ -437,14 +446,3 @@ fn ticket_from_storage(position: u64, ticket_id: u64) -> u64 { ticket_id } } - -mod seed_nft_minter { - #[multiversx_sc::proxy] - pub trait SeedNftMinter { - #[endpoint(getNftCount)] - fn get_nft_count(&self) -> u64; - - #[endpoint(getNftTokenId)] - fn get_nft_token_id(&self) -> TokenIdentifier; - } -} diff --git a/contracts/examples/rewards-distribution/src/rewards_distribution_proxy.rs b/contracts/examples/rewards-distribution/src/rewards_distribution_proxy.rs new file mode 100644 index 0000000000..83ec15b473 --- /dev/null +++ b/contracts/examples/rewards-distribution/src/rewards_distribution_proxy.rs @@ -0,0 +1,234 @@ +// 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 RewardsDistributionProxy; + +impl TxProxyTrait for RewardsDistributionProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = RewardsDistributionProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + RewardsDistributionProxyMethods { wrapped_tx: tx } + } +} + +pub struct RewardsDistributionProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl RewardsDistributionProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + seed_nft_minter_address: Arg0, + brackets: Arg1, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&seed_nft_minter_address) + .argument(&brackets) + .original_result() + } +} + +#[rustfmt::skip] +impl RewardsDistributionProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn deposit_royalties( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("depositRoyalties") + .original_result() + } + + pub fn raffle( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("raffle") + .original_result() + } + + pub fn claim_rewards< + Arg0: ProxyArg, + Arg1: ProxyArg, + Arg2: ProxyArg, u64>>>, + >( + self, + raffle_id_start: Arg0, + raffle_id_end: Arg1, + reward_tokens: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claimRewards") + .argument(&raffle_id_start) + .argument(&raffle_id_end) + .argument(&reward_tokens) + .original_result() + } + + pub fn compute_claimable_amount< + Arg0: ProxyArg, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + >( + self, + raffle_id: Arg0, + reward_token_id: Arg1, + reward_token_nonce: Arg2, + nft_nonce: Arg3, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("computeClaimableAmount") + .argument(&raffle_id) + .argument(&reward_token_id) + .argument(&reward_token_nonce) + .argument(&nft_nonce) + .original_result() + } + + pub fn raffle_id( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getRaffleId") + .original_result() + } + + pub fn completed_raffle_id_count( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getCompletedRaffleIdCount") + .original_result() + } + + pub fn royalties< + Arg0: ProxyArg, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + raffle_id: Arg0, + reward_token_id: Arg1, + reward_token_nonce: Arg2, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getRoyalties") + .argument(&raffle_id) + .argument(&reward_token_id) + .argument(&reward_token_nonce) + .original_result() + } + + pub fn nft_reward_percent< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + raffle_id: Arg0, + nft_nonce: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getNftRewardPercent") + .argument(&raffle_id) + .argument(&nft_nonce) + .original_result() + } + + pub fn was_claimed< + Arg0: ProxyArg, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + >( + self, + raffle_id: Arg0, + reward_token_id: Arg1, + reward_token_nonce: Arg2, + nft_nonce: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getWasClaimed") + .argument(&raffle_id) + .argument(&reward_token_id) + .argument(&reward_token_nonce) + .argument(&nft_nonce) + .original_result() + } + + pub fn seed_nft_minter_address( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getSeedNftMinterAddress") + .original_result() + } + + pub fn brackets( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getBrackets") + .original_result() + } + + pub fn last_raffle_epoch( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getLastRaffleEpoch") + .original_result() + } + + pub fn nft_token_id( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getNftTokenId") + .original_result() + } +} + +#[type_abi] +#[derive(ManagedVecItem, NestedEncode, NestedDecode)] +pub struct Bracket { + pub index_percent: u64, + pub bracket_reward_percent: u64, +} diff --git a/contracts/examples/rewards-distribution/src/seed_nft_minter_proxy.rs b/contracts/examples/rewards-distribution/src/seed_nft_minter_proxy.rs new file mode 100644 index 0000000000..84349daae7 --- /dev/null +++ b/contracts/examples/rewards-distribution/src/seed_nft_minter_proxy.rs @@ -0,0 +1,195 @@ +// 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 SeedNftMinterProxy; + +impl TxProxyTrait for SeedNftMinterProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = SeedNftMinterProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + SeedNftMinterProxyMethods { wrapped_tx: tx } + } +} + +pub struct SeedNftMinterProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl SeedNftMinterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + Arg1: ProxyArg>>, + >( + self, + marketplaces: Arg0, + distribution: Arg1, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&marketplaces) + .argument(&distribution) + .original_result() + } +} + +#[rustfmt::skip] +impl SeedNftMinterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn create_nft< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>>, + Arg5: ProxyArg>, + >( + self, + name: Arg0, + royalties: Arg1, + uri: Arg2, + selling_price: Arg3, + opt_token_used_as_payment: Arg4, + opt_token_used_as_payment_nonce: Arg5, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("createNft") + .argument(&name) + .argument(&royalties) + .argument(&uri) + .argument(&selling_price) + .argument(&opt_token_used_as_payment) + .argument(&opt_token_used_as_payment_nonce) + .original_result() + } + + pub fn claim_and_distribute< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + token_id: Arg0, + token_nonce: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("claimAndDistribute") + .argument(&token_id) + .argument(&token_nonce) + .original_result() + } + + pub fn marketplaces( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getMarketplaces") + .original_result() + } + + pub fn nft_count( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getNftCount") + .original_result() + } + + pub fn distribution_rules( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("getDistributionRules") + .original_result() + } + + pub fn issue_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("issueToken") + .argument(&token_display_name) + .argument(&token_ticker) + .original_result() + } + + pub fn buy_nft< + Arg0: ProxyArg, + >( + self, + nft_nonce: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("buyNft") + .argument(&nft_nonce) + .original_result() + } + + pub fn get_nft_price< + Arg0: ProxyArg, + >( + self, + nft_nonce: Arg0, + ) -> TxProxyCall, u64, BigUint>>> { + self.wrapped_tx + .raw_call("getNftPrice") + .argument(&nft_nonce) + .original_result() + } + + pub fn nft_token_id( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getNftTokenId") + .original_result() + } +} + +#[type_abi] +#[derive(ManagedVecItem, NestedEncode, NestedDecode)] +pub struct Distribution +where + Api: ManagedTypeApi, +{ + pub address: ManagedAddress, + pub percentage: u64, + pub endpoint: ManagedBuffer, + pub gas_limit: u64, +} diff --git a/contracts/examples/rewards-distribution/tests/mock_seed_nft_minter_proxy.rs b/contracts/examples/rewards-distribution/tests/mock_seed_nft_minter_proxy.rs new file mode 100644 index 0000000000..379b8e0d05 --- /dev/null +++ b/contracts/examples/rewards-distribution/tests/mock_seed_nft_minter_proxy.rs @@ -0,0 +1,70 @@ +use multiversx_sc::proxy_imports::*; + +pub struct MockSeedNftMinterProxy; + +impl TxProxyTrait for MockSeedNftMinterProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = MockSeedNftMinterProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + MockSeedNftMinterProxyMethods { wrapped_tx: tx } + } +} + +pub struct MockSeedNftMinterProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl MockSeedNftMinterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + >( + self, + nft_token_id: Arg0, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&nft_token_id) + .original_result() + } +} + +#[rustfmt::skip] +impl MockSeedNftMinterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn set_nft_count< + Arg0: ProxyArg, + >( + self, + nft_count: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setNftCount") + .argument(&nft_count) + .original_result() + } +} diff --git a/contracts/examples/rewards-distribution/tests/rewards_distribution_blackbox_test.rs b/contracts/examples/rewards-distribution/tests/rewards_distribution_blackbox_test.rs deleted file mode 100644 index 2902c7832c..0000000000 --- a/contracts/examples/rewards-distribution/tests/rewards_distribution_blackbox_test.rs +++ /dev/null @@ -1,373 +0,0 @@ -mod mock_seed_nft_minter; -mod utils; - -use std::iter::zip; - -use multiversx_sc::{ - codec::multi_types::MultiValue2, - storage::mappers::SingleValue, - types::{ - Address, BigUint, EgldOrEsdtTokenIdentifier, ManagedVec, MultiValueEncoded, - OperationCompletionStatus, TokenIdentifier, - }, -}; -use multiversx_sc_scenario::{ - api::StaticApi, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, ScQueryStep, - SetStateStep, TxESDT, TypedResponse, - }, - ContractInfo, DebugApi, ScenarioWorld, WhiteboxContract, -}; - -use crate::mock_seed_nft_minter::ProxyTrait as _; -use rewards_distribution::{ - Bracket, ContractObj, ProxyTrait as _, RewardsDistribution, DIVISION_SAFETY_CONSTANT, -}; - -const NFT_TOKEN_ID: &[u8] = b"NFT-123456"; -const NFT_TOKEN_ID_EXPR: &str = "str:NFT-123456"; - -const ALICE_ADDRESS_EXPR: &str = "address:alice"; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; -const REWARDS_DISTRIBUTION_ADDRESS_EXPR: &str = "sc:rewards-distribution"; -const REWARDS_DISTRIBUTION_PATH_EXPR: &str = "mxsc:output/rewards-distribution.mxsc.json"; -const SEED_NFT_MINTER_ADDRESS_EXPR: &str = "sc:seed-nft-minter"; -const SEED_NFT_MINTER_PATH_EXPR: &str = "mxsc:../seed-nft-minter/output/seed-nft-minter.mxsc.json"; - -type RewardsDistributionContract = ContractInfo>; -type SeedNFTMinterContract = ContractInfo>; - -fn world() -> ScenarioWorld { - let mut blockchain = ScenarioWorld::new(); - blockchain.set_current_dir_from_workspace("contracts/examples/rewards-distribution"); - - blockchain.register_contract( - REWARDS_DISTRIBUTION_PATH_EXPR, - rewards_distribution::ContractBuilder, - ); - blockchain.register_contract( - SEED_NFT_MINTER_PATH_EXPR, - mock_seed_nft_minter::ContractBuilder, - ); - blockchain -} - -struct RewardsDistributionTestState { - world: ScenarioWorld, - seed_nft_minter_address: Address, - seed_nft_minter_contract: SeedNFTMinterContract, - rewards_distribution_contract: RewardsDistributionContract, - rewards_distribution_whitebox: WhiteboxContract>, -} - -impl RewardsDistributionTestState { - fn new() -> Self { - let mut world = world(); - - world.set_state_step( - SetStateStep::new().put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)), - ); - - let seed_nft_minter_address = AddressValue::from(SEED_NFT_MINTER_ADDRESS_EXPR).to_address(); - - let seed_nft_minter_contract = SeedNFTMinterContract::new(SEED_NFT_MINTER_ADDRESS_EXPR); - let rewards_distribution_contract = - RewardsDistributionContract::new(REWARDS_DISTRIBUTION_ADDRESS_EXPR); - let rewards_distribution_whitebox = WhiteboxContract::new( - REWARDS_DISTRIBUTION_ADDRESS_EXPR, - rewards_distribution::contract_obj, - ); - - Self { - world, - seed_nft_minter_address, - seed_nft_minter_contract, - rewards_distribution_contract, - rewards_distribution_whitebox, - } - } - - fn deploy_seed_nft_minter_contract(&mut self) -> &mut Self { - let seed_nft_miinter_code = self.world.code_expression(SEED_NFT_MINTER_PATH_EXPR); - - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(seed_nft_miinter_code) - .call( - self.seed_nft_minter_contract - .init(TokenIdentifier::from_esdt_bytes(NFT_TOKEN_ID)), - ), - ); - - self.world.sc_call( - ScCallStep::new() - .from(OWNER_ADDRESS_EXPR) - .call(self.seed_nft_minter_contract.set_nft_count(10_000u64)), - ); - - self - } - - fn deploy_rewards_distribution_contract(&mut self) -> &mut Self { - let rewards_distribution_code = self.world.code_expression(REWARDS_DISTRIBUTION_PATH_EXPR); - - let brackets_vec = &[ - (10, 2_000), - (90, 6_000), - (400, 7_000), - (2_500, 10_000), - (25_000, 35_000), - (72_000, 40_000), - ]; - let mut brackets = ManagedVec::::new(); - for (index_percent, bracket_reward_percent) in brackets_vec.iter().cloned() { - brackets.push(Bracket { - index_percent, - bracket_reward_percent, - }); - } - self.world.sc_deploy( - ScDeployStep::new() - .from(OWNER_ADDRESS_EXPR) - .code(rewards_distribution_code) - .call( - self.rewards_distribution_contract - .init(self.seed_nft_minter_address.clone(), brackets), - ), - ); - - self - } -} - -#[test] -fn test_compute_brackets() { - let mut state = RewardsDistributionTestState::new(); - - let rewards_distribution_code = state.world.code_expression(REWARDS_DISTRIBUTION_PATH_EXPR); - - state.world.set_state_step( - SetStateStep::new().put_account( - REWARDS_DISTRIBUTION_ADDRESS_EXPR, - Account::new() - .nonce(1) - .owner(OWNER_ADDRESS_EXPR) - .code(rewards_distribution_code) - .balance("0"), - ), - ); - - state.world.whitebox_call( - &state.rewards_distribution_whitebox, - ScCallStep::new().from(OWNER_ADDRESS_EXPR), - |sc| { - let brackets = utils::to_brackets(&[ - (10, 2_000), - (90, 6_000), - (400, 7_000), - (2_500, 10_000), - (25_000, 35_000), - (72_000, 40_000), - ]); - - let computed_brackets = sc.compute_brackets(brackets, 10_000); - - let expected_values = vec![ - (1, 2_000 * DIVISION_SAFETY_CONSTANT), - (10, 6_000 * DIVISION_SAFETY_CONSTANT / (10 - 1)), - (50, 7_000 * DIVISION_SAFETY_CONSTANT / (50 - 10)), - (300, 10_000 * DIVISION_SAFETY_CONSTANT / (300 - 50)), - (2_800, 35_000 * DIVISION_SAFETY_CONSTANT / (2_800 - 300)), - (10_000, 40_000 * DIVISION_SAFETY_CONSTANT / (10_000 - 2_800)), - ]; - - assert_eq!(computed_brackets.len(), expected_values.len()); - for (computed, expected) in zip(computed_brackets.iter(), expected_values) { - let (expected_end_index, expected_reward_percent) = expected; - assert_eq!(computed.end_index, expected_end_index); - assert_eq!(computed.nft_reward_percent, expected_reward_percent); - } - }, - ); -} - -#[test] -fn test_raffle_and_claim() { - let mut state = RewardsDistributionTestState::new(); - - let nft_nonces: [u64; 6] = [1, 2, 3, 4, 5, 6]; - let nft_payments: Vec = nft_nonces - .iter() - .map(|nonce| TxESDT { - esdt_token_identifier: NFT_TOKEN_ID.into(), - nonce: (*nonce).into(), - esdt_value: 1u64.into(), - }) - .collect(); - - let mut alice_account = Account::new().nonce(1).balance("2_070_000_000"); - for nonce in nft_nonces.iter() { - alice_account = - alice_account.esdt_nft_balance(NFT_TOKEN_ID_EXPR, *nonce, "1", Option::<&[u8]>::None); - } - - state.world.set_state_step( - SetStateStep::new() - .put_account(ALICE_ADDRESS_EXPR, alice_account) - .new_address(OWNER_ADDRESS_EXPR, 1, SEED_NFT_MINTER_ADDRESS_EXPR) - .new_address(OWNER_ADDRESS_EXPR, 3, REWARDS_DISTRIBUTION_ADDRESS_EXPR), - ); - - state - .deploy_seed_nft_minter_contract() - .deploy_rewards_distribution_contract(); - - // deposit royalties - state.world.sc_call( - ScCallStep::new() - .from(ALICE_ADDRESS_EXPR) - .egld_value("2_070_000_000") - .call(state.rewards_distribution_contract.deposit_royalties()), - ); - - // run the raffle - state.world.sc_call( - ScCallStep::new() - .from(ALICE_ADDRESS_EXPR) - .tx_hash(&[0u8; 32]) // blockchain rng is deterministic, so we can use a fixed hash - .call(state.rewards_distribution_contract.raffle()) - .expect_value(OperationCompletionStatus::Completed), - ); - - let mut rewards: Vec> = Vec::new(); - // post-raffle reward amount frequency checksstate - for nonce in 1u64..=10_000u64 { - state.world.sc_call_use_result( - ScCallStep::new().from(ALICE_ADDRESS_EXPR).call( - state - .rewards_distribution_contract - .compute_claimable_amount( - 0u64, - &EgldOrEsdtTokenIdentifier::egld(), - 0u64, - nonce, - ), - ), - |r: TypedResponse>| rewards.push(r.result.unwrap()), - ); - } - - assert_eq!(rewards.len() as u64, 10_000u64); - - // check that the reward amounts match in frequency - let expected_reward_amounts = [ - (41_400_000, 1), - (13_799_999, 9), - (3_622_500, 40), - (828_000, 250), - (289_800, 2500), - (114_999, 7200), - ]; - - let total_expected_count: u64 = expected_reward_amounts.iter().map(|(_, count)| count).sum(); - assert_eq!(total_expected_count, 10_000u64); - - for (amount, expected_count) in expected_reward_amounts { - let expected_amount = amount as u64; - assert_eq!( - rewards - .iter() - .filter(|value| *value == &expected_amount) - .count(), - expected_count as usize - ); - } - - let expected_rewards = [114_999, 114_999, 114_999, 828_000, 114_999, 114_999]; - - for (nonce, expected_reward) in std::iter::zip(nft_nonces, expected_rewards) { - state.world.sc_call_use_result( - ScCallStep::new().from(ALICE_ADDRESS_EXPR).call( - state - .rewards_distribution_contract - .compute_claimable_amount( - 0u64, - &EgldOrEsdtTokenIdentifier::egld(), - 0u64, - nonce, - ), - ), - |r: TypedResponse>| { - assert_eq!(r.result.unwrap().to_u64().unwrap(), expected_reward); - }, - ); - } - - // claim rewards - let mut reward_tokens: MultiValueEncoded< - StaticApi, - MultiValue2, u64>, - > = MultiValueEncoded::new(); - reward_tokens.push((EgldOrEsdtTokenIdentifier::egld(), 0).into()); - state.world.sc_call( - ScCallStep::new() - .from(ALICE_ADDRESS_EXPR) - .multi_esdt_transfer(nft_payments.clone()) - .call( - state - .rewards_distribution_contract - .claim_rewards(0u64, 0u64, reward_tokens), - ), - ); - - // check that the rewards were claimed - for nonce in nft_nonces.iter() { - state.world.sc_query( - ScQueryStep::new() - .call(state.rewards_distribution_contract.was_claimed( - 0u64, - &EgldOrEsdtTokenIdentifier::egld(), - 0u64, - nonce, - )) - .expect_value(SingleValue::from(true)), - ); - } - - // confirm the received amount matches the sum of the queried rewards - let alice_balance_after_claim: u64 = expected_rewards.iter().sum(); - let balance_expr = alice_balance_after_claim.to_string(); - - state - .world - .check_state_step(CheckStateStep::new().put_account( - ALICE_ADDRESS_EXPR, - CheckAccount::new().balance(balance_expr.as_str()), - )); - - // a second claim with the same nfts should succeed, but return no more rewards - let mut reward_tokens: MultiValueEncoded< - StaticApi, - MultiValue2, u64>, - > = MultiValueEncoded::new(); - reward_tokens.push((EgldOrEsdtTokenIdentifier::egld(), 0).into()); - state.world.sc_call( - ScCallStep::new() - .from(ALICE_ADDRESS_EXPR) - .multi_esdt_transfer(nft_payments) - .call( - state - .rewards_distribution_contract - .claim_rewards(0u64, 0u64, reward_tokens), - ), - ); - - state - .world - .check_state_step(CheckStateStep::new().put_account( - ALICE_ADDRESS_EXPR, - CheckAccount::new().balance(balance_expr.as_str()), - )); -} diff --git a/contracts/examples/rewards-distribution/tests/rewards_distribution_integration_test.rs b/contracts/examples/rewards-distribution/tests/rewards_distribution_integration_test.rs new file mode 100644 index 0000000000..be3a4cb788 --- /dev/null +++ b/contracts/examples/rewards-distribution/tests/rewards_distribution_integration_test.rs @@ -0,0 +1,312 @@ +mod mock_seed_nft_minter; +mod mock_seed_nft_minter_proxy; +mod utils; + +use multiversx_sc_scenario::imports::*; +use std::iter::zip; + +use rewards_distribution::{ + rewards_distribution_proxy, ContractObj, RewardsDistribution, DIVISION_SAFETY_CONSTANT, +}; + +const ALICE_ADDRESS: TestAddress = TestAddress::new("alice"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const REWARDS_DISTRIBUTION_ADDRESS: TestSCAddress = TestSCAddress::new("rewards-distribution"); +const REWARDS_DISTRIBUTION_PATH: MxscPath = MxscPath::new("output/rewards-distribution.mxsc.json"); +const SEED_NFT_MINTER_ADDRESS: TestSCAddress = TestSCAddress::new("seed-nft-minter"); +const SEED_NFT_MINTER_PATH: MxscPath = + MxscPath::new("../seed-nft-minter/output/seed-nft-minter.mxsc.json"); +const NFT_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("NFT-123456"); + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract( + REWARDS_DISTRIBUTION_PATH, + rewards_distribution::ContractBuilder, + ); + blockchain.register_contract(SEED_NFT_MINTER_PATH, mock_seed_nft_minter::ContractBuilder); + blockchain +} + +struct RewardsDistributionTestState { + world: ScenarioWorld, + rewards_distribution_whitebox: WhiteboxContract>, +} + +impl RewardsDistributionTestState { + fn new() -> Self { + let mut world = world(); + + world.account(OWNER_ADDRESS).nonce(1); + + let rewards_distribution_whitebox = WhiteboxContract::new( + REWARDS_DISTRIBUTION_ADDRESS, + rewards_distribution::contract_obj, + ); + + Self { + world, + rewards_distribution_whitebox, + } + } + + fn deploy_seed_nft_minter_contract(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(mock_seed_nft_minter_proxy::MockSeedNftMinterProxy) + .init(NFT_TOKEN_ID) + .code(SEED_NFT_MINTER_PATH) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(SEED_NFT_MINTER_ADDRESS) + .typed(mock_seed_nft_minter_proxy::MockSeedNftMinterProxy) + .set_nft_count(10_000u64) + .run(); + + self + } + + fn deploy_rewards_distribution_contract(&mut self) -> &mut Self { + let brackets_vec = &[ + (10, 2_000), + (90, 6_000), + (400, 7_000), + (2_500, 10_000), + (25_000, 35_000), + (72_000, 40_000), + ]; + let mut brackets = ManagedVec::new(); + for (index_percent, bracket_reward_percent) in brackets_vec.iter().cloned() { + brackets.push(rewards_distribution_proxy::Bracket { + index_percent, + bracket_reward_percent, + }); + } + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .init(SEED_NFT_MINTER_ADDRESS.to_address(), brackets) + .code(REWARDS_DISTRIBUTION_PATH) + .run(); + + self + } +} + +#[test] +fn test_compute_brackets() { + let mut state = RewardsDistributionTestState::new(); + + state + .world + .account(REWARDS_DISTRIBUTION_ADDRESS) + .nonce(1) + .owner(OWNER_ADDRESS) + .code(REWARDS_DISTRIBUTION_PATH); + + state.world.whitebox_call( + &state.rewards_distribution_whitebox, + ScCallStep::new().from(OWNER_ADDRESS), + |sc| { + let brackets = utils::to_brackets(&[ + (10, 2_000), + (90, 6_000), + (400, 7_000), + (2_500, 10_000), + (25_000, 35_000), + (72_000, 40_000), + ]); + + let computed_brackets = sc.compute_brackets(brackets, 10_000); + + let expected_values = vec![ + (1, 2_000 * DIVISION_SAFETY_CONSTANT), + (10, 6_000 * DIVISION_SAFETY_CONSTANT / (10 - 1)), + (50, 7_000 * DIVISION_SAFETY_CONSTANT / (50 - 10)), + (300, 10_000 * DIVISION_SAFETY_CONSTANT / (300 - 50)), + (2_800, 35_000 * DIVISION_SAFETY_CONSTANT / (2_800 - 300)), + (10_000, 40_000 * DIVISION_SAFETY_CONSTANT / (10_000 - 2_800)), + ]; + + assert_eq!(computed_brackets.len(), expected_values.len()); + for (computed, expected) in zip(computed_brackets.iter(), expected_values) { + let (expected_end_index, expected_reward_percent) = expected; + assert_eq!(computed.end_index, expected_end_index); + assert_eq!(computed.nft_reward_percent, expected_reward_percent); + } + }, + ); +} + +#[test] +fn test_raffle_and_claim() { + let mut state = RewardsDistributionTestState::new(); + + let nft_nonces: [u64; 6] = [1, 2, 3, 4, 5, 6]; + let mut nft_payments = ManagedVec::new(); + for nonce in nft_nonces.into_iter() { + let payment = EsdtTokenPayment::new(NFT_TOKEN_ID.into(), nonce, 1u64.into()); + nft_payments.push(payment); + } + + { + let mut account_setter = state + .world + .account(ALICE_ADDRESS) + .nonce(1) + .balance(2_070_000_000); + for nft_nonce in nft_nonces { + account_setter = account_setter.esdt_nft_balance(NFT_TOKEN_ID, nft_nonce, 1, ()); + } + } + + state.world.set_state_step( + SetStateStep::new() + .new_address(OWNER_ADDRESS, 1, SEED_NFT_MINTER_ADDRESS) + .new_address(OWNER_ADDRESS, 3, REWARDS_DISTRIBUTION_ADDRESS), + ); + + state + .deploy_seed_nft_minter_contract() + .deploy_rewards_distribution_contract(); + + // deposit royalties + state + .world + .tx() + .from(ALICE_ADDRESS) + .to(REWARDS_DISTRIBUTION_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .deposit_royalties() + .egld(2_070_000_000) + .run(); + + // run the raffle + state + .world + .tx() + .from(ALICE_ADDRESS) + .to(REWARDS_DISTRIBUTION_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .raffle() + .tx_hash([0u8; 32]) // blockchain rng is deterministic, so we can use a fixed hash + .run(); + + let mut rewards: Vec> = Vec::new(); + // post-raffle reward amount frequency checksstate + for nonce in 1u64..=10_000u64 { + let reward = state + .world + .tx() + .from(ALICE_ADDRESS) + .to(REWARDS_DISTRIBUTION_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .compute_claimable_amount(0u64, &EgldOrEsdtTokenIdentifier::egld(), 0u64, nonce) + .returns(ReturnsResult) + .run(); + rewards.push(reward); + } + + assert_eq!(rewards.len() as u64, 10_000u64); + + // check that the reward amounts match in frequency + let expected_reward_amounts = [ + (41_400_000, 1), + (13_799_999, 9), + (3_622_500, 40), + (828_000, 250), + (289_800, 2500), + (114_999, 7200), + ]; + + let total_expected_count: u64 = expected_reward_amounts.iter().map(|(_, count)| count).sum(); + assert_eq!(total_expected_count, 10_000u64); + + for (amount, expected_count) in expected_reward_amounts { + let expected_amount = amount as u64; + assert_eq!( + rewards + .iter() + .filter(|value| *value == &expected_amount) + .count(), + expected_count as usize + ); + } + + let expected_rewards = [114_999, 114_999, 114_999, 828_000, 114_999, 114_999]; + + for (nonce, expected_reward) in std::iter::zip(nft_nonces, expected_rewards) { + state + .world + .tx() + .from(ALICE_ADDRESS) + .to(REWARDS_DISTRIBUTION_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .compute_claimable_amount(0u64, &EgldOrEsdtTokenIdentifier::egld(), 0u64, nonce) + .returns(ExpectValue(expected_reward)) + .run(); + } + + // claim rewards + let mut reward_tokens: MultiValueEncoded< + StaticApi, + MultiValue2, u64>, + > = MultiValueEncoded::new(); + reward_tokens.push((EgldOrEsdtTokenIdentifier::egld(), 0).into()); + state + .world + .tx() + .from(ALICE_ADDRESS) + .to(REWARDS_DISTRIBUTION_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .claim_rewards(0u64, 0u64, reward_tokens) + .with_multi_token_transfer(nft_payments.clone()) + .run(); + + // check that the rewards were claimed + for nonce in nft_nonces.iter() { + state + .world + .query() + .to(REWARDS_DISTRIBUTION_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .was_claimed(0u64, &EgldOrEsdtTokenIdentifier::egld(), 0u64, nonce) + .returns(ExpectValue(true)) + .run(); + } + + // confirm the received amount matches the sum of the queried rewards + let alice_balance_after_claim: u64 = expected_rewards.iter().sum(); + + state + .world + .check_account(ALICE_ADDRESS) + .balance(alice_balance_after_claim); + + // a second claim with the same nfts should succeed, but return no more rewards + let mut reward_tokens: MultiValueEncoded< + StaticApi, + MultiValue2, u64>, + > = MultiValueEncoded::new(); + reward_tokens.push((EgldOrEsdtTokenIdentifier::egld(), 0).into()); + state + .world + .tx() + .from(ALICE_ADDRESS) + .to(REWARDS_DISTRIBUTION_ADDRESS) + .typed(rewards_distribution_proxy::RewardsDistributionProxy) + .claim_rewards(0u64, 0u64, reward_tokens) + .with_multi_token_transfer(nft_payments) + .run(); + + state + .world + .check_account(ALICE_ADDRESS) + .balance(alice_balance_after_claim); +} diff --git a/contracts/examples/rewards-distribution/wasm/Cargo.lock b/contracts/examples/rewards-distribution/wasm/Cargo.lock index 82e8b6241e..018b42f4dc 100644 --- a/contracts/examples/rewards-distribution/wasm/Cargo.lock +++ b/contracts/examples/rewards-distribution/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,14 +80,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/rewards-distribution/wasm/Cargo.toml b/contracts/examples/rewards-distribution/wasm/Cargo.toml index d524872e2f..a62cac8525 100644 --- a/contracts/examples/rewards-distribution/wasm/Cargo.toml +++ b/contracts/examples/rewards-distribution/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/seed-nft-minter/Cargo.toml b/contracts/examples/seed-nft-minter/Cargo.toml index dd732d1613..a57db6b6dc 100644 --- a/contracts/examples/seed-nft-minter/Cargo.toml +++ b/contracts/examples/seed-nft-minter/Cargo.toml @@ -9,13 +9,13 @@ publish = false path = "src/seed_nft_minter.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/seed-nft-minter/meta/Cargo.toml b/contracts/examples/seed-nft-minter/meta/Cargo.toml index 4ac054f405..af481426af 100644 --- a/contracts/examples/seed-nft-minter/meta/Cargo.toml +++ b/contracts/examples/seed-nft-minter/meta/Cargo.toml @@ -11,6 +11,6 @@ authors = ["Claudiu-Marcel Bruda "] path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/seed-nft-minter/sc-config.toml b/contracts/examples/seed-nft-minter/sc-config.toml new file mode 100644 index 0000000000..5597c10092 --- /dev/null +++ b/contracts/examples/seed-nft-minter/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "../rewards-distribution/src/seed_nft_minter_proxy.rs" diff --git a/contracts/examples/seed-nft-minter/src/distribution_module.rs b/contracts/examples/seed-nft-minter/src/distribution_module.rs index 9b3bb6d507..54f8bf2586 100644 --- a/contracts/examples/seed-nft-minter/src/distribution_module.rs +++ b/contracts/examples/seed-nft-minter/src/distribution_module.rs @@ -2,7 +2,8 @@ use multiversx_sc::{derive_imports::*, imports::*}; pub const MAX_DISTRIBUTION_PERCENTAGE: u64 = 100_000; // 100% -#[derive(ManagedVecItem, NestedEncode, NestedDecode, TypeAbi)] +#[type_abi] +#[derive(ManagedVecItem, NestedEncode, NestedDecode)] pub struct Distribution { pub address: ManagedAddress, pub percentage: u64, @@ -32,10 +33,11 @@ pub trait DistributionModule { if payment_amount == 0 { continue; } - self.send() - .contract_call::(distribution.address, distribution.endpoint) - .with_egld_or_single_esdt_transfer((token_id.clone(), token_nonce, payment_amount)) - .with_gas_limit(distribution.gas_limit) + self.tx() + .to(&distribution.address) + .raw_call(distribution.endpoint) + .egld_or_single_esdt(token_id, token_nonce, &payment_amount) + .gas(distribution.gas_limit) .transfer_execute(); } } diff --git a/contracts/examples/seed-nft-minter/src/nft_marketplace_proxy.rs b/contracts/examples/seed-nft-minter/src/nft_marketplace_proxy.rs new file mode 100644 index 0000000000..e41b477e03 --- /dev/null +++ b/contracts/examples/seed-nft-minter/src/nft_marketplace_proxy.rs @@ -0,0 +1,74 @@ +#![allow(clippy::all)] + +use multiversx_sc::proxy_imports::*; + +pub struct NftMarketplaceProxy; + +impl TxProxyTrait for NftMarketplaceProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = NftMarketplaceProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + NftMarketplaceProxyMethods { wrapped_tx: tx } + } +} + +pub struct NftMarketplaceProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl NftMarketplaceProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl NftMarketplaceProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn claim_tokens< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + claim_destination: Arg0, + token_id: Arg1, + token_nonce: Arg2, + ) -> TxProxyCall, ManagedVec>>> { + self.wrapped_tx + .raw_call("claimTokens") + .argument(&claim_destination) + .argument(&token_id) + .argument(&token_nonce) + .original_result() + } +} diff --git a/contracts/examples/seed-nft-minter/src/nft_module.rs b/contracts/examples/seed-nft-minter/src/nft_module.rs index 885ff36c90..a65a4175d7 100644 --- a/contracts/examples/seed-nft-minter/src/nft_module.rs +++ b/contracts/examples/seed-nft-minter/src/nft_module.rs @@ -65,13 +65,11 @@ pub trait NftModule: self.price_tag(nft_nonce).clear(); let nft_token_id = self.nft_token_id().get_token_id(); - let caller = self.blockchain().get_caller(); - self.send().direct_esdt( - &caller, - &nft_token_id, - nft_nonce, - &BigUint::from(NFT_AMOUNT), - ); + + self.tx() + .to(ToCaller) + .single_esdt(&nft_token_id, nft_nonce, &BigUint::from(NFT_AMOUNT)) + .transfer(); self.distribute_funds( &payment.token_identifier, diff --git a/contracts/examples/seed-nft-minter/src/seed_nft_minter.rs b/contracts/examples/seed-nft-minter/src/seed_nft_minter.rs index 42b064e5cd..1a6ac5ffe2 100644 --- a/contracts/examples/seed-nft-minter/src/seed_nft_minter.rs +++ b/contracts/examples/seed-nft-minter/src/seed_nft_minter.rs @@ -3,6 +3,7 @@ use multiversx_sc::{derive_imports::*, imports::*}; mod distribution_module; +pub mod nft_marketplace_proxy; mod nft_module; use distribution_module::Distribution; @@ -86,10 +87,13 @@ pub trait SeedNftMinter: let claim_destination = self.blockchain().get_sc_address(); let mut total_amount = BigUint::zero(); for address in self.marketplaces().iter() { - let results: MultiValue2> = self - .marketplace_proxy(address) + let results = self + .tx() + .to(&address) + .typed(nft_marketplace_proxy::NftMarketplaceProxy) .claim_tokens(&claim_destination, token_id, token_nonce) - .execute_on_dest_context(); + .returns(ReturnsResult) + .sync_call(); let (egld_amount, esdt_payments) = results.into_tuple(); let amount = if token_id.is_egld() { @@ -113,25 +117,4 @@ pub trait SeedNftMinter: #[view(getNftCount)] #[storage_mapper("nftCount")] fn nft_count(&self) -> SingleValueMapper; - - #[proxy] - fn marketplace_proxy( - &self, - sc_address: ManagedAddress, - ) -> nft_marketplace_proxy::Proxy; -} - -mod nft_marketplace_proxy { - use multiversx_sc::imports::*; - - #[multiversx_sc::proxy] - pub trait NftMarketplace { - #[endpoint(claimTokens)] - fn claim_tokens( - &self, - claim_destination: &ManagedAddress, - token_id: &EgldOrEsdtTokenIdentifier, - token_nonce: u64, - ) -> MultiValue2>; - } } diff --git a/contracts/examples/seed-nft-minter/wasm/Cargo.lock b/contracts/examples/seed-nft-minter/wasm/Cargo.lock index 7bd62a16fd..70729a49cd 100644 --- a/contracts/examples/seed-nft-minter/wasm/Cargo.lock +++ b/contracts/examples/seed-nft-minter/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,14 +80,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/seed-nft-minter/wasm/Cargo.toml b/contracts/examples/seed-nft-minter/wasm/Cargo.toml index 09d0d167e3..e6a61820c9 100644 --- a/contracts/examples/seed-nft-minter/wasm/Cargo.toml +++ b/contracts/examples/seed-nft-minter/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/examples/token-release/Cargo.toml b/contracts/examples/token-release/Cargo.toml index 53d5f29a71..7c7c810787 100644 --- a/contracts/examples/token-release/Cargo.toml +++ b/contracts/examples/token-release/Cargo.toml @@ -9,10 +9,10 @@ publish = false path = "src/token_release.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/examples/token-release/meta/Cargo.toml b/contracts/examples/token-release/meta/Cargo.toml index 92e78d42f9..68be5330b2 100644 --- a/contracts/examples/token-release/meta/Cargo.toml +++ b/contracts/examples/token-release/meta/Cargo.toml @@ -10,7 +10,7 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/examples/token-release/src/token_release.rs b/contracts/examples/token-release/src/token_release.rs index 29fb3890e0..b0acd8a0e7 100644 --- a/contracts/examples/token-release/src/token_release.rs +++ b/contracts/examples/token-release/src/token_release.rs @@ -312,8 +312,10 @@ pub trait TokenRelease { address: &ManagedAddress, amount: &BigUint, ) { - self.send() - .direct_esdt(address, token_identifier, 0, amount); + self.tx() + .to(address) + .single_esdt(token_identifier, 0, amount) + .transfer(); } fn mint_all_tokens(&self, token_identifier: &TokenIdentifier, amount: &BigUint) { diff --git a/contracts/examples/token-release/wasm/Cargo.lock b/contracts/examples/token-release/wasm/Cargo.lock index 6d39aac883..5ec1dea342 100644 --- a/contracts/examples/token-release/wasm/Cargo.lock +++ b/contracts/examples/token-release/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/examples/token-release/wasm/Cargo.toml b/contracts/examples/token-release/wasm/Cargo.toml index 356d0a7ce1..bce00fce24 100644 --- a/contracts/examples/token-release/wasm/Cargo.toml +++ b/contracts/examples/token-release/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/abi-tester/Cargo.toml b/contracts/feature-tests/abi-tester/Cargo.toml index 7c0e7e80b5..714c488750 100644 --- a/contracts/feature-tests/abi-tester/Cargo.toml +++ b/contracts/feature-tests/abi-tester/Cargo.toml @@ -9,14 +9,14 @@ publish = false path = "src/abi_tester.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/meta" diff --git a/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json b/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json index 2abfdd2a48..77d8423bfb 100644 --- a/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json +++ b/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json @@ -14,7 +14,7 @@ }, "framework": { "name": "multiversx-sc", - "version": "0.48.1" + "version": "0.49.0-alpha.4" } }, "docs": [ @@ -44,6 +44,22 @@ ], "outputs": [] }, + "upgradeConstructor": { + "docs": [ + "Upgrade constructor." + ], + "inputs": [ + { + "name": "_constructor_arg_1", + "type": "i32" + }, + { + "name": "_constructor_arg_2", + "type": "OnlyShowsUpInConstructor" + } + ], + "outputs": [] + }, "endpoints": [ { "docs": [ @@ -363,6 +379,16 @@ } ] }, + { + "name": "operation_completion_status", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "OperationCompletionStatus" + } + ] + }, { "name": "payable_egld", "mutability": "mutable", @@ -910,6 +936,23 @@ "type": "OnlyShowsUpAsNested10" } ] + }, + "OperationCompletionStatus": { + "type": "explicit-enum", + "variants": [ + { + "docs": [ + "indicates that operation was completed" + ], + "name": "completed" + }, + { + "docs": [ + "indicates that operation was interrupted prematurely, due to low gas" + ], + "name": "interrupted" + } + ] } } } diff --git a/contracts/feature-tests/abi-tester/abi_tester_expected_view.abi.json b/contracts/feature-tests/abi-tester/abi_tester_expected_view.abi.json index 5a22e77ae9..f678f60c87 100644 --- a/contracts/feature-tests/abi-tester/abi_tester_expected_view.abi.json +++ b/contracts/feature-tests/abi-tester/abi_tester_expected_view.abi.json @@ -14,7 +14,7 @@ }, "framework": { "name": "multiversx-sc", - "version": "0.48.1" + "version": "0.49.0-alpha.4" } }, "docs": [ @@ -587,6 +587,23 @@ "type": "OnlyShowsUpAsNested10" } ] + }, + "OperationCompletionStatus": { + "type": "explicit-enum", + "variants": [ + { + "docs": [ + "indicates that operation was completed" + ], + "name": "completed" + }, + { + "docs": [ + "indicates that operation was interrupted prematurely, due to low gas" + ], + "name": "interrupted" + } + ] } } } diff --git a/contracts/feature-tests/abi-tester/meta/Cargo.toml b/contracts/feature-tests/abi-tester/meta/Cargo.toml index 13ea670021..7edae725e5 100644 --- a/contracts/feature-tests/abi-tester/meta/Cargo.toml +++ b/contracts/feature-tests/abi-tester/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/abi-tester/sc-config.toml b/contracts/feature-tests/abi-tester/sc-config.toml index 5a61f68d47..df90daa529 100644 --- a/contracts/feature-tests/abi-tester/sc-config.toml +++ b/contracts/feature-tests/abi-tester/sc-config.toml @@ -11,4 +11,10 @@ name = "abi-tester-ev" external-view = true add-unlabelled = false add-labels = ["test-external-view"] -add-endpoints = ["payable_any_token", "label_a"] # labels can be bypassed, endpoints added directly +add-endpoints = [ + "payable_any_token", + "label_a", +] # labels can be bypassed, endpoints added directly + +[[proxy]] +path = "src/abi_proxy.rs" diff --git a/contracts/feature-tests/abi-tester/src/abi_proxy.rs b/contracts/feature-tests/abi-tester/src/abi_proxy.rs new file mode 100644 index 0000000000..f02412c39d --- /dev/null +++ b/contracts/feature-tests/abi-tester/src/abi_proxy.rs @@ -0,0 +1,551 @@ +// 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 AbiTesterProxy; + +impl TxProxyTrait for AbiTesterProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = AbiTesterProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + AbiTesterProxyMethods { wrapped_tx: tx } + } +} + +pub struct AbiTesterProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl AbiTesterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + /// Contract constructor. + pub fn init< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + _constructor_arg_1: Arg0, + _constructor_arg_2: Arg1, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&_constructor_arg_1) + .argument(&_constructor_arg_2) + .original_result() + } +} + +#[rustfmt::skip] +impl AbiTesterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Upgrade constructor. + pub fn upgrade< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + _constructor_arg_1: Arg0, + _constructor_arg_2: Arg1, + ) -> TxProxyUpgrade { + self.wrapped_tx + .raw_upgrade() + .argument(&_constructor_arg_1) + .argument(&_constructor_arg_2) + .original_result() + } +} + +#[rustfmt::skip] +impl AbiTesterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Example endpoint docs. + pub fn echo_abi_test_type< + Arg0: ProxyArg, + >( + self, + att: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("echo_abi_test_type") + .argument(&att) + .original_result() + } + + pub fn echo_enum< + Arg0: ProxyArg, + >( + self, + e: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("echo_enum") + .argument(&e) + .original_result() + } + + pub fn take_managed_type< + Arg0: ProxyArg>, + >( + self, + _arg: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("take_managed_type") + .argument(&_arg) + .original_result() + } + + pub fn multi_result_3( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("multi_result_3") + .original_result() + } + + pub fn multi_result_4( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("multi_result_4") + .original_result() + } + + pub fn var_args< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + _simple_arg: Arg0, + _var_args: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("var_args") + .argument(&_simple_arg) + .argument(&_var_args) + .original_result() + } + + pub fn multi_result_vec( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("multi_result_vec") + .original_result() + } + + pub fn optional_arg< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + _simple_arg: Arg0, + _opt_args: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("optional_arg") + .argument(&_simple_arg) + .argument(&_opt_args) + .original_result() + } + + pub fn optional_result( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("optional_result") + .original_result() + } + + pub fn address_vs_h256< + Arg0: ProxyArg
, + Arg1: ProxyArg, + >( + self, + address: Arg0, + h256: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("address_vs_h256") + .argument(&address) + .argument(&h256) + .original_result() + } + + pub fn managed_address_vs_byte_array< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + address: Arg0, + byte_array: Arg1, + ) -> TxProxyCall, ManagedByteArray>> { + self.wrapped_tx + .raw_call("managed_address_vs_byte_array") + .argument(&address) + .argument(&byte_array) + .original_result() + } + + pub fn esdt_local_role( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("esdt_local_role") + .original_result() + } + + pub fn esdt_token_payment( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("esdt_token_payment") + .original_result() + } + + pub fn esdt_token_data( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("esdt_token_data") + .original_result() + } + + pub fn sample_storage_mapper( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("sample_storage_mapper") + .original_result() + } + + pub fn item_for_vec( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("item_for_vec") + .original_result() + } + + pub fn item_for_array_vec( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("item_for_array_vec") + .original_result() + } + + pub fn item_for_managed_vec( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("item_for_managed_vec") + .original_result() + } + + pub fn item_for_array< + Arg0: ProxyArg<[OnlyShowsUpAsNestedInArray; 5]>, + >( + self, + _array: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("item_for_array") + .argument(&_array) + .original_result() + } + + pub fn item_for_box( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("item_for_box") + .original_result() + } + + pub fn item_for_boxed_slice( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("item_for_boxed_slice") + .original_result() + } + + pub fn item_for_ref< + Arg0: ProxyArg, + >( + self, + _ref: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("item_for_ref") + .argument(&_ref) + .original_result() + } + + pub fn item_for_slice< + Arg0: ProxyArg>, + >( + self, + _ref: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("item_for_slice") + .argument(&_ref) + .original_result() + } + + pub fn item_for_option( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("item_for_option") + .original_result() + } + + pub fn operation_completion_status( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("operation_completion_status") + .original_result() + } + + pub fn payable_egld( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("payable_egld") + .original_result() + } + + pub fn payable_some_token( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("payable_some_token") + .original_result() + } + + pub fn payable_any_token( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("payable_any_token") + .original_result() + } + + pub fn external_view( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("external_view") + .original_result() + } + + pub fn label_a( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("label_a") + .original_result() + } + + pub fn label_b( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("label_b") + .original_result() + } +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpInConstructor { + pub something: (), +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct AbiTestType { + pub nested: OnlyShowsUpAsNested01, + pub next: Option>, + pub tuple_madness: (OnlyShowsUpAsNested02, Option>), +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested01 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested02 { + pub something: [u8; 0], +} + +#[rustfmt::skip] +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub enum AbiEnum { + Nothing, + Something(i32), + SomethingMore(u8, OnlyShowsUpAsNested08), + SomeStruct { + a: u16, + b: OnlyShowsUpAsNested09, + }, +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested08 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested09 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct AbiManagedType +where + Api: ManagedTypeApi, +{ + pub big_uint: BigUint, + pub integer: i32, + pub managed_buffer: ManagedBuffer, +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested03 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested04 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested05 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested06 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested07 {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInSingleValueMapper {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInVec {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInArrayVec {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, ManagedVecItem)] +pub struct AbiManagedVecItem { + pub value1: u32, + pub value2: u32, +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInArray {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInBox {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInBoxedSlice {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInRef {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInSlice {} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNestedInOption {} + +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub struct OnlyShowsUpInEsdtAttr { + pub field: OnlyShowsUpAsNested10, +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub struct OnlyShowsUpAsNested10 {} + +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub enum ExplicitDiscriminant { + Zero, + Thirty, + Twelve, + Fifty, + FiftyOne, +} + +#[rustfmt::skip] +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub enum ExplicitDiscriminantMixed { + Zero, + Unit, + Tuple(u16), + Five, + Struct { + a: u8, + b: u16, + }, +} diff --git a/contracts/feature-tests/abi-tester/src/abi_test_type.rs b/contracts/feature-tests/abi-tester/src/abi_test_type.rs index 2cc1fc4db4..ff4f76b744 100644 --- a/contracts/feature-tests/abi-tester/src/abi_test_type.rs +++ b/contracts/feature-tests/abi-tester/src/abi_test_type.rs @@ -6,7 +6,8 @@ use multiversx_sc::{ multiversx_sc::derive_imports!(); /// Its only purpose is to test that the ABI generator works fine. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct AbiTestType { /// This type should only appear here. pub nested: OnlyShowsUpAsNested01, @@ -20,7 +21,8 @@ pub struct AbiTestType { } /// Its only purpose is to test that the ABI generator works fine. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct AbiManagedType { pub big_uint: BigUint, pub integer: i32, @@ -28,13 +30,14 @@ pub struct AbiManagedType { } /// Its only purpose is to test that the ABI generator works fine. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi, ManagedVecItem)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, ManagedVecItem)] pub struct AbiManagedVecItem { pub value1: u32, pub value2: u32, } -#[derive(TypeAbi)] +#[type_abi] pub struct OnlyShowsUpInEsdtAttr { pub field: OnlyShowsUpAsNested10, } diff --git a/contracts/feature-tests/abi-tester/src/abi_tester.rs b/contracts/feature-tests/abi-tester/src/abi_tester.rs index a68ea341a3..22b4c2e26d 100644 --- a/contracts/feature-tests/abi-tester/src/abi_tester.rs +++ b/contracts/feature-tests/abi-tester/src/abi_tester.rs @@ -3,6 +3,7 @@ multiversx_sc::imports!(); mod abi_enum; +pub mod abi_proxy; mod abi_test_type; mod only_nested; @@ -30,6 +31,12 @@ pub trait AbiTester { #[payable("EGLD")] fn init(&self, _constructor_arg_1: i32, _constructor_arg_2: OnlyShowsUpInConstructor) {} + /// Upgrade constructor. + #[upgrade] + fn upgrade(&self, _constructor_arg_1: i32, _constructor_arg_2: OnlyShowsUpInConstructor) { + self.init(_constructor_arg_1, _constructor_arg_2) + } + /// Example endpoint docs. #[endpoint] #[output_name("single output")] @@ -158,6 +165,11 @@ pub trait AbiTester { None } + #[view] + fn operation_completion_status(&self) -> OperationCompletionStatus { + OperationCompletionStatus::Completed + } + #[endpoint] #[payable("EGLD")] fn payable_egld(&self) {} diff --git a/contracts/feature-tests/abi-tester/src/only_nested.rs b/contracts/feature-tests/abi-tester/src/only_nested.rs index d1e19441d0..5c960cc95a 100644 --- a/contracts/feature-tests/abi-tester/src/only_nested.rs +++ b/contracts/feature-tests/abi-tester/src/only_nested.rs @@ -1,85 +1,105 @@ multiversx_sc::derive_imports!(); /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpInConstructor { pub something: (), } /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested01; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested02 { pub something: [u8; 0], } /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested03(); /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested04; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested05; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested06; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested07; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested08; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested09; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNested10; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInSingleValueMapper; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInVec; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInArrayVec; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInArray; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInBox; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInBoxedSlice; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInRef; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInSlice; /// Tests that the ABI generator also fetches types that only appear as fields. -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub struct OnlyShowsUpAsNestedInOption; diff --git a/contracts/feature-tests/abi-tester/tests/abi_tester_abi_test.rs b/contracts/feature-tests/abi-tester/tests/abi_tester_abi_test.rs index f4274861de..e5a31ef9e4 100644 --- a/contracts/feature-tests/abi-tester/tests/abi_tester_abi_test.rs +++ b/contracts/feature-tests/abi-tester/tests/abi_tester_abi_test.rs @@ -1,7 +1,7 @@ use std::{fs, fs::File, io::Write}; use multiversx_sc::{ - abi::{EnumVariantDescription, TypeContents}, + abi::{EnumVariantDescription, TypeContents, TypeNames}, contract_base::ContractAbiProvider, }; use multiversx_sc_meta::{ @@ -94,7 +94,10 @@ fn abi_deserialization_check() { .types .get("AbiEnum") .unwrap() - .to_type_description("AbiEnum"); + .to_type_description(TypeNames { + abi: "AbiEnum".to_string(), + rust: "Enum".to_string(), + }); if let TypeContents::Enum(variants) = abi_enum_type.contents { assert_eq!(variants.len(), 4); assert_eq!( diff --git a/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.lock b/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.lock index 95b5bf4d2b..fee4cf1dbc 100644 --- a/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.lock +++ b/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.toml b/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.toml index 974a67c2aa..963ef8f870 100644 --- a/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.toml +++ b/contracts/feature-tests/abi-tester/wasm-abi-tester-ev/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/abi-tester/wasm/Cargo.lock b/contracts/feature-tests/abi-tester/wasm/Cargo.lock index cee49ced4a..e5e8466144 100755 --- a/contracts/feature-tests/abi-tester/wasm/Cargo.lock +++ b/contracts/feature-tests/abi-tester/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/abi-tester/wasm/Cargo.toml b/contracts/feature-tests/abi-tester/wasm/Cargo.toml index ec7a639034..f5700ad92e 100644 --- a/contracts/feature-tests/abi-tester/wasm/Cargo.toml +++ b/contracts/feature-tests/abi-tester/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/abi-tester/wasm/src/lib.rs b/contracts/feature-tests/abi-tester/wasm/src/lib.rs index 6a15c9899b..cf9aa68978 100644 --- a/contracts/feature-tests/abi-tester/wasm/src/lib.rs +++ b/contracts/feature-tests/abi-tester/wasm/src/lib.rs @@ -5,9 +5,10 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 27 +// Upgrade: 1 +// Endpoints: 28 // Async Callback (empty): 1 -// Total number of exported functions: 29 +// Total number of exported functions: 31 #![no_std] #![allow(internal_features)] @@ -20,6 +21,7 @@ multiversx_sc_wasm_adapter::endpoints! { abi_tester ( init => init + upgrade => upgrade echo_abi_test_type => echo_abi_test_type echo_enum => echo_enum take_managed_type => take_managed_type @@ -44,6 +46,7 @@ multiversx_sc_wasm_adapter::endpoints! { item_for_ref => item_for_ref item_for_slice => item_for_slice item_for_option => item_for_option + operation_completion_status => operation_completion_status payable_egld => payable_egld payable_some_token => payable_some_token payable_any_token => payable_any_token diff --git a/contracts/feature-tests/alloc-features/Cargo.toml b/contracts/feature-tests/alloc-features/Cargo.toml index a68c272034..3dd34d56a7 100644 --- a/contracts/feature-tests/alloc-features/Cargo.toml +++ b/contracts/feature-tests/alloc-features/Cargo.toml @@ -9,12 +9,12 @@ publish = false path = "src/alloc_features_main.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies.esdt-system-sc-mock] diff --git a/contracts/feature-tests/alloc-features/meta/Cargo.toml b/contracts/feature-tests/alloc-features/meta/Cargo.toml index 7b89a027f5..3ed3b16104 100644 --- a/contracts/feature-tests/alloc-features/meta/Cargo.toml +++ b/contracts/feature-tests/alloc-features/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.lock b/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.lock index 1898fab79b..8b16c89d1b 100644 --- a/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.lock +++ b/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.toml b/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.toml index 1dddab93aa..130a20cf6e 100644 --- a/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.toml +++ b/contracts/feature-tests/alloc-features/wasm-alloc-mem-fail/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.lock b/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.lock index 193a32459f..a9d74ed0f6 100644 --- a/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.lock +++ b/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.toml b/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.toml index 6cc627db2c..aa66bcb1cb 100644 --- a/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.toml +++ b/contracts/feature-tests/alloc-features/wasm-alloc-mem-leaking/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/alloc-features/wasm/Cargo.lock b/contracts/feature-tests/alloc-features/wasm/Cargo.lock index 6f2be1822e..df6ddbb5b6 100644 --- a/contracts/feature-tests/alloc-features/wasm/Cargo.lock +++ b/contracts/feature-tests/alloc-features/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/alloc-features/wasm/Cargo.toml b/contracts/feature-tests/alloc-features/wasm/Cargo.toml index 14b4608740..0a8f7e641a 100644 --- a/contracts/feature-tests/alloc-features/wasm/Cargo.toml +++ b/contracts/feature-tests/alloc-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/basic-features/Cargo.toml b/contracts/feature-tests/basic-features/Cargo.toml index 9eb9c5c71c..f3633e8bd1 100644 --- a/contracts/feature-tests/basic-features/Cargo.toml +++ b/contracts/feature-tests/basic-features/Cargo.toml @@ -9,15 +9,15 @@ publish = false path = "src/basic_features_main.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dev-dependencies.esdt-system-sc-mock] diff --git a/contracts/feature-tests/basic-features/interact/Cargo.toml b/contracts/feature-tests/basic-features/interact/Cargo.toml index 4c2ec62f46..ef0209cab4 100644 --- a/contracts/feature-tests/basic-features/interact/Cargo.toml +++ b/contracts/feature-tests/basic-features/interact/Cargo.toml @@ -18,5 +18,5 @@ toml = "0.8.6" path = ".." [dependencies.multiversx-sc-snippets] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/snippets" diff --git a/contracts/feature-tests/basic-features/interact/src/bf_interact.rs b/contracts/feature-tests/basic-features/interact/src/bf_interact.rs index ceca3ace12..e02d281120 100644 --- a/contracts/feature-tests/basic-features/interact/src/bf_interact.rs +++ b/contracts/feature-tests/basic-features/interact/src/bf_interact.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] // TODO: unified syntax + mod bf_interact_cli; mod bf_interact_config; mod bf_interact_state; @@ -8,20 +10,8 @@ use basic_features::{ use bf_interact_config::Config; use bf_interact_state::State; use clap::Parser; -use multiversx_sc_snippets::{ - env_logger, - multiversx_sc::{codec::multi_types::IgnoreValue, types::Address}, - multiversx_sc_scenario::{ - api::StaticApi, - bech32, - mandos_system::ScenarioRunner, - scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, - scenario_model::{BytesValue, ScCallStep, ScDeployStep, Scenario, TxExpect}, - standalone::retrieve_account_as_scenario_set_state, - test_wallets, ContractInfo, - }, - tokio, Interactor, -}; + +use multiversx_sc_snippets::imports::*; const INTERACTOR_SCENARIO_TRACE_PATH: &str = "interactor_trace.scen.json"; @@ -85,17 +75,9 @@ impl BasicFeaturesInteract { async fn set_state(&mut self) { println!("wallet address: {}", bech32::encode(&self.wallet_address)); - let scenario_raw = retrieve_account_as_scenario_set_state( - Config::load_config().gateway().to_string(), - bech32::encode(&self.wallet_address), - true, - ) - .await; - - let scenario = Scenario::interpret_from(scenario_raw, &InterpreterContext::default()); - - self.interactor.pre_runners.run_scenario(&scenario); - self.interactor.post_runners.run_scenario(&scenario); + self.interactor + .retrieve_account(&Bech32Address::from(&self.wallet_address)) + .await; } async fn deploy(&mut self) { diff --git a/contracts/feature-tests/basic-features/meta/Cargo.toml b/contracts/feature-tests/basic-features/meta/Cargo.toml index 064891ac10..670da00dbd 100644 --- a/contracts/feature-tests/basic-features/meta/Cargo.toml +++ b/contracts/feature-tests/basic-features/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/basic-features/src/codec_err_test.rs b/contracts/feature-tests/basic-features/src/codec_err_test.rs index 4fa4da2258..23e21310a6 100644 --- a/contracts/feature-tests/basic-features/src/codec_err_test.rs +++ b/contracts/feature-tests/basic-features/src/codec_err_test.rs @@ -1,20 +1,6 @@ multiversx_sc::imports!(); use crate::types::CodecErrorTestType; -mod encode_err_proxy { - multiversx_sc::imports!(); - use crate::types::CodecErrorTestType; - - #[multiversx_sc::proxy] - pub trait EncodeErrorProxy { - #[init] - fn init(&self, error_arg: CodecErrorTestType); - - #[endpoint] - fn encode_error_method(&self, error_arg: CodecErrorTestType); - } -} - /// Test various serialization errors. #[multiversx_sc::module] pub trait CodecErrorTest { @@ -62,24 +48,17 @@ pub trait CodecErrorTest { fn codec_err_event_data(&self) { self.event_err_data(CodecErrorTestType); } - - #[proxy] - fn encode_err_proxy(&self) -> encode_err_proxy::Proxy; - /// Never actually calls any deploy/upgrade, so it is appropriate in this contract. /// It just covers contract init serialization errors. #[endpoint] fn codec_err_contract_init(&self) { - let _ = self.encode_err_proxy().init(CodecErrorTestType); + let _ = self.tx().raw_deploy().argument(&CodecErrorTestType); } /// Never actually calls any async/sync call, so it is appropriate in this contract. /// It just covers contract call serialization errors. #[endpoint] fn codec_err_contract_call(&self) { - let _ = self - .encode_err_proxy() - .contract(ManagedAddress::zero()) - .encode_error_method(CodecErrorTestType); + let _ = self.tx().raw_call("dummy").argument(&CodecErrorTestType); } } diff --git a/contracts/feature-tests/basic-features/src/types/codec_err_test_type.rs b/contracts/feature-tests/basic-features/src/types/codec_err_test_type.rs index 16350f3a5a..41c1524c41 100644 --- a/contracts/feature-tests/basic-features/src/types/codec_err_test_type.rs +++ b/contracts/feature-tests/basic-features/src/types/codec_err_test_type.rs @@ -4,11 +4,11 @@ use multiversx_sc::{ NestedDecodeInput, NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, }, - derive::TypeAbi, + derive::type_abi, }; /// Helper type to explore encode/decode errors. -#[derive(TypeAbi)] +#[type_abi] pub struct CodecErrorTestType; impl TopEncode for CodecErrorTestType { diff --git a/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs index cde4caa56e..88320b17f6 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs @@ -1,5 +1,4 @@ -use multiversx_sc::types::{ManagedAddress, ManagedBuffer}; -use multiversx_sc_scenario::{api::StaticApi, *}; +use multiversx_sc_scenario::imports::*; use basic_features::managed_buffer_features::ManagedBufferFeatures; diff --git a/contracts/feature-tests/basic-features/tests/basic_features_managed_vec_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_managed_vec_test.rs index 62790660d0..fccc91e431 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_managed_vec_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_managed_vec_test.rs @@ -1,5 +1,4 @@ -use multiversx_sc::types::{BigUint, ManagedVec}; -use multiversx_sc_scenario::{api::StaticApi, *}; +use multiversx_sc_scenario::imports::*; use basic_features::managed_vec_features::ManagedVecFeatures; diff --git a/contracts/feature-tests/basic-features/tests/basic_features_ordered_binary_tree_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_ordered_binary_tree_test.rs index 071da4a958..fe48caecba 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_ordered_binary_tree_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_ordered_binary_tree_test.rs @@ -1,10 +1,8 @@ #![allow(deprecated)] use basic_features::BasicFeatures; -use multiversx_sc::imports::{OrderedBinaryTreeNode, NULL_NODE_ID}; -use multiversx_sc_scenario::{ - managed_biguint, rust_biguint, testing_framework::BlockchainStateWrapper, -}; + +use multiversx_sc_scenario::imports::*; #[test] fn ordered_binary_tree_test() { diff --git a/contracts/feature-tests/basic-features/tests/basic_features_token_identifier_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_token_identifier_test.rs index 3b85d24b4f..8cfe9ba2d2 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_token_identifier_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_token_identifier_test.rs @@ -1,5 +1,4 @@ -use multiversx_sc::types::{EgldOrEsdtTokenIdentifier, ManagedBuffer, TokenIdentifier}; -use multiversx_sc_scenario::{api::StaticApi, *}; +use multiversx_sc_scenario::imports::*; use basic_features::token_identifier_features::TokenIdentifierFeatures; diff --git a/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.lock b/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.lock index b8582c7218..58a94ca113 100644 --- a/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.lock +++ b/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.lock @@ -56,7 +56,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.toml b/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.toml index 9d856c470e..7d1cc921f4 100644 --- a/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.toml +++ b/contracts/feature-tests/basic-features/wasm-basic-features-storage-bytes/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/basic-features/wasm/Cargo.lock b/contracts/feature-tests/basic-features/wasm/Cargo.lock index 1f5af1b98b..c44431afb1 100755 --- a/contracts/feature-tests/basic-features/wasm/Cargo.lock +++ b/contracts/feature-tests/basic-features/wasm/Cargo.lock @@ -56,7 +56,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +85,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,14 +96,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/basic-features/wasm/Cargo.toml b/contracts/feature-tests/basic-features/wasm/Cargo.toml index af9e347794..cf42ff107a 100644 --- a/contracts/feature-tests/basic-features/wasm/Cargo.toml +++ b/contracts/feature-tests/basic-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = true path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/big-float-features/Cargo.toml b/contracts/feature-tests/big-float-features/Cargo.toml index dcdae6d108..ae27c92b74 100644 --- a/contracts/feature-tests/big-float-features/Cargo.toml +++ b/contracts/feature-tests/big-float-features/Cargo.toml @@ -9,11 +9,11 @@ publish = false path = "src/big_float_main.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies.esdt-system-sc-mock] diff --git a/contracts/feature-tests/big-float-features/meta/Cargo.toml b/contracts/feature-tests/big-float-features/meta/Cargo.toml index 92d80d90a0..603f584ece 100644 --- a/contracts/feature-tests/big-float-features/meta/Cargo.toml +++ b/contracts/feature-tests/big-float-features/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/big-float-features/wasm/Cargo.lock b/contracts/feature-tests/big-float-features/wasm/Cargo.lock index 5e95524a81..8e2d6618a0 100644 --- a/contracts/feature-tests/big-float-features/wasm/Cargo.lock +++ b/contracts/feature-tests/big-float-features/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/big-float-features/wasm/Cargo.toml b/contracts/feature-tests/big-float-features/wasm/Cargo.toml index 0aa0ca142e..13c3fb8bdc 100644 --- a/contracts/feature-tests/big-float-features/wasm/Cargo.toml +++ b/contracts/feature-tests/big-float-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/Cargo.toml b/contracts/feature-tests/composability/Cargo.toml index 6332301262..5d372b4128 100644 --- a/contracts/feature-tests/composability/Cargo.toml +++ b/contracts/feature-tests/composability/Cargo.toml @@ -11,6 +11,9 @@ path = "builtin-func-features" [dev-dependencies.forwarder] path = "forwarder" +[dev-dependencies.forwarder-legacy] +path = "forwarder-legacy" + [dev-dependencies.forwarder-queue] path = "forwarder-queue" @@ -33,9 +36,9 @@ path = "recursive-caller" path = "vault" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/composability/builtin-func-features/Cargo.toml b/contracts/feature-tests/composability/builtin-func-features/Cargo.toml index 1ef0c0c225..58c9d24215 100644 --- a/contracts/feature-tests/composability/builtin-func-features/Cargo.toml +++ b/contracts/feature-tests/composability/builtin-func-features/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/builtin_func_features.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/builtin-func-features/meta/Cargo.toml b/contracts/feature-tests/composability/builtin-func-features/meta/Cargo.toml index c7e165f394..3c33b8d81d 100644 --- a/contracts/feature-tests/composability/builtin-func-features/meta/Cargo.toml +++ b/contracts/feature-tests/composability/builtin-func-features/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs b/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs index 81df199e68..de33932a9e 100644 --- a/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs +++ b/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_features.rs @@ -1,31 +1,28 @@ #![no_std] -pub mod builtin_func_proxy; - multiversx_sc::imports!(); /// Test contract for investigating async calls. #[multiversx_sc::contract] pub trait BuiltinFuncFeatures { - #[proxy] - fn builtin_func_proxy(&self, to: ManagedAddress) -> builtin_func_proxy::Proxy; - #[init] fn init(&self) {} #[endpoint] fn call_set_user_name(&self, address: ManagedAddress, name: ManagedBuffer) { - self.builtin_func_proxy(address) - .set_user_name(&name) - .async_call() - .call_and_exit() + self.tx() + .to(&address) + .typed(system_proxy::UserBuiltinProxy) + .set_user_name(name) + .async_call_and_exit() } #[endpoint] fn call_delete_user_name(&self, address: ManagedAddress) { - self.builtin_func_proxy(address) + self.tx() + .to(&address) + .typed(system_proxy::UserBuiltinProxy) .delete_user_name() - .async_call() - .call_and_exit(); + .async_call_and_exit() } } diff --git a/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_proxy.rs b/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_proxy.rs deleted file mode 100644 index 5499deee5e..0000000000 --- a/contracts/feature-tests/composability/builtin-func-features/src/builtin_func_proxy.rs +++ /dev/null @@ -1,10 +0,0 @@ -multiversx_sc::imports!(); - -#[multiversx_sc::derive::proxy] -pub trait UserBuiltin { - #[endpoint(SetUserName)] - fn set_user_name(&self, name: &ManagedBuffer); - - #[endpoint(DeleteUserName)] - fn delete_user_name(&self); -} diff --git a/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.lock b/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.lock index 8b0361ffb9..a1e69001c6 100644 --- a/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.toml b/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.toml index 0849b96d5b..63dbe95fcb 100644 --- a/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/builtin-func-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/esdt-contract-pair/Cargo.toml b/contracts/feature-tests/composability/esdt-contract-pair/Cargo.toml index 567a272e2a..63b7e46395 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/Cargo.toml +++ b/contracts/feature-tests/composability/esdt-contract-pair/Cargo.toml @@ -12,9 +12,9 @@ path = "first-contract" path = "second-contract" [dev-dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/Cargo.toml b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/Cargo.toml index 6183b93122..49c6e25659 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/Cargo.toml +++ b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/Cargo.toml @@ -8,12 +8,11 @@ publish = false [lib] path = "src/lib.rs" - [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/meta/Cargo.toml b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/meta/Cargo.toml index 01fceb451a..ccf10c89ad 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/meta/Cargo.toml +++ b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/meta/Cargo.toml @@ -8,10 +8,10 @@ publish = false path = ".." [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/base" [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/src/lib.rs b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/src/lib.rs index dfa6ff75e5..2d35ac5ea8 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/src/lib.rs +++ b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/src/lib.rs @@ -2,9 +2,9 @@ multiversx_sc::imports!(); -const ESDT_TRANSFER_STRING: &[u8] = b"ESDTTransfer"; -const SECOND_CONTRACT_ACCEPT_ESDT_PAYMENT: &[u8] = b"acceptEsdtPayment"; -const SECOND_CONTRACT_REJECT_ESDT_PAYMENT: &[u8] = b"rejectEsdtPayment"; +const ESDT_TRANSFER_STRING: &str = "ESDTTransfer"; +const SECOND_CONTRACT_ACCEPT_ESDT_PAYMENT: &str = "acceptEsdtPayment"; +const SECOND_CONTRACT_REJECT_ESDT_PAYMENT: &str = "rejectEsdtPayment"; #[multiversx_sc::contract] pub trait FirstContract { @@ -90,14 +90,13 @@ pub trait FirstContract { "Wrong esdt token" ); - let _ = self.send_raw().transfer_esdt_execute( - &second_contract_address, - &expected_token_identifier, - &esdt_value, - self.blockchain().get_gas_left(), - &ManagedBuffer::from(SECOND_CONTRACT_REJECT_ESDT_PAYMENT), - &ManagedArgBuffer::new(), - ); + let gas_left = self.blockchain().get_gas_left(); + self.tx() + .to(&second_contract_address) + .gas(gas_left) + .raw_call(SECOND_CONTRACT_REJECT_ESDT_PAYMENT) + .single_esdt(&expected_token_identifier, 0u64, &esdt_value) + .transfer_execute(); } #[payable("*")] @@ -112,14 +111,13 @@ pub trait FirstContract { "Wrong esdt token" ); - let _ = self.send_raw().transfer_esdt_execute( - &second_contract_address, - &expected_token_identifier, - &esdt_value, - self.blockchain().get_gas_left(), - &ManagedBuffer::from(SECOND_CONTRACT_ACCEPT_ESDT_PAYMENT), - &ManagedArgBuffer::new(), - ); + let gas_left = self.blockchain().get_gas_left(); + self.tx() + .to(&second_contract_address) + .gas(gas_left) + .raw_call(SECOND_CONTRACT_ACCEPT_ESDT_PAYMENT) + .single_esdt(&expected_token_identifier, 0u64, &esdt_value) + .transfer_execute(); } fn call_esdt_second_contract( @@ -138,12 +136,11 @@ pub trait FirstContract { arg_buffer.push_arg_raw(arg); } - self.send_raw().async_call_raw( - to, - &BigUint::zero(), - &ManagedBuffer::from(ESDT_TRANSFER_STRING), - &arg_buffer, - ); + self.tx() + .to(to) + .raw_call(ESDT_TRANSFER_STRING) + .arguments_raw(arg_buffer) + .async_call_and_exit(); } // storage diff --git a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.lock b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.lock index f0e1a09e32..5a7020c0cc 100755 --- a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.toml b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.toml index 49863070ff..57c15b6fe2 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/esdt-contract-pair/first-contract/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/Cargo.toml b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/Cargo.toml index 38407e5e4e..89fe5071b8 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/Cargo.toml +++ b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/Cargo.toml @@ -10,10 +10,10 @@ path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/meta/Cargo.toml b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/meta/Cargo.toml index 8e3b0d819c..8788acf4ac 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/meta/Cargo.toml +++ b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/meta/Cargo.toml @@ -8,10 +8,10 @@ publish = false path = ".." [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/base" [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.lock b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.lock index 41987ecfe9..c4c31a8fb6 100755 --- a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.toml b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.toml index dc6db87986..aa93fcf9d7 100644 --- a/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/esdt-contract-pair/second-contract/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/Cargo.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/Cargo.toml index 2ccd253223..c90b451b29 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/Cargo.toml +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/Cargo.toml @@ -16,9 +16,9 @@ path = "parent" path = "child" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/Cargo.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/Cargo.toml index b659cd0d18..a084afe56c 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/Cargo.toml +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/Cargo.toml @@ -10,9 +10,9 @@ path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/meta/Cargo.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/meta/Cargo.toml index 18e6fce479..a1b68d9807 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/meta/Cargo.toml +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/meta/Cargo.toml @@ -8,10 +8,10 @@ publish = false path = ".." [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/base" [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/sc-config.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/sc-config.toml new file mode 100644 index 0000000000..14d4385ae3 --- /dev/null +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "../parent/src/child_proxy.rs" diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.lock b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.lock index 532a78bc80..77bbdd0fb0 100755 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.toml index 46ccb26612..b9678d7c3e 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/child/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/Cargo.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/Cargo.toml index a31d643f4c..7fbc51b49a 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/Cargo.toml +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/Cargo.toml @@ -8,15 +8,11 @@ publish = false [lib] path = "src/lib.rs" - -[dependencies.child] -path = "../child" - [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/meta/Cargo.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/meta/Cargo.toml index 23bb1ab2cb..8e9105a3ad 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/meta/Cargo.toml +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/meta/Cargo.toml @@ -8,10 +8,10 @@ publish = false path = ".." [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/base" [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/src/child_proxy.rs b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/src/child_proxy.rs new file mode 100644 index 0000000000..b4808f8eba --- /dev/null +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/src/child_proxy.rs @@ -0,0 +1,89 @@ +// 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 ChildProxy; + +impl TxProxyTrait for ChildProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = ChildProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + ChildProxyMethods { wrapped_tx: tx } + } +} + +pub struct ChildProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl ChildProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl ChildProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn issue_wrapped_egld< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + initial_supply: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("issueWrappedEgld") + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&initial_supply) + .original_result() + } + + pub fn wrapped_egld_token_identifier( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getWrappedEgldTokenIdentifier") + .original_result() + } +} diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/src/lib.rs b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/src/lib.rs index ddb8a09a09..5c4bff50d0 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/src/lib.rs +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/src/lib.rs @@ -2,14 +2,13 @@ multiversx_sc::imports!(); +pub mod child_proxy; + // Base cost for standalone + estimate cost of actual sc call const ISSUE_EXPECTED_GAS_COST: u64 = 90_000_000 + 25_000_000; #[multiversx_sc::contract] pub trait Parent { - #[proxy] - fn child_proxy(&self, to: ManagedAddress) -> child::Proxy; - #[init] fn init(&self) {} @@ -19,13 +18,14 @@ pub trait Parent { #[endpoint(deployChildContract)] fn deploy_child_contract(&self, code: ManagedBuffer) { - let (child_contract_address, _) = self.send_raw().deploy_contract( - self.blockchain().get_gas_left(), - &BigUint::zero(), - &code, - CodeMetadata::DEFAULT, - &ManagedArgBuffer::new(), - ); + let gas_left = self.blockchain().get_gas_left(); + let child_contract_address = self + .tx() + .raw_deploy() + .code(code) + .gas(gas_left) + .returns(ReturnsNewManagedAddress) + .sync_call(); self.child_contract_address().set(&child_contract_address); } @@ -40,12 +40,14 @@ pub trait Parent { ) { let issue_cost = self.call_value().egld_value(); let child_contract_adress = self.child_contract_address().get(); - let _: IgnoreValue = self - .child_proxy(child_contract_adress) + + self.tx() + .to(&child_contract_adress) + .typed(child_proxy::ChildProxy) .issue_wrapped_egld(token_display_name, token_ticker, initial_supply) - .with_egld_transfer(issue_cost.clone_value()) - .with_gas_limit(ISSUE_EXPECTED_GAS_COST) - .execute_on_dest_context(); + .egld(issue_cost) + .gas(ISSUE_EXPECTED_GAS_COST) + .sync_call(); } // storage diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.lock b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.lock index 31410f1b90..375b37c6d9 100755 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.lock @@ -20,13 +20,6 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" -[[package]] -name = "child" -version = "0.0.0" -dependencies = [ - "multiversx-sc", -] - [[package]] name = "endian-type" version = "0.1.2" @@ -47,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -76,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -87,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] @@ -114,7 +107,6 @@ dependencies = [ name = "parent" version = "0.0.0" dependencies = [ - "child", "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.toml b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.toml index 6cc2cdff13..62fb2dc77c 100644 --- a/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/execute-on-dest-esdt-issue-callback/parent/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/forwarder-legacy/Cargo.toml b/contracts/feature-tests/composability/forwarder-legacy/Cargo.toml new file mode 100644 index 0000000000..8d985f30c1 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "forwarder-legacy" +version = "0.0.0" +authors = ["Andrei Marinica "] +edition = "2021" +publish = false + +[lib] +path = "src/forwarder_legacy_main.rs" + +[dependencies.vault] +path = "../vault" + +[dependencies.multiversx-sc] +version = "0.49.0-alpha.4" +path = "../../../../framework/base" + +[dev-dependencies.multiversx-sc-scenario] +version = "0.49.0-alpha.4" +path = "../../../../framework/scenario" + diff --git a/contracts/feature-tests/composability/forwarder-legacy/meta/Cargo.toml b/contracts/feature-tests/composability/forwarder-legacy/meta/Cargo.toml new file mode 100644 index 0000000000..de74469420 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/meta/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "forwarder-legacy-meta" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies.forwarder-legacy] +path = ".." + +[dependencies.multiversx-sc-meta] +version = "0.49.0-alpha.4" +path = "../../../../../framework/meta" +default-features = false diff --git a/contracts/feature-tests/composability/forwarder-legacy/meta/src/main.rs b/contracts/feature-tests/composability/forwarder-legacy/meta/src/main.rs new file mode 100644 index 0000000000..a6e424dff6 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta::cli_main::(); +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/multiversx.json b/contracts/feature-tests/composability/forwarder-legacy/multiversx.json new file mode 100644 index 0000000000..8d77ca316c --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/call_async_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/call_async_legacy.rs new file mode 100644 index 0000000000..8826c2db48 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/call_async_legacy.rs @@ -0,0 +1,229 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(TopEncode, TopDecode, TypeAbi)] +pub struct CallbackData { + callback_name: ManagedBuffer, + token_identifier: EgldOrEsdtTokenIdentifier, + token_nonce: u64, + token_amount: BigUint, + args: ManagedVec>, +} + +const PERCENTAGE_TOTAL: u64 = 10_000; // 100% + +#[multiversx_sc::module] +pub trait ForwarderAsyncCallModule { + #[proxy] + fn vault_proxy(&self) -> vault::Proxy; + + #[endpoint] + fn echo_args_async(&self, to: ManagedAddress, args: MultiValueEncoded) { + self.vault_proxy() + .contract(to) + .echo_arguments(args) + .async_call() + .with_callback(self.callbacks().echo_args_callback()) + .call_and_exit(); + } + + #[callback] + fn echo_args_callback( + &self, + #[call_result] result: ManagedAsyncCallResult>, + ) -> MultiValueEncoded { + match result { + ManagedAsyncCallResult::Ok(results) => { + let mut cb_result = + ManagedVec::from_single_item(ManagedBuffer::new_from_bytes(b"success")); + cb_result.append_vec(results.into_vec_of_buffers()); + + cb_result.into() + }, + ManagedAsyncCallResult::Err(err) => { + let mut cb_result = + ManagedVec::from_single_item(ManagedBuffer::new_from_bytes(b"error")); + cb_result.push(ManagedBuffer::new_from_bytes( + &err.err_code.to_be_bytes()[..], + )); + cb_result.push(err.err_msg); + + cb_result.into() + }, + } + } + + #[endpoint] + #[payable("*")] + fn forward_async_accept_funds(&self, to: ManagedAddress) { + let payment = self.call_value().egld_or_single_esdt(); + self.vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer(payment) + .async_call() + .call_and_exit() + } + + #[endpoint] + #[payable("*")] + fn forward_async_accept_funds_half_payment(&self, to: ManagedAddress) { + let payment = self.call_value().egld_or_single_esdt(); + let half_payment = payment.amount / 2u32; + self.vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer(( + payment.token_identifier, + payment.token_nonce, + half_payment, + )) + .async_call() + .call_and_exit() + } + + #[payable("*")] + #[endpoint] + fn forward_async_accept_funds_with_fees(&self, to: ManagedAddress, percentage_fees: BigUint) { + let payment = self.call_value().egld_or_single_esdt(); + let fees = &payment.amount * &percentage_fees / PERCENTAGE_TOTAL; + let amount_to_send = &payment.amount - &fees; + + self.vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer(( + payment.token_identifier, + payment.token_nonce, + amount_to_send, + )) + .async_call() + .call_and_exit() + } + + #[endpoint] + fn forward_async_retrieve_funds( + &self, + to: ManagedAddress, + token: EgldOrEsdtTokenIdentifier, + token_nonce: u64, + amount: BigUint, + ) { + self.vault_proxy() + .contract(to) + .retrieve_funds(token, token_nonce, amount) + .async_call() + .with_callback(self.callbacks().retrieve_funds_callback()) + .call_and_exit() + } + + #[callback] + fn retrieve_funds_callback(&self) { + let (token, nonce, payment) = self.call_value().egld_or_single_esdt().into_tuple(); + self.retrieve_funds_callback_event(&token, nonce, &payment); + + let _ = self.callback_data().push(&CallbackData { + callback_name: ManagedBuffer::from(b"retrieve_funds_callback"), + token_identifier: token, + token_nonce: nonce, + token_amount: payment, + args: ManagedVec::new(), + }); + } + + #[event("retrieve_funds_callback")] + fn retrieve_funds_callback_event( + &self, + #[indexed] token: &EgldOrEsdtTokenIdentifier, + #[indexed] nonce: u64, + #[indexed] payment: &BigUint, + ); + + #[endpoint] + fn send_funds_twice( + &self, + to: &ManagedAddress, + token_identifier: &EgldOrEsdtTokenIdentifier, + amount: &BigUint, + ) { + self.vault_proxy() + .contract(to.clone()) + .accept_funds() + .with_egld_or_single_esdt_transfer((token_identifier.clone(), 0, amount.clone())) + .async_call() + .with_callback( + self.callbacks() + .send_funds_twice_callback(to, token_identifier, amount), + ) + .call_and_exit() + } + + #[callback] + fn send_funds_twice_callback( + &self, + to: &ManagedAddress, + token_identifier: &EgldOrEsdtTokenIdentifier, + cb_amount: &BigUint, + ) { + self.vault_proxy() + .contract(to.clone()) + .accept_funds() + .with_egld_or_single_esdt_transfer((token_identifier.clone(), 0, cb_amount.clone())) + .async_call() + .call_and_exit() + } + + #[endpoint] + fn send_async_accept_multi_transfer( + &self, + to: ManagedAddress, + token_payments: MultiValueEncoded>, + ) { + let mut all_token_payments = ManagedVec::new(); + + for multi_arg in token_payments.into_iter() { + let (token_identifier, token_nonce, amount) = multi_arg.into_tuple(); + let payment = EsdtTokenPayment::new(token_identifier, token_nonce, amount); + + all_token_payments.push(payment); + } + + self.vault_proxy() + .contract(to) + .accept_funds() + .with_multi_token_transfer(all_token_payments) + .async_call() + .call_and_exit() + } + + #[view] + #[storage_mapper("callback_data")] + fn callback_data(&self) -> VecMapper>; + + #[view] + fn callback_data_at_index( + &self, + index: usize, + ) -> MultiValue5< + ManagedBuffer, + EgldOrEsdtTokenIdentifier, + u64, + BigUint, + MultiValueManagedVec, + > { + let cb_data = self.callback_data().get(index); + ( + cb_data.callback_name, + cb_data.token_identifier, + cb_data.token_nonce, + cb_data.token_amount, + cb_data.args.into(), + ) + .into() + } + + #[endpoint] + fn clear_callback_data(&self) { + self.callback_data().clear(); + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/call_sync_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/call_sync_legacy.rs new file mode 100644 index 0000000000..67d923936e --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/call_sync_legacy.rs @@ -0,0 +1,173 @@ +multiversx_sc::imports!(); + +const PERCENTAGE_TOTAL: u64 = 10_000; // 100% + +#[multiversx_sc::module] +pub trait ForwarderSyncCallModule { + #[proxy] + fn vault_proxy(&self) -> vault::Proxy; + + #[endpoint] + #[payable("*")] + fn echo_arguments_sync(&self, to: ManagedAddress, args: MultiValueEncoded) { + let half_gas = self.blockchain().get_gas_left() / 2; + + let result: MultiValueEncoded = self + .vault_proxy() + .contract(to) + .echo_arguments(args) + .with_gas_limit(half_gas) + .execute_on_dest_context(); + + self.execute_on_dest_context_result_event(&result.into_vec_of_buffers()); + } + + #[endpoint] + #[payable("*")] + fn echo_arguments_sync_twice( + &self, + to: ManagedAddress, + args: MultiValueEncoded, + ) { + let one_third_gas = self.blockchain().get_gas_left() / 3; + + let result: MultiValueEncoded = self + .vault_proxy() + .contract(to.clone()) + .echo_arguments(&args) + .with_gas_limit(one_third_gas) + .execute_on_dest_context(); + + self.execute_on_dest_context_result_event(&result.into_vec_of_buffers()); + + let result: MultiValueEncoded = self + .vault_proxy() + .contract(to) + .echo_arguments(&args) + .with_gas_limit(one_third_gas) + .execute_on_dest_context(); + + self.execute_on_dest_context_result_event(&result.into_vec_of_buffers()); + } + + #[event("echo_arguments_sync_result")] + fn execute_on_dest_context_result_event(&self, result: &ManagedVec); + + #[endpoint] + #[payable("*")] + fn forward_sync_accept_funds(&self, to: ManagedAddress) { + let payment = self.call_value().egld_or_single_esdt(); + let half_gas = self.blockchain().get_gas_left() / 2; + + let result: MultiValue2> = self + .vault_proxy() + .contract(to) + .accept_funds_echo_payment() + .with_egld_or_single_esdt_transfer(payment) + .with_gas_limit(half_gas) + .execute_on_dest_context(); + let (egld_value, esdt_transfers_multi) = result.into_tuple(); + + self.accept_funds_sync_result_event(&egld_value, &esdt_transfers_multi); + } + + #[payable("*")] + #[endpoint] + fn forward_sync_accept_funds_with_fees(&self, to: ManagedAddress, percentage_fees: BigUint) { + let (token_id, payment) = self.call_value().egld_or_single_fungible_esdt(); + let fees = &payment * &percentage_fees / PERCENTAGE_TOTAL; + let amount_to_send = payment - fees; + + let () = self + .vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer((token_id, 0, amount_to_send)) + .execute_on_dest_context(); + } + + #[event("accept_funds_sync_result")] + fn accept_funds_sync_result_event( + &self, + #[indexed] egld_value: &BigUint, + #[indexed] multi_esdt: &MultiValueEncoded, + ); + + #[endpoint] + #[payable("*")] + fn forward_sync_accept_funds_then_read(&self, to: ManagedAddress) -> usize { + let payment = self.call_value().egld_or_single_esdt(); + self.vault_proxy() + .contract(to.clone()) + .accept_funds() + .with_egld_or_single_esdt_transfer(payment) + .execute_on_dest_context::<()>(); + + self.vault_proxy() + .contract(to) + .call_counts(b"accept_funds") + .execute_on_dest_context::>() + .into() + } + + #[endpoint] + fn forward_sync_retrieve_funds( + &self, + to: ManagedAddress, + token: EgldOrEsdtTokenIdentifier, + token_nonce: u64, + amount: BigUint, + ) { + self.vault_proxy() + .contract(to) + .retrieve_funds(token, token_nonce, amount) + .execute_on_dest_context::<()>(); + } + + #[payable("*")] + #[endpoint] + fn forward_sync_retrieve_funds_with_accept_func( + &self, + to: ManagedAddress, + token: TokenIdentifier, + amount: BigUint, + ) { + let payments = self.call_value().all_esdt_transfers(); + + self.vault_proxy() + .contract(to) + .retrieve_funds_with_transfer_exec( + token, + amount, + OptionalValue::::Some(b"accept_funds_func".into()), + ) + .with_multi_token_transfer(payments.clone_value()) + .execute_on_dest_context::<()>(); + } + + #[payable("*")] + #[endpoint] + fn accept_funds_func(&self) {} + + #[endpoint] + fn forward_sync_accept_funds_multi_transfer( + &self, + to: ManagedAddress, + token_payments: MultiValueEncoded>, + ) { + let mut all_token_payments = ManagedVec::new(); + + for multi_arg in token_payments.into_iter() { + let (token_identifier, token_nonce, amount) = multi_arg.into_tuple(); + let payment = EsdtTokenPayment::new(token_identifier, token_nonce, amount); + all_token_payments.push(payment); + } + + let () = self + .vault_proxy() + .contract(to) + .accept_funds() + .with_multi_token_transfer(all_token_payments) + .execute_on_dest_context(); + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/call_transf_exec_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/call_transf_exec_legacy.rs new file mode 100644 index 0000000000..e789e4644f --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/call_transf_exec_legacy.rs @@ -0,0 +1,190 @@ +multiversx_sc::imports!(); + +const PERCENTAGE_TOTAL: u64 = 10_000; // 100% + +#[multiversx_sc::module] +pub trait ForwarderTransferExecuteModule { + #[proxy] + fn vault_proxy(&self) -> vault::Proxy; + + #[endpoint] + #[payable("*")] + fn forward_transf_exec_accept_funds(&self, to: ManagedAddress) { + let payment = self.call_value().egld_or_single_esdt(); + self.vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer(payment) + .transfer_execute(); + } + + /// Tests triple as ESDTTokenPayment. + /// + /// TODO: move somewhere else after release + #[endpoint] + #[payable("*")] + fn forward_transf_exec_accept_single_esdt(&self, to: ManagedAddress) { + let payment = self.call_value().single_esdt(); + self.vault_proxy() + .contract(to) + .accept_funds() + .payment((payment.token_identifier, 0, payment.amount)) + .transfer_execute(); + } + + #[endpoint] + #[payable("*")] + fn forward_transf_execu_accept_funds_with_fees( + &self, + to: ManagedAddress, + percentage_fees: BigUint, + ) { + let (token_id, payment) = self.call_value().egld_or_single_fungible_esdt(); + let fees = &payment * &percentage_fees / PERCENTAGE_TOTAL; + let amount_to_send = payment - fees; + + self.vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer((token_id, 0, amount_to_send)) + .transfer_execute(); + } + + #[endpoint] + #[payable("*")] + fn forward_transf_exec_accept_funds_twice(&self, to: ManagedAddress) { + let (token, token_nonce, payment) = self.call_value().egld_or_single_esdt().into_tuple(); + let half_payment = payment / 2u32; + let half_gas = self.blockchain().get_gas_left() / 2; + + self.vault_proxy() + .contract(to.clone()) + .accept_funds() + .with_egld_or_single_esdt_transfer((token.clone(), token_nonce, half_payment.clone())) + .with_gas_limit(half_gas) + .transfer_execute(); + + self.vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer((token, token_nonce, half_payment)) + .with_gas_limit(half_gas) + .transfer_execute(); + } + + /// Test that the default gas provided to the transfer_execute call + /// leaves enough in the transaction for finish to happen. + #[endpoint] + #[payable("*")] + fn forward_transf_exec_accept_funds_return_values( + &self, + to: ManagedAddress, + ) -> MultiValue4 { + let payment = self.call_value().egld_or_single_esdt(); + let payment_token = payment.token_identifier.clone(); + let gas_left_before = self.blockchain().get_gas_left(); + + self.vault_proxy() + .contract(to) + .accept_funds() + .with_egld_or_single_esdt_transfer(payment) + .transfer_execute(); + + let gas_left_after = self.blockchain().get_gas_left(); + + ( + gas_left_before, + gas_left_after, + BigUint::zero(), + payment_token, + ) + .into() + } + + #[endpoint] + fn transf_exec_multi_accept_funds( + &self, + to: ManagedAddress, + token_payments: MultiValueEncoded>, + ) { + let mut all_token_payments = ManagedVec::new(); + + for multi_arg in token_payments.into_iter() { + let (token_identifier, token_nonce, amount) = multi_arg.into_tuple(); + let payment = EsdtTokenPayment::new(token_identifier, token_nonce, amount); + + all_token_payments.push(payment); + } + + self.vault_proxy() + .contract(to) + .accept_funds() + .with_multi_token_transfer(all_token_payments) + .transfer_execute() + } + + #[endpoint] + fn transf_exec_multi_accept_funds_v2( + &self, + to: ManagedAddress, + token_payments: MultiValueEncoded>, + ) { + let mut tx = self + .vault_proxy() + .contract(to) + .accept_funds() + .multi_esdt(()); + + for multi_arg in token_payments.into_iter() { + let (token_identifier, token_nonce, amount) = multi_arg.into_tuple(); + let payment_triple = (token_identifier, token_nonce, amount); + tx = tx.with_esdt_transfer(payment_triple); + } + + tx.transfer_execute() + } + + #[endpoint] + fn forward_transf_exec_reject_funds_multi_transfer( + &self, + to: ManagedAddress, + token_payments: MultiValueEncoded>, + ) { + let mut all_token_payments = ManagedVec::new(); + + for multi_arg in token_payments.into_iter() { + let (token_identifier, token_nonce, amount) = multi_arg.into_tuple(); + let payment = EsdtTokenPayment::new(token_identifier, token_nonce, amount); + + all_token_payments.push(payment); + } + + self.vault_proxy() + .contract(to) + .accept_funds() + .with_multi_token_transfer(all_token_payments) + .transfer_execute() + } + + #[endpoint] + fn transf_exec_multi_reject_funds( + &self, + to: ManagedAddress, + token_payments: MultiValueEncoded>, + ) { + let mut all_token_payments = ManagedVec::new(); + + for multi_arg in token_payments.into_iter() { + let (token_identifier, token_nonce, amount) = multi_arg.into_tuple(); + let payment = EsdtTokenPayment::new(token_identifier, token_nonce, amount); + + all_token_payments.push(payment); + } + + self.vault_proxy() + .contract(to) + .reject_funds() + .with_multi_token_transfer(all_token_payments) + .transfer_execute() + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/contract_change_owner_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/contract_change_owner_legacy.rs new file mode 100644 index 0000000000..8c5a140e8d --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/contract_change_owner_legacy.rs @@ -0,0 +1,28 @@ +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait ChangeOwnerModule { + #[proxy] + fn vault_proxy(&self) -> vault::Proxy; + + #[endpoint(changeOwnerAddress)] + fn change_owner( + &self, + child_sc_address: ManagedAddress, + new_owner: ManagedAddress, + ) -> ManagedAddress { + let () = self + .send() + .change_owner_address(child_sc_address.clone(), &new_owner) + .execute_on_dest_context(); + + self.get_owner_of_vault_contract(child_sc_address) + } + + fn get_owner_of_vault_contract(&self, address: ManagedAddress) -> ManagedAddress { + self.vault_proxy() + .contract(address) + .get_owner_address() + .execute_on_dest_context() + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/contract_deploy_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/contract_deploy_legacy.rs new file mode 100644 index 0000000000..d573b45ec0 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/contract_deploy_legacy.rs @@ -0,0 +1,55 @@ +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait DeployContractModule { + #[proxy] + fn vault_proxy(&self) -> vault::Proxy; + + #[endpoint] + fn deploy_contract( + &self, + code: ManagedBuffer, + opt_arg: OptionalValue, + ) -> MultiValue2> { + self.perform_deploy_vault(&code, opt_arg).into() + } + + #[endpoint] + fn deploy_two_contracts( + &self, + code: ManagedBuffer, + ) -> MultiValue2 { + let (first_deployed_contract_address, _) = + self.perform_deploy_vault(&code, OptionalValue::None); + let (second_deployed_contract_address, _) = + self.perform_deploy_vault(&code, OptionalValue::None); + + ( + first_deployed_contract_address, + second_deployed_contract_address, + ) + .into() + } + + fn perform_deploy_vault( + &self, + code: &ManagedBuffer, + opt_arg: OptionalValue, + ) -> (ManagedAddress, OptionalValue) { + self.vault_proxy() + .init(opt_arg) + .deploy_contract(code, CodeMetadata::DEFAULT) + } + + #[endpoint] + fn deploy_vault_from_source( + &self, + source_address: ManagedAddress, + opt_arg: OptionalValue, + ) -> MultiValue2> { + self.vault_proxy() + .init(opt_arg) + .deploy_from_source(&source_address, CodeMetadata::DEFAULT) + .into() + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/contract_upgrade_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/contract_upgrade_legacy.rs new file mode 100644 index 0000000000..32e92844c7 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/contract_upgrade_legacy.rs @@ -0,0 +1,33 @@ +#![allow(deprecated)] + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait UpgradeContractModule { + #[proxy] + fn vault_proxy(&self, sc_address: ManagedAddress) -> vault::Proxy; + + #[endpoint(upgradeVault)] + fn upgrade_vault( + &self, + child_sc_address: ManagedAddress, + new_code: ManagedBuffer, + opt_arg: OptionalValue, + ) { + self.vault_proxy(child_sc_address) + .init(opt_arg) + .upgrade_contract(&new_code, CodeMetadata::UPGRADEABLE); + } + + #[endpoint] + fn upgrade_vault_from_source( + &self, + child_sc_address: ManagedAddress, + source_address: ManagedAddress, + opt_arg: OptionalValue, + ) { + self.vault_proxy(child_sc_address) + .init(opt_arg) + .upgrade_from_source(&source_address, CodeMetadata::UPGRADEABLE) + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/esdt_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/esdt_legacy.rs new file mode 100644 index 0000000000..900620c0c1 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/esdt_legacy.rs @@ -0,0 +1,215 @@ +multiversx_sc::imports!(); + +use super::storage_legacy; + +const PERCENTAGE_TOTAL: u64 = 10_000; // 100% + +pub type EsdtTokenDataMultiValue = MultiValue9< + EsdtTokenType, + BigUint, + bool, + ManagedBuffer, + ManagedBuffer, + ManagedBuffer, + ManagedAddress, + BigUint, + ManagedVec>, +>; + +#[multiversx_sc::module] +pub trait ForwarderEsdtModule: storage_legacy::ForwarderStorageModule { + #[view(getFungibleEsdtBalance)] + fn get_fungible_esdt_balance(&self, token_identifier: &TokenIdentifier) -> BigUint { + self.blockchain() + .get_esdt_balance(&self.blockchain().get_sc_address(), token_identifier, 0) + } + + #[view(getCurrentNftNonce)] + fn get_current_nft_nonce(&self, token_identifier: &TokenIdentifier) -> u64 { + self.blockchain() + .get_current_esdt_nft_nonce(&self.blockchain().get_sc_address(), token_identifier) + } + + #[endpoint] + fn send_esdt(&self, to: &ManagedAddress, token_id: TokenIdentifier, amount: &BigUint) { + self.send().direct_esdt(to, &token_id, 0, amount); + } + + #[payable("*")] + #[endpoint] + fn send_esdt_with_fees(&self, to: ManagedAddress, percentage_fees: BigUint) { + let (token_id, payment) = self.call_value().single_fungible_esdt(); + let fees = &payment * &percentage_fees / PERCENTAGE_TOTAL; + let amount_to_send = payment - fees; + + self.send().direct_esdt(&to, &token_id, 0, &amount_to_send); + } + + #[endpoint] + fn send_esdt_twice( + &self, + to: &ManagedAddress, + token_id: TokenIdentifier, + amount_first_time: &BigUint, + amount_second_time: &BigUint, + ) { + self.send().direct_esdt(to, &token_id, 0, amount_first_time); + self.send() + .direct_esdt(to, &token_id, 0, amount_second_time); + } + + #[endpoint] + fn send_esdt_direct_multi_transfer( + &self, + to: ManagedAddress, + token_payments: MultiValueEncoded>, + ) { + let mut all_token_payments = ManagedVec::new(); + + for multi_arg in token_payments.into_iter() { + let (token_identifier, token_nonce, amount) = multi_arg.into_tuple(); + let payment = EsdtTokenPayment::new(token_identifier, token_nonce, amount); + + all_token_payments.push(payment); + } + + let _ = self.send_raw().multi_esdt_transfer_execute( + &to, + &all_token_payments, + self.blockchain().get_gas_left(), + &ManagedBuffer::new(), + &ManagedArgBuffer::new(), + ); + } + + #[payable("EGLD")] + #[endpoint] + fn issue_fungible_token( + &self, + token_display_name: ManagedBuffer, + token_ticker: ManagedBuffer, + initial_supply: BigUint, + ) { + let issue_cost = self.call_value().egld_value(); + let caller = self.blockchain().get_caller(); + + self.send() + .esdt_system_sc_proxy() + .issue_fungible( + issue_cost.clone_value(), + &token_display_name, + &token_ticker, + &initial_supply, + FungibleTokenProperties { + num_decimals: 0, + 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, + }, + ) + .async_call() + .with_callback(self.callbacks().esdt_issue_callback(&caller)) + .call_and_exit() + } + + #[callback] + fn esdt_issue_callback( + &self, + caller: &ManagedAddress, + #[call_result] result: ManagedAsyncCallResult<()>, + ) { + let (token_identifier, returned_tokens) = self.call_value().egld_or_single_fungible_esdt(); + // callback is called with ESDTTransfer of the newly issued token, with the amount requested, + // 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_error_message().clear(); + }, + ManagedAsyncCallResult::Err(message) => { + // return issue cost to the caller + if token_identifier.is_egld() && returned_tokens > 0 { + self.send().direct_egld(caller, &returned_tokens); + } + + self.last_error_message().set(&message.err_msg); + }, + } + } + + #[endpoint] + fn local_mint(&self, token_identifier: TokenIdentifier, amount: BigUint) { + self.send().esdt_local_mint(&token_identifier, 0, &amount); + } + + #[endpoint] + fn local_burn(&self, token_identifier: TokenIdentifier, amount: BigUint) { + self.send().esdt_local_burn(&token_identifier, 0, &amount); + } + + #[view] + fn get_esdt_local_roles(&self, token_id: TokenIdentifier) -> MultiValueEncoded { + let roles = self.blockchain().get_esdt_local_roles(&token_id); + let mut result = MultiValueEncoded::new(); + for role in roles.iter_roles() { + result.push(role.as_role_name().into()); + } + result + } + + #[view] + fn get_esdt_token_data( + &self, + address: ManagedAddress, + token_id: TokenIdentifier, + nonce: u64, + ) -> EsdtTokenDataMultiValue { + let token_data = self + .blockchain() + .get_esdt_token_data(&address, &token_id, nonce); + + ( + token_data.token_type, + token_data.amount, + token_data.frozen, + token_data.hash, + token_data.name, + token_data.attributes, + token_data.creator, + token_data.royalties, + token_data.uris, + ) + .into() + } + + #[view] + fn is_esdt_frozen( + &self, + address: &ManagedAddress, + token_id: &TokenIdentifier, + nonce: u64, + ) -> bool { + self.blockchain().is_esdt_frozen(address, token_id, nonce) + } + + #[view] + fn is_esdt_paused(&self, token_id: &TokenIdentifier) -> bool { + self.blockchain().is_esdt_paused(token_id) + } + + #[view] + fn is_esdt_limited_transfer(&self, token_id: &TokenIdentifier) -> bool { + self.blockchain().is_esdt_limited_transfer(token_id) + } + + #[view] + fn validate_token_identifier(&self, token_id: TokenIdentifier) -> bool { + token_id.is_valid_esdt_identifier() + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/forwarder_legacy_main.rs b/contracts/feature-tests/composability/forwarder-legacy/src/forwarder_legacy_main.rs new file mode 100644 index 0000000000..feae6a9965 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/forwarder_legacy_main.rs @@ -0,0 +1,41 @@ +#![no_std] +#![allow(clippy::type_complexity)] +#![allow(clippy::let_unit_value)] + +pub mod call_async_legacy; +pub mod call_sync_legacy; +pub mod call_transf_exec_legacy; +pub mod contract_change_owner_legacy; +pub mod contract_deploy_legacy; +pub mod contract_upgrade_legacy; +pub mod esdt_legacy; +pub mod nft_legacy; +pub mod roles_legacy; +pub mod sft_legacy; +pub mod storage_legacy; + +multiversx_sc::imports!(); + +/// Test contract for investigating backwards compatibility in smart contract calls. +#[multiversx_sc::contract] +pub trait ForwarderLegacy: + call_sync_legacy::ForwarderSyncCallModule + + call_async_legacy::ForwarderAsyncCallModule + + call_transf_exec_legacy::ForwarderTransferExecuteModule + + contract_change_owner_legacy::ChangeOwnerModule + + contract_deploy_legacy::DeployContractModule + + contract_upgrade_legacy::UpgradeContractModule + + esdt_legacy::ForwarderEsdtModule + + sft_legacy::ForwarderSftModule + + nft_legacy::ForwarderNftModule + + roles_legacy::ForwarderRolesModule + + storage_legacy::ForwarderStorageModule +{ + #[init] + fn init(&self) {} + + #[endpoint] + fn send_egld(&self, to: &ManagedAddress, amount: &BigUint) { + self.send().direct_egld(to, amount); + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/nft_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/nft_legacy.rs new file mode 100644 index 0000000000..91fc37d85f --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/nft_legacy.rs @@ -0,0 +1,296 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use super::storage_legacy; + +// used as mock attributes for NFTs +#[derive(TopEncode, TopDecode, TypeAbi, Clone, Copy, PartialEq, Debug)] +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, +} + +#[derive(TopEncode, TopDecode, TypeAbi, PartialEq, Eq, Clone)] +pub struct ComplexAttributes { + pub biguint: BigUint, + pub vec_u8: ManagedBuffer, + pub token_id: TokenIdentifier, + pub boolean: bool, + pub boxed_bytes: ManagedBuffer, +} + +#[multiversx_sc::module] +pub trait ForwarderNftModule: storage_legacy::ForwarderStorageModule { + #[view] + fn get_nft_balance(&self, token_identifier: &TokenIdentifier, nonce: u64) -> BigUint { + self.blockchain().get_esdt_balance( + &self.blockchain().get_sc_address(), + token_identifier, + nonce, + ) + } + + #[payable("*")] + #[endpoint] + fn buy_nft(&self, nft_id: TokenIdentifier, nft_nonce: u64, nft_amount: BigUint) -> BigUint { + let payment = self.call_value().egld_or_single_esdt(); + + self.send().sell_nft( + &nft_id, + nft_nonce, + &nft_amount, + &self.blockchain().get_caller(), + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ) + } + + #[payable("EGLD")] + #[endpoint] + fn nft_issue(&self, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer) { + let issue_cost = self.call_value().egld_value(); + let caller = self.blockchain().get_caller(); + + self.send() + .esdt_system_sc_proxy() + .issue_non_fungible( + issue_cost.clone_value(), + &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, + }, + ) + .async_call() + .with_callback(self.callbacks().nft_issue_callback(&caller)) + .call_and_exit() + } + + #[callback] + fn nft_issue_callback( + &self, + caller: &ManagedAddress, + #[call_result] result: ManagedAsyncCallResult, + ) { + match result { + ManagedAsyncCallResult::Ok(token_identifier) => { + self.last_issued_token().set(&token_identifier); + self.last_error_message().clear(); + }, + ManagedAsyncCallResult::Err(message) => { + // return issue cost to the caller + let (token_identifier, returned_tokens) = + self.call_value().egld_or_single_fungible_esdt(); + if token_identifier.is_egld() && returned_tokens > 0 { + self.send().direct_egld(caller, &returned_tokens); + } + + self.last_error_message().set(&message.err_msg); + }, + } + } + + #[endpoint] + fn nft_create( + &self, + token_identifier: TokenIdentifier, + amount: BigUint, + name: ManagedBuffer, + royalties: BigUint, + hash: ManagedBuffer, + color: Color, + uri: ManagedBuffer, + ) -> u64 { + let mut uris = ManagedVec::new(); + uris.push(uri); + let token_nonce = self.send().esdt_nft_create::( + &token_identifier, + &amount, + &name, + &royalties, + &hash, + &color, + &uris, + ); + + self.create_event(&token_identifier, token_nonce, &amount); + + token_nonce + } + + #[endpoint] + fn nft_create_compact(&self, token_identifier: TokenIdentifier, amount: BigUint, color: Color) { + self.send() + .esdt_nft_create_compact(&token_identifier, &amount, &color); + } + + #[endpoint] + fn nft_add_uris( + &self, + token_identifier: TokenIdentifier, + nonce: u64, + uris: MultiValueEncoded, + ) { + self.send() + .nft_add_multiple_uri(&token_identifier, nonce, &uris.to_vec()); + } + + #[endpoint] + fn nft_update_attributes( + &self, + token_identifier: TokenIdentifier, + nonce: u64, + new_attributes: Color, + ) { + self.send() + .nft_update_attributes(&token_identifier, nonce, &new_attributes); + } + + #[endpoint] + fn nft_decode_complex_attributes( + &self, + token_identifier: TokenIdentifier, + amount: BigUint, + name: ManagedBuffer, + royalties: BigUint, + hash: ManagedBuffer, + uri: ManagedBuffer, + attrs_arg: MultiValue5, + ) { + let attrs_pieces = attrs_arg.into_tuple(); + let orig_attr = ComplexAttributes { + biguint: attrs_pieces.0, + vec_u8: attrs_pieces.1, + token_id: attrs_pieces.2, + boolean: attrs_pieces.3, + boxed_bytes: attrs_pieces.4, + }; + + let mut uris = ManagedVec::new(); + uris.push(uri); + let token_nonce = self.send().esdt_nft_create::>( + &token_identifier, + &amount, + &name, + &royalties, + &hash, + &orig_attr, + &uris, + ); + + let token_info = self.blockchain().get_esdt_token_data( + &self.blockchain().get_sc_address(), + &token_identifier, + token_nonce, + ); + + let decoded_attr = token_info.decode_attributes::>(); + + require!( + orig_attr.biguint == decoded_attr.biguint + && orig_attr.vec_u8 == decoded_attr.vec_u8 + && orig_attr.token_id == decoded_attr.token_id + && orig_attr.boolean == decoded_attr.boolean + && orig_attr.boxed_bytes == decoded_attr.boxed_bytes, + "orig_attr != decoded_attr" + ); + } + + #[endpoint] + fn nft_add_quantity(&self, token_identifier: TokenIdentifier, nonce: u64, amount: BigUint) { + self.send() + .esdt_local_mint(&token_identifier, nonce, &amount); + } + + #[endpoint] + fn nft_burn(&self, token_identifier: TokenIdentifier, nonce: u64, amount: BigUint) { + self.send() + .esdt_local_burn(&token_identifier, nonce, &amount); + } + + #[endpoint] + fn transfer_nft_via_async_call( + &self, + to: ManagedAddress, + token_identifier: TokenIdentifier, + nonce: u64, + amount: BigUint, + ) { + self.send() + .transfer_esdt_via_async_call(to, token_identifier, nonce, amount); + } + + #[endpoint] + fn transfer_nft_and_execute( + &self, + to: ManagedAddress, + token_identifier: TokenIdentifier, + nonce: u64, + amount: BigUint, + function: ManagedBuffer, + arguments: MultiValueEncoded, + ) { + let _ = self.send_raw().transfer_esdt_nft_execute( + &to, + &token_identifier, + nonce, + &amount, + self.blockchain().get_gas_left(), + &function, + &arguments.to_arg_buffer(), + ); + } + + #[endpoint] + fn create_and_send( + &self, + to: ManagedAddress, + token_identifier: TokenIdentifier, + amount: BigUint, + name: ManagedBuffer, + royalties: BigUint, + hash: ManagedBuffer, + color: Color, + uri: ManagedBuffer, + ) { + let token_nonce = self.nft_create( + token_identifier.clone(), + amount.clone(), + name, + royalties, + hash, + color, + uri, + ); + + self.send() + .direct_esdt(&to, &token_identifier, token_nonce, &amount); + + self.send_event(&to, &token_identifier, token_nonce, &amount); + } + + #[event("create")] + fn create_event( + &self, + #[indexed] token_id: &TokenIdentifier, + #[indexed] token_nonce: u64, + #[indexed] amount: &BigUint, + ); + + #[event("send")] + fn send_event( + &self, + #[indexed] to: &ManagedAddress, + #[indexed] token_id: &TokenIdentifier, + #[indexed] token_nonce: u64, + #[indexed] amount: &BigUint, + ); +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/roles_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/roles_legacy.rs new file mode 100644 index 0000000000..9c795bfa7b --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/roles_legacy.rs @@ -0,0 +1,48 @@ +multiversx_sc::imports!(); + +use super::storage_legacy; + +#[multiversx_sc::module] +pub trait ForwarderRolesModule: storage_legacy::ForwarderStorageModule { + #[endpoint(setLocalRoles)] + fn set_local_roles( + &self, + address: ManagedAddress, + token_identifier: TokenIdentifier, + roles: MultiValueEncoded, + ) { + self.send() + .esdt_system_sc_proxy() + .set_special_roles(&address, &token_identifier, roles.into_iter()) + .async_call() + .with_callback(self.callbacks().change_roles_callback()) + .call_and_exit() + } + + #[endpoint(unsetLocalRoles)] + fn unset_local_roles( + &self, + address: ManagedAddress, + token_identifier: TokenIdentifier, + roles: MultiValueEncoded, + ) { + self.send() + .esdt_system_sc_proxy() + .unset_special_roles(&address, &token_identifier, roles.into_iter()) + .async_call() + .with_callback(self.callbacks().change_roles_callback()) + .call_and_exit() + } + + #[callback] + fn change_roles_callback(&self, #[call_result] result: ManagedAsyncCallResult<()>) { + match result { + ManagedAsyncCallResult::Ok(()) => { + self.last_error_message().clear(); + }, + ManagedAsyncCallResult::Err(message) => { + self.last_error_message().set(&message.err_msg); + }, + } + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/sft_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/sft_legacy.rs new file mode 100644 index 0000000000..4b0a5c2f3c --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/sft_legacy.rs @@ -0,0 +1,57 @@ +multiversx_sc::imports!(); + +use super::storage_legacy; + +#[multiversx_sc::module] +pub trait ForwarderSftModule: storage_legacy::ForwarderStorageModule { + #[payable("EGLD")] + #[endpoint] + fn sft_issue(&self, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer) { + let issue_cost = self.call_value().egld_value(); + let caller = self.blockchain().get_caller(); + + self.send() + .esdt_system_sc_proxy() + .issue_semi_fungible( + issue_cost.clone_value(), + &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, + }, + ) + .async_call() + .with_callback(self.callbacks().sft_issue_callback(&caller)) + .call_and_exit() + } + + #[callback] + fn sft_issue_callback( + &self, + caller: &ManagedAddress, + #[call_result] result: ManagedAsyncCallResult, + ) { + match result { + ManagedAsyncCallResult::Ok(token_identifier) => { + self.last_issued_token().set(&token_identifier); + self.last_error_message().clear(); + }, + ManagedAsyncCallResult::Err(message) => { + // return issue cost to the caller + let (token_identifier, returned_tokens) = + self.call_value().egld_or_single_fungible_esdt(); + if token_identifier.is_egld() && returned_tokens > 0 { + self.send().direct_egld(caller, &returned_tokens); + } + + self.last_error_message().set(&message.err_msg); + }, + } + } +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/src/storage_legacy.rs b/contracts/feature-tests/composability/forwarder-legacy/src/storage_legacy.rs new file mode 100644 index 0000000000..f27887b63f --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/src/storage_legacy.rs @@ -0,0 +1,12 @@ +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait ForwarderStorageModule { + #[view(lastIssuedToken)] + #[storage_mapper("lastIssuedToken")] + fn last_issued_token(&self) -> SingleValueMapper; + + #[view(lastErrorMessage)] + #[storage_mapper("lastErrorMessage")] + fn last_error_message(&self) -> SingleValueMapper; +} diff --git a/contracts/feature-tests/composability/forwarder-legacy/wasm/Cargo.lock b/contracts/feature-tests/composability/forwarder-legacy/wasm/Cargo.lock new file mode 100644 index 0000000000..6f2efbb4a7 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/wasm/Cargo.lock @@ -0,0 +1,178 @@ +# 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.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "forwarder-legacy" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "vault", +] + +[[package]] +name = "forwarder-legacy-wasm" +version = "0.0.0" +dependencies = [ + "forwarder-legacy", + "multiversx-sc-wasm-adapter", +] + +[[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.49.0-alpha.4" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.18.6" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.18.6" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.49.0-alpha.4" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.49.0-alpha.4" +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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +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.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +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 = "vault" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] diff --git a/contracts/feature-tests/composability/forwarder-legacy/wasm/Cargo.toml b/contracts/feature-tests/composability/forwarder-legacy/wasm/Cargo.toml new file mode 100644 index 0000000000..3ce5ef1de3 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/wasm/Cargo.toml @@ -0,0 +1,32 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "forwarder-legacy-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 + +[dependencies.forwarder-legacy] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.49.0-alpha.4" +path = "../../../../../framework/wasm-adapter" + +[workspace] +members = ["."] diff --git a/contracts/feature-tests/composability/forwarder-legacy/wasm/src/lib.rs b/contracts/feature-tests/composability/forwarder-legacy/wasm/src/lib.rs new file mode 100644 index 0000000000..180b626b66 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder-legacy/wasm/src/lib.rs @@ -0,0 +1,94 @@ +// Code generated by the multiversx-sc build system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Endpoints: 68 +// Async Callback: 1 +// Total number of exported functions: 70 + +#![no_std] +#![allow(internal_features)] +#![feature(lang_items)] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + forwarder_legacy + ( + init => init + send_egld => send_egld + echo_arguments_sync => echo_arguments_sync + echo_arguments_sync_twice => echo_arguments_sync_twice + forward_sync_accept_funds => forward_sync_accept_funds + forward_sync_accept_funds_with_fees => forward_sync_accept_funds_with_fees + forward_sync_accept_funds_then_read => forward_sync_accept_funds_then_read + forward_sync_retrieve_funds => forward_sync_retrieve_funds + forward_sync_retrieve_funds_with_accept_func => forward_sync_retrieve_funds_with_accept_func + accept_funds_func => accept_funds_func + forward_sync_accept_funds_multi_transfer => forward_sync_accept_funds_multi_transfer + echo_args_async => echo_args_async + forward_async_accept_funds => forward_async_accept_funds + forward_async_accept_funds_half_payment => forward_async_accept_funds_half_payment + forward_async_accept_funds_with_fees => forward_async_accept_funds_with_fees + forward_async_retrieve_funds => forward_async_retrieve_funds + send_funds_twice => send_funds_twice + send_async_accept_multi_transfer => send_async_accept_multi_transfer + callback_data => callback_data + callback_data_at_index => callback_data_at_index + clear_callback_data => clear_callback_data + forward_transf_exec_accept_funds => forward_transf_exec_accept_funds + forward_transf_exec_accept_single_esdt => forward_transf_exec_accept_single_esdt + forward_transf_execu_accept_funds_with_fees => forward_transf_execu_accept_funds_with_fees + forward_transf_exec_accept_funds_twice => forward_transf_exec_accept_funds_twice + forward_transf_exec_accept_funds_return_values => forward_transf_exec_accept_funds_return_values + transf_exec_multi_accept_funds => transf_exec_multi_accept_funds + transf_exec_multi_accept_funds_v2 => transf_exec_multi_accept_funds_v2 + forward_transf_exec_reject_funds_multi_transfer => forward_transf_exec_reject_funds_multi_transfer + transf_exec_multi_reject_funds => transf_exec_multi_reject_funds + changeOwnerAddress => change_owner + deploy_contract => deploy_contract + deploy_two_contracts => deploy_two_contracts + deploy_vault_from_source => deploy_vault_from_source + upgradeVault => upgrade_vault + upgrade_vault_from_source => upgrade_vault_from_source + getFungibleEsdtBalance => get_fungible_esdt_balance + getCurrentNftNonce => get_current_nft_nonce + send_esdt => send_esdt + send_esdt_with_fees => send_esdt_with_fees + send_esdt_twice => send_esdt_twice + send_esdt_direct_multi_transfer => send_esdt_direct_multi_transfer + issue_fungible_token => issue_fungible_token + local_mint => local_mint + local_burn => local_burn + get_esdt_local_roles => get_esdt_local_roles + get_esdt_token_data => get_esdt_token_data + is_esdt_frozen => is_esdt_frozen + is_esdt_paused => is_esdt_paused + is_esdt_limited_transfer => is_esdt_limited_transfer + validate_token_identifier => validate_token_identifier + sft_issue => sft_issue + get_nft_balance => get_nft_balance + buy_nft => buy_nft + nft_issue => nft_issue + nft_create => nft_create + nft_create_compact => nft_create_compact + nft_add_uris => nft_add_uris + nft_update_attributes => nft_update_attributes + nft_decode_complex_attributes => nft_decode_complex_attributes + nft_add_quantity => nft_add_quantity + nft_burn => nft_burn + transfer_nft_via_async_call => transfer_nft_via_async_call + transfer_nft_and_execute => transfer_nft_and_execute + create_and_send => create_and_send + setLocalRoles => set_local_roles + unsetLocalRoles => unset_local_roles + lastIssuedToken => last_issued_token + lastErrorMessage => last_error_message + ) +} + +multiversx_sc_wasm_adapter::async_callback! { forwarder_legacy } diff --git a/contracts/feature-tests/composability/forwarder-queue/Cargo.toml b/contracts/feature-tests/composability/forwarder-queue/Cargo.toml index f2cd325c08..accf0696e9 100644 --- a/contracts/feature-tests/composability/forwarder-queue/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-queue/Cargo.toml @@ -8,18 +8,15 @@ publish = false [lib] path = "src/forwarder_queue.rs" -[dependencies.vault] -path = "../vault" - [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" optional = true [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/forwarder-queue/meta/Cargo.toml b/contracts/feature-tests/composability/forwarder-queue/meta/Cargo.toml index 32d7cb6aa8..6347cdc858 100644 --- a/contracts/feature-tests/composability/forwarder-queue/meta/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-queue/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/forwarder-queue/src/forwarder_queue.rs b/contracts/feature-tests/composability/forwarder-queue/src/forwarder_queue.rs index 66595bc54f..376fc61d76 100644 --- a/contracts/feature-tests/composability/forwarder-queue/src/forwarder_queue.rs +++ b/contracts/feature-tests/composability/forwarder-queue/src/forwarder_queue.rs @@ -172,30 +172,27 @@ pub trait ForwarderQueue { }, }; - let contract_call = ContractCallWithAnyPayment::<_, ()>::new( - call.to, - call.endpoint_name, - call.payments, - ); + let contract_call = self + .tx() + .raw_call(call.endpoint_name) + .to(&call.to) + .payment(&call.payments); match call.call_type { QueuedCallType::Sync => { - contract_call.execute_on_dest_context::<()>(); + contract_call.sync_call(); }, QueuedCallType::LegacyAsync => { - contract_call.async_call().call_and_exit(); + contract_call.async_call_and_exit(); }, QueuedCallType::TransferExecute => { - contract_call - .with_gas_limit(call.gas_limit) - .transfer_execute(); + contract_call.gas(call.gas_limit).transfer_execute(); }, QueuedCallType::Promise => { contract_call - .with_gas_limit(call.gas_limit) - .with_raw_arguments(call.args) - .async_call_promise() - .with_callback(self.callbacks().promises_callback_method()) + .gas(call.gas_limit) + .arguments_raw(call.args) + .callback(self.callbacks().promises_callback_method()) .register_promise(); }, } @@ -208,10 +205,13 @@ pub trait ForwarderQueue { self.callback_count().update(|c| *c += 1); let payments = self.call_value().any_payment(); - let payments_data_string = - ContractCallNoPayment::<_, ()>::new(ManagedAddress::default(), ManagedBuffer::new()) - .with_any_payment(payments) - .into_call_data_string(); + let payments_data_string = self + .tx() + .to(&ManagedAddress::default()) + .payment(payments) + .raw_call("") + .to_call_data_string(); + self.callback_payments().set(payments_data_string); } diff --git a/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.lock b/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.lock index f05e7a0cdd..345df6ab7c 100644 --- a/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.lock +++ b/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.lock @@ -31,7 +31,6 @@ name = "forwarder-queue" version = "0.0.0" dependencies = [ "multiversx-sc", - "vault", ] [[package]] @@ -56,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] @@ -169,10 +168,3 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "vault" -version = "0.0.0" -dependencies = [ - "multiversx-sc", -] diff --git a/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.toml b/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.toml index 6fdabaefda..ea15c56706 100644 --- a/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-queue/wasm-forwarder-queue-promises/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.lock b/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.lock index bd11942252..618aeb9569 100644 --- a/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.lock @@ -31,7 +31,6 @@ name = "forwarder-queue" version = "0.0.0" dependencies = [ "multiversx-sc", - "vault", ] [[package]] @@ -56,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] @@ -169,10 +168,3 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "vault" -version = "0.0.0" -dependencies = [ - "multiversx-sc", -] diff --git a/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.toml b/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.toml index be9b3a7549..ae6dab9b35 100644 --- a/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-queue/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/forwarder-raw/Cargo.toml b/contracts/feature-tests/composability/forwarder-raw/Cargo.toml index 134cb94004..98838bf0e4 100644 --- a/contracts/feature-tests/composability/forwarder-raw/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-raw/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/forwarder_raw.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/forwarder-raw/meta/Cargo.toml b/contracts/feature-tests/composability/forwarder-raw/meta/Cargo.toml index d700ea2a51..221d44e4eb 100644 --- a/contracts/feature-tests/composability/forwarder-raw/meta/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-raw/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_alt_init.rs b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_alt_init.rs index 79cab17a11..f00a10d434 100644 --- a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_alt_init.rs +++ b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_alt_init.rs @@ -17,11 +17,11 @@ pub trait ForwarderRawAlterativeInit: super::forwarder_raw_common::ForwarderRawC endpoint_name: ManagedBuffer, args: MultiValueEncoded, ) { - self.send() - .contract_call::<()>(to, endpoint_name) - .with_raw_arguments(args.to_arg_buffer()) - .async_call() - .call_and_exit(); + self.tx() + .to(&to) + .raw_call(endpoint_name) + .arguments_raw(args.to_arg_buffer()) + .async_call_and_exit(); } /// Will not work, only written for VM testing. @@ -29,7 +29,7 @@ pub trait ForwarderRawAlterativeInit: super::forwarder_raw_common::ForwarderRawC /// Async calls are explicitly forbidden in upgrade constructors. /// /// TODO: write test once scenario tests support upgrades directly. - #[endpoint(upgrade)] + #[upgrade] #[label("init-async-call")] fn upgrade_async_call( &self, @@ -54,13 +54,16 @@ pub trait ForwarderRawAlterativeInit: super::forwarder_raw_common::ForwarderRawC ) { let payment = self.call_value().egld_value(); let half_gas = self.blockchain().get_gas_left() / 2; - let result = self.send_raw().execute_on_dest_context_raw( - half_gas, - &to, - &payment, - &endpoint_name, - &args.to_arg_buffer(), - ); + + let result = self + .tx() + .to(&to) + .gas(half_gas) + .egld(payment) + .raw_call(endpoint_name) + .arguments_raw(args.to_arg_buffer()) + .returns(ReturnsRawResult) + .sync_call(); self.execute_on_dest_context_result(result); } diff --git a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_async.rs b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_async.rs index 25d8868298..e43ef13603 100644 --- a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_async.rs +++ b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_async.rs @@ -6,21 +6,27 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { #[payable("*")] fn forward_payment(&self, to: ManagedAddress) { let (token, payment) = self.call_value().egld_or_single_fungible_esdt(); - self.send().direct(&to, &token, 0, &payment); + self.tx() + .to(to) + .egld_or_single_esdt(&token, 0, &payment) + .transfer(); } #[endpoint] #[payable("*")] fn forward_direct_esdt_via_transf_exec(&self, to: ManagedAddress) { let (token, payment) = self.call_value().single_fungible_esdt(); - self.send().direct_esdt(&to, &token, 0, &payment); + self.tx() + .to(&to) + .single_esdt(&token, 0, &payment) + .transfer(); } #[endpoint] #[payable("*")] fn forward_direct_esdt_multi(&self, to: ManagedAddress) { let payments = self.call_value().all_esdt_transfers(); - self.send().direct_multi(&to, &payments); + self.tx().to(&to).payment(payments).transfer(); } fn forward_contract_call( @@ -30,11 +36,24 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { payment_amount: BigUint, endpoint_name: ManagedBuffer, args: MultiValueEncoded, - ) -> ContractCallWithEgldOrSingleEsdt { - self.send() - .contract_call(to, endpoint_name) - .with_raw_arguments(args.to_arg_buffer()) - .with_egld_or_single_esdt_transfer((payment_token, 0, payment_amount)) + ) -> Tx< + TxScEnv, + (), + ManagedAddress, + EgldOrEsdtTokenPayment, + (), + FunctionCall, + (), + > { + self.tx() + .to(to) + .raw_call(endpoint_name) + .arguments_raw(args.to_arg_buffer()) + .payment(EgldOrEsdtTokenPayment::new( + payment_token, + 0, + payment_amount, + )) } #[endpoint] @@ -82,7 +101,7 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { endpoint_name, args, ) - .with_gas_limit(self.blockchain().get_gas_left() / 2) + .gas(self.blockchain().get_gas_left() / 2) .transfer_execute(); } @@ -102,7 +121,7 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { endpoint_name, args, ) - .with_gas_limit(self.blockchain().get_gas_left() / 2) + .gas(self.blockchain().get_gas_left() / 2) .transfer_execute(); } @@ -116,7 +135,7 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { ) { let (token, payment) = self.call_value().egld_or_single_fungible_esdt(); self.forward_contract_call(to, token, payment, endpoint_name, args) - .with_gas_limit(self.blockchain().get_gas_left() / 2) + .gas(self.blockchain().get_gas_left() / 2) .transfer_execute(); } @@ -137,10 +156,10 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { endpoint_name.clone(), args.clone(), ) - .with_gas_limit(self.blockchain().get_gas_left() / 2) + .gas(self.blockchain().get_gas_left() / 2) .transfer_execute(); self.forward_contract_call(to, token, half_payment, endpoint_name, args) - .with_gas_limit(self.blockchain().get_gas_left() / 2) + .gas(self.blockchain().get_gas_left() / 2) .transfer_execute(); } @@ -159,12 +178,11 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { arg_buffer.push_arg(amount); } - self.send_raw().async_call_raw( - &to, - &BigUint::zero(), - &ManagedBuffer::from(&b"retrieve_multi_funds_async"[..]), - &arg_buffer, - ); + self.tx() + .to(&to) + .raw_call("retrieve_multi_funds_async") + .arguments_raw(arg_buffer) + .async_call_and_exit(); } #[endpoint] @@ -180,12 +198,10 @@ pub trait ForwarderRawAsync: super::forwarder_raw_common::ForwarderRawCommon { all_payments.push(EsdtTokenPayment::new(token_identifier, token_nonce, amount)); } - ContractCallWithMultiEsdt::::new( - to, - "burn_and_create_retrive_async", - all_payments, - ) - .async_call() - .call_and_exit_ignore_callback() + self.tx() + .raw_call("burn_and_create_retrieve_async") + .to(&to) + .payment(&all_payments) + .async_call_and_exit() } } diff --git a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_deploy_upgrade.rs b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_deploy_upgrade.rs index 1f89186e0e..803119c140 100644 --- a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_deploy_upgrade.rs +++ b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_deploy_upgrade.rs @@ -9,14 +9,15 @@ pub trait ForwarderRawDeployUpgrade { code_metadata: CodeMetadata, args: MultiValueEncoded, ) -> MultiValue2> { - self.send_raw() - .deploy_contract( - self.blockchain().get_gas_left(), - &BigUint::zero(), - &code, - code_metadata, - &args.to_arg_buffer(), - ) + self.tx() + .raw_deploy() + .code(code) + .code_metadata(code_metadata) + .arguments_raw(args.to_arg_buffer()) + .gas(self.blockchain().get_gas_left()) + .returns(ReturnsNewManagedAddress) + .returns(ReturnsRawResult) + .sync_call() .into() } @@ -25,35 +26,33 @@ pub trait ForwarderRawDeployUpgrade { &self, source_contract_address: ManagedAddress, code_metadata: CodeMetadata, - arguments: MultiValueEncoded, + args: MultiValueEncoded, ) -> ManagedAddress { - let (address, _) = self.send_raw().deploy_from_source_contract( - self.blockchain().get_gas_left(), - &BigUint::zero(), - &source_contract_address, - code_metadata, - &arguments.to_arg_buffer(), - ); - - address + self.tx() + .raw_deploy() + .from_source(source_contract_address) + .code_metadata(code_metadata) + .arguments_raw(args.to_arg_buffer()) + .gas(self.blockchain().get_gas_left()) + .returns(ReturnsNewManagedAddress) + .sync_call() } #[endpoint] fn call_upgrade( &self, - child_sc_address: &ManagedAddress, - new_code: &ManagedBuffer, + child_sc_address: ManagedAddress, + new_code: ManagedBuffer, code_metadata: CodeMetadata, - arguments: MultiValueEncoded, + args: MultiValueEncoded, ) { - self.send_raw().upgrade_contract( - child_sc_address, - self.blockchain().get_gas_left(), - &BigUint::zero(), - new_code, - code_metadata, - &arguments.to_arg_buffer(), - ); + self.tx() + .to(child_sc_address) + .raw_upgrade() + .code(new_code) + .code_metadata(code_metadata) + .arguments_raw(args.to_arg_buffer()) + .upgrade_async_call_and_exit(); } #[endpoint] @@ -62,15 +61,15 @@ pub trait ForwarderRawDeployUpgrade { sc_address: ManagedAddress, source_contract_address: ManagedAddress, code_metadata: CodeMetadata, - arguments: MultiValueEncoded, + args: MultiValueEncoded, ) { - self.send_raw().upgrade_from_source_contract( - &sc_address, - self.blockchain().get_gas_left(), - &BigUint::zero(), - &source_contract_address, - code_metadata, - &arguments.to_arg_buffer(), - ) + self.tx() + .to(sc_address) + .raw_upgrade() + .from_source(source_contract_address) + .code_metadata(code_metadata) + .arguments_raw(args.to_arg_buffer()) + .gas(self.blockchain().get_gas_left()) + .upgrade_async_call_and_exit(); } } diff --git a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_sync.rs b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_sync.rs index d01245ca59..799ce0cb83 100644 --- a/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_sync.rs +++ b/contracts/feature-tests/composability/forwarder-raw/src/forwarder_raw_sync.rs @@ -10,15 +10,17 @@ pub trait ForwarderRawSync: super::forwarder_raw_common::ForwarderRawCommon { endpoint_name: ManagedBuffer, args: MultiValueEncoded, ) { - let payment = self.call_value().egld_value(); + let payment = self.call_value().egld_value().clone_value(); let half_gas = self.blockchain().get_gas_left() / 2; - let result = self.send_raw().execute_on_dest_context_raw( - half_gas, - &to, - &payment, - &endpoint_name, - &args.to_arg_buffer(), - ); + let result = self + .tx() + .to(to) + .egld(payment) + .raw_call(endpoint_name) + .argument(&args) + .gas(half_gas) + .returns(ReturnsRawResult) + .sync_call(); self.execute_on_dest_context_result(result); } @@ -36,22 +38,28 @@ pub trait ForwarderRawSync: super::forwarder_raw_common::ForwarderRawCommon { let half_payment = &*payment / 2u32; let arg_buffer = args.to_arg_buffer(); - let result = self.send_raw().execute_on_dest_context_raw( - one_third_gas, - &to, - &half_payment, - &endpoint_name, - &arg_buffer, - ); + let result = self + .tx() + .to(&to) + .gas(one_third_gas) + .egld(&half_payment) + .raw_call(endpoint_name.clone()) + .arguments_raw(arg_buffer.clone()) + .returns(ReturnsRawResult) + .sync_call(); + self.execute_on_dest_context_result(result); - let result = self.send_raw().execute_on_dest_context_raw( - one_third_gas, - &to, - &half_payment, - &endpoint_name, - &arg_buffer, - ); + let result = self + .tx() + .to(&to) + .gas(one_third_gas) + .egld(&half_payment) + .raw_call(endpoint_name) + .arguments_raw(arg_buffer) + .returns(ReturnsRawResult) + .sync_call(); + self.execute_on_dest_context_result(result); } @@ -65,13 +73,16 @@ pub trait ForwarderRawSync: super::forwarder_raw_common::ForwarderRawCommon { ) { let payment = self.call_value().egld_value(); let half_gas = self.blockchain().get_gas_left() / 2; - let result = self.send_raw().execute_on_same_context_raw( - half_gas, - &to, - &payment, - &endpoint_name, - &args.to_arg_buffer(), - ); + + let result = self + .tx() + .to(&to) + .gas(half_gas) + .egld(payment) + .raw_call(endpoint_name) + .arguments_raw(args.to_arg_buffer()) + .returns(ReturnsRawResult) + .sync_call_same_context(); self.execute_on_same_context_result(result); } @@ -84,12 +95,14 @@ pub trait ForwarderRawSync: super::forwarder_raw_common::ForwarderRawCommon { args: MultiValueEncoded, ) { let half_gas = self.blockchain().get_gas_left() / 2; - let result = self.send_raw().execute_on_dest_context_readonly_raw( - half_gas, - &to, - &endpoint_name, - &args.to_arg_buffer(), - ); + let result = self + .tx() + .to(&to) + .gas(half_gas) + .raw_call(endpoint_name) + .arguments_raw(args.to_arg_buffer()) + .returns(ReturnsRawResult) + .sync_call_readonly(); self.execute_on_dest_context_result(result); } diff --git a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.lock b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.lock index 3cbb66650a..4efcd69b75 100644 --- a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.lock +++ b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.toml b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.toml index 8ab31ee41b..208dcd4d05 100644 --- a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/src/lib.rs b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/src/lib.rs index 01c9657fd7..cd1297b69f 100644 --- a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/src/lib.rs +++ b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-async-call/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 1 +// Upgrade: 1 +// Endpoints: 0 // Async Callback: 1 // Total number of exported functions: 3 diff --git a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.lock b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.lock index 0854d75c17..5eebcf9076 100644 --- a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.lock +++ b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.toml b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.toml index b8e486edb7..5b4c266c48 100644 --- a/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-raw/wasm-forwarder-raw-init-sync-call/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.lock b/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.lock index 01e46ccd34..25b4034e97 100755 --- a/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.toml b/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.toml index 5b5c0108b2..63cfbfed3b 100644 --- a/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder-raw/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/forwarder/Cargo.toml b/contracts/feature-tests/composability/forwarder/Cargo.toml index f8aa438588..6790cc028c 100644 --- a/contracts/feature-tests/composability/forwarder/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder/Cargo.toml @@ -8,14 +8,11 @@ publish = false [lib] path = "src/forwarder_main.rs" -[dependencies.vault] -path = "../vault" - [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/forwarder/meta/Cargo.toml b/contracts/feature-tests/composability/forwarder/meta/Cargo.toml index d8911c3f1d..a6b2ad50fa 100644 --- a/contracts/feature-tests/composability/forwarder/meta/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/forwarder/sc-config.toml b/contracts/feature-tests/composability/forwarder/sc-config.toml new file mode 100644 index 0000000000..b78f0086a5 --- /dev/null +++ b/contracts/feature-tests/composability/forwarder/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "src/forwarder_proxy.rs" diff --git a/contracts/feature-tests/composability/forwarder/src/call_async.rs b/contracts/feature-tests/composability/forwarder/src/call_async.rs index 8826c2db48..51a751b114 100644 --- a/contracts/feature-tests/composability/forwarder/src/call_async.rs +++ b/contracts/feature-tests/composability/forwarder/src/call_async.rs @@ -1,7 +1,10 @@ +use crate::vault_proxy; + multiversx_sc::imports!(); multiversx_sc::derive_imports!(); -#[derive(TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(TopEncode, TopDecode)] pub struct CallbackData { callback_name: ManagedBuffer, token_identifier: EgldOrEsdtTokenIdentifier, @@ -14,17 +17,14 @@ const PERCENTAGE_TOTAL: u64 = 10_000; // 100% #[multiversx_sc::module] pub trait ForwarderAsyncCallModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] fn echo_args_async(&self, to: ManagedAddress, args: MultiValueEncoded) { - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .echo_arguments(args) - .async_call() - .with_callback(self.callbacks().echo_args_callback()) - .call_and_exit(); + .callback(self.callbacks().echo_args_callback()) + .async_call_and_exit(); } #[callback] @@ -57,10 +57,11 @@ pub trait ForwarderAsyncCallModule { #[payable("*")] fn forward_async_accept_funds(&self, to: ManagedAddress) { let payment = self.call_value().egld_or_single_esdt(); - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer(payment) + .payment(payment) .async_call() .call_and_exit() } @@ -70,14 +71,15 @@ pub trait ForwarderAsyncCallModule { fn forward_async_accept_funds_half_payment(&self, to: ManagedAddress) { let payment = self.call_value().egld_or_single_esdt(); let half_payment = payment.amount / 2u32; - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer(( - payment.token_identifier, + .egld_or_single_esdt( + &payment.token_identifier, payment.token_nonce, - half_payment, - )) + &half_payment, + ) .async_call() .call_and_exit() } @@ -89,16 +91,16 @@ pub trait ForwarderAsyncCallModule { let fees = &payment.amount * &percentage_fees / PERCENTAGE_TOTAL; let amount_to_send = &payment.amount - &fees; - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer(( - payment.token_identifier, + .egld_or_single_esdt( + &payment.token_identifier, payment.token_nonce, - amount_to_send, - )) - .async_call() - .call_and_exit() + &amount_to_send, + ) + .async_call_and_exit(); } #[endpoint] @@ -109,11 +111,12 @@ pub trait ForwarderAsyncCallModule { token_nonce: u64, amount: BigUint, ) { - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds(token, token_nonce, amount) .async_call() - .with_callback(self.callbacks().retrieve_funds_callback()) + .callback(self.callbacks().retrieve_funds_callback()) .call_and_exit() } @@ -146,16 +149,16 @@ pub trait ForwarderAsyncCallModule { token_identifier: &EgldOrEsdtTokenIdentifier, amount: &BigUint, ) { - self.vault_proxy() - .contract(to.clone()) + self.tx() + .to(to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer((token_identifier.clone(), 0, amount.clone())) - .async_call() - .with_callback( + .egld_or_single_esdt(token_identifier, 0u64, amount) + .callback( self.callbacks() .send_funds_twice_callback(to, token_identifier, amount), ) - .call_and_exit() + .async_call_and_exit(); } #[callback] @@ -165,12 +168,12 @@ pub trait ForwarderAsyncCallModule { token_identifier: &EgldOrEsdtTokenIdentifier, cb_amount: &BigUint, ) { - self.vault_proxy() - .contract(to.clone()) + self.tx() + .to(to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer((token_identifier.clone(), 0, cb_amount.clone())) - .async_call() - .call_and_exit() + .egld_or_single_esdt(token_identifier, 0u64, cb_amount) + .async_call_and_exit(); } #[endpoint] @@ -188,12 +191,13 @@ pub trait ForwarderAsyncCallModule { all_token_payments.push(payment); } - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_multi_token_transfer(all_token_payments) + .payment(all_token_payments) .async_call() - .call_and_exit() + .call_and_exit(); } #[view] diff --git a/contracts/feature-tests/composability/forwarder/src/call_sync.rs b/contracts/feature-tests/composability/forwarder/src/call_sync.rs index 67d923936e..13fbcd40db 100644 --- a/contracts/feature-tests/composability/forwarder/src/call_sync.rs +++ b/contracts/feature-tests/composability/forwarder/src/call_sync.rs @@ -1,23 +1,24 @@ +use crate::vault_proxy; + multiversx_sc::imports!(); const PERCENTAGE_TOTAL: u64 = 10_000; // 100% #[multiversx_sc::module] pub trait ForwarderSyncCallModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] #[payable("*")] fn echo_arguments_sync(&self, to: ManagedAddress, args: MultiValueEncoded) { let half_gas = self.blockchain().get_gas_left() / 2; - let result: MultiValueEncoded = self - .vault_proxy() - .contract(to) + let result = self + .tx() + .to(&to) + .gas(half_gas) + .typed(vault_proxy::VaultProxy) .echo_arguments(args) - .with_gas_limit(half_gas) - .execute_on_dest_context(); + .returns(ReturnsResult) + .sync_call(); self.execute_on_dest_context_result_event(&result.into_vec_of_buffers()); } @@ -31,21 +32,25 @@ pub trait ForwarderSyncCallModule { ) { let one_third_gas = self.blockchain().get_gas_left() / 3; - let result: MultiValueEncoded = self - .vault_proxy() - .contract(to.clone()) - .echo_arguments(&args) - .with_gas_limit(one_third_gas) - .execute_on_dest_context(); + let result = self + .tx() + .to(&to) + .gas(one_third_gas) + .typed(vault_proxy::VaultProxy) + .echo_arguments(args.clone()) + .returns(ReturnsResult) + .sync_call(); self.execute_on_dest_context_result_event(&result.into_vec_of_buffers()); - let result: MultiValueEncoded = self - .vault_proxy() - .contract(to) - .echo_arguments(&args) - .with_gas_limit(one_third_gas) - .execute_on_dest_context(); + let result = self + .tx() + .to(&to) + .gas(one_third_gas) + .typed(vault_proxy::VaultProxy) + .echo_arguments(args) + .returns(ReturnsResult) + .sync_call(); self.execute_on_dest_context_result_event(&result.into_vec_of_buffers()); } @@ -59,13 +64,16 @@ pub trait ForwarderSyncCallModule { let payment = self.call_value().egld_or_single_esdt(); let half_gas = self.blockchain().get_gas_left() / 2; - let result: MultiValue2> = self - .vault_proxy() - .contract(to) + let result = self + .tx() + .to(&to) + .gas(half_gas) + .typed(vault_proxy::VaultProxy) .accept_funds_echo_payment() - .with_egld_or_single_esdt_transfer(payment) - .with_gas_limit(half_gas) - .execute_on_dest_context(); + .payment(payment) + .returns(ReturnsResult) + .sync_call(); + let (egld_value, esdt_transfers_multi) = result.into_tuple(); self.accept_funds_sync_result_event(&egld_value, &esdt_transfers_multi); @@ -78,12 +86,13 @@ pub trait ForwarderSyncCallModule { let fees = &payment * &percentage_fees / PERCENTAGE_TOTAL; let amount_to_send = payment - fees; - let () = self - .vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer((token_id, 0, amount_to_send)) - .execute_on_dest_context(); + .egld_or_single_esdt(&token_id, 0u64, &amount_to_send) + .returns(ReturnsResult) + .sync_call(); } #[event("accept_funds_sync_result")] @@ -97,17 +106,19 @@ pub trait ForwarderSyncCallModule { #[payable("*")] fn forward_sync_accept_funds_then_read(&self, to: ManagedAddress) -> usize { let payment = self.call_value().egld_or_single_esdt(); - self.vault_proxy() - .contract(to.clone()) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer(payment) - .execute_on_dest_context::<()>(); + .payment(payment) + .sync_call(); - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .call_counts(b"accept_funds") - .execute_on_dest_context::>() - .into() + .returns(ReturnsResult) + .sync_call() } #[endpoint] @@ -118,10 +129,11 @@ pub trait ForwarderSyncCallModule { token_nonce: u64, amount: BigUint, ) { - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds(token, token_nonce, amount) - .execute_on_dest_context::<()>(); + .sync_call(); } #[payable("*")] @@ -134,15 +146,16 @@ pub trait ForwarderSyncCallModule { ) { let payments = self.call_value().all_esdt_transfers(); - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds_with_transfer_exec( token, amount, OptionalValue::::Some(b"accept_funds_func".into()), ) - .with_multi_token_transfer(payments.clone_value()) - .execute_on_dest_context::<()>(); + .payment(payments) + .sync_call(); } #[payable("*")] @@ -163,11 +176,11 @@ pub trait ForwarderSyncCallModule { all_token_payments.push(payment); } - let () = self - .vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_multi_token_transfer(all_token_payments) - .execute_on_dest_context(); + .payment(all_token_payments) + .sync_call(); } } diff --git a/contracts/feature-tests/composability/forwarder/src/call_transf_exec.rs b/contracts/feature-tests/composability/forwarder/src/call_transf_exec.rs index e402ea5316..952f50275c 100644 --- a/contracts/feature-tests/composability/forwarder/src/call_transf_exec.rs +++ b/contracts/feature-tests/composability/forwarder/src/call_transf_exec.rs @@ -1,20 +1,20 @@ +use crate::vault_proxy; + multiversx_sc::imports!(); const PERCENTAGE_TOTAL: u64 = 10_000; // 100% #[multiversx_sc::module] pub trait ForwarderTransferExecuteModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] #[payable("*")] fn forward_transf_exec_accept_funds(&self, to: ManagedAddress) { let payment = self.call_value().egld_or_single_esdt(); - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer(payment) + .payment(payment) .transfer_execute(); } @@ -29,10 +29,11 @@ pub trait ForwarderTransferExecuteModule { let fees = &payment * &percentage_fees / PERCENTAGE_TOTAL; let amount_to_send = payment - fees; - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer((token_id, 0, amount_to_send)) + .egld_or_single_esdt(&token_id, 0u64, &amount_to_send) .transfer_execute(); } @@ -43,18 +44,20 @@ pub trait ForwarderTransferExecuteModule { let half_payment = payment / 2u32; let half_gas = self.blockchain().get_gas_left() / 2; - self.vault_proxy() - .contract(to.clone()) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer((token.clone(), token_nonce, half_payment.clone())) - .with_gas_limit(half_gas) + .egld_or_single_esdt(&token, token_nonce, &half_payment) + .gas(half_gas) .transfer_execute(); - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer((token, token_nonce, half_payment)) - .with_gas_limit(half_gas) + .egld_or_single_esdt(&token, token_nonce, &half_payment) + .gas(half_gas) .transfer_execute(); } @@ -70,10 +73,11 @@ pub trait ForwarderTransferExecuteModule { let payment_token = payment.token_identifier.clone(); let gas_left_before = self.blockchain().get_gas_left(); - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer(payment) + .payment(payment) .transfer_execute(); let gas_left_after = self.blockchain().get_gas_left(); @@ -102,10 +106,11 @@ pub trait ForwarderTransferExecuteModule { all_token_payments.push(payment); } - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_multi_token_transfer(all_token_payments) + .payment(all_token_payments) .transfer_execute() } @@ -124,10 +129,11 @@ pub trait ForwarderTransferExecuteModule { all_token_payments.push(payment); } - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_multi_token_transfer(all_token_payments) + .payment(all_token_payments) .transfer_execute() } @@ -146,10 +152,11 @@ pub trait ForwarderTransferExecuteModule { all_token_payments.push(payment); } - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .reject_funds() - .with_multi_token_transfer(all_token_payments) + .payment(all_token_payments) .transfer_execute() } } diff --git a/contracts/feature-tests/composability/forwarder/src/contract_change_owner.rs b/contracts/feature-tests/composability/forwarder/src/contract_change_owner.rs index 8c5a140e8d..672d55c3f7 100644 --- a/contracts/feature-tests/composability/forwarder/src/contract_change_owner.rs +++ b/contracts/feature-tests/composability/forwarder/src/contract_change_owner.rs @@ -1,28 +1,28 @@ +use crate::vault_proxy; + multiversx_sc::imports!(); #[multiversx_sc::module] pub trait ChangeOwnerModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint(changeOwnerAddress)] fn change_owner( &self, child_sc_address: ManagedAddress, new_owner: ManagedAddress, ) -> ManagedAddress { - let () = self - .send() + self.send() .change_owner_address(child_sc_address.clone(), &new_owner) - .execute_on_dest_context(); + .sync_call(); self.get_owner_of_vault_contract(child_sc_address) } fn get_owner_of_vault_contract(&self, address: ManagedAddress) -> ManagedAddress { - self.vault_proxy() - .contract(address) + self.tx() + .to(&address) + .typed(vault_proxy::VaultProxy) .get_owner_address() - .execute_on_dest_context() + .returns(ReturnsResult) + .sync_call() } } diff --git a/contracts/feature-tests/composability/forwarder/src/contract_deploy.rs b/contracts/feature-tests/composability/forwarder/src/contract_deploy.rs index d573b45ec0..7145f2555a 100644 --- a/contracts/feature-tests/composability/forwarder/src/contract_deploy.rs +++ b/contracts/feature-tests/composability/forwarder/src/contract_deploy.rs @@ -1,10 +1,9 @@ +use crate::vault_proxy; + multiversx_sc::imports!(); #[multiversx_sc::module] pub trait DeployContractModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] fn deploy_contract( &self, @@ -36,9 +35,13 @@ pub trait DeployContractModule { code: &ManagedBuffer, opt_arg: OptionalValue, ) -> (ManagedAddress, OptionalValue) { - self.vault_proxy() + self.tx() + .typed(vault_proxy::VaultProxy) .init(opt_arg) - .deploy_contract(code, CodeMetadata::DEFAULT) + .code(code.clone()) + .returns(ReturnsNewManagedAddress) + .returns(ReturnsResult) + .sync_call() } #[endpoint] @@ -47,9 +50,14 @@ pub trait DeployContractModule { source_address: ManagedAddress, opt_arg: OptionalValue, ) -> MultiValue2> { - self.vault_proxy() + self.tx() + .typed(vault_proxy::VaultProxy) .init(opt_arg) - .deploy_from_source(&source_address, CodeMetadata::DEFAULT) + .code_metadata(CodeMetadata::DEFAULT) + .from_source(source_address) + .returns(ReturnsNewManagedAddress) + .returns(ReturnsResult) + .sync_call() .into() } } diff --git a/contracts/feature-tests/composability/forwarder/src/contract_upgrade.rs b/contracts/feature-tests/composability/forwarder/src/contract_upgrade.rs index b1629eeaa1..f4782821e0 100644 --- a/contracts/feature-tests/composability/forwarder/src/contract_upgrade.rs +++ b/contracts/feature-tests/composability/forwarder/src/contract_upgrade.rs @@ -1,10 +1,9 @@ +use crate::vault_proxy; + multiversx_sc::imports!(); #[multiversx_sc::module] pub trait UpgradeContractModule { - #[proxy] - fn vault_proxy(&self, sc_address: ManagedAddress) -> vault::Proxy; - #[endpoint(upgradeVault)] fn upgrade_vault( &self, @@ -12,9 +11,13 @@ pub trait UpgradeContractModule { new_code: ManagedBuffer, opt_arg: OptionalValue, ) { - self.vault_proxy(child_sc_address) - .init(opt_arg) - .upgrade_contract(&new_code, CodeMetadata::UPGRADEABLE); + self.tx() + .to(child_sc_address) + .typed(vault_proxy::VaultProxy) + .upgrade(opt_arg) + .code(new_code) + .code_metadata(CodeMetadata::UPGRADEABLE) + .upgrade_async_call_and_exit(); } #[endpoint] @@ -24,8 +27,12 @@ pub trait UpgradeContractModule { source_address: ManagedAddress, opt_arg: OptionalValue, ) { - self.vault_proxy(child_sc_address) - .init(opt_arg) - .upgrade_from_source(&source_address, CodeMetadata::UPGRADEABLE) + self.tx() + .to(child_sc_address) + .typed(vault_proxy::VaultProxy) + .upgrade(opt_arg) + .code_metadata(CodeMetadata::UPGRADEABLE) + .from_source(source_address) + .upgrade_async_call_and_exit(); } } diff --git a/contracts/feature-tests/composability/forwarder/src/esdt.rs b/contracts/feature-tests/composability/forwarder/src/esdt.rs index ed809e514a..7a3e938c06 100644 --- a/contracts/feature-tests/composability/forwarder/src/esdt.rs +++ b/contracts/feature-tests/composability/forwarder/src/esdt.rs @@ -32,7 +32,10 @@ pub trait ForwarderEsdtModule: storage::ForwarderStorageModule { #[endpoint] fn send_esdt(&self, to: &ManagedAddress, token_id: TokenIdentifier, amount: &BigUint) { - self.send().direct_esdt(to, &token_id, 0, amount); + self.tx() + .to(to) + .single_esdt(&token_id, 0, amount) + .transfer(); } #[payable("*")] @@ -42,7 +45,10 @@ pub trait ForwarderEsdtModule: storage::ForwarderStorageModule { let fees = &payment * &percentage_fees / PERCENTAGE_TOTAL; let amount_to_send = payment - fees; - self.send().direct_esdt(&to, &token_id, 0, &amount_to_send); + self.tx() + .to(&to) + .single_esdt(&token_id, 0, &amount_to_send) + .transfer(); } #[endpoint] @@ -53,9 +59,14 @@ pub trait ForwarderEsdtModule: storage::ForwarderStorageModule { amount_first_time: &BigUint, amount_second_time: &BigUint, ) { - self.send().direct_esdt(to, &token_id, 0, amount_first_time); - self.send() - .direct_esdt(to, &token_id, 0, amount_second_time); + self.tx() + .to(to) + .single_esdt(&token_id, 0, amount_first_time) + .transfer(); + self.tx() + .to(to) + .single_esdt(&token_id, 0, amount_second_time) + .transfer(); } #[endpoint] @@ -73,13 +84,7 @@ pub trait ForwarderEsdtModule: storage::ForwarderStorageModule { all_token_payments.push(payment); } - let _ = self.send_raw().multi_esdt_transfer_execute( - &to, - &all_token_payments, - self.blockchain().get_gas_left(), - &ManagedBuffer::new(), - &ManagedArgBuffer::new(), - ); + self.tx().to(&to).payment(all_token_payments).transfer(); } #[payable("EGLD")] @@ -135,7 +140,7 @@ pub trait ForwarderEsdtModule: storage::ForwarderStorageModule { ManagedAsyncCallResult::Err(message) => { // return issue cost to the caller if token_identifier.is_egld() && returned_tokens > 0 { - self.send().direct_egld(caller, &returned_tokens); + self.tx().to(caller).egld(&returned_tokens).transfer(); } self.last_error_message().set(&message.err_msg); diff --git a/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs b/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs index 71ddd886df..1344c66be5 100644 --- a/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs +++ b/contracts/feature-tests/composability/forwarder/src/forwarder_main.rs @@ -1,6 +1,5 @@ #![no_std] #![allow(clippy::type_complexity)] -#![allow(clippy::let_unit_value)] pub mod call_async; pub mod call_sync; @@ -9,10 +8,12 @@ pub mod contract_change_owner; pub mod contract_deploy; pub mod contract_upgrade; pub mod esdt; +pub mod forwarder_proxy; pub mod nft; pub mod roles; pub mod sft; pub mod storage; +pub mod vault_proxy; multiversx_sc::imports!(); @@ -36,6 +37,6 @@ pub trait Forwarder: #[endpoint] fn send_egld(&self, to: &ManagedAddress, amount: &BigUint) { - self.send().direct_egld(to, amount); + self.tx().to(to).egld(amount).transfer(); } } diff --git a/contracts/feature-tests/composability/forwarder/src/forwarder_proxy.rs b/contracts/feature-tests/composability/forwarder/src/forwarder_proxy.rs new file mode 100644 index 0000000000..c5e53db05d --- /dev/null +++ b/contracts/feature-tests/composability/forwarder/src/forwarder_proxy.rs @@ -0,0 +1,1128 @@ +// 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 ForwarderProxy; + +impl TxProxyTrait for ForwarderProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = ForwarderProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + ForwarderProxyMethods { wrapped_tx: tx } + } +} + +pub struct ForwarderProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl ForwarderProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl ForwarderProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn send_egld< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("send_egld") + .argument(&to) + .argument(&amount) + .original_result() + } + + pub fn echo_arguments_sync< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + args: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("echo_arguments_sync") + .argument(&to) + .argument(&args) + .original_result() + } + + pub fn echo_arguments_sync_twice< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + args: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("echo_arguments_sync_twice") + .argument(&to) + .argument(&args) + .original_result() + } + + pub fn forward_sync_accept_funds< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_sync_accept_funds") + .argument(&to) + .original_result() + } + + pub fn forward_sync_accept_funds_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn forward_sync_accept_funds_then_read< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_then_read") + .argument(&to) + .original_result() + } + + pub fn forward_sync_retrieve_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token: Arg1, + token_nonce: Arg2, + amount: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_sync_retrieve_funds") + .argument(&to) + .argument(&token) + .argument(&token_nonce) + .argument(&amount) + .original_result() + } + + pub fn forward_sync_retrieve_funds_with_accept_func< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + token: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_sync_retrieve_funds_with_accept_func") + .argument(&to) + .argument(&token) + .argument(&amount) + .original_result() + } + + pub fn accept_funds_func( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("accept_funds_func") + .original_result() + } + + pub fn forward_sync_accept_funds_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_sync_accept_funds_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn echo_args_async< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + args: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("echo_args_async") + .argument(&to) + .argument(&args) + .original_result() + } + + pub fn forward_async_accept_funds< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_async_accept_funds") + .argument(&to) + .original_result() + } + + pub fn forward_async_accept_funds_half_payment< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_async_accept_funds_half_payment") + .argument(&to) + .original_result() + } + + pub fn forward_async_accept_funds_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_async_accept_funds_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn forward_async_retrieve_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token: Arg1, + token_nonce: Arg2, + amount: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_async_retrieve_funds") + .argument(&to) + .argument(&token) + .argument(&token_nonce) + .argument(&amount) + .original_result() + } + + pub fn send_funds_twice< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + token_identifier: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("send_funds_twice") + .argument(&to) + .argument(&token_identifier) + .argument(&amount) + .original_result() + } + + pub fn send_async_accept_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("send_async_accept_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn callback_data( + self, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("callback_data") + .original_result() + } + + pub fn callback_data_at_index< + Arg0: ProxyArg, + >( + self, + index: Arg0, + ) -> TxProxyCall, EgldOrEsdtTokenIdentifier, u64, BigUint, MultiValueManagedVec>>> { + self.wrapped_tx + .raw_call("callback_data_at_index") + .argument(&index) + .original_result() + } + + pub fn clear_callback_data( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("clear_callback_data") + .original_result() + } + + pub fn forward_transf_exec_accept_funds< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_transf_exec_accept_funds") + .argument(&to) + .original_result() + } + + pub fn forward_transf_execu_accept_funds_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_transf_execu_accept_funds_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn forward_transf_exec_accept_funds_twice< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_transf_exec_accept_funds_twice") + .argument(&to) + .original_result() + } + + /// Test that the default gas provided to the transfer_execute call + /// leaves enough in the transaction for finish to happen. + pub fn forward_transf_exec_accept_funds_return_values< + Arg0: ProxyArg>, + >( + self, + to: Arg0, + ) -> TxProxyCall, EgldOrEsdtTokenIdentifier>> { + self.wrapped_tx + .raw_call("forward_transf_exec_accept_funds_return_values") + .argument(&to) + .original_result() + } + + pub fn transf_exec_multi_accept_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transf_exec_multi_accept_funds") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn forward_transf_exec_reject_funds_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("forward_transf_exec_reject_funds_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn transf_exec_multi_reject_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transf_exec_multi_reject_funds") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn change_owner< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + child_sc_address: Arg0, + new_owner: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("changeOwnerAddress") + .argument(&child_sc_address) + .argument(&new_owner) + .original_result() + } + + pub fn deploy_contract< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + code: Arg0, + opt_arg: Arg1, + ) -> TxProxyCall, OptionalValue>>> { + self.wrapped_tx + .raw_call("deploy_contract") + .argument(&code) + .argument(&opt_arg) + .original_result() + } + + pub fn deploy_two_contracts< + Arg0: ProxyArg>, + >( + self, + code: Arg0, + ) -> TxProxyCall, ManagedAddress>> { + self.wrapped_tx + .raw_call("deploy_two_contracts") + .argument(&code) + .original_result() + } + + pub fn deploy_vault_from_source< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + source_address: Arg0, + opt_arg: Arg1, + ) -> TxProxyCall, OptionalValue>>> { + self.wrapped_tx + .raw_call("deploy_vault_from_source") + .argument(&source_address) + .argument(&opt_arg) + .original_result() + } + + pub fn upgrade_vault< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + child_sc_address: Arg0, + new_code: Arg1, + opt_arg: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("upgradeVault") + .argument(&child_sc_address) + .argument(&new_code) + .argument(&opt_arg) + .original_result() + } + + pub fn upgrade_vault_from_source< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + child_sc_address: Arg0, + source_address: Arg1, + opt_arg: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("upgrade_vault_from_source") + .argument(&child_sc_address) + .argument(&source_address) + .argument(&opt_arg) + .original_result() + } + + pub fn get_fungible_esdt_balance< + Arg0: ProxyArg>, + >( + self, + token_identifier: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getFungibleEsdtBalance") + .argument(&token_identifier) + .original_result() + } + + pub fn get_current_nft_nonce< + Arg0: ProxyArg>, + >( + self, + token_identifier: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getCurrentNftNonce") + .argument(&token_identifier) + .original_result() + } + + pub fn send_esdt< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + to: Arg0, + token_id: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("send_esdt") + .argument(&to) + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn send_esdt_with_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + percentage_fees: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("send_esdt_with_fees") + .argument(&to) + .argument(&percentage_fees) + .original_result() + } + + pub fn send_esdt_twice< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token_id: Arg1, + amount_first_time: Arg2, + amount_second_time: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("send_esdt_twice") + .argument(&to) + .argument(&token_id) + .argument(&amount_first_time) + .argument(&amount_second_time) + .original_result() + } + + pub fn send_esdt_direct_multi_transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg, u64, BigUint>>>, + >( + self, + to: Arg0, + token_payments: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("send_esdt_direct_multi_transfer") + .argument(&to) + .argument(&token_payments) + .original_result() + } + + pub fn issue_fungible_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + initial_supply: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("issue_fungible_token") + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&initial_supply) + .original_result() + } + + pub fn local_mint< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("local_mint") + .argument(&token_identifier) + .argument(&amount) + .original_result() + } + + pub fn local_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("local_burn") + .argument(&token_identifier) + .argument(&amount) + .original_result() + } + + pub fn get_esdt_local_roles< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("get_esdt_local_roles") + .argument(&token_id) + .original_result() + } + + pub fn get_esdt_token_data< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + address: Arg0, + token_id: Arg1, + nonce: Arg2, + ) -> TxProxyCall, bool, ManagedBuffer, ManagedBuffer, ManagedBuffer, ManagedAddress, BigUint, ManagedVec>>> { + self.wrapped_tx + .raw_call("get_esdt_token_data") + .argument(&address) + .argument(&token_id) + .argument(&nonce) + .original_result() + } + + pub fn is_esdt_frozen< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + address: Arg0, + token_id: Arg1, + nonce: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("is_esdt_frozen") + .argument(&address) + .argument(&token_id) + .argument(&nonce) + .original_result() + } + + pub fn is_esdt_paused< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("is_esdt_paused") + .argument(&token_id) + .original_result() + } + + pub fn is_esdt_limited_transfer< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("is_esdt_limited_transfer") + .argument(&token_id) + .original_result() + } + + pub fn validate_token_identifier< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("validate_token_identifier") + .argument(&token_id) + .original_result() + } + + pub fn sft_issue< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("sft_issue") + .argument(&token_display_name) + .argument(&token_ticker) + .original_result() + } + + pub fn get_nft_balance< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("get_nft_balance") + .argument(&token_identifier) + .argument(&nonce) + .original_result() + } + + pub fn buy_nft< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + nft_id: Arg0, + nft_nonce: Arg1, + nft_amount: Arg2, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("buy_nft") + .argument(&nft_id) + .argument(&nft_nonce) + .argument(&nft_amount) + .original_result() + } + + pub fn nft_issue< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_display_name: Arg0, + token_ticker: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_issue") + .argument(&token_display_name) + .argument(&token_ticker) + .original_result() + } + + pub fn nft_create< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg, + Arg6: ProxyArg>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + color: Arg5, + uri: Arg6, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_create") + .argument(&token_identifier) + .argument(&amount) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&color) + .argument(&uri) + .original_result() + } + + pub fn nft_create_compact< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + token_identifier: Arg0, + amount: Arg1, + color: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_create_compact") + .argument(&token_identifier) + .argument(&amount) + .argument(&color) + .original_result() + } + + pub fn nft_add_uris< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>>, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + uris: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_add_uris") + .argument(&token_identifier) + .argument(&nonce) + .argument(&uris) + .original_result() + } + + pub fn nft_update_attributes< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + new_attributes: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_update_attributes") + .argument(&token_identifier) + .argument(&nonce) + .argument(&new_attributes) + .original_result() + } + + pub fn nft_decode_complex_attributes< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg, ManagedBuffer, TokenIdentifier, bool, ManagedBuffer>>, + >( + self, + token_identifier: Arg0, + amount: Arg1, + name: Arg2, + royalties: Arg3, + hash: Arg4, + uri: Arg5, + attrs_arg: Arg6, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_decode_complex_attributes") + .argument(&token_identifier) + .argument(&amount) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&uri) + .argument(&attrs_arg) + .original_result() + } + + pub fn nft_add_quantity< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_add_quantity") + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn nft_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token_identifier: Arg0, + nonce: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("nft_burn") + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn transfer_nft_via_async_call< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + >( + self, + to: Arg0, + token_identifier: Arg1, + nonce: Arg2, + amount: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer_nft_via_async_call") + .argument(&to) + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn transfer_nft_and_execute< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg>>, + >( + self, + to: Arg0, + token_identifier: Arg1, + nonce: Arg2, + amount: Arg3, + function: Arg4, + arguments: Arg5, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer_nft_and_execute") + .argument(&to) + .argument(&token_identifier) + .argument(&nonce) + .argument(&amount) + .argument(&function) + .argument(&arguments) + .original_result() + } + + pub fn create_and_send< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg, + Arg7: ProxyArg>, + >( + self, + to: Arg0, + token_identifier: Arg1, + amount: Arg2, + name: Arg3, + royalties: Arg4, + hash: Arg5, + color: Arg6, + uri: Arg7, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("create_and_send") + .argument(&to) + .argument(&token_identifier) + .argument(&amount) + .argument(&name) + .argument(&royalties) + .argument(&hash) + .argument(&color) + .argument(&uri) + .original_result() + } + + pub fn set_local_roles< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + address: Arg0, + token_identifier: Arg1, + roles: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setLocalRoles") + .argument(&address) + .argument(&token_identifier) + .argument(&roles) + .original_result() + } + + pub fn unset_local_roles< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + address: Arg0, + token_identifier: Arg1, + roles: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unsetLocalRoles") + .argument(&address) + .argument(&token_identifier) + .argument(&roles) + .original_result() + } + + pub fn last_issued_token( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("lastIssuedToken") + .original_result() + } + + pub fn last_error_message( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("lastErrorMessage") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode)] +pub struct CallbackData +where + Api: ManagedTypeApi, +{ + pub callback_name: ManagedBuffer, + pub token_identifier: EgldOrEsdtTokenIdentifier, + pub token_nonce: u64, + pub token_amount: BigUint, + pub args: ManagedVec>, +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq, Debug)] +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, +} diff --git a/contracts/feature-tests/composability/forwarder/src/nft.rs b/contracts/feature-tests/composability/forwarder/src/nft.rs index 97d7a2dbd2..3deb7f1493 100644 --- a/contracts/feature-tests/composability/forwarder/src/nft.rs +++ b/contracts/feature-tests/composability/forwarder/src/nft.rs @@ -4,14 +4,16 @@ multiversx_sc::derive_imports!(); use super::storage; // used as mock attributes for NFTs -#[derive(TopEncode, TopDecode, TypeAbi, Clone, Copy, PartialEq, Debug)] +#[type_abi] +#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq, Debug)] pub struct Color { pub r: u8, pub g: u8, pub b: u8, } -#[derive(TopEncode, TopDecode, TypeAbi, PartialEq, Eq, Clone)] +#[type_abi] +#[derive(TopEncode, TopDecode, PartialEq, Eq, Clone)] pub struct ComplexAttributes { pub biguint: BigUint, pub vec_u8: ManagedBuffer, @@ -90,7 +92,7 @@ pub trait ForwarderNftModule: storage::ForwarderStorageModule { let (token_identifier, returned_tokens) = self.call_value().egld_or_single_fungible_esdt(); if token_identifier.is_egld() && returned_tokens > 0 { - self.send().direct_egld(caller, &returned_tokens); + self.tx().to(caller).egld(&returned_tokens).transfer(); } self.last_error_message().set(&message.err_msg); @@ -238,15 +240,14 @@ pub trait ForwarderNftModule: storage::ForwarderStorageModule { function: ManagedBuffer, arguments: MultiValueEncoded, ) { - let _ = self.send_raw().transfer_esdt_nft_execute( - &to, - &token_identifier, - nonce, - &amount, - self.blockchain().get_gas_left(), - &function, - &arguments.to_arg_buffer(), - ); + let gas_left = self.blockchain().get_gas_left(); + self.tx() + .to(&to) + .gas(gas_left) + .raw_call(function) + .arguments_raw(arguments.to_arg_buffer()) + .single_esdt(&token_identifier, nonce, &amount) + .transfer_execute(); } #[endpoint] @@ -271,8 +272,10 @@ pub trait ForwarderNftModule: storage::ForwarderStorageModule { uri, ); - self.send() - .direct_esdt(&to, &token_identifier, token_nonce, &amount); + self.tx() + .to(&to) + .single_esdt(&token_identifier, token_nonce, &amount) + .transfer(); self.send_event(&to, &token_identifier, token_nonce, &amount); } diff --git a/contracts/feature-tests/composability/forwarder/src/sft.rs b/contracts/feature-tests/composability/forwarder/src/sft.rs index 12e1a2f431..77b8d8b37c 100644 --- a/contracts/feature-tests/composability/forwarder/src/sft.rs +++ b/contracts/feature-tests/composability/forwarder/src/sft.rs @@ -47,7 +47,7 @@ pub trait ForwarderSftModule: storage::ForwarderStorageModule { let (token_identifier, returned_tokens) = self.call_value().egld_or_single_fungible_esdt(); if token_identifier.is_egld() && returned_tokens > 0 { - self.send().direct_egld(caller, &returned_tokens); + self.tx().to(caller).egld(&returned_tokens).transfer(); } self.last_error_message().set(&message.err_msg); diff --git a/contracts/feature-tests/composability/forwarder/src/vault_proxy.rs b/contracts/feature-tests/composability/forwarder/src/vault_proxy.rs new file mode 100644 index 0000000000..c43f59c36a --- /dev/null +++ b/contracts/feature-tests/composability/forwarder/src/vault_proxy.rs @@ -0,0 +1,262 @@ +// 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 VaultProxy; + +impl TxProxyTrait for VaultProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = VaultProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + VaultProxyMethods { wrapped_tx: tx } + } +} + +pub struct VaultProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + opt_arg_to_echo: Arg0, + ) -> TxProxyDeploy>> { + self.wrapped_tx + .raw_deploy() + .argument(&opt_arg_to_echo) + .original_result() + } +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>>, + >( + self, + opt_arg_to_echo: Arg0, + ) -> TxProxyUpgrade>>> { + self.wrapped_tx + .raw_upgrade() + .argument(&opt_arg_to_echo) + .original_result() + } +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn echo_arguments< + Arg0: ProxyArg>>, + >( + self, + args: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("echo_arguments") + .argument(&args) + .original_result() + } + + pub fn echo_arguments_without_storage< + Arg0: ProxyArg>>, + >( + self, + args: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("echo_arguments_without_storage") + .argument(&args) + .original_result() + } + + pub fn echo_caller( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("echo_caller") + .original_result() + } + + pub fn accept_funds( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("accept_funds") + .original_result() + } + + pub fn accept_funds_echo_payment( + self, + ) -> TxProxyCall, MultiValueEncoded>>> { + self.wrapped_tx + .raw_call("accept_funds_echo_payment") + .original_result() + } + + pub fn accept_funds_single_esdt_transfer( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("accept_funds_single_esdt_transfer") + .original_result() + } + + pub fn reject_funds( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("reject_funds") + .original_result() + } + + pub fn retrieve_funds_with_transfer_exec< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + token: Arg0, + amount: Arg1, + opt_receive_func: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds_with_transfer_exec") + .argument(&token) + .argument(&amount) + .argument(&opt_receive_func) + .original_result() + } + + pub fn retrieve_funds_promises< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + back_transfers: Arg0, + back_transfer_value: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds_promises") + .argument(&back_transfers) + .argument(&back_transfer_value) + .original_result() + } + + pub fn retrieve_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token: Arg0, + nonce: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds") + .argument(&token) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn retrieve_multi_funds_async< + Arg0: ProxyArg, u64, BigUint>>>, + >( + self, + token_payments: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_multi_funds_async") + .argument(&token_payments) + .original_result() + } + + pub fn burn_and_create_retrieve_async( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("burn_and_create_retrieve_async") + .original_result() + } + + pub fn get_owner_address( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("get_owner_address") + .original_result() + } + + /// We already leave a trace of the calls using the event logs; + /// this additional counter has the role of showing that storage also gets saved correctly. + pub fn call_counts< + Arg0: ProxyArg>, + >( + self, + endpoint: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("call_counts") + .argument(&endpoint) + .original_result() + } + + pub fn num_called_retrieve_funds_promises( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("num_called_retrieve_funds_promises") + .original_result() + } + + pub fn num_async_calls_sent_from_child( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("num_async_calls_sent_from_child") + .original_result() + } +} diff --git a/contracts/feature-tests/composability/forwarder/wasm/Cargo.lock b/contracts/feature-tests/composability/forwarder/wasm/Cargo.lock index 45f9ebb16c..9ac4d71496 100755 --- a/contracts/feature-tests/composability/forwarder/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/forwarder/wasm/Cargo.lock @@ -31,7 +31,6 @@ name = "forwarder" version = "0.0.0" dependencies = [ "multiversx-sc", - "vault", ] [[package]] @@ -56,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -85,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -96,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] @@ -169,10 +168,3 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "vault" -version = "0.0.0" -dependencies = [ - "multiversx-sc", -] diff --git a/contracts/feature-tests/composability/forwarder/wasm/Cargo.toml b/contracts/feature-tests/composability/forwarder/wasm/Cargo.toml index 9bc90a4fe2..2395849caf 100644 --- a/contracts/feature-tests/composability/forwarder/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/forwarder/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/interact/Cargo.toml b/contracts/feature-tests/composability/interact/Cargo.toml index 0f15a7432a..97cd3f93f5 100644 --- a/contracts/feature-tests/composability/interact/Cargo.toml +++ b/contracts/feature-tests/composability/interact/Cargo.toml @@ -24,9 +24,9 @@ path = "../forwarder-queue" path = "../promises-features" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../contracts/modules" [dependencies.multiversx-sc-snippets] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/snippets" diff --git a/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs b/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs index 9e86f5dfdb..9305aca3be 100644 --- a/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs +++ b/contracts/feature-tests/composability/interact/src/call_tree_calling_functions.rs @@ -1,16 +1,9 @@ use std::{cell::RefCell, rc::Rc}; use forwarder_queue::QueuedCallType; -use multiversx_sc_snippets::{ - multiversx_sc::types::{EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment, MultiValueEncoded}, - multiversx_sc_scenario::{ - api::StaticApi, - bech32, - num_bigint::BigUint, - scenario_model::{ScCallStep, TxExpect}, - }, - StepBuffer, -}; + +use multiversx_sc_snippets::imports::*; +use num_bigint::BigUint; use crate::{ call_tree::{CallNode, CallState, ForwarderQueueTarget}, diff --git a/contracts/feature-tests/composability/interact/src/call_tree_deploy.rs b/contracts/feature-tests/composability/interact/src/call_tree_deploy.rs index c9c2f1498c..46e5c4804d 100644 --- a/contracts/feature-tests/composability/interact/src/call_tree_deploy.rs +++ b/contracts/feature-tests/composability/interact/src/call_tree_deploy.rs @@ -1,20 +1,10 @@ use crate::{call_tree::CallState, comp_interact_controller::ComposabilityInteract}; use forwarder_queue::ProxyTrait as _; -use multiversx_sc_snippets::{ - multiversx_sc::{ - codec::multi_types::OptionalValue, - types::{BoxedBytes, ManagedBuffer}, - }, - multiversx_sc_scenario::{ - api::StaticApi, - bech32, - scenario_model::{ScDeployStep, TypedScDeploy}, - }, - StepBuffer, -}; use vault::ProxyTrait as _; +use multiversx_sc_snippets::imports::*; + impl ComposabilityInteract { pub async fn deploy_call_tree_contracts(&mut self, call_state: &CallState) { let mut typed_vault_deploys = self.typed_sc_deploy_vault(call_state).await; diff --git a/contracts/feature-tests/composability/interact/src/comp_interact_config.rs b/contracts/feature-tests/composability/interact/src/comp_interact_config.rs index c27957a9fb..cbe6d6498f 100644 --- a/contracts/feature-tests/composability/interact/src/comp_interact_config.rs +++ b/contracts/feature-tests/composability/interact/src/comp_interact_config.rs @@ -1,8 +1,6 @@ use forwarder_queue::QueuedCallType; -use multiversx_sc_snippets::{ - multiversx_sc::types::{EgldOrEsdtTokenIdentifier, TokenIdentifier}, - multiversx_sc_scenario::{api::StaticApi, num_bigint::BigUint}, -}; +use multiversx_sc_snippets::imports::*; +use num_bigint::BigUint; use serde::Deserialize; use std::{fmt::Debug, io::Read, str::FromStr}; diff --git a/contracts/feature-tests/composability/interact/src/comp_interact_controller.rs b/contracts/feature-tests/composability/interact/src/comp_interact_controller.rs index f5851d6e6c..409ce234a7 100644 --- a/contracts/feature-tests/composability/interact/src/comp_interact_controller.rs +++ b/contracts/feature-tests/composability/interact/src/comp_interact_controller.rs @@ -1,14 +1,6 @@ use crate::{call_tree::CallState, comp_interact_config::Config, comp_interact_state::State}; -use multiversx_sc_snippets::{ - multiversx_sc::types::Address, - multiversx_sc_scenario::{ - scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, - scenario_model::BytesValue, - test_wallets::judy, - }, - Interactor, -}; +use multiversx_sc_snippets::imports::*; const INTERACTOR_SCENARIO_TRACE_PATH: &str = "comp_interact_trace.scen.json"; @@ -27,7 +19,7 @@ impl ComposabilityInteract { .await .with_tracer(INTERACTOR_SCENARIO_TRACE_PATH) .await; - let wallet_address = interactor.register_wallet(judy()); + let wallet_address = interactor.register_wallet(test_wallets::judy()); let forw_queue_code = BytesValue::interpret_from( "mxsc:../forwarder-queue/output/forwarder-queue.mxsc.json", &InterpreterContext::default(), diff --git a/contracts/feature-tests/composability/interact/src/comp_interact_main.rs b/contracts/feature-tests/composability/interact/src/comp_interact_main.rs index b6e0ba9778..9f4a6d6872 100644 --- a/contracts/feature-tests/composability/interact/src/comp_interact_main.rs +++ b/contracts/feature-tests/composability/interact/src/comp_interact_main.rs @@ -1,4 +1,5 @@ #![allow(clippy::too_many_arguments)] +#![allow(deprecated)] // TODO: switch to unified syntax mod call_tree; mod call_tree_calling_functions; @@ -12,11 +13,7 @@ use clap::Parser; use comp_interact_controller::ComposabilityInteract; -use multiversx_sc_snippets::{ - env_logger, - multiversx_sc_scenario::{api::StaticApi, ContractInfo}, - tokio, -}; +use multiversx_sc_snippets::imports::*; #[tokio::main] async fn main() { diff --git a/contracts/feature-tests/composability/local-esdt-and-nft/Cargo.toml b/contracts/feature-tests/composability/local-esdt-and-nft/Cargo.toml index b5dbc4bb26..b969ae9c8b 100644 --- a/contracts/feature-tests/composability/local-esdt-and-nft/Cargo.toml +++ b/contracts/feature-tests/composability/local-esdt-and-nft/Cargo.toml @@ -10,9 +10,9 @@ path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/local-esdt-and-nft/meta/Cargo.toml b/contracts/feature-tests/composability/local-esdt-and-nft/meta/Cargo.toml index 0895ea8849..d9aa379fde 100644 --- a/contracts/feature-tests/composability/local-esdt-and-nft/meta/Cargo.toml +++ b/contracts/feature-tests/composability/local-esdt-and-nft/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false 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 235e3cde63..9923ef89e5 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 @@ -138,8 +138,10 @@ pub trait LocalEsdtAndEsdtNft { nonce: u64, amount: BigUint, ) { - self.send() - .transfer_esdt_via_async_call(to, token_identifier, nonce, amount); + self.tx() + .to(to) + .esdt((token_identifier, nonce, amount)) + .async_call_and_exit(); } #[endpoint] @@ -157,15 +159,15 @@ pub trait LocalEsdtAndEsdtNft { arg_buffer.push_arg_raw(arg); } - let _ = self.send_raw().transfer_esdt_nft_execute( - &to, - &token_identifier, - nonce, - &amount, - self.blockchain().get_gas_left(), - &function, - &arg_buffer, - ); + let gas_left = self.blockchain().get_gas_left(); + + self.tx() + .to(&to) + .gas(gas_left) + .raw_call(function) + .arguments_raw(arg_buffer) + .single_esdt(&token_identifier, nonce, &amount) + .transfer_execute(); } // Semi-Fungible @@ -287,7 +289,7 @@ pub trait LocalEsdtAndEsdtNft { ManagedAsyncCallResult::Err(message) => { // return issue cost to the caller if token_identifier.is_egld() && returned_tokens > 0 { - self.send().direct_egld(caller, &returned_tokens); + self.tx().to(caller).egld(&returned_tokens).transfer(); } self.last_error_message().set(&message.err_msg); @@ -311,7 +313,7 @@ pub trait LocalEsdtAndEsdtNft { let (token_identifier, returned_tokens) = self.call_value().egld_or_single_fungible_esdt(); if token_identifier.is_egld() && returned_tokens > 0 { - self.send().direct_egld(caller, &returned_tokens); + self.tx().to(caller).egld(&returned_tokens).transfer(); } self.last_error_message().set(&message.err_msg); diff --git a/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.lock b/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.lock index 4f188cc77a..a8525f910a 100755 --- a/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.toml b/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.toml index 85cf633c9e..89dfb08625 100644 --- a/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/local-esdt-and-nft/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/promises-features/Cargo.toml b/contracts/feature-tests/composability/promises-features/Cargo.toml index 9fd6433748..d8f4c2ed7e 100644 --- a/contracts/feature-tests/composability/promises-features/Cargo.toml +++ b/contracts/feature-tests/composability/promises-features/Cargo.toml @@ -8,10 +8,7 @@ publish = false [lib] path = "src/promises_main.rs" -[dependencies.vault] -path = "../vault" - [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" diff --git a/contracts/feature-tests/composability/promises-features/meta/Cargo.toml b/contracts/feature-tests/composability/promises-features/meta/Cargo.toml index 535835eea8..16159a0190 100644 --- a/contracts/feature-tests/composability/promises-features/meta/Cargo.toml +++ b/contracts/feature-tests/composability/promises-features/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/promises-features/src/call_promise_direct.rs b/contracts/feature-tests/composability/promises-features/src/call_promise_direct.rs index 8ce47a10c3..b722ad4f5d 100644 --- a/contracts/feature-tests/composability/promises-features/src/call_promise_direct.rs +++ b/contracts/feature-tests/composability/promises-features/src/call_promise_direct.rs @@ -3,9 +3,6 @@ multiversx_sc::imports!(); /// Test contract for investigating the new async call framework. #[multiversx_sc::module] pub trait CallPromisesDirectModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] #[payable("*")] fn promise_raw_single_token( @@ -17,14 +14,15 @@ pub trait CallPromisesDirectModule { args: MultiValueEncoded, ) { let payment = self.call_value().egld_or_single_esdt(); - self.send() - .contract_call::<()>(to, endpoint_name) - .with_egld_or_single_esdt_transfer(payment) - .with_raw_arguments(args.to_arg_buffer()) - .with_gas_limit(gas_limit) + self.tx() + .to(&to) + .raw_call(endpoint_name) + .payment(payment) + .arguments_raw(args.to_arg_buffer()) + .gas(gas_limit) .async_call_promise() - .with_extra_gas_for_callback(extra_gas_for_callback) - .with_callback(self.callbacks().the_one_callback(1001, 1002u32.into())) + .callback(self.callbacks().the_one_callback(1001, 1002u32.into())) + .gas_for_callback(extra_gas_for_callback) .register_promise(); } @@ -43,13 +41,14 @@ pub trait CallPromisesDirectModule { let gas_limit = (self.blockchain().get_gas_left() - extra_gas_for_callback) * 9 / 10; - self.send() - .contract_call::<()>(to, endpoint_name) - .with_multi_token_transfer(token_payments_vec) - .with_gas_limit(gas_limit) + self.tx() + .to(&to) + .raw_call(endpoint_name) + .payment(EgldOrMultiEsdtPayment::MultiEsdt(token_payments_vec)) + .gas(gas_limit) .async_call_promise() - .with_extra_gas_for_callback(extra_gas_for_callback) - .with_callback(self.callbacks().the_one_callback(2001, 2002u32.into())) + .callback(self.callbacks().the_one_callback(2001, 2002u32.into())) + .gas_for_callback(extra_gas_for_callback) .register_promise(); } diff --git a/contracts/feature-tests/composability/promises-features/src/call_promises.rs b/contracts/feature-tests/composability/promises-features/src/call_promises.rs index 616d8c5cb0..92a2c8e0e1 100644 --- a/contracts/feature-tests/composability/promises-features/src/call_promises.rs +++ b/contracts/feature-tests/composability/promises-features/src/call_promises.rs @@ -1,24 +1,25 @@ multiversx_sc::imports!(); -use crate::common::{self, CallbackData}; +use crate::{ + common::{self, CallbackData}, + vault_proxy, +}; #[multiversx_sc::module] pub trait CallPromisesModule: common::CommonModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] #[payable("*")] fn forward_promise_accept_funds(&self, to: ManagedAddress) { let payment = self.call_value().egld_or_single_esdt(); let gas_limit = self.blockchain().get_gas_left() / 2; - self.vault_proxy() - .contract(to) + + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer(payment) - .with_gas_limit(gas_limit) - .async_call_promise() - .register_promise() + .gas(gas_limit) + .payment(payment) + .register_promise(); } #[endpoint] @@ -30,14 +31,15 @@ pub trait CallPromisesModule: common::CommonModule { amount: BigUint, ) { let gas_limit = self.blockchain().get_gas_left() - 20_000_000; - self.vault_proxy() - .contract(to) + + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds(token, token_nonce, amount) - .with_gas_limit(gas_limit) - .async_call_promise() - .with_callback(self.callbacks().retrieve_funds_callback()) - .with_extra_gas_for_callback(10_000_000) - .register_promise() + .gas(gas_limit) + .callback(self.callbacks().retrieve_funds_callback()) + .gas_for_callback(10_000_000) + .register_promise(); } #[promises_callback] diff --git a/contracts/feature-tests/composability/promises-features/src/call_promises_bt.rs b/contracts/feature-tests/composability/promises-features/src/call_promises_bt.rs index e1e2188852..f6cbbfa188 100644 --- a/contracts/feature-tests/composability/promises-features/src/call_promises_bt.rs +++ b/contracts/feature-tests/composability/promises-features/src/call_promises_bt.rs @@ -1,13 +1,12 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); -use crate::common::{self, CallbackData}; - +use crate::{ + common::{self, CallbackData}, + vault_proxy, +}; #[multiversx_sc::module] pub trait CallPromisesBackTransfersModule: common::CommonModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] fn forward_promise_retrieve_funds_back_transfers( &self, @@ -17,14 +16,15 @@ pub trait CallPromisesBackTransfersModule: common::CommonModule { amount: BigUint, ) { let gas_limit = self.blockchain().get_gas_left() - 20_000_000; - self.vault_proxy() - .contract(to) + self.tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds(token, token_nonce, amount) - .with_gas_limit(gas_limit) - .async_call_promise() - .with_callback(self.callbacks().retrieve_funds_back_transfers_callback()) - .with_extra_gas_for_callback(10_000_000) - .register_promise() + .gas(gas_limit) + .async_call() + .callback(self.callbacks().retrieve_funds_back_transfers_callback()) + .gas_for_callback(10_000_000) + .register_promise(); } #[promises_callback] diff --git a/contracts/feature-tests/composability/promises-features/src/call_sync_bt.rs b/contracts/feature-tests/composability/promises-features/src/call_sync_bt.rs index d3cc048ccc..d31ac022dc 100644 --- a/contracts/feature-tests/composability/promises-features/src/call_sync_bt.rs +++ b/contracts/feature-tests/composability/promises-features/src/call_sync_bt.rs @@ -1,11 +1,10 @@ +use crate::vault_proxy; + multiversx_sc::imports!(); /// Not directly related to promises, but this contract already has the setup for VM 1.5. #[multiversx_sc::module] pub trait BackTransfersFeatureModule { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - #[endpoint] fn forward_sync_retrieve_funds_bt( &self, @@ -14,11 +13,13 @@ pub trait BackTransfersFeatureModule { token_nonce: u64, amount: BigUint, ) { - let ((), back_transfers) = self - .vault_proxy() - .contract(to) + let back_transfers = self + .tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds(token, token_nonce, amount) - .execute_on_dest_context_with_back_transfers::<()>(); + .returns(ReturnsBackTransfers) + .sync_call(); require!( back_transfers.esdt_payments.len() == 1 || back_transfers.total_egld_amount != 0, @@ -39,11 +40,13 @@ pub trait BackTransfersFeatureModule { token_nonce: u64, amount: BigUint, ) { - let ((), back_transfers) = self - .vault_proxy() - .contract(to.clone()) + let back_transfers = self + .tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds(token.clone(), token_nonce, amount.clone()) - .execute_on_dest_context_with_back_transfers::<()>(); + .returns(ReturnsBackTransfers) + .sync_call(); require!( back_transfers.esdt_payments.len() == 1 || back_transfers.total_egld_amount != 0, @@ -55,11 +58,13 @@ pub trait BackTransfersFeatureModule { &back_transfers.esdt_payments.into_multi_value(), ); - let ((), back_transfers) = self - .vault_proxy() - .contract(to) + let back_transfers = self + .tx() + .to(&to) + .typed(vault_proxy::VaultProxy) .retrieve_funds(token, token_nonce, amount) - .execute_on_dest_context_with_back_transfers::<()>(); + .returns(ReturnsBackTransfers) + .sync_call(); require!( back_transfers.esdt_payments.len() == 1 || back_transfers.total_egld_amount != 0, diff --git a/contracts/feature-tests/composability/promises-features/src/promises_main.rs b/contracts/feature-tests/composability/promises-features/src/promises_main.rs index 11eb5d3935..ddcc00d965 100644 --- a/contracts/feature-tests/composability/promises-features/src/promises_main.rs +++ b/contracts/feature-tests/composability/promises-features/src/promises_main.rs @@ -6,6 +6,7 @@ mod call_promises; mod call_promises_bt; pub mod call_sync_bt; mod common; +pub mod vault_proxy; multiversx_sc::imports!(); diff --git a/contracts/feature-tests/composability/promises-features/src/vault_proxy.rs b/contracts/feature-tests/composability/promises-features/src/vault_proxy.rs new file mode 100644 index 0000000000..c43f59c36a --- /dev/null +++ b/contracts/feature-tests/composability/promises-features/src/vault_proxy.rs @@ -0,0 +1,262 @@ +// 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 VaultProxy; + +impl TxProxyTrait for VaultProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = VaultProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + VaultProxyMethods { wrapped_tx: tx } + } +} + +pub struct VaultProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + opt_arg_to_echo: Arg0, + ) -> TxProxyDeploy>> { + self.wrapped_tx + .raw_deploy() + .argument(&opt_arg_to_echo) + .original_result() + } +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>>, + >( + self, + opt_arg_to_echo: Arg0, + ) -> TxProxyUpgrade>>> { + self.wrapped_tx + .raw_upgrade() + .argument(&opt_arg_to_echo) + .original_result() + } +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn echo_arguments< + Arg0: ProxyArg>>, + >( + self, + args: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("echo_arguments") + .argument(&args) + .original_result() + } + + pub fn echo_arguments_without_storage< + Arg0: ProxyArg>>, + >( + self, + args: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("echo_arguments_without_storage") + .argument(&args) + .original_result() + } + + pub fn echo_caller( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("echo_caller") + .original_result() + } + + pub fn accept_funds( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("accept_funds") + .original_result() + } + + pub fn accept_funds_echo_payment( + self, + ) -> TxProxyCall, MultiValueEncoded>>> { + self.wrapped_tx + .raw_call("accept_funds_echo_payment") + .original_result() + } + + pub fn accept_funds_single_esdt_transfer( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("accept_funds_single_esdt_transfer") + .original_result() + } + + pub fn reject_funds( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("reject_funds") + .original_result() + } + + pub fn retrieve_funds_with_transfer_exec< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + token: Arg0, + amount: Arg1, + opt_receive_func: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds_with_transfer_exec") + .argument(&token) + .argument(&amount) + .argument(&opt_receive_func) + .original_result() + } + + pub fn retrieve_funds_promises< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + back_transfers: Arg0, + back_transfer_value: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds_promises") + .argument(&back_transfers) + .argument(&back_transfer_value) + .original_result() + } + + pub fn retrieve_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token: Arg0, + nonce: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds") + .argument(&token) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn retrieve_multi_funds_async< + Arg0: ProxyArg, u64, BigUint>>>, + >( + self, + token_payments: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_multi_funds_async") + .argument(&token_payments) + .original_result() + } + + pub fn burn_and_create_retrieve_async( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("burn_and_create_retrieve_async") + .original_result() + } + + pub fn get_owner_address( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("get_owner_address") + .original_result() + } + + /// We already leave a trace of the calls using the event logs; + /// this additional counter has the role of showing that storage also gets saved correctly. + pub fn call_counts< + Arg0: ProxyArg>, + >( + self, + endpoint: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("call_counts") + .argument(&endpoint) + .original_result() + } + + pub fn num_called_retrieve_funds_promises( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("num_called_retrieve_funds_promises") + .original_result() + } + + pub fn num_async_calls_sent_from_child( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("num_async_calls_sent_from_child") + .original_result() + } +} diff --git a/contracts/feature-tests/composability/promises-features/wasm/Cargo.lock b/contracts/feature-tests/composability/promises-features/wasm/Cargo.lock index edd5f4e52a..1b366a0da0 100644 --- a/contracts/feature-tests/composability/promises-features/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/promises-features/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] @@ -117,7 +117,6 @@ name = "promises-features" version = "0.0.0" dependencies = [ "multiversx-sc", - "vault", ] [[package]] @@ -169,10 +168,3 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "vault" -version = "0.0.0" -dependencies = [ - "multiversx-sc", -] diff --git a/contracts/feature-tests/composability/promises-features/wasm/Cargo.toml b/contracts/feature-tests/composability/promises-features/wasm/Cargo.toml index 06de0a0367..cdb0aa0d3e 100644 --- a/contracts/feature-tests/composability/promises-features/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/promises-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/proxy-test-first/Cargo.toml b/contracts/feature-tests/composability/proxy-test-first/Cargo.toml index 734caab8e5..6a9fcceaaf 100644 --- a/contracts/feature-tests/composability/proxy-test-first/Cargo.toml +++ b/contracts/feature-tests/composability/proxy-test-first/Cargo.toml @@ -12,10 +12,10 @@ path = "src/proxy-test-first.rs" hex-literal = "0.4.1" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/proxy-test-first/meta/Cargo.toml b/contracts/feature-tests/composability/proxy-test-first/meta/Cargo.toml index 382322c6d8..02488e11e3 100644 --- a/contracts/feature-tests/composability/proxy-test-first/meta/Cargo.toml +++ b/contracts/feature-tests/composability/proxy-test-first/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/proxy-test-first/src/message_me_proxy.rs b/contracts/feature-tests/composability/proxy-test-first/src/message_me_proxy.rs new file mode 100644 index 0000000000..4609a3a0bd --- /dev/null +++ b/contracts/feature-tests/composability/proxy-test-first/src/message_me_proxy.rs @@ -0,0 +1,106 @@ +// 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 MessageMeProxy; + +impl TxProxyTrait for MessageMeProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = MessageMeProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + MessageMeProxyMethods { wrapped_tx: tx } + } +} + +pub struct MessageMeProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl MessageMeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg, + >( + self, + init_arg: Arg0, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&init_arg) + .original_result() + } +} + +#[rustfmt::skip] +impl MessageMeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxProxyUpgrade { + self.wrapped_tx + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl MessageMeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn message_me< + Arg0: ProxyArg, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + >( + self, + arg1: Arg0, + arg2: Arg1, + arg3: Arg2, + arg4: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("messageMe") + .argument(&arg1) + .argument(&arg2) + .argument(&arg3) + .argument(&arg4) + .original_result() + } +} diff --git a/contracts/feature-tests/composability/proxy-test-first/src/pay_me_proxy.rs b/contracts/feature-tests/composability/proxy-test-first/src/pay_me_proxy.rs new file mode 100644 index 0000000000..cfd32f2516 --- /dev/null +++ b/contracts/feature-tests/composability/proxy-test-first/src/pay_me_proxy.rs @@ -0,0 +1,105 @@ +// 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 PayMeProxy; + +impl TxProxyTrait for PayMeProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = PayMeProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + PayMeProxyMethods { wrapped_tx: tx } + } +} + +pub struct PayMeProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl PayMeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl PayMeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxProxyUpgrade { + self.wrapped_tx + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl PayMeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn pay_me< + Arg0: ProxyArg, + >( + self, + arg1: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("payMe") + .argument(&arg1) + .original_result() + } + + pub fn pay_me_with_result< + Arg0: ProxyArg, + >( + self, + arg1: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("payMeWithResult") + .argument(&arg1) + .original_result() + } +} diff --git a/contracts/feature-tests/composability/proxy-test-first/src/proxy-test-first.rs b/contracts/feature-tests/composability/proxy-test-first/src/proxy-test-first.rs index d84f36e5fa..5cad76733c 100644 --- a/contracts/feature-tests/composability/proxy-test-first/src/proxy-test-first.rs +++ b/contracts/feature-tests/composability/proxy-test-first/src/proxy-test-first.rs @@ -4,46 +4,14 @@ multiversx_sc::imports!(); use hex_literal::hex; +pub mod message_me_proxy; +pub mod pay_me_proxy; + static HARDCODED_ADDRESS: [u8; 32] = hex!("fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe"); -mod pay_me_proxy { - multiversx_sc::imports!(); - - #[multiversx_sc::proxy] - pub trait PayMe { - #[payable("EGLD")] - #[endpoint(payMe)] - fn pay_me(&self, arg1: i64); - - #[payable("EGLD")] - #[endpoint(payMeWithResult)] - fn pay_me_with_result(&self, arg1: i64); - } -} - -mod message_me_proxy { - multiversx_sc::imports!(); - - #[multiversx_sc::proxy] - pub trait MessageMe { - #[init] - #[payable("EGLD")] - fn init(&self, init_arg: i32) -> i32; - - #[endpoint(messageMe)] - fn message_me(&self, arg1: i64, arg2: &BigUint, arg3: Vec, arg4: &ManagedAddress); - } -} - #[multiversx_sc::contract] pub trait ProxyTestFirst { - #[proxy] - fn pay_me_proxy(&self) -> pay_me_proxy::Proxy; - - #[proxy] - fn message_me_proxy(&self) -> message_me_proxy::Proxy; - #[storage_get("other_contract")] fn get_other_contract(&self) -> ManagedAddress; @@ -62,11 +30,18 @@ pub trait ProxyTestFirst { #[endpoint(deploySecondContract)] fn deploy_second_contract(&self, code: ManagedBuffer) -> i32 { let payment = self.call_value().egld_value(); + let (address, init_result) = self - .message_me_proxy() + .tx() + .typed(message_me_proxy::MessageMeProxy) .init(123) - .with_egld_transfer(payment.clone_value()) - .deploy_contract::(&code, CodeMetadata::UPGRADEABLE); + .code(code) + .code_metadata(CodeMetadata::UPGRADEABLE) + .returns(ReturnsNewManagedAddress) + .returns(ReturnsResult) + .egld(payment) + .sync_call(); + self.set_other_contract(&address); init_result + 1 } @@ -77,11 +52,15 @@ pub trait ProxyTestFirst { let payment = self.call_value().egld_value(); let other_contract = self.get_other_contract(); - self.message_me_proxy() - .contract(other_contract) - .init(456) // TODO: upgrade proxy - .with_egld_transfer(payment.clone_value()) - .upgrade_contract(&code, CodeMetadata::UPGRADEABLE); + self.tx() + .to(other_contract) + .typed(pay_me_proxy::PayMeProxy) + .upgrade() + .argument(&456) + .egld(payment) + .code(code) + .code_metadata(CodeMetadata::UPGRADEABLE) + .upgrade_async_call_and_exit(); } #[payable("EGLD")] @@ -89,12 +68,13 @@ pub trait ProxyTestFirst { fn forward_to_other_contract(&self) { let payment = self.call_value().egld_value(); let other_contract = self.get_other_contract(); - self.pay_me_proxy() - .contract(other_contract) + self.tx() + .to(&other_contract) + .typed(pay_me_proxy::PayMeProxy) .pay_me(0x56) - .with_egld_transfer(payment.clone_value()) + .egld(payment) .async_call() - .call_and_exit() + .call_and_exit(); } #[payable("EGLD")] @@ -102,20 +82,21 @@ pub trait ProxyTestFirst { fn forward_to_other_contract_with_callback(&self) { let payment = self.call_value().egld_value(); let other_contract = self.get_other_contract(); - self.pay_me_proxy() - .contract(other_contract) + self.tx() + .to(&other_contract) + .typed(pay_me_proxy::PayMeProxy) .pay_me_with_result(0x56) - .with_egld_transfer(payment.clone_value()) - .async_call() - .with_callback(self.callbacks().pay_callback()) - .call_and_exit() + .egld(payment) + .callback(self.callbacks().pay_callback()) + .async_call_and_exit(); } #[endpoint(messageOtherContract)] fn message_other_contract(&self) { let other_contract = self.get_other_contract(); - self.message_me_proxy() - .contract(other_contract) + self.tx() + .to(&other_contract) + .typed(message_me_proxy::MessageMeProxy) .message_me( 0x01, &BigUint::from(2u32), @@ -129,17 +110,17 @@ pub trait ProxyTestFirst { #[endpoint(messageOtherContractWithCallback)] fn message_other_contract_with_callback(&self) { let other_contract = self.get_other_contract(); - self.message_me_proxy() - .contract(other_contract) + self.tx() + .to(&other_contract) + .typed(message_me_proxy::MessageMeProxy) .message_me( 0x01, &BigUint::from(2u32), [3u8; 3].to_vec(), &ManagedAddress::from(&HARDCODED_ADDRESS), ) - .async_call() - .with_callback(self.callbacks().message_callback()) - .call_and_exit() + .callback(self.callbacks().message_callback()) + .async_call_and_exit() } #[callback(payCallback)] // although uncommon, custom callback names are possible diff --git a/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.lock b/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.lock index eb64ca8f63..582b043d05 100755 --- a/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.toml b/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.toml index b38bbd9b84..88a44946b0 100644 --- a/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/proxy-test-first/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/proxy-test-second/Cargo.toml b/contracts/feature-tests/composability/proxy-test-second/Cargo.toml index ec491380e4..d3d878969d 100644 --- a/contracts/feature-tests/composability/proxy-test-second/Cargo.toml +++ b/contracts/feature-tests/composability/proxy-test-second/Cargo.toml @@ -9,10 +9,10 @@ publish = false path = "src/proxy-test-second.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/proxy-test-second/meta/Cargo.toml b/contracts/feature-tests/composability/proxy-test-second/meta/Cargo.toml index 61e56848e6..dcfd56990b 100644 --- a/contracts/feature-tests/composability/proxy-test-second/meta/Cargo.toml +++ b/contracts/feature-tests/composability/proxy-test-second/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.lock b/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.lock index c0694e8a27..bc6cb03e36 100755 --- a/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.toml b/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.toml index 68b6ff26d7..b93eb8a20f 100644 --- a/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/proxy-test-second/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/proxy-test-second/wasm/src/lib.rs b/contracts/feature-tests/composability/proxy-test-second/wasm/src/lib.rs index e10ed79624..d920e6b80c 100644 --- a/contracts/feature-tests/composability/proxy-test-second/wasm/src/lib.rs +++ b/contracts/feature-tests/composability/proxy-test-second/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 4 +// Upgrade: 1 +// Endpoints: 3 // Async Callback (empty): 1 // Total number of exported functions: 6 diff --git a/contracts/feature-tests/composability/recursive-caller/Cargo.toml b/contracts/feature-tests/composability/recursive-caller/Cargo.toml index 2c55d5f5fb..bd7b5fa4af 100644 --- a/contracts/feature-tests/composability/recursive-caller/Cargo.toml +++ b/contracts/feature-tests/composability/recursive-caller/Cargo.toml @@ -12,9 +12,9 @@ path = "src/recursive_caller.rs" path = "../vault" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/recursive-caller/meta/Cargo.toml b/contracts/feature-tests/composability/recursive-caller/meta/Cargo.toml index f236bc8cb5..4b2f4f93b8 100644 --- a/contracts/feature-tests/composability/recursive-caller/meta/Cargo.toml +++ b/contracts/feature-tests/composability/recursive-caller/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/recursive-caller/sc-config.toml b/contracts/feature-tests/composability/recursive-caller/sc-config.toml new file mode 100644 index 0000000000..48d2e6bb8f --- /dev/null +++ b/contracts/feature-tests/composability/recursive-caller/sc-config.toml @@ -0,0 +1,2 @@ +[[proxy]] +path = "src/self_proxy.rs" diff --git a/contracts/feature-tests/composability/recursive-caller/src/recursive_caller.rs b/contracts/feature-tests/composability/recursive-caller/src/recursive_caller.rs index 617f29e901..339a9c7304 100644 --- a/contracts/feature-tests/composability/recursive-caller/src/recursive_caller.rs +++ b/contracts/feature-tests/composability/recursive-caller/src/recursive_caller.rs @@ -2,15 +2,12 @@ multiversx_sc::imports!(); +pub mod self_proxy; +pub mod vault_proxy; + /// Test contract for investigating async calls. #[multiversx_sc::contract] pub trait RecursiveCaller { - #[proxy] - fn vault_proxy(&self) -> vault::Proxy; - - #[proxy] - fn self_proxy(&self) -> self::Proxy; - #[init] fn init(&self) {} @@ -24,18 +21,18 @@ pub trait RecursiveCaller { ) { self.recursive_send_funds_event(to, token_identifier, amount, counter); - self.vault_proxy() - .contract(to.clone()) + self.tx() + .to(to) + .typed(vault_proxy::VaultProxy) .accept_funds() - .with_egld_or_single_esdt_transfer((token_identifier.clone(), 0, amount.clone())) - .async_call() - .with_callback(self.callbacks().recursive_send_funds_callback( + .egld_or_single_esdt(token_identifier, 0, amount) + .callback(self.callbacks().recursive_send_funds_callback( to, token_identifier, amount, counter, )) - .call_and_exit() + .async_call_and_exit(); } #[callback] @@ -49,8 +46,10 @@ pub trait RecursiveCaller { self.recursive_send_funds_callback_event(to, token_identifier, amount, counter); if counter > 1 { - self.self_proxy() - .contract(self.blockchain().get_sc_address()) + let self_address = self.blockchain().get_sc_address(); + self.tx() + .to(&self_address) + .typed(self_proxy::RecursiveCallerProxy) .recursive_send_funds(to, token_identifier, amount, counter - 1) .async_call() .call_and_exit() diff --git a/contracts/feature-tests/composability/recursive-caller/src/self_proxy.rs b/contracts/feature-tests/composability/recursive-caller/src/self_proxy.rs new file mode 100644 index 0000000000..7fd86a1c8f --- /dev/null +++ b/contracts/feature-tests/composability/recursive-caller/src/self_proxy.rs @@ -0,0 +1,84 @@ +// 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 RecursiveCallerProxy; + +impl TxProxyTrait for RecursiveCallerProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = RecursiveCallerProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + RecursiveCallerProxyMethods { wrapped_tx: tx } + } +} + +pub struct RecursiveCallerProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl RecursiveCallerProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl RecursiveCallerProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn recursive_send_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg, + >( + self, + to: Arg0, + token_identifier: Arg1, + amount: Arg2, + counter: Arg3, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("recursive_send_funds") + .argument(&to) + .argument(&token_identifier) + .argument(&amount) + .argument(&counter) + .original_result() + } +} diff --git a/contracts/feature-tests/composability/recursive-caller/src/vault_proxy.rs b/contracts/feature-tests/composability/recursive-caller/src/vault_proxy.rs new file mode 100644 index 0000000000..c43f59c36a --- /dev/null +++ b/contracts/feature-tests/composability/recursive-caller/src/vault_proxy.rs @@ -0,0 +1,262 @@ +// 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 VaultProxy; + +impl TxProxyTrait for VaultProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = VaultProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + VaultProxyMethods { wrapped_tx: tx } + } +} + +pub struct VaultProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + opt_arg_to_echo: Arg0, + ) -> TxProxyDeploy>> { + self.wrapped_tx + .raw_deploy() + .argument(&opt_arg_to_echo) + .original_result() + } +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>>, + >( + self, + opt_arg_to_echo: Arg0, + ) -> TxProxyUpgrade>>> { + self.wrapped_tx + .raw_upgrade() + .argument(&opt_arg_to_echo) + .original_result() + } +} + +#[rustfmt::skip] +impl VaultProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn echo_arguments< + Arg0: ProxyArg>>, + >( + self, + args: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("echo_arguments") + .argument(&args) + .original_result() + } + + pub fn echo_arguments_without_storage< + Arg0: ProxyArg>>, + >( + self, + args: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("echo_arguments_without_storage") + .argument(&args) + .original_result() + } + + pub fn echo_caller( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("echo_caller") + .original_result() + } + + pub fn accept_funds( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("accept_funds") + .original_result() + } + + pub fn accept_funds_echo_payment( + self, + ) -> TxProxyCall, MultiValueEncoded>>> { + self.wrapped_tx + .raw_call("accept_funds_echo_payment") + .original_result() + } + + pub fn accept_funds_single_esdt_transfer( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("accept_funds_single_esdt_transfer") + .original_result() + } + + pub fn reject_funds( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("reject_funds") + .original_result() + } + + pub fn retrieve_funds_with_transfer_exec< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + >( + self, + token: Arg0, + amount: Arg1, + opt_receive_func: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds_with_transfer_exec") + .argument(&token) + .argument(&amount) + .argument(&opt_receive_func) + .original_result() + } + + pub fn retrieve_funds_promises< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + back_transfers: Arg0, + back_transfer_value: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds_promises") + .argument(&back_transfers) + .argument(&back_transfer_value) + .original_result() + } + + pub fn retrieve_funds< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + token: Arg0, + nonce: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_funds") + .argument(&token) + .argument(&nonce) + .argument(&amount) + .original_result() + } + + pub fn retrieve_multi_funds_async< + Arg0: ProxyArg, u64, BigUint>>>, + >( + self, + token_payments: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("retrieve_multi_funds_async") + .argument(&token_payments) + .original_result() + } + + pub fn burn_and_create_retrieve_async( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("burn_and_create_retrieve_async") + .original_result() + } + + pub fn get_owner_address( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("get_owner_address") + .original_result() + } + + /// We already leave a trace of the calls using the event logs; + /// this additional counter has the role of showing that storage also gets saved correctly. + pub fn call_counts< + Arg0: ProxyArg>, + >( + self, + endpoint: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("call_counts") + .argument(&endpoint) + .original_result() + } + + pub fn num_called_retrieve_funds_promises( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("num_called_retrieve_funds_promises") + .original_result() + } + + pub fn num_async_calls_sent_from_child( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("num_async_calls_sent_from_child") + .original_result() + } +} diff --git a/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.lock b/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.lock index 2a46d970f4..612de9c53d 100755 --- a/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.toml b/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.toml index 077d61f49f..d12fc3c8c6 100644 --- a/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/recursive-caller/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/scenarios/forw_raw_contract_deploy.scen.json b/contracts/feature-tests/composability/scenarios/forw_raw_contract_deploy.scen.json index dfaf89f427..5e0097f354 100644 --- a/contracts/feature-tests/composability/scenarios/forw_raw_contract_deploy.scen.json +++ b/contracts/feature-tests/composability/scenarios/forw_raw_contract_deploy.scen.json @@ -88,7 +88,6 @@ }, "expect": { "out": [ - "str:some_argument", "sc:child-with-arg", "nested:str:some_argument" ], @@ -129,7 +128,6 @@ }, "expect": { "out": [ - "str:some_argument", "sc:child-src-with-arg" ], "status": "0", diff --git a/contracts/feature-tests/composability/scenarios/forw_raw_init_sync_echo.scen.json b/contracts/feature-tests/composability/scenarios/forw_raw_init_sync_echo.scen.json index 2c1bc8dff7..085233e5a9 100644 --- a/contracts/feature-tests/composability/scenarios/forw_raw_init_sync_echo.scen.json +++ b/contracts/feature-tests/composability/scenarios/forw_raw_init_sync_echo.scen.json @@ -37,10 +37,7 @@ "gasPrice": "0" }, "expect": { - "out": [ - "1", - "2" - ], + "out": [], "status": "", "logs": [ { diff --git a/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo.scen.json b/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo.scen.json index ac1f58b191..a34e9497fd 100644 --- a/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo.scen.json +++ b/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo.scen.json @@ -37,10 +37,7 @@ "gasPrice": "0" }, "expect": { - "out": [ - "1", - "2" - ], + "out": [], "status": "0", "logs": [ { @@ -94,12 +91,7 @@ "gasPrice": "0" }, "expect": { - "out": [ - "1", - "2", - "1", - "2" - ], + "out": [], "status": "0", "logs": [ { diff --git a/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo_caller.scen.json b/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo_caller.scen.json index 99bf0f279f..a964ec9e19 100644 --- a/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo_caller.scen.json +++ b/contracts/feature-tests/composability/scenarios/forw_raw_sync_echo_caller.scen.json @@ -35,9 +35,7 @@ "gasPrice": "0" }, "expect": { - "out": [ - "sc:forwarder" - ], + "out": [], "status": "0", "logs": [ { @@ -82,10 +80,7 @@ "gasPrice": "0" }, "expect": { - "out": [ - "sc:forwarder", - "sc:forwarder" - ], + "out": [], "status": "0", "logs": [ { diff --git a/contracts/feature-tests/composability/scenarios/forw_raw_sync_readonly.scen.json b/contracts/feature-tests/composability/scenarios/forw_raw_sync_readonly.scen.json index f1b53d61ea..0da08b7c08 100644 --- a/contracts/feature-tests/composability/scenarios/forw_raw_sync_readonly.scen.json +++ b/contracts/feature-tests/composability/scenarios/forw_raw_sync_readonly.scen.json @@ -37,10 +37,7 @@ "gasPrice": "0" }, "expect": { - "out": [ - "1", - "2" - ], + "out": [], "status": "", "gas": "*", "refund": "*" diff --git a/contracts/feature-tests/composability/scenarios/forw_raw_sync_same_context.scen.json b/contracts/feature-tests/composability/scenarios/forw_raw_sync_same_context.scen.json index 08b6b3349b..ff8b81238c 100644 --- a/contracts/feature-tests/composability/scenarios/forw_raw_sync_same_context.scen.json +++ b/contracts/feature-tests/composability/scenarios/forw_raw_sync_same_context.scen.json @@ -38,10 +38,7 @@ "gasPrice": "0" }, "expect": { - "out": [ - "1", - "2" - ], + "out": [], "status": "", "logs": [ { diff --git a/contracts/feature-tests/composability/forwarder/tests/forwarder_blackbox_test.rs b/contracts/feature-tests/composability/tests/forwarder_blackbox_legacy_test.rs similarity index 73% rename from contracts/feature-tests/composability/forwarder/tests/forwarder_blackbox_test.rs rename to contracts/feature-tests/composability/tests/forwarder_blackbox_legacy_test.rs index bbe8d68ecb..cc13982a2d 100644 --- a/contracts/feature-tests/composability/forwarder/tests/forwarder_blackbox_test.rs +++ b/contracts/feature-tests/composability/tests/forwarder_blackbox_legacy_test.rs @@ -1,4 +1,6 @@ -use forwarder::nft::{Color, ProxyTrait as _}; +#![allow(deprecated)] + +use forwarder_legacy::nft_legacy::{Color, ProxyTrait as _}; use multiversx_sc_scenario::{ api::StaticApi, @@ -9,32 +11,32 @@ use multiversx_sc_scenario::{ }; 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 FORWARDER_ADDRESS_EXPR: &str = "sc:forwarder_legacy"; +const FORWARDER_PATH_EXPR: &str = "mxsc:output/forwarder_legacy.mxsc.json"; const NFT_TOKEN_ID_EXPR: &str = "str:COOL-123456"; const NFT_TOKEN_ID: &[u8] = b"COOL-123456"; -type ForwarderContract = ContractInfo>; +type ForwarderContract = ContractInfo>; fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.set_current_dir_from_workspace("contracts/composability/forwarder"); + blockchain.set_current_dir_from_workspace("contracts/composability/"); - blockchain.register_contract(FORWARDER_PATH_EXPR, forwarder::ContractBuilder); + blockchain.register_contract(FORWARDER_PATH_EXPR, forwarder_legacy::ContractBuilder); blockchain } struct ForwarderTestState { world: ScenarioWorld, - forwarder_contract: ForwarderContract, + forwarder_legacy_contract: ForwarderContract, } impl ForwarderTestState { fn new() -> Self { let mut world = world(); - let forwarder_code = world.code_expression(FORWARDER_PATH_EXPR); + let forwarder_legacy_code = world.code_expression(FORWARDER_PATH_EXPR); let roles = vec![ "ESDTRoleNFTCreate".to_string(), "ESDTRoleNFTUpdateAttributes".to_string(), @@ -47,16 +49,16 @@ impl ForwarderTestState { FORWARDER_ADDRESS_EXPR, Account::new() .nonce(1) - .code(forwarder_code) + .code(forwarder_legacy_code) .esdt_roles(NFT_TOKEN_ID_EXPR, roles), ), ); - let forwarder_contract = ForwarderContract::new(FORWARDER_ADDRESS_EXPR); + let forwarder_legacy_contract = ForwarderContract::new(FORWARDER_ADDRESS_EXPR); Self { world, - forwarder_contract, + forwarder_legacy_contract, } } } @@ -69,9 +71,11 @@ fn test_nft_update_attributes_and_send() { state.world.sc_call( ScCallStep::new().from(USER_ADDRESS_EXPR).call( - state - .forwarder_contract - .nft_create_compact(NFT_TOKEN_ID, 1u64, original_attributes), + state.forwarder_legacy_contract.nft_create_compact( + NFT_TOKEN_ID, + 1u64, + original_attributes, + ), ), ); @@ -109,9 +113,11 @@ fn test_nft_update_attributes_and_send() { state.world.sc_call( ScCallStep::new().from(USER_ADDRESS_EXPR).call( - state - .forwarder_contract - .nft_update_attributes(NFT_TOKEN_ID, 1u64, new_attributes), + state.forwarder_legacy_contract.nft_update_attributes( + NFT_TOKEN_ID, + 1u64, + new_attributes, + ), ), ); diff --git a/contracts/feature-tests/composability/tests/forwarder_blackbox_test.rs b/contracts/feature-tests/composability/tests/forwarder_blackbox_test.rs new file mode 100644 index 0000000000..7dd5c1a81b --- /dev/null +++ b/contracts/feature-tests/composability/tests/forwarder_blackbox_test.rs @@ -0,0 +1,103 @@ +use forwarder::forwarder_proxy; + +use multiversx_sc_scenario::imports::*; + +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"); +const NFT_TOKEN: &[u8] = b"COOL-123456"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract(FORWARDER_PATH, forwarder::ContractBuilder); + blockchain +} + +struct ForwarderTestState { + world: ScenarioWorld, +} + +impl ForwarderTestState { + fn new() -> Self { + let mut world = world(); + + let roles = vec![ + "ESDTRoleNFTCreate".to_string(), + "ESDTRoleNFTUpdateAttributes".to_string(), + ]; + + world.account(USER_ADDRESS).nonce(1); + world + .account(FORWARDER_ADDRESS) + .nonce(1) + .code(FORWARDER_PATH) + .esdt_roles(NFT_TOKEN_ID, roles); + + Self { world } + } +} + +#[test] +fn test_nft_update_attributes_and_send() { + let mut state = ForwarderTestState::new(); + + let original_attributes = forwarder_proxy::Color { r: 0, g: 0, b: 0 }; + + state + .world + .tx() + .from(USER_ADDRESS) + .to(FORWARDER_ADDRESS) + .typed(forwarder_proxy::ForwarderProxy) + .nft_create_compact(NFT_TOKEN_ID, 1u64, original_attributes) + .run(); + + state.world.transfer_step( + TransferStep::new() + .from(FORWARDER_ADDRESS.eval_to_expr().as_str()) + .to(USER_ADDRESS.eval_to_expr().as_str()) + .esdt_transfer(NFT_TOKEN, 1, "1"), + ); + + state + .world + .check_account(USER_ADDRESS) + .esdt_nft_balance_and_attributes(NFT_TOKEN_ID, 1, 1, original_attributes); + + let new_attributes = forwarder_proxy::Color { + r: 255, + g: 255, + b: 255, + }; + + state.world.transfer_step( + TransferStep::new() + .from(USER_ADDRESS.eval_to_expr().as_str()) + .to(FORWARDER_ADDRESS.eval_to_expr().as_str()) + .esdt_transfer(NFT_TOKEN, 1, "1"), + ); + + state + .world + .tx() + .from(USER_ADDRESS) + .to(FORWARDER_ADDRESS) + .typed(forwarder_proxy::ForwarderProxy) + .nft_update_attributes(NFT_TOKEN_ID, 1u64, new_attributes) + .run(); + + state.world.transfer_step( + TransferStep::new() + .from(FORWARDER_ADDRESS.eval_to_expr().as_str()) + .to(USER_ADDRESS.eval_to_expr().as_str()) + .esdt_transfer(NFT_TOKEN, 1, "1"), + ); + + state + .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_legacy_test.rs b/contracts/feature-tests/composability/tests/forwarder_whitebox_legacy_test.rs new file mode 100644 index 0000000000..d829016176 --- /dev/null +++ b/contracts/feature-tests/composability/tests/forwarder_whitebox_legacy_test.rs @@ -0,0 +1,118 @@ +use forwarder_legacy::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"; + +const NFT_TOKEN_ID_EXPR: &str = "str:COOL-123456"; +const NFT_TOKEN_ID: &[u8] = b"COOL-123456"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/composability/forwarder_legacy"); + + blockchain.register_contract(FORWARDER_PATH_EXPR, forwarder_legacy::ContractBuilder); + blockchain +} + +#[test] +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); + + let original_attributes = Color { r: 0, g: 0, b: 0 }; + + world.whitebox_call( + &forwarder_legacy_whitebox, + ScCallStep::new().from(USER_ADDRESS_EXPR), + |sc| { + sc.nft_create_compact( + managed_token_id!(NFT_TOKEN_ID), + 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), + ); + }, + ); + + 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), + ), + )); + + let new_attributes = Color { + r: 255, + g: 255, + 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() +} diff --git a/contracts/feature-tests/composability/forwarder/tests/forwarder_whitebox_test.rs b/contracts/feature-tests/composability/tests/forwarder_whitebox_test.rs similarity index 91% rename from contracts/feature-tests/composability/forwarder/tests/forwarder_whitebox_test.rs rename to contracts/feature-tests/composability/tests/forwarder_whitebox_test.rs index 4cb15d884f..0adb09b286 100644 --- a/contracts/feature-tests/composability/forwarder/tests/forwarder_whitebox_test.rs +++ b/contracts/feature-tests/composability/tests/forwarder_whitebox_test.rs @@ -1,12 +1,5 @@ use forwarder::nft::{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, -}; +use multiversx_sc_scenario::imports::*; const USER_ADDRESS_EXPR: &str = "address:user"; const FORWARDER_ADDRESS_EXPR: &str = "sc:forwarder"; 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 a2ee00c631..180cb1c508 100644 --- a/contracts/feature-tests/composability/tests/promises_feature_blackbox_test.rs +++ b/contracts/feature-tests/composability/tests/promises_feature_blackbox_test.rs @@ -1,9 +1,7 @@ +#![allow(deprecated)] // TODO: unified syntax + use multiversx_sc::types::BigUint; -use multiversx_sc_scenario::{ - api::StaticApi, - scenario_model::{Account, CheckAccount, CheckStateStep, ScCallStep, SetStateStep}, - ContractInfo, ScenarioWorld, -}; +use multiversx_sc_scenario::imports::*; use promises_features::call_sync_bt::ProxyTrait; diff --git a/contracts/feature-tests/composability/transfer-role-features/Cargo.toml b/contracts/feature-tests/composability/transfer-role-features/Cargo.toml index 6ac8831405..9f1da71c0b 100644 --- a/contracts/feature-tests/composability/transfer-role-features/Cargo.toml +++ b/contracts/feature-tests/composability/transfer-role-features/Cargo.toml @@ -12,13 +12,13 @@ path = "src/lib.rs" path = "../vault" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../contracts/modules" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/transfer-role-features/meta/Cargo.toml b/contracts/feature-tests/composability/transfer-role-features/meta/Cargo.toml index 58b8add8ee..3100fcd04c 100644 --- a/contracts/feature-tests/composability/transfer-role-features/meta/Cargo.toml +++ b/contracts/feature-tests/composability/transfer-role-features/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/transfer-role-features/src/lib.rs b/contracts/feature-tests/composability/transfer-role-features/src/lib.rs index b689b76d43..125cd4fb23 100644 --- a/contracts/feature-tests/composability/transfer-role-features/src/lib.rs +++ b/contracts/feature-tests/composability/transfer-role-features/src/lib.rs @@ -30,7 +30,7 @@ pub trait TransferRoleFeatures: } if !self.blockchain().is_smart_contract(&dest) { - self.transfer_to_user(original_caller, dest, payments.clone_value(), endpoint_name); + self.transfer_to_user(original_caller, dest, &payments, endpoint_name); } else { let mut args_buffer = ManagedArgBuffer::new(); for arg in args { @@ -40,7 +40,7 @@ pub trait TransferRoleFeatures: self.transfer_to_contract_raw( original_caller, dest, - payments.clone_value(), + &payments, endpoint_name, args_buffer, None, diff --git a/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_blackbox_test.rs b/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_blackbox_test.rs index acaefbfb1d..a1588759d6 100644 --- a/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_blackbox_test.rs +++ b/contracts/feature-tests/composability/transfer-role-features/tests/transfer_role_blackbox_test.rs @@ -1,12 +1,6 @@ -use multiversx_sc::{codec::multi_types::MultiValueVec, types::Address}; -use multiversx_sc_scenario::{ - api::StaticApi, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, - SetStateStep, TxExpect, - }, - ContractInfo, ScenarioWorld, -}; +#![allow(deprecated)] // TODO: unified syntax + +use multiversx_sc_scenario::imports::*; use transfer_role_features::ProxyTrait as _; const ACCEPT_FUNDS_FUNC_NAME: &[u8] = b"accept_funds"; 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 155f82ce9d..dc733dede9 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,14 +1,5 @@ -use multiversx_sc::types::{ - Address, EsdtTokenPayment, ManagedArgBuffer, ManagedVec, MultiValueEncoded, -}; use multiversx_sc_modules::transfer_role_proxy::TransferRoleProxyModule; -use multiversx_sc_scenario::{ - managed_address, managed_biguint, managed_buffer, managed_token_id, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, SetStateStep, - }, - ScenarioWorld, WhiteboxContract, -}; +use multiversx_sc_scenario::imports::*; use transfer_role_features::TransferRoleFeatures; const OWNER_ADDRESS_EXPR: &str = "address:owner"; @@ -104,7 +95,7 @@ fn test_transfer_role() { sc.transfer_to_user( managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), managed_address!(&address_expr_to_address(OWNER_ADDRESS_EXPR)), - payments, + &payments, managed_buffer!(b"enjoy"), ); }, @@ -135,7 +126,7 @@ fn test_transfer_role() { sc.transfer_to_user( managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), managed_address!(&Address::zero()), - payments, + &payments, managed_buffer!(b"enjoy"), ); }, @@ -159,7 +150,7 @@ fn test_transfer_role() { sc.transfer_to_contract_raw( managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), managed_address!(&address_expr_to_address(VAULT_ADDRESS_EXPR)), - payments, + &payments, managed_buffer!(ACCEPT_FUNDS_FUNC_NAME), ManagedArgBuffer::new(), None, @@ -191,7 +182,7 @@ fn test_transfer_role() { sc.transfer_to_contract_raw( managed_address!(&address_expr_to_address(USER_ADDRESS_EXPR)), managed_address!(&address_expr_to_address(VAULT_ADDRESS_EXPR)), - payments, + &payments, managed_buffer!(REJECT_FUNDS_FUNC_NAME), ManagedArgBuffer::new(), None, diff --git a/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.lock b/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.lock index 24369519bc..62d98f1411 100644 --- a/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,14 +80,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.toml b/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.toml index 92ca0cea4d..6a49bd9d5c 100644 --- a/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/transfer-role-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/vault/Cargo.toml b/contracts/feature-tests/composability/vault/Cargo.toml index aece88286e..58201feda6 100644 --- a/contracts/feature-tests/composability/vault/Cargo.toml +++ b/contracts/feature-tests/composability/vault/Cargo.toml @@ -10,9 +10,9 @@ path = "src/vault.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/composability/vault/meta/Cargo.toml b/contracts/feature-tests/composability/vault/meta/Cargo.toml index 2a7c63ee3f..e7d99c51cc 100644 --- a/contracts/feature-tests/composability/vault/meta/Cargo.toml +++ b/contracts/feature-tests/composability/vault/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/composability/vault/sc-config.toml b/contracts/feature-tests/composability/vault/sc-config.toml index f0d4da2f02..130812eff2 100644 --- a/contracts/feature-tests/composability/vault/sc-config.toml +++ b/contracts/feature-tests/composability/vault/sc-config.toml @@ -15,3 +15,12 @@ add-labels = ["promises-endpoint"] name = "vault-upgrade" add-unlabelled = false add-labels = ["upgrade"] + +[[proxy]] +path = "../forwarder/src/vault_proxy.rs" + +[[proxy]] +path = "../promises-features/src/vault_proxy.rs" + +[[proxy]] +path = "../recursive-caller/src/vault_proxy.rs" diff --git a/contracts/feature-tests/composability/vault/src/vault.rs b/contracts/feature-tests/composability/vault/src/vault.rs index 9dfaa11a07..1fb32cccdd 100644 --- a/contracts/feature-tests/composability/vault/src/vault.rs +++ b/contracts/feature-tests/composability/vault/src/vault.rs @@ -107,16 +107,12 @@ pub trait Vault { let caller = self.blockchain().get_caller(); let func_name = opt_receive_func.into_option().unwrap_or_default(); - self.send_raw() - .transfer_esdt_execute( - &caller, - &token, - &amount, - 50_000_000, - &func_name, - &ManagedArgBuffer::new(), - ) - .unwrap_or_else(|_| sc_panic!("ESDT transfer failed")); + self.tx() + .to(&caller) + .gas(50_000_000u64) + .raw_call(func_name) + .single_esdt(&token, 0u64, &amount) + .transfer_execute(); } #[allow_multiple_var_args] @@ -150,10 +146,11 @@ pub trait Vault { for _ in 0..nr_callbacks { self.num_async_calls_sent_from_child().update(|c| *c += 1); - self.send() - .contract_call::<()>(caller.clone(), endpoint_name.clone()) - .with_egld_or_single_esdt_transfer(return_payment.clone()) - .with_gas_limit(self.blockchain().get_gas_left() / 2) + self.tx() + .to(&caller) + .raw_call(endpoint_name.clone()) + .payment(&return_payment) + .gas(self.blockchain().get_gas_left() / 2) .transfer_execute() } } @@ -164,10 +161,12 @@ pub trait Vault { let caller = self.blockchain().get_caller(); if let Some(esdt_token_id) = token.into_esdt_option() { - self.send() - .direct_esdt(&caller, &esdt_token_id, nonce, &amount); + self.tx() + .to(caller) + .esdt((esdt_token_id, nonce, amount)) + .transfer(); } else { - self.send().direct_egld(&caller, &amount); + self.tx().to(caller).egld(amount).transfer(); } } @@ -185,12 +184,12 @@ pub trait Vault { all_payments.push(EsdtTokenPayment::new(token_id, nonce, amount)); } - self.send().direct_multi(&caller, &all_payments); + self.tx().to(caller).payment(all_payments).transfer(); } #[payable("*")] #[endpoint] - fn burn_and_create_retrive_async(&self) { + fn burn_and_create_retrieve_async(&self) { let payments = self.call_value().all_esdt_transfers(); let mut uris = ManagedVec::new(); uris.push(ManagedBuffer::new()); @@ -223,8 +222,7 @@ pub trait Vault { )); } - self.send() - .direct_multi(&self.blockchain().get_caller(), &new_tokens); + self.tx().to(ToCaller).payment(new_tokens).transfer(); } #[event("accept_funds")] diff --git a/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.lock b/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.lock index 8df1fd19a5..ec577ac90a 100644 --- a/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.lock +++ b/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.toml b/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.toml index b7c65021e3..9d3799aedb 100644 --- a/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.toml +++ b/contracts/feature-tests/composability/vault/wasm-vault-promises/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/vault/wasm-vault-promises/src/lib.rs b/contracts/feature-tests/composability/vault/wasm-vault-promises/src/lib.rs index f1a599dafe..6a814f3b57 100644 --- a/contracts/feature-tests/composability/vault/wasm-vault-promises/src/lib.rs +++ b/contracts/feature-tests/composability/vault/wasm-vault-promises/src/lib.rs @@ -30,7 +30,7 @@ multiversx_sc_wasm_adapter::endpoints! { retrieve_funds_with_transfer_exec => retrieve_funds_with_transfer_exec retrieve_funds => retrieve_funds retrieve_multi_funds_async => retrieve_multi_funds_async - burn_and_create_retrive_async => burn_and_create_retrive_async + burn_and_create_retrieve_async => burn_and_create_retrieve_async get_owner_address => get_owner_address call_counts => call_counts num_called_retrieve_funds_promises => num_called_retrieve_funds_promises diff --git a/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.lock b/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.lock index b0b9342959..6d9e7ffafe 100644 --- a/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.lock +++ b/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.toml b/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.toml index 26b9b015cd..d0e8dd308b 100644 --- a/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.toml +++ b/contracts/feature-tests/composability/vault/wasm-vault-upgrade/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/vault/wasm-vault-upgrade/src/lib.rs b/contracts/feature-tests/composability/vault/wasm-vault-upgrade/src/lib.rs index 904a343933..1592f8eec6 100644 --- a/contracts/feature-tests/composability/vault/wasm-vault-upgrade/src/lib.rs +++ b/contracts/feature-tests/composability/vault/wasm-vault-upgrade/src/lib.rs @@ -4,10 +4,10 @@ ////////////////// AUTO-GENERATED ////////////////// //////////////////////////////////////////////////// -// Init: 1 -// Endpoints: 1 +// Upgrade: 1 +// Endpoints: 0 // Async Callback (empty): 1 -// Total number of exported functions: 3 +// Total number of exported functions: 2 #![no_std] #![allow(internal_features)] diff --git a/contracts/feature-tests/composability/vault/wasm/Cargo.lock b/contracts/feature-tests/composability/vault/wasm/Cargo.lock index 5d36265ec2..64462a7d14 100755 --- a/contracts/feature-tests/composability/vault/wasm/Cargo.lock +++ b/contracts/feature-tests/composability/vault/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/composability/vault/wasm/Cargo.toml b/contracts/feature-tests/composability/vault/wasm/Cargo.toml index d8d3d17aac..7b8ee74e2c 100644 --- a/contracts/feature-tests/composability/vault/wasm/Cargo.toml +++ b/contracts/feature-tests/composability/vault/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/composability/vault/wasm/src/lib.rs b/contracts/feature-tests/composability/vault/wasm/src/lib.rs index 3ef976396a..30a7fadf8b 100644 --- a/contracts/feature-tests/composability/vault/wasm/src/lib.rs +++ b/contracts/feature-tests/composability/vault/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 16 +// Upgrade: 1 +// Endpoints: 15 // Async Callback (empty): 1 // Total number of exported functions: 18 @@ -20,6 +21,7 @@ multiversx_sc_wasm_adapter::endpoints! { vault ( init => init + upgrade => upgrade echo_arguments => echo_arguments echo_arguments_without_storage => echo_arguments_without_storage echo_caller => echo_caller @@ -30,12 +32,11 @@ multiversx_sc_wasm_adapter::endpoints! { retrieve_funds_with_transfer_exec => retrieve_funds_with_transfer_exec retrieve_funds => retrieve_funds retrieve_multi_funds_async => retrieve_multi_funds_async - burn_and_create_retrive_async => burn_and_create_retrive_async + burn_and_create_retrieve_async => burn_and_create_retrieve_async get_owner_address => get_owner_address call_counts => call_counts num_called_retrieve_funds_promises => num_called_retrieve_funds_promises num_async_calls_sent_from_child => num_async_calls_sent_from_child - upgrade => upgrade ) } diff --git a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/Cargo.toml b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/Cargo.toml index 5c18660536..f3e9127598 100644 --- a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/Cargo.toml @@ -12,10 +12,10 @@ path = "src/crowdfunding_erc20.rs" path = "../erc20" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/meta/Cargo.toml b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/meta/Cargo.toml index f929c7c105..fdee90fda9 100644 --- a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/meta/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/src/crowdfunding_erc20.rs b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/src/crowdfunding_erc20.rs index fe509eba5b..019ec560a5 100644 --- a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/src/crowdfunding_erc20.rs +++ b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/src/crowdfunding_erc20.rs @@ -3,6 +3,8 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); +pub mod erc20_proxy; + #[derive(TopEncode, TopDecode, PartialEq, Eq, TypeAbi, Clone, Copy)] pub enum Status { FundingPeriod, @@ -30,14 +32,15 @@ pub trait Crowdfunding { let erc20_address = self.erc20_contract_address().get(); let cf_contract_address = self.blockchain().get_sc_address(); - self.erc20_proxy(erc20_address) + self.tx() + .to(&erc20_address) + .typed(erc20_proxy::SimpleErc20TokenProxy) .transfer_from(caller.clone(), cf_contract_address, token_amount.clone()) - .async_call() - .with_callback( + .callback( self.callbacks() .transfer_from_callback(caller, token_amount), ) - .call_and_exit() + .async_call_and_exit(); } #[view] @@ -70,10 +73,11 @@ pub trait Crowdfunding { let erc20_address = self.erc20_contract_address().get(); - self.erc20_proxy(erc20_address) + self.tx() + .to(&erc20_address) + .typed(erc20_proxy::SimpleErc20TokenProxy) .transfer(caller, balance) - .async_call() - .call_and_exit() + .async_call_and_exit(); }, Status::Failed => { let caller = self.blockchain().get_caller(); @@ -84,10 +88,11 @@ pub trait Crowdfunding { let erc20_address = self.erc20_contract_address().get(); - self.erc20_proxy(erc20_address) + self.tx() + .to(&erc20_address) + .typed(erc20_proxy::SimpleErc20TokenProxy) .transfer(caller, deposit) - .async_call() - .call_and_exit() + .async_call_and_exit(); } }, } @@ -106,10 +111,11 @@ pub trait Crowdfunding { if self.blockchain().get_block_nonce() > self.deadline().get() { let erc20_address = self.erc20_contract_address().get(); - self.erc20_proxy(erc20_address) + self.tx() + .to(&erc20_address) + .typed(erc20_proxy::SimpleErc20TokenProxy) .transfer(cb_sender, cb_amount) - .async_call() - .call_and_exit(); + .async_call_and_exit(); } self.deposit(&cb_sender) @@ -120,11 +126,6 @@ pub trait Crowdfunding { } } - // proxy - - #[proxy] - fn erc20_proxy(&self, to: ManagedAddress) -> erc20::Proxy; - // storage #[view(get_target)] diff --git a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/src/erc20_proxy.rs b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/src/erc20_proxy.rs new file mode 100644 index 0000000000..eaceb1da73 --- /dev/null +++ b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/src/erc20_proxy.rs @@ -0,0 +1,188 @@ +// 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 SimpleErc20TokenProxy; + +impl TxProxyTrait for SimpleErc20TokenProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = SimpleErc20TokenProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + SimpleErc20TokenProxyMethods { wrapped_tx: tx } + } +} + +pub struct SimpleErc20TokenProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl SimpleErc20TokenProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + /// Constructor, is called immediately after the contract is created + /// Will set the fixed global token supply and give all the supply to the creator. + pub fn init< + Arg0: ProxyArg>, + >( + self, + total_supply: Arg0, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&total_supply) + .original_result() + } +} + +#[rustfmt::skip] +impl SimpleErc20TokenProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Total number of tokens in existence. + pub fn total_supply( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("totalSupply") + .original_result() + } + + /// Gets the balance of the specified address. + /// + /// Arguments: + /// + /// * `address` The address to query the the balance of + /// + pub fn token_balance< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("balanceOf") + .argument(&address) + .original_result() + } + + /// The amount of tokens that an owner allowed to a spender. + /// + /// Arguments: + /// + /// * `owner` The address that owns the funds. + /// * `spender` The address that will spend the funds. + /// + pub fn allowance< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + owner: Arg0, + spender: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("allowance") + .argument(&owner) + .argument(&spender) + .original_result() + } + + /// Transfer token to a specified address from sender. + /// + /// Arguments: + /// + /// * `to` The address to transfer to. + /// + pub fn transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer") + .argument(&to) + .argument(&amount) + .original_result() + } + + /// Use allowance to transfer funds between two accounts. + /// + /// Arguments: + /// + /// * `sender` The address to transfer from. + /// * `recipient` The address to transfer to. + /// * `amount` the amount of tokens to be transferred. + /// + pub fn transfer_from< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + sender: Arg0, + recipient: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transferFrom") + .argument(&sender) + .argument(&recipient) + .argument(&amount) + .original_result() + } + + /// Approve the given address to spend the specified amount of tokens on behalf of the sender. + /// It overwrites any previously existing allowance from sender to beneficiary. + /// + /// Arguments: + /// + /// * `spender` The address that will spend the funds. + /// * `amount` The amount of tokens to be spent. + /// + pub fn approve< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + spender: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approve") + .argument(&spender) + .argument(&amount) + .original_result() + } +} diff --git a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.lock b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.lock index e4339b3283..9848b01662 100644 --- a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.lock +++ b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.lock @@ -63,7 +63,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -103,7 +103,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.toml b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.toml index 0b8c916c0a..20285a8b66 100644 --- a/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/crowdfunding-erc20/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/Cargo.toml index 0cb5ab615f..630c24b5f2 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/Cargo.toml @@ -13,10 +13,10 @@ path = "src/lib.rs" path = "../erc1155" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/meta/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/meta/Cargo.toml index 2555c62735..64f519f9a3 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/meta/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/src/erc1155_proxy.rs b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/src/erc1155_proxy.rs new file mode 100644 index 0000000000..899a036f41 --- /dev/null +++ b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/src/erc1155_proxy.rs @@ -0,0 +1,269 @@ +// 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 Erc1155Proxy; + +impl TxProxyTrait for Erc1155Proxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = Erc1155ProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + Erc1155ProxyMethods { wrapped_tx: tx } + } +} + +pub struct Erc1155ProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl Erc1155ProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl Erc1155ProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// `value` is amount for fungible, nft_id for non-fungible + pub fn safe_transfer_from< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + >( + self, + from: Arg0, + to: Arg1, + type_id: Arg2, + value: Arg3, + data: Arg4, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("safeTransferFrom") + .argument(&from) + .argument(&to) + .argument(&type_id) + .argument(&value) + .argument(&data) + .original_result() + } + + /// `value` is amount for fungible, nft_id for non-fungible + pub fn safe_batch_transfer_from< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg]>>, + Arg3: ProxyArg]>>, + Arg4: ProxyArg>, + >( + self, + from: Arg0, + to: Arg1, + type_ids: Arg2, + values: Arg3, + data: Arg4, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("safeBatchTransferFrom") + .argument(&from) + .argument(&to) + .argument(&type_ids) + .argument(&values) + .argument(&data) + .original_result() + } + + pub fn set_approved_for_all< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + operator: Arg0, + approved: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("setApprovalForAll") + .argument(&operator) + .argument(&approved) + .original_result() + } + + pub fn create_token< + Arg0: ProxyArg, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + uri: Arg0, + initial_supply: Arg1, + is_fungible: Arg2, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("createToken") + .argument(&uri) + .argument(&initial_supply) + .argument(&is_fungible) + .original_result() + } + + pub fn mint< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + type_id: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("mint") + .argument(&type_id) + .argument(&amount) + .original_result() + } + + pub fn burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + type_id: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("burn") + .argument(&type_id) + .argument(&amount) + .original_result() + } + + pub fn balance_of< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + owner: Arg0, + type_id: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("balanceOf") + .argument(&owner) + .argument(&type_id) + .original_result() + } + + pub fn balance_of_batch< + Arg0: ProxyArg, BigUint>>>, + >( + self, + owner_type_id_pairs: Arg0, + ) -> TxProxyCall>> { + self.wrapped_tx + .raw_call("balanceOfBatch") + .argument(&owner_type_id_pairs) + .original_result() + } + + pub fn token_owner< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + type_id: Arg0, + nft_id: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getTokenOwner") + .argument(&type_id) + .argument(&nft_id) + .original_result() + } + + pub fn token_type_creator< + Arg0: ProxyArg>, + >( + self, + type_id: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getTokenTypeCreator") + .argument(&type_id) + .original_result() + } + + pub fn token_type_uri< + Arg0: ProxyArg>, + >( + self, + type_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("getTokenTypeUri") + .argument(&type_id) + .original_result() + } + + pub fn is_fungible< + Arg0: ProxyArg>, + >( + self, + type_id: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isFungible") + .argument(&type_id) + .original_result() + } + + pub fn is_approved< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + operator: Arg0, + owner: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("isApprovedForAll") + .argument(&operator) + .argument(&owner) + .original_result() + } +} diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/src/lib.rs b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/src/lib.rs index 676b2b5b1d..7aa633d71c 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/src/lib.rs +++ b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/src/lib.rs @@ -3,6 +3,8 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); +pub mod erc1155_proxy; + const PERCENTAGE_TOTAL: u8 = 100; #[derive(TopEncode, TopDecode, TypeAbi)] @@ -106,7 +108,10 @@ pub trait Erc1155Marketplace { let claimable_funds_mapper = self.get_claimable_funds_mapper(); for (token_identifier, amount) in claimable_funds_mapper.iter() { - self.send().direct(&caller, &token_identifier, 0, &amount); + self.tx() + .to(&caller) + .egld_or_single_esdt(&token_identifier, 0, &amount) + .transfer(); self.clear_claimable_funds(&token_identifier); } } @@ -176,12 +181,10 @@ pub trait Erc1155Marketplace { // refund losing bid if !auction.current_winner.is_zero() { - self.send().direct( - &auction.current_winner, - &auction.token_identifier, - 0, - &auction.current_bid, - ); + self.tx() + .to(&auction.current_winner) + .egld_or_single_esdt(&auction.token_identifier, 0, &auction.current_bid) + .transfer(); } // update auction bid and winner @@ -215,12 +218,10 @@ pub trait Erc1155Marketplace { self.add_claimable_funds(&auction.token_identifier, &cut_amount); // send part of the bid to the original owner - self.send().direct( - &auction.original_owner, - &auction.token_identifier, - 0, - &amount_to_send, - ); + self.tx() + .to(&auction.original_owner) + .egld_or_single_esdt(&auction.token_identifier, 0, &amount_to_send) + .transfer(); // send token to winner self.async_transfer_token(type_id, nft_id, auction.current_winner); @@ -310,10 +311,11 @@ pub trait Erc1155Marketplace { let sc_own_address = self.blockchain().get_sc_address(); let token_ownership_contract_address = self.token_ownership_contract_address().get(); - self.erc1155_proxy(token_ownership_contract_address) + self.tx() + .to(&token_ownership_contract_address) + .typed(erc1155_proxy::Erc1155Proxy) .safe_transfer_from(sc_own_address, to, type_id, nft_id, &[]) - .async_call() - .call_and_exit() + .async_call_and_exit(); } fn calculate_cut_amount(&self, total_amount: &BigUint, cut_percentage: u8) -> BigUint { @@ -332,11 +334,6 @@ pub trait Erc1155Marketplace { mapper.insert(token_identifier.clone(), BigUint::zero()); } - // proxy - - #[proxy] - fn erc1155_proxy(&self, to: ManagedAddress) -> erc1155::Proxy; - // storage // token ownership contract, i.e. the erc1155 SC diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.lock b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.lock index 96edd6a295..df492c51db 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.lock +++ b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.lock @@ -63,7 +63,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -103,7 +103,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.toml index 04ddab6e25..b4b0a71b4c 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155-marketplace/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/Cargo.toml index 84b4ed1422..27c5f2d2a6 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/Cargo.toml @@ -9,10 +9,10 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/meta/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/meta/Cargo.toml index a3005dc7a5..d662e3f8e9 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/meta/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.lock b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.lock index be9d41b78d..dc29477e1d 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.lock +++ b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.toml index 01018d9bba..0af2d54c37 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155-user-mock/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/erc-style-contracts/erc1155/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155/Cargo.toml index b2a2908748..1566019c49 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155/Cargo.toml @@ -9,12 +9,12 @@ publish = false path = "src/erc1155.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" [dev-dependencies.erc1155-user-mock] diff --git a/contracts/feature-tests/erc-style-contracts/erc1155/meta/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155/meta/Cargo.toml index 41f4a03c09..8cad0e03b2 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/meta/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/erc-style-contracts/erc1155/sc-config.toml b/contracts/feature-tests/erc-style-contracts/erc1155/sc-config.toml index 9d5da94a85..41ca1e2eee 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/sc-config.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155/sc-config.toml @@ -1,6 +1,9 @@ [settings] main = "erc1155" +[[proxy]] +path = "../erc1155-marketplace/src/erc1155_proxy.rs" + # the only purpose of this config is to specify the allocator [contracts.erc1155] add-unlabelled = true 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 9fb1fb5216..725cff90de 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155.rs +++ b/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155.rs @@ -350,16 +350,17 @@ pub trait Erc1155 { ) { let caller = self.blockchain().get_caller(); - self.erc1155_user_proxy(to.clone()) + self.tx() + .to(to.clone()) + .typed(erc1155_user_proxy::Erc1155UserProxy) .on_erc1155_received(caller, from.clone(), type_id.clone(), value.clone(), data) - .async_call() - .with_callback(self.callbacks().transfer_callback( + .callback(self.callbacks().transfer_callback( from, to, [type_id].to_vec(), [value].to_vec(), )) - .call_and_exit() + .async_call_and_exit(); } fn peform_async_call_batch_transfer( @@ -372,7 +373,9 @@ pub trait Erc1155 { ) { let caller = self.blockchain().get_caller(); - self.erc1155_user_proxy(to.clone()) + self.tx() + .to(to.clone()) + .typed(erc1155_user_proxy::Erc1155UserProxy) .on_erc1155_batch_received( caller, from.clone(), @@ -380,14 +383,13 @@ pub trait Erc1155 { values.to_vec(), data, ) - .async_call() - .with_callback(self.callbacks().transfer_callback( + .callback(self.callbacks().transfer_callback( from, to, type_ids.to_vec(), values.to_vec(), )) - .call_and_exit() + .async_call_and_exit(); } // callbacks @@ -418,14 +420,6 @@ pub trait Erc1155 { } } - // proxy - - #[proxy] - fn erc1155_user_proxy( - &self, - sc_address: ManagedAddress, - ) -> erc1155_user_proxy::Proxy; - // storage // map for address -> type_id -> amount diff --git a/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155_user_proxy.rs b/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155_user_proxy.rs index 5c645bf4be..600c12792f 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155_user_proxy.rs +++ b/contracts/feature-tests/erc-style-contracts/erc1155/src/erc1155_user_proxy.rs @@ -1,24 +1,87 @@ -multiversx_sc::imports!(); +#![allow(clippy::all)] -#[multiversx_sc::proxy] -pub trait Erc1155UserProxy { - #[endpoint(onERC1155Received)] - fn on_erc1155_received( - &self, - operator: ManagedAddress, - from: ManagedAddress, - type_id: BigUint, - value: BigUint, - data: ManagedBuffer, - ); +use multiversx_sc::proxy_imports::*; - #[endpoint(onERC1155BatchReceived)] - fn on_erc1155_batch_received( - &self, - operator: ManagedAddress, - from: ManagedAddress, - type_ids: Vec, - values: Vec, - data: ManagedBuffer, - ); +pub struct Erc1155UserProxy; + +impl TxProxyTrait for Erc1155UserProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = Erc1155UserProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + Erc1155UserProxyMethods { wrapped_tx: tx } + } +} + +pub struct Erc1155UserProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl Erc1155UserProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn on_erc1155_received< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + >( + self, + operator: Arg0, + from: Arg1, + type_id: Arg2, + value: Arg3, + data: Arg4, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("onERC1155Received") + .argument(&operator) + .argument(&from) + .argument(&type_id) + .argument(&value) + .argument(&data) + .original_result() + } + + pub fn on_erc1155_batch_received< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>>, + Arg3: ProxyArg>>, + Arg4: ProxyArg>, + >( + self, + operator: Arg0, + from: Arg1, + type_ids: Arg2, + values: Arg3, + data: Arg4, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("onERC1155BatchReceived") + .argument(&operator) + .argument(&from) + .argument(&type_ids) + .argument(&values) + .argument(&data) + .original_result() + } } diff --git a/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.lock b/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.lock index 91409bfda7..f34cb19087 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.lock +++ b/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.toml index 88bd84fd56..6299d90bcb 100644 --- a/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc1155/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/erc-style-contracts/erc20/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc20/Cargo.toml index 44a5aa05cc..8d12e823b9 100644 --- a/contracts/feature-tests/erc-style-contracts/erc20/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc20/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/erc20.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/erc-style-contracts/erc20/meta/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc20/meta/Cargo.toml index e73119bdf0..0db234389f 100644 --- a/contracts/feature-tests/erc-style-contracts/erc20/meta/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc20/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/erc-style-contracts/erc20/sc-config.toml b/contracts/feature-tests/erc-style-contracts/erc20/sc-config.toml new file mode 100644 index 0000000000..68aff47cba --- /dev/null +++ b/contracts/feature-tests/erc-style-contracts/erc20/sc-config.toml @@ -0,0 +1,7 @@ +[settings] + +[[proxy]] +path = "../crowdfunding-erc20/src/erc20_proxy.rs" + +[[proxy]] +path = "../lottery-erc20/src/erc20_proxy.rs" diff --git a/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.lock b/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.lock index 492ddf9510..b0ba8e546c 100644 --- a/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.lock +++ b/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.toml index c01efbb7a4..060cf6a1a1 100644 --- a/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc20/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/erc-style-contracts/erc721/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc721/Cargo.toml index fa723cf47a..b0aff72a5c 100644 --- a/contracts/feature-tests/erc-style-contracts/erc721/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc721/Cargo.toml @@ -10,9 +10,9 @@ path = "src/erc721.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/erc-style-contracts/erc721/meta/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc721/meta/Cargo.toml index 45ea2fcbdf..05ee5b504e 100644 --- a/contracts/feature-tests/erc-style-contracts/erc721/meta/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc721/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.lock b/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.lock index 140f4dfbbc..9b4caaf7b6 100644 --- a/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.lock +++ b/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.toml b/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.toml index aaab30fad6..c18d25cd9b 100644 --- a/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/erc721/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/erc-style-contracts/lottery-erc20/Cargo.toml b/contracts/feature-tests/erc-style-contracts/lottery-erc20/Cargo.toml index 1511bf2c91..3995505b5a 100644 --- a/contracts/feature-tests/erc-style-contracts/lottery-erc20/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/lottery-erc20/Cargo.toml @@ -12,10 +12,10 @@ path = "src/lottery.rs" path = "../erc20" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" features = ["alloc"] [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/scenario" diff --git a/contracts/feature-tests/erc-style-contracts/lottery-erc20/meta/Cargo.toml b/contracts/feature-tests/erc-style-contracts/lottery-erc20/meta/Cargo.toml index 7d2f5b3d15..81e598d14e 100644 --- a/contracts/feature-tests/erc-style-contracts/lottery-erc20/meta/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/lottery-erc20/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/erc-style-contracts/lottery-erc20/src/erc20_proxy.rs b/contracts/feature-tests/erc-style-contracts/lottery-erc20/src/erc20_proxy.rs new file mode 100644 index 0000000000..eaceb1da73 --- /dev/null +++ b/contracts/feature-tests/erc-style-contracts/lottery-erc20/src/erc20_proxy.rs @@ -0,0 +1,188 @@ +// 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 SimpleErc20TokenProxy; + +impl TxProxyTrait for SimpleErc20TokenProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = SimpleErc20TokenProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + SimpleErc20TokenProxyMethods { wrapped_tx: tx } + } +} + +pub struct SimpleErc20TokenProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl SimpleErc20TokenProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + /// Constructor, is called immediately after the contract is created + /// Will set the fixed global token supply and give all the supply to the creator. + pub fn init< + Arg0: ProxyArg>, + >( + self, + total_supply: Arg0, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&total_supply) + .original_result() + } +} + +#[rustfmt::skip] +impl SimpleErc20TokenProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Total number of tokens in existence. + pub fn total_supply( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("totalSupply") + .original_result() + } + + /// Gets the balance of the specified address. + /// + /// Arguments: + /// + /// * `address` The address to query the the balance of + /// + pub fn token_balance< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("balanceOf") + .argument(&address) + .original_result() + } + + /// The amount of tokens that an owner allowed to a spender. + /// + /// Arguments: + /// + /// * `owner` The address that owns the funds. + /// * `spender` The address that will spend the funds. + /// + pub fn allowance< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + owner: Arg0, + spender: Arg1, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("allowance") + .argument(&owner) + .argument(&spender) + .original_result() + } + + /// Transfer token to a specified address from sender. + /// + /// Arguments: + /// + /// * `to` The address to transfer to. + /// + pub fn transfer< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + to: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transfer") + .argument(&to) + .argument(&amount) + .original_result() + } + + /// Use allowance to transfer funds between two accounts. + /// + /// Arguments: + /// + /// * `sender` The address to transfer from. + /// * `recipient` The address to transfer to. + /// * `amount` the amount of tokens to be transferred. + /// + pub fn transfer_from< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + sender: Arg0, + recipient: Arg1, + amount: Arg2, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transferFrom") + .argument(&sender) + .argument(&recipient) + .argument(&amount) + .original_result() + } + + /// Approve the given address to spend the specified amount of tokens on behalf of the sender. + /// It overwrites any previously existing allowance from sender to beneficiary. + /// + /// Arguments: + /// + /// * `spender` The address that will spend the funds. + /// * `amount` The amount of tokens to be spent. + /// + pub fn approve< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + spender: Arg0, + amount: Arg1, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("approve") + .argument(&spender) + .argument(&amount) + .original_result() + } +} diff --git a/contracts/feature-tests/erc-style-contracts/lottery-erc20/src/lottery.rs b/contracts/feature-tests/erc-style-contracts/lottery-erc20/src/lottery.rs index 318563e703..1bbd1f7370 100644 --- a/contracts/feature-tests/erc-style-contracts/lottery-erc20/src/lottery.rs +++ b/contracts/feature-tests/erc-style-contracts/lottery-erc20/src/lottery.rs @@ -2,6 +2,7 @@ multiversx_sc::imports!(); +mod erc20_proxy; mod lottery_info; mod random; mod status; @@ -15,9 +16,6 @@ const THIRTY_DAYS_IN_SECONDS: u64 = 60 * 60 * 24 * 30; #[multiversx_sc::contract] pub trait Lottery { - #[proxy] - fn erc20_proxy(&self, to: ManagedAddress) -> erc20::Proxy; - #[init] fn init(&self, erc20_contract_address: ManagedAddress) { self.set_erc20_contract_address(&erc20_contract_address); @@ -212,14 +210,15 @@ pub trait Lottery { let erc20_address = self.get_erc20_contract_address(); let lottery_contract_address = self.blockchain().get_sc_address(); - self.erc20_proxy(erc20_address) + self.tx() + .to(&erc20_address) + .typed(erc20_proxy::SimpleErc20TokenProxy) .transfer_from(caller.clone(), lottery_contract_address, token_amount) - .async_call() - .with_callback( + .callback( self.callbacks() .transfer_from_callback(lottery_name, &caller), ) - .call_and_exit() + .async_call_and_exit(); } fn reserve_ticket(&self, lottery_name: &BoxedBytes) { @@ -282,11 +281,12 @@ pub trait Lottery { let erc20_address = self.get_erc20_contract_address(); - self.erc20_proxy(erc20_address) + self.tx() + .to(&erc20_address) + .typed(erc20_proxy::SimpleErc20TokenProxy) .transfer(winner_address, prize) - .async_call() - .with_callback(self.callbacks().distribute_prizes_callback(lottery_name)) - .call_and_exit() + .callback(self.callbacks().distribute_prizes_callback(lottery_name)) + .async_call_and_exit(); } fn get_random_winning_ticket_id(&self, prev_winners: &[u32], total_tickets: u32) -> u32 { diff --git a/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.lock b/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.lock index 50d1f38715..64019726c1 100644 --- a/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.lock +++ b/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.lock @@ -63,7 +63,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -92,7 +92,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -103,7 +103,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.toml b/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.toml index f999a60635..0bcd0316c2 100644 --- a/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.toml +++ b/contracts/feature-tests/erc-style-contracts/lottery-erc20/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/esdt-system-sc-mock/Cargo.toml b/contracts/feature-tests/esdt-system-sc-mock/Cargo.toml index 5b4b511ed6..8e8b693ebe 100644 --- a/contracts/feature-tests/esdt-system-sc-mock/Cargo.toml +++ b/contracts/feature-tests/esdt-system-sc-mock/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/esdt_system_sc_mock.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/esdt-system-sc-mock/meta/Cargo.toml b/contracts/feature-tests/esdt-system-sc-mock/meta/Cargo.toml index 93075bf8c3..425d3ee8eb 100644 --- a/contracts/feature-tests/esdt-system-sc-mock/meta/Cargo.toml +++ b/contracts/feature-tests/esdt-system-sc-mock/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.lock b/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.lock index 1316ca215f..b66a768ae1 100644 --- a/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.lock +++ b/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.toml b/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.toml index 1a28c98d4c..690f09686b 100644 --- a/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.toml +++ b/contracts/feature-tests/esdt-system-sc-mock/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/exchange-features/Cargo.toml b/contracts/feature-tests/exchange-features/Cargo.toml index 6d3a48ad00..2963251bb9 100644 --- a/contracts/feature-tests/exchange-features/Cargo.toml +++ b/contracts/feature-tests/exchange-features/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/exchange_features.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/exchange-features/meta/Cargo.toml b/contracts/feature-tests/exchange-features/meta/Cargo.toml index 90e47b7c03..a5bb2c339e 100644 --- a/contracts/feature-tests/exchange-features/meta/Cargo.toml +++ b/contracts/feature-tests/exchange-features/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/exchange-features/tests/exchange_features_blackbox_test.rs b/contracts/feature-tests/exchange-features/tests/exchange_features_blackbox_test.rs index 6ea73fb3a6..88c87e3931 100644 --- a/contracts/feature-tests/exchange-features/tests/exchange_features_blackbox_test.rs +++ b/contracts/feature-tests/exchange-features/tests/exchange_features_blackbox_test.rs @@ -1,4 +1,4 @@ -use multiversx_sc_scenario::{scenario_model::*, *}; +use multiversx_sc_scenario::imports::*; const EXCHANGE_FEATURES_PATH_EXPR: &str = "mxsc:output/exchange-features.mxsc.json"; diff --git a/contracts/feature-tests/exchange-features/wasm/Cargo.lock b/contracts/feature-tests/exchange-features/wasm/Cargo.lock index e9c8ff82c2..adf5bb4ee3 100644 --- a/contracts/feature-tests/exchange-features/wasm/Cargo.lock +++ b/contracts/feature-tests/exchange-features/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/exchange-features/wasm/Cargo.toml b/contracts/feature-tests/exchange-features/wasm/Cargo.toml index b8925ad4a4..9aed886551 100644 --- a/contracts/feature-tests/exchange-features/wasm/Cargo.toml +++ b/contracts/feature-tests/exchange-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/exchange-features/wasm/src/lib.rs b/contracts/feature-tests/exchange-features/wasm/src/lib.rs index b0842b89d6..944349b256 100644 --- a/contracts/feature-tests/exchange-features/wasm/src/lib.rs +++ b/contracts/feature-tests/exchange-features/wasm/src/lib.rs @@ -5,7 +5,8 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 3 +// Upgrade: 1 +// Endpoints: 2 // Async Callback (empty): 1 // Total number of exported functions: 5 diff --git a/contracts/feature-tests/formatted-message-features/Cargo.toml b/contracts/feature-tests/formatted-message-features/Cargo.toml index b9953c21ee..3ae3030b5d 100644 --- a/contracts/feature-tests/formatted-message-features/Cargo.toml +++ b/contracts/feature-tests/formatted-message-features/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/formatted_message_features.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/formatted-message-features/meta/Cargo.toml b/contracts/feature-tests/formatted-message-features/meta/Cargo.toml index 5a5494af2a..1dbe41b175 100644 --- a/contracts/feature-tests/formatted-message-features/meta/Cargo.toml +++ b/contracts/feature-tests/formatted-message-features/meta/Cargo.toml @@ -11,6 +11,6 @@ authors = [ "you",] path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/formatted-message-features/wasm/Cargo.lock b/contracts/feature-tests/formatted-message-features/wasm/Cargo.lock index 279238f2e2..9f3eabdcfc 100644 --- a/contracts/feature-tests/formatted-message-features/wasm/Cargo.lock +++ b/contracts/feature-tests/formatted-message-features/wasm/Cargo.lock @@ -55,7 +55,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/formatted-message-features/wasm/Cargo.toml b/contracts/feature-tests/formatted-message-features/wasm/Cargo.toml index d0599cc360..8230ed884b 100644 --- a/contracts/feature-tests/formatted-message-features/wasm/Cargo.toml +++ b/contracts/feature-tests/formatted-message-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/managed-map-features/Cargo.toml b/contracts/feature-tests/managed-map-features/Cargo.toml index 13ff3f0628..552cbb84b0 100644 --- a/contracts/feature-tests/managed-map-features/Cargo.toml +++ b/contracts/feature-tests/managed-map-features/Cargo.toml @@ -9,11 +9,11 @@ publish = false path = "src/mmap_features.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies.esdt-system-sc-mock] diff --git a/contracts/feature-tests/managed-map-features/meta/Cargo.toml b/contracts/feature-tests/managed-map-features/meta/Cargo.toml index bf12a6a524..91c7eb646a 100644 --- a/contracts/feature-tests/managed-map-features/meta/Cargo.toml +++ b/contracts/feature-tests/managed-map-features/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/managed-map-features/wasm/Cargo.lock b/contracts/feature-tests/managed-map-features/wasm/Cargo.lock index 8de61c1187..59d4875222 100644 --- a/contracts/feature-tests/managed-map-features/wasm/Cargo.lock +++ b/contracts/feature-tests/managed-map-features/wasm/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/managed-map-features/wasm/Cargo.toml b/contracts/feature-tests/managed-map-features/wasm/Cargo.toml index 09e977363e..5762a40856 100644 --- a/contracts/feature-tests/managed-map-features/wasm/Cargo.toml +++ b/contracts/feature-tests/managed-map-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/multi-contract-features/Cargo.toml b/contracts/feature-tests/multi-contract-features/Cargo.toml index 80fccb51f3..213f19e779 100644 --- a/contracts/feature-tests/multi-contract-features/Cargo.toml +++ b/contracts/feature-tests/multi-contract-features/Cargo.toml @@ -12,9 +12,9 @@ path = "src/multi_contract_features.rs" example_feature = [] [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/multi-contract-features/meta/Cargo.toml b/contracts/feature-tests/multi-contract-features/meta/Cargo.toml index 4a96c5e067..866bfa5da1 100644 --- a/contracts/feature-tests/multi-contract-features/meta/Cargo.toml +++ b/contracts/feature-tests/multi-contract-features/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.lock b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.lock index edb911a2f4..bd6f9e8daf 100644 --- a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.lock +++ b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.toml b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.toml index d6192e9eb3..1f77f836ed 100644 --- a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.toml +++ b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-alt-impl/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.lock b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.lock index 92f5d93116..a234b10710 100644 --- a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.lock +++ b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.toml b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.toml index 4b733fdda8..f6ebe4edb9 100644 --- a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.toml +++ b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-example-feature/Cargo.toml @@ -26,7 +26,7 @@ path = ".." features = ["example_feature"] [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.lock b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.lock index b05ca10df5..b74f0b96b8 100644 --- a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.lock +++ b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.toml b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.toml index 21f2ef0bee..28a8f95c7c 100644 --- a/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.toml +++ b/contracts/feature-tests/multi-contract-features/wasm-multi-contract-features-view/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/multi-contract-features/wasm/Cargo.lock b/contracts/feature-tests/multi-contract-features/wasm/Cargo.lock index d3e3e66eb7..7b7b14b240 100755 --- a/contracts/feature-tests/multi-contract-features/wasm/Cargo.lock +++ b/contracts/feature-tests/multi-contract-features/wasm/Cargo.lock @@ -55,7 +55,7 @@ dependencies = [ [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -84,7 +84,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/multi-contract-features/wasm/Cargo.toml b/contracts/feature-tests/multi-contract-features/wasm/Cargo.toml index 12144e1645..ba28d1f0d1 100644 --- a/contracts/feature-tests/multi-contract-features/wasm/Cargo.toml +++ b/contracts/feature-tests/multi-contract-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/panic-message-features/Cargo.toml b/contracts/feature-tests/panic-message-features/Cargo.toml index 656c6e2b13..11eb995356 100644 --- a/contracts/feature-tests/panic-message-features/Cargo.toml +++ b/contracts/feature-tests/panic-message-features/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/panic_features.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/panic-message-features/meta/Cargo.toml b/contracts/feature-tests/panic-message-features/meta/Cargo.toml index 8c67b8ebba..7e1007837d 100644 --- a/contracts/feature-tests/panic-message-features/meta/Cargo.toml +++ b/contracts/feature-tests/panic-message-features/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/panic-message-features/sc-config.toml b/contracts/feature-tests/panic-message-features/sc-config.toml index fc05c90bba..a5d6671115 100644 --- a/contracts/feature-tests/panic-message-features/sc-config.toml +++ b/contracts/feature-tests/panic-message-features/sc-config.toml @@ -4,3 +4,6 @@ main = "main" [contracts.main] name = "panic-message-features" panic-message = true + +[[proxy]] +path = "tests/pmf_proxy.rs" diff --git a/contracts/feature-tests/panic-message-features/src/panic_features.rs b/contracts/feature-tests/panic-message-features/src/panic_features.rs index 4b4ed32258..a2726d2fea 100644 --- a/contracts/feature-tests/panic-message-features/src/panic_features.rs +++ b/contracts/feature-tests/panic-message-features/src/panic_features.rs @@ -24,4 +24,9 @@ pub trait PanicMessageFeatures { #[event("before-panic")] fn before_panic(&self); + + #[view] + fn sc_panic(&self) { + sc_panic!("sc_panic! test"); + } } diff --git a/contracts/feature-tests/panic-message-features/tests/pmf_blackbox_test.rs b/contracts/feature-tests/panic-message-features/tests/pmf_blackbox_test.rs new file mode 100644 index 0000000000..e8ad3c2a33 --- /dev/null +++ b/contracts/feature-tests/panic-message-features/tests/pmf_blackbox_test.rs @@ -0,0 +1,95 @@ +mod pmf_proxy; + +use multiversx_sc_scenario::imports::*; + +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const SC_PMF: TestSCAddress = TestSCAddress::new("pmf"); +const CODE_EXPR: &str = "mxsc:output/panic-message-features.mxsc.json"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/examples/adder"); + + blockchain.register_contract(CODE_EXPR, panic_message_features::ContractBuilder); + blockchain +} + +fn setup() -> ScenarioWorld { + let mut world = world(); + let code = world.code_expression(CODE_EXPR); + + world.set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDRESS, Account::new().nonce(1)) + .put_account(SC_PMF, Account::new().code(code)), + ); + + world +} + +// TODO: move to basic-features a testing framework tester +#[test] +fn tx_returns_error_test() { + let mut world = setup(); + + let (status, message) = world + .tx() + .from(OWNER_ADDRESS) + .to(SC_PMF) + .typed(pmf_proxy::PanicMessageFeaturesProxy) + .sc_panic() + .returns(ReturnsStatus) + .returns(ReturnsMessage) + .run(); + + assert_eq!(status, 4); + assert_eq!(message, "sc_panic! test"); +} + +#[test] +fn query_returns_error_test() { + let mut world = setup(); + + let (status, message) = world + .query() + .to(SC_PMF) + .typed(pmf_proxy::PanicMessageFeaturesProxy) + .sc_panic() + .returns(ReturnsStatus) + .returns(ReturnsMessage) + .run(); + + assert_eq!(status, 4); + assert_eq!(message, "sc_panic! test"); +} + +#[test] +fn tx_expect_error_test() { + let mut world = setup(); + + world + .tx() + .from(OWNER_ADDRESS) + .to(SC_PMF) + .typed(pmf_proxy::PanicMessageFeaturesProxy) + .sc_panic() + .with_result(ExpectMessage("sc_panic! test")) + .with_result(ExpectError(4, "sc_panic! test")) + .with_result(ExpectStatus(4)) + .run(); +} + +#[test] +fn query_expect_error_test() { + let mut world = setup(); + + world + .query() + .to(SC_PMF) + .typed(pmf_proxy::PanicMessageFeaturesProxy) + .sc_panic() + .with_result(ExpectStatus(4)) + .with_result(ExpectMessage("sc_panic! test")) + .with_result(ExpectError(4, "sc_panic! test")) + .run(); +} diff --git a/contracts/feature-tests/panic-message-features/tests/pmf_proxy.rs b/contracts/feature-tests/panic-message-features/tests/pmf_proxy.rs new file mode 100644 index 0000000000..6e4c6e0cea --- /dev/null +++ b/contracts/feature-tests/panic-message-features/tests/pmf_proxy.rs @@ -0,0 +1,92 @@ +// 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 PanicMessageFeaturesProxy; + +impl TxProxyTrait for PanicMessageFeaturesProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = PanicMessageFeaturesProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + PanicMessageFeaturesProxyMethods { wrapped_tx: tx } + } +} + +pub struct PanicMessageFeaturesProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl PanicMessageFeaturesProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl PanicMessageFeaturesProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn panic_with_message< + Arg0: ProxyArg, + >( + self, + some_value: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("panicWithMessage") + .argument(&some_value) + .original_result() + } + + /// Logs do not get recorded in case of panic. + pub fn panic_after_log( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("panicAfterLog") + .original_result() + } + + pub fn sc_panic( + self, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("sc_panic") + .original_result() + } +} diff --git a/contracts/feature-tests/panic-message-features/wasm/Cargo.lock b/contracts/feature-tests/panic-message-features/wasm/Cargo.lock index ccde2cee09..f05b039ab2 100755 --- a/contracts/feature-tests/panic-message-features/wasm/Cargo.lock +++ b/contracts/feature-tests/panic-message-features/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/panic-message-features/wasm/Cargo.toml b/contracts/feature-tests/panic-message-features/wasm/Cargo.toml index 93e00552f3..3b0455e096 100644 --- a/contracts/feature-tests/panic-message-features/wasm/Cargo.toml +++ b/contracts/feature-tests/panic-message-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/panic-message-features/wasm/src/lib.rs b/contracts/feature-tests/panic-message-features/wasm/src/lib.rs index 2a024b15d2..a347a1aaa3 100644 --- a/contracts/feature-tests/panic-message-features/wasm/src/lib.rs +++ b/contracts/feature-tests/panic-message-features/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 2 +// Endpoints: 3 // Async Callback (empty): 1 -// Total number of exported functions: 4 +// Total number of exported functions: 5 #![no_std] #![allow(internal_features)] @@ -22,6 +22,7 @@ multiversx_sc_wasm_adapter::endpoints! { init => init panicWithMessage => panic_with_message panicAfterLog => panic_after_log + sc_panic => sc_panic ) } diff --git a/contracts/feature-tests/payable-features/Cargo.toml b/contracts/feature-tests/payable-features/Cargo.toml index 6862e0ac62..7973c85f03 100644 --- a/contracts/feature-tests/payable-features/Cargo.toml +++ b/contracts/feature-tests/payable-features/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/payable_features.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/payable-features/meta/Cargo.toml b/contracts/feature-tests/payable-features/meta/Cargo.toml index 850ef041c7..bc934da0cf 100644 --- a/contracts/feature-tests/payable-features/meta/Cargo.toml +++ b/contracts/feature-tests/payable-features/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/payable-features/tests/payable_blackbox_test.rs b/contracts/feature-tests/payable-features/tests/payable_blackbox_test.rs index 6d86ebe77f..82581c8170 100644 --- a/contracts/feature-tests/payable-features/tests/payable_blackbox_test.rs +++ b/contracts/feature-tests/payable-features/tests/payable_blackbox_test.rs @@ -1,4 +1,4 @@ -use multiversx_sc_scenario::{scenario_model::*, *}; +use multiversx_sc_scenario::imports::*; const PF_PATH_EXPR: &str = "mxsc:output/payable-features.mxsc.json"; diff --git a/contracts/feature-tests/payable-features/wasm/Cargo.lock b/contracts/feature-tests/payable-features/wasm/Cargo.lock index a20d9a05bd..46f3efdb23 100755 --- a/contracts/feature-tests/payable-features/wasm/Cargo.lock +++ b/contracts/feature-tests/payable-features/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/payable-features/wasm/Cargo.toml b/contracts/feature-tests/payable-features/wasm/Cargo.toml index 55210f0e10..8cd5e49030 100644 --- a/contracts/feature-tests/payable-features/wasm/Cargo.toml +++ b/contracts/feature-tests/payable-features/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/rust-snippets-generator-test/Cargo.toml b/contracts/feature-tests/rust-snippets-generator-test/Cargo.toml index 9a6188feb4..4f4fb8ba56 100644 --- a/contracts/feature-tests/rust-snippets-generator-test/Cargo.toml +++ b/contracts/feature-tests/rust-snippets-generator-test/Cargo.toml @@ -9,9 +9,9 @@ publish = false path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" diff --git a/contracts/feature-tests/rust-snippets-generator-test/interact-rs/Cargo.toml b/contracts/feature-tests/rust-snippets-generator-test/interact-rs/Cargo.toml index 6064d313a3..c84332da38 100644 --- a/contracts/feature-tests/rust-snippets-generator-test/interact-rs/Cargo.toml +++ b/contracts/feature-tests/rust-snippets-generator-test/interact-rs/Cargo.toml @@ -13,7 +13,7 @@ path = "src/interactor_main.rs" path = ".." [dependencies.multiversx-sc-snippets] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/snippets" # [workspace] diff --git a/contracts/feature-tests/rust-snippets-generator-test/interact-rs/src/interactor_main.rs b/contracts/feature-tests/rust-snippets-generator-test/interact-rs/src/interactor_main.rs index e0999b7644..389c717f2c 100644 --- a/contracts/feature-tests/rust-snippets-generator-test/interact-rs/src/interactor_main.rs +++ b/contracts/feature-tests/rust-snippets-generator-test/interact-rs/src/interactor_main.rs @@ -2,25 +2,12 @@ use rust_snippets_generator_test::{ProxyTrait as _, *}; -use multiversx_sc_snippets::{ - env_logger, - erdrs::wallet::Wallet, - multiversx_sc::{codec::multi_types::*, types::*}, - multiversx_sc_scenario::{ - api::StaticApi, - bech32, - scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, - scenario_model::*, - ContractInfo, - }, - sdk, tokio, Interactor, -}; +use multiversx_sc_snippets::imports::*; const GATEWAY: &str = sdk::blockchain::DEVNET_GATEWAY; const PEM: &str = "alice.pem"; const SC_ADDRESS: &str = ""; -const SYSTEM_SC_BECH32: &str = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"; const DEFAULT_ADDRESS_EXPR: &str = "0x0000000000000000000000000000000000000000000000000000000000000000"; const TOKEN_ISSUE_COST: u64 = 50_000_000_000_000_000; diff --git a/contracts/feature-tests/rust-snippets-generator-test/meta/Cargo.toml b/contracts/feature-tests/rust-snippets-generator-test/meta/Cargo.toml index 90111ca338..5260217e43 100644 --- a/contracts/feature-tests/rust-snippets-generator-test/meta/Cargo.toml +++ b/contracts/feature-tests/rust-snippets-generator-test/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.lock b/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.lock index a35b1f0228..c5a3c14f3b 100644 --- a/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.lock +++ b/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.toml b/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.toml index 251d1b49aa..38946bc17a 100644 --- a/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.toml +++ b/contracts/feature-tests/rust-snippets-generator-test/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/rust-testing-framework-tester/Cargo.toml b/contracts/feature-tests/rust-testing-framework-tester/Cargo.toml index 015d94cc4f..aa9942a6d7 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/Cargo.toml +++ b/contracts/feature-tests/rust-testing-framework-tester/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" publish = false [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" features = [ "alloc" ] @@ -17,7 +17,7 @@ path = "../../examples/adder" path = "../../feature-tests/basic-features" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies] diff --git a/contracts/feature-tests/rust-testing-framework-tester/meta/Cargo.toml b/contracts/feature-tests/rust-testing-framework-tester/meta/Cargo.toml index 746732fc11..7e63f066fa 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/meta/Cargo.toml +++ b/contracts/feature-tests/rust-testing-framework-tester/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false 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 010f002e6a..4133f3f039 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/src/lib.rs +++ b/contracts/feature-tests/rust-testing-framework-tester/src/lib.rs @@ -62,14 +62,8 @@ pub trait RustTestingFrameworkTester: dummy_module::DummyModule { #[payable("EGLD")] #[endpoint] fn recieve_egld_half(&self) { - let caller = self.blockchain().get_caller(); let payment_amount = &*self.call_value().egld_value() / 2u32; - self.send().direct( - &caller, - &EgldOrEsdtTokenIdentifier::egld(), - 0, - &payment_amount, - ); + self.tx().to(ToCaller).egld(payment_amount).transfer(); } #[payable("*")] @@ -88,12 +82,13 @@ pub trait RustTestingFrameworkTester: dummy_module::DummyModule { #[payable("*")] #[endpoint] fn receive_esdt_half(&self) { - let caller = self.blockchain().get_caller(); let payment = self.call_value().single_esdt(); let amount = payment.amount / 2u32; - self.send() - .direct_esdt(&caller, &payment.token_identifier, 0, &amount); + self.tx() + .to(ToCaller) + .single_esdt(&payment.token_identifier, 0, &amount) + .transfer(); } #[payable("*")] @@ -111,7 +106,10 @@ pub trait RustTestingFrameworkTester: dummy_module::DummyModule { nft_nonce: u64, amount: BigUint, ) { - self.send().direct_esdt(&to, &token_id, nft_nonce, &amount); + self.tx() + .to(&to) + .single_esdt(&token_id, nft_nonce, &amount) + .transfer(); } #[endpoint] @@ -172,13 +170,14 @@ pub trait RustTestingFrameworkTester: dummy_module::DummyModule { #[endpoint] fn call_other_contract_execute_on_dest(&self, other_sc_address: ManagedAddress) -> BigUint { - let call_result = self.send_raw().execute_on_dest_context_raw( - self.blockchain().get_gas_left(), - &other_sc_address, - &BigUint::zero(), - &ManagedBuffer::new_from_bytes(b"getTotalValue"), - &ManagedArgBuffer::new(), - ); + let gas_left = self.blockchain().get_gas_left(); + let call_result = self + .tx() + .to(&other_sc_address) + .gas(gas_left) + .raw_call("getTotalValue") + .returns(ReturnsRawResult) + .sync_call(); if let Some(raw_value) = call_result.try_get(0) { BigUint::from_bytes_be_buffer(&raw_value) } else { @@ -188,15 +187,11 @@ pub trait RustTestingFrameworkTester: dummy_module::DummyModule { #[endpoint] fn call_other_contract_add_async_call(&self, other_sc_address: ManagedAddress, value: BigUint) { - let mut args = ManagedArgBuffer::new(); - args.push_arg(&value); - - self.send_raw().async_call_raw( - &other_sc_address, - &BigUint::zero(), - &ManagedBuffer::new_from_bytes(b"add"), - &args, - ); + self.tx() + .to(&other_sc_address) + .raw_call("add") + .argument(&value) + .async_call_and_exit(); } #[callback_raw] @@ -211,16 +206,13 @@ pub trait RustTestingFrameworkTester: dummy_module::DummyModule { #[endpoint] fn execute_on_dest_add_value(&self, other_sc_address: ManagedAddress, value: BigUint) { - let mut args = ManagedArgBuffer::new(); - args.push_arg(value); - - let _ = self.send_raw().execute_on_dest_context_raw( - self.blockchain().get_gas_left(), - &other_sc_address, - &BigUint::zero(), - &ManagedBuffer::new_from_bytes(b"addValue"), - &args, - ); + let gas_left = self.blockchain().get_gas_left(); + self.tx() + .to(&other_sc_address) + .gas(gas_left) + .raw_call("addValue") + .argument(&value) + .sync_call(); } #[endpoint(addValue)] 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 d544af3a04..b47c83fcef 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,5 +1,5 @@ -use multiversx_sc_scenario::{api::StaticApi, scenario_model::*, *}; -use rust_testing_framework_tester::*; // TODO: clean up imports +use multiversx_sc_scenario::imports::*; +use rust_testing_framework_tester::*; const WASM_PATH_EXPR: &str = "mxsc:output/rust-testing-framework-tester.mxsc.json"; @@ -16,6 +16,7 @@ fn world() -> ScenarioWorld { } #[test] +#[allow(deprecated)] fn tester_deploy_test() { let mut world = world(); let code = world.code_expression(WASM_PATH_EXPR); @@ -45,6 +46,7 @@ fn tester_deploy_test() { } #[test] +#[allow(deprecated)] fn tester_deploy_test_spawned_thread() { let handler = std::thread::spawn(|| { let mut world = world(); diff --git a/contracts/feature-tests/rust-testing-framework-tester/tests/tester_whitebox_legacy_test.rs b/contracts/feature-tests/rust-testing-framework-tester/tests/tester_whitebox_legacy_test.rs index 1f56f5bb21..0acd222cc9 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/tests/tester_whitebox_legacy_test.rs +++ b/contracts/feature-tests/rust-testing-framework-tester/tests/tester_whitebox_legacy_test.rs @@ -1,20 +1,9 @@ -#![allow(deprecated)] // TODO: migrate tests - -use adder::*; -use forwarder::call_sync::*; +use multiversx_sc_scenario::imports::*; use num_traits::ToPrimitive; +use adder::*; use basic_features::BasicFeatures; -use multiversx_sc::{ - codec::Empty, - contract_base::ContractBase, - err_msg, - types::{Address, BigUint, EsdtLocalRole, EsdtTokenPayment, ManagedVec, TokenIdentifier}, -}; -use multiversx_sc_scenario::{ - api::DebugApi, assert_values_eq, managed_address, managed_biguint, managed_buffer, - managed_token_id, rust_biguint, testing_framework::*, -}; +use forwarder::call_sync::*; use rust_testing_framework_tester::{dummy_module::DummyModule, *}; const TEST_OUTPUT_PATH: &str = "test.scen.json"; diff --git a/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.lock b/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.lock index 287a90ba46..b9637d20a1 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.lock +++ b/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.toml b/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.toml index 267402b339..26a2d8d271 100644 --- a/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.toml +++ b/contracts/feature-tests/rust-testing-framework-tester/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/scenario-tester/.gitignore b/contracts/feature-tests/scenario-tester/.gitignore new file mode 100644 index 0000000000..dd49a95243 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The mxpy output +/output*/ + +# Mandos test trace +trace*.scen.json diff --git a/contracts/feature-tests/scenario-tester/Cargo.toml b/contracts/feature-tests/scenario-tester/Cargo.toml new file mode 100644 index 0000000000..33c6f5cdcc --- /dev/null +++ b/contracts/feature-tests/scenario-tester/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "scenario-tester" +version = "0.0.0" +authors = ["Andrei Marinica "] +edition = "2021" +publish = false + +[lib] +path = "src/lib.rs" + +[dependencies.multiversx-sc] +version = "0.49.0-alpha.4" +path = "../../../framework/base" + +[dev-dependencies.multiversx-sc-scenario] +version = "0.49.0-alpha.4" +path = "../../../framework/scenario" diff --git a/contracts/feature-tests/scenario-tester/README.md b/contracts/feature-tests/scenario-tester/README.md new file mode 100644 index 0000000000..4538caeca9 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/README.md @@ -0,0 +1,3 @@ +# Adder + +`Adder` is a simple Smart Contract. diff --git a/contracts/feature-tests/scenario-tester/meta/Cargo.toml b/contracts/feature-tests/scenario-tester/meta/Cargo.toml new file mode 100644 index 0000000000..2d689e8a13 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/meta/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "scenario-tester-meta" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies.scenario-tester] +path = ".." + +[dependencies.multiversx-sc-meta] +version = "0.49.0-alpha.4" +path = "../../../../framework/meta" +default-features = false diff --git a/contracts/feature-tests/scenario-tester/meta/src/main.rs b/contracts/feature-tests/scenario-tester/meta/src/main.rs new file mode 100644 index 0000000000..d88f5e7545 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta::cli_main::(); +} diff --git a/contracts/feature-tests/scenario-tester/multiversx.json b/contracts/feature-tests/scenario-tester/multiversx.json new file mode 100644 index 0000000000..7365539625 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/contracts/feature-tests/scenario-tester/sc-config.toml b/contracts/feature-tests/scenario-tester/sc-config.toml new file mode 100644 index 0000000000..4b16ba7311 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/sc-config.toml @@ -0,0 +1,4 @@ +[settings] + +[[proxy]] +path = "src/scenario_tester_proxy.rs" diff --git a/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json b/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json new file mode 100644 index 0000000000..07fd7f68ca --- /dev/null +++ b/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json @@ -0,0 +1,76 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60": { + "nonce": "481", + "balance": "106274669842530000003", + "esdt": { + "str:CAN-14dc0a": "1000", + "str:CAN-2abf4b": "1000", + "str:CAN-6d39e6": "1000", + "str:CAN-ac1592": "1000" + } + } + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "creatorNonce": "481", + "newAddress": "0x0000000000000000050028600ceb73ac22ec0b6f257aff7bed74dffa3ebfed60" + } + ] + }, + { + "step": "scDeploy", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "contractCode": "mxsc:../output/scenario-tester.mxsc.json", + "arguments": [ + "0x00" + ], + "gasLimit": "70,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x0000000000000000050028600ceb73ac22ec0b6f257aff7bed74dffa3ebfed60", + "function": "add", + "arguments": [ + "0x07" + ], + "gasLimit": "70,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "tx": { + "from": "0xe32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed60", + "to": "0x0000000000000000050028600ceb73ac22ec0b6f257aff7bed74dffa3ebfed60", + "function": "add", + "arguments": [ + "0x05" + ], + "gasLimit": "70,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + } + ] +} diff --git a/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json b/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json new file mode 100644 index 0000000000..94ba305ed2 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json @@ -0,0 +1,99 @@ +{ + "name": "adder", + "comment": "add then check", + "gasSchedule": "v3", + "steps": [ + { + "step": "setState", + "accounts": { + "address:owner": { + "nonce": "1", + "balance": "0" + } + }, + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:adder" + } + ] + }, + { + "step": "scDeploy", + "id": "1", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../output/scenario-tester.mxsc.json", + "arguments": [ + "5" + ], + "gasLimit": "5,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "", + "logs": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scQuery", + "id": "2", + "tx": { + "to": "sc:adder", + "function": "getSum", + "arguments": [] + }, + "expect": { + "out": [ + "5" + ], + "status": "", + "logs": [] + } + }, + { + "step": "scCall", + "id": "3", + "tx": { + "from": "address:owner", + "to": "sc:adder", + "function": "add", + "arguments": [ + "3" + ], + "gasLimit": "5,000,000", + "gasPrice": "0" + }, + "expect": { + "out": [], + "status": "", + "logs": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "checkState", + "accounts": { + "address:owner": { + "nonce": "*", + "balance": "0", + "storage": {}, + "code": "" + }, + "sc:adder": { + "nonce": "0", + "balance": "0", + "storage": { + "str:sum": "8" + }, + "code": "mxsc:../output/scenario-tester.mxsc.json" + } + } + } + ] +} diff --git a/contracts/feature-tests/scenario-tester/src/lib.rs b/contracts/feature-tests/scenario-tester/src/lib.rs new file mode 100644 index 0000000000..015b3e82c2 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/src/lib.rs @@ -0,0 +1,30 @@ +#![no_std] + +use multiversx_sc::imports::*; + +pub mod scenario_tester_proxy; + +/// One of the simplest smart contracts possible, +/// it holds a single variable in storage, which anyone can increment. +#[multiversx_sc::contract] +pub trait ScenarioTester { + #[view(getSum)] + #[storage_mapper("sum")] + fn sum(&self) -> SingleValueMapper; + + #[init] + fn init(&self, initial_value: BigUint) { + self.sum().set(initial_value); + } + + #[upgrade] + fn upgrade(&self, initial_value: BigUint) { + self.init(initial_value); + } + + /// Add desired amount to the storage variable. + #[endpoint] + fn add(&self, value: BigUint) { + self.sum().update(|sum| *sum += value); + } +} diff --git a/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs new file mode 100644 index 0000000000..3358a126e4 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs @@ -0,0 +1,110 @@ +// 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 ScenarioTesterProxy; + +impl TxProxyTrait for ScenarioTesterProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = ScenarioTesterProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + ScenarioTesterProxyMethods { wrapped_tx: tx } + } +} + +pub struct ScenarioTesterProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl ScenarioTesterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>, + >( + self, + initial_value: Arg0, + ) -> TxProxyDeploy { + self.wrapped_tx + .raw_deploy() + .argument(&initial_value) + .original_result() + } +} + +#[rustfmt::skip] +impl ScenarioTesterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>, + >( + self, + initial_value: Arg0, + ) -> TxProxyUpgrade { + self.wrapped_tx + .raw_upgrade() + .argument(&initial_value) + .original_result() + } +} + +#[rustfmt::skip] +impl ScenarioTesterProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn sum( + self, + ) -> TxProxyCall> { + self.wrapped_tx + .raw_call("getSum") + .original_result() + } + + /// Add desired amount to the storage variable. + pub fn add< + Arg0: ProxyArg>, + >( + self, + value: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("add") + .argument(&value) + .original_result() + } +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_chained_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_chained_test.rs new file mode 100644 index 0000000000..71b8a982c5 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_chained_test.rs @@ -0,0 +1,64 @@ +use multiversx_sc_scenario::imports::*; +use num_bigint::BigUint; + +use scenario_tester::*; + +const ADDER_PATH_EXPR: &str = "mxsc:output/scenario-tester.mxsc.json"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/feature-tests/scenario-tester"); + + blockchain.register_contract(ADDER_PATH_EXPR, scenario_tester::ContractBuilder); + blockchain +} + +#[test] +fn st_blackbox_chained() { + let mut world = world(); + let owner_address = "address:owner"; + let st_contract = ContractInfo::>::new("sc:adder"); + + world + .start_trace() + .set_state_step( + SetStateStep::new() + .put_account(owner_address, Account::new().nonce(1)) + .new_address(owner_address, 1, "sc:adder"), + ) + .chain_deploy(|tx| { + tx.from(TestAddress::new("owner")) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .init(5u32) + .code(MxscPath::new("output/scenario-tester.mxsc.json")) + .with_result(WithNewAddress::new(|new_address| { + assert_eq!(new_address.to_address(), st_contract.to_address()); + })) + }) + .chain_query(|tx| { + tx.to(TestSCAddress::new("adder")) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .sum() + .with_result(WithResultAs::new(|value: BigUint| { + assert_eq!(value, BigUint::from(5u32)); + })) + }) + .chain_call(|tx| { + tx.from(TestAddress::new("owner")) + .to(TestSCAddress::new("adder")) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .add(3u32) + .with_result(WithRawTxResponse(|response| { + assert!(response.tx_error.is_success()); + })) + }) + .check_state_step( + CheckStateStep::new() + .put_account(owner_address, CheckAccount::new()) + .put_account( + &st_contract, + CheckAccount::new().check_storage("str:sum", "8"), + ), + ) + .write_scenario_trace("trace2.scen.json"); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_legacy_proxy_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_legacy_proxy_test.rs new file mode 100644 index 0000000000..f62672bb36 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_legacy_proxy_test.rs @@ -0,0 +1,79 @@ +#![allow(deprecated)] + +use multiversx_sc_scenario::imports::*; +use num_bigint::BigUint; + +use scenario_tester::*; + +const ADDER_PATH_EXPR: &str = "mxsc:output/adder.mxsc.json"; + +const OWNER: TestAddress = TestAddress::new("owner"); +const CODE_EXPR: MxscPath = MxscPath::new("output/adder.mxsc.json"); + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/examples/adder"); + + blockchain.register_contract(ADDER_PATH_EXPR, scenario_tester::ContractBuilder); + blockchain +} + +#[test] +fn st_blackbox_legacy_proxy() { + let mut world = world(); + let owner_address = "address:owner"; + let mut st_contract = ContractInfo::>::new("sc:adder"); + + world.start_trace(); + + world.set_state_step( + SetStateStep::new() + .put_account(owner_address, Account::new().nonce(1)) + .new_address(owner_address, 1, "sc:adder"), + ); + + world + .tx() + .from(OWNER) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .init(5u32) + .code(CODE_EXPR) + .with_result(WithNewAddress::new(|new_address| { + assert_eq!(new_address.to_address(), st_contract.to_address()); + })) + .run(); + + world.sc_query( + ScQueryStep::new() + .to(&st_contract) + .call(st_contract.sum()) + .expect_value(SingleValue::from(BigUint::from(5u32))), + ); + + let value = world + .query() + .legacy_proxy_call(st_contract.sum()) + .returns(ReturnsResultAs::>::new()) + .run(); + assert_eq!(value.into(), BigUint::from(5u32)); + + world + .tx() + .from(OWNER) + .legacy_proxy_call(st_contract.add(3u32)) + .with_result(WithRawTxResponse(|response| { + assert!(response.tx_error.is_success()); + })) + .run(); + + world.check_state_step( + CheckStateStep::new() + .put_account(owner_address, CheckAccount::new()) + .put_account( + &st_contract, + CheckAccount::new().check_storage("str:sum", "8"), + ), + ); + + world.write_scenario_trace("trace1.scen.json"); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs new file mode 100644 index 0000000000..fc6b5d02a0 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs @@ -0,0 +1,53 @@ +use multiversx_sc_scenario::imports::*; + +const SCENARIO_TESTER_PATH_EXPR: &str = "mxsc:output/scenario-tester.mxsc.json"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/feature-tests/scenario-tester"); + + blockchain.register_contract(SCENARIO_TESTER_PATH_EXPR, scenario_tester::ContractBuilder); + blockchain +} + +#[test] +fn scenario_tester_blackbox_raw() { + let mut world = world(); + let scenario_tester_code = world.code_expression(SCENARIO_TESTER_PATH_EXPR); + + world + .set_state_step( + SetStateStep::new() + .put_account("address:owner", Account::new().nonce(1)) + .new_address("address:owner", 1, "sc:scenario-tester"), + ) + .sc_deploy( + ScDeployStep::new() + .from("address:owner") + .code(scenario_tester_code) + .argument("5") + .expect(TxExpect::ok().no_result()), + ) + .sc_query( + ScQueryStep::new() + .to("sc:scenario-tester") + .function("getSum") + .expect(TxExpect::ok().result("5")), + ) + .sc_call( + ScCallStep::new() + .from("address:owner") + .to("sc:scenario-tester") + .function("add") + .argument("3") + .expect(TxExpect::ok().no_result()), + ) + .check_state_step( + CheckStateStep::new() + .put_account("address:owner", CheckAccount::new()) + .put_account( + "sc:scenario-tester", + CheckAccount::new().check_storage("str:sum", "8"), + ), + ); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs new file mode 100644 index 0000000000..20ff801864 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -0,0 +1,217 @@ +use multiversx_sc_scenario::imports::*; + +use scenario_tester::*; + +const SC_SCENARIO_TESTER_PATH_EXPR: &str = "mxsc:output/scenario-tester.mxsc.json"; +const FOURTH_ATTRIBUTES: &[u8] = b"FourthhAttributes"; +const FOURTH_URIS: &[&[u8]] = &[b"FirstUri", b"SecondUri"]; + +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const OTHER_ADDRESS: TestAddress = TestAddress::new("other"); +const ST_ADDRESS: TestSCAddress = TestSCAddress::new("scenario-tester"); +const CODE_PATH: MxscPath = MxscPath::new("output/scenario-tester.mxsc.json"); +const TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("TOKEN-123456"); +const NFT_ID: TestTokenIdentifier = TestTokenIdentifier::new("NFT-123456"); + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/examples/scenario-tester"); + + blockchain.register_contract( + SC_SCENARIO_TESTER_PATH_EXPR, + scenario_tester::ContractBuilder, + ); + blockchain +} + +#[test] +fn st_blackbox() { + let mut world = world(); + + world.start_trace(); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .balance(100) + .account(OTHER_ADDRESS) + .nonce(2) + .balance(300) + .esdt_balance(TOKEN_ID, 500) + .commit(); + + world + .check_account(OWNER_ADDRESS) + .nonce(1) + .balance(100) + .check_account(OTHER_ADDRESS) + .nonce(2) + .balance(300) + .esdt_balance(TOKEN_ID, 500) + .commit(); + + world.new_address(OWNER_ADDRESS, 1, ST_ADDRESS); + + let new_address = world + .tx() + .from(OWNER_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .init(5u32) + .code(CODE_PATH) + .returns(ReturnsNewAddress) + .run(); + assert_eq!(new_address, ST_ADDRESS.to_address()); + + let value = world + .query() + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .sum() + .returns(ReturnsResultUnmanaged) + .run(); + assert_eq!(value, RustBigUint::from(5u32)); + + world + .tx() + .from(OWNER_ADDRESS) + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .add(1u32) + .run(); + + world + .check_account(OWNER_ADDRESS) + .nonce(3) + .balance(100) + .check_account(ST_ADDRESS) + .check_storage("str:sum", "6") + .commit(); + + world + .tx() + .from(OTHER_ADDRESS) + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .add(1u32) + .run(); + + world.write_scenario_trace("trace1.scen.json"); +} + +#[test] +fn set_state_test() { + let mut world = world(); + let first = TestAddress::new("first"); + let second = TestAddress::new("second"); + let third = TestAddress::new("third"); + let fourth = TestAddress::new("fourth"); + let fifth = TestAddress::new("fifth"); + let sixth = TestAddress::new("sixth"); + let seventh = TestAddress::new("seventh"); + let eighth = TestAddress::new("eighth"); + + world.start_trace(); + + world + .account(first) + .nonce(1) + .balance(100) + .account(second) + .nonce(2) + .balance(300) + .esdt_balance(TOKEN_ID, 500) + .commit(); + + world + .check_account(first) + .nonce(1) + .balance(100) + .check_account(second) + .nonce(2) + .balance(300) + .esdt_balance(TOKEN_ID, 500) + .commit(); + + world + .account(third) + .nonce(3) + .balance(50) + .esdt_nft_balance(NFT_ID, 2, 1, ()) + .commit(); + + world + .check_account(third) + .nonce(3) + .balance(50) + .esdt_nft_balance_and_attributes(NFT_ID, 2, 1, "") + .commit(); + + let fourth_uris = FOURTH_URIS + .iter() + .map(|first_uri| managed_buffer!(first_uri)) + .collect(); + world + .account(fourth) + .nonce(3) + .balance(50) + .esdt_nft_all_properties( + NFT_ID, + 2, + 1, + managed_buffer!(FOURTH_ATTRIBUTES), + 1000, + None::
, + (), + fourth_uris, + ) + .commit(); + + world + .check_account(fourth) + .nonce(3) + .balance(50) + .esdt_nft_balance_and_attributes(NFT_ID, 2, 1, FOURTH_ATTRIBUTES) + .commit(); + + world + .account(fifth) + .nonce(2) + .balance(30) + .esdt_nft_last_nonce(NFT_ID, 5); + world + .check_account(fifth) + .nonce(2) + .balance(30) + .esdt_nft_balance_and_attributes(NFT_ID, 5, 0, ""); + + // using no commit should drop the value naturally + world + .account(sixth) + .nonce(4) + .balance(400) + .account(seventh) + .nonce(5) + .balance(250) + .esdt_balance(TOKEN_ID, 2); + + world + .check_account(sixth) + .nonce(4) + .balance(400) + .check_account(seventh) + .nonce(5) + .balance(250) + .esdt_balance(TOKEN_ID, 2); + + world + .account(eighth) + .nonce(6) + .balance(600) + .esdt_balance(TOKEN_ID, 60); + + world + .check_account(eighth) + .nonce(6) + .balance(600) + .esdt_balance(TOKEN_ID, 60); +} diff --git a/contracts/examples/adder/tests/adder_blackbox_upgrade_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs similarity index 71% rename from contracts/examples/adder/tests/adder_blackbox_upgrade_test.rs rename to contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs index 4cb12cad54..786fea9725 100644 --- a/contracts/examples/adder/tests/adder_blackbox_upgrade_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs @@ -1,19 +1,22 @@ -use multiversx_sc_scenario::{scenario_model::*, *}; +use multiversx_sc_scenario::imports::*; -const ADDER_PATH_EXPR: &str = "mxsc:output/adder.mxsc.json"; +const ADDER_PATH_EXPR: &str = "mxsc:output/scenario-tester.mxsc.json"; fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); - blockchain.set_current_dir_from_workspace("contracts/examples/adder"); + blockchain.set_current_dir_from_workspace("contracts/feature-tests/scenario-tester"); - blockchain.register_contract("mxsc:output/adder.mxsc.json", adder::ContractBuilder); + blockchain.register_contract( + "mxsc:output/scenario-tester.mxsc.json", + scenario_tester::ContractBuilder, + ); blockchain } #[test] -fn adder_blackbox_upgrade() { +fn st_blackbox_upgrade() { let mut world = world(); - let adder_code = world.code_expression(ADDER_PATH_EXPR); + let st_code = world.code_expression(ADDER_PATH_EXPR); world .set_state_step( @@ -24,7 +27,7 @@ fn adder_blackbox_upgrade() { .sc_deploy( ScDeployStep::new() .from("address:owner") - .code(&adder_code) + .code(&st_code) .argument("5") .gas_limit("5,000,000") .expect(TxExpect::ok().no_result()), @@ -34,7 +37,7 @@ fn adder_blackbox_upgrade() { .from("address:owner") .to("sc:adder") .function("upgradeContract") - .argument(&adder_code) + .argument(&st_code) .argument("0x0502") // codeMetadata .argument("8") // contract argument .expect(TxExpect::ok().no_result()), diff --git a/contracts/feature-tests/scenario-tester/tests/st_scenario_go_test.rs b/contracts/feature-tests/scenario-tester/tests/st_scenario_go_test.rs new file mode 100644 index 0000000000..a62c9ea10f --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_scenario_go_test.rs @@ -0,0 +1,15 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + ScenarioWorld::vm_go() +} + +#[test] +fn interactor_trace_go() { + world().run("scenarios/interactor_trace.scen.json"); +} + +#[test] +fn st_adder_go() { + world().run("scenarios/st-adder.scen.json"); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_scenario_rs_test.rs b/contracts/feature-tests/scenario-tester/tests/st_scenario_rs_test.rs new file mode 100644 index 0000000000..32f289733d --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_scenario_rs_test.rs @@ -0,0 +1,22 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/feature-tests/scenario-tester"); + + blockchain.register_contract( + "mxsc:output/scenario-tester.mxsc.json", + scenario_tester::ContractBuilder, + ); + blockchain +} + +#[test] +fn interactor_trace_rs() { + world().run("scenarios/interactor_trace.scen.json"); +} + +#[test] +fn st_adder_rs() { + world().run("scenarios/st-adder.scen.json"); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_unit_test.rs b/contracts/feature-tests/scenario-tester/tests/st_unit_test.rs new file mode 100644 index 0000000000..e9b418dfad --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_unit_test.rs @@ -0,0 +1,17 @@ +use multiversx_sc::types::BigUint; +use multiversx_sc_scenario::api::SingleTxApi; +use scenario_tester::*; + +#[test] +fn st_unit_test() { + let contract = scenario_tester::contract_obj::(); + + contract.init(BigUint::from(5u32)); + assert_eq!(BigUint::from(5u32), contract.sum().get()); + + contract.add(BigUint::from(7u32)); + assert_eq!(BigUint::from(12u32), contract.sum().get()); + + contract.add(BigUint::from(1u32)); + assert_eq!(BigUint::from(13u32), contract.sum().get()); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs new file mode 100644 index 0000000000..072292ed91 --- /dev/null +++ b/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs @@ -0,0 +1,53 @@ +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.set_current_dir_from_workspace("contracts/feature-tests/scenario-tester"); + + 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/wasm/Cargo.lock b/contracts/feature-tests/scenario-tester/wasm/Cargo.lock new file mode 100755 index 0000000000..c92359d81b --- /dev/null +++ b/contracts/feature-tests/scenario-tester/wasm/Cargo.lock @@ -0,0 +1,170 @@ +# 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.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[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.49.0-alpha.4" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.18.6" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.18.6" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.49.0-alpha.4" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.49.0-alpha.4" +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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +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 = "scenario-tester" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "scenario-tester-wasm" +version = "0.0.0" +dependencies = [ + "multiversx-sc-wasm-adapter", + "scenario-tester", +] + +[[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.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +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" diff --git a/contracts/feature-tests/scenario-tester/wasm/Cargo.toml b/contracts/feature-tests/scenario-tester/wasm/Cargo.toml new file mode 100644 index 0000000000..fc67b3c6dc --- /dev/null +++ b/contracts/feature-tests/scenario-tester/wasm/Cargo.toml @@ -0,0 +1,32 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "scenario-tester-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 + +[dependencies.scenario-tester] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.49.0-alpha.4" +path = "../../../../framework/wasm-adapter" + +[workspace] +members = ["."] diff --git a/contracts/feature-tests/scenario-tester/wasm/src/lib.rs b/contracts/feature-tests/scenario-tester/wasm/src/lib.rs new file mode 100644 index 0000000000..ae1ba48ffd --- /dev/null +++ b/contracts/feature-tests/scenario-tester/wasm/src/lib.rs @@ -0,0 +1,30 @@ +// Code generated by the multiversx-sc build system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Upgrade: 1 +// Endpoints: 2 +// Async Callback (empty): 1 +// Total number of exported functions: 5 + +#![no_std] +#![allow(internal_features)] +#![feature(lang_items)] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + scenario_tester + ( + init => init + upgrade => upgrade + getSum => sum + add => add + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {} diff --git a/contracts/feature-tests/use-module/Cargo.toml b/contracts/feature-tests/use-module/Cargo.toml index 8671f3c4fc..24efcdf34c 100644 --- a/contracts/feature-tests/use-module/Cargo.toml +++ b/contracts/feature-tests/use-module/Cargo.toml @@ -9,17 +9,17 @@ publish = false path = "src/use_module.rs" [dependencies.multiversx-sc-modules] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../contracts/modules" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/base" [dev-dependencies.multiversx-sc-scenario] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/scenario" [dev-dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../framework/meta" diff --git a/contracts/feature-tests/use-module/meta/Cargo.toml b/contracts/feature-tests/use-module/meta/Cargo.toml index 94a60a1999..bd6cec3fee 100644 --- a/contracts/feature-tests/use-module/meta/Cargo.toml +++ b/contracts/feature-tests/use-module/meta/Cargo.toml @@ -9,6 +9,6 @@ publish = false path = ".." [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/use-module/meta/abi/Cargo.toml b/contracts/feature-tests/use-module/meta/abi/Cargo.toml index 81f7c46385..7d3415622f 100644 --- a/contracts/feature-tests/use-module/meta/abi/Cargo.toml +++ b/contracts/feature-tests/use-module/meta/abi/Cargo.toml @@ -9,10 +9,10 @@ publish = false path = ".." [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/base" [dependencies.multiversx-sc-meta] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/meta" default-features = false diff --git a/contracts/feature-tests/use-module/scenarios/use_module_ongoing_operation_example.scen.json b/contracts/feature-tests/use-module/scenarios/use_module_ongoing_operation_example.scen.json index 3e43e9270a..a8a16623b2 100644 --- a/contracts/feature-tests/use-module/scenarios/use_module_ongoing_operation_example.scen.json +++ b/contracts/feature-tests/use-module/scenarios/use_module_ongoing_operation_example.scen.json @@ -52,7 +52,7 @@ "to": "sc:use_module", "function": "countTo100", "arguments": [], - "gasLimit": "4,500,000", + "gasLimit": "4,700,000", "gasPrice": "0" }, "expect": { 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 fe90f658e4..267639fd6f 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 @@ -1,15 +1,8 @@ -use multiversx_sc::types::{Address, ManagedVec, MultiValueEncoded}; use multiversx_sc_modules::governance::{ governance_configurable::GovernanceConfigurablePropertiesModule, governance_proposal::VoteType, GovernanceModule, }; -use multiversx_sc_scenario::{ - managed_address, managed_biguint, managed_buffer, managed_token_id, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, SetStateStep, - }, - ScenarioWorld, WhiteboxContract, -}; +use multiversx_sc_scenario::imports::*; const GOV_TOKEN_ID_EXPR: &str = "str:GOV-123456"; const GOV_TOKEN_ID: &[u8] = b"GOV-123456"; 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 91a96db16a..049936bb44 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,12 +1,5 @@ -use multiversx_sc::types::{Address, EgldOrEsdtTokenIdentifier, ManagedVec}; use multiversx_sc_modules::staking::StakingModule; -use multiversx_sc_scenario::{ - managed_address, managed_biguint, managed_token_id, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, SetStateStep, - }, - ScenarioWorld, WhiteboxContract, -}; +use multiversx_sc_scenario::imports::*; const STAKING_TOKEN_ID_EXPR: &str = "str:STAKE-123456"; const STAKING_TOKEN_ID: &[u8] = b"STAKE-123456"; 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 a970685918..3f723c323a 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 @@ -1,20 +1,8 @@ -use multiversx_sc::{ - arrayvec::ArrayVec, - codec::{test_util::top_encode_to_vec_u8_or_panic, Empty}, - contract_base::ContractBase, - storage::mappers::StorageTokenWrapper, - types::{Address, EsdtTokenPayment, ManagedVec}, -}; +use multiversx_sc_scenario::imports::*; + use multiversx_sc_modules::token_merge::{ merged_token_instances::MergedTokenInstances, merged_token_setup::MergedTokenSetupModule, }; -use multiversx_sc_scenario::{ - managed_address, managed_biguint, managed_token_id, - scenario_model::{ - Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, SetStateStep, TxESDT, - }, - ScenarioWorld, WhiteboxContract, -}; use use_module::token_merge_mod_impl::{CustomAttributes, TokenMergeModImpl}; const OWNER_ADDRESS_EXPR: &str = "address:owner"; @@ -78,7 +66,7 @@ fn test_token_merge() { NFT_AMOUNT, Some(FIRST_ATTRIBUTES), FIRST_ROYALTIES, - None, + None::, None, Vec::from(FIRST_URIS), ) @@ -88,7 +76,7 @@ fn test_token_merge() { NFT_AMOUNT, Some(SECOND_ATTRIBUTES), SECOND_ROYALTIES, - None, + None::, None, Vec::from(SECOND_URIS), ), @@ -466,7 +454,7 @@ fn test_partial_split() { NFT_AMOUNT, Some(FIRST_ATTRIBUTES), FIRST_ROYALTIES, - None, + None::, None, Vec::from(FIRST_URIS), ) @@ -476,7 +464,7 @@ fn test_partial_split() { NFT_AMOUNT, Some(SECOND_ATTRIBUTES), SECOND_ROYALTIES, - None, + None::, None, Vec::from(SECOND_URIS), ), @@ -684,7 +672,7 @@ fn test_custom_attributes() { NFT_AMOUNT, Some(FIRST_ATTRIBUTES), FIRST_ROYALTIES, - None, + None::, None, Vec::from(FIRST_URIS), ) @@ -694,7 +682,7 @@ fn test_custom_attributes() { NFT_AMOUNT, Some(SECOND_ATTRIBUTES), SECOND_ROYALTIES, - None, + None::, None, Vec::from(SECOND_URIS), ), diff --git a/contracts/feature-tests/use-module/tests/use_module_scenario_rs_test.rs b/contracts/feature-tests/use-module/tests/use_module_scenario_rs_test.rs index 2ecb798d24..a7360462a4 100644 --- a/contracts/feature-tests/use-module/tests/use_module_scenario_rs_test.rs +++ b/contracts/feature-tests/use-module/tests/use_module_scenario_rs_test.rs @@ -1,30 +1,18 @@ -mod user_builtin { - multiversx_sc::imports!(); - - #[multiversx_sc::proxy] - pub trait UserBuiltin { - #[endpoint(SetUserName)] - fn set_user_name(&self, name: &BoxedBytes) -> BigUint; - } -} - mod dns_mock { multiversx_sc::imports!(); #[multiversx_sc::contract] pub trait DnsMock { - #[proxy] - fn user_builtin_proxy(&self, to: ManagedAddress) -> super::user_builtin::Proxy; - #[payable("EGLD")] #[endpoint] fn register(&self, name: BoxedBytes) { let _payment = self.call_value().egld_value(); let address = self.blockchain().get_caller(); - self.user_builtin_proxy(address) + self.tx() + .to(&address) + .typed(system_proxy::UserBuiltinProxy) .set_user_name(&name) - .async_call() - .call_and_exit() + .async_call_and_exit(); } } } diff --git a/contracts/feature-tests/use-module/use_module_expected_main.abi.json b/contracts/feature-tests/use-module/use_module_expected_main.abi.json index 6d77fe6da0..372d1ca170 100644 --- a/contracts/feature-tests/use-module/use_module_expected_main.abi.json +++ b/contracts/feature-tests/use-module/use_module_expected_main.abi.json @@ -14,7 +14,7 @@ }, "framework": { "name": "multiversx-sc", - "version": "0.48.1" + "version": "0.49.0-alpha.4" } }, "docs": [ diff --git a/contracts/feature-tests/use-module/use_module_expected_view.abi.json b/contracts/feature-tests/use-module/use_module_expected_view.abi.json index c4d4ea960c..7b0ae08a4f 100644 --- a/contracts/feature-tests/use-module/use_module_expected_view.abi.json +++ b/contracts/feature-tests/use-module/use_module_expected_view.abi.json @@ -14,7 +14,7 @@ }, "framework": { "name": "multiversx-sc", - "version": "0.48.1" + "version": "0.49.0-alpha.4" } }, "docs": [ diff --git a/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.lock b/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.lock index c0abc2c92c..f5320776c8 100644 --- a/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.lock +++ b/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,14 +80,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.toml b/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.toml index 1d644729aa..62a866a3e3 100644 --- a/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.toml +++ b/contracts/feature-tests/use-module/wasm-use-module-view/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/feature-tests/use-module/wasm/Cargo.lock b/contracts/feature-tests/use-module/wasm/Cargo.lock index f48df08dc8..29c091ca70 100644 --- a/contracts/feature-tests/use-module/wasm/Cargo.lock +++ b/contracts/feature-tests/use-module/wasm/Cargo.lock @@ -40,7 +40,7 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "bitflags", "hex-literal", @@ -69,7 +69,7 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "hex", "proc-macro2", @@ -80,14 +80,14 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" dependencies = [ "multiversx-sc", ] diff --git a/contracts/feature-tests/use-module/wasm/Cargo.toml b/contracts/feature-tests/use-module/wasm/Cargo.toml index 18f3e41dca..f514309260 100644 --- a/contracts/feature-tests/use-module/wasm/Cargo.toml +++ b/contracts/feature-tests/use-module/wasm/Cargo.toml @@ -25,7 +25,7 @@ overflow-checks = false path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../../../framework/wasm-adapter" [workspace] diff --git a/contracts/modules/Cargo.toml b/contracts/modules/Cargo.toml index d3f742c99a..924bbab515 100644 --- a/contracts/modules/Cargo.toml +++ b/contracts/modules/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sc-modules" -version = "0.48.1" +version = "0.49.0-alpha.4" edition = "2021" authors = ["MultiversX "] @@ -17,5 +17,5 @@ categories = ["no-std", "wasm", "cryptography::cryptocurrencies"] alloc = ["multiversx-sc/alloc"] [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../framework/base" diff --git a/contracts/modules/src/bonding_curve/utils/owner_endpoints.rs b/contracts/modules/src/bonding_curve/utils/owner_endpoints.rs index 51f5eaaa35..820ba41446 100644 --- a/contracts/modules/src/bonding_curve/utils/owner_endpoints.rs +++ b/contracts/modules/src/bonding_curve/utils/owner_endpoints.rs @@ -179,9 +179,9 @@ pub trait OwnerEndpointsModule: storage::StorageModule + events::EventsModule { self.bonding_curve(&token).clear(); } self.owned_tokens(&caller).clear(); - self.send().direct_multi(&caller, &tokens_to_claim); + self.tx().to(&caller).multi_esdt(tokens_to_claim).transfer(); if egld_to_claim > BigUint::zero() { - self.send().direct_egld(&caller, &egld_to_claim); + self.tx().to(&caller).egld(&egld_to_claim).transfer(); } } diff --git a/contracts/modules/src/bonding_curve/utils/user_endpoints.rs b/contracts/modules/src/bonding_curve/utils/user_endpoints.rs index 321a0bd439..f627d26256 100644 --- a/contracts/modules/src/bonding_curve/utils/user_endpoints.rs +++ b/contracts/modules/src/bonding_curve/utils/user_endpoints.rs @@ -48,8 +48,11 @@ pub trait UserEndpointsModule: storage::StorageModule + events::EventsModule { self.nonce_amount(&offered_token, nonce) .update(|val| *val += sell_amount); - self.send() - .direct(&caller, &payment_token, 0u64, &calculated_price); + self.tx() + .to(&caller) + .egld_or_single_esdt(&payment_token, 0u64, &calculated_price) + .transfer(); + self.token_details(&offered_token) .update(|details| details.add_nonce(nonce)); @@ -98,8 +101,10 @@ pub trait UserEndpointsModule: storage::StorageModule + events::EventsModule { match requested_nonce { OptionalValue::Some(nonce) => { - self.send() - .direct_esdt(&caller, &requested_token, nonce, &requested_amount); + self.tx() + .to(&caller) + .single_esdt(&requested_token, nonce, &requested_amount) + .transfer(); if self.nonce_amount(&requested_token, nonce).get() - requested_amount.clone() > 0 { self.nonce_amount(&requested_token, nonce) .update(|val| *val -= requested_amount.clone()); @@ -114,12 +119,10 @@ pub trait UserEndpointsModule: storage::StorageModule + events::EventsModule { }, }; - self.send().direct( - &caller, - &offered_token, - 0u64, - &(&payment - &calculated_price), - ); + self.tx() + .to(&caller) + .egld_or_single_esdt(&offered_token, 0u64, &(&payment - &calculated_price)) + .transfer(); self.buy_token_event(&caller, &calculated_price); } @@ -156,7 +159,7 @@ pub trait UserEndpointsModule: storage::StorageModule + events::EventsModule { } } - self.send().direct_multi(caller, &tokens_to_send); + self.tx().to(caller).multi_esdt(tokens_to_send).transfer(); self.token_details(&token) .update(|token_ownership| token_ownership.token_nonces = nonces); diff --git a/contracts/modules/src/claim_developer_rewards.rs b/contracts/modules/src/claim_developer_rewards.rs index 05be2a0012..ac1187ab20 100644 --- a/contracts/modules/src/claim_developer_rewards.rs +++ b/contracts/modules/src/claim_developer_rewards.rs @@ -4,9 +4,8 @@ multiversx_sc::imports!(); pub trait ClaimDeveloperRewardsModule { #[endpoint(claimDeveloperRewards)] fn claim_developer_rewards(&self, child_sc_address: ManagedAddress) { - let () = self - .send() + self.send() .claim_developer_rewards(child_sc_address) - .execute_on_dest_context(); + .sync_call(); } } diff --git a/contracts/modules/src/default_issue_callbacks.rs b/contracts/modules/src/default_issue_callbacks.rs index 7c0d096b2e..6edd7abeec 100644 --- a/contracts/modules/src/default_issue_callbacks.rs +++ b/contracts/modules/src/default_issue_callbacks.rs @@ -46,9 +46,9 @@ pub trait DefaultIssueCallbacksModule { } fn return_failed_issue_funds(&self, initial_caller: ManagedAddress) { - let egld_returned = self.call_value().egld_value(); - if *egld_returned > 0u32 { - self.send().direct_egld(&initial_caller, &egld_returned); + let egld_returned = self.call_value().egld_value().to_u64().unwrap(); + if egld_returned > 0u64 { + self.tx().to(&initial_caller).egld(egld_returned).transfer(); } } } diff --git a/contracts/modules/src/dns.rs b/contracts/modules/src/dns.rs index 0bbeb38101..7e8123a0cf 100644 --- a/contracts/modules/src/dns.rs +++ b/contracts/modules/src/dns.rs @@ -1,13 +1,4 @@ -mod dns_proxy { - multiversx_sc::imports!(); - - #[multiversx_sc::proxy] - pub trait Dns { - #[payable("EGLD")] - #[endpoint] - fn register(&self, name: &ManagedBuffer); - } -} +use crate::dns_proxy; multiversx_sc::imports!(); @@ -18,18 +9,16 @@ multiversx_sc::imports!(); /// #[multiversx_sc::module] pub trait DnsModule { - #[proxy] - fn dns_proxy(&self, to: ManagedAddress) -> dns_proxy::Proxy; - #[payable("EGLD")] #[only_owner] #[endpoint(dnsRegister)] fn dns_register(&self, dns_address: ManagedAddress, name: ManagedBuffer) { let payment = self.call_value().egld_value().clone_value(); - self.dns_proxy(dns_address) - .register(&name) - .with_egld_transfer(payment) - .async_call() - .call_and_exit() + self.tx() + .to(&dns_address) + .typed(dns_proxy::DnsProxy) + .register(name) + .egld(payment) + .async_call_and_exit(); } } diff --git a/contracts/modules/src/dns_proxy.rs b/contracts/modules/src/dns_proxy.rs new file mode 100644 index 0000000000..25ac68e4c4 --- /dev/null +++ b/contracts/modules/src/dns_proxy.rs @@ -0,0 +1,51 @@ +#![allow(clippy::all)] + +use multiversx_sc::proxy_imports::*; + +pub struct DnsProxy; + +impl TxProxyTrait for DnsProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = DnsProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + DnsProxyMethods { wrapped_tx: tx } + } +} + +pub struct DnsProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl DnsProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn register< + Arg0: ProxyArg>, + >( + self, + name: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("register") + .argument(&name) + .original_result() + } +} diff --git a/contracts/modules/src/esdt.rs b/contracts/modules/src/esdt.rs index 18f43b896f..f39e5fe650 100644 --- a/contracts/modules/src/esdt.rs +++ b/contracts/modules/src/esdt.rs @@ -64,9 +64,10 @@ pub trait EsdtModule { // return payment to initial caller let initial_caller = self.blockchain().get_owner_address(); let egld_returned = self.call_value().egld_value(); - if *egld_returned > 0u32 { - self.send().direct_egld(&initial_caller, &egld_returned); - } + self.tx() + .to(&initial_caller) + .egld(egld_returned) + .transfer_if_not_empty(); }, } } diff --git a/contracts/modules/src/governance/mod.rs b/contracts/modules/src/governance/mod.rs index ee343f7101..92eeb038db 100644 --- a/contracts/modules/src/governance/mod.rs +++ b/contracts/modules/src/governance/mod.rs @@ -84,12 +84,14 @@ pub trait GovernanceModule: for fee_entry in fees_to_send.iter() { let payment = fee_entry.tokens.clone(); - self.send().direct_esdt( - &fee_entry.depositor_addr, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); + self.tx() + .to(&fee_entry.depositor_addr) + .single_esdt( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ) + .transfer(); self.user_claim_event(&caller, proposal_id, &fee_entry.tokens); } } @@ -276,16 +278,12 @@ pub trait GovernanceModule: self.clear_proposal(proposal_id); for action in proposal.actions { - let mut contract_call = self - .send() - .contract_call::<()>(action.dest_address, action.function_name) - .with_gas_limit(action.gas_limit); - - for arg in &action.arguments { - contract_call.push_raw_argument(arg); - } - - contract_call.transfer_execute(); + self.tx() + .to(&action.dest_address) + .raw_call(action.function_name) + .gas(action.gas_limit) + .arguments_raw(action.arguments.into()) + .transfer_execute() } self.proposal_executed_event(proposal_id); @@ -420,12 +418,14 @@ pub trait GovernanceModule: for fee_entry in payments.entries.iter() { let payment = fee_entry.tokens; - self.send().direct_esdt( - &fee_entry.depositor_addr, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); + self.tx() + .to(&fee_entry.depositor_addr) + .single_esdt( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ) + .transfer(); } } diff --git a/contracts/modules/src/lib.rs b/contracts/modules/src/lib.rs index b1973e3fc0..58b5da9c73 100644 --- a/contracts/modules/src/lib.rs +++ b/contracts/modules/src/lib.rs @@ -5,6 +5,7 @@ pub mod bonding_curve; pub mod claim_developer_rewards; pub mod default_issue_callbacks; pub mod dns; +pub mod dns_proxy; pub mod esdt; pub mod features; pub mod governance; diff --git a/contracts/modules/src/staking.rs b/contracts/modules/src/staking.rs index 3db2350fb1..e30a457e51 100644 --- a/contracts/modules/src/staking.rs +++ b/contracts/modules/src/staking.rs @@ -90,8 +90,10 @@ pub trait StakingModule { staked_amount_mapper.set(&leftover_amount); let staking_token = self.staking_token().get(); - self.send() - .direct(&caller, &staking_token, 0, &unstake_amount); + self.tx() + .to(caller) + .egld_or_single_esdt(&staking_token, 0, &unstake_amount) + .transfer(); } #[endpoint(voteSlashMember)] diff --git a/contracts/modules/src/token_merge/mod.rs b/contracts/modules/src/token_merge/mod.rs index 024626e2f1..b940980dfe 100644 --- a/contracts/modules/src/token_merge/mod.rs +++ b/contracts/modules/src/token_merge/mod.rs @@ -74,9 +74,11 @@ pub trait TokenMergeModule: let merged_token_payment = self.create_merged_token(merged_token_id, &all_merged_instances, attr_creator); - let caller = self.blockchain().get_caller(); - self.send() - .direct_non_zero_esdt_payment(&caller, &merged_token_payment); + + self.tx() + .to(ToCaller) + .payment(&merged_token_payment) + .transfer_if_not_empty(); merged_token_payment } @@ -118,8 +120,7 @@ pub trait TokenMergeModule: .esdt_local_burn(&token.token_identifier, token.token_nonce, &token.amount); } - let caller = self.blockchain().get_caller(); - self.send().direct_multi(&caller, &output_payments); + self.tx().to(ToCaller).payment(&output_payments).transfer(); output_payments } @@ -165,8 +166,7 @@ pub trait TokenMergeModule: ); tokens_to_remove.push(new_merged_token); - let caller = self.blockchain().get_caller(); - self.send().direct_multi(&caller, &tokens_to_remove); + self.tx().to(ToCaller).payment(&tokens_to_remove).transfer(); tokens_to_remove } diff --git a/contracts/modules/src/transfer_role_proxy.rs b/contracts/modules/src/transfer_role_proxy.rs index 80995eff04..d5249ce04c 100644 --- a/contracts/modules/src/transfer_role_proxy.rs +++ b/contracts/modules/src/transfer_role_proxy.rs @@ -13,19 +13,26 @@ pub trait TransferRoleProxyModule { &self, original_caller: ManagedAddress, dest: ManagedAddress, - payments: PaymentsVec, + payments: &PaymentsVec, data: ManagedBuffer, ) -> ! { - let contract_call = - ContractCallWithMultiEsdt::::new(dest, data, payments.clone()); + let transaction = self.tx().to(&dest).raw_call(data).payment(payments); - self.execute_async_call(original_caller, payments, contract_call, None); + self.execute_async_call(original_caller, payments, transaction, None) } fn transfer_to_contract_typed_call( &self, original_caller: ManagedAddress, - contract_call: ContractCallWithMultiEsdt, + transaction: Tx< + TxScEnv, + (), + &ManagedAddress, + &ManagedVec>, + (), + FunctionCall, + (), + >, opt_custom_callback: Option>, ) -> ! where @@ -33,8 +40,8 @@ pub trait TransferRoleProxyModule { { self.execute_async_call( original_caller, - contract_call.esdt_payments.clone(), - contract_call, + transaction.payment, + transaction, opt_custom_callback, ); } @@ -43,59 +50,55 @@ pub trait TransferRoleProxyModule { &self, original_caller: ManagedAddress, dest: ManagedAddress, - payments: PaymentsVec, + payments: &PaymentsVec, endpoint_name: ManagedBuffer, args: ManagedArgBuffer, opt_custom_callback: Option>, ) -> ! { - let contract_call = - ContractCallWithMultiEsdt::::new(dest, endpoint_name, payments.clone()) - .with_raw_arguments(args); - - self.execute_async_call( - original_caller, - payments, - contract_call, - opt_custom_callback, - ); + let transaction = self + .tx() + .to(&dest) + .raw_call(endpoint_name) + .payment(payments) + .arguments_raw(args); + + self.execute_async_call(original_caller, payments, transaction, opt_custom_callback) } - fn execute_async_call( + fn execute_async_call( &self, original_caller: ManagedAddress, - initial_payments: PaymentsVec, - contract_call: ContractCallWithMultiEsdt, + initial_payments: &PaymentsVec, + transaction: Tx< + TxScEnv, + (), + &ManagedAddress, + &ManagedVec>, + (), + FunctionCall, + (), + >, opt_custom_callback: Option>, - ) -> ! - where - T: TopEncodeMulti, - { + ) -> ! { require!( - self.destination_whitelist() - .contains(&contract_call.basic.to), + self.destination_whitelist().contains(transaction.to), "Destination address not whitelisted" ); let remaining_gas = self.blockchain().get_gas_left(); - let cb_gas_needed = - CALLBACK_RESERVED_GAS_PER_TOKEN * contract_call.esdt_payments.len() as u64; + let cb_gas_needed = CALLBACK_RESERVED_GAS_PER_TOKEN * transaction.payment.len() as u64; require!( remaining_gas > cb_gas_needed, "Not enough gas to launch async call" ); - let async_call_gas = remaining_gas - cb_gas_needed; let cb = match opt_custom_callback { Some(custom_cb) => custom_cb, None => TransferRoleProxyModule::callbacks(self) - .transfer_callback(original_caller, initial_payments), + .transfer_callback(original_caller, initial_payments.clone()), }; - contract_call - .with_gas_limit(async_call_gas) - .async_call() - .with_callback(cb) - .call_and_exit() + transaction.callback(cb).async_call_and_exit() } #[callback] @@ -109,8 +112,10 @@ pub trait TransferRoleProxyModule { ManagedAsyncCallResult::Ok(return_values) => return_values, ManagedAsyncCallResult::Err(err) => { if !initial_payments.is_empty() { - self.send() - .direct_multi(&original_caller, &initial_payments); + self.tx() + .to(&original_caller) + .payment(initial_payments) + .transfer(); } let mut err_result = MultiValueEncoded::new(); diff --git a/data/codec-derive/src/nested_de_derive.rs b/data/codec-derive/src/nested_de_derive.rs index 2eb9d18f41..f24ab1a256 100644 --- a/data/codec-derive/src/nested_de_derive.rs +++ b/data/codec-derive/src/nested_de_derive.rs @@ -27,20 +27,20 @@ pub fn variant_dep_decode_snippets( ) -> Vec { let mut previous_disc: Vec = Vec::new(); data_enum - .variants - .iter() - .enumerate() - .map(|(variant_index, variant)| { + .variants + .iter() + .enumerate() + .map(|(variant_index, variant)| { let variant_discriminant = get_discriminant(variant_index, variant, &mut previous_disc); - let variant_ident = &variant.ident; - let variant_field_snippets = fields_decl_syntax(&variant.fields, |index, field| { - dep_decode_snippet(index, field, input_value) - }); - quote! { + let variant_ident = &variant.ident; + let variant_field_snippets = fields_decl_syntax(&variant.fields, |index, field| { + dep_decode_snippet(index, field, input_value) + }); + quote! { #variant_discriminant => core::result::Result::Ok( #name::#variant_ident #variant_field_snippets ), - } - }) - .collect() + } + }) + .collect() } pub fn nested_decode_impl(ast: &syn::DeriveInput) -> TokenStream { diff --git a/data/codec/src/equivalent/codec_from.rs b/data/codec/src/equivalent/codec_from.rs index 27695a56a2..f6fc1ffda2 100644 --- a/data/codec/src/equivalent/codec_from.rs +++ b/data/codec/src/equivalent/codec_from.rs @@ -1,12 +1,14 @@ use crate::{TopDecodeMulti, TopEncodeMulti}; /// Signals that after serializing `T`, we can safely deserialize it as `Self`. +#[deprecated(since = "0.49.0", note = "Please use trait `TypeAbiFrom` instead.")] pub trait CodecFrom: TopDecodeMulti where T: TopEncodeMulti, { } +#[deprecated(since = "0.49.0", note = "Please use trait `TypeAbiFrom` instead.")] pub auto trait CodecFromSelf {} impl CodecFrom for T where T: TopEncodeMulti + TopDecodeMulti + CodecFromSelf {} diff --git a/data/codec/src/equivalent/codec_into.rs b/data/codec/src/equivalent/codec_into.rs index 3f4a60cdb2..06013c41bb 100644 --- a/data/codec/src/equivalent/codec_into.rs +++ b/data/codec/src/equivalent/codec_into.rs @@ -1,6 +1,7 @@ use crate::{CodecFrom, TopDecodeMulti, TopEncodeMulti}; /// Signals that we can safely serialize `Self` in order to obtain a `T` on the other size. +#[deprecated(since = "0.49.0", note = "Please use trait `TypeAbiFrom` instead.")] pub trait CodecInto: TopEncodeMulti where T: TopDecodeMulti, diff --git a/data/codec/src/equivalent/mod.rs b/data/codec/src/equivalent/mod.rs index 3715c4a87c..632fef5ae1 100644 --- a/data/codec/src/equivalent/mod.rs +++ b/data/codec/src/equivalent/mod.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + mod codec_convert; mod codec_from; mod codec_into; diff --git a/data/codec/src/impl_for_types/impl_tuple.rs b/data/codec/src/impl_for_types/impl_tuple.rs index c59ead5126..b5278a92b5 100644 --- a/data/codec/src/impl_for_types/impl_tuple.rs +++ b/data/codec/src/impl_for_types/impl_tuple.rs @@ -11,18 +11,18 @@ macro_rules! tuple_impls { where $($name: NestedEncode,)+ { - fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> where O: TopEncodeOutput, H: EncodeErrorHandler, { - let mut buffer = output.start_nested_encode(); - $( + let mut buffer = output.start_nested_encode(); + $( self.$n.dep_encode_or_handle_err(&mut buffer, h)?; )+ - output.finalize_nested_encode(buffer); - Ok(()) - } + output.finalize_nested_encode(buffer); + Ok(()) + } } impl<$($name),+> TopDecode for ($($name,)+) @@ -42,16 +42,16 @@ macro_rules! tuple_impls { where $($name: NestedEncode,)+ { - fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> + fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> where O: NestedEncodeOutput, H: EncodeErrorHandler, { - $( + $( self.$n.dep_encode_or_handle_err(dest, h)?; )+ - Ok(()) - } + Ok(()) + } } impl<$($name),+> NestedDecode for ($($name,)+) diff --git a/data/codec/src/multi_types/mod.rs b/data/codec/src/multi_types/mod.rs index 2bb9948b41..0a7ae541c4 100644 --- a/data/codec/src/multi_types/mod.rs +++ b/data/codec/src/multi_types/mod.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] // TODO: remove after deleting CodecFrom + mod multi_value_ignore; mod multi_value_optional; mod multi_value_placeholder; diff --git a/data/codec/tests/derive_enum_or_default_test.rs b/data/codec/tests/derive_enum_or_default_test.rs index 24d1017654..7d9b57c755 100644 --- a/data/codec/tests/derive_enum_or_default_test.rs +++ b/data/codec/tests/derive_enum_or_default_test.rs @@ -53,15 +53,15 @@ fn enum_not_defaults() { }; #[rustfmt::skip] - let enum_struct_bytes = &[ - /* discriminant */ 2, - /* int */ 0, 0x42, - /* seq length */ 0, 0, 0, 5, - /* seq contents */ 1, 2, 3, 4, 5, - /* another_byte */ 6, - /* uint_32 */ 0x00, 0x01, 0x23, 0x45, - /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, - ]; + let enum_struct_bytes = &[ + /* discriminant */ 2, + /* int */ 0, 0x42, + /* seq length */ 0, 0, 0, 5, + /* seq contents */ 1, 2, 3, 4, 5, + /* another_byte */ 6, + /* uint_32 */ 0x00, 0x01, 0x23, 0x45, + /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, + ]; check_top_encode_decode(enum_struct, enum_struct_bytes); } diff --git a/data/codec/tests/derive_enum_test.rs b/data/codec/tests/derive_enum_test.rs index b4626400ac..bd798b33ee 100644 --- a/data/codec/tests/derive_enum_test.rs +++ b/data/codec/tests/derive_enum_test.rs @@ -68,11 +68,11 @@ fn field_enum_variant_with_value() { let enum_tuple_0 = EnumWithEverything::Write(Vec::new(), 0); #[rustfmt::skip] - let enum_tuple_0_bytes = &[ - /* discriminant */ 2, - /* vec length */ 0, 0, 0, 0, - /* u16 */ 0, 0, - ]; + let enum_tuple_0_bytes = &[ + /* discriminant */ 2, + /* vec length */ 0, 0, 0, 0, + /* u16 */ 0, 0, + ]; check_top_encode_decode(enum_tuple_0.clone(), enum_tuple_0_bytes); check_dep_encode_decode(enum_tuple_0, enum_tuple_0_bytes); } @@ -81,12 +81,12 @@ fn field_enum_variant_with_value() { fn field_enum_variant_with_tuple() { let enum_tuple_1 = EnumWithEverything::Write([1, 2, 3].to_vec(), 4); #[rustfmt::skip] - let enum_tuple_1_bytes = &[ - /* discriminant */ 2, - /* vec length */ 0, 0, 0, 3, - /* vec contents */ 1, 2, 3, - /* an extra 16 */ 0, 4, - ]; + let enum_tuple_1_bytes = &[ + /* discriminant */ 2, + /* vec length */ 0, 0, 0, 3, + /* vec contents */ 1, 2, 3, + /* an extra 16 */ 0, 4, + ]; check_top_encode_decode(enum_tuple_1.clone(), enum_tuple_1_bytes); check_dep_encode_decode(enum_tuple_1, enum_tuple_1_bytes); @@ -103,15 +103,15 @@ fn field_enum_struct_variant() { }; #[rustfmt::skip] - let enum_struct_bytes = &[ - /* discriminant */ 3, - /* int */ 0, 0x42, - /* seq length */ 0, 0, 0, 5, - /* seq contents */ 1, 2, 3, 4, 5, - /* another_byte */ 6, - /* uint_32 */ 0x00, 0x01, 0x23, 0x45, - /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, - ]; + let enum_struct_bytes = &[ + /* discriminant */ 3, + /* int */ 0, 0x42, + /* seq length */ 0, 0, 0, 5, + /* seq contents */ 1, 2, 3, 4, 5, + /* another_byte */ 6, + /* uint_32 */ 0x00, 0x01, 0x23, 0x45, + /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, + ]; check_top_encode_decode(enum_struct.clone(), enum_struct_bytes); check_dep_encode_decode(enum_struct, enum_struct_bytes); diff --git a/data/codec/tests/derive_struct_or_default_generic_test.rs b/data/codec/tests/derive_struct_or_default_generic_test.rs index e8ab6bbe20..d7631b0ae2 100644 --- a/data/codec/tests/derive_struct_or_default_generic_test.rs +++ b/data/codec/tests/derive_struct_or_default_generic_test.rs @@ -63,14 +63,14 @@ fn struct_or_default_not_default() { }; #[rustfmt::skip] - let bytes_1 = &[ - /* int */ 0, 0x42, - /* seq length */ 0, 0, 0, 5, - /* seq contents */ 1, 2, 3, 4, 5, - /* another_byte */ 6, - /* uint_32 */ 0x00, 0x01, 0x23, 0x45, - /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, - ]; + let bytes_1 = &[ + /* int */ 0, 0x42, + /* seq length */ 0, 0, 0, 5, + /* seq contents */ 1, 2, 3, 4, 5, + /* another_byte */ 6, + /* uint_32 */ 0x00, 0x01, 0x23, 0x45, + /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, + ]; check_top_encode_decode(s, bytes_1); } diff --git a/data/codec/tests/derive_struct_or_default_test.rs b/data/codec/tests/derive_struct_or_default_test.rs index 1b75d5962c..8953b94dc6 100644 --- a/data/codec/tests/derive_struct_or_default_test.rs +++ b/data/codec/tests/derive_struct_or_default_test.rs @@ -54,14 +54,14 @@ fn struct_or_default_not_default() { }; #[rustfmt::skip] - let bytes_1 = &[ - /* int */ 0, 0x42, - /* seq length */ 0, 0, 0, 5, - /* seq contents */ 1, 2, 3, 4, 5, - /* another_byte */ 6, - /* uint_32 */ 0x00, 0x01, 0x23, 0x45, - /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, - ]; + let bytes_1 = &[ + /* int */ 0, 0x42, + /* seq length */ 0, 0, 0, 5, + /* seq contents */ 1, 2, 3, 4, 5, + /* another_byte */ 6, + /* uint_32 */ 0x00, 0x01, 0x23, 0x45, + /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, + ]; check_top_encode_decode(s, bytes_1); } diff --git a/data/codec/tests/derive_struct_test.rs b/data/codec/tests/derive_struct_test.rs index b7967dd9ae..fbe293b7e1 100644 --- a/data/codec/tests/derive_struct_test.rs +++ b/data/codec/tests/derive_struct_test.rs @@ -26,14 +26,14 @@ fn struct_named_fields_test() { }; #[rustfmt::skip] - let bytes_1 = &[ - /* int */ 0, 0x42, - /* seq length */ 0, 0, 0, 5, - /* seq contents */ 1, 2, 3, 4, 5, - /* another_byte */ 6, - /* uint_32 */ 0x00, 0x01, 0x23, 0x45, - /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, - ]; + let bytes_1 = &[ + /* int */ 0, 0x42, + /* seq length */ 0, 0, 0, 5, + /* seq contents */ 1, 2, 3, 4, 5, + /* another_byte */ 6, + /* uint_32 */ 0x00, 0x01, 0x23, 0x45, + /* uint_64 */ 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, + ]; check_top_encode_decode(s.clone(), bytes_1); check_dep_encode_decode(s, bytes_1); diff --git a/data/codec/tests/derive_tuple_struct_test.rs b/data/codec/tests/derive_tuple_struct_test.rs index 53e17ff529..4d6b3c9559 100644 --- a/data/codec/tests/derive_tuple_struct_test.rs +++ b/data/codec/tests/derive_tuple_struct_test.rs @@ -14,11 +14,11 @@ fn tuple_struct_derive_test() { let s = TupleStruct(8, 16, 32); #[rustfmt::skip] - let bytes = &[ - /* 0: u8 */ 8, - /* 1: u32 */ 0, 16, - /* 2: u64 */ 0, 0, 0, 32, - ]; + let bytes = &[ + /* 0: u8 */ 8, + /* 1: u32 */ 0, 16, + /* 2: u64 */ 0, 0, 0, 32, + ]; check_top_encode_decode(s.clone(), bytes); check_dep_encode_decode(s, bytes); diff --git a/framework/base/Cargo.toml b/framework/base/Cargo.toml index 577b05ee7d..de706261d1 100644 --- a/framework/base/Cargo.toml +++ b/framework/base/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sc" -version = "0.48.1" +version = "0.49.0-alpha.4" edition = "2021" authors = ["Andrei Marinica ", "MultiversX "] @@ -28,7 +28,7 @@ bitflags = "=2.4.2" num-traits = { version = "=0.2.17", default-features = false } [dependencies.multiversx-sc-derive] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../derive" [dependencies.multiversx-sc-codec] diff --git a/framework/base/src/abi.rs b/framework/base/src/abi.rs index b79ae26124..993518acb2 100644 --- a/framework/base/src/abi.rs +++ b/framework/base/src/abi.rs @@ -4,18 +4,38 @@ mod endpoint_abi; mod esdt_attribute_abi; mod event_abi; mod type_abi; +mod type_abi_from; mod type_abi_impl_basic; mod type_abi_impl_codec_multi; mod type_description; mod type_description_container; +#[cfg(feature = "num-bigint")] +mod type_abi_impl_big_int; + pub use build_info_abi::*; pub use contract_abi::*; pub use endpoint_abi::*; pub use esdt_attribute_abi::EsdtAttributeAbi; pub use event_abi::*; pub use type_abi::*; +pub use type_abi_from::*; pub use type_description::*; pub use type_description_container::*; pub type TypeName = alloc::string::String; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TypeNames { + pub abi: alloc::string::String, + pub rust: alloc::string::String, +} + +impl TypeNames { + pub const fn new() -> Self { + TypeNames { + abi: alloc::string::String::new(), + rust: alloc::string::String::new(), + } + } +} diff --git a/framework/base/src/abi/contract_abi.rs b/framework/base/src/abi/contract_abi.rs index 3b22d160e7..2c8ad67fba 100644 --- a/framework/base/src/abi/contract_abi.rs +++ b/framework/base/src/abi/contract_abi.rs @@ -10,6 +10,7 @@ pub struct ContractAbi { pub docs: Vec, pub name: String, pub constructors: Vec, + pub upgrade_constructors: Vec, pub endpoints: Vec, pub promise_callbacks: Vec, pub events: Vec, @@ -26,6 +27,7 @@ impl ContractAbi { docs: docs.iter().map(|s| s.to_string()).collect(), name: name.to_string(), constructors: Vec::new(), + upgrade_constructors: Vec::new(), endpoints: Vec::new(), promise_callbacks: Vec::new(), events: Vec::new(), @@ -39,6 +41,8 @@ impl ContractAbi { self.constructors .extend_from_slice(other.constructors.as_slice()); self.endpoints.extend_from_slice(other.endpoints.as_slice()); + self.upgrade_constructors + .extend_from_slice(other.upgrade_constructors.as_slice()); self.events.extend_from_slice(other.events.as_slice()); self.promise_callbacks .extend_from_slice(other.promise_callbacks.as_slice()); @@ -75,6 +79,7 @@ impl ContractAbi { pub fn iter_all_exports(&self) -> impl Iterator { self.constructors .iter() + .chain(self.upgrade_constructors.iter()) .chain(self.endpoints.iter()) .chain(self.promise_callbacks.iter()) } diff --git a/framework/base/src/abi/endpoint_abi.rs b/framework/base/src/abi/endpoint_abi.rs index 1ce6b5c363..03e098d0e9 100644 --- a/framework/base/src/abi/endpoint_abi.rs +++ b/framework/base/src/abi/endpoint_abi.rs @@ -7,15 +7,14 @@ use alloc::{ #[derive(Clone, Debug)] pub struct InputAbi { pub arg_name: String, - pub type_name: TypeName, - // pub original_type_name: TypeName, + pub type_names: TypeNames, pub multi_arg: bool, } #[derive(Clone, Debug)] pub struct OutputAbi { pub output_name: String, - pub type_name: TypeName, + pub type_names: TypeNames, pub multi_result: bool, } @@ -33,6 +32,7 @@ pub enum EndpointMutabilityAbi { pub enum EndpointTypeAbi { #[default] Init, + Upgrade, Endpoint, PromisesCallback, } @@ -89,7 +89,7 @@ impl EndpointAbi { pub fn add_input(&mut self, arg_name: &str) { self.inputs.push(InputAbi { arg_name: arg_name.to_string(), - type_name: T::type_name(), + type_names: T::type_names(), multi_arg: T::is_variadic(), }); } diff --git a/framework/base/src/abi/type_abi.rs b/framework/base/src/abi/type_abi.rs index cdf6c153ac..25d4e92b46 100644 --- a/framework/base/src/abi/type_abi.rs +++ b/framework/base/src/abi/type_abi.rs @@ -1,23 +1,44 @@ use super::*; -use alloc::{string::ToString, vec::Vec}; +use alloc::{format, string::ToString, vec::Vec}; + +/// Implemented for all types that can end up in the ABI: +/// - argument types, +/// - result types, +/// - event log arguments +/// - etc. +/// +/// Will be automatically implemented for struct ad enum types via the `#[type_abi]` annotation. +pub trait TypeAbi: TypeAbiFrom { + type Unmanaged: TypeAbiFrom; + + fn type_names() -> TypeNames { + TypeNames { + abi: Self::type_name(), + rust: Self::type_name_rust(), + } + } -pub trait TypeAbi { fn type_name() -> TypeName { core::any::type_name::().into() } + fn type_name_rust() -> TypeName { + core::any::type_name::().into() + } + /// A type can provide more than its own name. /// For instance, a struct can also provide the descriptions of the type of its fields. /// TypeAbi doesn't care for the exact accumulator type, /// which is abstracted by the TypeDescriptionContainer trait. fn provide_type_descriptions(accumulator: &mut TDC) { - let type_name = Self::type_name(); + let type_names = Self::type_names(); accumulator.insert( - type_name, + type_names, TypeDescription { docs: Vec::new(), - name: Self::type_name(), + names: Self::type_names(), contents: TypeContents::NotSpecified, + macro_attributes: Vec::new(), }, ); } @@ -44,7 +65,7 @@ pub trait TypeAbi { }; result.push(OutputAbi { output_name: output_name.to_string(), - type_name: Self::type_name(), + type_names: Self::type_names(), multi_result: Self::is_variadic(), }); result @@ -52,10 +73,11 @@ pub trait TypeAbi { } pub fn type_name_variadic() -> TypeName { - let mut repr = TypeName::from("variadic<"); - repr.push_str(T::type_name().as_str()); - repr.push('>'); - repr + format!("variadic<{}>", T::type_name()) +} + +pub fn type_name_multi_value_encoded() -> TypeName { + format!("MultiValueEncoded<$API, {}>", T::type_name_rust()) } pub fn type_name_optional() -> TypeName { diff --git a/framework/base/src/abi/type_abi_from.rs b/framework/base/src/abi/type_abi_from.rs new file mode 100644 index 0000000000..81f5345fd5 --- /dev/null +++ b/framework/base/src/abi/type_abi_from.rs @@ -0,0 +1,4 @@ +/// Indicates that 2 types have the same encoding, so they can be used interchangeably in proxies. +/// +/// Only relevant for serializable types. +pub trait TypeAbiFrom {} diff --git a/framework/base/src/abi/type_abi_impl_basic.rs b/framework/base/src/abi/type_abi_impl_basic.rs index 00965215de..878a09bc87 100644 --- a/framework/base/src/abi/type_abi_impl_basic.rs +++ b/framework/base/src/abi/type_abi_impl_basic.rs @@ -2,11 +2,16 @@ use super::*; use crate::arrayvec::ArrayVec; use alloc::{ boxed::Box, + format, string::{String, ToString}, vec::Vec, }; +impl TypeAbiFrom<()> for () {} + impl TypeAbi for () { + type Unmanaged = Self; + /// No another exception from the 1-type-1-output-abi rule: /// the unit type produces no output. fn output_abis(_output_names: &[&'static str]) -> OutputAbis { @@ -14,27 +19,47 @@ impl TypeAbi for () { } } +impl TypeAbiFrom<&U> for &T where T: TypeAbiFrom {} + impl TypeAbi for &T { + type Unmanaged = Self; + fn type_name() -> TypeName { T::type_name() } + fn type_name_rust() -> TypeName { + T::type_name_rust() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } } +impl TypeAbiFrom> for Box where T: TypeAbiFrom {} + impl TypeAbi for Box { + type Unmanaged = Self; + fn type_name() -> TypeName { T::type_name() } + fn type_name_rust() -> TypeName { + format!("Box<{}>", T::type_name_rust()) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } } +impl TypeAbiFrom<&[T]> for &[U] where T: TypeAbiFrom {} + impl TypeAbi for &[T] { + type Unmanaged = Self; + fn type_name() -> TypeName { let t_name = T::type_name(); if t_name == "u8" { @@ -46,62 +71,121 @@ impl TypeAbi for &[T] { repr } + fn type_name_rust() -> TypeName { + // we need to convert to an owned type + format!("Box<[{}]>", T::type_name_rust()) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } } +impl TypeAbiFrom> for Vec where T: TypeAbiFrom {} + impl TypeAbi for Vec { + type Unmanaged = Self; + fn type_name() -> TypeName { <&[T]>::type_name() } + fn type_name_rust() -> TypeName { + format!("Vec<{}>", T::type_name_rust()) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } } +impl TypeAbiFrom> for ArrayVec {} + impl TypeAbi for ArrayVec { + type Unmanaged = Self; + fn type_name() -> TypeName { <&[T]>::type_name() } + fn type_name_rust() -> TypeName { + format!("ArrayVec<{}, {}usize>", T::type_name_rust(), CAP) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } } +impl TypeAbiFrom> for Box<[T]> {} + impl TypeAbi for Box<[T]> { + type Unmanaged = Self; + fn type_name() -> TypeName { <&[T]>::type_name() } + fn type_name_rust() -> TypeName { + format!("Box<[{}]>", T::type_name_rust()) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } } +impl TypeAbiFrom for String {} +impl TypeAbiFrom<&String> for String {} +impl TypeAbiFrom<&str> for String {} +impl TypeAbiFrom> for String {} + impl TypeAbi for String { + type Unmanaged = Self; + fn type_name() -> TypeName { "utf-8 string".into() } } -impl TypeAbi for &str { +impl TypeAbiFrom<&'static str> for &'static str {} + +impl TypeAbi for &'static str { + type Unmanaged = Self; + fn type_name() -> TypeName { - TypeName::type_name() + String::type_name() + } + + fn type_name_rust() -> TypeName { + "&'static str".into() } } +impl TypeAbiFrom> for Box {} +impl TypeAbiFrom<&str> for Box {} +impl TypeAbiFrom for Box {} + impl TypeAbi for Box { + type Unmanaged = Self; + fn type_name() -> TypeName { - TypeName::type_name() + String::type_name() + } + + fn type_name_rust() -> TypeName { + "Box".into() } } macro_rules! type_abi_name_only { ($ty:ty, $name:expr) => { + impl TypeAbiFrom<$ty> for $ty {} + impl TypeAbiFrom<&$ty> for $ty {} + impl TypeAbi for $ty { + type Unmanaged = Self; + fn type_name() -> TypeName { TypeName::from($name) } @@ -126,12 +210,51 @@ type_abi_name_only!(i64, "i64"); type_abi_name_only!(core::num::NonZeroUsize, "NonZeroUsize"); type_abi_name_only!(bool, "bool"); +// Unsigned integer types: the contract can return a smaller capacity result and and we can interpret it as a larger capacity type. + +impl TypeAbiFrom for u64 {} +impl TypeAbiFrom for u64 {} +impl TypeAbiFrom for u64 {} +impl TypeAbiFrom for u64 {} + +impl TypeAbiFrom for u32 {} +impl TypeAbiFrom for u32 {} +impl TypeAbiFrom for u32 {} + +impl TypeAbiFrom for usize {} +impl TypeAbiFrom for usize {} +impl TypeAbiFrom for usize {} + +impl TypeAbiFrom for u16 {} + +// Signed, the same. + +impl TypeAbiFrom for i64 {} +impl TypeAbiFrom for i64 {} +impl TypeAbiFrom for i64 {} +impl TypeAbiFrom for i64 {} + +impl TypeAbiFrom for i32 {} +impl TypeAbiFrom for i32 {} +impl TypeAbiFrom for i32 {} + +impl TypeAbiFrom for isize {} +impl TypeAbiFrom for isize {} +impl TypeAbiFrom for isize {} + +impl TypeAbiFrom for i16 {} + +impl TypeAbiFrom> for Option where T: TypeAbiFrom {} + impl TypeAbi for Option { + type Unmanaged = Self; + fn type_name() -> TypeName { - let mut repr = TypeName::from("Option<"); - repr.push_str(T::type_name().as_str()); - repr.push('>'); - repr + format!("Option<{}>", T::type_name()) + } + + fn type_name_rust() -> TypeName { + format!("Option<{}>", T::type_name_rust()) } fn provide_type_descriptions(accumulator: &mut TDC) { @@ -139,11 +262,23 @@ impl TypeAbi for Option { } } +impl TypeAbiFrom> for Result where T: TypeAbiFrom {} + impl TypeAbi for Result { + type Unmanaged = Self; + fn type_name() -> TypeName { T::type_name() } + fn type_name_rust() -> TypeName { + format!( + "Result<{}, {}>", + T::type_name_rust(), + core::any::type_name::() + ) + } + /// Similar to the SCResult implementation. fn output_abis(output_names: &[&'static str]) -> OutputAbis { T::output_abis(output_names) @@ -157,28 +292,46 @@ impl TypeAbi for Result { macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( + impl<$($name),+> TypeAbiFrom for ($($name,)+) + where + $($name: TypeAbi,)+ + {} + impl<$($name),+> TypeAbi for ($($name,)+) where $($name: TypeAbi,)+ { - fn type_name() -> TypeName { - let mut repr = TypeName::from("tuple"); - repr.push_str("<"); - $( - if $n > 0 { - repr.push(','); - } - repr.push_str($name::type_name().as_str()); + type Unmanaged = Self; + + fn type_name() -> TypeName { + let mut repr = TypeName::from("tuple<"); + $( + if $n > 0 { + repr.push(','); + } + repr.push_str($name::type_name().as_str()); )+ - repr.push('>'); - repr - } + repr.push('>'); + repr + } - fn provide_type_descriptions(accumulator: &mut TDC) { - $( - $name::provide_type_descriptions(accumulator); + fn type_name_rust() -> TypeName { + let mut repr = TypeName::from("("); + $( + if $n > 0 { + repr.push_str(", "); + } + repr.push_str($name::type_name_rust().as_str()); )+ - } + repr.push(')'); + repr + } + + fn provide_type_descriptions(accumulator: &mut TDC) { + $( + $name::provide_type_descriptions(accumulator); + )+ + } } )+ } @@ -203,7 +356,11 @@ tuple_impls! { 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) } +impl TypeAbiFrom<[T; N]> for [U; N] where T: TypeAbiFrom {} + impl TypeAbi for [T; N] { + type Unmanaged = Self; + fn type_name() -> TypeName { let mut repr = TypeName::from("array"); repr.push_str(N.to_string().as_str()); @@ -213,6 +370,15 @@ impl TypeAbi for [T; N] { repr } + fn type_name_rust() -> TypeName { + let mut repr = TypeName::from("["); + repr.push_str(T::type_name_rust().as_str()); + repr.push_str("; "); + repr.push_str(N.to_string().as_str()); + repr.push(']'); + repr + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/abi/type_abi_impl_big_int.rs b/framework/base/src/abi/type_abi_impl_big_int.rs new file mode 100644 index 0000000000..c3b0e6bccf --- /dev/null +++ b/framework/base/src/abi/type_abi_impl_big_int.rs @@ -0,0 +1,33 @@ +use crate::codec::num_bigint::{BigInt, BigUint}; + +use super::{TypeAbi, TypeAbiFrom, TypeName}; + +impl TypeAbiFrom for BigUint {} +impl TypeAbiFrom<&Self> for BigUint {} + +impl TypeAbi for BigUint { + type Unmanaged = Self; + + fn type_name() -> TypeName { + TypeName::from("BigUint") + } + + fn type_name_rust() -> TypeName { + TypeName::from("num_bigint::BigUint") + } +} + +impl TypeAbiFrom for BigInt {} +impl TypeAbiFrom<&Self> for BigInt {} + +impl TypeAbi for BigInt { + type Unmanaged = Self; + + fn type_name() -> TypeName { + TypeName::from("BigInt") + } + + fn type_name_rust() -> TypeName { + TypeName::from("num_bigint::BigInt") + } +} diff --git a/framework/base/src/abi/type_abi_impl_codec_multi.rs b/framework/base/src/abi/type_abi_impl_codec_multi.rs index 6227634258..4fc42f37a6 100644 --- a/framework/base/src/abi/type_abi_impl_codec_multi.rs +++ b/framework/base/src/abi/type_abi_impl_codec_multi.rs @@ -1,14 +1,30 @@ +use alloc::format; + use crate::{ - abi::{OutputAbis, TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{OutputAbis, TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, codec::multi_types::{IgnoreValue, OptionalValue}, }; +#[cfg(feature = "alloc")] +impl TypeAbiFrom> + for crate::codec::multi_types::MultiValueVec +where + T: TypeAbiFrom, +{ +} + #[cfg(feature = "alloc")] impl TypeAbi for crate::codec::multi_types::MultiValueVec { + type Unmanaged = Self; + fn type_name() -> TypeName { super::type_name_variadic::() } + fn type_name_rust() -> TypeName { + format!("MultiValueVec<{}>", T::type_name_rust()) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } @@ -18,21 +34,37 @@ impl TypeAbi for crate::codec::multi_types::MultiValueVec { } } +impl TypeAbiFrom for IgnoreValue {} + impl TypeAbi for IgnoreValue { + type Unmanaged = Self; + fn type_name() -> TypeName { TypeName::from("ignore") } + fn type_name_rust() -> TypeName { + "IgnoreValue".into() + } + fn is_variadic() -> bool { true } } +impl TypeAbiFrom> for OptionalValue where T: TypeAbiFrom {} + impl TypeAbi for OptionalValue { + type Unmanaged = Self; + fn type_name() -> TypeName { super::type_name_optional::() } + fn type_name_rust() -> TypeName { + format!("OptionalValue<{}>", T::type_name_rust()) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } @@ -45,10 +77,17 @@ impl TypeAbi for OptionalValue { macro_rules! multi_arg_impls { ($(($mval_struct:ident $($n:tt $name:ident)+) )+) => { $( + impl<$($name),+ > TypeAbiFrom for crate::codec::multi_types::$mval_struct<$($name,)+> + where + $($name: TypeAbi,)+ + {} + impl<$($name),+ > TypeAbi for crate::codec::multi_types::$mval_struct<$($name,)+> where $($name: TypeAbi,)+ { + type Unmanaged = Self; + fn type_name() -> TypeName { let mut repr = TypeName::from("multi"); repr.push('<'); @@ -62,9 +101,22 @@ macro_rules! multi_arg_impls { repr } + fn type_name_rust() -> TypeName { + let mut repr = TypeName::from(stringify!($mval_struct)); + repr.push('<'); + $( + if $n > 0 { + repr.push_str(", "); + } + repr.push_str($name::type_name_rust().as_str()); + )+ + repr.push('>'); + repr + } + fn provide_type_descriptions(accumulator: &mut TDC) { - $( - $name::provide_type_descriptions(accumulator); + $( + $name::provide_type_descriptions(accumulator); )+ } diff --git a/framework/base/src/abi/type_description.rs b/framework/base/src/abi/type_description.rs index 2f0f5a4336..f7e78ccef7 100644 --- a/framework/base/src/abi/type_description.rs +++ b/framework/base/src/abi/type_description.rs @@ -3,11 +3,14 @@ use alloc::{ vec::Vec, }; +use super::TypeNames; + #[derive(Clone, Debug)] pub struct TypeDescription { pub docs: Vec, - pub name: String, + pub names: TypeNames, pub contents: TypeContents, + pub macro_attributes: Vec, } impl TypeDescription { @@ -17,18 +20,28 @@ impl TypeDescription { /// We use this as value while the fields are being computed. pub const PLACEHOLDER: TypeDescription = TypeDescription { docs: Vec::new(), - name: String::new(), + names: TypeNames { + abi: String::new(), + rust: String::new(), + }, contents: TypeContents::NotSpecified, + macro_attributes: Vec::new(), }; } impl TypeDescription { /// Used in code generation. - pub fn new(docs: &[&str], name: String, contents: TypeContents) -> Self { + pub fn new( + docs: &[&str], + names: TypeNames, + contents: TypeContents, + macro_attributes: &[&str], + ) -> Self { TypeDescription { docs: docs.iter().map(|s| s.to_string()).collect(), - name, + names, contents, + macro_attributes: macro_attributes.iter().map(|s| s.to_string()).collect(), } } } @@ -78,12 +91,12 @@ impl EnumVariantDescription { pub struct StructFieldDescription { pub docs: Vec, pub name: String, - pub field_type: String, + pub field_type: TypeNames, } impl StructFieldDescription { /// Used in code generation. - pub fn new(docs: &[&str], name: &str, field_type: String) -> Self { + pub fn new(docs: &[&str], name: &str, field_type: TypeNames) -> Self { Self { docs: docs.iter().map(|s| s.to_string()).collect(), name: name.to_string(), diff --git a/framework/base/src/abi/type_description_container.rs b/framework/base/src/abi/type_description_container.rs index 7b9c0e892c..16dda2c8b9 100644 --- a/framework/base/src/abi/type_description_container.rs +++ b/framework/base/src/abi/type_description_container.rs @@ -8,17 +8,17 @@ pub trait TypeDescriptionContainer { // A placeholder gets inserted while computing field descriptions for a type, // to avoid an infinite loop for recursive types (if the same type appears again lower in the tree). - fn reserve_type_name(&mut self, type_name: TypeName) { - self.insert(type_name, TypeDescription::PLACEHOLDER); + fn reserve_type_name(&mut self, type_names: TypeNames) { + self.insert(type_names, TypeDescription::PLACEHOLDER); } - fn insert(&mut self, type_name: TypeName, type_description: TypeDescription); + fn insert(&mut self, type_names: TypeNames, type_description: TypeDescription); fn insert_all(&mut self, other: &Self); } #[derive(Clone, Default, Debug)] -pub struct TypeDescriptionContainerImpl(pub Vec<(TypeName, TypeDescription)>); +pub struct TypeDescriptionContainerImpl(pub Vec<(TypeNames, TypeDescription)>); impl TypeDescriptionContainer for TypeDescriptionContainerImpl { fn new() -> Self { @@ -28,16 +28,18 @@ impl TypeDescriptionContainer for TypeDescriptionContainerImpl { fn contains_type(&self, type_name: &str) -> bool { self.0 .iter() - .any(|(existing_type_name, _)| existing_type_name == type_name) + .any(|(existing_type_name, _)| existing_type_name.abi == type_name) } - fn insert(&mut self, type_name: TypeName, type_description: TypeDescription) { - if let Some((_existing_type_name, exisiting_type_description)) = - self.0.iter_mut().find(|(name, _)| name == &type_name) + fn insert(&mut self, type_names: TypeNames, type_description: TypeDescription) { + if let Some((_existing_type_name, exisiting_type_description)) = self + .0 + .iter_mut() + .find(|(name, _)| name.abi == type_names.abi) { *exisiting_type_description = type_description; } else { - self.0.push((type_name, type_description)); + self.0.push((type_names, type_description)); } } diff --git a/framework/base/src/api.rs b/framework/base/src/api.rs index 88f18ca94b..094522d1ac 100644 --- a/framework/base/src/api.rs +++ b/framework/base/src/api.rs @@ -1,5 +1,4 @@ mod blockchain_api; -mod builtin_function_names; mod call_value_api; mod composite_api; mod crypto_api; @@ -16,7 +15,6 @@ pub mod uncallable; mod vm_api; pub use blockchain_api::*; -pub use builtin_function_names::*; pub use call_value_api::*; pub use composite_api::*; pub use crypto_api::*; @@ -30,3 +28,6 @@ pub use print_api::*; pub use send_api::*; pub use storage_api::*; pub use vm_api::VMApi; + +// Backwards compatibility. +pub use crate::types::system_proxy::builtin_func_names::*; diff --git a/framework/base/src/api/composite_api.rs b/framework/base/src/api/composite_api.rs index bf197ade59..d1ca8413d8 100644 --- a/framework/base/src/api/composite_api.rs +++ b/framework/base/src/api/composite_api.rs @@ -2,7 +2,7 @@ use super::{ErrorApi, ManagedTypeApi, SendApi, StorageReadApi, StorageWriteApi}; /// Provided for convenience. /// Designed to be used in any types that send tokens or calls. -pub trait CallTypeApi: SendApi + ManagedTypeApi + ErrorApi {} +pub trait CallTypeApi: SendApi + ManagedTypeApi + StorageWriteApi + ErrorApi {} /// Provided for convenience. /// Designed to be used in storage mappers. diff --git a/framework/base/src/api/managed_types/const_handles.rs b/framework/base/src/api/managed_types/const_handles.rs index bd92bcc1db..1657d18e67 100644 --- a/framework/base/src/api/managed_types/const_handles.rs +++ b/framework/base/src/api/managed_types/const_handles.rs @@ -22,6 +22,9 @@ pub const CALLBACK_CLOSURE_ARGS_BUFFER: RawHandle = -23; pub const MBUF_TEMPORARY_1: RawHandle = -25; pub const MBUF_TEMPORARY_2: RawHandle = -26; +pub const ADDRESS_CALLER: RawHandle = -30; +pub const ADDRESS_SELF: RawHandle = -31; + pub const NEW_HANDLE_START_FROM: RawHandle = -100; // > -100 reserved for APIs /// Used as a flag. Do not use as a regular handle. diff --git a/framework/base/src/contract_base.rs b/framework/base/src/contract_base.rs index 07ee908d93..b7ae48ea10 100644 --- a/framework/base/src/contract_base.rs +++ b/framework/base/src/contract_base.rs @@ -9,7 +9,7 @@ mod wrappers; pub use callable_contract::{CallableContract, CallableContractBuilder}; pub use contract_abi_provider::ContractAbiProvider; pub use contract_base_trait::ContractBase; -pub use proxy_obj_base::ProxyObjBase; +pub use proxy_obj_base::{ProxyObjBase, ProxyObjNew}; pub use proxy_obj_callback_base::CallbackProxyObjBase; pub use universal_contract_obj::*; pub use wrappers::*; diff --git a/framework/base/src/contract_base/contract_base_trait.rs b/framework/base/src/contract_base/contract_base_trait.rs index cec45dfa0f..342b9ea61d 100644 --- a/framework/base/src/contract_base/contract_base_trait.rs +++ b/framework/base/src/contract_base/contract_base_trait.rs @@ -2,7 +2,10 @@ use super::{ BlockchainWrapper, CallValueWrapper, CryptoWrapper, ErrorHelper, ManagedSerializer, SendRawWrapper, SendWrapper, StorageRawWrapper, }; -use crate::api::VMApi; +use crate::{ + api::VMApi, + types::{Tx, TxBaseWithEnv, TxScEnv}, +}; /// Interface to be used by the actual smart contract code. /// @@ -26,6 +29,12 @@ pub trait ContractBase: Sized { SendWrapper::new() } + /// Starts the declaration of a new transaction. + #[inline] + fn tx(&self) -> TxBaseWithEnv> { + Tx::new_tx_from_sc() + } + /// Low-level functionality related to sending transactions from the current contract. /// /// For almost all cases contracts should instead use `self.send()` and `ContractCall`. diff --git a/framework/base/src/contract_base/proxy_obj_base.rs b/framework/base/src/contract_base/proxy_obj_base.rs index 54eadd26cd..0d3053d8f4 100644 --- a/framework/base/src/contract_base/proxy_obj_base.rs +++ b/framework/base/src/contract_base/proxy_obj_base.rs @@ -1,18 +1,11 @@ use crate::{ api::VMApi, - types::{ManagedAddress, ManagedOption}, + types::{ManagedAddress, ManagedOption, TxScEnv, TxTo}, }; pub trait ProxyObjBase { type Api: VMApi; - - #[doc(hidden)] - fn new_proxy_obj() -> Self; - - /// Specify the target contract to call. - /// Not taken into account for deploys. - #[must_use] - fn contract(self, address: ManagedAddress) -> Self; + type To: TxTo>; /// Extracts the address contained in the proxy object and replaces it with None. /// @@ -25,4 +18,19 @@ pub trait ProxyObjBase { /// Will crash if no address was specified. #[doc(hidden)] fn extract_address(&mut self) -> ManagedAddress; + + #[doc(hidden)] + fn extract_proxy_to(&mut self) -> Self::To; +} + +pub trait ProxyObjNew: ProxyObjBase { + type ProxyTo: ProxyObjBase; + + #[doc(hidden)] + fn new_proxy_obj() -> Self; + + /// Specify the target contract to call. + /// Not taken into account for deploys. + #[must_use] + fn contract(self, address: ManagedAddress) -> Self::ProxyTo; } diff --git a/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs b/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs index 01ce71d189..5a7f36a722 100644 --- a/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs @@ -153,8 +153,9 @@ where #[inline] pub fn get_sc_balance(&self, token: &EgldOrEsdtTokenIdentifier, nonce: u64) -> BigUint { token.map_ref_or_else( - || self.get_balance(&self.get_sc_address()), - |token_identifier| { + (), + |()| self.get_balance(&self.get_sc_address()), + |(), token_identifier| { self.get_esdt_balance(&self.get_sc_address(), token_identifier, nonce) }, ) diff --git a/framework/base/src/contract_base/wrappers/send_raw_wrapper.rs b/framework/base/src/contract_base/wrappers/send_raw_wrapper.rs index 5635c0b44a..5d290369df 100644 --- a/framework/base/src/contract_base/wrappers/send_raw_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_raw_wrapper.rs @@ -79,20 +79,12 @@ where &self, to: &ManagedAddress, token: &TokenIdentifier, - egld_value: &BigUint, + value: &BigUint, gas_limit: u64, endpoint_name: &ManagedBuffer, arg_buffer: &ManagedArgBuffer, ) -> Result<(), &'static [u8]> { - self.transfer_esdt_nft_execute( - to, - token, - 0, - egld_value, - gas_limit, - endpoint_name, - arg_buffer, - ) + self.transfer_esdt_nft_execute(to, token, 0, value, gas_limit, endpoint_name, arg_buffer) } #[allow(clippy::too_many_arguments)] diff --git a/framework/base/src/contract_base/wrappers/send_wrapper.rs b/framework/base/src/contract_base/wrappers/send_wrapper.rs index 78f4f045d6..11a8f748fc 100644 --- a/framework/base/src/contract_base/wrappers/send_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/send_wrapper.rs @@ -3,18 +3,13 @@ use core::marker::PhantomData; use crate::codec::Empty; use crate::{ - api::{ - BlockchainApi, BlockchainApiImpl, CallTypeApi, StorageReadApi, - CHANGE_OWNER_BUILTIN_FUNC_NAME, CLAIM_DEVELOPER_REWARDS_FUNC_NAME, - ESDT_LOCAL_BURN_FUNC_NAME, ESDT_LOCAL_MINT_FUNC_NAME, ESDT_NFT_ADD_QUANTITY_FUNC_NAME, - ESDT_NFT_ADD_URI_FUNC_NAME, ESDT_NFT_BURN_FUNC_NAME, ESDT_NFT_CREATE_FUNC_NAME, - ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME, - }, + api::{BlockchainApi, CallTypeApi, StorageReadApi}, codec, - esdt::ESDTSystemSmartContractProxy, types::{ - BigUint, ContractCall, ContractCallNoPayment, EgldOrEsdtTokenIdentifier, EsdtTokenPayment, - ManagedAddress, ManagedArgBuffer, ManagedBuffer, ManagedType, ManagedVec, TokenIdentifier, + system_proxy, BigUint, ContractCallNoPayment, ESDTSystemSCAddress, + EgldOrEsdtTokenIdentifier, EsdtTokenPayment, FunctionCall, GasLeft, ManagedAddress, + ManagedArgBuffer, ManagedBuffer, ManagedType, ManagedVec, OriginalResultMarker, + ReturnsRawResult, ReturnsResult, ToSelf, TokenIdentifier, Tx, TxScEnv, }, }; @@ -50,12 +45,21 @@ where SendRawWrapper::new() } - /// A proxy for calling the system smart contract. - /// - /// Use the methods of this proxy to launch contract calls to the system SC. - #[inline] - pub fn esdt_system_sc_proxy(&self) -> ESDTSystemSmartContractProxy { - ESDTSystemSmartContractProxy::new_proxy_obj() + /// Backwards compatibility, synonymous to `esdt_system_sc_tx`, which is the more appropriate name now. + pub fn esdt_system_sc_proxy( + &self, + ) -> system_proxy::ESDTSystemSCProxyMethods, (), ESDTSystemSCAddress, ()> { + self.esdt_system_sc_tx() + } + + /// Prepares a proxy object to call the system SC. + /// It has the destination address set, as well as the contract type (as specified in the proxy). + pub fn esdt_system_sc_tx( + &self, + ) -> system_proxy::ESDTSystemSCProxyMethods, (), ESDTSystemSCAddress, ()> { + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(system_proxy::ESDTSystemSCProxy) } /// Convenient way to quickly instance a minimal contract call (with no EGLD, no arguments, etc.) @@ -74,7 +78,7 @@ where /// Used especially for sending EGLD to regular accounts. #[inline] pub fn direct_egld(&self, to: &ManagedAddress, amount: &BigUint) { - self.send_raw_wrapper().direct_egld(to, amount, Empty) + Tx::new_tx_from_sc().to(to).egld(amount).transfer(); } /// Sends EGLD to a given address, directly. @@ -82,11 +86,10 @@ where /// /// If the amount is 0, it returns without error. pub fn direct_non_zero_egld(&self, to: &ManagedAddress, amount: &BigUint) { - if amount == &0 { - return; - } - - self.direct_egld(to, amount) + Tx::new_tx_from_sc() + .to(to) + .egld(amount) + .transfer_if_not_empty(); } /// Sends either EGLD, ESDT or NFT to the target address, @@ -188,16 +191,17 @@ where } /// Sends a single ESDT transfer to target address. - #[inline] - #[allow(clippy::too_many_arguments)] pub fn direct_esdt( &self, to: &ManagedAddress, token_identifier: &TokenIdentifier, - nonce: u64, + token_nonce: u64, amount: &BigUint, ) { - self.direct_esdt_with_gas_limit(to, token_identifier, nonce, amount, 0, Empty, &[]); + Tx::new_tx_from_sc() + .to(to) + .single_esdt(token_identifier, token_nonce, amount) + .transfer(); } /// Sends a single ESDT transfer to target address. @@ -290,13 +294,7 @@ where to: &ManagedAddress, payments: &ManagedVec>, ) { - let _ = self.send_raw_wrapper().multi_esdt_transfer_execute( - to, - payments, - 0, - &ManagedBuffer::new(), - &ManagedArgBuffer::new(), - ); + Tx::new_tx_from_sc().to(to).payment(payments).transfer(); } /// Performs a simple ESDT/NFT transfer, but via async call. @@ -314,10 +312,10 @@ where nonce: u64, amount: BigUint, ) -> ! { - ContractCallNoPayment::::new(to, ManagedBuffer::new()) - .with_esdt_transfer((token, nonce, amount)) - .async_call() - .call_and_exit_ignore_callback() + Tx::new_tx_from_sc() + .to(to) + .esdt((token, nonce, amount)) + .async_call_and_exit() } /// Performs a simple ESDT/NFT transfer, but via async call. @@ -339,10 +337,7 @@ where if amount == 0 { return; } - ContractCallNoPayment::::new(to, ManagedBuffer::new()) - .with_esdt_transfer((token, nonce, amount)) - .async_call() - .call_and_exit_ignore_callback() + self.transfer_esdt_via_async_call(to, token, nonce, amount) } /// Sends multiple ESDT tokens to a target address, via an async call. @@ -351,32 +346,37 @@ where to: ManagedAddress, payments: ManagedVec>, ) -> ! { - ContractCallNoPayment::::new(to, ManagedBuffer::new()) - .with_multi_token_transfer(payments) - .async_call() - .call_and_exit_ignore_callback() + Tx::new_tx_from_sc() + .to(to) + .payment(payments) + .async_call_and_exit() } /// Creates a call to the `ClaimDeveloperRewards` builtin function. - /// - /// In itself, this does nothing. You need to then call turn the contract call into an async call. + #[allow(clippy::type_complexity)] pub fn claim_developer_rewards( &self, child_sc_address: ManagedAddress, - ) -> ContractCallNoPayment { - ContractCallNoPayment::new(child_sc_address, CLAIM_DEVELOPER_REWARDS_FUNC_NAME) + ) -> Tx, (), ManagedAddress, (), (), FunctionCall, OriginalResultMarker<()>> + { + Tx::new_tx_from_sc() + .to(child_sc_address) + .typed(system_proxy::UserBuiltinProxy) + .claim_developer_rewards() } /// Creates a call to the `ChangeOwnerAddress` builtin function. - /// - /// In itself, this does nothing. You need to then call turn the contract call into an async call. + #[allow(clippy::type_complexity)] pub fn change_owner_address( &self, child_sc_address: ManagedAddress, new_owner: &ManagedAddress, - ) -> ContractCallNoPayment { - self.contract_call(child_sc_address, CHANGE_OWNER_BUILTIN_FUNC_NAME) - .argument(&new_owner) + ) -> Tx, (), ManagedAddress, (), (), FunctionCall, OriginalResultMarker<()>> + { + Tx::new_tx_from_sc() + .to(child_sc_address) + .typed(system_proxy::UserBuiltinProxy) + .change_owner_address(new_owner) } /// Allows synchronously calling a local function by name. Execution is resumed afterwards. @@ -385,11 +385,16 @@ where pub fn call_local_esdt_built_in_function( &self, gas: u64, - endpoint_name: &ManagedBuffer, - arg_buffer: &ManagedArgBuffer, + endpoint_name: ManagedBuffer, + arg_buffer: ManagedArgBuffer, ) -> ManagedVec> { - self.send_raw_wrapper() - .call_local_esdt_built_in_function(gas, endpoint_name, arg_buffer) + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(gas) + .raw_call(endpoint_name) + .arguments_raw(arg_buffer) + .returns(ReturnsRawResult) + .sync_call() } /// Allows synchronous minting of ESDT/SFT (depending on nonce). Execution is resumed afterwards. @@ -401,25 +406,12 @@ where /// /// This function cannot be used for NFTs. pub fn esdt_local_mint(&self, token: &TokenIdentifier, nonce: u64, amount: &BigUint) { - let mut arg_buffer = ManagedArgBuffer::new(); - let func_name: &str; - - arg_buffer.push_arg(token); - - if nonce == 0 { - func_name = ESDT_LOCAL_MINT_FUNC_NAME; - } else { - func_name = ESDT_NFT_ADD_QUANTITY_FUNC_NAME; - arg_buffer.push_arg(nonce); - } - - arg_buffer.push_arg(amount); - - let _ = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(func_name), - &arg_buffer, - ); + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_local_mint(token, nonce, amount) + .sync_call() } /// Allows synchronous minting of ESDT/SFT (depending on nonce). Execution is resumed afterwards. @@ -448,24 +440,12 @@ where /// Note that the SC must have the ESDTLocalBurn or ESDTNftBurn roles set, /// or this will fail with "action is not allowed". pub fn esdt_local_burn(&self, token: &TokenIdentifier, nonce: u64, amount: &BigUint) { - let mut arg_buffer = ManagedArgBuffer::new(); - let func_name: &str; - - arg_buffer.push_arg(token); - if nonce == 0 { - func_name = ESDT_LOCAL_BURN_FUNC_NAME; - } else { - func_name = ESDT_NFT_BURN_FUNC_NAME; - arg_buffer.push_arg(nonce); - } - - arg_buffer.push_arg(amount); - - let _ = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(func_name), - &arg_buffer, - ); + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_local_burn(token, nonce, amount) + .sync_call() } /// Allows synchronous burning of ESDT/SFT/NFT (depending on nonce). Execution is resumed afterwards. @@ -533,36 +513,13 @@ where attributes: &T, uris: &ManagedVec>, ) -> u64 { - let mut arg_buffer = ManagedArgBuffer::new(); - arg_buffer.push_arg(token); - arg_buffer.push_arg(amount); - arg_buffer.push_arg(name); - arg_buffer.push_arg(royalties); - arg_buffer.push_arg(hash); - arg_buffer.push_arg(attributes); - - if uris.is_empty() { - // at least one URI is required, so we push an empty one - arg_buffer.push_arg(codec::Empty); - } else { - // The API function has the last argument as variadic, - // so we top-encode each and send as separate argument - for uri in uris { - arg_buffer.push_arg(uri); - } - } - - let output = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(ESDT_NFT_CREATE_FUNC_NAME), - &arg_buffer, - ); - - if let Some(first_result_bytes) = output.try_get(0) { - first_result_bytes.parse_as_u64().unwrap_or_default() - } else { - 0 - } + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .esdt_nft_create(token, amount, name, royalties, hash, attributes, uris) + .returns(ReturnsResult) + .sync_call() } /// Creates a new NFT token of a certain type (determined by `token_identifier`). @@ -767,19 +724,12 @@ where return; } - let mut arg_buffer = ManagedArgBuffer::new(); - arg_buffer.push_arg(token_id); - arg_buffer.push_arg(nft_nonce); - - for uri in new_uris { - arg_buffer.push_arg(uri); - } - - let _ = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(ESDT_NFT_ADD_URI_FUNC_NAME), - &arg_buffer, - ); + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .nft_add_multiple_uri(token_id, nft_nonce, new_uris) + .sync_call() } /// Changes attributes of an NFT, via a synchronous builtin function call. @@ -789,15 +739,11 @@ where nft_nonce: u64, new_attributes: &T, ) { - let mut arg_buffer = ManagedArgBuffer::new(); - arg_buffer.push_arg(token_id); - arg_buffer.push_arg(nft_nonce); - arg_buffer.push_arg(new_attributes); - - let _ = self.call_local_esdt_built_in_function( - A::blockchain_api_impl().get_gas_left(), - &ManagedBuffer::from(ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME), - &arg_buffer, - ); + Tx::new_tx_from_sc() + .to(ToSelf) + .gas(GasLeft) + .typed(system_proxy::UserBuiltinProxy) + .nft_update_attributes(token_id, nft_nonce, new_attributes) + .sync_call() } } diff --git a/framework/base/src/derive_imports.rs b/framework/base/src/derive_imports.rs new file mode 100644 index 0000000000..64f45ead1d --- /dev/null +++ b/framework/base/src/derive_imports.rs @@ -0,0 +1,7 @@ +pub use crate::{ + codec, + codec::derive::{ + NestedDecode, NestedEncode, TopDecode, TopDecodeOrDefault, TopEncode, TopEncodeOrDefault, + }, + derive::{type_abi, ManagedVecItem, TypeAbi}, +}; diff --git a/framework/base/src/esdt.rs b/framework/base/src/esdt.rs deleted file mode 100644 index db1730be29..0000000000 --- a/framework/base/src/esdt.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod properties; -mod system_sc_proxy; - -pub use properties::*; -pub use system_sc_proxy::ESDTSystemSmartContractProxy; diff --git a/framework/base/src/external_view_contract.rs b/framework/base/src/external_view_contract.rs index ba14d7072a..2b01176176 100644 --- a/framework/base/src/external_view_contract.rs +++ b/framework/base/src/external_view_contract.rs @@ -49,7 +49,7 @@ pub fn external_view_contract_constructor_abi() -> EndpointAbi { ); endpoint_abi.inputs.push(InputAbi { arg_name: "target_contract_address".to_string(), - type_name: crate::types::heap::Address::type_name(), + type_names: crate::types::heap::Address::type_names(), multi_arg: false, }); endpoint_abi diff --git a/framework/base/src/imports.rs b/framework/base/src/imports.rs new file mode 100644 index 0000000000..016aa7bb4e --- /dev/null +++ b/framework/base/src/imports.rs @@ -0,0 +1,22 @@ +pub use crate::{ + abi::TypeAbi, + api::{ErrorApiImpl, ManagedTypeApi, VMApi}, + arrayvec::ArrayVec, + codec::{ + multi_types::*, CodecFrom, CodecFromSelf, CodecInto, DecodeError, Empty, IntoMultiValue, + NestedDecode, NestedEncode, TopDecode, TopEncode, + }, + contract_base::{ContractBase, ProxyObjBase, ProxyObjNew}, + err_msg, + io::*, + non_zero_usize, + non_zero_util::*, + require, sc_format, sc_panic, sc_print, + storage::mappers::*, + types::{system_proxy::*, *}, +}; + +pub use core::ops::{ + Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, + Mul, MulAssign, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, +}; diff --git a/framework/base/src/lib.rs b/framework/base/src/lib.rs index 951e3b5b4f..043ba4bebb 100644 --- a/framework/base/src/lib.rs +++ b/framework/base/src/lib.rs @@ -23,7 +23,6 @@ pub mod abi; pub mod api; pub mod contract_base; pub mod err_msg; -pub mod esdt; pub mod external_view_contract; pub mod formatter; pub mod hex_call_data; @@ -32,6 +31,7 @@ pub mod log_util; mod macros; pub mod non_zero_util; pub mod storage; +pub mod tuple_util; pub mod types; pub use hex_call_data::*; @@ -39,39 +39,12 @@ pub use hex_literal; pub use storage::{storage_clear, storage_get, storage_get_len, storage_set}; /// Conveniently groups all framework imports required by a smart contract form the framework. -pub mod imports { - pub use crate::{ - abi::TypeAbi, - api::{ErrorApiImpl, ManagedTypeApi}, - arrayvec::ArrayVec, - codec::{ - multi_types::*, DecodeError, IntoMultiValue, NestedDecode, NestedEncode, TopDecode, - TopEncode, - }, - contract_base::{ContractBase, ProxyObjBase}, - err_msg, - esdt::*, - io::*, - non_zero_usize, - non_zero_util::*, - require, sc_format, sc_panic, sc_print, - storage::mappers::*, - types::*, - }; - pub use core::ops::{ - Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, - DivAssign, Mul, MulAssign, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, - }; -} +pub mod imports; /// Conveniently groups all imports required for deriving framework-related traits for types. -pub mod derive_imports { - pub use crate::{ - codec, - codec::derive::{ - NestedDecode, NestedEncode, TopDecode, TopDecodeOrDefault, TopEncode, - TopEncodeOrDefault, - }, - derive::{ManagedVecItem, TypeAbi}, - }; +pub mod derive_imports; + +/// Conveniently groups all imports required for generated proxies. +pub mod proxy_imports { + pub use super::{derive_imports::*, imports::*}; } diff --git a/framework/base/src/storage/mappers/bi_di_mapper.rs b/framework/base/src/storage/mappers/bi_di_mapper.rs index 42c55e5275..4c59caa0ce 100644 --- a/framework/base/src/storage/mappers/bi_di_mapper.rs +++ b/framework/base/src/storage/mappers/bi_di_mapper.rs @@ -1,6 +1,7 @@ use core::marker::PhantomData; use crate::{ + abi::TypeAbiFrom, codec::{ multi_encode_iter_or_handle_err, multi_types::MultiValue2, CodecFrom, EncodeErrorHandler, NestedDecode, NestedEncode, TopDecode, TopEncode, TopEncodeMulti, TopEncodeMultiOutput, @@ -307,6 +308,23 @@ where { } +impl TypeAbiFrom> + for MultiValueEncoded> +where + SA: StorageMapperApi, + K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq, + V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq, +{ +} + +impl TypeAbiFrom for BiDiMapper +where + SA: StorageMapperApi, + K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq, + V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq, +{ +} + impl TypeAbi for BiDiMapper where SA: StorageMapperApi, @@ -327,10 +345,16 @@ where + PartialEq + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { MultiValueEncoded::>::type_name() } + fn type_name_rust() -> TypeName { + MultiValueEncoded::>::type_name_rust() + } + fn provide_type_descriptions(accumulator: &mut TDC) { K::provide_type_descriptions(accumulator); V::provide_type_descriptions(accumulator); diff --git a/framework/base/src/storage/mappers/linked_list_mapper.rs b/framework/base/src/storage/mappers/linked_list_mapper.rs index d58c0ad19d..d2d8af3b10 100644 --- a/framework/base/src/storage/mappers/linked_list_mapper.rs +++ b/framework/base/src/storage/mappers/linked_list_mapper.rs @@ -5,7 +5,7 @@ use super::{ StorageClearable, StorageMapper, }; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::StorageMapperApi, codec::{ self, @@ -620,15 +620,36 @@ where { } +impl TypeAbiFrom> for MultiValueEncoded +where + SA: StorageMapperApi, + T: TopEncode + TopDecode + NestedEncode + NestedDecode + Clone, + U: TypeAbiFrom, +{ +} + +impl TypeAbiFrom for LinkedListMapper +where + SA: StorageMapperApi, + T: TopEncode + TopDecode + NestedEncode + NestedDecode + Clone, +{ +} + impl TypeAbi for LinkedListMapper where SA: StorageMapperApi, T: TopEncode + TopDecode + NestedEncode + NestedDecode + Clone + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/storage/mappers/map_mapper.rs b/framework/base/src/storage/mappers/map_mapper.rs index af4bbda6ff..eda95d8930 100644 --- a/framework/base/src/storage/mappers/map_mapper.rs +++ b/framework/base/src/storage/mappers/map_mapper.rs @@ -5,7 +5,7 @@ use super::{ SetMapper, StorageClearable, StorageMapper, }; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::StorageMapperApi, codec::{ multi_encode_iter_or_handle_err, multi_types::MultiValue2, CodecFrom, EncodeErrorHandler, @@ -548,6 +548,23 @@ where { } +impl TypeAbiFrom> + for MultiValueEncoded> +where + SA: StorageMapperApi, + K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static, + V: TopEncode + TopDecode + 'static, +{ +} + +impl TypeAbiFrom for MapMapper +where + SA: StorageMapperApi, + K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static, + V: TopEncode + TopDecode + 'static, +{ +} + /// Behaves like a MultiResultVec> when an endpoint result. impl TypeAbi for MapMapper where @@ -555,10 +572,16 @@ where K: TopEncode + TopDecode + NestedEncode + NestedDecode + TypeAbi + 'static, V: TopEncode + TopDecode + TypeAbi + 'static, { + type Unmanaged = Self; + fn type_name() -> TypeName { MultiValueEncoded::>::type_name() } + fn type_name_rust() -> TypeName { + MultiValueEncoded::>::type_name_rust() + } + fn provide_type_descriptions(accumulator: &mut TDC) { K::provide_type_descriptions(accumulator); V::provide_type_descriptions(accumulator); 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 8d56c302aa..fbc3de782f 100644 --- a/framework/base/src/storage/mappers/ordered_binary_tree_mapper.rs +++ b/framework/base/src/storage/mappers/ordered_binary_tree_mapper.rs @@ -3,10 +3,10 @@ use core::marker::PhantomData; use codec::Empty; use crate::{ - api::StorageMapperApi, - imports::{ErrorApiImpl, ManagedType}, + api::{ErrorApiImpl, StorageMapperApi}, storage::StorageKey, storage_set, + types::ManagedType, }; use super::{ diff --git a/framework/base/src/storage/mappers/queue_mapper.rs b/framework/base/src/storage/mappers/queue_mapper.rs index 79ac5f37d7..a1ba11e2a6 100644 --- a/framework/base/src/storage/mappers/queue_mapper.rs +++ b/framework/base/src/storage/mappers/queue_mapper.rs @@ -5,7 +5,7 @@ use super::{ StorageClearable, StorageMapper, }; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::StorageMapperApi, codec::{ self, @@ -525,16 +525,36 @@ where { } +impl TypeAbiFrom> for MultiValueEncoded +where + SA: StorageMapperApi, + T: TopEncode + TopDecode, +{ +} + +impl TypeAbiFrom for QueueMapper +where + SA: StorageMapperApi, + T: TopEncode + TopDecode, +{ +} + /// Behaves like a MultiResultVec when an endpoint result. impl TypeAbi for QueueMapper where SA: StorageMapperApi, T: TopEncode + TopDecode + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/storage/mappers/set_mapper.rs b/framework/base/src/storage/mappers/set_mapper.rs index 28941a7a8c..1579f1938e 100644 --- a/framework/base/src/storage/mappers/set_mapper.rs +++ b/framework/base/src/storage/mappers/set_mapper.rs @@ -5,7 +5,7 @@ use storage_get_from_address::storage_get_len_from_address; pub use super::queue_mapper::Iter; use super::{QueueMapper, StorageClearable, StorageMapper}; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::StorageMapperApi, codec::{ self, multi_encode_iter_or_handle_err, CodecFrom, EncodeErrorHandler, NestedDecode, @@ -301,16 +301,36 @@ where { } +impl TypeAbiFrom> for MultiValueEncoded +where + SA: StorageMapperApi, + T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static, +{ +} + +impl TypeAbiFrom for SetMapper +where + SA: StorageMapperApi, + T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static, +{ +} + /// Behaves like a MultiResultVec when an endpoint result. impl TypeAbi for SetMapper where SA: StorageMapperApi, T: TopEncode + TopDecode + NestedEncode + NestedDecode + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/storage/mappers/single_value_mapper.rs b/framework/base/src/storage/mappers/single_value_mapper.rs index b00d605542..dfaa41a393 100644 --- a/framework/base/src/storage/mappers/single_value_mapper.rs +++ b/framework/base/src/storage/mappers/single_value_mapper.rs @@ -5,7 +5,7 @@ use super::{ StorageMapper, }; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::StorageMapperApi, codec::{ multi_types::PlaceholderOutput, CodecFrom, CodecFromSelf, DecodeErrorHandler, @@ -210,6 +210,14 @@ where { } +impl TypeAbiFrom> for SingleValue +where + SA: StorageMapperApi, + T: TopEncode + TopDecode, + R: TopDecode + CodecFrom, +{ +} + impl CodecFrom> for PlaceholderOutput where SA: StorageMapperApi, @@ -217,15 +225,35 @@ where { } +impl TypeAbiFrom> for PlaceholderOutput +where + SA: StorageMapperApi, + T: TopEncode + TopDecode, +{ +} + +impl TypeAbiFrom for SingleValueMapper +where + SA: StorageMapperApi, + T: TopEncode + TopDecode + TypeAbi, +{ +} + impl TypeAbi for SingleValueMapper where SA: StorageMapperApi, T: TopEncode + TopDecode + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { T::type_name() } + fn type_name_rust() -> TypeName { + T::type_name_rust() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator) } diff --git a/framework/base/src/storage/mappers/token/fungible_token_mapper.rs b/framework/base/src/storage/mappers/token/fungible_token_mapper.rs index 5cc3b88e2a..6164e919df 100644 --- a/framework/base/src/storage/mappers/token/fungible_token_mapper.rs +++ b/framework/base/src/storage/mappers/token/fungible_token_mapper.rs @@ -1,8 +1,12 @@ use crate::{ - abi::TypeAbi, + abi::{TypeAbi, TypeAbiFrom}, api::ErrorApiImpl, codec::{CodecFrom, EncodeErrorHandler, TopEncodeMulti, TopEncodeMultiOutput}, storage_clear, storage_get, storage_set, + types::{ + system_proxy::{ESDTSystemSCProxy, FungibleTokenProperties}, + ESDTSystemSCAddress, Tx, + }, }; use super::{ @@ -14,11 +18,10 @@ use crate::{ abi::TypeName, api::{CallTypeApi, StorageMapperApi}, contract_base::{BlockchainWrapper, SendWrapper}, - esdt::{ESDTSystemSmartContractProxy, FungibleTokenProperties}, storage::StorageKey, types::{ - BigUint, CallbackClosure, ContractCall, EsdtTokenPayment, EsdtTokenType, ManagedAddress, - ManagedBuffer, ManagedType, TokenIdentifier, + BigUint, CallbackClosure, EsdtTokenPayment, EsdtTokenType, ManagedAddress, ManagedBuffer, + ManagedType, TokenIdentifier, }, }; @@ -113,7 +116,6 @@ where ) -> ! { check_not_set(self); - let system_sc_proxy = ESDTSystemSmartContractProxy::::new_proxy_obj(); let callback = match opt_callback { Some(cb) => cb, None => self.default_callback_closure_obj(&initial_supply), @@ -124,7 +126,9 @@ where }; storage_set(self.get_storage_key(), &TokenMapperState::::Pending); - system_sc_proxy + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) .issue_fungible( issue_cost, &token_display_name, @@ -132,9 +136,8 @@ where &initial_supply, properties, ) - .async_call() - .with_callback(callback) - .call_and_exit(); + .callback(callback) + .async_call_and_exit() } /// Important: If you use custom callback, remember to save the token ID in the callback and clear the mapper in case of error! Clear is unusable outside this specific case. @@ -165,14 +168,15 @@ where ) -> ! { check_not_set(self); - let system_sc_proxy = ESDTSystemSmartContractProxy::::new_proxy_obj(); let callback = match opt_callback { Some(cb) => cb, None => self.default_callback_closure_obj(&BigUint::zero()), }; storage_set(self.get_storage_key(), &TokenMapperState::::Pending); - system_sc_proxy + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) .issue_and_set_all_roles( issue_cost, token_display_name, @@ -180,9 +184,8 @@ where EsdtTokenType::Fungible, num_decimals, ) - .async_call() - .with_callback(callback) - .call_and_exit(); + .callback(callback) + .async_call_and_exit(); } pub fn clear(&mut self) { @@ -243,8 +246,10 @@ where } fn send_payment(&self, to: &ManagedAddress, payment: &EsdtTokenPayment) { - let send_wrapper = SendWrapper::::new(); - send_wrapper.direct_esdt(to, &payment.token_identifier, 0, &payment.amount); + Tx::new_tx_from_sc() + .to(to) + .single_esdt(&payment.token_identifier, 0, &payment.amount) + .transfer(); } } @@ -270,14 +275,27 @@ impl CodecFrom> for TokenIdentifier where { } +impl TypeAbiFrom> for TokenIdentifier where + SA: StorageMapperApi + CallTypeApi +{ +} + +impl TypeAbiFrom for FungibleTokenMapper where SA: StorageMapperApi + CallTypeApi {} + impl TypeAbi for FungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, { + type Unmanaged = Self; + fn type_name() -> TypeName { TokenIdentifier::::type_name() } + fn type_name_rust() -> TypeName { + TokenIdentifier::::type_name_rust() + } + fn provide_type_descriptions(accumulator: &mut TDC) { TokenIdentifier::::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs b/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs index 11207c70a3..193c73bc68 100644 --- a/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs +++ b/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs @@ -1,8 +1,13 @@ use crate::{ + abi::TypeAbiFrom, codec::{ CodecFrom, EncodeErrorHandler, TopDecode, TopEncode, TopEncodeMulti, TopEncodeMultiOutput, }, storage_clear, storage_get, storage_set, + types::{ + system_proxy::ESDTSystemSCProxy, ESDTSystemSCAddress, EgldPayment, FunctionCall, + OriginalResultMarker, Tx, TxScEnv, + }, }; use super::{ @@ -15,20 +20,28 @@ use crate::{ abi::{TypeAbi, TypeName}, api::{CallTypeApi, ErrorApiImpl, StorageMapperApi}, contract_base::{BlockchainWrapper, SendWrapper}, - esdt::{ - ESDTSystemSmartContractProxy, MetaTokenProperties, NonFungibleTokenProperties, - SemiFungibleTokenProperties, - }, storage::StorageKey, types::{ - BigUint, CallbackClosure, ContractCall, ContractCallWithEgld, EsdtTokenData, - EsdtTokenPayment, EsdtTokenType, ManagedAddress, ManagedBuffer, ManagedType, - TokenIdentifier, + system_proxy::{ + MetaTokenProperties, NonFungibleTokenProperties, SemiFungibleTokenProperties, + }, + BigUint, CallbackClosure, EsdtTokenData, EsdtTokenPayment, EsdtTokenType, ManagedAddress, + ManagedBuffer, ManagedType, TokenIdentifier, }, }; const INVALID_TOKEN_TYPE_ERR_MSG: &[u8] = b"Invalid token type for NonFungible issue"; +pub type IssueCallTo = Tx< + TxScEnv, + (), + ESDTSystemSCAddress, + EgldPayment, + (), + FunctionCall, + OriginalResultMarker>, +>; + pub struct NonFungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, @@ -173,14 +186,15 @@ where SA::error_api_impl().signal_error(INVALID_TOKEN_TYPE_ERR_MSG); } - let system_sc_proxy = ESDTSystemSmartContractProxy::::new_proxy_obj(); let callback = match opt_callback { Some(cb) => cb, None => self.default_callback_closure_obj(), }; storage_set(self.get_storage_key(), &TokenMapperState::::Pending); - system_sc_proxy + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) .issue_and_set_all_roles( issue_cost, token_display_name, @@ -189,8 +203,8 @@ where num_decimals, ) .async_call() - .with_callback(callback) - .call_and_exit(); + .callback(callback) + .call_and_exit() } pub fn clear(&mut self) { @@ -215,28 +229,32 @@ where issue_cost: BigUint, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer, - ) -> ContractCallWithEgld { - let system_sc_proxy = ESDTSystemSmartContractProxy::::new_proxy_obj(); - system_sc_proxy.issue_non_fungible( - issue_cost, - &token_display_name, - &token_ticker, - NonFungibleTokenProperties::default(), - ) + ) -> IssueCallTo { + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) + .issue_non_fungible( + issue_cost, + &token_display_name, + &token_ticker, + NonFungibleTokenProperties::default(), + ) } fn sft_issue( issue_cost: BigUint, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer, - ) -> ContractCallWithEgld { - let system_sc_proxy = ESDTSystemSmartContractProxy::::new_proxy_obj(); - system_sc_proxy.issue_semi_fungible( - issue_cost, - &token_display_name, - &token_ticker, - SemiFungibleTokenProperties::default(), - ) + ) -> IssueCallTo { + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) + .issue_semi_fungible( + issue_cost, + &token_display_name, + &token_ticker, + SemiFungibleTokenProperties::default(), + ) } fn meta_issue( @@ -244,19 +262,16 @@ where token_display_name: ManagedBuffer, token_ticker: ManagedBuffer, num_decimals: usize, - ) -> ContractCallWithEgld { - let system_sc_proxy = ESDTSystemSmartContractProxy::::new_proxy_obj(); + ) -> IssueCallTo { let properties = MetaTokenProperties { num_decimals, ..Default::default() }; - system_sc_proxy.register_meta_esdt( - issue_cost, - &token_display_name, - &token_ticker, - properties, - ) + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) + .register_meta_esdt(issue_cost, &token_display_name, &token_ticker, properties) } pub fn nft_create( @@ -368,13 +383,14 @@ where } fn send_payment(&self, to: &ManagedAddress, payment: &EsdtTokenPayment) { - let send_wrapper = SendWrapper::::new(); - send_wrapper.direct_esdt( - to, - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); + Tx::new_tx_from_sc() + .to(to) + .single_esdt( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ) + .transfer(); } } @@ -400,14 +416,27 @@ impl CodecFrom> for TokenIdentifier where { } +impl TypeAbiFrom> for TokenIdentifier where + SA: StorageMapperApi + CallTypeApi +{ +} + +impl TypeAbiFrom for NonFungibleTokenMapper where SA: StorageMapperApi + CallTypeApi {} + impl TypeAbi for NonFungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, { + type Unmanaged = Self; + fn type_name() -> TypeName { TokenIdentifier::::type_name() } + fn type_name_rust() -> TypeName { + TokenIdentifier::::type_name_rust() + } + fn provide_type_descriptions(accumulator: &mut TDC) { TokenIdentifier::::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/storage/mappers/token/token_mapper.rs b/framework/base/src/storage/mappers/token/token_mapper.rs index e0867f7414..d9d923c2f8 100644 --- a/framework/base/src/storage/mappers/token/token_mapper.rs +++ b/framework/base/src/storage/mappers/token/token_mapper.rs @@ -1,12 +1,11 @@ use crate::{ api::{CallTypeApi, ErrorApiImpl, StorageMapperApi}, contract_base::BlockchainWrapper, - esdt::ESDTSystemSmartContractProxy, storage::StorageKey, storage_get, storage_get_len, storage_set, types::{ - CallbackClosure, ContractCall, EsdtLocalRole, EsdtTokenPayment, ManagedAddress, ManagedRef, - ManagedVec, TokenIdentifier, + system_proxy::ESDTSystemSCProxy, CallbackClosure, ESDTSystemSCAddress, EsdtLocalRole, + EsdtTokenPayment, ManagedAddress, ManagedRef, ManagedVec, TokenIdentifier, Tx, }, }; @@ -81,17 +80,13 @@ where ) -> ! { self.require_issued_or_set(); - let system_sc_proxy = ESDTSystemSmartContractProxy::::new_proxy_obj(); let token_id = self.get_token_id_ref(); - let mut async_call = system_sc_proxy + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) .set_special_roles(address, token_id, roles[..].iter().cloned()) - .async_call(); - - if let Some(cb) = opt_callback { - async_call = async_call.with_callback(cb); - } - - async_call.call_and_exit() + .callback(opt_callback) + .call_and_exit() } fn get_sc_address() -> ManagedAddress { diff --git a/framework/base/src/storage/mappers/unique_id_mapper.rs b/framework/base/src/storage/mappers/unique_id_mapper.rs index 779e1a1b71..4eb3a7d638 100644 --- a/framework/base/src/storage/mappers/unique_id_mapper.rs +++ b/framework/base/src/storage/mappers/unique_id_mapper.rs @@ -1,4 +1,5 @@ use crate::{ + abi::TypeAbiFrom, codec::{ multi_encode_iter_or_handle_err, CodecFrom, EncodeErrorHandler, TopEncodeMulti, TopEncodeMultiOutput, @@ -218,15 +219,28 @@ impl CodecFrom> for MultiValueEncoded TypeAbiFrom> for MultiValueEncoded where + SA: StorageMapperApi +{ +} + +impl TypeAbiFrom for UniqueIdMapper where SA: StorageMapperApi {} + /// Behaves like a MultiResultVec when an endpoint result. impl TypeAbi for UniqueIdMapper where SA: StorageMapperApi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::() + } + fn provide_type_descriptions(accumulator: &mut TDC) { usize::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/storage/mappers/unordered_set_mapper.rs b/framework/base/src/storage/mappers/unordered_set_mapper.rs index fa151759ea..2b0cf7cac1 100644 --- a/framework/base/src/storage/mappers/unordered_set_mapper.rs +++ b/framework/base/src/storage/mappers/unordered_set_mapper.rs @@ -6,7 +6,7 @@ use super::{ StorageClearable, StorageMapper, VecMapper, }; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::StorageMapperApi, codec::{ multi_encode_iter_or_handle_err, CodecFrom, EncodeErrorHandler, NestedDecode, NestedEncode, @@ -232,16 +232,36 @@ where { } +impl TypeAbiFrom> for MultiValueEncoded +where + SA: StorageMapperApi, + T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static, +{ +} + +impl TypeAbiFrom for UnorderedSetMapper +where + SA: StorageMapperApi, + T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static, +{ +} + /// Behaves like a MultiResultVec when an endpoint result. impl TypeAbi for UnorderedSetMapper where SA: StorageMapperApi, T: TopEncode + TopDecode + NestedEncode + NestedDecode + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/storage/mappers/user_mapper.rs b/framework/base/src/storage/mappers/user_mapper.rs index bbfdcfb27b..6d511fe567 100644 --- a/framework/base/src/storage/mappers/user_mapper.rs +++ b/framework/base/src/storage/mappers/user_mapper.rs @@ -1,8 +1,11 @@ use core::marker::PhantomData; -use crate::codec::{ - multi_encode_iter_or_handle_err, CodecFrom, EncodeErrorHandler, TopEncodeMulti, - TopEncodeMultiOutput, +use crate::{ + abi::TypeAbiFrom, + codec::{ + multi_encode_iter_or_handle_err, CodecFrom, EncodeErrorHandler, TopEncodeMulti, + TopEncodeMultiOutput, + }, }; use super::{ @@ -224,15 +227,28 @@ impl CodecFrom> for MultiValueEncoded TypeAbiFrom> for MultiValueEncoded> where + SA: StorageMapperApi +{ +} + +impl TypeAbiFrom for UserMapper where SA: StorageMapperApi {} + /// Behaves like a MultiResultVec when an endpoint result. impl TypeAbi for UserMapper where SA: StorageMapperApi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::>() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::>() + } + fn is_variadic() -> bool { true } diff --git a/framework/base/src/storage/mappers/vec_mapper.rs b/framework/base/src/storage/mappers/vec_mapper.rs index cc4db40e29..5bde908ee2 100644 --- a/framework/base/src/storage/mappers/vec_mapper.rs +++ b/framework/base/src/storage/mappers/vec_mapper.rs @@ -3,7 +3,7 @@ use super::{ StorageClearable, StorageMapper, }; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::{ErrorApiImpl, StorageMapperApi}, codec::{ multi_encode_iter_or_handle_err, CodecFrom, EncodeErrorHandler, TopDecode, TopEncode, @@ -351,16 +351,36 @@ where { } +impl TypeAbiFrom> for MultiValueEncoded +where + SA: StorageMapperApi, + T: TopEncode + TopDecode, +{ +} + +impl TypeAbiFrom for VecMapper +where + SA: StorageMapperApi, + T: TopEncode + TopDecode, +{ +} + /// Behaves like a MultiResultVec when an endpoint result. impl TypeAbi for VecMapper where SA: StorageMapperApi, T: TopEncode + TopDecode + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/tuple_util.rs b/framework/base/src/tuple_util.rs new file mode 100644 index 0000000000..717058e641 --- /dev/null +++ b/framework/base/src/tuple_util.rs @@ -0,0 +1,3 @@ +mod nested_tuples; + +pub use nested_tuples::*; diff --git a/framework/base/src/tuple_util/nested_tuples.rs b/framework/base/src/tuple_util/nested_tuples.rs new file mode 100644 index 0000000000..a6dda04391 --- /dev/null +++ b/framework/base/src/tuple_util/nested_tuples.rs @@ -0,0 +1,137 @@ +/// A tuple of the form (A, (B, (... (N, ())))). +/// +/// It is always terminated with a unit. +pub trait NestedTuple {} + +impl NestedTuple for () {} + +impl NestedTuple for (Head, Tail) where Tail: NestedTuple {} + +/// Allows to append at the end of a nested tuple list. +pub trait NestedTupleAppend { + type Output; + + fn append(self, t: T) -> Self::Output; +} + +impl NestedTupleAppend for () { + type Output = (T, ()); + + fn append(self, t: T) -> Self::Output { + (t, ()) + } +} + +impl NestedTupleAppend for (Head, Tail) +where + Tail: NestedTupleAppend, +{ + type Output = (Head, Tail::Output); + + fn append(self, t: T) -> Self::Output { + (self.0, self.1.append(t)) + } +} + +/// Defines conversion of a nested tuple list to a regular tuple. +pub trait NestedTupleFlatten: NestedTuple { + type Flattened; + type Unpacked; + + /// Converts a nested tuple list to a regular tuple. + fn flatten(self) -> Self::Flattened; + + /// Same as `flatten`, converts a nested tuple list to a regular tuple, + /// but additionally, it unpacks singleton tuples into their content (`(item,)` -> `item`). + fn flatten_unpack(self) -> Self::Unpacked; +} + +impl NestedTupleFlatten for () { + type Flattened = (); + type Unpacked = (); + + fn flatten(self) -> Self::Flattened {} + fn flatten_unpack(self) -> Self::Unpacked {} +} + +impl NestedTupleFlatten for (T, ()) { + type Flattened = (T,); + type Unpacked = T; + + fn flatten(self) -> Self::Flattened { + (self.0,) + } + + fn flatten_unpack(self) -> Self::Unpacked { + self.0 + } +} + +macro_rules! tuple_list_type { + () => ( () ); + ($i:ty) => ( ($i, ()) ); + ($i:ty, $($e:ty),*) => ( ($i, tuple_list_type!($($e),*)) ); +} + +macro_rules! unnest { + (($layer:expr); ($($v:expr),*); ($u:ident, $($us:ident,)*)) => { + unnest!(($layer . 1); ($($v,)* $layer . 0); ($($us,)*)) + }; + (($layer:expr); ($($v:expr),*); ()) => { ($($v,)*) }; +} + +macro_rules! flatten_impl { + ($(($t:ident $($ts:ident)+))+) => { + $( + impl<$t,$($ts),+> NestedTupleFlatten for tuple_list_type!($t,$($ts),+) { + type Flattened = ($t,$($ts),+); + type Unpacked = ($t,$($ts),+); + + fn flatten(self) -> Self::Flattened { + unnest!((self); (); ($t, $($ts,)*)) + } + + fn flatten_unpack(self) -> Self::Unpacked { + self.flatten() + } + } + )+ + } +} + +flatten_impl! { + (T1 T2) + (T1 T2 T3) + (T1 T2 T3 T4) + (T1 T2 T3 T4 T5) + (T1 T2 T3 T4 T5 T6) + (T1 T2 T3 T4 T5 T6 T7) + (T1 T2 T3 T4 T5 T6 T7 T8) + (T1 T2 T3 T4 T5 T6 T7 T8 T9) + (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10) + (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11) + (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12) + (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13) + (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14) + (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15) + (T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_flatten() { + let flat2 = (1, (2, ())).flatten(); + assert_eq!(flat2, (1, 2)); + + let n3 = (1u8, (2u16, (3u32, ()))); + let flat3 = n3.flatten(); + assert_eq!(flat3, (1u8, 2u16, 3u32)); + + let n4 = n3.append(4u64); + let flat4 = n4.flatten(); + assert_eq!(flat4, (1u8, 2u16, 3u32, 4u64)); + } +} diff --git a/framework/base/src/types/crypto/message_hash_type.rs b/framework/base/src/types/crypto/message_hash_type.rs index 18d3f384fe..209887fdfc 100644 --- a/framework/base/src/types/crypto/message_hash_type.rs +++ b/framework/base/src/types/crypto/message_hash_type.rs @@ -1,7 +1,9 @@ use crate::{ - abi::{TypeAbi, TypeName}, - codec, - codec::derive::{NestedDecode, NestedEncode, TopDecode, TopEncode}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, + codec::{ + self, + derive::{NestedDecode, NestedEncode, TopDecode, TopEncode}, + }, }; /// Message hash type for the `verifyCustomSecp256k1` CryptoApi function @@ -38,7 +40,11 @@ impl From for MessageHashType { } } +impl TypeAbiFrom for MessageHashType {} + impl TypeAbi for MessageHashType { + type Unmanaged = Self; + fn type_name() -> TypeName { "MessageHashType".into() } diff --git a/framework/base/src/types/flags/code_metadata.rs b/framework/base/src/types/flags/code_metadata.rs index 89df4b91de..9275e976cf 100644 --- a/framework/base/src/types/flags/code_metadata.rs +++ b/framework/base/src/types/flags/code_metadata.rs @@ -1,7 +1,7 @@ #![allow(clippy::bad_bit_mask)] use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, codec::*, formatter::{hex_util, FormatByteReceiver, SCBinary, SCDisplay, SCLowerHex}, }; @@ -103,10 +103,18 @@ impl TopDecode for CodeMetadata { } } +impl TypeAbiFrom for CodeMetadata {} + impl TypeAbi for CodeMetadata { + type Unmanaged = Self; + fn type_name() -> TypeName { "CodeMetadata".into() } + + fn type_name_rust() -> TypeName { + "CodeMetadata".into() + } } impl SCDisplay for CodeMetadata { diff --git a/framework/base/src/types/flags/esdt_local_role.rs b/framework/base/src/types/flags/esdt_local_role.rs index f0f241d931..9bc5edfc68 100644 --- a/framework/base/src/types/flags/esdt_local_role.rs +++ b/framework/base/src/types/flags/esdt_local_role.rs @@ -5,7 +5,7 @@ use crate::{ use super::EsdtLocalRoleFlags; use crate as multiversx_sc; -use crate::{derive::TypeAbi, types::ManagedVecItem}; +use crate::{derive::type_abi, types::ManagedVecItem}; static ESDT_ROLE_NONE: &[u8] = &[]; static ESDT_ROLE_LOCAL_MINT: &[u8] = b"ESDTRoleLocalMint"; @@ -17,9 +17,8 @@ static ESDT_ROLE_NFT_ADD_URI: &[u8] = b"ESDTRoleNFTAddURI"; static ESDT_ROLE_NFT_UPDATE_ATTRIBUTES: &[u8] = b"ESDTRoleNFTUpdateAttributes"; static ESDT_ROLE_TRANSFER: &[u8] = b"ESDTTransferRole"; -#[derive( - TopDecode, TopEncode, NestedDecode, NestedEncode, TypeAbi, Clone, PartialEq, Eq, Debug, Copy, -)] +#[type_abi] +#[derive(TopDecode, TopEncode, NestedDecode, NestedEncode, Clone, PartialEq, Eq, Debug, Copy)] pub enum EsdtLocalRole { None, Mint, diff --git a/framework/base/src/types/flags/esdt_token_type.rs b/framework/base/src/types/flags/esdt_token_type.rs index 2348254455..e80b91590d 100644 --- a/framework/base/src/types/flags/esdt_token_type.rs +++ b/framework/base/src/types/flags/esdt_token_type.rs @@ -1,6 +1,9 @@ -use multiversx_sc_derive::ManagedVecItem; +use multiversx_sc_derive::{type_abi, ManagedVecItem}; -use crate::codec::*; +use crate::codec::{ + self, + derive::{NestedDecode, NestedEncode, TopDecode, TopEncode}, +}; const ESDT_TYPE_FUNGIBLE: &[u8] = b"FungibleESDT"; const ESDT_TYPE_NON_FUNGIBLE: &[u8] = b"NonFungibleESDT"; @@ -9,10 +12,13 @@ const ESDT_TYPE_META: &[u8] = b"MetaESDT"; const ESDT_TYPE_INVALID: &[u8] = &[]; use crate as multiversx_sc; // needed by the TypeAbi generated code -use crate::derive::TypeAbi; // Note: In the current implementation, SemiFungible is never returned -#[derive(Clone, PartialEq, Eq, Debug, TypeAbi, ManagedVecItem)] + +#[type_abi] +#[derive( + TopDecode, TopEncode, NestedDecode, NestedEncode, Clone, PartialEq, Eq, Debug, ManagedVecItem, +)] pub enum EsdtTokenType { Fungible, NonFungible, @@ -80,45 +86,3 @@ impl<'a> From<&'a [u8]> for EsdtTokenType { } } } - -impl NestedEncode for EsdtTokenType { - #[inline] - fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> - where - O: NestedEncodeOutput, - H: EncodeErrorHandler, - { - self.as_u8().dep_encode_or_handle_err(dest, h) - } -} - -impl TopEncode for EsdtTokenType { - #[inline] - fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> - where - O: TopEncodeOutput, - H: EncodeErrorHandler, - { - self.as_u8().top_encode_or_handle_err(output, h) - } -} - -impl NestedDecode for EsdtTokenType { - fn dep_decode_or_handle_err(input: &mut I, h: H) -> Result - where - I: NestedDecodeInput, - H: DecodeErrorHandler, - { - Ok(Self::from(u8::dep_decode_or_handle_err(input, h)?)) - } -} - -impl TopDecode for EsdtTokenType { - fn top_decode_or_handle_err(input: I, h: H) -> Result - where - I: TopDecodeInput, - H: DecodeErrorHandler, - { - Ok(Self::from(u8::top_decode_or_handle_err(input, h)?)) - } -} diff --git a/framework/base/src/types/heap/async_call_result.rs b/framework/base/src/types/heap/async_call_result.rs index 4084c83bc7..ab738cba71 100644 --- a/framework/base/src/types/heap/async_call_result.rs +++ b/framework/base/src/types/heap/async_call_result.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, codec::{ DecodeErrorHandler, EncodeErrorHandler, TopDecodeMulti, TopDecodeMultiInput, TopEncodeMulti, TopEncodeMultiOutput, @@ -82,7 +82,11 @@ where } } +impl TypeAbiFrom for AsyncCallResult {} + impl TypeAbi for AsyncCallResult { + type Unmanaged = Self; + fn type_name() -> TypeName { let mut repr = TypeName::from("AsyncCallResult<"); repr.push_str(T::type_name().as_str()); diff --git a/framework/base/src/types/heap/boxed_bytes.rs b/framework/base/src/types/heap/boxed_bytes.rs index 24c08d1199..338af818c2 100644 --- a/framework/base/src/types/heap/boxed_bytes.rs +++ b/framework/base/src/types/heap/boxed_bytes.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, codec::*, }; use alloc::{ @@ -240,10 +240,18 @@ impl TopDecode for BoxedBytes { } } +impl TypeAbiFrom for BoxedBytes {} + impl TypeAbi for BoxedBytes { + type Unmanaged = Self; + fn type_name() -> TypeName { "bytes".into() } + + fn type_name_rust() -> TypeName { + "BoxedBytes".into() + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/framework/base/src/types/heap/h256.rs b/framework/base/src/types/heap/h256.rs index 5dd0a2786b..f440765d00 100644 --- a/framework/base/src/types/heap/h256.rs +++ b/framework/base/src/types/heap/h256.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, types::heap::BoxedBytes, }; use alloc::{boxed::Box, vec::Vec}; @@ -224,10 +224,18 @@ impl TopDecode for H256 { } } +impl TypeAbiFrom for H256 {} + impl TypeAbi for H256 { + type Unmanaged = Self; + fn type_name() -> TypeName { "H256".into() } + + fn type_name_rust() -> TypeName { + "H256".into() + } } #[cfg(test)] diff --git a/framework/base/src/types/heap/h256_address.rs b/framework/base/src/types/heap/h256_address.rs index e4c9b055d2..a9fa69c2e7 100644 --- a/framework/base/src/types/heap/h256_address.rs +++ b/framework/base/src/types/heap/h256_address.rs @@ -1,6 +1,6 @@ use super::h256::H256; use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, types::heap::BoxedBytes, }; use alloc::{boxed::Box, vec::Vec}; @@ -202,10 +202,18 @@ impl TopDecode for Address { } } +impl TypeAbiFrom for Address {} + impl TypeAbi for Address { + type Unmanaged = Self; + fn type_name() -> TypeName { "Address".into() } + + fn type_name_rust() -> TypeName { + "Address".into() + } } #[cfg(test)] diff --git a/framework/base/src/types/heap/queue.rs b/framework/base/src/types/heap/queue.rs index 1c32848acf..cbb0b03d58 100644 --- a/framework/base/src/types/heap/queue.rs +++ b/framework/base/src/types/heap/queue.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, codec::*, }; use alloc::vec::Vec; @@ -136,7 +136,11 @@ impl TopDecode for Queue { } } +impl TypeAbiFrom for Queue {} + impl TypeAbi for Queue { + type Unmanaged = Self; + fn type_name() -> TypeName { let mut repr = TypeName::from("Queue<"); repr.push_str(T::type_name().as_str()); diff --git a/framework/base/src/types/interaction.rs b/framework/base/src/types/interaction.rs new file mode 100644 index 0000000000..710b482b8c --- /dev/null +++ b/framework/base/src/types/interaction.rs @@ -0,0 +1,46 @@ +mod annotated; +mod back_transfers; +mod callback_closure; +mod callback_selector_result; +mod contract_call_legacy; +mod expr; +mod managed_arg_buffer; +mod markers; +mod result_handlers; +pub mod system_proxy; +mod tx; +mod tx_data; +mod tx_env; +mod tx_exec; +mod tx_from; +mod tx_gas; +mod tx_payment; +mod tx_proxy; +mod tx_result_handler; +mod tx_result_handler_list; +mod tx_to; + +pub use annotated::*; +pub use back_transfers::BackTransfers; +pub use callback_closure::{ + new_callback_call, CallbackClosure, CallbackClosureForDeser, CallbackClosureMatcher, +}; +pub use callback_selector_result::CallbackSelectorResult; +pub use contract_call_legacy::*; +pub use expr::*; +pub use managed_arg_buffer::ManagedArgBuffer; +pub use markers::*; +pub use result_handlers::*; +pub use tx::*; +pub use tx_data::*; +pub use tx_env::*; +pub use tx_exec::*; +pub use tx_from::*; +pub use tx_gas::*; +pub use tx_payment::*; +pub use tx_proxy::*; +pub use tx_result_handler::{TxEmptyResultHandler, TxResultHandler}; +pub use tx_result_handler_list::*; +pub use tx_to::*; + +pub type TxScBase = TxBaseWithEnv>; diff --git a/framework/base/src/types/interaction/annotated.rs b/framework/base/src/types/interaction/annotated.rs new file mode 100644 index 0000000000..315994e66e --- /dev/null +++ b/framework/base/src/types/interaction/annotated.rs @@ -0,0 +1,53 @@ +mod annotated_impl_big_uint; +mod annotated_impl_managed_address; +mod annotated_impl_managed_buffer; +mod annotated_impl_token_identifier; +mod annotated_impl_u64; + +use crate::{ + api::ManagedTypeApi, + formatter::FormatBuffer, + types::{ManagedBuffer, ManagedBufferCachedBuilder}, +}; + +use super::TxEnv; + +/// Describes a value can also have a custom representation in a mandos scenario. +/// +/// It is based on managed types in order to be embedded into parametric tests too. +pub trait AnnotatedValue: Sized +where + Env: TxEnv, +{ + fn annotation(&self, env: &Env) -> ManagedBuffer; + + /// Produces the value from a reference of the annotated type. Might involve a `.clone()` in some cases. + fn to_value(&self, env: &Env) -> T; + + /// Consumes annotated value to produce actual value. + /// + /// Override whenever it helps to avoid an unnecessary clone. + fn into_value(self, env: &Env) -> T { + self.to_value(env) + } + + /// Can be used when working with references only. + /// + /// Override whenever it helps to avoid an unnecessary clone. + fn with_value_ref(&self, env: &Env, f: F) -> R + where + F: FnOnce(&T) -> R, + { + f(&self.to_value(env)) + } +} + +/// Useful for u64 display in several places. +pub(super) fn display_u64(n: u64) -> ManagedBuffer +where + Api: ManagedTypeApi, +{ + let mut result = ManagedBufferCachedBuilder::new_from_slice(&[]); + result.append_display(&n); + result.into_managed_buffer() +} diff --git a/framework/base/src/types/interaction/annotated/annotated_impl_big_uint.rs b/framework/base/src/types/interaction/annotated/annotated_impl_big_uint.rs new file mode 100644 index 0000000000..685af7fdb3 --- /dev/null +++ b/framework/base/src/types/interaction/annotated/annotated_impl_big_uint.rs @@ -0,0 +1,114 @@ +use crate::types::{BigUint, ManagedBuffer, ManagedRef}; + +use super::{AnnotatedValue, TxEnv}; + +impl AnnotatedValue> for BigUint +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.to_display() + } + + fn to_value(&self, _env: &Env) -> BigUint { + self.clone() + } + + fn into_value(self, _env: &Env) -> BigUint { + self + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&BigUint) -> R, + { + f(self) + } +} + +impl AnnotatedValue> for &BigUint +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.to_display() + } + + fn to_value(&self, _env: &Env) -> BigUint { + (*self).clone() + } + + fn into_value(self, _env: &Env) -> BigUint { + self.clone() + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&BigUint) -> R, + { + f(self) + } +} + +impl<'a, Env> AnnotatedValue> for ManagedRef<'a, Env::Api, BigUint> +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.to_display() + } + + fn to_value(&self, _env: &Env) -> BigUint { + (*self).clone_value() + } + + fn into_value(self, _env: &Env) -> BigUint { + self.clone_value() + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&BigUint) -> R, + { + f(self) + } +} + +impl AnnotatedValue> for u64 +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + BigUint::from(*self).to_display() + } + + fn to_value(&self, _env: &Env) -> BigUint { + BigUint::from(*self) + } +} + +impl AnnotatedValue> for i32 +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + BigUint::from(*self as u64).to_display() + } + + fn to_value(&self, _env: &Env) -> BigUint { + BigUint::from(*self as u64) + } +} + +impl AnnotatedValue> for () +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + ManagedBuffer::from("0") + } + + fn to_value(&self, _env: &Env) -> BigUint { + BigUint::zero() + } +} diff --git a/framework/base/src/types/interaction/annotated/annotated_impl_managed_address.rs b/framework/base/src/types/interaction/annotated/annotated_impl_managed_address.rs new file mode 100644 index 0000000000..403ccf4603 --- /dev/null +++ b/framework/base/src/types/interaction/annotated/annotated_impl_managed_address.rs @@ -0,0 +1,77 @@ +use crate::types::{heap::Address, ManagedAddress, ManagedBuffer}; + +use super::{AnnotatedValue, TxEnv}; + +impl AnnotatedValue> for ManagedAddress +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.hex_expr() + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + self.clone() + } + + fn into_value(self, _env: &Env) -> ManagedAddress { + self + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&ManagedAddress) -> R, + { + f(self) + } +} + +impl AnnotatedValue> for &ManagedAddress +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.hex_expr() + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + (*self).clone() + } + + fn into_value(self, _env: &Env) -> ManagedAddress { + self.clone() + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&ManagedAddress) -> R, + { + f(self) + } +} + +impl AnnotatedValue> for Address +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + ManagedAddress::from(self).hex_expr() + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + ManagedAddress::from(self) + } +} + +impl AnnotatedValue> for &Address +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + ManagedAddress::from(*self).hex_expr() + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + ManagedAddress::from(*self) + } +} diff --git a/framework/base/src/types/interaction/annotated/annotated_impl_managed_buffer.rs b/framework/base/src/types/interaction/annotated/annotated_impl_managed_buffer.rs new file mode 100644 index 0000000000..547e88fefb --- /dev/null +++ b/framework/base/src/types/interaction/annotated/annotated_impl_managed_buffer.rs @@ -0,0 +1,40 @@ +use crate::types::ManagedBuffer; + +use super::{AnnotatedValue, TxEnv}; + +impl AnnotatedValue> for ManagedBuffer +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.hex_expr() + } + + fn to_value(&self, _env: &Env) -> ManagedBuffer { + self.clone() + } + + fn into_value(self, _env: &Env) -> ManagedBuffer { + self + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&ManagedBuffer) -> R, + { + f(self) + } +} + +impl AnnotatedValue> for () +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + ManagedBuffer::new() + } + + fn to_value(&self, _env: &Env) -> ManagedBuffer { + ManagedBuffer::new() + } +} diff --git a/framework/base/src/types/interaction/annotated/annotated_impl_token_identifier.rs b/framework/base/src/types/interaction/annotated/annotated_impl_token_identifier.rs new file mode 100644 index 0000000000..c689024632 --- /dev/null +++ b/framework/base/src/types/interaction/annotated/annotated_impl_token_identifier.rs @@ -0,0 +1,56 @@ +use crate::{ + proxy_imports::ManagedBufferBuilder, + types::{ManagedBuffer, TokenIdentifier}, +}; + +use super::{AnnotatedValue, TxEnv}; + +impl AnnotatedValue> for TokenIdentifier +where + Env: TxEnv, +{ + fn annotation(&self, env: &Env) -> ManagedBuffer { + (&self).annotation(env) + } + + fn to_value(&self, _env: &Env) -> TokenIdentifier { + self.clone() + } + + fn into_value(self, _env: &Env) -> TokenIdentifier { + self + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&TokenIdentifier) -> R, + { + f(self) + } +} + +impl AnnotatedValue> for &TokenIdentifier +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + let mut annot = ManagedBufferBuilder::::new_from_slice("str:".as_bytes()); + annot.append_managed_buffer(self.as_managed_buffer()); + annot.into_managed_buffer() + } + + fn to_value(&self, _env: &Env) -> TokenIdentifier { + (*self).clone() + } + + fn into_value(self, _env: &Env) -> TokenIdentifier { + (*self).clone() + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&TokenIdentifier) -> R, + { + f(self) + } +} diff --git a/framework/base/src/types/interaction/annotated/annotated_impl_u64.rs b/framework/base/src/types/interaction/annotated/annotated_impl_u64.rs new file mode 100644 index 0000000000..ed310d1f43 --- /dev/null +++ b/framework/base/src/types/interaction/annotated/annotated_impl_u64.rs @@ -0,0 +1,29 @@ +use crate::types::ManagedBuffer; + +use super::{display_u64, AnnotatedValue, TxEnv}; + +impl AnnotatedValue for u64 +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + display_u64(*self) + } + + fn to_value(&self, _env: &Env) -> u64 { + *self + } +} + +impl AnnotatedValue for i32 +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + display_u64(*self as u64) + } + + fn to_value(&self, _env: &Env) -> u64 { + *self as u64 + } +} diff --git a/framework/base/src/types/interaction/async_call.rs b/framework/base/src/types/interaction/async_call.rs deleted file mode 100644 index 9c5554baba..0000000000 --- a/framework/base/src/types/interaction/async_call.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::{ - api::{CallTypeApi, StorageWriteApi}, - contract_base::SendRawWrapper, - types::{BigUint, CallbackClosure, ManagedAddress}, -}; - -use super::FunctionCall; - -#[must_use] -pub struct AsyncCall -where - SA: CallTypeApi + 'static, -{ - pub(crate) to: ManagedAddress, - pub(crate) egld_payment: BigUint, - pub(crate) function_call: FunctionCall, - pub(crate) callback_call: Option>, -} - -#[allow(clippy::return_self_not_must_use)] -impl AsyncCall -where - SA: CallTypeApi, -{ - pub fn with_callback(self, callback_call: CallbackClosure) -> Self { - AsyncCall { - callback_call: Some(callback_call), - ..self - } - } -} - -impl AsyncCall -where - SA: CallTypeApi, -{ - pub fn call_and_exit_ignore_callback(&self) -> ! { - SendRawWrapper::::new().async_call_raw( - &self.to, - &self.egld_payment, - &self.function_call.function_name, - &self.function_call.arg_buffer, - ) - } -} - -impl AsyncCall -where - SA: CallTypeApi + StorageWriteApi, -{ - pub fn call_and_exit(&self) -> ! { - // first, save the callback closure - if let Some(callback_call) = &self.callback_call { - callback_call.save_to_storage::(); - } - - // last, send the async call, which will kill the execution - self.call_and_exit_ignore_callback() - } -} diff --git a/framework/base/src/types/interaction/callback_closure.rs b/framework/base/src/types/interaction/callback_closure.rs index 98b6fece64..a8884695f7 100644 --- a/framework/base/src/types/interaction/callback_closure.rs +++ b/framework/base/src/types/interaction/callback_closure.rs @@ -28,11 +28,22 @@ pub const CALLBACK_CLOSURE_STORAGE_BASE_KEY: &[u8] = b"CB_CLOSURE"; /// /// In both cases the framework hides all the magic, the developer shouldn't worry about it. #[derive(TopEncode)] -pub struct CallbackClosure { +pub struct CallbackClosure +where + M: ManagedTypeApi + ErrorApi, +{ pub(super) callback_name: &'static str, pub(super) closure_args: ManagedArgBuffer, } +pub struct CallbackClosureWithGas +where + M: ManagedTypeApi + ErrorApi, +{ + pub(super) closure: CallbackClosure, + pub(super) gas_for_callback: u64, +} + /// Syntactical sugar to help macros to generate code easier. /// Unlike calling `CallbackClosure::::new`, here types can be inferred from the context. pub fn new_callback_call(callback_name: &'static str) -> CallbackClosure diff --git a/framework/base/src/types/interaction/mod.rs b/framework/base/src/types/interaction/contract_call_legacy.rs similarity index 63% rename from framework/base/src/types/interaction/mod.rs rename to framework/base/src/types/interaction/contract_call_legacy.rs index 3de007ee79..8532f6de09 100644 --- a/framework/base/src/types/interaction/mod.rs +++ b/framework/base/src/types/interaction/contract_call_legacy.rs @@ -1,8 +1,5 @@ mod async_call; mod async_call_promises; -mod back_transfers; -mod callback_closure; -mod callback_selector_result; mod contract_call_convert; mod contract_call_exec; mod contract_call_no_payment; @@ -12,22 +9,20 @@ mod contract_call_with_egld; mod contract_call_with_egld_or_single_esdt; mod contract_call_with_multi_esdt; mod contract_deploy; -mod function_call; -mod managed_arg_buffer; +mod typed_function_call; pub use async_call::AsyncCall; pub use async_call_promises::AsyncCallPromises; -pub use back_transfers::BackTransfers; -pub use callback_closure::{ - new_callback_call, CallbackClosure, CallbackClosureForDeser, CallbackClosureMatcher, -}; -pub use callback_selector_result::CallbackSelectorResult; pub use contract_call_no_payment::ContractCallNoPayment; -pub use contract_call_trait::ContractCall; +pub use contract_call_trait::{ContractCall, ContractCallBase}; pub use contract_call_with_any_payment::ContractCallWithAnyPayment; pub use contract_call_with_egld::ContractCallWithEgld; pub use contract_call_with_egld_or_single_esdt::ContractCallWithEgldOrSingleEsdt; pub use contract_call_with_multi_esdt::ContractCallWithMultiEsdt; pub use contract_deploy::{new_contract_deploy, ContractDeploy}; -pub use function_call::FunctionCall; -pub use managed_arg_buffer::ManagedArgBuffer; +pub use typed_function_call::TypedFunctionCall; + +/// Using max u64 to represent maximum possible gas, +/// so that the value zero is not reserved and can be specified explicitly. +/// Leaving the gas limit unspecified will replace it with `api.get_gas_left()`. +pub(crate) const UNSPECIFIED_GAS_LIMIT: u64 = u64::MAX; diff --git a/framework/base/src/types/interaction/contract_call_legacy/async_call.rs b/framework/base/src/types/interaction/contract_call_legacy/async_call.rs new file mode 100644 index 0000000000..05faf11c2d --- /dev/null +++ b/framework/base/src/types/interaction/contract_call_legacy/async_call.rs @@ -0,0 +1,39 @@ +use crate::{ + api::{CallTypeApi, StorageWriteApi}, + types::{CallbackClosure, EgldPayment, FunctionCall, ManagedAddress, Tx, TxScEnv}, +}; + +/// Kept as alias for backwards compatibility. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] +pub type AsyncCall = Tx< + TxScEnv, + (), + ManagedAddress, + EgldPayment, + (), + FunctionCall, + Option>, +>; + +#[allow(clippy::return_self_not_must_use)] +impl AsyncCall +where + Api: CallTypeApi, +{ + pub fn with_callback(mut self, callback_call: CallbackClosure) -> Self { + self.result_handler = Some(callback_call); + self + } +} + +impl AsyncCall +where + Api: CallTypeApi + StorageWriteApi, +{ + pub fn call_and_exit_ignore_callback(self) -> ! { + self.async_call_and_exit() + } +} diff --git a/framework/base/src/types/interaction/async_call_promises.rs b/framework/base/src/types/interaction/contract_call_legacy/async_call_promises.rs similarity index 91% rename from framework/base/src/types/interaction/async_call_promises.rs rename to framework/base/src/types/interaction/contract_call_legacy/async_call_promises.rs index ea03c0e777..ee3726c0eb 100644 --- a/framework/base/src/types/interaction/async_call_promises.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/async_call_promises.rs @@ -1,12 +1,14 @@ use crate::{ api::CallTypeApi, contract_base::SendRawWrapper, - types::{BigUint, CallbackClosure, ManagedAddress, ManagedBuffer}, + types::{BigUint, CallbackClosure, FunctionCall, ManagedAddress, ManagedBuffer}, }; -use super::FunctionCall; - /// Will be renamed to `AsyncCall` and `AsyncCall` to `AsyncCallLegacy` when the promises end up on the mainnet. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[must_use] pub struct AsyncCallPromises where diff --git a/framework/base/src/types/interaction/contract_call_convert.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_convert.rs similarity index 97% rename from framework/base/src/types/interaction/contract_call_convert.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_convert.rs index c7e4301c2c..fe4225d9a4 100644 --- a/framework/base/src/types/interaction/contract_call_convert.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_convert.rs @@ -38,7 +38,7 @@ where function_call: self .basic .function_call - .convert_to_single_transfer_fungible_call(payment), + .convert_to_single_transfer_fungible_call(payment.as_refs()), explicit_gas_limit: self.basic.explicit_gas_limit, _return_type: PhantomData, }, @@ -55,7 +55,7 @@ where function_call: self .basic .function_call - .convert_to_single_transfer_nft_call(&self.basic.to, payment), + .convert_to_single_transfer_nft_call(&self.basic.to, payment.as_refs()), explicit_gas_limit: self.basic.explicit_gas_limit, _return_type: PhantomData, }, @@ -78,7 +78,7 @@ where function_call: self .basic .function_call - .convert_to_multi_transfer_esdt_call(&self.basic.to, payments), + .convert_to_multi_transfer_esdt_call(&self.basic.to, &payments), explicit_gas_limit: self.basic.explicit_gas_limit, _return_type: PhantomData, }, diff --git a/framework/base/src/types/interaction/contract_call_exec.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_exec.rs similarity index 80% rename from framework/base/src/types/interaction/contract_call_exec.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_exec.rs index fd9994f2b0..427218f1c8 100644 --- a/framework/base/src/types/interaction/contract_call_exec.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_exec.rs @@ -1,29 +1,17 @@ use crate::{ - api::{use_raw_handle, StaticVarApiImpl}, + api::{use_raw_handle, BlockchainApiImpl, CallTypeApi, StaticVarApiImpl, StorageWriteApi}, codec::TopDecodeMulti, -}; - -use crate::{ - api::{BlockchainApiImpl, CallTypeApi}, contract_base::SendRawWrapper, formatter::SCLowerHex, - io::{ArgErrorHandler, ArgId, ManagedResultArgLoader}, types::{ - BigUint, EsdtTokenPayment, ManagedBuffer, ManagedBufferBuilder, ManagedType, ManagedVec, + decode_result, AsyncCall, AsyncCallPromises, BigUint, EsdtTokenPayment, ManagedBuffer, + ManagedBufferBuilder, ManagedType, ManagedVec, Tx, TRANSFER_EXECUTE_DEFAULT_LEFTOVER, }, }; -use super::{AsyncCall, ContractCallNoPayment, ContractCallWithEgld}; +use super::{ContractCallNoPayment, ContractCallWithEgld, UNSPECIFIED_GAS_LIMIT}; use crate::api::managed_types::handles::HandleConstraints; -/// Using max u64 to represent maximum possible gas, -/// so that the value zero is not reserved and can be specified explicitly. -/// Leaving the gas limit unspecified will replace it with `api.get_gas_left()`. -pub(super) const UNSPECIFIED_GAS_LIMIT: u64 = u64::MAX; - -/// In case of `transfer_execute`, we leave by default a little gas for the calling transaction to finish. -pub(super) const TRANSFER_EXECUTE_DEFAULT_LEFTOVER: u64 = 100_000; - impl ContractCallWithEgld where SA: CallTypeApi + 'static, @@ -63,18 +51,27 @@ where } result.into_managed_buffer() } +} - pub(super) fn async_call(self) -> AsyncCall { - AsyncCall { - to: self.basic.to, - egld_payment: self.egld_payment, - function_call: self.basic.function_call, - callback_call: None, - } +impl ContractCallWithEgld +where + SA: CallTypeApi + StorageWriteApi + 'static, +{ + pub(super) fn build_async_call(self) -> AsyncCall { + Tx::new_tx_from_sc() + .to(self.basic.to) + .egld(self.egld_payment) + .raw_data(self.basic.function_call) + .callback(None) } +} - pub(super) fn async_call_promise(self) -> super::AsyncCallPromises { - super::AsyncCallPromises { +impl ContractCallWithEgld +where + SA: CallTypeApi + 'static, +{ + pub(super) fn build_async_call_promise(self) -> AsyncCallPromises { + AsyncCallPromises { to: self.basic.to, egld_payment: self.egld_payment, function_call: self.basic.function_call, @@ -214,17 +211,3 @@ where } } } - -fn decode_result( - raw_result: ManagedVec>, -) -> RequestedResult -where - SA: CallTypeApi + 'static, - RequestedResult: TopDecodeMulti, -{ - let mut loader = ManagedResultArgLoader::new(raw_result); - let arg_id = ArgId::from(&b"sync result"[..]); - let h: ArgErrorHandler = ArgErrorHandler::::from(arg_id); - let Ok(result) = RequestedResult::multi_decode_or_handle_err(&mut loader, h); - result -} diff --git a/framework/base/src/types/interaction/contract_call_no_payment.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_no_payment.rs similarity index 86% rename from framework/base/src/types/interaction/contract_call_no_payment.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_no_payment.rs index 7198f71cd1..2a067c761b 100644 --- a/framework/base/src/types/interaction/contract_call_no_payment.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_no_payment.rs @@ -6,14 +6,15 @@ use crate::{ api::CallTypeApi, types::{ BigUint, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment, EgldOrMultiEsdtPayment, - EsdtTokenPayment, ManagedAddress, ManagedBuffer, ManagedVec, TokenIdentifier, + EsdtTokenPayment, FunctionCall, ManagedAddress, ManagedArgBuffer, ManagedBuffer, + ManagedVec, TokenIdentifier, Tx, TxScEnv, }, }; use super::{ - contract_call_exec::UNSPECIFIED_GAS_LIMIT, contract_call_with_egld::ContractCallWithEgld, + contract_call_trait::ContractCallBase, contract_call_with_egld::ContractCallWithEgld, contract_call_with_multi_esdt::ContractCallWithMultiEsdt, ContractCall, - ContractCallWithAnyPayment, ContractCallWithEgldOrSingleEsdt, FunctionCall, ManagedArgBuffer, + ContractCallWithAnyPayment, ContractCallWithEgldOrSingleEsdt, UNSPECIFIED_GAS_LIMIT, }; /// Holds metadata for calling another contract, without payments. @@ -22,19 +23,23 @@ use super::{ /// (unless there are payment arguments in the endpoint - but these are mostly obsolete now). /// /// It is also the basis for all other contract call types, all of them contain this one. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[must_use] pub struct ContractCallNoPayment where SA: CallTypeApi + 'static, { - pub(super) _phantom: PhantomData, + pub(crate) _phantom: PhantomData, pub to: ManagedAddress, pub function_call: FunctionCall, pub explicit_gas_limit: u64, - pub(super) _return_type: PhantomData, + pub(crate) _return_type: PhantomData, } -impl ContractCall for ContractCallNoPayment +impl ContractCallBase for ContractCallNoPayment where SA: CallTypeApi + 'static, OriginalResult: TopEncodeMulti, @@ -48,7 +53,13 @@ where egld_payment: BigUint::zero(), } } +} +impl ContractCall for ContractCallNoPayment +where + SA: CallTypeApi + 'static, + OriginalResult: TopEncodeMulti, +{ #[inline] fn get_mut_basic(&mut self) -> &mut ContractCallNoPayment { self @@ -166,4 +177,8 @@ where pub fn into_function_call(self) -> FunctionCall { self.function_call } + + pub fn tx(self) -> Tx, (), (), (), (), FunctionCall, ()> { + Tx::new_tx_from_sc().raw_data(self.function_call) + } } diff --git a/framework/base/src/types/interaction/contract_call_trait.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_trait.rs similarity index 88% rename from framework/base/src/types/interaction/contract_call_trait.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_trait.rs index 073dae603d..70c5faaac3 100644 --- a/framework/base/src/types/interaction/contract_call_trait.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_trait.rs @@ -1,15 +1,17 @@ use crate::{ api::CallTypeApi, codec::{multi_types::IgnoreValue, TopDecodeMulti, TopEncodeMulti}, - types::ManagedBuffer, + types::{AsyncCall, AsyncCallPromises, BackTransfers, ManagedArgBuffer, ManagedBuffer}, }; -use super::{AsyncCall, ContractCallNoPayment, ContractCallWithEgld, ManagedArgBuffer}; +use super::{ContractCallNoPayment, ContractCallWithEgld}; -/// Defines a contract call object, which is the basis for all calls to other contracts. -/// -/// Its implementations differ on the type of payment that gets sent with the call. -pub trait ContractCall: Sized +/// Converts into a legacy contract call. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] +pub trait ContractCallBase where SA: CallTypeApi + 'static, { @@ -19,7 +21,15 @@ where /// thus reducing it to a simple transaction with optional EGLD value. #[doc(hidden)] fn into_normalized(self) -> ContractCallWithEgld; +} +/// Defines a contract call object, which is the basis for all calls to other contracts. +/// +/// Its implementations differ on the type of payment that gets sent with the call. +pub trait ContractCall: ContractCallBase + Sized +where + SA: CallTypeApi + 'static, +{ /// Mutable access to the common base. #[doc(hidden)] fn get_mut_basic(&mut self) -> &mut ContractCallNoPayment; @@ -75,13 +85,13 @@ where /// Converts to a legacy async call. #[inline] fn async_call(self) -> AsyncCall { - self.into_normalized().async_call() + self.into_normalized().build_async_call() } /// Converts to an async promise. #[inline] - fn async_call_promise(self) -> super::AsyncCallPromises { - self.into_normalized().async_call_promise() + fn async_call_promise(self) -> AsyncCallPromises { + self.into_normalized().build_async_call_promise() } /// Executes immediately, synchronously, and returns contract call result. @@ -99,7 +109,7 @@ where #[inline] fn execute_on_dest_context_with_back_transfers( self, - ) -> (RequestedResult, super::BackTransfers) + ) -> (RequestedResult, BackTransfers) where RequestedResult: TopDecodeMulti, { diff --git a/framework/base/src/types/interaction/contract_call_with_any_payment.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_any_payment.rs similarity index 83% rename from framework/base/src/types/interaction/contract_call_with_any_payment.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_with_any_payment.rs index 07f468a671..2a8a4262f0 100644 --- a/framework/base/src/types/interaction/contract_call_with_any_payment.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_any_payment.rs @@ -5,11 +5,18 @@ use crate::{ types::{EgldOrMultiEsdtPayment, ManagedAddress, ManagedBuffer}, }; -use super::{contract_call_no_payment::ContractCallNoPayment, ContractCall, ContractCallWithEgld}; +use super::{ + contract_call_no_payment::ContractCallNoPayment, contract_call_trait::ContractCallBase, + ContractCall, ContractCallWithEgld, +}; /// Holds data for calling another contract, with any type of payment: none, EGLD, Multi-ESDT. /// /// Gets created when chaining method `with_any_payment`. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[must_use] pub struct ContractCallWithAnyPayment where @@ -19,7 +26,7 @@ where pub payment: EgldOrMultiEsdtPayment, } -impl ContractCall for ContractCallWithAnyPayment +impl ContractCallBase for ContractCallWithAnyPayment where SA: CallTypeApi + 'static, OriginalResult: TopEncodeMulti, @@ -35,7 +42,13 @@ where .convert_to_esdt_transfer_call(multi_esdt_payment), } } +} +impl ContractCall for ContractCallWithAnyPayment +where + SA: CallTypeApi + 'static, + OriginalResult: TopEncodeMulti, +{ #[inline] fn get_mut_basic(&mut self) -> &mut ContractCallNoPayment { &mut self.basic diff --git a/framework/base/src/types/interaction/contract_call_with_egld.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_egld.rs similarity index 83% rename from framework/base/src/types/interaction/contract_call_with_egld.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_with_egld.rs index 9d856cf7b5..47d1fa0c11 100644 --- a/framework/base/src/types/interaction/contract_call_with_egld.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_egld.rs @@ -5,7 +5,10 @@ use crate::{ types::{BigUint, ManagedAddress, ManagedBuffer}, }; -use super::{contract_call_no_payment::ContractCallNoPayment, ContractCall}; +use super::{ + contract_call_no_payment::ContractCallNoPayment, contract_call_trait::ContractCallBase, + ContractCall, +}; /// Holds data for calling another contract, with EGLD payment only. /// @@ -15,6 +18,10 @@ use super::{contract_call_no_payment::ContractCallNoPayment, ContractCall}; /// /// It also represents the normalized form of any contract call, since ESDT transfers /// (the only payment not available here) get converted to builtin function calls in normalized form. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[must_use] pub struct ContractCallWithEgld where @@ -24,7 +31,7 @@ where pub egld_payment: BigUint, } -impl ContractCall for ContractCallWithEgld +impl ContractCallBase for ContractCallWithEgld where SA: CallTypeApi + 'static, OriginalResult: TopEncodeMulti, @@ -36,7 +43,13 @@ where // no ESDT, no conversion needed self } +} +impl ContractCall for ContractCallWithEgld +where + SA: CallTypeApi + 'static, + OriginalResult: TopEncodeMulti, +{ #[inline] fn get_mut_basic(&mut self) -> &mut ContractCallNoPayment { &mut self.basic diff --git a/framework/base/src/types/interaction/contract_call_with_egld_or_single_esdt.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_egld_or_single_esdt.rs similarity index 87% rename from framework/base/src/types/interaction/contract_call_with_egld_or_single_esdt.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_with_egld_or_single_esdt.rs index 66d0b27a41..a6d9a76845 100644 --- a/framework/base/src/types/interaction/contract_call_with_egld_or_single_esdt.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_egld_or_single_esdt.rs @@ -7,11 +7,18 @@ use crate::{ }, }; -use super::{contract_call_no_payment::ContractCallNoPayment, ContractCall, ContractCallWithEgld}; +use super::{ + contract_call_no_payment::ContractCallNoPayment, contract_call_trait::ContractCallBase, + ContractCall, ContractCallWithEgld, +}; /// Holds data for calling another contract, with a single payment, either EGLD or a single ESDT token. /// /// Gets created when chaining method `with_egld_or_single_esdt_transfer`. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[must_use] pub struct ContractCallWithEgldOrSingleEsdt where @@ -40,7 +47,8 @@ where } } -impl ContractCall for ContractCallWithEgldOrSingleEsdt +impl ContractCallBase + for ContractCallWithEgldOrSingleEsdt where SA: CallTypeApi + 'static, OriginalResult: TopEncodeMulti, @@ -56,7 +64,13 @@ where self.into_normalized_esdt() } } +} +impl ContractCall for ContractCallWithEgldOrSingleEsdt +where + SA: CallTypeApi + 'static, + OriginalResult: TopEncodeMulti, +{ #[inline] fn get_mut_basic(&mut self) -> &mut ContractCallNoPayment { &mut self.basic diff --git a/framework/base/src/types/interaction/contract_call_with_multi_esdt.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_multi_esdt.rs similarity index 85% rename from framework/base/src/types/interaction/contract_call_with_multi_esdt.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_call_with_multi_esdt.rs index 240d4ac270..9064507dbf 100644 --- a/framework/base/src/types/interaction/contract_call_with_multi_esdt.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_call_with_multi_esdt.rs @@ -7,8 +7,15 @@ use crate::{ }, }; -use super::{contract_call_no_payment::ContractCallNoPayment, ContractCall, ContractCallWithEgld}; +use super::{ + contract_call_no_payment::ContractCallNoPayment, contract_call_trait::ContractCallBase, + ContractCall, ContractCallWithEgld, +}; +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[must_use] pub struct ContractCallWithMultiEsdt where @@ -18,7 +25,7 @@ where pub esdt_payments: ManagedVec>, } -impl ContractCall for ContractCallWithMultiEsdt +impl ContractCallBase for ContractCallWithMultiEsdt where SA: CallTypeApi + 'static, OriginalResult: TopEncodeMulti, @@ -30,7 +37,13 @@ where .into_normalized() .convert_to_esdt_transfer_call(self.esdt_payments) } +} +impl ContractCall for ContractCallWithMultiEsdt +where + SA: CallTypeApi + 'static, + OriginalResult: TopEncodeMulti, +{ #[inline] fn get_mut_basic(&mut self) -> &mut ContractCallNoPayment { &mut self.basic diff --git a/framework/base/src/types/interaction/contract_deploy.rs b/framework/base/src/types/interaction/contract_call_legacy/contract_deploy.rs similarity index 88% rename from framework/base/src/types/interaction/contract_deploy.rs rename to framework/base/src/types/interaction/contract_call_legacy/contract_deploy.rs index 1c61b7c977..c04ec0ab4b 100644 --- a/framework/base/src/types/interaction/contract_deploy.rs +++ b/framework/base/src/types/interaction/contract_call_legacy/contract_deploy.rs @@ -1,33 +1,37 @@ use core::marker::PhantomData; -use crate::codec::{CodecFrom, TopEncodeMulti}; +use multiversx_sc_codec::TopDecodeMulti; + +use crate::{abi::TypeAbiFrom, codec::TopEncodeMulti}; use crate::{ api::{BlockchainApiImpl, CallTypeApi}, contract_base::{ExitCodecErrorHandler, SendRawWrapper}, err_msg, io::{ArgErrorHandler, ArgId, ManagedResultArgLoader}, - types::{BigUint, CodeMetadata, ManagedAddress, ManagedBuffer, ManagedOption, ManagedVec}, + types::{ + BigUint, CodeMetadata, ManagedAddress, ManagedArgBuffer, ManagedBuffer, ManagedOption, + ManagedVec, + }, }; -use super::ManagedArgBuffer; - -/// Using max u64 to represent maximum possible gas, -/// so that the value zero is not reserved and can be specified explicitly. -/// Leaving the gas limit unspecified will replace it with `api.get_gas_left()`. -const UNSPECIFIED_GAS_LIMIT: u64 = u64::MAX; +use super::UNSPECIFIED_GAS_LIMIT; +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[must_use] pub struct ContractDeploy where SA: CallTypeApi + 'static, { - _phantom: PhantomData, + pub(crate) _phantom: PhantomData, pub to: ManagedOption>, // only used for Upgrade, ignored for Deploy pub egld_payment: BigUint, pub explicit_gas_limit: u64, pub arg_buffer: ManagedArgBuffer, - _return_type: PhantomData, + pub(crate) _return_type: PhantomData, } /// Syntactical sugar to help macros to generate code easier. @@ -103,7 +107,7 @@ where raw_result: ManagedVec>, ) -> RequestedResult where - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { let mut loader = ManagedResultArgLoader::new(raw_result); let arg_id = ArgId::from(&b"init result"[..]); @@ -120,7 +124,7 @@ where code_metadata: CodeMetadata, ) -> (ManagedAddress, RequestedResult) where - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { let (address, raw_result) = SendRawWrapper::::new().deploy_contract( self.resolve_gas_limit(), @@ -141,7 +145,7 @@ where code_metadata: CodeMetadata, ) -> (ManagedAddress, RequestedResult) where - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { let (address, raw_result) = SendRawWrapper::::new().deploy_from_source_contract( self.resolve_gas_limit(), diff --git a/framework/base/src/types/interaction/contract_call_legacy/typed_function_call.rs b/framework/base/src/types/interaction/contract_call_legacy/typed_function_call.rs new file mode 100644 index 0000000000..8589a0dc28 --- /dev/null +++ b/framework/base/src/types/interaction/contract_call_legacy/typed_function_call.rs @@ -0,0 +1,28 @@ +use core::marker::PhantomData; + +use crate::{api::ManagedTypeApi, types::FunctionCall}; + +/// Old attempt at grouping FunctionCall + OriginalTypeMarker. +#[deprecated( + since = "0.49.0", + note = "Not clear if it still used anywhere, will delete soon." +)] +pub struct TypedFunctionCall +where + Api: ManagedTypeApi, +{ + pub function_call: FunctionCall, + _return_type: PhantomData, +} + +impl From> for TypedFunctionCall +where + Api: ManagedTypeApi, +{ + fn from(function_call: FunctionCall) -> Self { + TypedFunctionCall { + function_call, + _return_type: PhantomData, + } + } +} diff --git a/framework/base/src/types/interaction/expr.rs b/framework/base/src/types/interaction/expr.rs new file mode 100644 index 0000000000..9ecbd18112 --- /dev/null +++ b/framework/base/src/types/interaction/expr.rs @@ -0,0 +1,7 @@ +mod test_address; +mod test_sc_address; +mod test_token_identifier; + +pub use test_address::TestAddress; +pub use test_sc_address::TestSCAddress; +pub use test_token_identifier::TestTokenIdentifier; diff --git a/framework/base/src/types/interaction/expr/test_address.rs b/framework/base/src/types/interaction/expr/test_address.rs new file mode 100644 index 0000000000..d2824002ba --- /dev/null +++ b/framework/base/src/types/interaction/expr/test_address.rs @@ -0,0 +1,114 @@ +use core::ptr; + +use multiversx_sc_codec::{CodecFrom, EncodeErrorHandler, TopEncode, TopEncodeOutput}; + +use crate::{ + abi::TypeAbiFrom, + api::ManagedTypeApi, + types::{ + AnnotatedValue, ManagedAddress, ManagedBuffer, TxEnv, TxFrom, TxFromSpecified, TxTo, + TxToSpecified, + }, +}; + +const ADDRESS_PREFIX: &str = "address:"; + +/// Encodes a dummy address, to be used for tests. +/// +/// It is designed to be usable from contracts (especiall test contracts), with a minimal footprint. +/// For this reason, its inner structure is subject to change. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TestAddress<'a> { + name: &'a str, +} + +impl<'a> TestAddress<'a> { + pub const fn new(name: &'a str) -> Self { + TestAddress { name } + } + + pub const fn eval_to_array(&self) -> [u8; 32] { + let result = [b'_'; 32]; + let expr_bytes = self.name.as_bytes(); + let mut len = expr_bytes.len(); + if len > 32 { + len = 32; + } + unsafe { + ptr::copy_nonoverlapping(expr_bytes.as_ptr(), result.as_ptr() as *mut u8, len); + } + result + } + + #[cfg(feature = "alloc")] + pub fn eval_to_expr(&self) -> alloc::string::String { + alloc::format!("{ADDRESS_PREFIX}{}", self.name) + } +} + +impl<'a, Env> AnnotatedValue> for TestAddress<'a> +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + let mut result = ManagedBuffer::new_from_bytes(ADDRESS_PREFIX.as_bytes()); + result.append_bytes(self.name.as_bytes()); + result + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + let expr: [u8; 32] = self.eval_to_array(); + expr.into() + } +} + +impl<'a, Env> TxFrom for TestAddress<'a> +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + let expr: [u8; 32] = self.eval_to_array(); + expr.into() + } +} +impl<'a, Env> TxFromSpecified for TestAddress<'a> where Env: TxEnv {} +impl<'a, Env> TxTo for TestAddress<'a> where Env: TxEnv {} +impl<'a, Env> TxToSpecified for TestAddress<'a> where Env: TxEnv {} + +impl<'a> TopEncode for TestAddress<'a> { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + self.eval_to_array().top_encode_or_handle_err(output, h) + } +} + +impl<'a, Api> CodecFrom> for ManagedAddress where Api: ManagedTypeApi {} +impl<'a, Api> TypeAbiFrom> for ManagedAddress where Api: ManagedTypeApi {} + +#[cfg(test)] +pub mod tests { + use super::*; + + fn assert_eq_eval(expr: &'static str, expected: &[u8; 32]) { + assert_eq!(&TestAddress::new(expr).eval_to_array(), expected); + } + + #[test] + fn test_address_value() { + assert_eq_eval("", b"________________________________"); + assert_eq_eval("a", b"a_______________________________"); + assert_eq_eval("a\x05", b"a\x05______________________________"); + assert_eq_eval("an_address", b"an_address______________________"); + assert_eq_eval( + "12345678901234567890123456789012", + b"12345678901234567890123456789012", + ); + assert_eq_eval( + "123456789012345678901234567890123", + b"12345678901234567890123456789012", + ); + } +} diff --git a/framework/base/src/types/interaction/expr/test_sc_address.rs b/framework/base/src/types/interaction/expr/test_sc_address.rs new file mode 100644 index 0000000000..c752777bfa --- /dev/null +++ b/framework/base/src/types/interaction/expr/test_sc_address.rs @@ -0,0 +1,134 @@ +use core::ptr; + +use multiversx_sc_codec::{CodecFrom, EncodeErrorHandler, TopEncode, TopEncodeOutput}; + +use crate::{ + abi::TypeAbiFrom, + api::ManagedTypeApi, + types::{ + heap::Address, AnnotatedValue, ManagedAddress, ManagedBuffer, TxEnv, TxFrom, + TxFromSpecified, TxTo, TxToSpecified, + }, +}; + +const SC_PREFIX: &str = "sc:"; +const VM_TYPE_LEN: usize = 2; +const DEFAULT_VM_TYPE: &[u8] = &[5, 0]; + +/// Encodes a dummy SC address, to be used for tests. +/// +/// It is designed to be usable from contracts (especiall test contracts), with a minimal footprint. +/// For this reason, its inner structure is subject to change. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TestSCAddress<'a> { + name: &'a str, +} + +impl<'a> TestSCAddress<'a> { + pub const fn new(name: &'a str) -> Self { + TestSCAddress { name } + } +} + +impl<'a, Env> AnnotatedValue> for TestSCAddress<'a> +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + let mut result = ManagedBuffer::new_from_bytes(SC_PREFIX.as_bytes()); + result.append_bytes(self.name.as_bytes()); + result + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + let expr: [u8; 32] = self.eval_to_array(); + expr.into() + } +} + +impl<'a> TestSCAddress<'a> { + pub fn to_address(&self) -> Address { + let expr: [u8; 32] = self.eval_to_array(); + expr.into() + } +} + +impl<'a, Env> TxFrom for TestSCAddress<'a> +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + let expr: [u8; 32] = self.eval_to_array(); + expr.into() + } +} +impl<'a, Env> TxFromSpecified for TestSCAddress<'a> where Env: TxEnv {} +impl<'a, Env> TxTo for TestSCAddress<'a> where Env: TxEnv {} +impl<'a, Env> TxToSpecified for TestSCAddress<'a> where Env: TxEnv {} + +impl<'a> TestSCAddress<'a> { + pub const fn eval_to_array(&self) -> [u8; 32] { + let result = *b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00______________________"; + let expr_bytes = self.name.as_bytes(); + let mut len = expr_bytes.len(); + if len > 22 { + len = 22; + } + unsafe { + ptr::copy_nonoverlapping( + DEFAULT_VM_TYPE.as_ptr(), + result.as_ptr().offset(8) as *mut u8, + VM_TYPE_LEN, + ); + ptr::copy_nonoverlapping( + expr_bytes.as_ptr(), + result.as_ptr().offset(10) as *mut u8, + len, + ); + } + result + } + + #[cfg(feature = "alloc")] + pub fn eval_to_expr(&self) -> alloc::string::String { + alloc::format!("{SC_PREFIX}{}", self.name) + } +} + +impl<'a> TopEncode for TestSCAddress<'a> { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + self.eval_to_array().top_encode_or_handle_err(output, h) + } +} + +impl<'a, Api> CodecFrom> for ManagedAddress where Api: ManagedTypeApi {} +impl<'a, Api> TypeAbiFrom> for ManagedAddress where Api: ManagedTypeApi {} + +#[cfg(test)] +pub mod tests { + use super::*; + + fn assert_eq_eval(expr: &'static str, expected: &[u8; 32]) { + assert_eq!(&TestSCAddress::new(expr).eval_to_array(), expected); + } + + #[test] + fn test_address_value() { + assert_eq_eval( + "", + b"\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00______________________", + ); + assert_eq_eval( + "a", + b"\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00a_____________________", + ); + assert_eq_eval( + "12345678901234567890120s", + b"\x00\x00\x00\x00\x00\x00\x00\x00\x05\x001234567890123456789012", + ); + } +} diff --git a/framework/base/src/types/interaction/expr/test_token_identifier.rs b/framework/base/src/types/interaction/expr/test_token_identifier.rs new file mode 100644 index 0000000000..1230a15664 --- /dev/null +++ b/framework/base/src/types/interaction/expr/test_token_identifier.rs @@ -0,0 +1,67 @@ +use multiversx_sc_codec::{CodecFrom, EncodeErrorHandler, TopEncode, TopEncodeOutput}; + +use crate::{ + abi::TypeAbiFrom, + api::ManagedTypeApi, + types::{AnnotatedValue, ManagedBuffer, TokenIdentifier, TxEnv}, +}; + +const STR_PREFIX: &str = "str:"; + +/// Encodes a dummy address, to be used for tests. +/// +/// It is designed to be usable from contracts (especiall test contracts), with a minimal footprint. +/// For this reason, its inner structure is subject to change. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TestTokenIdentifier<'a> { + name: &'a str, +} + +impl<'a> TestTokenIdentifier<'a> { + pub const fn new(name: &'a str) -> Self { + TestTokenIdentifier { name } + } + + #[cfg(feature = "alloc")] + pub fn eval_to_expr(&self) -> alloc::string::String { + alloc::format!("{STR_PREFIX}{}", self.name) + } +} + +impl<'a, Env> AnnotatedValue> for TestTokenIdentifier<'a> +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + let mut result = ManagedBuffer::new_from_bytes(STR_PREFIX.as_bytes()); + result.append_bytes(self.name.as_bytes()); + result + } + + fn to_value(&self, _env: &Env) -> TokenIdentifier { + self.name.into() + } +} + +impl<'a, Api> From> for TokenIdentifier +where + Api: ManagedTypeApi, +{ + fn from(value: TestTokenIdentifier<'a>) -> Self { + TokenIdentifier::from_esdt_bytes(value.name) + } +} + +impl<'a> TopEncode for TestTokenIdentifier<'a> { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + self.name.top_encode_or_handle_err(output, h) + } +} + +impl<'a, Api> CodecFrom> for TokenIdentifier where Api: ManagedTypeApi {} +impl<'a, Api> TypeAbiFrom> for TokenIdentifier where Api: ManagedTypeApi +{} diff --git a/framework/base/src/types/interaction/managed_arg_buffer.rs b/framework/base/src/types/interaction/managed_arg_buffer.rs index b0cee5db30..342f1c0d3d 100644 --- a/framework/base/src/types/interaction/managed_arg_buffer.rs +++ b/framework/base/src/types/interaction/managed_arg_buffer.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::{ErrorApi, ManagedTypeApi}, codec::{ DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode, @@ -172,6 +172,10 @@ where pub fn into_vec_of_buffers(self) -> ManagedVec> { self.data } + + pub fn iter_buffers(&self) -> ManagedVecRefIterator> { + ManagedVecRefIterator::new(&self.data) + } } impl ManagedArgBuffer @@ -295,12 +299,23 @@ where } } +impl TypeAbiFrom> for ArgBuffer where M: ManagedTypeApi {} + +impl TypeAbiFrom for ManagedArgBuffer where M: ManagedTypeApi {} +impl TypeAbiFrom<&Self> for ManagedArgBuffer where M: ManagedTypeApi {} + impl TypeAbi for ManagedArgBuffer where M: ManagedTypeApi, { + type Unmanaged = ArgBuffer; + /// It is semantically equivalent to any list of `T`. fn type_name() -> TypeName { <&[ManagedBuffer] as TypeAbi>::type_name() } + + fn type_name_rust() -> TypeName { + "ManagedArgBufer<$API>".into() + } } diff --git a/framework/base/src/types/interaction/markers.rs b/framework/base/src/types/interaction/markers.rs new file mode 100644 index 0000000000..4ebce757cc --- /dev/null +++ b/framework/base/src/types/interaction/markers.rs @@ -0,0 +1,9 @@ +mod esdt_system_sc_address; +mod gas_left; +mod to_caller; +mod to_self; + +pub use esdt_system_sc_address::ESDTSystemSCAddress; +pub use gas_left::GasLeft; +pub use to_caller::ToCaller; +pub use to_self::ToSelf; 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 new file mode 100644 index 0000000000..0cfe2e5588 --- /dev/null +++ b/framework/base/src/types/interaction/markers/esdt_system_sc_address.rs @@ -0,0 +1,71 @@ +use hex_literal::hex; +use multiversx_sc_codec::{CodecFrom, EncodeErrorHandler, TopEncode, TopEncodeOutput}; + +use crate::{ + abi::TypeAbiFrom, + api::{CallTypeApi, ManagedTypeApi}, + types::{AnnotatedValue, ManagedAddress, ManagedBuffer, TxScEnv, TxTo, TxToSpecified}, +}; + +/// Address of the system smart contract that manages ESDT. +const SYSTEM_SC_ADDRESS_BYTES: [u8; 32] = + hex!("000000000000000000010000000000000000000000000000000000000002ffff"); +const SYSTEM_SC_ADDRESS_BECH32: &str = + "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"; +const SYSTEM_SC_ADDRESS_ANNOTATION: &str = + "bech32:erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"; + +/// Indicates the system SC address, which is the same on any MultiversX blockchain. +pub struct ESDTSystemSCAddress; + +impl ESDTSystemSCAddress { + pub fn to_managed_address(self) -> ManagedAddress + where + Api: ManagedTypeApi, + { + ManagedAddress::from(SYSTEM_SC_ADDRESS_BYTES) + } + + pub fn to_bech32_str(&self) -> &str { + SYSTEM_SC_ADDRESS_BECH32 + } + + pub fn to_bech32_string(&self) -> alloc::string::String { + SYSTEM_SC_ADDRESS_BECH32.into() + } +} + +impl AnnotatedValue, ManagedAddress> for ESDTSystemSCAddress +where + Api: CallTypeApi, +{ + fn annotation(&self, _env: &TxScEnv) -> ManagedBuffer { + ManagedBuffer::from(SYSTEM_SC_ADDRESS_ANNOTATION) + } + + fn to_value(&self, _env: &TxScEnv) -> ManagedAddress { + ESDTSystemSCAddress.to_managed_address() + } +} + +impl TxTo> for ESDTSystemSCAddress where Api: CallTypeApi {} +impl TxToSpecified> for ESDTSystemSCAddress where Api: CallTypeApi {} + +impl TopEncode for ESDTSystemSCAddress { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + SYSTEM_SC_ADDRESS_BYTES.top_encode_or_handle_err(output, h) + } +} + +impl CodecFrom for ManagedAddress where M: ManagedTypeApi {} +impl TypeAbiFrom for ManagedAddress where M: ManagedTypeApi {} + +impl core::fmt::Display for ESDTSystemSCAddress { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(SYSTEM_SC_ADDRESS_BECH32) + } +} diff --git a/framework/base/src/types/interaction/markers/gas_left.rs b/framework/base/src/types/interaction/markers/gas_left.rs new file mode 100644 index 0000000000..d30209b3d1 --- /dev/null +++ b/framework/base/src/types/interaction/markers/gas_left.rs @@ -0,0 +1,24 @@ +use crate::{ + api::{BlockchainApi, BlockchainApiImpl}, + types::{interaction::display_u64, AnnotatedValue, ManagedBuffer, TxEnv, TxGasValue}, +}; + +/// Indicates that all remaining gas should be sent to a transaction. +/// +/// Usually unwise, other than for synchronous calls, you always want to have some gas left in the contract after the call. +pub struct GasLeft; + +impl AnnotatedValue for GasLeft +where + Env: TxEnv, +{ + fn annotation(&self, env: &Env) -> ManagedBuffer { + display_u64(self.to_value(env)) + } + + fn to_value(&self, _env: &Env) -> u64 { + Env::Api::blockchain_api_impl().get_gas_left() + } +} + +impl TxGasValue for GasLeft where Env: TxEnv {} diff --git a/framework/base/src/types/interaction/markers/to_caller.rs b/framework/base/src/types/interaction/markers/to_caller.rs new file mode 100644 index 0000000000..f24191ce9f --- /dev/null +++ b/framework/base/src/types/interaction/markers/to_caller.rs @@ -0,0 +1,35 @@ +use crate::{ + api::{const_handles, use_raw_handle, BlockchainApi, BlockchainApiImpl, CallTypeApi}, + contract_base::BlockchainWrapper, + types::{ + AnnotatedValue, ManagedAddress, ManagedBuffer, ManagedType, TxScEnv, TxTo, TxToSpecified, + }, +}; + +/// Indicates that transaction should be sent to the caller (the sender of the current transaction). +pub struct ToCaller; + +impl AnnotatedValue, ManagedAddress> for ToCaller +where + Api: CallTypeApi + BlockchainApi, +{ + fn annotation(&self, env: &TxScEnv) -> ManagedBuffer { + self.with_address_ref(env, |addr_ref| addr_ref.hex_expr()) + } + + fn to_value(&self, _env: &TxScEnv) -> ManagedAddress { + BlockchainWrapper::::new().get_caller() + } + + fn with_value_ref(&self, _env: &TxScEnv, f: F) -> R + where + F: FnOnce(&ManagedAddress) -> R, + { + let caller_handle: Api::ManagedBufferHandle = use_raw_handle(const_handles::ADDRESS_CALLER); + Api::blockchain_api_impl().load_caller_managed(caller_handle.clone()); + f(&ManagedAddress::from_handle(caller_handle)) + } +} + +impl TxTo> for ToCaller where Api: CallTypeApi + BlockchainApi {} +impl TxToSpecified> for ToCaller where Api: CallTypeApi + BlockchainApi {} diff --git a/framework/base/src/types/interaction/markers/to_self.rs b/framework/base/src/types/interaction/markers/to_self.rs new file mode 100644 index 0000000000..dee4d5ed3a --- /dev/null +++ b/framework/base/src/types/interaction/markers/to_self.rs @@ -0,0 +1,36 @@ +use crate::{ + api::{const_handles, use_raw_handle, BlockchainApi, BlockchainApiImpl, CallTypeApi}, + contract_base::BlockchainWrapper, + types::{ + AnnotatedValue, ManagedAddress, ManagedBuffer, ManagedType, TxScEnv, TxTo, TxToSpecified, + }, +}; + +/// Indicates that transaction should be sent to itself. +pub struct ToSelf; + +impl AnnotatedValue, ManagedAddress> for ToSelf +where + Api: CallTypeApi + BlockchainApi, +{ + fn annotation(&self, env: &TxScEnv) -> ManagedBuffer { + self.with_address_ref(env, |addr_ref| addr_ref.hex_expr()) + } + + fn to_value(&self, _env: &TxScEnv) -> ManagedAddress { + BlockchainWrapper::::new().get_sc_address() + } + + fn with_value_ref(&self, _env: &TxScEnv, f: F) -> R + where + F: FnOnce(&ManagedAddress) -> R, + { + let sc_address_handle: Api::ManagedBufferHandle = + use_raw_handle(const_handles::ADDRESS_CALLER); + Api::blockchain_api_impl().load_sc_address_managed(sc_address_handle.clone()); + f(&ManagedAddress::from_handle(sc_address_handle)) + } +} + +impl TxTo> for ToSelf where Api: CallTypeApi + BlockchainApi {} +impl TxToSpecified> for ToSelf where Api: CallTypeApi + BlockchainApi {} diff --git a/framework/base/src/types/interaction/result_handlers.rs b/framework/base/src/types/interaction/result_handlers.rs new file mode 100644 index 0000000000..dd3a334e2c --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers.rs @@ -0,0 +1,23 @@ +mod returns_bt; +mod returns_new_address; +mod returns_new_managed_address; +mod returns_raw_result; +mod returns_result; +mod returns_result_as; +mod returns_result_unmanaged; +mod with_new_address; +mod with_raw_result; +mod with_result; +mod with_result_as; + +pub use returns_bt::*; +pub use returns_new_address::*; +pub use returns_new_managed_address::*; +pub use returns_raw_result::*; +pub use returns_result::*; +pub use returns_result_as::*; +pub use returns_result_unmanaged::ReturnsResultUnmanaged; +pub use with_new_address::*; +pub use with_raw_result::WithRawResult; +pub use with_result::WithResult; +pub use with_result_as::*; diff --git a/framework/base/src/types/interaction/result_handlers/returns_bt.rs b/framework/base/src/types/interaction/result_handlers/returns_bt.rs new file mode 100644 index 0000000000..e61abf256d --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/returns_bt.rs @@ -0,0 +1,23 @@ +use crate::{ + contract_base::BlockchainWrapper, + types::{BackTransfers, RHListItem, RHListItemExec, TxEnv}, +}; + +/// Indicates that back-transfers will be returned. +pub struct ReturnsBackTransfers; + +impl RHListItem for ReturnsBackTransfers +where + Env: TxEnv, +{ + type Returns = BackTransfers; +} + +impl RHListItemExec for ReturnsBackTransfers +where + Env: TxEnv, +{ + fn item_process_result(self, _raw_result: &RawResult) -> Self::Returns { + BlockchainWrapper::::new().get_back_transfers() + } +} diff --git a/framework/base/src/types/interaction/result_handlers/returns_new_address.rs b/framework/base/src/types/interaction/result_handlers/returns_new_address.rs new file mode 100644 index 0000000000..eaa523828b --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/returns_new_address.rs @@ -0,0 +1,20 @@ +use crate::types::{heap::Address, DeployRawResult, RHListItem, RHListItemExec, TxEnv}; + +/// Indicates that the newly deployed address will be returned after a deploy. +pub struct ReturnsNewAddress; + +impl RHListItem for ReturnsNewAddress +where + Env: TxEnv, +{ + type Returns = Address; +} + +impl RHListItemExec, Env, Original> for ReturnsNewAddress +where + Env: TxEnv, +{ + fn item_process_result(self, raw_result: &DeployRawResult) -> Self::Returns { + raw_result.new_address.to_address() + } +} diff --git a/framework/base/src/types/interaction/result_handlers/returns_new_managed_address.rs b/framework/base/src/types/interaction/result_handlers/returns_new_managed_address.rs new file mode 100644 index 0000000000..15ed220dc4 --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/returns_new_managed_address.rs @@ -0,0 +1,21 @@ +use crate::types::{DeployRawResult, ManagedAddress, RHListItem, RHListItemExec, TxEnv}; + +/// Indicates that the newly deployed address will be returned after a deploy as a ManagedAddress. +pub struct ReturnsNewManagedAddress; + +impl RHListItem for ReturnsNewManagedAddress +where + Env: TxEnv, +{ + type Returns = ManagedAddress; +} + +impl RHListItemExec, Env, Original> + for ReturnsNewManagedAddress +where + Env: TxEnv, +{ + fn item_process_result(self, raw_result: &DeployRawResult) -> Self::Returns { + raw_result.new_address.clone() + } +} diff --git a/framework/base/src/types/interaction/result_handlers/returns_raw_result.rs b/framework/base/src/types/interaction/result_handlers/returns_raw_result.rs new file mode 100644 index 0000000000..807ce5cf82 --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/returns_raw_result.rs @@ -0,0 +1,32 @@ +use crate::types::{ + DeployRawResult, ManagedBuffer, ManagedVec, RHListItem, RHListItemExec, SyncCallRawResult, + TxEnv, +}; + +/// Indicates that the raw result data will be returned. +pub struct ReturnsRawResult; + +impl RHListItem for ReturnsRawResult +where + Env: TxEnv, +{ + type Returns = ManagedVec>; +} + +impl RHListItemExec, Env, Original> for ReturnsRawResult +where + Env: TxEnv, +{ + fn item_process_result(self, raw_result: &SyncCallRawResult) -> Self::Returns { + raw_result.0.clone() + } +} + +impl RHListItemExec, Env, Original> for ReturnsRawResult +where + Env: TxEnv, +{ + fn item_process_result(self, raw_result: &DeployRawResult) -> Self::Returns { + raw_result.raw_results.clone() + } +} diff --git a/framework/base/src/types/interaction/result_handlers/returns_result.rs b/framework/base/src/types/interaction/result_handlers/returns_result.rs new file mode 100644 index 0000000000..b5c4a5c491 --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/returns_result.rs @@ -0,0 +1,38 @@ +use multiversx_sc_codec::TopDecodeMulti; + +use crate::types::{ + interaction::decode_result, DeployRawResult, RHListItem, RHListItemExec, SyncCallRawResult, + TxEnv, +}; + +/// Indicates that result will be returned. +/// +/// Value will be decoded according to the type defined in the smart contract. +pub struct ReturnsResult; + +impl RHListItem for ReturnsResult +where + Env: TxEnv, +{ + type Returns = Original; +} + +impl RHListItemExec, Env, Original> for ReturnsResult +where + Env: TxEnv, + Original: TopDecodeMulti, +{ + fn item_process_result(self, raw_result: &SyncCallRawResult) -> Original { + decode_result::(raw_result.0.clone()) + } +} + +impl RHListItemExec, Env, Original> for ReturnsResult +where + Env: TxEnv, + Original: TopDecodeMulti, +{ + fn item_process_result(self, raw_result: &DeployRawResult) -> Original { + decode_result::(raw_result.raw_results.clone()) + } +} diff --git a/framework/base/src/types/interaction/result_handlers/returns_result_as.rs b/framework/base/src/types/interaction/result_handlers/returns_result_as.rs new file mode 100644 index 0000000000..842ae01eb8 --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/returns_result_as.rs @@ -0,0 +1,48 @@ +use core::marker::PhantomData; + +use multiversx_sc_codec::TopDecodeMulti; + +use crate::{ + abi::TypeAbiFrom, + types::{interaction::decode_result, RHListItem, RHListItemExec, SyncCallRawResult, TxEnv}, +}; + +/// Indicates that result will be returned. +/// +/// Value will be converted to type `T`, which should be compatible with the original type. +pub struct ReturnsResultAs { + _phantom: PhantomData, +} + +impl Default for ReturnsResultAs { + fn default() -> Self { + Self { + _phantom: Default::default(), + } + } +} + +impl ReturnsResultAs { + pub fn new() -> Self { + Self::default() + } +} + +impl RHListItem for ReturnsResultAs +where + Env: TxEnv, + T: TopDecodeMulti + TypeAbiFrom, +{ + type Returns = T; +} + +impl RHListItemExec, Env, Original> + for ReturnsResultAs +where + Env: TxEnv, + T: TopDecodeMulti + TypeAbiFrom, +{ + fn item_process_result(self, raw_result: &SyncCallRawResult) -> Self::Returns { + decode_result::(raw_result.0.clone()) + } +} diff --git a/framework/base/src/types/interaction/result_handlers/returns_result_unmanaged.rs b/framework/base/src/types/interaction/result_handlers/returns_result_unmanaged.rs new file mode 100644 index 0000000000..4785aef50a --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/returns_result_unmanaged.rs @@ -0,0 +1,30 @@ +use multiversx_sc_codec::TopDecodeMulti; + +use crate::{ + abi::TypeAbi, + types::{interaction::decode_result, RHListItem, RHListItemExec, SyncCallRawResult, TxEnv}, +}; + +/// Indicates that the unmanaged version of the result will be returned. +pub struct ReturnsResultUnmanaged; + +impl RHListItem for ReturnsResultUnmanaged +where + Env: TxEnv, + Original: TypeAbi, + Original::Unmanaged: TopDecodeMulti, +{ + type Returns = Original::Unmanaged; +} + +impl RHListItemExec, Env, Original> + for ReturnsResultUnmanaged +where + Env: TxEnv, + Original: TypeAbi, + Original::Unmanaged: TopDecodeMulti, +{ + fn item_process_result(self, raw_result: &SyncCallRawResult) -> Self::Returns { + decode_result::(raw_result.0.clone()) + } +} diff --git a/framework/base/src/types/interaction/result_handlers/with_new_address.rs b/framework/base/src/types/interaction/result_handlers/with_new_address.rs new file mode 100644 index 0000000000..f26d12983c --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/with_new_address.rs @@ -0,0 +1,45 @@ +use core::marker::PhantomData; + +use crate::types::{DeployRawResult, ManagedAddress, RHListItem, RHListItemExec, TxEnv}; + +/// Defines a lambda function to be called on the newly deployed address, after a deploy. +pub struct WithNewAddress +where + Env: TxEnv, + F: FnOnce(&ManagedAddress), +{ + _phantom: PhantomData, + pub f: F, +} + +impl WithNewAddress +where + Env: TxEnv, + F: FnOnce(&ManagedAddress), +{ + pub fn new(f: F) -> Self { + WithNewAddress { + _phantom: PhantomData, + f, + } + } +} + +impl RHListItem for WithNewAddress +where + Env: TxEnv, + F: FnOnce(&ManagedAddress), +{ + type Returns = (); +} + +impl RHListItemExec, Env, Original> + for WithNewAddress +where + Env: TxEnv, + F: FnOnce(&ManagedAddress), +{ + fn item_process_result(self, raw_result: &DeployRawResult) -> Self::Returns { + (self.f)(&raw_result.new_address); + } +} diff --git a/framework/base/src/types/interaction/result_handlers/with_raw_result.rs b/framework/base/src/types/interaction/result_handlers/with_raw_result.rs new file mode 100644 index 0000000000..f2d1457f07 --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/with_raw_result.rs @@ -0,0 +1,47 @@ +use core::marker::PhantomData; + +use crate::types::{ + ManagedBuffer, ManagedVec, RHListItem, RHListItemExec, SyncCallRawResult, TxEnv, +}; + +/// Defines a lambda function to be called on the raw result of the transaction. +pub struct WithRawResult +where + Env: TxEnv, + F: FnOnce(&ManagedVec>), +{ + _phantom: PhantomData, + f: F, +} + +impl WithRawResult +where + Env: TxEnv, + F: FnOnce(&ManagedVec>), +{ + pub fn new(f: F) -> Self { + WithRawResult { + _phantom: PhantomData, + f, + } + } +} + +impl RHListItem for WithRawResult +where + Env: TxEnv, + F: FnOnce(&ManagedVec>), +{ + type Returns = (); +} + +impl RHListItemExec, Env, Original> + for WithRawResult +where + Env: TxEnv, + F: FnOnce(&ManagedVec>), +{ + fn item_process_result(self, raw_result: &SyncCallRawResult) -> Self::Returns { + (self.f)(&raw_result.0) + } +} diff --git a/framework/base/src/types/interaction/result_handlers/with_result.rs b/framework/base/src/types/interaction/result_handlers/with_result.rs new file mode 100644 index 0000000000..ad4daea57d --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/with_result.rs @@ -0,0 +1,51 @@ +use core::marker::PhantomData; + +use multiversx_sc_codec::TopDecodeMulti; + +use crate::types::{ + interaction::decode_result, RHListItem, RHListItemExec, SyncCallRawResult, TxEnv, +}; + +/// Defines a lambda function to be called on the decoded result. +/// +/// Value will be decoded according to the type defined in the smart contract. +pub struct WithResult +where + F: FnOnce(T), +{ + _phantom: PhantomData, + f: F, +} + +impl WithResult +where + F: FnOnce(T), +{ + pub fn new(f: F) -> Self { + WithResult { + _phantom: PhantomData, + f, + } + } +} + +impl RHListItem for WithResult +where + Env: TxEnv, + F: FnOnce(Original), +{ + type Returns = (); +} + +impl RHListItemExec, Env, Original> + for WithResult +where + Env: TxEnv, + Original: TopDecodeMulti, + F: FnOnce(Original), +{ + fn item_process_result(self, raw_result: &SyncCallRawResult) -> Self::Returns { + let t = decode_result::(raw_result.0.clone()); + (self.f)(t) + } +} diff --git a/framework/base/src/types/interaction/result_handlers/with_result_as.rs b/framework/base/src/types/interaction/result_handlers/with_result_as.rs new file mode 100644 index 0000000000..4a2aed8f35 --- /dev/null +++ b/framework/base/src/types/interaction/result_handlers/with_result_as.rs @@ -0,0 +1,53 @@ +use core::marker::PhantomData; + +use multiversx_sc_codec::TopDecodeMulti; + +use crate::{ + abi::TypeAbiFrom, + types::{interaction::decode_result, RHListItem, RHListItemExec, SyncCallRawResult, TxEnv}, +}; + +/// Defines a lambda function to be called on the decoded result. +/// +/// Value will be converted to type `T`, which should be compatible with the original type. +pub struct WithResultAs +where + F: FnOnce(T), +{ + _phantom: PhantomData, + pub f: F, +} + +impl WithResultAs +where + F: FnOnce(T), +{ + pub fn new(f: F) -> Self { + WithResultAs { + _phantom: PhantomData, + f, + } + } +} + +impl RHListItem for WithResultAs +where + Env: TxEnv, + T: TopDecodeMulti + TypeAbiFrom, + F: FnOnce(T), +{ + type Returns = (); +} + +impl RHListItemExec, Env, Original> + for WithResultAs +where + Env: TxEnv, + T: TopDecodeMulti + TypeAbiFrom, + F: FnOnce(T), +{ + fn item_process_result(self, raw_result: &SyncCallRawResult) -> Self::Returns { + let t = decode_result::(raw_result.0.clone()); + (self.f)(t) + } +} diff --git a/framework/base/src/types/interaction/system_proxy.rs b/framework/base/src/types/interaction/system_proxy.rs new file mode 100644 index 0000000000..3b1fb836d6 --- /dev/null +++ b/framework/base/src/types/interaction/system_proxy.rs @@ -0,0 +1,10 @@ +pub mod builtin_func_names; +mod builtin_func_proxy; +mod esdt_system_sc_proxy; +mod legacy_system_sc_proxy; +pub(crate) mod token_properties; + +pub use builtin_func_proxy::*; +pub use esdt_system_sc_proxy::{ESDTSystemSCProxy, ESDTSystemSCProxyMethods, IssueCall}; +pub use legacy_system_sc_proxy::ESDTSystemSmartContractProxy; +pub use token_properties::*; diff --git a/framework/base/src/api/builtin_function_names.rs b/framework/base/src/types/interaction/system_proxy/builtin_func_names.rs similarity index 100% rename from framework/base/src/api/builtin_function_names.rs rename to framework/base/src/types/interaction/system_proxy/builtin_func_names.rs 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 new file mode 100644 index 0000000000..11972f72e8 --- /dev/null +++ b/framework/base/src/types/interaction/system_proxy/builtin_func_proxy.rs @@ -0,0 +1,193 @@ +use multiversx_sc_codec::{Empty, TopEncode}; + +use crate::types::{ + BigUint, ManagedAddress, ManagedBuffer, ManagedVec, ProxyArg, TokenIdentifier, Tx, TxEnv, + TxFrom, TxGas, TxProxyCall, TxProxyTrait, TxTo, +}; + +use super::builtin_func_names::{ + CHANGE_OWNER_BUILTIN_FUNC_NAME, CLAIM_DEVELOPER_REWARDS_FUNC_NAME, DELETE_USERNAME_FUNC_NAME, + ESDT_LOCAL_BURN_FUNC_NAME, ESDT_LOCAL_MINT_FUNC_NAME, ESDT_NFT_ADD_QUANTITY_FUNC_NAME, + ESDT_NFT_ADD_URI_FUNC_NAME, ESDT_NFT_BURN_FUNC_NAME, ESDT_NFT_CREATE_FUNC_NAME, + ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME, SET_USERNAME_FUNC_NAME, +}; + +/// Proxy describing the user builtin function signatures. +pub struct UserBuiltinProxy; + +impl TxProxyTrait for UserBuiltinProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = UserBuiltinProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + UserBuiltinProxyMethods { wrapped_tx: tx } + } +} + +pub struct UserBuiltinProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +impl UserBuiltinProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn set_user_name>>( + self, + name: Arg0, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call(SET_USERNAME_FUNC_NAME) + .argument(&name) + .original_result() + } + + pub fn delete_user_name(self) -> TxProxyCall { + self.wrapped_tx + .raw_call(DELETE_USERNAME_FUNC_NAME) + .original_result() + } + + pub fn claim_developer_rewards(self) -> TxProxyCall { + self.wrapped_tx + .raw_call(CLAIM_DEVELOPER_REWARDS_FUNC_NAME) + .original_result() + } + + pub fn change_owner_address( + self, + new_owner: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call(CHANGE_OWNER_BUILTIN_FUNC_NAME) + .argument(new_owner) + .original_result() + } + + pub fn esdt_local_burn( + self, + token: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + ) -> TxProxyCall { + if nonce == 0 { + return self + .wrapped_tx + .raw_call(ESDT_LOCAL_BURN_FUNC_NAME) + .argument(token) + .argument(amount) + .original_result(); + } + + self.wrapped_tx + .raw_call(ESDT_NFT_BURN_FUNC_NAME) + .argument(token) + .argument(&nonce) + .argument(amount) + .original_result() + } + + pub fn esdt_local_mint( + self, + token: &TokenIdentifier, + nonce: u64, + amount: &BigUint, + ) -> TxProxyCall { + if nonce == 0 { + return self + .wrapped_tx + .raw_call(ESDT_LOCAL_MINT_FUNC_NAME) + .argument(token) + .argument(amount) + .original_result(); + } + self.wrapped_tx + .raw_call(ESDT_NFT_ADD_QUANTITY_FUNC_NAME) + .argument(token) + .argument(&nonce) + .argument(amount) + .original_result() + } + + pub fn nft_add_multiple_uri( + self, + token_id: &TokenIdentifier, + nft_nonce: u64, + new_uris: &ManagedVec>, + ) -> TxProxyCall { + let mut tx = self + .wrapped_tx + .raw_call(ESDT_NFT_ADD_URI_FUNC_NAME) + .argument(token_id) + .argument(&nft_nonce); + + for uri in new_uris { + tx = tx.argument(&uri); + } + + tx.original_result() + } + + pub fn nft_update_attributes( + self, + token_id: &TokenIdentifier, + nft_nonce: u64, + new_attributes: &T, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call(ESDT_NFT_UPDATE_ATTRIBUTES_FUNC_NAME) + .argument(token_id) + .argument(&nft_nonce) + .argument(new_attributes) + .original_result() + } + + #[allow(clippy::too_many_arguments)] + pub fn esdt_nft_create( + self, + token: &TokenIdentifier, + amount: &BigUint, + name: &ManagedBuffer, + royalties: &BigUint, + hash: &ManagedBuffer, + attributes: &T, + uris: &ManagedVec>, + ) -> TxProxyCall { + let mut tx = self + .wrapped_tx + .raw_call(ESDT_NFT_CREATE_FUNC_NAME) + .argument(token) + .argument(amount) + .argument(name) + .argument(royalties) + .argument(hash) + .argument(attributes); + + if uris.is_empty() { + // at least one URI is required, so we push an empty one + tx = tx.argument(&Empty); + } else { + // The API function has the last argument as variadic, + // so we top-encode each and send as separate argument + for uri in uris { + tx = tx.argument(&uri); + } + } + + tx.original_result() + } +} 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 new file mode 100644 index 0000000000..3589f4ce28 --- /dev/null +++ b/framework/base/src/types/interaction/system_proxy/esdt_system_sc_proxy.rs @@ -0,0 +1,582 @@ +use super::token_properties::*; + +use crate::{ + api::CallTypeApi, + types::{ + BigUint, EgldPayment, EsdtLocalRole, EsdtTokenType, FunctionCall, ManagedAddress, + ManagedBuffer, OriginalResultMarker, TokenIdentifier, Tx, TxEnv, TxFrom, TxGas, + TxProxyCall, TxProxyTrait, TxTo, + }, +}; + +const ISSUE_FUNGIBLE_ENDPOINT_NAME: &str = "issue"; +const ISSUE_NON_FUNGIBLE_ENDPOINT_NAME: &str = "issueNonFungible"; +const ISSUE_SEMI_FUNGIBLE_ENDPOINT_NAME: &str = "issueSemiFungible"; +const REGISTER_META_ESDT_ENDPOINT_NAME: &str = "registerMetaESDT"; +const ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME: &str = "registerAndSetAllRoles"; + +/// The specific `Tx` type produces by the issue operations of the ESDTSystemSCProxy. +pub type IssueCall = Tx< + Env, + From, + To, + EgldPayment<::Api>, + Gas, + FunctionCall<::Api>, + OriginalResultMarker::Api>>, +>; + +/// Proxy for the ESDT system smart contract. +pub struct ESDTSystemSCProxy; + +impl TxProxyTrait for ESDTSystemSCProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = ESDTSystemSCProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + ESDTSystemSCProxyMethods { wrapped_tx: tx } + } +} + +/// Method container of the ESDT system smart contract proxy. +pub struct ESDTSystemSCProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +impl ESDTSystemSCProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Produces a contract call to the ESDT system SC, + /// which causes it to issue a new fungible ESDT token. + pub fn issue_fungible( + self, + issue_cost: BigUint, + token_display_name: &ManagedBuffer, + token_ticker: &ManagedBuffer, + initial_supply: &BigUint, + properties: FungibleTokenProperties, + ) -> IssueCall { + self.issue( + issue_cost, + EsdtTokenType::Fungible, + token_display_name, + token_ticker, + initial_supply, + TokenProperties { + num_decimals: properties.num_decimals, + can_freeze: properties.can_freeze, + can_wipe: properties.can_wipe, + can_pause: properties.can_pause, + can_transfer_create_role: false, + can_mint: properties.can_mint, + can_burn: properties.can_burn, + can_change_owner: properties.can_change_owner, + can_upgrade: properties.can_upgrade, + can_add_special_roles: properties.can_add_special_roles, + }, + ) + } + + /// 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( + self, + issue_cost: BigUint, + token_display_name: &ManagedBuffer, + token_ticker: &ManagedBuffer, + properties: NonFungibleTokenProperties, + ) -> IssueCall { + let zero = BigUint::zero(); + self.issue( + issue_cost, + EsdtTokenType::NonFungible, + token_display_name, + token_ticker, + &zero, + TokenProperties { + num_decimals: 0, + can_freeze: properties.can_freeze, + can_wipe: properties.can_wipe, + can_pause: properties.can_pause, + can_transfer_create_role: properties.can_transfer_create_role, + can_mint: false, + can_burn: false, + can_change_owner: properties.can_change_owner, + can_upgrade: properties.can_upgrade, + can_add_special_roles: properties.can_add_special_roles, + }, + ) + } + + /// 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( + self, + issue_cost: BigUint, + token_display_name: &ManagedBuffer, + token_ticker: &ManagedBuffer, + properties: SemiFungibleTokenProperties, + ) -> IssueCall { + let zero = BigUint::zero(); + self.issue( + issue_cost, + EsdtTokenType::SemiFungible, + token_display_name, + token_ticker, + &zero, + TokenProperties { + num_decimals: 0, + can_freeze: properties.can_freeze, + can_wipe: properties.can_wipe, + can_pause: properties.can_pause, + can_transfer_create_role: properties.can_transfer_create_role, + can_mint: false, + can_burn: false, + can_change_owner: properties.can_change_owner, + can_upgrade: properties.can_upgrade, + can_add_special_roles: properties.can_add_special_roles, + }, + ) + } + + /// Produces a contract call to the ESDT system SC, + /// which causes it to register a new Meta ESDT token. + pub fn register_meta_esdt( + self, + issue_cost: BigUint, + token_display_name: &ManagedBuffer, + token_ticker: &ManagedBuffer, + properties: MetaTokenProperties, + ) -> IssueCall { + let zero = BigUint::zero(); + self.issue( + issue_cost, + EsdtTokenType::Meta, + token_display_name, + token_ticker, + &zero, + TokenProperties { + num_decimals: properties.num_decimals, + can_freeze: properties.can_freeze, + can_wipe: properties.can_wipe, + can_pause: properties.can_pause, + can_transfer_create_role: properties.can_transfer_create_role, + can_mint: false, + can_burn: false, + can_change_owner: properties.can_change_owner, + can_upgrade: properties.can_upgrade, + can_add_special_roles: properties.can_add_special_roles, + }, + ) + } + + pub fn issue_and_set_all_roles( + self, + issue_cost: BigUint, + token_display_name: ManagedBuffer, + token_ticker: ManagedBuffer, + token_type: EsdtTokenType, + num_decimals: usize, + ) -> IssueCall { + let token_type_name = match token_type { + EsdtTokenType::Fungible => "FNG", + EsdtTokenType::NonFungible => "NFT", + EsdtTokenType::SemiFungible => "SFT", + EsdtTokenType::Meta => "META", + EsdtTokenType::Invalid => "", + }; + + self.wrapped_tx + .raw_call(ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME) + .egld(issue_cost) + .argument(&token_display_name) + .argument(&token_ticker) + .argument(&token_type_name) + .argument(&num_decimals) + .original_result() + } + + /// Deduplicates code from all the possible issue functions + fn issue( + self, + issue_cost: BigUint, + token_type: EsdtTokenType, + token_display_name: &ManagedBuffer, + token_ticker: &ManagedBuffer, + initial_supply: &BigUint, + properties: TokenProperties, + ) -> IssueCall { + let endpoint_name = match token_type { + EsdtTokenType::Fungible => ISSUE_FUNGIBLE_ENDPOINT_NAME, + EsdtTokenType::NonFungible => ISSUE_NON_FUNGIBLE_ENDPOINT_NAME, + EsdtTokenType::SemiFungible => ISSUE_SEMI_FUNGIBLE_ENDPOINT_NAME, + EsdtTokenType::Meta => REGISTER_META_ESDT_ENDPOINT_NAME, + EsdtTokenType::Invalid => "", + }; + + let mut tx = self + .wrapped_tx + .raw_call(endpoint_name) + .egld(issue_cost) + .argument(token_display_name) + .argument(token_ticker); + + if token_type == EsdtTokenType::Fungible { + tx = tx.argument(initial_supply); + tx = tx.argument(&properties.num_decimals); + } else if token_type == EsdtTokenType::Meta { + tx = tx.argument(&properties.num_decimals); + } + + let mut token_prop_args = TokenPropertyArguments { + can_freeze: Some(properties.can_freeze), + can_wipe: Some(properties.can_wipe), + can_pause: Some(properties.can_pause), + can_change_owner: Some(properties.can_change_owner), + can_upgrade: Some(properties.can_upgrade), + can_add_special_roles: Some(properties.can_add_special_roles), + ..TokenPropertyArguments::default() + }; + + if token_type == EsdtTokenType::Fungible { + token_prop_args.can_mint = Some(properties.can_mint); + token_prop_args.can_burn = Some(properties.can_burn); + } else { + token_prop_args.can_transfer_create_role = Some(properties.can_transfer_create_role); + } + + append_token_property_arguments(&mut tx.data, &token_prop_args); + + tx.original_result() + } + + /// 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( + self, + token_identifier: &TokenIdentifier, + amount: &BigUint, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("mint") + .argument(token_identifier) + .argument(amount) + .original_result() + } + + /// Produces a contract call to the ESDT system SC, + /// which causes it to burn fungible ESDT tokens owned by the SC. + pub fn burn( + self, + token_identifier: &TokenIdentifier, + amount: &BigUint, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("ESDTBurn") + .argument(token_identifier) + .argument(amount) + .original_result() + } + + /// The manager of an ESDT token may choose to suspend all transactions of the token, + /// except minting, freezing/unfreezing and wiping. + pub fn pause( + self, + token_identifier: &TokenIdentifier, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("pause") + .argument(token_identifier) + .original_result() + } + + /// The reverse operation of `pause`. + pub fn unpause( + self, + token_identifier: &TokenIdentifier, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unPause") + .argument(token_identifier) + .original_result() + } + + /// 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( + self, + token_identifier: &TokenIdentifier, + address: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("freeze") + .argument(token_identifier) + .argument(address) + .original_result() + } + + /// The reverse operation of `freeze`, unfreezing, will allow further transfers to and from the account. + pub fn unfreeze( + self, + token_identifier: &TokenIdentifier, + address: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unFreeze") + .argument(token_identifier) + .argument(address) + .original_result() + } + + /// The manager of an ESDT token may wipe out all the tokens held by a frozen account. + /// 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( + self, + token_identifier: &TokenIdentifier, + address: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("wipe") + .argument(token_identifier) + .argument(address) + .original_result() + } + + /// 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( + self, + token_identifier: &TokenIdentifier, + nft_nonce: u64, + address: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("freezeSingleNFT") + .argument(token_identifier) + .argument(&nft_nonce) + .argument(address) + .original_result() + } + + /// The reverse operation of `freeze`, unfreezing, will allow further transfers to and from the account. + pub fn unfreeze_nft( + self, + token_identifier: &TokenIdentifier, + nft_nonce: u64, + address: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("unFreezeSingleNFT") + .argument(token_identifier) + .argument(&nft_nonce) + .argument(address) + .original_result() + } + + /// The manager of an ESDT token may wipe out a single NFT held by a frozen Account. + /// 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( + self, + token_identifier: &TokenIdentifier, + nft_nonce: u64, + address: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("wipeSingleNFT") + .argument(token_identifier) + .argument(&nft_nonce) + .argument(address) + .original_result() + } + + /// 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( + self, + token_identifier: &TokenIdentifier, + num_decimals: usize, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("changeSFTToMetaESDT") + .argument(&token_identifier) + .argument(&num_decimals) + .original_result() + } + + /// This function can be called only if canSetSpecialRoles was set to true. + /// 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>( + self, + address: &ManagedAddress, + token_identifier: &TokenIdentifier, + roles_iter: RoleIter, + ) -> TxProxyCall { + let mut tx = self + .wrapped_tx + .raw_call("setSpecialRole") + .argument(token_identifier) + .argument(address); + for role in roles_iter { + if role != EsdtLocalRole::None { + tx = tx.argument(&role.as_role_name()); + } + } + + tx.original_result() + } + + /// This function can be called only if canSetSpecialRoles was set to true. + /// 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>( + self, + address: &ManagedAddress, + token_identifier: &TokenIdentifier, + roles_iter: RoleIter, + ) -> TxProxyCall { + let mut tx = self + .wrapped_tx + .raw_call("unSetSpecialRole") + .argument(token_identifier) + .argument(address); + for role in roles_iter { + if role != EsdtLocalRole::None { + tx = tx.argument(&role.as_role_name()); + } + } + + tx.original_result() + } + + pub fn transfer_ownership( + self, + token_identifier: &TokenIdentifier, + new_owner: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transferOwnership") + .argument(token_identifier) + .argument(new_owner) + .original_result() + } + + pub fn transfer_nft_create_role( + self, + token_identifier: &TokenIdentifier, + old_creator: &ManagedAddress, + new_creator: &ManagedAddress, + ) -> TxProxyCall { + self.wrapped_tx + .raw_call("transferNFTCreateRole") + .argument(token_identifier) + .argument(old_creator) + .argument(new_creator) + .original_result() + } + + pub fn control_changes( + self, + token_identifier: &TokenIdentifier, + property_arguments: &TokenPropertyArguments, + ) -> TxProxyCall { + let mut tx = self + .wrapped_tx + .raw_call("controlChanges") + .argument(token_identifier); + append_token_property_arguments(&mut tx.data, property_arguments); + tx.original_result() + } +} + +const TRUE_STR: &str = "true"; +const FALSE_STR: &str = "false"; + +fn bool_name_bytes(b: bool) -> &'static str { + if b { + TRUE_STR + } else { + FALSE_STR + } +} + +fn set_token_property(contract_call: &mut FunctionCall, name: &str, value: bool) +where + Api: CallTypeApi, +{ + contract_call.arg_buffer.push_multi_arg(&name); + contract_call + .arg_buffer + .push_multi_arg(&bool_name_bytes(value)); +} + +fn append_token_property_arguments( + contract_call: &mut FunctionCall, + token_prop_args: &TokenPropertyArguments, +) where + Api: CallTypeApi, +{ + if let Some(can_freeze) = token_prop_args.can_freeze { + set_token_property(contract_call, "canFreeze", can_freeze); + } + + if let Some(can_wipe) = token_prop_args.can_wipe { + set_token_property(contract_call, "canWipe", can_wipe); + } + + if let Some(can_pause) = token_prop_args.can_pause { + set_token_property(contract_call, "canPause", can_pause); + } + + if let Some(can_transfer_create_role) = token_prop_args.can_transfer_create_role { + set_token_property( + contract_call, + "canTransferNFTCreateRole", + can_transfer_create_role, + ); + } + + if let Some(can_mint) = token_prop_args.can_mint { + set_token_property(contract_call, "canMint", can_mint); + } + + if let Some(can_burn) = token_prop_args.can_burn { + set_token_property(contract_call, "canBurn", can_burn); + } + + if let Some(can_change_owner) = token_prop_args.can_change_owner { + set_token_property(contract_call, "canChangeOwner", can_change_owner); + } + + if let Some(can_upgrade) = token_prop_args.can_upgrade { + set_token_property(contract_call, "canUpgrade", can_upgrade); + } + + if let Some(can_add_special_roles) = token_prop_args.can_add_special_roles { + set_token_property(contract_call, "canAddSpecialRoles", can_add_special_roles); + } +} diff --git a/framework/base/src/esdt/system_sc_proxy.rs b/framework/base/src/types/interaction/system_proxy/legacy_system_sc_proxy.rs similarity index 97% rename from framework/base/src/esdt/system_sc_proxy.rs rename to framework/base/src/types/interaction/system_proxy/legacy_system_sc_proxy.rs index 62182eeb1a..6f74b80812 100644 --- a/framework/base/src/esdt/system_sc_proxy.rs +++ b/framework/base/src/types/interaction/system_proxy/legacy_system_sc_proxy.rs @@ -1,20 +1,16 @@ use core::marker::PhantomData; -use super::properties::*; -use hex_literal::hex; +// use super::properties::*; use crate::{ api::{CallTypeApi, SendApi}, types::{ - BigUint, ContractCall, ContractCallNoPayment, ContractCallWithEgld, EsdtLocalRole, - EsdtTokenType, ManagedAddress, ManagedBuffer, TokenIdentifier, + BigUint, ContractCall, ContractCallNoPayment, ContractCallWithEgld, ESDTSystemSCAddress, + EsdtLocalRole, EsdtTokenType, ManagedAddress, ManagedBuffer, TokenIdentifier, }, }; -/// Address of the system smart contract that manages ESDT. -/// Bech32: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u -pub const ESDT_SYSTEM_SC_ADDRESS_ARRAY: [u8; 32] = - hex!("000000000000000000010000000000000000000000000000000000000002ffff"); +use super::token_properties::*; const ISSUE_FUNGIBLE_ENDPOINT_NAME: &str = "issue"; const ISSUE_NON_FUNGIBLE_ENDPOINT_NAME: &str = "issueNonFungible"; @@ -25,6 +21,10 @@ const ISSUE_AND_SET_ALL_ROLES_ENDPOINT_NAME: &str = "registerAndSetAllRoles"; /// Proxy for the ESDT system smart contract. /// Unlike other contract proxies, this one has a fixed address, /// so the proxy object doesn't really contain any data, it is more of a placeholder. +#[deprecated( + since = "0.49.0", + note = "There is a new `ESDTSystemSCProxy`, which uses the new proxy model." +)] pub struct ESDTSystemSmartContractProxy where SA: SendApi + 'static, @@ -470,7 +470,7 @@ where } pub fn esdt_system_sc_address(&self) -> ManagedAddress { - ManagedAddress::new_from_bytes(&ESDT_SYSTEM_SC_ADDRESS_ARRAY) + ESDTSystemSCAddress.to_managed_address() } fn esdt_system_sc_call_no_args( diff --git a/framework/base/src/esdt/properties.rs b/framework/base/src/types/interaction/system_proxy/token_properties.rs similarity index 100% rename from framework/base/src/esdt/properties.rs rename to framework/base/src/types/interaction/system_proxy/token_properties.rs diff --git a/framework/base/src/types/interaction/tx.rs b/framework/base/src/types/interaction/tx.rs new file mode 100644 index 0000000000..b1e6de8a10 --- /dev/null +++ b/framework/base/src/types/interaction/tx.rs @@ -0,0 +1,951 @@ +use crate::{ + api::CallTypeApi, + types::{ + heap::H256, BigUint, CodeMetadata, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment, + EgldOrEsdtTokenPaymentRefs, EgldOrMultiEsdtPayment, EsdtTokenPayment, EsdtTokenPaymentRefs, + ManagedAddress, ManagedBuffer, ManagedOption, ManagedVec, MultiEsdtPayment, + TokenIdentifier, + }, +}; + +use multiversx_sc_codec::TopEncodeMulti; + +use super::{ + AnnotatedValue, Code, ContractCallBase, ContractCallNoPayment, ContractCallWithEgld, + ContractDeploy, DeployCall, Egld, EgldPayment, ExplicitGas, FromSource, FunctionCall, + ManagedArgBuffer, OriginalResultMarker, RHList, RHListAppendNoRet, RHListAppendRet, RHListItem, + TxCodeSource, TxCodeValue, TxData, TxDataFunctionCall, TxEgldValue, TxEnv, + TxEnvMockDeployAddress, TxEnvWithTxHash, TxFrom, TxFromSourceValue, TxFromSpecified, TxGas, + TxGasValue, TxPayment, TxPaymentEgldOnly, TxProxyTrait, TxResultHandler, TxScEnv, TxTo, + TxToSpecified, UpgradeCall, UNSPECIFIED_GAS_LIMIT, +}; + +/// Universal representation of a blockchain transaction. +/// +/// Uses 7 generic type arguments to encode all aspects of the transaction. +/// +/// It is future-like, does nothing by itself, it needs a specialized method call to actually run or send it. +/// +/// Rationale: https://twitter.com/andreimmarinica/status/1777157322155966601 +#[must_use] +pub struct Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + Data: TxData, + RH: TxResultHandler, +{ + pub env: Env, + pub from: From, + pub to: To, + pub payment: Payment, + pub gas: Gas, + pub data: Data, + pub result_handler: RH, +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + Data: TxDataFunctionCall, + RH: TxResultHandler, +{ + /// Converts object to a MultiversX transaction data field string. + pub fn to_call_data_string(&self) -> ManagedBuffer { + self.data.to_call_data_string() + } +} + +pub type TxBaseWithEnv = Tx; + +impl TxBaseWithEnv +where + Env: TxEnv, +{ + /// Constructor, needs to take an environment object. + #[inline] + pub fn new_with_env(env: Env) -> Self { + Tx { + env, + from: (), + to: (), + payment: (), + gas: (), + data: (), + result_handler: (), + } + } +} + +impl Tx +where + Env: TxEnv, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + Data: TxData, + RH: TxResultHandler, +{ + /// Specifies transaction sender. + pub fn from(self, from: From) -> Tx + where + From: TxFrom, + { + Tx { + env: self.env, + from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: self.result_handler, + } + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + Payment: TxPayment, + Gas: TxGas, + Data: TxData, + RH: TxResultHandler, +{ + /// Specifies the recipient of the transaction. + /// + /// Allows argument to also be `()`. + pub fn to(self, to: To) -> Tx + where + To: TxTo, + { + Tx { + env: self.env, + from: self.from, + to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: self.result_handler, + } + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, + Data: TxData, + RH: TxResultHandler, +{ + /// Adds any payment to a transaction, if no payment has been added before. + pub fn payment(self, payment: Payment) -> Tx + where + Payment: TxPayment, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment, + gas: self.gas, + data: self.data, + result_handler: self.result_handler, + } + } + + /// Adds EGLD value to a transaction. + /// + /// Accepts any type that can represent and EGLD amount: BigUint, &BigUint, etc. + pub fn egld( + self, + egld_value: EgldValue, + ) -> Tx, Gas, Data, RH> + where + EgldValue: TxEgldValue, + { + self.payment(Egld(egld_value)) + } + + /// Backwards compatibility. Use method `egld` instead. + pub fn with_egld_transfer( + self, + egld_amount: BigUint, + ) -> Tx, Gas, Data, RH> { + self.egld(egld_amount) + } + + /// Adds the first single, owned ESDT token payment to a transaction. + /// + /// Since this is the first ESDT payment, a single payment tx is produced. + /// + /// Can subsequently be called again for multiple payments. + pub fn esdt>>( + self, + payment: P, + ) -> Tx, Gas, Data, RH> { + self.payment(payment.into()) + } + + /// Sets a single token payment, with the token identifier and amount kept as references. + /// + /// This is handy whem we only want one ESDT transfer and we want to avoid unnecessary object clones. + pub fn single_esdt<'a>( + self, + token_identifier: &'a TokenIdentifier, + token_nonce: u64, + amount: &'a BigUint, + ) -> Tx, Gas, Data, RH> { + self.payment(EsdtTokenPaymentRefs { + token_identifier, + token_nonce, + amount, + }) + } + + /// Syntactic sugar for `self.payment(EgldOrEsdtTokenPaymentRefs::new(...)`. Takes references. + pub fn egld_or_single_esdt<'a>( + self, + token_identifier: &'a EgldOrEsdtTokenIdentifier, + token_nonce: u64, + amount: &'a BigUint, + ) -> Tx, Gas, Data, RH> { + self.payment(EgldOrEsdtTokenPaymentRefs::new( + token_identifier, + token_nonce, + amount, + )) + } + + /// Sets a collection of ESDT transfers as the payment of the transaction. + /// + /// Can be formed from single ESDT payments, but the result will always be a collection. + /// + /// Always converts the argument into an owned collection of ESDT payments. For work with references, use `.payment(&p)` instead. + pub fn multi_esdt( + self, + payments: IntoMulti, + ) -> Tx, Gas, Data, RH> + where + IntoMulti: Into>, + { + self.payment(payments.into()) + } + + /// Backwards compatibility. + pub fn with_esdt_transfer>>( + self, + payment: P, + ) -> Tx, Gas, Data, RH> { + self.payment(MultiEsdtPayment::new()) + .with_esdt_transfer(payment) + } + + /// Backwards compatibility. + pub fn with_multi_token_transfer( + self, + payments: MultiEsdtPayment, + ) -> Tx, Gas, Data, RH> { + self.multi_esdt(payments) + } + + /// Backwards compatibility. + pub fn with_egld_or_single_esdt_transfer>>( + self, + payment: P, + ) -> Tx, Gas, Data, RH> { + self.payment(payment.into()) + } + + /// Converts argument to `EgldOrMultiEsdtPayment`, then sets it as payment. + /// + /// In most cases, `payment` should be used instead. + pub fn egld_or_multi_esdt>>( + self, + payment: P, + ) -> Tx, Gas, Data, RH> { + self.payment(payment.into()) + } +} + +impl Tx, Gas, Data, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, + Data: TxData, + RH: TxResultHandler, +{ + /// Adds the second ESDT token transfer to a contract call. + /// + /// Can be called multiple times on the same call. + /// + /// When the Tx already contains a single (owned) ESDT payment, + /// adding the second one will convert it to a list. + pub fn esdt>>( + self, + payment: P, + ) -> Tx, Gas, Data, RH> { + let mut payments = ManagedVec::new(); + payments.push(self.payment); + payments.push(payment.into()); + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: payments, + gas: self.gas, + data: self.data, + result_handler: self.result_handler, + } + } +} + +impl Tx, Gas, Data, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, + Data: TxData, + RH: TxResultHandler, +{ + /// Adds a single ESDT token transfer to a contract call. + /// + /// Can be called multiple times on the same call. + pub fn esdt>>( + mut self, + payment: P, + ) -> Tx, Gas, Data, RH> { + self.payment.push(payment.into()); + self + } + + /// When the Tx already contains an owned collection of ESDT payments, + /// calling `multi_esdt` is equivalent to `esdt`, it just adds another payment to the list. + /// + /// Can be called multiple times. + pub fn multi_esdt>>( + self, + payment: P, + ) -> Tx, Gas, Data, RH> { + self.esdt(payment) + } + + /// Backwards compatibility. + pub fn with_esdt_transfer>>( + self, + payment: P, + ) -> Tx, Gas, Data, RH> { + self.multi_esdt(payment) + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Data: TxData, + RH: TxResultHandler, +{ + /// Sets an explicit gas limit to the call. + #[inline] + pub fn gas( + self, + gas_value: GasValue, + ) -> Tx, Data, RH> + where + GasValue: TxGasValue, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: ExplicitGas(gas_value), + data: self.data, + result_handler: self.result_handler, + } + } + + /// Backwards compatibility. + #[inline] + pub fn with_gas_limit( + self, + gas_limit: u64, + ) -> Tx, Data, RH> { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: ExplicitGas(gas_limit), + data: self.data, + result_handler: self.result_handler, + } + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + RH: TxResultHandler, +{ + /// Sets the data field. Do not use directly. + #[inline] + #[doc(hidden)] + pub fn raw_data(self, data: Data) -> Tx + where + Data: TxData, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data, + result_handler: self.result_handler, + } + } + + /// Starts a contract call, serialized by hand. + /// + /// Whenever possible, should use proxies instead, since manual serialization is not type-safe. + #[inline] + pub fn raw_call>>( + self, + function_name: N, + ) -> Tx, RH> { + self.raw_data(FunctionCall::new(function_name)) + } +} + +impl Tx, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + RH: TxResultHandler, +{ + /// Converts tx to a simple FunctionCall, to be used as argument or data in contracts. + pub fn into_function_call(self) -> FunctionCall { + self.data + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + Payment: TxPayment, + Gas: TxGas, +{ + /// Merges the argument data into the current tx. + /// Used for function calls originating in legacy proxies. + /// + /// Different environment in the argument allowed because of compatibility with old proxies. + /// + /// Method still subject to considerable change. + pub fn legacy_proxy_call( + self, + call: Tx, OriginalResultMarker>, + ) -> Tx, OriginalResultMarker> + where + Env2: TxEnv, + To: TxTo + TxTo, + { + Tx { + env: self.env, + from: self.from, + to: call.to, + payment: self.payment, + gas: self.gas, + data: call.data, + result_handler: call.result_handler, + } + } +} + +impl Tx, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + RH: TxResultHandler, +{ + /// Adds argument to function call. + /// + /// Whenever possible, use proxies instead. + /// + /// It serializes the value, but does not enforce type safety. + #[inline] + pub fn argument(mut self, arg: &T) -> Self { + self.data = self.data.argument(arg); + self + } + + /// Adds serialized argument to function call. + /// + /// Whenever possible, use proxies instead. + /// + /// Doesa not serialize, does not enforce type safety. + #[inline] + pub fn arguments_raw(mut self, raw: ManagedArgBuffer) -> Self { + self.data.arg_buffer = raw; + self + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + Data: TxData, +{ + /// Type marker to set the original contract or VM function return type. + /// + /// Only the compile-time type annotation is given. + #[inline] + pub fn original_result( + self, + ) -> Tx> { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: OriginalResultMarker::new(), + } + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Starts a proxy call, deploy, or upgrade. + /// + /// The proxy object will be given, the subsequent call will be from a proxy context, containing all the contract endpoint names. + pub fn typed(self, proxy: Proxy) -> Proxy::TxProxyMethods + where + Proxy: TxProxyTrait, + { + proxy.proxy_methods(self) + } +} + +impl + Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + Data: TxData, + ResultList: RHList, +{ + /// Adds a result handler that doesn't return anything. + #[inline] + pub fn with_result( + self, + result_handler: ResultHandler, + ) -> Tx + where + ResultHandler: RHListItem, + ResultList: RHListAppendNoRet, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: self.result_handler.append_no_ret(result_handler), + } + } + + /// Adds a result handler that can also return processed data. + #[inline] + pub fn returns( + self, + item: RH, + ) -> Tx + where + RH: RHListItem, + ResultList: RHListAppendRet, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: self.result_handler.append_ret(item), + } + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + RH: TxResultHandler, +{ + /// Starts a contract deploy call, serialized by hand. + /// + /// Whenever possible, should use proxies instead, since manual serialization is not type-safe. + pub fn raw_deploy(self) -> Tx, RH> { + self.raw_data(DeployCall::default()) + } +} + +impl Tx, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + RH: TxResultHandler, +{ + /// Sets upgrade code source as explicit code bytes. + pub fn code( + self, + code: CodeValue, + ) -> Tx>, RH> + where + CodeValue: TxCodeValue, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data.code_source(Code(code)), + result_handler: self.result_handler, + } + } + + /// Sets upgrade code source as another deployed contract code. + pub fn from_source( + self, + source_address: FromSourceValue, + ) -> Tx>, RH> + where + FromSourceValue: TxFromSourceValue, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data.code_source(FromSource(source_address)), + result_handler: self.result_handler, + } + } +} + +impl Tx, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + RH: TxResultHandler, +{ + /// Sets deploy code source as explicit code bytes. + pub fn code( + self, + code: CodeValue, + ) -> Tx>, RH> + where + CodeValue: TxCodeValue, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data.code_source(Code(code)), + result_handler: self.result_handler, + } + } + + /// Sets deploy code source as another deployed contract code. + pub fn from_source( + self, + source_address: FromSourceValue, + ) -> Tx>, RH> + where + FromSourceValue: TxFromSourceValue, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data.code_source(FromSource(source_address)), + result_handler: self.result_handler, + } + } +} + +impl + Tx, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + CodeSource: TxCodeSource, + RH: TxResultHandler, +{ + /// Sets code metadata to deploy. + pub fn code_metadata(mut self, code_metadata: CodeMetadata) -> Self { + self.data = self.data.code_metadata(code_metadata); + self + } + + /// Adds argument to a contract deploy. + /// + /// Whenever possible, use proxies instead. + /// + /// It serializes the value, but does not enforce type safety. + #[inline] + pub fn argument(mut self, arg: &T) -> Self { + self.data = self.data.argument(arg); + self + } + + /// Adds serialized argument to a contract deploy. + /// + /// Whenever possible, use proxies instead. + /// + /// Doesa not serialize, does not enforce type safety. + #[inline] + pub fn arguments_raw(mut self, raw: ManagedArgBuffer) -> Self { + self.data.arg_buffer = raw; + self + } +} + +impl + Tx, RH> +where + Env: TxEnvMockDeployAddress, + From: TxFromSpecified, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + CodeSource: TxCodeSource, + RH: TxResultHandler, +{ + /// Sets the new mock address to be used for the newly deployed contract. + /// + /// Only allowed in tests. + pub fn new_address(mut self, new_address: NA) -> Self + where + NA: AnnotatedValue>, + { + self.env.mock_deploy_new_address(&self.from, new_address); + self + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + RH: TxResultHandler, +{ + /// Starts a contract deploy upgrade, serialized by hand. + /// + /// Whenever possible, should use proxies instead, since manual serialization is not type-safe. + pub fn raw_upgrade(self) -> Tx, RH> { + self.raw_data(UpgradeCall::default()) + } +} + +impl + Tx, RH> +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + CodeSource: TxCodeSource, + RH: TxResultHandler, +{ + pub fn code_metadata(mut self, code_metadata: CodeMetadata) -> Self { + self.data = self.data.code_metadata(code_metadata); + self + } + + /// Adds argument to upgrade call. + /// + /// Whenever possible, use proxies instead. + /// + /// It serializes the value, but does not enforce type safety. + #[inline] + pub fn argument(mut self, arg: &T) -> Self { + self.data = self.data.argument(arg); + self + } + + /// Adds serialized argument to an upgrade call. + /// + /// Whenever possible, use proxies instead. + /// + /// Doesa not serialize, does not enforce type safety. + #[inline] + pub fn arguments_raw(mut self, raw: ManagedArgBuffer) -> Self { + self.data.arg_buffer = raw; + self + } +} + +impl Tx +where + Env: TxEnvWithTxHash, + From: TxFromSpecified, + To: TxTo, + Payment: TxPaymentEgldOnly, + Gas: TxGas, + Data: TxDataFunctionCall, + RH: TxResultHandler, +{ + /// Sets the mock transaction hash to be used in a test. + /// + /// Only allowed in tests. + pub fn tx_hash(mut self, tx_hash: H) -> Self + where + H256: core::convert::From, + { + self.env.set_tx_hash(H256::from(tx_hash)); + self + } +} + +impl + From< + Tx< + TxScEnv, + (), + To, + Payment, + (), + DeployCall, ()>, + OriginalResultMarker, + >, + > for ContractDeploy +where + Api: CallTypeApi + 'static, + To: TxTo>, + Payment: TxPaymentEgldOnly>, + OriginalResult: TopEncodeMulti, +{ + fn from( + value: Tx< + TxScEnv, + (), + To, + Payment, + (), + DeployCall, ()>, + OriginalResultMarker, + >, + ) -> Self { + ContractDeploy { + _phantom: core::marker::PhantomData, + to: ManagedOption::none(), + egld_payment: value.payment.into_egld_payment(&value.env), + explicit_gas_limit: UNSPECIFIED_GAS_LIMIT, + arg_buffer: value.data.arg_buffer, + _return_type: core::marker::PhantomData, + } + } +} + +// Conversion from new syntax to old syntax. +impl ContractCallBase + for Tx< + TxScEnv, + (), + To, + Payment, + (), + FunctionCall, + OriginalResultMarker, + > +where + Api: CallTypeApi + 'static, + To: TxToSpecified>, + Payment: TxPayment>, + OriginalResult: TopEncodeMulti, +{ + type OriginalResult = OriginalResult; + + fn into_normalized(self) -> ContractCallWithEgld { + self.payment.with_normalized( + &self.env, + &self.from, + self.to, + self.data, + |norm_to, norm_egld, norm_fc| ContractCallWithEgld { + basic: ContractCallNoPayment { + _phantom: core::marker::PhantomData, + to: norm_to.clone(), + function_call: norm_fc.clone(), + explicit_gas_limit: UNSPECIFIED_GAS_LIMIT, + _return_type: core::marker::PhantomData, + }, + egld_payment: norm_egld.clone(), + }, + ) + } +} diff --git a/framework/base/src/types/interaction/tx_data.rs b/framework/base/src/types/interaction/tx_data.rs new file mode 100644 index 0000000000..ddab631b1a --- /dev/null +++ b/framework/base/src/types/interaction/tx_data.rs @@ -0,0 +1,69 @@ +mod deploy_call; +mod function_call; +mod tx_code_source; +mod upgrade_call; + +pub use deploy_call::DeployCall; +pub use function_call::FunctionCall; +pub use tx_code_source::*; +pub use upgrade_call::UpgradeCall; + +use crate::{ + formatter::SCLowerHex, + types::{ManagedBuffer, ManagedBufferBuilder}, +}; + +use super::TxEnv; + +/// Marks the data field of a transaction in `Tx`. +/// +/// Can be nothing, deploy data, call data, etc. +pub trait TxData +where + Env: TxEnv, +{ + fn is_no_call(&self) -> bool; + + fn to_call_data_string(&self) -> ManagedBuffer; +} + +pub trait TxDataFunctionCall: TxData + Into> +where + Env: TxEnv, +{ +} + +impl TxData for () +where + Env: TxEnv, +{ + fn is_no_call(&self) -> bool { + true + } + + fn to_call_data_string(&self) -> ManagedBuffer { + ManagedBuffer::new() + } +} + +impl TxDataFunctionCall for () where Env: TxEnv {} + +impl TxData for FunctionCall +where + Env: TxEnv, +{ + fn is_no_call(&self) -> bool { + self.is_empty() + } + + fn to_call_data_string(&self) -> ManagedBuffer { + let mut result = ManagedBufferBuilder::default(); + result.append_managed_buffer(&self.function_name); + for arg in self.arg_buffer.raw_arg_iter() { + result.append_bytes(b"@"); + SCLowerHex::fmt(&*arg, &mut result); + } + result.into_managed_buffer() + } +} +impl TxDataFunctionCall for FunctionCall where Env: TxEnv {} diff --git a/framework/base/src/types/interaction/tx_data/deploy_call.rs b/framework/base/src/types/interaction/tx_data/deploy_call.rs new file mode 100644 index 0000000000..a742901736 --- /dev/null +++ b/framework/base/src/types/interaction/tx_data/deploy_call.rs @@ -0,0 +1,90 @@ +use multiversx_sc_codec::TopEncodeMulti; + +use crate::types::{CodeMetadata, ManagedArgBuffer, ManagedBuffer, ManagedBufferCachedBuilder}; + +use super::{TxCodeSource, TxData, TxEnv}; + +/// Holds deploy data: code, code metadata, and arguments. +pub struct DeployCall +where + Env: TxEnv, + CodeSource: TxCodeSource, +{ + pub code_source: CodeSource, + pub code_metadata: CodeMetadata, + pub arg_buffer: ManagedArgBuffer, +} + +impl Default for DeployCall +where + Env: TxEnv, +{ + fn default() -> DeployCall { + DeployCall { + code_source: (), + code_metadata: CodeMetadata::DEFAULT, + arg_buffer: ManagedArgBuffer::new(), + } + } +} + +impl TxData for DeployCall +where + Env: TxEnv, + CodeSource: TxCodeSource, +{ + fn is_no_call(&self) -> bool { + false + } + + fn to_call_data_string(&self) -> ManagedBuffer { + // Implement as needed for deployment-specific data + let result = ManagedBufferCachedBuilder::default(); + // result.append_managed_buffer(&self.code); + // Add other fields as needed + result.into_managed_buffer() + } +} + +impl DeployCall +where + Env: TxEnv, +{ + pub fn code_source(self, code_source: CodeSource) -> DeployCall + where + CodeSource: TxCodeSource, + { + DeployCall { + code_source, + code_metadata: self.code_metadata, + arg_buffer: self.arg_buffer, + } + } +} + +impl DeployCall +where + Env: TxEnv, + CodeSource: TxCodeSource, +{ + pub fn code_metadata(mut self, code_metadata: CodeMetadata) -> Self + where + CodeSource: TxCodeSource, + { + self.code_metadata = code_metadata; + self + } + + /// Adds an argument of any serializable type. + /// + /// Multi-values are accepted. No type checking performed. + pub fn argument(mut self, arg: &T) -> Self { + self.arg_buffer.push_multi_arg(arg); + self + } + + pub fn arguments_raw(mut self, raw: ManagedArgBuffer) -> Self { + self.arg_buffer = raw; + self + } +} diff --git a/framework/base/src/types/interaction/function_call.rs b/framework/base/src/types/interaction/tx_data/function_call.rs similarity index 75% rename from framework/base/src/types/interaction/function_call.rs rename to framework/base/src/types/interaction/tx_data/function_call.rs index 94740624f5..7ebf20dd1a 100644 --- a/framework/base/src/types/interaction/function_call.rs +++ b/framework/base/src/types/interaction/tx_data/function_call.rs @@ -4,23 +4,21 @@ use multiversx_sc_codec::{ }; use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::{ - ManagedTypeApi, ESDT_MULTI_TRANSFER_FUNC_NAME, ESDT_NFT_TRANSFER_FUNC_NAME, + CallTypeApi, ManagedTypeApi, ESDT_MULTI_TRANSFER_FUNC_NAME, ESDT_NFT_TRANSFER_FUNC_NAME, ESDT_TRANSFER_FUNC_NAME, }, - formatter::SCLowerHex, types::{ - EsdtTokenPayment, ManagedAddress, ManagedBuffer, ManagedBufferBuilder, ManagedVec, - MultiValueEncoded, + ContractCallNoPayment, EsdtTokenPayment, EsdtTokenPaymentRefs, ManagedAddress, + ManagedArgBuffer, ManagedBuffer, ManagedVec, MultiValueEncoded, TypedFunctionCall, }, }; -use super::ManagedArgBuffer; - /// Encodes a function call on the blockchain, composed of a function name and its encoded arguments. /// /// Can be used as a multi-argument, to embed a call within a call. +#[derive(Clone)] pub struct FunctionCall where Api: ManagedTypeApi, @@ -63,14 +61,34 @@ where self } - pub fn to_call_data_string(&self) -> ManagedBuffer { - let mut result = ManagedBufferBuilder::default(); - result.append_managed_buffer(&self.function_name); - for arg in self.arg_buffer.raw_arg_iter() { - result.append_bytes(b"@"); - SCLowerHex::fmt(&*arg, &mut result); - } - result.into_managed_buffer() + pub fn arguments_raw(mut self, raw: ManagedArgBuffer) -> Self { + self.arg_buffer = raw; + self + } + + pub fn typed_result(self) -> TypedFunctionCall + where + R: TopEncodeMulti + TopDecodeMulti, + { + self.into() + } +} + +impl From<()> for FunctionCall +where + Api: ManagedTypeApi, +{ + fn from(_: ()) -> Self { + FunctionCall::empty() + } +} + +impl From> for FunctionCall +where + Api: CallTypeApi, +{ + fn from(ccnp: ContractCallNoPayment) -> Self { + ccnp.function_call } } @@ -118,14 +136,22 @@ where } } +impl TypeAbiFrom for FunctionCall where Api: ManagedTypeApi {} + impl TypeAbi for FunctionCall where Api: ManagedTypeApi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::>() } + fn type_name_rust() -> TypeName { + "FunctionCall<$API>".into() + } + fn is_variadic() -> bool { true } @@ -136,9 +162,9 @@ where Api: ManagedTypeApi, { /// Constructs `ESDTTransfer` builtin function call. - pub(super) fn convert_to_single_transfer_fungible_call( + pub(crate) fn convert_to_single_transfer_fungible_call( self, - payment: EsdtTokenPayment, + payment: EsdtTokenPaymentRefs<'_, Api>, ) -> FunctionCall { FunctionCall::new(ESDT_TRANSFER_FUNC_NAME) .argument(&payment.token_identifier) @@ -153,10 +179,10 @@ where /// arg1 - nonce /// arg2 - quantity to transfer /// arg3 - destination address - pub(super) fn convert_to_single_transfer_nft_call( + pub(crate) fn convert_to_single_transfer_nft_call( self, to: &ManagedAddress, - payment: EsdtTokenPayment, + payment: EsdtTokenPaymentRefs<'_, Api>, ) -> FunctionCall { FunctionCall::new(ESDT_NFT_TRANSFER_FUNC_NAME) .argument(&payment.token_identifier) @@ -167,16 +193,16 @@ where } /// Constructs `MultiESDTNFTTransfer` builtin function call. - pub(super) fn convert_to_multi_transfer_esdt_call( + pub(crate) fn convert_to_multi_transfer_esdt_call( self, to: &ManagedAddress, - payments: ManagedVec>, + payments: &ManagedVec>, ) -> FunctionCall { let mut result = FunctionCall::new(ESDT_MULTI_TRANSFER_FUNC_NAME) .argument(&to) .argument(&payments.len()); - for payment in payments.into_iter() { + for payment in payments { result = result .argument(&payment.token_identifier) .argument(&payment.token_nonce) diff --git a/framework/base/src/types/interaction/tx_data/tx_code_source.rs b/framework/base/src/types/interaction/tx_data/tx_code_source.rs new file mode 100644 index 0000000000..e7bb0817ea --- /dev/null +++ b/framework/base/src/types/interaction/tx_data/tx_code_source.rs @@ -0,0 +1,65 @@ +use crate::types::{AnnotatedValue, ManagedAddress, ManagedBuffer, TxEnv}; + +pub trait TxCodeSource +where + Env: TxEnv, +{ +} + +impl TxCodeSource for () where Env: TxEnv {} + +pub trait TxCodeSourceSpecified: TxCodeSource +where + Env: TxEnv, +{ +} + +pub trait TxCodeValue: AnnotatedValue> +where + Env: TxEnv, +{ +} + +impl TxCodeValue for ManagedBuffer where Env: TxEnv {} + +/// Contains code for a deploy or upgrade. +pub struct Code(pub CodeValue); + +impl TxCodeSource for Code +where + Env: TxEnv, + CodeValue: TxCodeValue, +{ +} + +impl TxCodeSourceSpecified for Code +where + Env: TxEnv, + CodeValue: TxCodeValue, +{ +} + +pub trait TxFromSourceValue: AnnotatedValue> +where + Env: TxEnv, +{ +} + +impl TxFromSourceValue for ManagedAddress where Env: TxEnv {} + +/// Indicates the source of a "deploy from source" or "upgrade from source". +pub struct FromSource(pub FromSourceValue); + +impl TxCodeSource for FromSource +where + Env: TxEnv, + FromSourceValue: TxFromSourceValue, +{ +} + +impl TxCodeSourceSpecified for FromSource +where + Env: TxEnv, + FromSourceValue: TxFromSourceValue, +{ +} diff --git a/framework/base/src/types/interaction/tx_data/upgrade_call.rs b/framework/base/src/types/interaction/tx_data/upgrade_call.rs new file mode 100644 index 0000000000..591e8accb5 --- /dev/null +++ b/framework/base/src/types/interaction/tx_data/upgrade_call.rs @@ -0,0 +1,91 @@ +use multiversx_sc_codec::TopEncodeMulti; + +use crate::types::{ + CodeMetadata, ManagedArgBuffer, ManagedBuffer, ManagedBufferCachedBuilder, TxCodeSource, + TxData, TxEnv, +}; + +/// Holds deploy data: code, code metadata, and arguments. +pub struct UpgradeCall +where + Env: TxEnv, + CodeSource: TxCodeSource, +{ + pub code_source: CodeSource, + pub code_metadata: CodeMetadata, + pub arg_buffer: ManagedArgBuffer, +} + +impl Default for UpgradeCall +where + Env: TxEnv, +{ + fn default() -> UpgradeCall { + UpgradeCall { + code_source: (), + code_metadata: CodeMetadata::DEFAULT, + arg_buffer: ManagedArgBuffer::new(), + } + } +} + +impl TxData for UpgradeCall +where + Env: TxEnv, + CodeSource: TxCodeSource, +{ + fn is_no_call(&self) -> bool { + false + } + + fn to_call_data_string(&self) -> ManagedBuffer { + // Implement as needed for deployment-specific data + let result = ManagedBufferCachedBuilder::default(); + // result.append_managed_buffer(&self.code); + // Add other fields as needed + result.into_managed_buffer() + } +} + +impl UpgradeCall +where + Env: TxEnv, +{ + pub fn code_source(self, code_source: CodeSource) -> UpgradeCall + where + CodeSource: TxCodeSource, + { + UpgradeCall { + code_source, + code_metadata: self.code_metadata, + arg_buffer: self.arg_buffer, + } + } +} + +impl UpgradeCall +where + Env: TxEnv, + CodeSource: TxCodeSource, +{ + pub fn code_metadata(mut self, code_metadata: CodeMetadata) -> Self + where + CodeSource: TxCodeSource, + { + self.code_metadata = code_metadata; + self + } + + /// Adds an argument of any serializable type. + /// + /// Multi-values are accepted. No type checking performed. + pub fn argument(mut self, arg: &T) -> Self { + self.arg_buffer.push_multi_arg(arg); + self + } + + pub fn arguments_raw(mut self, raw: ManagedArgBuffer) -> Self { + self.arg_buffer = raw; + self + } +} diff --git a/framework/base/src/types/interaction/tx_env.rs b/framework/base/src/types/interaction/tx_env.rs new file mode 100644 index 0000000000..37e18d7dec --- /dev/null +++ b/framework/base/src/types/interaction/tx_env.rs @@ -0,0 +1,30 @@ +use crate::{ + api::CallTypeApi, + types::{heap::H256, ManagedAddress, ManagedBuffer}, +}; + +use super::{AnnotatedValue, TxFromSpecified}; + +pub trait TxEnv: Sized { + type Api: CallTypeApi; + + /// Type built by result handlers that translates into the "expect" section in scenarios. + type RHExpect: Default; + + fn resolve_sender_address(&self) -> ManagedAddress; + + fn default_gas_annotation(&self) -> ManagedBuffer; + + fn default_gas_value(&self) -> u64; +} + +pub trait TxEnvMockDeployAddress: TxEnv { + fn mock_deploy_new_address(&mut self, from: &From, new_address: NA) + where + From: TxFromSpecified, + NA: AnnotatedValue>; +} + +pub trait TxEnvWithTxHash: TxEnv { + fn set_tx_hash(&mut self, tx_hash: H256); +} diff --git a/framework/base/src/types/interaction/tx_exec.rs b/framework/base/src/types/interaction/tx_exec.rs new file mode 100644 index 0000000000..0ee6371b72 --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec.rs @@ -0,0 +1,37 @@ +mod tx_env_sc; +mod tx_exec_async; +mod tx_exec_async_promises; +mod tx_exec_deploy; +mod tx_exec_sync; +mod tx_exec_te; +mod tx_exec_upgrade; + +pub use tx_env_sc::*; +pub use tx_exec_async::*; +pub use tx_exec_async_promises::*; +pub use tx_exec_deploy::*; +pub use tx_exec_sync::*; + +use crate::{ + api::CallTypeApi, + io::{ArgErrorHandler, ArgId, ManagedResultArgLoader}, + types::{ManagedBuffer, ManagedVec}, +}; +use multiversx_sc_codec::TopDecodeMulti; + +/// In case of `transfer_execute`, we leave by default a little gas for the calling transaction to finish. +pub(crate) const TRANSFER_EXECUTE_DEFAULT_LEFTOVER: u64 = 100_000; + +pub(crate) fn decode_result( + raw_result: ManagedVec>, +) -> RequestedResult +where + SA: CallTypeApi + 'static, + RequestedResult: TopDecodeMulti, +{ + let mut loader = ManagedResultArgLoader::new(raw_result); + let arg_id = ArgId::from(&b"sync result"[..]); + let h: ArgErrorHandler = ArgErrorHandler::::from(arg_id); + let Ok(result) = RequestedResult::multi_decode_or_handle_err(&mut loader, h); + result +} diff --git a/framework/base/src/types/interaction/tx_exec/tx_env_sc.rs b/framework/base/src/types/interaction/tx_exec/tx_env_sc.rs new file mode 100644 index 0000000000..249d74c2bc --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec/tx_env_sc.rs @@ -0,0 +1,65 @@ +use core::marker::PhantomData; + +use crate::{ + api::{BlockchainApiImpl, CallTypeApi}, + contract_base::BlockchainWrapper, + types::{ + interaction::display_u64, ManagedAddress, ManagedBuffer, Tx, TxBaseWithEnv, TxEnv, + TRANSFER_EXECUTE_DEFAULT_LEFTOVER, + }, +}; + +/// The transaction environment used in calls launched from a SC. +/// +/// Contains no data, just a generic type for the (also zero-sized) API. +pub struct TxScEnv +where + Api: CallTypeApi, +{ + _phantom: PhantomData, +} + +impl Default for TxScEnv +where + Api: CallTypeApi, +{ + fn default() -> Self { + Self { + _phantom: PhantomData, + } + } +} + +impl TxBaseWithEnv> +where + Api: CallTypeApi, +{ + pub fn new_tx_from_sc() -> Self { + Tx::new_with_env(TxScEnv::default()) + } +} + +impl TxEnv for TxScEnv +where + Api: CallTypeApi, +{ + type Api = Api; + + type RHExpect = (); + + fn resolve_sender_address(&self) -> ManagedAddress { + BlockchainWrapper::::new().get_sc_address() + } + + fn default_gas_annotation(&self) -> ManagedBuffer { + display_u64(self.default_gas_value()) + } + + fn default_gas_value(&self) -> u64 { + let mut gas_left = Api::blockchain_api_impl().get_gas_left(); + if gas_left > TRANSFER_EXECUTE_DEFAULT_LEFTOVER { + gas_left -= TRANSFER_EXECUTE_DEFAULT_LEFTOVER; + } + gas_left + } +} diff --git a/framework/base/src/types/interaction/tx_exec/tx_exec_async.rs b/framework/base/src/types/interaction/tx_exec/tx_exec_async.rs new file mode 100644 index 0000000000..238b978139 --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec/tx_exec_async.rs @@ -0,0 +1,172 @@ +use crate::{ + api::{CallTypeApi, StorageWriteApi}, + contract_base::SendRawWrapper, + types::{ + CallbackClosure, OriginalResultMarker, Tx, TxData, TxDataFunctionCall, + TxEmptyResultHandler, TxEnv, TxFrom, TxGas, TxPayment, TxResultHandler, TxScEnv, TxTo, + TxToSpecified, + }, +}; + +pub trait TxAsyncCallCallback: TxResultHandler> +where + Api: CallTypeApi, +{ + fn save_callback_closure_to_storage(&self); +} + +impl TxAsyncCallCallback for () +where + Api: CallTypeApi, +{ + fn save_callback_closure_to_storage(&self) {} +} + +impl TxAsyncCallCallback for OriginalResultMarker +where + Api: CallTypeApi, +{ + fn save_callback_closure_to_storage(&self) {} +} + +impl TxResultHandler> for CallbackClosure +where + Api: CallTypeApi, +{ + type OriginalResult = (); +} + +impl TxAsyncCallCallback for CallbackClosure +where + Api: CallTypeApi + StorageWriteApi, +{ + fn save_callback_closure_to_storage(&self) { + self.save_to_storage::(); + } +} + +impl TxResultHandler> for Option> +where + Api: CallTypeApi, +{ + type OriginalResult = (); +} + +impl TxAsyncCallCallback for Option> +where + Api: CallTypeApi + StorageWriteApi, +{ + fn save_callback_closure_to_storage(&self) { + if let Some(closure) = self { + closure.save_callback_closure_to_storage(); + } + } +} + +impl Tx, (), To, Payment, Gas, Data, EmptyRH> +where + Api: CallTypeApi, + To: TxTo>, + Payment: TxPayment>, + Gas: TxGas>, + Data: TxData>, + EmptyRH: TxEmptyResultHandler>, +{ + #[inline] + pub fn callback(self, callback: RH) -> Tx, (), To, Payment, Gas, Data, RH> + where + RH: TxAsyncCallCallback, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: callback, + } + } +} + +impl Tx, (), To, Payment, Gas, FC, EmptyRH> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + FC: TxDataFunctionCall>, + EmptyRH: TxEmptyResultHandler>, +{ + /// Backwards compatibility. + pub fn with_callback(self, callback: RH) -> Tx, (), To, Payment, Gas, FC, RH> + where + RH: TxAsyncCallCallback, + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: callback, + } + } +} + +impl Tx, (), To, Payment, (), FC, RH> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPayment>, + FC: TxDataFunctionCall>, + RH: TxAsyncCallCallback, +{ + pub fn async_call_and_exit(self) -> ! { + self.result_handler.save_callback_closure_to_storage(); + self.payment.with_normalized( + &self.env, + &self.from, + self.to, + self.data.into(), + |norm_to, norm_egld, norm_fc| { + SendRawWrapper::::new().async_call_raw( + norm_to, + norm_egld, + &norm_fc.function_name, + &norm_fc.arg_buffer, + ) + }, + ) + } + + pub fn call_and_exit(self) -> ! { + self.async_call_and_exit() + } +} + +impl Tx +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Payment: TxPayment, + Gas: TxGas, + Data: TxData, + RH: TxResultHandler, +{ + /// Backwards compatibility only. + #[inline] + pub fn async_call(self) -> Tx { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: self.result_handler, + } + } +} diff --git a/framework/base/src/types/interaction/tx_exec/tx_exec_async_promises.rs b/framework/base/src/types/interaction/tx_exec/tx_exec_async_promises.rs new file mode 100644 index 0000000000..ad8d8d4145 --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec/tx_exec_async_promises.rs @@ -0,0 +1,192 @@ +use crate::{ + api::{const_handles, CallTypeApi}, + contract_base::SendRawWrapper, + types::{ + interaction::callback_closure::CallbackClosureWithGas, CallbackClosure, ExplicitGas, + FunctionCall, ManagedBuffer, ManagedType, OriginalResultMarker, Tx, TxGas, TxGasValue, + TxPayment, TxResultHandler, TxScEnv, TxToSpecified, + }, +}; + +pub trait TxPromisesCallback: TxResultHandler> +where + Api: CallTypeApi, +{ + fn callback_name(&self) -> &'static str; + + fn overwrite_with_serialized_args(&self, cb_closure_args_serialized: &mut ManagedBuffer); + + fn gas_for_callback(&self) -> u64; +} + +impl TxPromisesCallback for () +where + Api: CallTypeApi, +{ + fn callback_name(&self) -> &'static str { + "" + } + + fn overwrite_with_serialized_args(&self, cb_closure_args_serialized: &mut ManagedBuffer) { + cb_closure_args_serialized.overwrite(&[]); + } + + fn gas_for_callback(&self) -> u64 { + 0 + } +} + +impl TxPromisesCallback for OriginalResultMarker +where + Api: CallTypeApi, +{ + fn callback_name(&self) -> &'static str { + "" + } + + fn overwrite_with_serialized_args(&self, cb_closure_args_serialized: &mut ManagedBuffer) { + cb_closure_args_serialized.overwrite(&[]); + } + + fn gas_for_callback(&self) -> u64 { + 0 + } +} + +impl TxPromisesCallback for CallbackClosure +where + Api: CallTypeApi, +{ + fn callback_name(&self) -> &'static str { + self.callback_name + } + + fn overwrite_with_serialized_args(&self, cb_closure_args_serialized: &mut ManagedBuffer) { + self.closure_args + .serialize_overwrite(cb_closure_args_serialized); + } + + fn gas_for_callback(&self) -> u64 { + 0u64 + } +} + +impl TxResultHandler> for CallbackClosureWithGas +where + Api: CallTypeApi, +{ + type OriginalResult = (); +} + +impl TxPromisesCallback for CallbackClosureWithGas +where + Api: CallTypeApi, +{ + fn callback_name(&self) -> &'static str { + self.closure.callback_name + } + + fn overwrite_with_serialized_args(&self, cb_closure_args_serialized: &mut ManagedBuffer) { + self.closure + .closure_args + .serialize_overwrite(cb_closure_args_serialized); + } + + fn gas_for_callback(&self) -> u64 { + self.gas_for_callback + } +} + +impl + Tx, (), To, Payment, Gas, FunctionCall, CallbackClosure> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, +{ + pub fn gas_for_callback( + self, + gas: u64, + ) -> Tx, (), To, Payment, Gas, FunctionCall, CallbackClosureWithGas> + { + Tx { + env: self.env, + from: self.from, + to: self.to, + payment: self.payment, + gas: self.gas, + data: self.data, + result_handler: CallbackClosureWithGas { + closure: self.result_handler, + gas_for_callback: gas, + }, + } + } + + /// Backwards compatibility. + pub fn with_extra_gas_for_callback( + self, + gas: u64, + ) -> Tx, (), To, Payment, Gas, FunctionCall, CallbackClosureWithGas> + { + self.gas_for_callback(gas) + } +} + +impl + Tx, (), To, Payment, ExplicitGas, FunctionCall, Callback> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPayment>, + GasValue: TxGasValue>, + Callback: TxPromisesCallback, +{ + pub fn register_promise(self) { + let callback_name = self.result_handler.callback_name(); + let mut cb_closure_args_serialized = + ManagedBuffer::::from_raw_handle(const_handles::MBUF_TEMPORARY_1); + self.result_handler + .overwrite_with_serialized_args(&mut cb_closure_args_serialized); + let extra_gas_for_callback = self.result_handler.gas_for_callback(); + let gas = self.gas.gas_value(&self.env); + + self.payment.with_normalized( + &self.env, + &self.from, + self.to, + self.data, + |norm_to, norm_egld, norm_fc| { + SendRawWrapper::::new().create_async_call_raw( + norm_to, + norm_egld, + &norm_fc.function_name, + &norm_fc.arg_buffer, + callback_name, + callback_name, + gas, + extra_gas_for_callback, + &cb_closure_args_serialized, + ) + }, + ) + } +} + +impl + Tx, (), To, Payment, Gas, FunctionCall, Callback> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + Payment: TxPayment>, + Callback: TxPromisesCallback, +{ + /// Backwards compatibility only. + #[inline] + pub fn async_call_promise(self) -> Self { + self + } +} diff --git a/framework/base/src/types/interaction/tx_exec/tx_exec_deploy.rs b/framework/base/src/types/interaction/tx_exec/tx_exec_deploy.rs new file mode 100644 index 0000000000..ac93f909e8 --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec/tx_exec_deploy.rs @@ -0,0 +1,283 @@ +use multiversx_sc_codec::{TopDecodeMulti, TopEncodeMulti}; + +use crate::{ + abi::TypeAbiFrom, + api::CallTypeApi, + contract_base::SendRawWrapper, + tuple_util::NestedTupleFlatten, + types::{ + decode_result, Code, CodeMetadata, DeployCall, FromSource, ManagedAddress, ManagedBuffer, + ManagedVec, OriginalResultMarker, RHListExec, Tx, TxCodeValue, TxFromSourceValue, TxGas, + TxPaymentEgldOnly, TxResultHandler, TxScEnv, + }, +}; + +pub struct DeployRawResult +where + Api: CallTypeApi, +{ + pub new_address: ManagedAddress, + pub raw_results: ManagedVec>, +} + +impl + Tx, (), (), Payment, Gas, DeployCall, Code>, RH> +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: TxResultHandler>, +{ + fn execute_deploy_raw(self) -> (ManagedAddress, ManagedVec>, RH) { + let gas_limit = self.gas.gas_value(&self.env); + + let (new_address, raw_results) = self.payment.with_egld_value(&self.env, |egld_value| { + SendRawWrapper::::new().deploy_contract( + gas_limit, + egld_value, + &self.data.code_source.0.into_value(&self.env), + self.data.code_metadata, + &self.data.arg_buffer, + ) + }); + + SendRawWrapper::::new().clean_return_data(); + + (new_address, raw_results, self.result_handler) + } +} + +impl + Tx< + TxScEnv, + (), + (), + Payment, + Gas, + DeployCall, FromSource>, + RH, + > +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + FromSourceValue: TxFromSourceValue>, + RH: TxResultHandler>, +{ + fn execute_deploy_from_source_raw( + self, + ) -> (ManagedAddress, ManagedVec>, RH) { + let gas_limit = self.gas.gas_value(&self.env); + + let (new_address, raw_results) = self.payment.with_egld_value(&self.env, |egld_value| { + SendRawWrapper::::new().deploy_from_source_contract( + gas_limit, + egld_value, + &self.data.code_source.0.into_value(&self.env), + self.data.code_metadata, + &self.data.arg_buffer, + ) + }); + + SendRawWrapper::::new().clean_return_data(); + + (new_address, raw_results, self.result_handler) + } +} + +impl + Tx, (), (), Payment, Gas, DeployCall, Code>, RH> +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: RHListExec, TxScEnv>, + RH::ListReturns: NestedTupleFlatten, +{ + /// Synchronously deploys a contract. + pub fn sync_call(self) -> ::Unpacked { + let (new_address, raw_results, result_handler) = self.execute_deploy_raw(); + + let deploy_raw_result = DeployRawResult { + new_address, + raw_results, + }; + let tuple_result = result_handler.list_process_result(&deploy_raw_result); + tuple_result.flatten_unpack() + } +} + +impl + Tx< + TxScEnv, + (), + (), + Payment, + Gas, + DeployCall, FromSource>, + RH, + > +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + FromSourceValue: TxFromSourceValue>, + RH: RHListExec, TxScEnv>, + RH::ListReturns: NestedTupleFlatten, +{ + /// Synchronously deploys a contract from source. + pub fn sync_call(self) -> ::Unpacked { + let (new_address, raw_results, result_handler) = self.execute_deploy_from_source_raw(); + + let deploy_raw_result = DeployRawResult { + new_address, + raw_results, + }; + let tuple_result = result_handler.list_process_result(&deploy_raw_result); + tuple_result.flatten_unpack() + } +} + +impl + Tx< + TxScEnv, + (), + (), + Payment, + Gas, + DeployCall, ()>, + OriginalResultMarker, + > +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + OriginalResult: TopEncodeMulti, +{ + /// Backwards compatibility, immitates the old API. + /// + /// Note that the data type (the `DeployCall`) doesn't have the code set. + /// This is because the old API was passing it as paramter, so we use it from the `code` argument. + /// + /// Also note that the code metadata is taken from the `code_metadata` argument. + /// If another one was previously set in the `Tx` object, that one will be ignored. + pub fn deploy_contract( + self, + code: &ManagedBuffer, + code_metadata: CodeMetadata, + ) -> (ManagedAddress, RequestedResult) + where + RequestedResult: TopDecodeMulti + TypeAbiFrom, + { + let (new_address, raw_results, _) = self + .code(code.clone()) + .code_metadata(code_metadata) + .execute_deploy_raw(); + + (new_address, decode_result(raw_results)) + } + + /// Backwards compatibility, immitates the old API. + /// + /// Note that the data type (the `DeployCall`) doesn't have the code set. + /// This is because the old API was passing it as paramter, so we use it from the `code` argument. + /// + /// Also note that the code metadata is taken from the `code_metadata` argument. + /// If another one was previously set in the `Tx` object, that one will be ignored. + pub fn deploy_from_source( + self, + source_address: &ManagedAddress, + code_metadata: CodeMetadata, + ) -> (ManagedAddress, RequestedResult) + where + RequestedResult: TopDecodeMulti + TypeAbiFrom, + { + let (new_address, raw_results, _) = self + .from_source(source_address.clone()) + .code_metadata(code_metadata) + .execute_deploy_from_source_raw(); + + (new_address, decode_result(raw_results)) + } +} + +impl + Tx< + TxScEnv, + (), + ManagedAddress, + Payment, + Gas, + DeployCall, ()>, + OriginalResultMarker, + > +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + OriginalResult: TopEncodeMulti, +{ + /// Backwards compatibility, immitates the old API. + /// + /// Should no longer be used, which is why unlike all the rest of the old syntax, was deprecated. + /// + /// Uses a `DeployCall` instead of the correct `UpgradeCall`, because the old syntax did not know about upgrades. + /// + /// Note that the data type (the `DeployCall`) doesn't have the code set. + /// This is because the old API was passing it as paramter, so we use it from the `code` argument. + /// + /// Also note that the code metadata is taken from the `code_metadata` argument. + /// If another one was previously set in the `Tx` object, that one will be ignored. + #[deprecated( + since = "0.49.0", + note = "The legacy upgrade method does not correctly take the upgrade constructor into account. Please switch to the new syntax." + )] + pub fn upgrade_contract(self, code: &ManagedBuffer, code_metadata: CodeMetadata) { + let gas = self.gas.explicit_or_gas_left(&self.env); + self.payment.with_egld_value(&self.env, |egld_value| { + SendRawWrapper::::new().upgrade_contract( + &self.to, + gas, + egld_value, + code, + code_metadata, + &self.data.arg_buffer, + ); + }); + } + + /// Backwards compatibility, immitates the old API. + /// + /// Should no longer be used, which is why unlike all the rest of the old syntax, was deprecated. + /// + /// Uses a `DeployCall` instead of the correct `UpgradeCall`, because the old syntax did not know about upgrades. + /// + /// Note that the data type (the `DeployCall`) doesn't have the code set. + /// This is because the old API was passing it as paramter, so we use it from the `code` argument. + /// + /// Also note that the code metadata is taken from the `code_metadata` argument. + /// If another one was previously set in the `Tx` object, that one will be ignored. + #[deprecated( + since = "0.49.0", + note = "The legacy upgrade method does not correctly take the upgrade constructor into account. Please switch to the new syntax." + )] + pub fn upgrade_from_source( + self, + source_address: &ManagedAddress, + code_metadata: CodeMetadata, + ) { + let gas = self.gas.explicit_or_gas_left(&self.env); + self.payment.with_egld_value(&self.env, |egld_value| { + SendRawWrapper::::new().upgrade_from_source_contract( + &self.to, + gas, + egld_value, + source_address, + code_metadata, + &self.data.arg_buffer, + ); + }); + } +} diff --git a/framework/base/src/types/interaction/tx_exec/tx_exec_sync.rs b/framework/base/src/types/interaction/tx_exec/tx_exec_sync.rs new file mode 100644 index 0000000000..4ab9c29759 --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec/tx_exec_sync.rs @@ -0,0 +1,165 @@ +use multiversx_sc_codec::TopDecodeMulti; + +use crate::{ + api::CallTypeApi, + contract_base::SendRawWrapper, + tuple_util::NestedTupleFlatten, + types::{ + decode_result, BackTransfers, ManagedBuffer, ManagedVec, OriginalResultMarker, RHListExec, + Tx, TxDataFunctionCall, TxGas, TxPayment, TxScEnv, TxToSpecified, + }, +}; + +pub struct SyncCallRawResult(pub ManagedVec>) +where + Api: CallTypeApi; + +impl Tx, (), To, Payment, Gas, FC, RH> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + FC: TxDataFunctionCall>, + RH: RHListExec, TxScEnv>, + RH::ListReturns: NestedTupleFlatten, +{ + fn execute_sync_call_raw(self) -> (ManagedVec>, RH) { + let gas_limit = self.gas.gas_value(&self.env); + + let raw_result = self.payment.with_normalized( + &self.env, + &self.from, + self.to, + self.data.into(), + |norm_to, norm_egld, norm_fc| { + SendRawWrapper::::new().execute_on_dest_context_raw( + gas_limit, + norm_to, + norm_egld, + &norm_fc.function_name, + &norm_fc.arg_buffer, + ) + }, + ); + + SendRawWrapper::::new().clean_return_data(); + + (raw_result, self.result_handler) + } + + /// Executes transaction synchronously. + /// + /// Only works with contracts from the same shard. + pub fn sync_call(self) -> ::Unpacked { + let (raw_result, result_handler) = self.execute_sync_call_raw(); + let sync_raw_result = SyncCallRawResult(raw_result); + let tuple_result = result_handler.list_process_result(&sync_raw_result); + tuple_result.flatten_unpack() + } + + fn execute_sync_call_same_context_raw(self) -> (ManagedVec>, RH) { + let gas_limit = self.gas.gas_value(&self.env); + + let raw_result = self.payment.with_normalized( + &self.env, + &self.from, + self.to, + self.data.into(), + |norm_to, norm_egld, norm_fc| { + SendRawWrapper::::new().execute_on_same_context_raw( + gas_limit, + norm_to, + norm_egld, + &norm_fc.function_name, + &norm_fc.arg_buffer, + ) + }, + ); + + SendRawWrapper::::new().clean_return_data(); + + (raw_result, self.result_handler) + } + + /// Executes transaction synchronously, in the same context (performed in the name of the caller). + /// + /// Only works with contracts from the same shard. + pub fn sync_call_same_context(self) -> ::Unpacked { + let (raw_result, result_handler) = self.execute_sync_call_same_context_raw(); + let sync_raw_result = SyncCallRawResult(raw_result); + let tuple_result = result_handler.list_process_result(&sync_raw_result); + tuple_result.flatten_unpack() + } +} + +impl Tx, (), To, (), Gas, FC, RH> +where + Api: CallTypeApi, + To: TxToSpecified>, + Gas: TxGas>, + FC: TxDataFunctionCall>, + RH: RHListExec, TxScEnv>, + RH::ListReturns: NestedTupleFlatten, +{ + fn execute_sync_call_readonly_raw(self) -> (ManagedVec>, RH) { + let gas_limit = self.gas.gas_value(&self.env); + let function_call = self.data.into(); + + let raw_result = self.to.with_value_ref(&self.env, |to| { + SendRawWrapper::::new().execute_on_dest_context_readonly_raw( + gas_limit, + to, + &function_call.function_name, + &function_call.arg_buffer, + ) + }); + + SendRawWrapper::::new().clean_return_data(); + + (raw_result, self.result_handler) + } + + /// Executes transaction synchronously, in readonly mode (target contract cannot have its state altered). + /// + /// Only works with contracts from the same shard. + pub fn sync_call_readonly(self) -> ::Unpacked { + let (raw_result, result_handler) = self.execute_sync_call_readonly_raw(); + let sync_raw_result = SyncCallRawResult(raw_result); + let tuple_result = result_handler.list_process_result(&sync_raw_result); + tuple_result.flatten_unpack() + } +} + +impl + Tx, (), To, Payment, Gas, FC, OriginalResultMarker> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + FC: TxDataFunctionCall>, +{ + /// Backwards compatibility. + pub fn execute_on_dest_context(self) -> RequestedResult + where + RequestedResult: TopDecodeMulti, + { + let (raw_result, _) = self.execute_sync_call_raw(); + decode_result(raw_result) + } + + /// Backwards compatibility. + pub fn execute_on_dest_context_with_back_transfers( + self, + ) -> (RequestedResult, BackTransfers) + where + RequestedResult: TopDecodeMulti, + { + let result = self.execute_on_dest_context(); + let back_transfers = + crate::contract_base::BlockchainWrapper::::new().get_back_transfers(); + + (result, back_transfers) + } +} diff --git a/framework/base/src/types/interaction/tx_exec/tx_exec_te.rs b/framework/base/src/types/interaction/tx_exec/tx_exec_te.rs new file mode 100644 index 0000000000..b9db7539b9 --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec/tx_exec_te.rs @@ -0,0 +1,64 @@ +use crate::api::CallTypeApi; + +use crate::types::{ + FunctionCall, Tx, TxData, TxEmptyResultHandler, TxFrom, TxGas, TxPayment, TxScEnv, + TxToSpecified, +}; + +impl Tx, From, To, Payment, Gas, FC, RH> +where + Api: CallTypeApi, + From: TxFrom>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + FC: TxData> + Into>, + RH: TxEmptyResultHandler>, +{ + fn transfer_execute_with_gas(self, gas_limit: u64) { + self.to.with_address_ref(&self.env, |to| { + self.payment + .perform_transfer_execute(&self.env, to, gas_limit, self.data.into()); + }); + } + + /// Sends transaction asynchronously, and doesn't wait for callback ("fire and forget".) + pub fn transfer_execute(self) { + let gas_limit: u64; + if self.data.is_no_call() { + if self.payment.is_no_payment(&self.env) { + return; + } else { + gas_limit = 0; + } + } else { + gas_limit = self.gas.gas_value(&self.env); + } + + self.transfer_execute_with_gas(gas_limit); + } +} + +impl Tx, From, To, Payment, (), (), ()> +where + Api: CallTypeApi, + From: TxFrom>, + To: TxToSpecified>, + Payment: TxPayment>, +{ + /// Only allowed for simple transfers. + pub fn transfer(self) { + self.transfer_execute_with_gas(0) + } + + /// Transfers funds, if amount is greater than zero. Does nothing otherwise. + /// + /// Can only used for simple transfers. + pub fn transfer_if_not_empty(self) { + if self.payment.is_no_payment(&self.env) { + return; + } + + self.transfer(); + } +} diff --git a/framework/base/src/types/interaction/tx_exec/tx_exec_upgrade.rs b/framework/base/src/types/interaction/tx_exec/tx_exec_upgrade.rs new file mode 100644 index 0000000000..3222f39356 --- /dev/null +++ b/framework/base/src/types/interaction/tx_exec/tx_exec_upgrade.rs @@ -0,0 +1,147 @@ +use crate::{ + api::CallTypeApi, + contract_base::SendRawWrapper, + proxy_imports::TxToSpecified, + types::{ + Code, CodeMetadata, FromSource, ManagedAddress, ManagedBuffer, Tx, TxCodeValue, + TxEmptyResultHandler, TxFromSourceValue, TxGas, TxPaymentEgldOnly, TxScEnv, UpgradeCall, + }, +}; + +impl + Tx< + TxScEnv, + (), + ManagedAddress, + Payment, + Gas, + UpgradeCall, Code>, + RH, + > +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: TxEmptyResultHandler>, +{ + /// Launches the upgrade async call. + /// + /// TODO: change return type to `!`. + pub fn upgrade_async_call_and_exit(self) { + let gas = self.gas.explicit_or_gas_left(&self.env); + self.payment.with_egld_value(&self.env, |egld_value| { + SendRawWrapper::::new().upgrade_contract( + &self.to, + gas, + egld_value, + &self.data.code_source.0.into_value(&self.env), + self.data.code_metadata, + &self.data.arg_buffer, + ); + }); + } +} + +impl + Tx< + TxScEnv, + (), + ManagedAddress, + Payment, + Gas, + UpgradeCall, FromSource>, + RH, + > +where + Api: CallTypeApi, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + FromSourceValue: TxFromSourceValue>, + RH: TxEmptyResultHandler>, +{ + /// Launches the upgrade from source async call. + /// + /// TODO: change return type to `!`. + pub fn upgrade_async_call_and_exit(self) { + let gas = self.gas.explicit_or_gas_left(&self.env); + self.payment.with_egld_value(&self.env, |egld_value| { + SendRawWrapper::::new().upgrade_from_source_contract( + &self.to, + gas, + egld_value, + &self.data.code_source.0.into_value(&self.env), + self.data.code_metadata, + &self.data.arg_buffer, + ); + }); + } +} + +impl + Tx, (), To, Payment, Gas, UpgradeCall, ()>, RH> +where + Api: CallTypeApi, + To: TxToSpecified>, + Payment: TxPaymentEgldOnly>, + Gas: TxGas>, + RH: TxEmptyResultHandler>, +{ + /// Transition syntax, immitates the old API. + /// + /// Note that the data type (the `UpgradeCall`) doesn't have the code set. + /// This is because the old API was passing it as paramter, so we use it from the `code` argument. + /// + /// Also note that the code metadata is taken from the `code_metadata` argument. + /// If another one was previously set in the `Tx` object, that one will be ignored. + #[deprecated( + since = "0.49.0", + note = "This is a transition syntax, it would not have been reachable before 0.49.0. Use [upgrade_async_call_and_exit] instead." + )] + pub fn upgrade_contract(self, code: &ManagedBuffer, code_metadata: CodeMetadata) { + let gas = self.gas.explicit_or_gas_left(&self.env); + self.payment.with_egld_value(&self.env, |egld_value| { + self.to.with_value_ref(&self.env, |to| { + SendRawWrapper::::new().upgrade_contract( + to, + gas, + egld_value, + code, + code_metadata, + &self.data.arg_buffer, + ); + }); + }); + } + + /// Transition syntax, immitates the old API. + /// + /// Note that the data type (the `UpgradeCall`) doesn't have the code set. + /// This is because the old API was passing it as paramter, so we use it from the `code` argument. + /// + /// Also note that the code metadata is taken from the `code_metadata` argument. + /// If another one was previously set in the `Tx` object, that one will be ignored. + #[deprecated( + since = "0.49.0", + note = "This is a transition syntax, it would not have been reachable before 0.49.0. Use [upgrade_async_call_and_exit] instead." + )] + pub fn upgrade_from_source( + self, + source_address: &ManagedAddress, + code_metadata: CodeMetadata, + ) { + let gas = self.gas.explicit_or_gas_left(&self.env); + self.payment.with_egld_value(&self.env, |egld_value| { + self.to.with_value_ref(&self.env, |to| { + SendRawWrapper::::new().upgrade_from_source_contract( + to, + gas, + egld_value, + source_address, + code_metadata, + &self.data.arg_buffer, + ); + }); + }); + } +} diff --git a/framework/base/src/types/interaction/tx_from.rs b/framework/base/src/types/interaction/tx_from.rs new file mode 100644 index 0000000000..ff5dd73b88 --- /dev/null +++ b/framework/base/src/types/interaction/tx_from.rs @@ -0,0 +1,72 @@ +use crate::types::{heap::Address, ManagedAddress}; + +use super::{AnnotatedValue, TxEnv}; + +/// Marks the sender of any transaction. +pub trait TxFrom +where + Env: TxEnv, +{ + fn resolve_address(&self, env: &Env) -> ManagedAddress; +} + +/// Marks the non-empty sender of a transaction. +/// +/// Enforces the reciipent to be explicitly specified. +pub trait TxFromSpecified: + TxFrom + AnnotatedValue> +where + Env: TxEnv, +{ +} + +impl TxFrom for () +where + Env: TxEnv, +{ + fn resolve_address(&self, env: &Env) -> ManagedAddress { + env.resolve_sender_address() + } +} + +impl TxFrom for ManagedAddress +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + self.clone() + } +} +impl TxFromSpecified for ManagedAddress where Env: TxEnv {} + +impl TxFrom for &ManagedAddress +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + (*self).clone() + } +} +impl TxFromSpecified for &ManagedAddress where Env: TxEnv {} + +impl TxFrom for Address +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + self.into() + } +} + +impl TxFromSpecified for Address where Env: TxEnv {} + +impl TxFrom for &Address +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + ManagedAddress::from_address(self) + } +} + +impl TxFromSpecified for &Address where Env: TxEnv {} diff --git a/framework/base/src/types/interaction/tx_gas.rs b/framework/base/src/types/interaction/tx_gas.rs new file mode 100644 index 0000000000..986361e473 --- /dev/null +++ b/framework/base/src/types/interaction/tx_gas.rs @@ -0,0 +1,61 @@ +use super::{AnnotatedValue, TxEnv}; +use crate::{ + api::{BlockchainApi, BlockchainApiImpl}, + types::ManagedBuffer, +}; + +pub trait TxGas +where + Env: TxEnv, +{ + fn gas_annotation(&self, env: &Env) -> ManagedBuffer; + + fn gas_value(&self, env: &Env) -> u64; + + fn explicit_or_gas_left(&self, env: &Env) -> u64; +} + +impl TxGas for () +where + Env: TxEnv, +{ + fn gas_annotation(&self, env: &Env) -> ManagedBuffer<::Api> { + env.default_gas_annotation() + } + + fn gas_value(&self, env: &Env) -> u64 { + env.default_gas_value() + } + + fn explicit_or_gas_left(&self, _env: &Env) -> u64 { + Env::Api::blockchain_api_impl().get_gas_left() + } +} + +pub trait TxGasValue: AnnotatedValue +where + Env: TxEnv, +{ +} + +impl TxGasValue for u64 where Env: TxEnv {} + +pub struct ExplicitGas(pub GasValue); + +impl TxGas for ExplicitGas +where + Env: TxEnv, + GasValue: TxGasValue, +{ + fn gas_value(&self, env: &Env) -> u64 { + self.0.to_value(env) + } + + fn gas_annotation(&self, env: &Env) -> ManagedBuffer<::Api> { + self.0.annotation(env) + } + + fn explicit_or_gas_left(&self, env: &Env) -> u64 { + self.gas_value(env) + } +} diff --git a/framework/base/src/types/interaction/tx_payment.rs b/framework/base/src/types/interaction/tx_payment.rs new file mode 100644 index 0000000000..e72a5b9fa6 --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment.rs @@ -0,0 +1,115 @@ +mod tx_payment_egld; +mod tx_payment_egld_or_esdt; +mod tx_payment_egld_or_esdt_refs; +mod tx_payment_egld_or_multi_esdt; +mod tx_payment_egld_or_multi_esdt_ref; +mod tx_payment_egld_value; +mod tx_payment_multi_esdt; +mod tx_payment_none; +mod tx_payment_single_esdt; +mod tx_payment_single_esdt_ref; +mod tx_payment_single_esdt_triple; + +pub use tx_payment_egld::{Egld, EgldPayment}; +pub use tx_payment_egld_value::TxEgldValue; +pub use tx_payment_multi_esdt::TxPaymentMultiEsdt; + +use crate::{ + api::ManagedTypeApi, + types::{BigUint, ManagedAddress, ManagedBuffer, MultiEsdtPayment}, +}; + +use super::{AnnotatedValue, FunctionCall, TxEnv, TxFrom, TxToSpecified}; + +/// Describes a payment that is part of a transaction. +pub trait TxPayment +where + Env: TxEnv, +{ + /// Returns true if payment indicates transfer of either non-zero EGLD or ESDT amounts. + fn is_no_payment(&self, env: &Env) -> bool; + + /// Transfer-execute calls have different APIs for different payments types. + /// This method selects between them. + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ); + + /// Converts an ESDT call to a built-in function call, if necessary. + 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; + + /// Payment data to be used by the testing framework. Will be refactored. + fn into_full_payment_data(self, env: &Env) -> FullPaymentData; +} + +/// Marks a payment object that only contains EGLD or nothing at all. +pub trait TxPaymentEgldOnly: TxPayment + AnnotatedValue> +where + Env: TxEnv, +{ + fn with_egld_value(&self, env: &Env, f: F) -> R + where + F: FnOnce(&BigUint) -> R, + { + self.with_value_ref(env, f) + } + + fn into_egld_payment(self, env: &Env) -> BigUint { + self.into_value(env) + } +} + +#[derive(Clone)] +pub struct AnnotatedEgldPayment +where + Api: ManagedTypeApi, +{ + pub value: BigUint, + pub annotation: ManagedBuffer, +} + +impl AnnotatedEgldPayment +where + Api: ManagedTypeApi, +{ + pub fn new_egld(value: BigUint) -> Self { + let annotation = value.to_display(); + AnnotatedEgldPayment { value, annotation } + } +} + +#[derive(Clone)] +pub struct FullPaymentData +where + Api: ManagedTypeApi, +{ + pub egld: Option>, + pub multi_esdt: MultiEsdtPayment, +} + +impl Default for FullPaymentData +where + Api: ManagedTypeApi, +{ + fn default() -> Self { + Self { + egld: None, + multi_esdt: Default::default(), + } + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_egld.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_egld.rs new file mode 100644 index 0000000000..ad0969aca1 --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_egld.rs @@ -0,0 +1,102 @@ +use crate::{ + contract_base::SendRawWrapper, + types::{ + AnnotatedValue, BigUint, ManagedAddress, ManagedBuffer, ManagedVec, TxFrom, TxToSpecified, + }, +}; + +use super::{ + AnnotatedEgldPayment, FullPaymentData, FunctionCall, TxEgldValue, TxEnv, TxPayment, + TxPaymentEgldOnly, +}; + +/// Indicates the EGLD payment in a transaction. +pub struct Egld(pub EgldValue); + +pub type EgldPayment = Egld>; + +impl TxPayment for Egld +where + Env: TxEnv, + EgldValue: TxEgldValue, +{ + fn is_no_payment(&self, env: &Env) -> bool { + self.0.with_value_ref(env, |egld_value| egld_value == &0u32) + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + self.0.with_value_ref(env, |egld_value| { + let _ = SendRawWrapper::::new().direct_egld_execute( + to, + egld_value, + gas_limit, + &fc.function_name, + &fc.arg_buffer, + ); + }) + } + + 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, + { + to.with_address_ref(env, |to_addr| { + self.0 + .with_value_ref(env, |egld_value| f(to_addr, egld_value, &fc)) + }) + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + FullPaymentData { + egld: Some(AnnotatedEgldPayment::new_egld(self.0.into_value(env))), + multi_esdt: ManagedVec::new(), + } + } +} + +impl AnnotatedValue> for Egld +where + Env: TxEnv, + EgldValue: TxEgldValue, +{ + fn annotation(&self, env: &Env) -> ManagedBuffer { + self.0.annotation(env) + } + + fn to_value(&self, env: &Env) -> BigUint { + self.0.to_value(env) + } + + fn into_value(self, env: &Env) -> BigUint { + self.0.into_value(env) + } + + fn with_value_ref(&self, env: &Env, f: F) -> R + where + F: FnOnce(&BigUint) -> R, + { + self.0.with_value_ref(env, f) + } +} + +impl TxPaymentEgldOnly for Egld +where + Env: TxEnv, + EgldValue: TxEgldValue, +{ +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_esdt.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_esdt.rs new file mode 100644 index 0000000000..a4ac0577ff --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_esdt.rs @@ -0,0 +1,101 @@ +use crate::types::{BigUint, Egld, EgldOrEsdtTokenPayment, ManagedAddress, TxFrom, TxToSpecified}; + +use super::{FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +impl TxPayment for &EgldOrEsdtTokenPayment +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.amount == 0u32 + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + self.map_ref_egld_or_esdt( + (to, fc), + |(to, fc), amount| Egld(amount).perform_transfer_execute(env, to, gas_limit, fc), + |(to, fc), esdt_payment| esdt_payment.perform_transfer_execute(env, to, gas_limit, fc), + ) + } + + 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, + { + self.map_ref_egld_or_esdt( + (to, fc, f), + |(to, fc, f), amount| Egld(amount).with_normalized(env, from, to, fc, f), + |(to, fc, f), esdt_payment| esdt_payment.with_normalized(env, from, to, fc, f), + ) + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + self.map_ref_egld_or_esdt( + (), + |(), amount| TxPayment::::into_full_payment_data(Egld(amount), env), + |(), esdt_payment| TxPayment::::into_full_payment_data(esdt_payment, env), + ) + } +} + +impl TxPayment for EgldOrEsdtTokenPayment +where + Env: TxEnv, +{ + fn is_no_payment(&self, env: &Env) -> bool { + (&self).is_no_payment(env) + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + (&self).perform_transfer_execute(env, to, gas_limit, fc) + } + + 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, + { + self.map_egld_or_esdt( + (to, fc, f), + |(to, fc, f), amount| Egld(amount).with_normalized(env, from, to, fc, f), + |(to, fc, f), esdt_payment| esdt_payment.with_normalized(env, from, to, fc, f), + ) + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + self.map_egld_or_esdt( + (), + |(), amount| TxPayment::::into_full_payment_data(Egld(amount), env), + |(), esdt_payment| TxPayment::::into_full_payment_data(esdt_payment, env), + ) + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_esdt_refs.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_esdt_refs.rs new file mode 100644 index 0000000000..fe0bc1352d --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_esdt_refs.rs @@ -0,0 +1,54 @@ +use crate::types::{BigUint, EgldOrEsdtTokenPaymentRefs, ManagedAddress, TxFrom, TxToSpecified}; + +use super::{Egld, FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +impl<'a, Env> TxPayment for EgldOrEsdtTokenPaymentRefs<'a, Env::Api> +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.is_empty() + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + self.map_egld_or_esdt( + fc, + |fc, amount| Egld(amount).perform_transfer_execute(env, to, gas_limit, fc), + |fc, esdt_payment| esdt_payment.perform_transfer_execute(env, to, gas_limit, fc), + ) + } + + 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, + { + self.map_egld_or_esdt( + (to, fc, f), + |(to, fc, f), amount| Egld(amount).with_normalized(env, from, to, fc, f), + |(to, fc, f), esdt_payment| esdt_payment.with_normalized(env, from, to, fc, f), + ) + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + self.map_egld_or_esdt( + (), + |(), amount| TxPayment::::into_full_payment_data(Egld(amount), env), + |(), esdt_payment| TxPayment::::into_full_payment_data(esdt_payment, env), + ) + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_multi_esdt.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_multi_esdt.rs new file mode 100644 index 0000000000..2538383494 --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_multi_esdt.rs @@ -0,0 +1,123 @@ +use crate::types::{BigUint, EgldOrMultiEsdtPayment, ManagedAddress, TxFrom, TxToSpecified}; + +use super::{Egld, FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +impl TxPayment for EgldOrMultiEsdtPayment +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.is_empty() + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + match self { + EgldOrMultiEsdtPayment::Egld(egld_amount) => { + Egld(egld_amount).perform_transfer_execute(env, to, gas_limit, fc) + }, + EgldOrMultiEsdtPayment::MultiEsdt(multi_esdt_payment) => { + multi_esdt_payment.perform_transfer_execute(env, to, gas_limit, fc) + }, + } + } + + 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, + { + match self { + EgldOrMultiEsdtPayment::Egld(egld_amount) => { + Egld(egld_amount).with_normalized(env, from, to, fc, f) + }, + EgldOrMultiEsdtPayment::MultiEsdt(multi_esdt_payment) => { + multi_esdt_payment.with_normalized(env, from, to, fc, f) + }, + } + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + match self { + EgldOrMultiEsdtPayment::Egld(egld_amount) => { + TxPayment::::into_full_payment_data(Egld(egld_amount), env) + }, + EgldOrMultiEsdtPayment::MultiEsdt(multi_esdt_payment) => { + TxPayment::::into_full_payment_data(multi_esdt_payment, env) + }, + } + } +} + +impl TxPayment for &EgldOrMultiEsdtPayment +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.is_empty() + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + match self { + EgldOrMultiEsdtPayment::Egld(egld_amount) => { + Egld(egld_amount).perform_transfer_execute(env, to, gas_limit, fc) + }, + EgldOrMultiEsdtPayment::MultiEsdt(multi_esdt_payment) => { + multi_esdt_payment.perform_transfer_execute(env, to, gas_limit, fc) + }, + } + } + + 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, + { + match self { + EgldOrMultiEsdtPayment::Egld(egld_amount) => { + Egld(egld_amount).with_normalized(env, from, to, fc, f) + }, + EgldOrMultiEsdtPayment::MultiEsdt(multi_esdt_payment) => { + multi_esdt_payment.with_normalized(env, from, to, fc, f) + }, + } + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + match self { + EgldOrMultiEsdtPayment::Egld(egld_amount) => { + TxPayment::::into_full_payment_data(Egld(egld_amount), env) + }, + EgldOrMultiEsdtPayment::MultiEsdt(multi_esdt_payment) => { + TxPayment::::into_full_payment_data(multi_esdt_payment, env) + }, + } + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_multi_esdt_ref.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_multi_esdt_ref.rs new file mode 100644 index 0000000000..2bce84e1ff --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_or_multi_esdt_ref.rs @@ -0,0 +1,63 @@ +use crate::types::{BigUint, EgldOrMultiEsdtPaymentRefs, ManagedAddress, TxFrom, TxToSpecified}; + +use super::{Egld, FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +impl<'a, Env> TxPayment for EgldOrMultiEsdtPaymentRefs<'a, Env::Api> +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.is_empty() + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + match self { + EgldOrMultiEsdtPaymentRefs::Egld(egld_amount) => { + Egld(egld_amount).perform_transfer_execute(env, to, gas_limit, fc); + }, + EgldOrMultiEsdtPaymentRefs::MultiEsdt(multi_esdt_payment) => { + multi_esdt_payment.perform_transfer_execute(env, to, gas_limit, fc); + }, + } + } + + 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, + { + match self { + EgldOrMultiEsdtPaymentRefs::Egld(egld_amount) => { + Egld(egld_amount).with_normalized(env, from, to, fc, f) + }, + EgldOrMultiEsdtPaymentRefs::MultiEsdt(multi_esdt_payment) => { + multi_esdt_payment.with_normalized(env, from, to, fc, f) + }, + } + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + match self { + EgldOrMultiEsdtPaymentRefs::Egld(egld_amount) => { + Egld(egld_amount).into_full_payment_data(env) + }, + EgldOrMultiEsdtPaymentRefs::MultiEsdt(multi_esdt_payment) => { + multi_esdt_payment.into_full_payment_data(env) + }, + } + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_egld_value.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_value.rs new file mode 100644 index 0000000000..99d91b618f --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_egld_value.rs @@ -0,0 +1,14 @@ +use crate::types::{AnnotatedValue, BigUint, ManagedRef}; + +use super::TxEnv; + +pub trait TxEgldValue: AnnotatedValue> +where + Env: TxEnv, +{ +} + +impl TxEgldValue for BigUint where Env: TxEnv {} +impl TxEgldValue for &BigUint where Env: TxEnv {} +impl<'a, Env> TxEgldValue for ManagedRef<'a, Env::Api, BigUint> where Env: TxEnv {} +impl TxEgldValue for u64 where Env: TxEnv {} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_multi_esdt.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_multi_esdt.rs new file mode 100644 index 0000000000..892fd2c114 --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_multi_esdt.rs @@ -0,0 +1,159 @@ +use core::ops::Deref; + +use crate::{ + contract_base::SendRawWrapper, + types::{BigUint, ManagedAddress, ManagedRef, MultiEsdtPayment, TxFrom, TxToSpecified}, +}; + +use super::{FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +/// Indicates that a payment object contains a multi-ESDT payment. +pub trait TxPaymentMultiEsdt: TxPayment +where + Env: TxEnv, +{ +} + +impl TxPaymentMultiEsdt for MultiEsdtPayment where Env: TxEnv {} +impl TxPaymentMultiEsdt for &MultiEsdtPayment where Env: TxEnv {} +impl<'a, Env> TxPaymentMultiEsdt for ManagedRef<'a, Env::Api, MultiEsdtPayment> where + Env: TxEnv +{ +} + +impl TxPayment for &MultiEsdtPayment +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.is_empty() + } + + fn perform_transfer_execute( + self, + _env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + let _ = SendRawWrapper::::new().multi_esdt_transfer_execute( + to, + self, + gas_limit, + &fc.function_name, + &fc.arg_buffer, + ); + } + + 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, + { + match self.len() { + 0 => ().with_normalized(env, from, to, fc, f), + 1 => self.get(0).as_refs().with_normalized(env, from, to, fc, f), + _ => to.with_address_ref(env, |to_addr| { + let fc_conv = fc.convert_to_multi_transfer_esdt_call(to_addr, self); + f(&from.resolve_address(env), &BigUint::zero(), &fc_conv) + }), + } + } + + fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { + FullPaymentData { + egld: None, + multi_esdt: self.clone(), + } + } +} + +impl<'a, Env> TxPayment for ManagedRef<'a, Env::Api, MultiEsdtPayment> +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.deref().is_empty() + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + self.deref() + .perform_transfer_execute(env, to, gas_limit, fc) + } + + 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, + { + self.deref().with_normalized(env, from, to, fc, f) + } + + fn into_full_payment_data(self, env: &Env) -> FullPaymentData { + self.deref().into_full_payment_data(env) + } +} + +impl TxPayment for MultiEsdtPayment +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.is_empty() + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + (&self).perform_transfer_execute(env, to, gas_limit, fc); + } + + 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, + { + (&self).with_normalized(env, from, to, fc, f) + } + + fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { + FullPaymentData { + egld: None, + multi_esdt: self, + } + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_none.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_none.rs new file mode 100644 index 0000000000..fe6016e43b --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_none.rs @@ -0,0 +1,44 @@ +use crate::types::{BigUint, ManagedAddress, TxFrom, TxToSpecified}; + +use super::{Egld, FullPaymentData, FunctionCall, TxEnv, TxPayment, TxPaymentEgldOnly}; + +impl TxPayment for () +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + true + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + Egld(BigUint::zero()).perform_transfer_execute(env, to, gas_limit, fc); + } + + 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, + { + to.with_address_ref(env, |to_addr| f(to_addr, &BigUint::zero(), &fc)) + } + + fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { + FullPaymentData::default() + } +} + +impl TxPaymentEgldOnly for () where Env: TxEnv {} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt.rs new file mode 100644 index 0000000000..975a5d0d78 --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt.rs @@ -0,0 +1,94 @@ +use crate::types::{ + BigUint, EsdtTokenPayment, ManagedAddress, MultiEsdtPayment, TxFrom, TxToSpecified, +}; + +use super::{FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +impl TxPayment for EsdtTokenPayment +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.amount == 0u32 + } + + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + self.as_refs() + .perform_transfer_execute(env, to, gas_limit, fc); + } + + 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, + { + self.as_refs().with_normalized(env, from, to, fc, f) + } + + fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { + FullPaymentData { + egld: None, + multi_esdt: MultiEsdtPayment::from_single_item(self), + } + } +} + +impl TxPayment for &EsdtTokenPayment +where + Env: TxEnv, +{ + #[inline] + fn is_no_payment(&self, _env: &Env) -> bool { + self.amount == 0u32 + } + + #[inline] + fn perform_transfer_execute( + self, + env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + self.as_refs() + .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, + { + self.as_refs().with_normalized(env, from, to, fc, f) + } + + fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { + FullPaymentData { + egld: None, + multi_esdt: MultiEsdtPayment::from_single_item(self.clone()), + } + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_ref.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_ref.rs new file mode 100644 index 0000000000..bc5e2532a8 --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_ref.rs @@ -0,0 +1,79 @@ +use crate::{ + contract_base::SendRawWrapper, + types::{ + BigUint, EsdtTokenPaymentRefs, ManagedAddress, MultiEsdtPayment, TxFrom, TxToSpecified, + }, +}; + +use super::{FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +impl<'a, Env> TxPayment for EsdtTokenPaymentRefs<'a, Env::Api> +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.amount == &0u32 + } + + fn perform_transfer_execute( + self, + _env: &Env, + to: &ManagedAddress, + gas_limit: u64, + fc: FunctionCall, + ) { + if self.token_nonce == 0 { + // fungible ESDT + let _ = SendRawWrapper::::new().transfer_esdt_execute( + to, + self.token_identifier, + self.amount, + gas_limit, + &fc.function_name, + &fc.arg_buffer, + ); + } else { + // non-fungible/semi-fungible ESDT + let _ = SendRawWrapper::::new().transfer_esdt_nft_execute( + to, + self.token_identifier, + self.token_nonce, + self.amount, + gas_limit, + &fc.function_name, + &fc.arg_buffer, + ); + } + } + + 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, + { + to.with_address_ref(env, |to_addr| { + if self.token_nonce == 0 { + let fc_conv = fc.convert_to_single_transfer_fungible_call(self); + f(to_addr, &BigUint::zero(), &fc_conv) + } else { + let fc_conv = fc.convert_to_single_transfer_nft_call(to_addr, self); + f(&from.resolve_address(env), &BigUint::zero(), &fc_conv) + } + }) + } + + fn into_full_payment_data(self, _env: &Env) -> FullPaymentData { + FullPaymentData { + egld: None, + multi_esdt: MultiEsdtPayment::from_single_item(self.to_owned_payment()), + } + } +} diff --git a/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_triple.rs b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_triple.rs new file mode 100644 index 0000000000..c49062eb27 --- /dev/null +++ b/framework/base/src/types/interaction/tx_payment/tx_payment_single_esdt_triple.rs @@ -0,0 +1,44 @@ +use crate::types::{ + BigUint, EsdtTokenPayment, ManagedAddress, TokenIdentifier, TxFrom, TxToSpecified, +}; + +use super::{FullPaymentData, FunctionCall, TxEnv, TxPayment}; + +impl TxPayment for (TokenIdentifier, u64, BigUint) +where + Env: TxEnv, +{ + fn is_no_payment(&self, _env: &Env) -> bool { + self.2 == 0u32 + } + + 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) + } + + 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/interaction/tx_proxy.rs b/framework/base/src/types/interaction/tx_proxy.rs new file mode 100644 index 0000000000..2929a7bc4b --- /dev/null +++ b/framework/base/src/types/interaction/tx_proxy.rs @@ -0,0 +1,45 @@ +use multiversx_sc_codec::TopEncodeMulti; + +use crate::abi::TypeAbiFrom; + +use super::{ + DeployCall, FunctionCall, OriginalResultMarker, Tx, TxEnv, TxFrom, TxGas, TxTo, UpgradeCall, +}; + +/// Defines a proxy object for a smart contract. +pub trait TxProxyTrait +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods; + + /// Creates the associated type that contains the proxy methods implementations. + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods; +} + +/// Alias for a `Tx` generated from a proxy, in `init`. +pub type TxProxyDeploy = + Tx, OriginalResultMarker>; + +/// Alias for a `Tx` generated from a proxy, in an endpoint. +pub type TxProxyCall = + Tx::Api>, OriginalResultMarker>; + +/// Alias for a `Tx` generated from a proxy, in `upgrade`. +pub type TxProxyUpgrade = + Tx, OriginalResultMarker>; + +/// Trait that is automatically implemented for all types that are allowed as proxy inputs. +/// +/// Is automatically implemented for all traits that are `TypeAbiInto + TopEncodeMulti`. +pub trait ProxyArg: TopEncodeMulti {} + +impl ProxyArg for T +where + O: TypeAbiFrom, + T: TopEncodeMulti, +{ +} diff --git a/framework/base/src/types/interaction/tx_result_handler.rs b/framework/base/src/types/interaction/tx_result_handler.rs new file mode 100644 index 0000000000..099d060c44 --- /dev/null +++ b/framework/base/src/types/interaction/tx_result_handler.rs @@ -0,0 +1,33 @@ +use super::TxEnv; + +/// Marks a general result handler, to be used in the transaction unified syntax. +/// +/// Rationale described here: https://twitter.com/andreimmarinica/status/1781371938750841288 +/// +/// Used for: +/// - async callbacks +/// - processing of results in sync calls, tests and interactors. +pub trait TxResultHandler +where + Env: TxEnv, +{ + type OriginalResult; +} + +impl TxResultHandler for () +where + Env: TxEnv, +{ + type OriginalResult = (); +} + +/// Indicates that given result handler is empty, i.e. doesn't cause any side effects and returns nothing. +/// +/// Implemented for `()` and `OriginalResultMarker`. +pub trait TxEmptyResultHandler: TxResultHandler +where + Env: TxEnv, +{ +} + +impl TxEmptyResultHandler for () where Env: TxEnv {} diff --git a/framework/base/src/types/interaction/tx_result_handler_list.rs b/framework/base/src/types/interaction/tx_result_handler_list.rs new file mode 100644 index 0000000000..b66a4ba52e --- /dev/null +++ b/framework/base/src/types/interaction/tx_result_handler_list.rs @@ -0,0 +1,9 @@ +mod original_result; +mod tx_result_handler_list_cons; +mod tx_result_handler_list_exec; +mod tx_result_handler_list_item; + +pub use original_result::OriginalResultMarker; +pub use tx_result_handler_list_cons::*; +pub use tx_result_handler_list_exec::*; +pub use tx_result_handler_list_item::*; diff --git a/framework/base/src/types/interaction/tx_result_handler_list/original_result.rs b/framework/base/src/types/interaction/tx_result_handler_list/original_result.rs new file mode 100644 index 0000000000..175f5c6404 --- /dev/null +++ b/framework/base/src/types/interaction/tx_result_handler_list/original_result.rs @@ -0,0 +1,36 @@ +use core::marker::PhantomData; + +use crate::types::{TxEmptyResultHandler, TxEnv, TxResultHandler}; + +/// Contains no data. +/// +/// Indicates to the compiler the original result type expected from a transaction. +/// +/// Note that the transaction result might be interpreted as a different type, +/// but the originally declared type is required to perform any type checking. +pub struct OriginalResultMarker { + _phantom: PhantomData, +} + +impl Default for OriginalResultMarker { + fn default() -> Self { + Self { + _phantom: Default::default(), + } + } +} + +impl OriginalResultMarker { + pub fn new() -> Self { + Self::default() + } +} + +impl TxResultHandler for OriginalResultMarker +where + Env: TxEnv, +{ + type OriginalResult = O; +} + +impl TxEmptyResultHandler for OriginalResultMarker where Env: TxEnv {} diff --git a/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_cons.rs b/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_cons.rs new file mode 100644 index 0000000000..86a24e8a19 --- /dev/null +++ b/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_cons.rs @@ -0,0 +1,239 @@ +use core::marker::PhantomData; + +use crate::types::{OriginalResultMarker, TxEnv, TxResultHandler}; + +use super::RHListItem; + +pub trait RHList: TxResultHandler +where + Env: TxEnv, +{ + type ListReturns; +} + +pub trait RHListAppendRet: RHList +where + Env: TxEnv, + T: RHListItem, +{ + type RetOutput: RHList; + + fn append_ret(self, t: T) -> Self::RetOutput; +} + +pub trait RHListAppendNoRet: RHList +where + Env: TxEnv, + T: RHListItem, +{ + type NoRetOutput: RHList; + + fn append_no_ret(self, t: T) -> Self::NoRetOutput; +} + +impl RHList for () +where + Env: TxEnv, +{ + type ListReturns = (); +} + +impl RHListAppendRet for () +where + Env: TxEnv, + T: RHListItem, +{ + type RetOutput = ConsRet; + + fn append_ret(self, t: T) -> Self::RetOutput { + ConsRet::new(t, self) + } +} + +impl RHListAppendNoRet for () +where + Env: TxEnv, + T: RHListItem, +{ + type NoRetOutput = ConsNoRet; + + fn append_no_ret(self, t: T) -> Self::NoRetOutput { + ConsNoRet::new(t, self) + } +} + +impl RHList for OriginalResultMarker +where + Env: TxEnv, +{ + type ListReturns = (); +} + +impl RHListAppendRet for OriginalResultMarker +where + Env: TxEnv, + T: RHListItem, +{ + type RetOutput = ConsRet>; + + fn append_ret(self, t: T) -> Self::RetOutput { + ConsRet::new(t, self) + } +} + +impl RHListAppendNoRet for OriginalResultMarker +where + Env: TxEnv, + T: RHListItem, +{ + type NoRetOutput = ConsNoRet>; + + fn append_no_ret(self, t: T) -> Self::NoRetOutput { + ConsNoRet::new(t, self) + } +} + +pub struct ConsRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + _phantom: PhantomData, + pub head: Head, + pub tail: Tail, +} + +impl ConsRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + fn new(head: Head, tail: Tail) -> Self { + ConsRet { + _phantom: PhantomData, + head, + tail, + } + } +} + +impl TxResultHandler for ConsRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + type OriginalResult = Tail::OriginalResult; +} + +impl RHList for ConsRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + type ListReturns = (Head::Returns, Tail::ListReturns); +} + +impl RHListAppendRet for ConsRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList + RHListAppendRet, + T: RHListItem, +{ + type RetOutput = ConsRet>::RetOutput>; + + fn append_ret(self, t: T) -> Self::RetOutput { + ConsRet::new(self.head, self.tail.append_ret(t)) + } +} + +impl RHListAppendNoRet for ConsRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList + RHListAppendNoRet, + T: RHListItem, +{ + type NoRetOutput = ConsRet>::NoRetOutput>; + + fn append_no_ret(self, t: T) -> Self::NoRetOutput { + ConsRet::new(self.head, self.tail.append_no_ret(t)) + } +} + +/// Handlers that return nothing. +pub struct ConsNoRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + _phantom: PhantomData, + pub head: Head, + pub tail: Tail, +} + +impl ConsNoRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + fn new(head: Head, tail: Tail) -> Self { + ConsNoRet { + _phantom: PhantomData, + head, + tail, + } + } +} + +impl TxResultHandler for ConsNoRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + type OriginalResult = Tail::OriginalResult; +} + +impl RHList for ConsNoRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList, +{ + type ListReturns = Tail::ListReturns; +} + +impl RHListAppendRet for ConsNoRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList + RHListAppendRet, + T: RHListItem, +{ + type RetOutput = ConsNoRet>::RetOutput>; + + fn append_ret(self, t: T) -> Self::RetOutput { + ConsNoRet::new(self.head, self.tail.append_ret(t)) + } +} + +impl RHListAppendNoRet for ConsNoRet +where + Env: TxEnv, + Head: RHListItem, + Tail: RHList + RHListAppendNoRet, + T: RHListItem, +{ + type NoRetOutput = ConsNoRet>::NoRetOutput>; + + fn append_no_ret(self, t: T) -> Self::NoRetOutput { + ConsNoRet::new(self.head, self.tail.append_no_ret(t)) + } +} diff --git a/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_exec.rs b/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_exec.rs new file mode 100644 index 0000000000..93f559b4ba --- /dev/null +++ b/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_exec.rs @@ -0,0 +1,98 @@ +use crate::types::{OriginalResultMarker, TxEnv}; + +use super::{ConsNoRet, ConsRet, RHList, RHListItem}; + +/// Indicates how result processing will undergo for one specific result handler. +/// +/// Note that the `ResultType` needs to be the first generic type in the definition, +/// so we can add new implementations of the same result handlers for new raw result types in subsequent crates. +pub trait RHListItemExec: RHListItem +where + Env: TxEnv, +{ + /// Part of the execution pre-processing, each result handler needs to produce an "expect" field, + /// as defined in the environment. + /// + /// The operation is chained, so all result handlers can contribute, hence the `prev` argument, + /// which represents the "expect" field produces by the other result handlers. + /// + /// The default behavior is to leave it unchanged. + fn item_tx_expect(&self, prev: Env::RHExpect) -> Env::RHExpect { + prev + } + + /// The main functionality of a result handler, it either does some computation internally + /// (e.g. execution of a lambda function), or produces a result, or both. + fn item_process_result(self, raw_result: &RawResult) -> Self::Returns; +} + +/// Indicates how result processing will undergo for an ensemble of result handlers. +pub trait RHListExec: RHList +where + Env: TxEnv, +{ + /// Provides the execution pre-processing, in which result handlers collectively produce an "expect" field. + /// + /// The operation starts with the default "expect" field, which normally has all fields unspecified, except + /// for the "status", which is by default set to "0". This means that failing transactions will cause a panic + /// unless explicitly stated in one of the result handlers. + fn list_tx_expect(&self) -> Env::RHExpect; + + /// Aggregates the executions of all result handlers, as configured for a transaction. + fn list_process_result(self, raw_result: &RawResult) -> Self::ListReturns; +} + +impl RHListExec for () +where + Env: TxEnv, +{ + fn list_tx_expect(&self) -> Env::RHExpect { + Env::RHExpect::default() + } + + fn list_process_result(self, _raw_result: &RawResult) -> Self::ListReturns {} +} + +impl RHListExec for OriginalResultMarker +where + Env: TxEnv, +{ + fn list_tx_expect(&self) -> Env::RHExpect { + Env::RHExpect::default() + } + + fn list_process_result(self, _raw_result: &RawResult) -> Self::ListReturns {} +} + +impl RHListExec for ConsRet +where + Env: TxEnv, + Head: RHListItemExec, + Tail: RHListExec, +{ + fn list_tx_expect(&self) -> Env::RHExpect { + self.head.item_tx_expect(self.tail.list_tx_expect()) + } + + fn list_process_result(self, raw_result: &RawResult) -> Self::ListReturns { + let head_result = self.head.item_process_result(raw_result); + let tail_result = self.tail.list_process_result(raw_result); + (head_result, tail_result) + } +} + +impl RHListExec for ConsNoRet +where + Env: TxEnv, + Head: RHListItemExec, + Tail: RHListExec, +{ + fn list_tx_expect(&self) -> Env::RHExpect { + self.head.item_tx_expect(self.tail.list_tx_expect()) + } + + fn list_process_result(self, raw_result: &RawResult) -> Self::ListReturns { + self.head.item_process_result(raw_result); + self.tail.list_process_result(raw_result) + } +} diff --git a/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_item.rs b/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_item.rs new file mode 100644 index 0000000000..54e1d0cfa3 --- /dev/null +++ b/framework/base/src/types/interaction/tx_result_handler_list/tx_result_handler_list_item.rs @@ -0,0 +1,18 @@ +use crate::types::TxEnv; + +/// Result handler list item. +/// +/// It acts as a result handler that produces a single result. +pub trait RHListItem +where + Env: TxEnv, +{ + type Returns; +} + +impl RHListItem for () +where + Env: TxEnv, +{ + type Returns = (); +} diff --git a/framework/base/src/types/interaction/tx_to.rs b/framework/base/src/types/interaction/tx_to.rs new file mode 100644 index 0000000000..ad165a488f --- /dev/null +++ b/framework/base/src/types/interaction/tx_to.rs @@ -0,0 +1,42 @@ +use crate::types::{heap::Address, ManagedAddress}; + +use super::{AnnotatedValue, TxEnv}; + +/// Marks the recipient of any transaction. +pub trait TxTo +where + Env: TxEnv, +{ +} + +impl TxTo for () where Env: TxEnv {} + +/// Marks the non-empty recipient of a transaction. +/// +/// Enforces the reciipent to be explicitly specified. +pub trait TxToSpecified: TxTo + AnnotatedValue> +where + Env: TxEnv, +{ + /// Avoids a clone when performing transfer-execute. + /// + /// Other than that, does thesame as `AnnotatedValue::into_value`. + fn with_address_ref(&self, env: &Env, f: F) -> R + where + F: FnOnce(&ManagedAddress) -> R, + { + self.with_value_ref(env, f) + } +} + +impl TxTo for ManagedAddress where Env: TxEnv {} +impl TxToSpecified for ManagedAddress where Env: TxEnv {} + +impl TxTo for &ManagedAddress where Env: TxEnv {} +impl TxToSpecified for &ManagedAddress where Env: TxEnv {} + +impl TxTo for Address where Env: TxEnv {} +impl TxToSpecified for Address where Env: TxEnv {} + +impl TxTo for &Address where Env: TxEnv {} +impl TxToSpecified for &Address where Env: TxEnv {} diff --git a/framework/base/src/types/io/operation_completion_status.rs b/framework/base/src/types/io/operation_completion_status.rs index 7ae9df69f8..b1da830356 100644 --- a/framework/base/src/types/io/operation_completion_status.rs +++ b/framework/base/src/types/io/operation_completion_status.rs @@ -4,7 +4,7 @@ use multiversx_sc_codec::{ use crate::{ abi::{ - ExplicitEnumVariantDescription, TypeAbi, TypeContents, TypeDescription, + ExplicitEnumVariantDescription, TypeAbi, TypeAbiFrom, TypeContents, TypeDescription, TypeDescriptionContainer, TypeName, }, api::ManagedTypeApi, @@ -77,19 +77,31 @@ impl CodecFrom for ManagedBuffer for crate::types::heap::BoxedBytes {} impl CodecFrom for crate::types::heap::Vec {} +impl TypeAbiFrom for ManagedBuffer {} +impl TypeAbiFrom for crate::types::heap::BoxedBytes {} +impl TypeAbiFrom for crate::types::heap::Vec {} + +impl TypeAbiFrom for OperationCompletionStatus {} + impl TypeAbi for OperationCompletionStatus { + type Unmanaged = Self; + fn type_name() -> TypeName { TypeName::from("OperationCompletionStatus") } + fn type_name_rust() -> TypeName { + TypeName::from("OperationCompletionStatus") + } + fn provide_type_descriptions(accumulator: &mut TDC) { - let type_name = Self::type_name(); + let type_names = Self::type_names(); accumulator.insert( - type_name, + type_names, TypeDescription { docs: Vec::new(), - name: Self::type_name(), + names: Self::type_names(), contents: TypeContents::ExplicitEnum([ ExplicitEnumVariantDescription::new( &["indicates that operation was completed"], @@ -100,6 +112,7 @@ impl TypeAbi for OperationCompletionStatus { INTERRUPTED_STR, ) ].to_vec()), + macro_attributes: Vec::new() }, ); } diff --git a/framework/base/src/types/io/sc_result.rs b/framework/base/src/types/io/sc_result.rs index 6278987b45..0557cd9f94 100644 --- a/framework/base/src/types/io/sc_result.rs +++ b/framework/base/src/types/io/sc_result.rs @@ -1,4 +1,9 @@ -use crate::codec::{EncodeErrorHandler, TopEncodeMulti, TopEncodeMultiOutput}; +use alloc::format; + +use crate::{ + abi::TypeAbiFrom, + codec::{EncodeErrorHandler, TopEncodeMulti, TopEncodeMultiOutput}, +}; use crate::{ abi::{OutputAbis, TypeAbi, TypeDescriptionContainer, TypeName}, @@ -127,11 +132,23 @@ where } } +impl TypeAbiFrom for SCResult {} + impl TypeAbi for SCResult { + type Unmanaged = Self; + fn type_name() -> TypeName { T::type_name() } + fn type_name_rust() -> TypeName { + format!( + "SCResult<{}, {}>", + T::type_name_rust(), + core::any::type_name::() + ) + } + /// Gives `SCResult<()>` the possibility to produce 0 output ABIs, /// just like `()`. /// It is also possible to have `SCResult>`, diff --git a/framework/base/src/types/managed/basic/big_float.rs b/framework/base/src/types/managed/basic/big_float.rs index 83ef5613e3..dd8a04b080 100644 --- a/framework/base/src/types/managed/basic/big_float.rs +++ b/framework/base/src/types/managed/basic/big_float.rs @@ -1,6 +1,7 @@ use super::ManagedBuffer; use crate::{ + abi::{TypeAbi, TypeAbiFrom}, api::{ use_raw_handle, BigFloatApiImpl, ManagedTypeApi, ManagedTypeApiImpl, Sign, StaticVarApiImpl, }, @@ -285,7 +286,14 @@ impl NestedDecode for BigFloat { } } -impl crate::abi::TypeAbi for BigFloat { +impl TypeAbiFrom> for f64 where M: ManagedTypeApi {} + +impl TypeAbiFrom for BigFloat where M: ManagedTypeApi {} +impl TypeAbiFrom<&Self> for BigFloat where M: ManagedTypeApi {} + +impl TypeAbi for BigFloat { + type Unmanaged = f64; + fn type_name() -> String { String::from("BigFloat") } diff --git a/framework/base/src/types/managed/basic/big_int.rs b/framework/base/src/types/managed/basic/big_int.rs index 227a298d02..b73fbab6fa 100644 --- a/framework/base/src/types/managed/basic/big_int.rs +++ b/framework/base/src/types/managed/basic/big_int.rs @@ -1,7 +1,7 @@ use core::{convert::TryInto, marker::PhantomData}; use crate::{ - abi::TypeName, + abi::{TypeAbiFrom, TypeName}, api::{ const_handles, use_raw_handle, BigIntApiImpl, HandleConstraints, ManagedBufferApiImpl, ManagedTypeApi, ManagedTypeApiImpl, RawHandle, StaticVarApiImpl, @@ -101,6 +101,10 @@ macro_rules! big_int_conv_num { } impl CodecFrom<$num_ty> for BigInt {} + impl CodecFrom<&$num_ty> for BigInt {} + + impl TypeAbiFrom<$num_ty> for BigInt {} + impl TypeAbiFrom<&$num_ty> for BigInt {} }; } @@ -298,10 +302,28 @@ impl TopDecode for BigInt { } } +#[cfg(feature = "num-bigint")] +impl TypeAbiFrom for BigInt {} +#[cfg(feature = "num-bigint")] +impl TypeAbiFrom> for crate::codec::num_bigint::BigInt {} + +impl TypeAbiFrom for BigInt where M: ManagedTypeApi {} +impl TypeAbiFrom<&Self> for BigInt where M: ManagedTypeApi {} + impl crate::abi::TypeAbi for BigInt { + #[cfg(feature = "num-bigint")] + type Unmanaged = crate::codec::num_bigint::BigInt; + + #[cfg(not(feature = "num-bigint"))] + type Unmanaged = Self; + fn type_name() -> TypeName { TypeName::from("BigInt") } + + fn type_name_rust() -> TypeName { + TypeName::from("BigInt<$API>") + } } impl BigInt { diff --git a/framework/base/src/types/managed/basic/big_int_sign.rs b/framework/base/src/types/managed/basic/big_int_sign.rs index 5d850afe79..178e55f981 100644 --- a/framework/base/src/types/managed/basic/big_int_sign.rs +++ b/framework/base/src/types/managed/basic/big_int_sign.rs @@ -3,7 +3,7 @@ use crate::codec::{ NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, }; -use crate::abi::TypeName; +use crate::abi::{TypeAbi, TypeAbiFrom, TypeName}; // BigInt sign. #[allow(clippy::enum_variant_names)] @@ -79,8 +79,16 @@ impl TopDecode for Sign { } } -impl crate::abi::TypeAbi for Sign { +impl TypeAbiFrom for Sign {} + +impl TypeAbi for Sign { + type Unmanaged = Self; + fn type_name() -> TypeName { TypeName::from("Sign") } + + fn type_name_rust() -> TypeName { + TypeName::from("multiversx_sc::types::Sign") + } } diff --git a/framework/base/src/types/managed/basic/big_uint.rs b/framework/base/src/types/managed/basic/big_uint.rs index b139f823dc..34a6c6df23 100644 --- a/framework/base/src/types/managed/basic/big_uint.rs +++ b/framework/base/src/types/managed/basic/big_uint.rs @@ -1,7 +1,7 @@ use core::convert::TryInto; use crate::{ - abi::TypeName, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::{ const_handles, use_raw_handle, BigIntApiImpl, HandleConstraints, ManagedBufferApiImpl, ManagedTypeApi, ManagedTypeApiImpl, RawHandle, StaticVarApiImpl, @@ -11,8 +11,8 @@ use crate::{ NestedDecodeInput, NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, TryStaticCast, }, - formatter::{hex_util::encode_bytes_as_hex, FormatByteReceiver, SCDisplay}, - types::{heap::BoxedBytes, ManagedBuffer, ManagedType}, + formatter::{hex_util::encode_bytes_as_hex, FormatBuffer, FormatByteReceiver, SCDisplay}, + types::{heap::BoxedBytes, ManagedBuffer, ManagedBufferCachedBuilder, ManagedType}, }; use super::cast_to_i64::cast_to_i64; @@ -95,6 +95,7 @@ macro_rules! big_uint_conv_num { } impl CodecFrom<$num_ty> for BigUint {} + impl TypeAbiFrom<$num_ty> for BigUint {} }; } @@ -111,6 +112,11 @@ impl CodecFrom for BigUint #[cfg(feature = "num-bigint")] impl CodecFrom> for crate::codec::num_bigint::BigUint {} +#[cfg(feature = "num-bigint")] +impl TypeAbiFrom for BigUint {} +#[cfg(feature = "num-bigint")] +impl TypeAbiFrom> for crate::codec::num_bigint::BigUint {} + #[cfg(feature = "num-bigint")] impl From<&crate::codec::num_bigint::BigUint> for BigUint { fn from(alloc_big_uint: &crate::codec::num_bigint::BigUint) -> Self { @@ -287,10 +293,23 @@ impl TopDecode for BigUint { } } -impl crate::abi::TypeAbi for BigUint { +impl TypeAbiFrom for BigUint where M: ManagedTypeApi {} +impl TypeAbiFrom<&Self> for BigUint where M: ManagedTypeApi {} + +impl TypeAbi for BigUint { + #[cfg(feature = "num-bigint")] + type Unmanaged = crate::codec::num_bigint::BigUint; + + #[cfg(not(feature = "num-bigint"))] + type Unmanaged = Self; + fn type_name() -> TypeName { TypeName::from("BigUint") } + + fn type_name_rust() -> TypeName { + TypeName::from("BigUint<$API>") + } } impl SCDisplay for BigUint { @@ -303,6 +322,15 @@ impl SCDisplay for BigUint { } } +impl BigUint { + /// Creates to a managed buffer containing the textual representation of the number. + pub fn to_display(&self) -> ManagedBuffer { + let mut result = ManagedBufferCachedBuilder::new_from_slice(&[]); + result.append_display(self); + result.into_managed_buffer() + } +} + impl core::fmt::Debug for BigUint { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("BigUint") diff --git a/framework/base/src/types/managed/basic/elliptic_curve.rs b/framework/base/src/types/managed/basic/elliptic_curve.rs index d70f7f738d..8c6d66990f 100644 --- a/framework/base/src/types/managed/basic/elliptic_curve.rs +++ b/framework/base/src/types/managed/basic/elliptic_curve.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::{use_raw_handle, BigIntApiImpl, EllipticCurveApiImpl, ManagedTypeApi}, types::{BigUint, ManagedType}, }; @@ -418,8 +418,16 @@ impl TopEncode for EllipticCurve { } } +impl TypeAbiFrom for EllipticCurve where M: ManagedTypeApi {} + impl TypeAbi for EllipticCurve { + type Unmanaged = Self; + fn type_name() -> TypeName { TypeName::from("EllipticCurve") } + + fn type_name_rust() -> TypeName { + TypeName::from("EllipticCurve<$API>") + } } diff --git a/framework/base/src/types/managed/basic/managed_buffer.rs b/framework/base/src/types/managed/basic/managed_buffer.rs index 7c08f32699..358444c445 100644 --- a/framework/base/src/types/managed/basic/managed_buffer.rs +++ b/framework/base/src/types/managed/basic/managed_buffer.rs @@ -1,5 +1,5 @@ use crate::{ - abi::TypeName, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::{ use_raw_handle, ErrorApiImpl, HandleConstraints, InvalidSliceError, ManagedBufferApiImpl, ManagedTypeApi, StaticVarApiImpl, @@ -10,9 +10,10 @@ use crate::{ TopEncodeOutput, TryStaticCast, }, formatter::{ - hex_util::encode_bytes_as_hex, FormatByteReceiver, SCBinary, SCDisplay, SCLowerHex, + hex_util::encode_bytes_as_hex, FormatBuffer, FormatByteReceiver, SCBinary, SCDisplay, + SCLowerHex, }, - types::{heap::BoxedBytes, ManagedType, StaticBufferRef}, + types::{heap::BoxedBytes, ManagedBufferCachedBuilder, ManagedType, StaticBufferRef}, }; /// A byte buffer managed by an external API. @@ -159,6 +160,26 @@ where } } +impl From for ManagedBuffer +where + M: ManagedTypeApi, +{ + #[inline] + fn from(s: crate::types::heap::String) -> Self { + Self::new_from_bytes(s.as_bytes()) + } +} + +impl From<&crate::types::heap::String> for ManagedBuffer +where + M: ManagedTypeApi, +{ + #[inline] + fn from(s: &crate::types::heap::String) -> Self { + Self::new_from_bytes(s.as_bytes()) + } +} + impl Default for ManagedBuffer { #[inline] fn default() -> Self { @@ -310,6 +331,14 @@ impl ManagedBuffer { Some(u64::from_be_bytes(bytes)) } } + + /// Produces a hex expression in another managed buffer, + /// made up of "0x" + the hex representation of the data. + pub fn hex_expr(&self) -> ManagedBuffer { + let mut result = ManagedBufferCachedBuilder::new_from_slice(b"0x"); + result.append_lower_hex(self); + result.into_managed_buffer() + } } impl Clone for ManagedBuffer { @@ -390,12 +419,21 @@ impl CodecFrom<&[u8]> for ManagedBuffer where M: ManagedTypeApi {} impl CodecFrom<&str> for ManagedBuffer where M: ManagedTypeApi {} impl CodecFrom<&[u8; N]> for ManagedBuffer where M: ManagedTypeApi {} +impl TypeAbiFrom<&[u8]> for ManagedBuffer where M: ManagedTypeApi {} +impl TypeAbiFrom<&str> for ManagedBuffer where M: ManagedTypeApi {} +impl TypeAbiFrom<&[u8; N]> for ManagedBuffer where M: ManagedTypeApi {} + macro_rules! managed_buffer_codec_from_impl_bi_di { ($other_ty:ty) => { impl CodecFrom<$other_ty> for ManagedBuffer {} impl CodecFrom<&$other_ty> for ManagedBuffer {} impl CodecFrom> for $other_ty {} impl CodecFrom<&ManagedBuffer> for $other_ty {} + + impl TypeAbiFrom<$other_ty> for ManagedBuffer {} + impl TypeAbiFrom<&$other_ty> for ManagedBuffer {} + impl TypeAbiFrom> for $other_ty {} + impl TypeAbiFrom<&ManagedBuffer> for $other_ty {} }; } @@ -432,10 +470,19 @@ impl TopDecode for ManagedBuffer { } } -impl crate::abi::TypeAbi for ManagedBuffer { +impl TypeAbiFrom for ManagedBuffer where M: ManagedTypeApi {} +impl TypeAbiFrom<&Self> for ManagedBuffer where M: ManagedTypeApi {} + +impl TypeAbi for ManagedBuffer { + type Unmanaged = multiversx_sc_codec::Vec; + fn type_name() -> TypeName { "bytes".into() } + + fn type_name_rust() -> TypeName { + "ManagedBuffer<$API>".into() + } } impl SCDisplay for ManagedBuffer { diff --git a/framework/base/src/types/managed/multi_value/async_call_result_managed.rs b/framework/base/src/types/managed/multi_value/async_call_result_managed.rs index 6cdd2d7513..afa978f429 100644 --- a/framework/base/src/types/managed/multi_value/async_call_result_managed.rs +++ b/framework/base/src/types/managed/multi_value/async_call_result_managed.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::ManagedTypeApi, codec::{ DecodeErrorHandler, EncodeErrorHandler, TopDecodeMulti, TopDecodeMultiInput, @@ -97,11 +97,20 @@ where } } +impl TypeAbiFrom for ManagedAsyncCallResult +where + M: ManagedTypeApi, + T: TypeAbi, +{ +} + impl TypeAbi for ManagedAsyncCallResult where M: ManagedTypeApi, T: TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { let mut repr = TypeName::from("AsyncCallResult<"); repr.push_str(T::type_name().as_str()); diff --git a/framework/base/src/types/managed/multi_value/esdt_token_payment_multi_value.rs b/framework/base/src/types/managed/multi_value/esdt_token_payment_multi_value.rs index 66149fe04c..d9b312f45b 100644 --- a/framework/base/src/types/managed/multi_value/esdt_token_payment_multi_value.rs +++ b/framework/base/src/types/managed/multi_value/esdt_token_payment_multi_value.rs @@ -1,6 +1,9 @@ -use crate::codec::{ - multi_types::MultiValue3, DecodeErrorHandler, EncodeErrorHandler, TopDecodeMulti, - TopDecodeMultiInput, TopDecodeMultiLength, TopEncodeMulti, TopEncodeMultiOutput, +use crate::{ + abi::TypeAbiFrom, + codec::{ + multi_types::MultiValue3, DecodeErrorHandler, EncodeErrorHandler, TopDecodeMulti, + TopDecodeMultiInput, TopDecodeMultiLength, TopEncodeMulti, TopEncodeMultiOutput, + }, }; use crate::{ @@ -98,14 +101,22 @@ where const LEN: usize = 3; } +impl TypeAbiFrom for EsdtTokenPaymentMultiValue where M: ManagedTypeApi {} + impl TypeAbi for EsdtTokenPaymentMultiValue where M: ManagedTypeApi, { + type Unmanaged = Self; + fn type_name() -> TypeName { MultiValue3::, u64, BigUint>::type_name() } + fn type_name_rust() -> TypeName { + "EsdtTokenPaymentMultiValue<$API>".into() + } + fn is_variadic() -> bool { true } diff --git a/framework/base/src/types/managed/multi_value/multi_value_encoded.rs b/framework/base/src/types/managed/multi_value/multi_value_encoded.rs index ebf8e0cb69..42567e7ae3 100644 --- a/framework/base/src/types/managed/multi_value/multi_value_encoded.rs +++ b/framework/base/src/types/managed/multi_value/multi_value_encoded.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::{ErrorApi, ManagedTypeApi}, codec::{ try_cast_execute_or_else, CodecFromSelf, DecodeErrorHandler, EncodeErrorHandler, TopDecode, @@ -222,15 +222,35 @@ where } } +impl TypeAbiFrom for MultiValueEncoded +where + M: ManagedTypeApi, + T: TypeAbi, +{ +} + +impl TypeAbiFrom<&Self> for MultiValueEncoded +where + M: ManagedTypeApi, + T: TypeAbi, +{ +} + impl TypeAbi for MultiValueEncoded where M: ManagedTypeApi, T: TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { crate::abi::type_name_variadic::() } + fn type_name_rust() -> TypeName { + crate::abi::type_name_multi_value_encoded::() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } @@ -254,6 +274,15 @@ where { } +#[cfg(feature = "alloc")] +impl TypeAbiFrom> for MultiValueEncoded +where + M: ManagedTypeApi + ErrorApi, + T: TopEncodeMulti, + U: TypeAbiFrom, +{ +} + #[cfg(feature = "alloc")] impl CodecFrom> for MultiValueVec where @@ -263,6 +292,15 @@ where { } +#[cfg(feature = "alloc")] +impl TypeAbiFrom> for MultiValueVec +where + M: ManagedTypeApi + ErrorApi, + T: TopEncodeMulti, + U: TypeAbiFrom, +{ +} + impl FromIterator for MultiValueEncoded where M: ManagedTypeApi, diff --git a/framework/base/src/types/managed/multi_value/multi_value_managed_vec.rs b/framework/base/src/types/managed/multi_value/multi_value_managed_vec.rs index a00042ed5b..a7f1337080 100644 --- a/framework/base/src/types/managed/multi_value/multi_value_managed_vec.rs +++ b/framework/base/src/types/managed/multi_value/multi_value_managed_vec.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::ManagedTypeApi, codec::{ DecodeErrorHandler, EncodeErrorHandler, TopDecodeMulti, TopDecodeMultiInput, @@ -210,16 +210,26 @@ where } } +impl TypeAbiFrom for MultiValueManagedVec +where + M: ManagedTypeApi, + T: ManagedVecItem, +{ +} + impl TypeAbi for MultiValueManagedVec where M: ManagedTypeApi, T: ManagedVecItem, { + type Unmanaged = Self; + fn type_name() -> TypeName { - let mut repr = TypeName::from("variadic<"); - repr.push_str(T::type_name().as_str()); - repr.push('>'); - repr + crate::abi::type_name_variadic::() + } + + fn type_name_rust() -> TypeName { + alloc::format!("MultiValueManagedVec<$API, {}>", T::type_name_rust()) } fn provide_type_descriptions(accumulator: &mut TDC) { diff --git a/framework/base/src/types/managed/multi_value/multi_value_managed_vec_counted.rs b/framework/base/src/types/managed/multi_value/multi_value_managed_vec_counted.rs index eaab79dbed..60ffb780ee 100644 --- a/framework/base/src/types/managed/multi_value/multi_value_managed_vec_counted.rs +++ b/framework/base/src/types/managed/multi_value/multi_value_managed_vec_counted.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::ManagedTypeApi, codec::{ DecodeErrorHandler, EncodeErrorHandler, TopDecodeMulti, TopDecodeMultiInput, @@ -126,11 +126,20 @@ where } } +impl TypeAbiFrom for MultiValueManagedVecCounted +where + M: ManagedTypeApi, + T: ManagedVecItem + TypeAbi, +{ +} + impl TypeAbi for MultiValueManagedVecCounted where M: ManagedTypeApi, T: ManagedVecItem + TypeAbi, { + type Unmanaged = Self; + fn type_name() -> TypeName { let mut repr = TypeName::from("counted-variadic<"); repr.push_str(T::type_name().as_str()); diff --git a/framework/base/src/types/managed/wrapped/egld_or_esdt_token_identifier.rs b/framework/base/src/types/managed/wrapped/egld_or_esdt_token_identifier.rs index 3e7ae8afb5..8fa90f8186 100644 --- a/framework/base/src/types/managed/wrapped/egld_or_esdt_token_identifier.rs +++ b/framework/base/src/types/managed/wrapped/egld_or_esdt_token_identifier.rs @@ -1,9 +1,10 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::{HandleConstraints, ManagedTypeApi}, codec::*, derive::ManagedVecItem, formatter::{FormatByteReceiver, SCDisplay, SCLowerHex}, + proxy_imports::TestTokenIdentifier, types::{ManagedBuffer, ManagedOption, ManagedRef, ManagedType, TokenIdentifier}, }; @@ -26,7 +27,7 @@ use crate as multiversx_sc; // required by the ManagedVecItem derive #[repr(transparent)] #[derive(ManagedVecItem, Clone)] pub struct EgldOrEsdtTokenIdentifier { - data: ManagedOption>, + pub(crate) data: ManagedOption>, } impl EgldOrEsdtTokenIdentifier { @@ -81,8 +82,9 @@ impl EgldOrEsdtTokenIdentifier { #[inline] pub fn into_name(self) -> ManagedBuffer { self.map_or_else( - || ManagedBuffer::from(&Self::EGLD_REPRESENTATION[..]), - |token_identifier| token_identifier.into_managed_buffer(), + (), + |()| ManagedBuffer::from(&Self::EGLD_REPRESENTATION[..]), + |(), token_identifier| token_identifier.into_managed_buffer(), ) } @@ -91,25 +93,26 @@ impl EgldOrEsdtTokenIdentifier { /// Will fail if it encodes an invalid ESDT token identifier. pub fn is_valid(&self) -> bool { self.map_ref_or_else( - || true, - |token_identifier| token_identifier.is_valid_esdt_identifier(), + (), + |()| true, + |(), token_identifier| token_identifier.is_valid_esdt_identifier(), ) } - pub fn map_or_else(self, for_egld: D, for_esdt: F) -> U + pub fn map_or_else(self, context: Context, for_egld: D, for_esdt: F) -> R where - D: FnOnce() -> U, - F: FnOnce(TokenIdentifier) -> U, + D: FnOnce(Context) -> R, + F: FnOnce(Context, TokenIdentifier) -> R, { - self.data.map_or_else(for_egld, for_esdt) + self.data.map_or_else(context, for_egld, for_esdt) } - pub fn map_ref_or_else(&self, for_egld: D, for_esdt: F) -> U + pub fn map_ref_or_else(&self, context: Context, for_egld: D, for_esdt: F) -> R where - D: FnOnce() -> U, - F: FnOnce(&TokenIdentifier) -> U, + D: FnOnce(Context) -> R, + F: FnOnce(Context, &TokenIdentifier) -> R, { - self.data.map_ref_or_else(for_egld, for_esdt) + self.data.map_ref_or_else(context, for_egld, for_esdt) } pub fn unwrap_esdt(self) -> TokenIdentifier { @@ -142,8 +145,9 @@ impl PartialEq> for EgldOrEsdtTokenIdentif #[inline] fn eq(&self, other: &TokenIdentifier) -> bool { self.map_ref_or_else( - || false, - |self_esdt_token_identifier| self_esdt_token_identifier == other, + (), + |()| false, + |(), self_esdt_token_identifier| self_esdt_token_identifier == other, ) } } @@ -206,14 +210,36 @@ impl CodecFromSelf for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi { impl CodecFrom> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} impl CodecFrom<&TokenIdentifier> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} - impl CodecFrom<&[u8]> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} impl CodecFrom<&str> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} +impl TypeAbiFrom> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} +impl TypeAbiFrom<&TokenIdentifier> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} +impl TypeAbiFrom<&[u8]> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} +impl TypeAbiFrom<&str> for EgldOrEsdtTokenIdentifier where M: ManagedTypeApi {} + +impl<'a, M> TypeAbiFrom> for EgldOrEsdtTokenIdentifier where + M: ManagedTypeApi +{ +} +impl<'a, M> TypeAbiFrom<&TestTokenIdentifier<'a>> for EgldOrEsdtTokenIdentifier where + M: ManagedTypeApi +{ +} + +impl TypeAbiFrom for EgldOrEsdtTokenIdentifier {} +impl TypeAbiFrom<&Self> for EgldOrEsdtTokenIdentifier {} + impl TypeAbi for EgldOrEsdtTokenIdentifier { + type Unmanaged = Self; + fn type_name() -> TypeName { "EgldOrEsdtTokenIdentifier".into() } + + fn type_name_rust() -> TypeName { + "EgldOrEsdtTokenIdentifier<$API>".into() + } } impl SCDisplay for EgldOrEsdtTokenIdentifier { diff --git a/framework/base/src/types/managed/wrapped/egld_or_esdt_token_payment.rs b/framework/base/src/types/managed/wrapped/egld_or_esdt_token_payment.rs index ed76946617..ffce0c44e7 100644 --- a/framework/base/src/types/managed/wrapped/egld_or_esdt_token_payment.rs +++ b/framework/base/src/types/managed/wrapped/egld_or_esdt_token_payment.rs @@ -12,7 +12,7 @@ use crate::codec::{ use crate as multiversx_sc; // needed by the TypeAbi generated code use crate::derive::TypeAbi; -use super::EsdtTokenPayment; +use super::{EsdtTokenPayment, EsdtTokenPaymentRefs}; #[derive( TopDecode, TopEncode, NestedDecode, NestedEncode, TypeAbi, Clone, PartialEq, Eq, Debug, @@ -53,6 +53,54 @@ impl EgldOrEsdtTokenPayment { ) } + /// Equivalent to a `match { Egld | Esdt }`. + /// + /// Context passed on from function to closures, to avoid ownership issues. + /// More precisely, since only one of the two closures `for_egld` and `for_esdt` is called, + /// it is ok for them to have fully owned access to anything from the environment. + /// The compiler doesn't know that only one of them can ever be called, + /// so if we pass context to both closures, it will complain that they are moved twice. + pub fn map_egld_or_esdt(self, context: Context, for_egld: D, for_esdt: F) -> U + where + D: FnOnce(Context, BigUint) -> U, + F: FnOnce(Context, EsdtTokenPayment) -> U, + { + self.token_identifier.map_or_else( + (context, self.amount), + |(context, amount)| for_egld(context, amount), + |(context, amount), token_identifier| { + for_esdt( + context, + EsdtTokenPayment::new(token_identifier, self.token_nonce, amount), + ) + }, + ) + } + + /// Same as `map_egld_or_esdt`, but only takes a reference, + /// and consequently, the closures also only get references. + pub fn map_ref_egld_or_esdt( + &self, + context: Context, + for_egld: D, + for_esdt: F, + ) -> U + where + D: FnOnce(Context, &BigUint) -> U, + F: FnOnce(Context, EsdtTokenPaymentRefs<'_, M>) -> U, + { + self.token_identifier.map_ref_or_else( + context, + |context| for_egld(context, &self.amount), + |context, token_identifier| { + for_esdt( + context, + EsdtTokenPaymentRefs::new(token_identifier, self.token_nonce, &self.amount), + ) + }, + ) + } + pub fn into_tuple(self) -> (EgldOrEsdtTokenIdentifier, u64, BigUint) { (self.token_identifier, self.token_nonce, self.amount) } @@ -81,3 +129,59 @@ impl From> for EgldOrEsdtTokenPayment impl CodecFromSelf for EgldOrEsdtTokenPayment where M: ManagedTypeApi {} impl CodecFrom<&[u8]> for EgldOrEsdtTokenPayment where M: ManagedTypeApi {} + +impl EgldOrEsdtTokenPayment { + pub fn as_refs(&self) -> EgldOrEsdtTokenPaymentRefs<'_, M> { + EgldOrEsdtTokenPaymentRefs::new(&self.token_identifier, self.token_nonce, &self.amount) + } +} + +/// Similar to `EgldOrEsdtTokenPayment`, but only contains references. +pub struct EgldOrEsdtTokenPaymentRefs<'a, M: ManagedTypeApi> { + pub token_identifier: &'a EgldOrEsdtTokenIdentifier, + pub token_nonce: u64, + pub amount: &'a BigUint, +} + +impl<'a, M: ManagedTypeApi> EgldOrEsdtTokenPaymentRefs<'a, M> { + pub fn new( + token_identifier: &'a EgldOrEsdtTokenIdentifier, + token_nonce: u64, + amount: &'a BigUint, + ) -> EgldOrEsdtTokenPaymentRefs<'a, M> { + EgldOrEsdtTokenPaymentRefs { + token_identifier, + token_nonce, + amount, + } + } + + pub fn to_owned_payment(&self) -> EgldOrEsdtTokenPayment { + EgldOrEsdtTokenPayment { + token_identifier: self.token_identifier.clone(), + token_nonce: self.token_nonce, + amount: self.amount.clone(), + } + } + + pub fn is_empty(&self) -> bool { + self.amount == &BigUint::zero() + } + + pub fn map_egld_or_esdt(self, context: Context, for_egld: D, for_esdt: F) -> U + where + D: FnOnce(Context, &BigUint) -> U, + F: FnOnce(Context, EsdtTokenPaymentRefs) -> U, + { + self.token_identifier.map_ref_or_else( + context, + |context| for_egld(context, self.amount), + |context, token_identifier| { + for_esdt( + context, + EsdtTokenPaymentRefs::new(token_identifier, self.token_nonce, self.amount), + ) + }, + ) + } +} diff --git a/framework/base/src/types/managed/wrapped/egld_or_multi_esdt_payment.rs b/framework/base/src/types/managed/wrapped/egld_or_multi_esdt_payment.rs index 653b76d5a0..838fc278a4 100644 --- a/framework/base/src/types/managed/wrapped/egld_or_multi_esdt_payment.rs +++ b/framework/base/src/types/managed/wrapped/egld_or_multi_esdt_payment.rs @@ -24,3 +24,51 @@ pub enum EgldOrMultiEsdtPayment { } impl CodecFromSelf for EgldOrMultiEsdtPayment where M: ManagedTypeApi {} + +impl EgldOrMultiEsdtPayment { + pub fn is_empty(&self) -> bool { + match self { + EgldOrMultiEsdtPayment::Egld(egld_value) => egld_value == &0u32, + EgldOrMultiEsdtPayment::MultiEsdt(esdt_payments) => esdt_payments.is_empty(), + } + } +} + +/// The version of `EgldOrMultiEsdtPayment` that contains referrences instead of owned fields. +pub enum EgldOrMultiEsdtPaymentRefs<'a, M: ManagedTypeApi> { + Egld(&'a BigUint), + MultiEsdt(&'a ManagedVec>), +} + +impl EgldOrMultiEsdtPayment { + pub fn as_refs(&self) -> EgldOrMultiEsdtPaymentRefs<'_, M> { + match self { + EgldOrMultiEsdtPayment::Egld(egld_value) => { + EgldOrMultiEsdtPaymentRefs::Egld(egld_value) + }, + EgldOrMultiEsdtPayment::MultiEsdt(esdt_payments) => { + EgldOrMultiEsdtPaymentRefs::MultiEsdt(esdt_payments) + }, + } + } +} + +impl<'a, M: ManagedTypeApi> EgldOrMultiEsdtPaymentRefs<'a, M> { + pub fn to_owned_payment(&self) -> EgldOrMultiEsdtPayment { + match self { + EgldOrMultiEsdtPaymentRefs::Egld(egld_value) => { + EgldOrMultiEsdtPayment::Egld((*egld_value).clone()) + }, + EgldOrMultiEsdtPaymentRefs::MultiEsdt(esdt_payments) => { + EgldOrMultiEsdtPayment::MultiEsdt((*esdt_payments).clone()) + }, + } + } + + pub fn is_empty(&self) -> bool { + match self { + EgldOrMultiEsdtPaymentRefs::Egld(egld_value) => *egld_value == &0u32, + EgldOrMultiEsdtPaymentRefs::MultiEsdt(esdt_payments) => esdt_payments.is_empty(), + } + } +} diff --git a/framework/base/src/types/managed/wrapped/esdt_token_data.rs b/framework/base/src/types/managed/wrapped/esdt_token_data.rs index d4b13afdbe..5bbd550299 100644 --- a/framework/base/src/types/managed/wrapped/esdt_token_data.rs +++ b/framework/base/src/types/managed/wrapped/esdt_token_data.rs @@ -12,13 +12,12 @@ use crate::{ }; use crate as multiversx_sc; // needed by the TypeAbi generated code -use crate::derive::TypeAbi; +use crate::derive::type_abi; const DECODE_ATTRIBUTE_ERROR_PREFIX: &[u8] = b"error decoding ESDT attributes: "; -#[derive( - Clone, TopDecode, TopEncode, NestedDecode, NestedEncode, TypeAbi, Debug, ManagedVecItem, -)] +#[type_abi] +#[derive(Clone, TopDecode, TopEncode, NestedDecode, NestedEncode, Debug, ManagedVecItem)] pub struct EsdtTokenData { pub token_type: EsdtTokenType, pub amount: BigUint, diff --git a/framework/base/src/types/managed/wrapped/esdt_token_payment.rs b/framework/base/src/types/managed/wrapped/esdt_token_payment.rs index 29391f5381..ac7a54c442 100644 --- a/framework/base/src/types/managed/wrapped/esdt_token_payment.rs +++ b/framework/base/src/types/managed/wrapped/esdt_token_payment.rs @@ -10,12 +10,13 @@ use crate::{ derive::{NestedEncode, TopEncode}, IntoMultiValue, NestedDecode, TopDecode, }, - derive::TypeAbi, + derive::type_abi, }; use super::ManagedVec; -#[derive(TopEncode, NestedEncode, TypeAbi, Clone, PartialEq, Eq, Debug)] +#[type_abi] +#[derive(TopEncode, NestedEncode, Clone, PartialEq, Eq, Debug)] pub struct EsdtTokenPayment { pub token_identifier: TokenIdentifier, pub token_nonce: u64, @@ -221,3 +222,60 @@ impl ManagedVecItem for EsdtTokenPayment { writer(&arr[..]) } } + +/// The version of `EsdtTokenPayment` that contains referrences instead of owned fields. +pub struct EsdtTokenPaymentRefs<'a, M: ManagedTypeApi> { + pub token_identifier: &'a TokenIdentifier, + pub token_nonce: u64, + pub amount: &'a BigUint, +} + +impl EsdtTokenPayment { + pub fn as_refs(&self) -> EsdtTokenPaymentRefs<'_, M> { + EsdtTokenPaymentRefs::new(&self.token_identifier, self.token_nonce, &self.amount) + } +} + +impl<'a, M: ManagedTypeApi> EsdtTokenPaymentRefs<'a, M> { + pub fn new( + token_identifier: &'a TokenIdentifier, + token_nonce: u64, + amount: &'a BigUint, + ) -> Self { + EsdtTokenPaymentRefs { + token_identifier, + token_nonce, + amount, + } + } + + /// Will clone the referenced values. + pub fn to_owned_payment(&self) -> EsdtTokenPayment { + EsdtTokenPayment { + token_identifier: self.token_identifier.clone(), + token_nonce: self.token_nonce, + amount: self.amount.clone(), + } + } +} + +impl From<()> for MultiEsdtPayment { + #[inline] + fn from(_value: ()) -> Self { + MultiEsdtPayment::new() + } +} + +impl From> for MultiEsdtPayment { + #[inline] + fn from(value: EsdtTokenPayment) -> Self { + MultiEsdtPayment::from_single_item(value) + } +} + +impl From<(TokenIdentifier, u64, BigUint)> for MultiEsdtPayment { + #[inline] + fn from(value: (TokenIdentifier, u64, BigUint)) -> Self { + MultiEsdtPayment::from_single_item(value.into()) + } +} diff --git a/framework/base/src/types/managed/wrapped/managed_address.rs b/framework/base/src/types/managed/wrapped/managed_address.rs index 1ce1524bb6..318e5940ce 100644 --- a/framework/base/src/types/managed/wrapped/managed_address.rs +++ b/framework/base/src/types/managed/wrapped/managed_address.rs @@ -1,7 +1,7 @@ use core::convert::{TryFrom, TryInto}; use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::ManagedTypeApi, codec::{ CodecFrom, CodecFromSelf, DecodeError, DecodeErrorHandler, EncodeErrorHandler, @@ -234,14 +234,27 @@ where } } +impl TypeAbiFrom for ManagedAddress where M: ManagedTypeApi {} +impl TypeAbiFrom<&Self> for ManagedAddress where M: ManagedTypeApi {} + impl TypeAbi for ManagedAddress where M: ManagedTypeApi, { + #[cfg(feature = "alloc")] + type Unmanaged = crate::types::heap::Address; + + #[cfg(not(feature = "alloc"))] + type Unmanaged = Self; + /// `"Address"` instead of `"array32"`. fn type_name() -> TypeName { Address::type_name() } + + fn type_name_rust() -> TypeName { + "ManagedAddress<$API>".into() + } } impl SCLowerHex for ManagedAddress { @@ -250,6 +263,12 @@ impl SCLowerHex for ManagedAddress { } } +impl ManagedAddress { + pub fn hex_expr(&self) -> ManagedBuffer { + self.bytes.buffer.hex_expr() + } +} + impl core::fmt::Debug for ManagedAddress { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("ManagedAddress") @@ -262,6 +281,7 @@ impl core::fmt::Debug for ManagedAddress { impl CodecFromSelf for ManagedAddress where M: ManagedTypeApi {} impl CodecFrom<[u8; 32]> for ManagedAddress where M: ManagedTypeApi {} +impl TypeAbiFrom<[u8; 32]> for ManagedAddress where M: ManagedTypeApi {} #[cfg(feature = "alloc")] impl CodecFrom
for ManagedAddress where M: ManagedTypeApi {} @@ -274,3 +294,15 @@ impl CodecFrom> for Address where M: ManagedTypeApi {} #[cfg(feature = "alloc")] impl CodecFrom<&ManagedAddress> for Address where M: ManagedTypeApi {} + +#[cfg(feature = "alloc")] +impl TypeAbiFrom
for ManagedAddress where M: ManagedTypeApi {} + +#[cfg(feature = "alloc")] +impl TypeAbiFrom<&Address> for ManagedAddress where M: ManagedTypeApi {} + +#[cfg(feature = "alloc")] +impl TypeAbiFrom> for Address where M: ManagedTypeApi {} + +#[cfg(feature = "alloc")] +impl TypeAbiFrom<&ManagedAddress> for Address where M: ManagedTypeApi {} diff --git a/framework/base/src/types/managed/wrapped/managed_byte_array.rs b/framework/base/src/types/managed/wrapped/managed_byte_array.rs index ed41ba4951..83e95d332c 100644 --- a/framework/base/src/types/managed/wrapped/managed_byte_array.rs +++ b/framework/base/src/types/managed/wrapped/managed_byte_array.rs @@ -1,7 +1,9 @@ use core::convert::TryFrom; +use alloc::format; + use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::ManagedTypeApi, codec::{ DecodeError, DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, @@ -203,13 +205,24 @@ where } } +impl TypeAbiFrom> for [u8; N] where M: ManagedTypeApi {} + +impl TypeAbiFrom for ManagedByteArray where M: ManagedTypeApi {} +impl TypeAbiFrom<&Self> for ManagedByteArray where M: ManagedTypeApi {} + impl TypeAbi for ManagedByteArray where M: ManagedTypeApi, { + type Unmanaged = [u8; N]; + /// It is semantically equivalent to `[u8; N]`. fn type_name() -> TypeName { - <&[u8; N] as TypeAbi>::type_name() + <[u8; N] as TypeAbi>::type_name() + } + + fn type_name_rust() -> TypeName { + format!("ManagedByteArray<$API, {N}usize>") } } diff --git a/framework/base/src/types/managed/wrapped/managed_option.rs b/framework/base/src/types/managed/wrapped/managed_option.rs index 64766f43db..a34a4f7ab3 100644 --- a/framework/base/src/types/managed/wrapped/managed_option.rs +++ b/framework/base/src/types/managed/wrapped/managed_option.rs @@ -1,8 +1,11 @@ use core::marker::PhantomData; -use crate::codec::{ - DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode, - NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, +use crate::{ + abi::TypeAbiFrom, + codec::{ + DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput, NestedEncode, + NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput, + }, }; use crate::{ @@ -73,9 +76,18 @@ where !self.is_none() } + /// Assumes that value is Some and unwraps without checking. + /// + /// # Safety + /// + /// Must always be called under an `if` checking `.is_some()`, otherwise will lead to undefined behaviour. + pub unsafe fn unwrap_no_check(self) -> T { + T::from_handle(self.handle) + } + pub fn into_option(self) -> Option { if self.is_some() { - Some(T::from_handle(self.handle)) + Some(unsafe { self.unwrap_no_check() }) } else { None } @@ -91,7 +103,7 @@ where pub fn unwrap_or_else T>(self, f: F) -> T { if self.is_some() { - T::from_handle(self.handle) + unsafe { self.unwrap_no_check() } } else { f() } @@ -107,33 +119,33 @@ where F: FnOnce(T) -> U, { if self.is_some() { - ManagedOption::::some(f(T::from_handle(self.handle))) + ManagedOption::::some(f(unsafe { self.unwrap_no_check() })) } else { ManagedOption::::none() } } - pub fn map_or_else(self, default: D, f: F) -> U + pub fn map_or_else(self, context: Context, default: D, f: F) -> R where - D: FnOnce() -> U, - F: FnOnce(T) -> U, + D: FnOnce(Context) -> R, + F: FnOnce(Context, T) -> R, { if self.is_some() { - f(T::from_handle(self.handle)) + f(context, unsafe { self.unwrap_no_check() }) } else { - default() + default(context) } } - pub fn map_ref_or_else(&self, default: D, f: F) -> U + pub fn map_ref_or_else(&self, context: Context, default: D, f: F) -> R where - D: FnOnce() -> U, - F: FnOnce(&T) -> U, + D: FnOnce(Context) -> R, + F: FnOnce(Context, &T) -> R, { if self.is_some() { - f(&T::from_handle(self.handle.clone())) + f(context, &T::from_handle(self.handle.clone())) } else { - default() + default(context) } } } @@ -260,16 +272,45 @@ where } } +impl TypeAbiFrom> for ManagedOption +where + M: ManagedTypeApi, + U: ManagedType, + T: ManagedType + TypeAbiFrom, +{ +} + +impl TypeAbiFrom> for ManagedOption +where + M: ManagedTypeApi, + T: ManagedType + TypeAbiFrom, +{ +} + +impl TypeAbiFrom> for Option +where + M: ManagedTypeApi, + U: ManagedType, + T: TypeAbiFrom, +{ +} + impl TypeAbi for ManagedOption where M: ManagedTypeApi, T: ManagedType + TypeAbi, { + type Unmanaged = Option; + /// It is semantically equivalent to any list of `T`. fn type_name() -> TypeName { Option::::type_name() } + fn type_name_rust() -> TypeName { + Option::::type_name_rust() + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/types/managed/wrapped/managed_ref.rs b/framework/base/src/types/managed/wrapped/managed_ref.rs index 748c704956..143d79e1d4 100644 --- a/framework/base/src/types/managed/wrapped/managed_ref.rs +++ b/framework/base/src/types/managed/wrapped/managed_ref.rs @@ -54,6 +54,7 @@ where M: ManagedTypeApi, T: ManagedType + Clone, { + /// Syntactic sugar for dereferencing and cloning the object. pub fn clone_value(&self) -> T { self.deref().clone() } diff --git a/framework/base/src/types/managed/wrapped/managed_vec.rs b/framework/base/src/types/managed/wrapped/managed_vec.rs index f7b8cad171..8ba9b1d355 100644 --- a/framework/base/src/types/managed/wrapped/managed_vec.rs +++ b/framework/base/src/types/managed/wrapped/managed_vec.rs @@ -1,6 +1,6 @@ use super::EncodedManagedVecItem; use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::{ErrorApiImpl, InvalidSliceError, ManagedTypeApi}, codec::{ DecodeErrorHandler, EncodeErrorHandler, IntoMultiValue, NestedDecode, NestedDecodeInput, @@ -12,7 +12,7 @@ use crate::{ ManagedVecRefIterator, MultiValueEncoded, MultiValueManagedVec, }, }; -use alloc::vec::Vec; +use alloc::{format, vec::Vec}; use core::{ borrow::Borrow, cmp::Ordering, @@ -678,16 +678,45 @@ where } } +impl TypeAbiFrom> for ManagedVec +where + M: ManagedTypeApi, + U: ManagedVecItem, + T: ManagedVecItem + TypeAbiFrom, +{ +} + +impl TypeAbiFrom> for ManagedVec +where + M: ManagedTypeApi, + T: ManagedVecItem + TypeAbiFrom, +{ +} + +impl TypeAbiFrom> for Vec +where + M: ManagedTypeApi, + U: ManagedVecItem, + T: TypeAbiFrom, +{ +} + impl TypeAbi for ManagedVec where M: ManagedTypeApi, T: ManagedVecItem + TypeAbi, { + type Unmanaged = Vec; + /// It is semantically equivalent to any list of `T`. fn type_name() -> TypeName { <&[T] as TypeAbi>::type_name() } + fn type_name_rust() -> TypeName { + format!("ManagedVec<$API, {}>", T::type_name_rust()) + } + fn provide_type_descriptions(accumulator: &mut TDC) { T::provide_type_descriptions(accumulator); } diff --git a/framework/base/src/types/managed/wrapped/mod.rs b/framework/base/src/types/managed/wrapped/mod.rs index e883e67e93..c5d8d03391 100644 --- a/framework/base/src/types/managed/wrapped/mod.rs +++ b/framework/base/src/types/managed/wrapped/mod.rs @@ -21,11 +21,11 @@ mod traits; pub use builder::*; pub use egld_or_esdt_token_identifier::EgldOrEsdtTokenIdentifier; -pub use egld_or_esdt_token_payment::EgldOrEsdtTokenPayment; -pub use egld_or_multi_esdt_payment::EgldOrMultiEsdtPayment; +pub use egld_or_esdt_token_payment::{EgldOrEsdtTokenPayment, EgldOrEsdtTokenPaymentRefs}; +pub use egld_or_multi_esdt_payment::{EgldOrMultiEsdtPayment, EgldOrMultiEsdtPaymentRefs}; pub(crate) use encoded_managed_vec_item::EncodedManagedVecItem; pub use esdt_token_data::EsdtTokenData; -pub use esdt_token_payment::{EsdtTokenPayment, MultiEsdtPayment}; +pub use esdt_token_payment::{EsdtTokenPayment, EsdtTokenPaymentRefs, MultiEsdtPayment}; pub use managed_address::ManagedAddress; pub(crate) use managed_byte_array::ManagedBufferSizeContext; pub use managed_byte_array::ManagedByteArray; diff --git a/framework/base/src/types/managed/wrapped/token_identifier.rs b/framework/base/src/types/managed/wrapped/token_identifier.rs index 329b3f2b3d..f4c978b0d1 100644 --- a/framework/base/src/types/managed/wrapped/token_identifier.rs +++ b/framework/base/src/types/managed/wrapped/token_identifier.rs @@ -1,5 +1,5 @@ use crate::{ - abi::{TypeAbi, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeName}, api::{ErrorApi, ErrorApiImpl, HandleConstraints, ManagedTypeApi, ManagedTypeApiImpl}, codec::*, err_msg, @@ -109,8 +109,9 @@ impl PartialEq> for TokenIdentif #[inline] fn eq(&self, other: &EgldOrEsdtTokenIdentifier) -> bool { other.map_ref_or_else( - || false, - |esdt_token_identifier| esdt_token_identifier == self, + (), + |()| false, + |(), esdt_token_identifier| esdt_token_identifier == self, ) } } @@ -164,13 +165,24 @@ impl TopDecode for TokenIdentifier { impl CodecFromSelf for TokenIdentifier where M: ManagedTypeApi {} impl CodecFrom<&[u8]> for TokenIdentifier where M: ManagedTypeApi {} - impl CodecFrom> for TokenIdentifier where M: ManagedTypeApi {} +impl TypeAbiFrom<&[u8]> for TokenIdentifier where M: ManagedTypeApi {} +impl TypeAbiFrom> for TokenIdentifier where M: ManagedTypeApi {} + +impl TypeAbiFrom for TokenIdentifier {} +impl TypeAbiFrom<&Self> for TokenIdentifier {} + impl TypeAbi for TokenIdentifier { + type Unmanaged = Self; + fn type_name() -> TypeName { "TokenIdentifier".into() } + + fn type_name_rust() -> TypeName { + "TokenIdentifier<$API>".into() + } } impl SCDisplay for TokenIdentifier { diff --git a/framework/base/src/types/managed/wrapped/traits/fixed_token_supply.rs b/framework/base/src/types/managed/wrapped/traits/fixed_token_supply.rs index 838486c203..0b94cbbf6b 100644 --- a/framework/base/src/types/managed/wrapped/traits/fixed_token_supply.rs +++ b/framework/base/src/types/managed/wrapped/traits/fixed_token_supply.rs @@ -1,4 +1,7 @@ -use crate::imports::{BigUint, ErrorApiImpl, ManagedTypeApi}; +use crate::{ + api::{ErrorApiImpl, ManagedTypeApi}, + types::BigUint, +}; pub trait FixedSupplyToken { fn get_total_supply(&self) -> BigUint; diff --git a/framework/base/src/types/managed/wrapped/traits/mergeable.rs b/framework/base/src/types/managed/wrapped/traits/mergeable.rs index 2ed714973a..51298ba130 100644 --- a/framework/base/src/types/managed/wrapped/traits/mergeable.rs +++ b/framework/base/src/types/managed/wrapped/traits/mergeable.rs @@ -1,4 +1,7 @@ -use crate::imports::{ErrorApiImpl, EsdtTokenPayment, ManagedTypeApi, ManagedVec, ManagedVecItem}; +use crate::{ + api::{ErrorApiImpl, ManagedTypeApi}, + types::{EsdtTokenPayment, ManagedVec, ManagedVecItem}, +}; pub static CANNOT_MERGE_ERR_MSG: &[u8] = b"Cannot merge"; diff --git a/framework/base/src/types/static_buffer/sparse_array.rs b/framework/base/src/types/static_buffer/sparse_array.rs index 2c6ddd61e2..bb3a083243 100644 --- a/framework/base/src/types/static_buffer/sparse_array.rs +++ b/framework/base/src/types/static_buffer/sparse_array.rs @@ -1,5 +1,7 @@ +use alloc::format; + use crate::{ - abi::{TypeAbi, TypeDescriptionContainer, TypeName}, + abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName}, api::{ErrorApi, ErrorApiImpl}, codec::{self, arrayvec::ArrayVec, NestedDecode, NestedEncode, TopDecode, TopEncode}, }; @@ -302,15 +304,24 @@ where } } +impl TypeAbiFrom for SparseArray where E: ErrorApi {} +impl TypeAbiFrom<&Self> for SparseArray where E: ErrorApi {} + impl TypeAbi for SparseArray where E: ErrorApi, { + type Unmanaged = Self; + /// It is semantically equivalent to any list of `usize`. fn type_name() -> TypeName { <&[usize] as TypeAbi>::type_name() } + fn type_name_rust() -> TypeName { + format!("SparseArray<$API, {CAPACITY}usize>") + } + fn provide_type_descriptions(accumulator: &mut TDC) { usize::provide_type_descriptions(accumulator); } diff --git a/framework/derive/Cargo.toml b/framework/derive/Cargo.toml index d0b128dda2..c9c1c4635c 100644 --- a/framework/derive/Cargo.toml +++ b/framework/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sc-derive" -version = "0.48.1" +version = "0.49.0-alpha.4" edition = "2021" authors = ["Andrei Marinica ", "MultiversX "] diff --git a/framework/derive/src/generate/abi_gen.rs b/framework/derive/src/generate/abi_gen.rs index df8755ded7..5d5a73934c 100644 --- a/framework/derive/src/generate/abi_gen.rs +++ b/framework/derive/src/generate/abi_gen.rs @@ -91,6 +91,21 @@ fn generate_endpoint_snippets(contract: &ContractTrait) -> Vec { + let endpoint_def = generate_endpoint_snippet( + m, + "upgrade", + false, + false, + EndpointMutabilityMetadata::Mutable, + EndpointTypeMetadata::Upgrade, + m.is_allow_multiple_var_args(), + ); + Some(quote! { + #endpoint_def + contract_abi.upgrade_constructors.push(endpoint_abi); + }) + }, PublicRole::Endpoint(endpoint_metadata) => { let endpoint_def = generate_endpoint_snippet( m, @@ -182,15 +197,15 @@ fn has_callback(contract: &ContractTrait) -> bool { fn generate_supertrait_snippets(contract: &ContractTrait) -> Vec { contract - .supertraits - .iter() - .map(|supertrait| { - let module_path = &supertrait.module_path; - quote! { - contract_abi.coalesce(<#module_path AbiProvider as multiversx_sc::contract_base::ContractAbiProvider>::abi()); - } - }) - .collect() + .supertraits + .iter() + .map(|supertrait| { + let module_path = &supertrait.module_path; + quote! { + contract_abi.coalesce(<#module_path AbiProvider as multiversx_sc::contract_base::ContractAbiProvider>::abi()); + } + }) + .collect() } fn generate_esdt_attribute_snippets(contract: &ContractTrait) -> Vec { diff --git a/framework/derive/src/generate/auto_impl_proxy.rs b/framework/derive/src/generate/auto_impl_proxy.rs index 7590b57b63..33c36724ca 100644 --- a/framework/derive/src/generate/auto_impl_proxy.rs +++ b/framework/derive/src/generate/auto_impl_proxy.rs @@ -3,7 +3,8 @@ use crate::{ model::{AutoImpl, ContractTrait, Method, MethodImpl}, parse::split_path_last, }; -use syn::{punctuated::Punctuated, token::PathSep}; +use proc_macro2::Ident; +use syn::{punctuated::Punctuated, token::PathSep, Pat}; /// Path to a Rust module containing a contract call proxy. pub type ProxyModulePath = Punctuated; @@ -34,19 +35,37 @@ pub fn proxy_getter_return_type(m: &Method) -> ProxyGetterReturnType { } } -fn proxy_getter_address_snippet(m: &Method) -> proc_macro2::TokenStream { +pub fn proxy_getter_return_type_token(m: &Method) -> proc_macro2::TokenStream { + let ProxyGetterReturnType { + module_path, + mut proxy_obj_name, + } = proxy_getter_return_type(m); + if proxy_getter_address_arg_name(m).is_some() { + // replace type name + let span = proxy_obj_name.ident.span(); // preserve span + proxy_obj_name.ident = Ident::new("ProxyTo", span); + } + quote! { #module_path #proxy_obj_name} +} + +fn proxy_getter_address_arg_name(m: &Method) -> Option { match m.method_args.len() { - 0 => quote! {}, - 1 => { - let address_arg_name = &m.method_args[0].pat; - quote! { - .contract(#address_arg_name) - } - }, + 0 => None, + 1 => Some(m.method_args[0].pat.clone()), _ => panic!("Proxy getter can have at most 1 argument, which is the target address"), } } +fn proxy_getter_address_snippet(m: &Method) -> proc_macro2::TokenStream { + if let Some(address_arg_name) = proxy_getter_address_arg_name(m) { + quote! { + .contract(#address_arg_name) + } + } else { + quote! {} + } +} + pub fn generate_proxy_getter_impl(m: &Method) -> proc_macro2::TokenStream { let msig = method_gen::generate_sig_with_attributes(m); let parsed_return_type = proxy_getter_return_type(m); @@ -55,7 +74,7 @@ pub fn generate_proxy_getter_impl(m: &Method) -> proc_macro2::TokenStream { quote! { #msig { - #module_path Proxy::new_proxy_obj() #address_snippet + <#module_path Proxy as multiversx_sc::contract_base::ProxyObjNew>::new_proxy_obj() #address_snippet } } } diff --git a/framework/derive/src/generate/callback_gen.rs b/framework/derive/src/generate/callback_gen.rs index 5d1cda744f..d5ed94bc7b 100644 --- a/framework/derive/src/generate/callback_gen.rs +++ b/framework/derive/src/generate/callback_gen.rs @@ -48,7 +48,7 @@ pub fn generate_callback_selector_and_main( let cb_main_body = quote! { if let Some(___cb_closure___) = multiversx_sc::types::CallbackClosureForDeser::storage_load_and_clear::() { if let multiversx_sc::types::CallbackSelectorResult::NotProcessed(_) = - self::EndpointWrappers::callback_selector(self, ___cb_closure___) { + self::EndpointWrappers::callback_selector(self, ___cb_closure___) { multiversx_sc::api::ErrorApiImpl::signal_error( &::error_api_impl(), err_msg::CALLBACK_BAD_FUNC, diff --git a/framework/derive/src/generate/contract_gen.rs b/framework/derive/src/generate/contract_gen.rs index 6d3cf620e6..ba7ace5879 100644 --- a/framework/derive/src/generate/contract_gen.rs +++ b/framework/derive/src/generate/contract_gen.rs @@ -28,6 +28,7 @@ pub fn generate_call_methods(contract_trait: &ContractTrait) -> Vec Some(generate_call_method(m)), + PublicRole::Upgrade(_upgrade_metadata) => Some(generate_call_method(m)), PublicRole::Endpoint(_endpoint_metadata) => Some(generate_call_method(m)), PublicRole::CallbackPromise(_callback_metadata) => { Some(generate_promises_callback_call_method(m)) diff --git a/framework/derive/src/generate/endpoints_mod_gen.rs b/framework/derive/src/generate/endpoints_mod_gen.rs index 5f780f0c4a..b32a7ce9a8 100644 --- a/framework/derive/src/generate/endpoints_mod_gen.rs +++ b/framework/derive/src/generate/endpoints_mod_gen.rs @@ -67,6 +67,7 @@ fn generate_wasm_endpoints(contract_trait: &ContractTrait) -> Vec Some(generate_wasm_endpoint(m, "e! { init })), + PublicRole::Upgrade(_) => Some(generate_wasm_endpoint(m, "e! { upgrade })), PublicRole::Endpoint(endpoint_metadata) => { let endpoint_ident = &endpoint_metadata.public_name; Some(generate_wasm_endpoint(m, "e! { #endpoint_ident })) diff --git a/framework/derive/src/generate/function_selector.rs b/framework/derive/src/generate/function_selector.rs index d49a673d71..6f157724f8 100644 --- a/framework/derive/src/generate/function_selector.rs +++ b/framework/derive/src/generate/function_selector.rs @@ -27,6 +27,11 @@ pub fn generate_function_selector_body(contract: &ContractTrait) -> proc_macro2: "init", quote! { if !::external_view_init_override() }, )), + PublicRole::Upgrade(_) => Some(endpoint_match_arm( + m, + "upgrade", + quote! {}, + )), PublicRole::Endpoint(endpoint_metadata) => Some(endpoint_match_arm( m, endpoint_metadata.public_name.to_string().as_str(), diff --git a/framework/derive/src/generate/method_gen.rs b/framework/derive/src/generate/method_gen.rs index dc979fe300..88de2bd30a 100644 --- a/framework/derive/src/generate/method_gen.rs +++ b/framework/derive/src/generate/method_gen.rs @@ -1,4 +1,6 @@ -use crate::model::{Method, MethodArgument}; +use crate::model::{AutoImpl, Method, MethodArgument, MethodImpl}; + +use super::auto_impl_proxy::proxy_getter_return_type_token; pub fn arg_declarations(method_args: &[MethodArgument]) -> Vec { method_args @@ -17,10 +19,7 @@ pub fn generate_sig(m: &Method) -> proc_macro2::TokenStream { let generics = &m.generics; let generics_where = &m.generics.where_clause; let arg_decl = arg_declarations(&m.method_args); - let ret_tok = match &m.return_type { - syn::ReturnType::Default => quote! {}, - syn::ReturnType::Type(r_arrow_token, ty) => quote! { #r_arrow_token #ty }, - }; + let ret_tok = generate_sig_return(m); let result = quote! { #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] @@ -29,6 +28,18 @@ pub fn generate_sig(m: &Method) -> proc_macro2::TokenStream { result } +pub fn generate_sig_return(m: &Method) -> proc_macro2::TokenStream { + if let MethodImpl::Generated(AutoImpl::ProxyGetter) = &m.implementation { + let proxy_ret_tok = proxy_getter_return_type_token(m); + return quote! { -> #proxy_ret_tok }; + } + + match &m.return_type { + syn::ReturnType::Default => quote! {}, + syn::ReturnType::Type(r_arrow_token, ty) => quote! { #r_arrow_token #ty }, + } +} + pub fn generate_sig_with_attributes(m: &Method) -> proc_macro2::TokenStream { let unprocessed_attributes = &m.unprocessed_attributes; let msig = generate_sig(m); diff --git a/framework/derive/src/generate/proxy_gen.rs b/framework/derive/src/generate/proxy_gen.rs index bc44d03b95..81b416c009 100644 --- a/framework/derive/src/generate/proxy_gen.rs +++ b/framework/derive/src/generate/proxy_gen.rs @@ -46,26 +46,29 @@ pub fn proxy_arg_gen( pub fn generate_proxy_method_sig( method: &Method, - proxy_return_struct_path: proc_macro2::TokenStream, + return_type: proc_macro2::TokenStream, ) -> proc_macro2::TokenStream { let method_name = &method.name; let mut generics = method.generics.clone(); let generics_where = &method.generics.where_clause; let arg_decl = proxy_arg_gen(&method.method_args, &mut generics); - let ret_tok = match &method.return_type { - syn::ReturnType::Default => quote! { () }, - syn::ReturnType::Type(_, ty) => quote! { #ty }, - }; let result = quote! { fn #method_name #generics ( &mut self, #(#arg_decl),* - ) -> #proxy_return_struct_path + ) -> #return_type #generics_where }; result } +fn original_type_tokens(m: &Method) -> proc_macro2::TokenStream { + match &m.return_type { + syn::ReturnType::Default => quote! { () }, + syn::ReturnType::Type(_, ty) => quote! { #ty }, + } +} + pub fn generate_proxy_endpoint(m: &Method, endpoint_name: String) -> proc_macro2::TokenStream { let mut token_count = 0; let mut token_expr = @@ -84,7 +87,7 @@ pub fn generate_proxy_endpoint(m: &Method, endpoint_name: String) -> proc_macro2 ArgPaymentMetadata::NotPayment => { let pat = &arg.pat; arg_push_snippets.push(quote! { - multiversx_sc::types::ContractCall::proxy_arg(&mut ___contract_call___, &#pat); + .argument(&#pat) }); }, ArgPaymentMetadata::PaymentToken => { @@ -127,62 +130,58 @@ pub fn generate_proxy_endpoint(m: &Method, endpoint_name: String) -> proc_macro2 "No more than one payment multi argument allowed in call proxy" ); - let contract_call_type; - let contract_call_init; + let payment_type; + let payment_init; if token_count > 0 || nonce_count > 0 || payment_count > 0 { assert!(multi_count == 0, "#[payment_multi] cannot coexist with any other payment annotation in the same endpoint"); if token_count == 0 && nonce_count == 0 { - contract_call_type = quote! { multiversx_sc::types::ContractCallWithEgld }; - contract_call_init = quote! { - let mut ___contract_call___ = multiversx_sc::types::ContractCallWithEgld::new( - ___address___, - #endpoint_name, - #payment_expr, - ); - }; + payment_type = quote! { multiversx_sc::types::EgldPayment }; + payment_init = quote! { .egld(#payment_expr) }; } else { - contract_call_type = quote! { multiversx_sc::types::ContractCallWithEgldOrSingleEsdt }; - contract_call_init = quote! { - let mut ___contract_call___ = multiversx_sc::types::ContractCallWithEgldOrSingleEsdt::new( - ___address___, - #endpoint_name, + payment_type = quote! { multiversx_sc::types::EgldOrEsdtTokenPayment }; + payment_init = quote! { .payment( + multiversx_sc::types::EgldOrEsdtTokenPayment::new( #token_expr, #nonce_expr, #payment_expr, - ); - }; + ) + )}; } } else if multi_count > 0 { let multi_expr = multi_expr_opt.unwrap(); - contract_call_type = quote! { multiversx_sc::types::ContractCallWithMultiEsdt }; - contract_call_init = quote! { - let mut ___contract_call___ = multiversx_sc::types::ContractCallWithMultiEsdt::new( - ___address___, - #endpoint_name, - #multi_expr.clone_value(), - ); - }; + payment_type = quote! { MultiEsdtPayment }; + payment_init = quote! { .multi_esdt(#multi_expr.clone_value()) }; } else { - contract_call_type = quote! { multiversx_sc::types::ContractCallNoPayment }; - contract_call_init = quote! { - let mut ___contract_call___ = multiversx_sc::types::ContractCallNoPayment::new( - ___address___, - #endpoint_name, - ); - }; + payment_type = quote! { () }; + payment_init = quote! {}; } - let msig = generate_proxy_method_sig(m, contract_call_type); + let original_type = original_type_tokens(m); + let return_type = quote! { + multiversx_sc::types::Tx< + multiversx_sc::types::TxScEnv, + (), + Self::To, + #payment_type, + (), + multiversx_sc::types::FunctionCall, + multiversx_sc::types::OriginalResultMarker<#original_type>, + > + }; + + let msig = generate_proxy_method_sig(m, return_type); let sig = quote! { #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] #msig { - let ___address___ = self.extract_address(); - #contract_call_init - #(#arg_push_snippets)* - ___contract_call___ + multiversx_sc::types::TxBaseWithEnv::new_tx_from_sc() + .to(self.extract_proxy_to()) + .original_result() + .raw_call(#endpoint_name) + #payment_init + #(#arg_push_snippets)* } }; @@ -190,50 +189,41 @@ pub fn generate_proxy_endpoint(m: &Method, endpoint_name: String) -> proc_macro2 } pub fn generate_proxy_deploy(init_method: &Method) -> proc_macro2::TokenStream { - let msig = - generate_proxy_method_sig(init_method, quote! { multiversx_sc::types::ContractDeploy }); - let mut payment_count = 0; let mut multi_count = 0; let mut token_count = 0; let mut nonce_count = 0; - let arg_push_snippets: Vec = init_method - .method_args - .iter() - .map(|arg| match &arg.metadata.payment { + let mut payment_type = quote! { () }; + let mut payment_init = quote! {}; + + let mut arg_push_snippets = Vec::::new(); + + for arg in &init_method.method_args { + match &arg.metadata.payment { ArgPaymentMetadata::NotPayment => { let pat = &arg.pat; - quote! { - ___contract_deploy___.push_endpoint_arg(&#pat); - } + arg_push_snippets.push(quote! { + .argument(&#pat) + }); }, ArgPaymentMetadata::PaymentToken => { token_count += 1; - - quote! {} }, ArgPaymentMetadata::PaymentNonce => { nonce_count += 1; - - quote! {} }, ArgPaymentMetadata::PaymentAmount => { payment_count += 1; - let pat = &arg.pat; - quote! { - ___contract_deploy___ = ___contract_deploy___.with_egld_transfer(#pat); - } + let payment_expr = &arg.pat; + payment_type = quote! { multiversx_sc::types::EgldPayment }; + payment_init = quote! { .egld(#payment_expr) }; }, ArgPaymentMetadata::PaymentMulti => { multi_count += 1; - let pat = &arg.pat; - quote! { - ___contract_deploy___ = ___contract_deploy___.with_multi_token_transfer(#pat); - } }, - }) - .collect(); + } + } assert!( payment_count <= 1, @@ -241,17 +231,36 @@ pub fn generate_proxy_deploy(init_method: &Method) -> proc_macro2::TokenStream { ); assert!(token_count == 0, "No ESDT payment allowed in #[init]"); assert!(nonce_count == 0, "No SFT/NFT payment allowed in #[init]"); + assert!( + multi_count == 0, + "No multi ESDT payments allowed in #[init]" + ); + + let original_type = original_type_tokens(init_method); + let return_type = quote! { + multiversx_sc::types::Tx< + multiversx_sc::types::TxScEnv, + (), + Self::To, // still accepted, until we separate the upgrade constructor completely + #payment_type, + (), + multiversx_sc::types::DeployCall, ()>, + multiversx_sc::types::OriginalResultMarker<#original_type>, + > + }; + + let msig = generate_proxy_method_sig(init_method, return_type); let sig = quote! { #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] #msig { - let ___opt_address___ = self.extract_opt_address(); - let mut ___contract_deploy___ = multiversx_sc::types::new_contract_deploy( - ___opt_address___, - ); - #(#arg_push_snippets)* - ___contract_deploy___ + multiversx_sc::types::TxBaseWithEnv::new_tx_from_sc() + .raw_deploy() + #payment_init + #(#arg_push_snippets)* + .original_result() + .to(self.extract_proxy_to()) // still accepted, until we separate the upgrade constructor completely } }; @@ -264,6 +273,7 @@ pub fn generate_method_impl(contract_trait: &ContractTrait) -> Vec Some(generate_proxy_deploy(m)), + PublicRole::Upgrade(_) => Some(generate_proxy_endpoint(m, "upgrade".to_string())), PublicRole::Endpoint(endpoint_metadata) => Some(generate_proxy_endpoint( m, endpoint_metadata.public_name.to_string(), @@ -303,7 +313,7 @@ fn equivalent_encode_path_gen(ty: &syn::Type) -> syn::Path { let owned_type = convert_to_owned_type(ty); syn::parse_str( format!( - "multiversx_sc::codec::CodecInto<{}>", + "multiversx_sc::types::ProxyArg<{}>", owned_type.to_token_stream() ) .as_str(), diff --git a/framework/derive/src/generate/snippets.rs b/framework/derive/src/generate/snippets.rs index 6c1751a187..6e66eb9ae4 100644 --- a/framework/derive/src/generate/snippets.rs +++ b/framework/derive/src/generate/snippets.rs @@ -79,7 +79,7 @@ pub fn proxy_object_def() -> proc_macro2::TokenStream { where A: multiversx_sc::api::VMApi + 'static, { - pub address: multiversx_sc::types::ManagedOption>, + _phantom: core::marker::PhantomData, } impl multiversx_sc::contract_base::ProxyObjBase for Proxy @@ -87,17 +87,60 @@ pub fn proxy_object_def() -> proc_macro2::TokenStream { A: multiversx_sc::api::VMApi + 'static, { type Api = A; + type To = (); + + fn extract_opt_address( + &mut self, + ) -> multiversx_sc::types::ManagedOption< + Self::Api, + multiversx_sc::types::ManagedAddress, + > { + multiversx_sc::types::ManagedOption::none() + } + + fn extract_address(&mut self) -> multiversx_sc::types::ManagedAddress { + multiversx_sc::api::ErrorApiImpl::signal_error( + &::error_api_impl(), + multiversx_sc::err_msg::RECIPIENT_ADDRESS_NOT_SET.as_bytes(), + ) + } + + fn extract_proxy_to(&mut self) -> Self::To {} + } + + impl multiversx_sc::contract_base::ProxyObjNew for Proxy + where + A: multiversx_sc::api::VMApi + 'static, + { + type ProxyTo = ProxyTo; fn new_proxy_obj() -> Self { Proxy { - address: multiversx_sc::types::ManagedOption::none(), + _phantom: core::marker::PhantomData, } } - fn contract(mut self, address: multiversx_sc::types::ManagedAddress) -> Self { - self.address = multiversx_sc::types::ManagedOption::some(address); - self + fn contract(mut self, address: multiversx_sc::types::ManagedAddress) -> Self::ProxyTo { + ProxyTo { + address: multiversx_sc::types::ManagedOption::some(address) + } } + } + + pub struct ProxyTo + where + A: multiversx_sc::api::VMApi + 'static, + { + pub address: + multiversx_sc::types::ManagedOption>, + } + + impl multiversx_sc::contract_base::ProxyObjBase for ProxyTo + where + A: multiversx_sc::api::VMApi + 'static, + { + type Api = A; + type To = multiversx_sc::types::ManagedAddress; fn extract_opt_address( &mut self, @@ -105,11 +148,22 @@ pub fn proxy_object_def() -> proc_macro2::TokenStream { Self::Api, multiversx_sc::types::ManagedAddress, > { - core::mem::replace(&mut self.address, multiversx_sc::types::ManagedOption::none()) + core::mem::replace( + &mut self.address, + multiversx_sc::types::ManagedOption::none(), + ) } fn extract_address(&mut self) -> multiversx_sc::types::ManagedAddress { - self.extract_opt_address().unwrap_or_sc_panic(multiversx_sc::err_msg::RECIPIENT_ADDRESS_NOT_SET) + let address = core::mem::replace( + &mut self.address, + multiversx_sc::types::ManagedOption::none(), + ); + address.unwrap_or_sc_panic(multiversx_sc::err_msg::RECIPIENT_ADDRESS_NOT_SET) + } + + fn extract_proxy_to(&mut self) -> Self::To { + self.extract_address() } } } diff --git a/framework/derive/src/generate/supertrait_gen.rs b/framework/derive/src/generate/supertrait_gen.rs index de5ba0f393..3d12cbb913 100644 --- a/framework/derive/src/generate/supertrait_gen.rs +++ b/framework/derive/src/generate/supertrait_gen.rs @@ -135,6 +135,7 @@ pub fn function_selector_module_calls(supertraits: &[Supertrait]) -> Vec proc_macro2::TokenStream { quote! { impl #module_path ProxyTrait for Proxy where A: multiversx_sc::api::VMApi {} + impl #module_path ProxyTrait for ProxyTo where A: multiversx_sc::api::VMApi {} } } diff --git a/framework/derive/src/lib.rs b/framework/derive/src/lib.rs index a68d493c97..917ecb2159 100644 --- a/framework/derive/src/lib.rs +++ b/framework/derive/src/lib.rs @@ -48,8 +48,16 @@ pub fn proxy( #[proc_macro_derive(TypeAbi)] pub fn type_abi_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let ast = syn::parse(input).unwrap(); - type_abi_derive::type_abi_derive(&ast) + type_abi_derive::type_abi_derive(input).into() +} + +#[proc_macro_attribute] +pub fn type_abi( + args: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + assert!(args.is_empty(), "#[type_abi] attribute takes no args"); + type_abi_derive::type_abi_full(input).into() } #[proc_macro_derive(ManagedVecItem)] diff --git a/framework/derive/src/model/endpoint.rs b/framework/derive/src/model/endpoint.rs index 5c3d403fdc..1385dd1ada 100644 --- a/framework/derive/src/model/endpoint.rs +++ b/framework/derive/src/model/endpoint.rs @@ -29,6 +29,9 @@ pub enum PublicRole { /// The smart contract constructor. There can be only one. Init(InitMetadata), + /// The smart contract upgrade constructor. + Upgrade(InitMetadata), + /// Means it gets a smart contract function generated for it Endpoint(EndpointMetadata), diff --git a/framework/derive/src/model/endpoint_type_metadata.rs b/framework/derive/src/model/endpoint_type_metadata.rs index 4d668b2df7..4c048e94cb 100644 --- a/framework/derive/src/model/endpoint_type_metadata.rs +++ b/framework/derive/src/model/endpoint_type_metadata.rs @@ -2,6 +2,7 @@ #[derive(Debug, Clone)] pub enum EndpointTypeMetadata { Init, + Upgrade, Endpoint, PromisesCallback, } @@ -12,6 +13,9 @@ impl EndpointTypeMetadata { EndpointTypeMetadata::Init => { quote! { multiversx_sc::abi::EndpointTypeAbi::Init } }, + EndpointTypeMetadata::Upgrade => { + quote! { multiversx_sc::abi::EndpointTypeAbi::Upgrade } + }, EndpointTypeMetadata::Endpoint => { quote! { multiversx_sc::abi::EndpointTypeAbi::Endpoint } }, diff --git a/framework/derive/src/model/method.rs b/framework/derive/src/model/method.rs index c705ecb268..776e39dfaa 100644 --- a/framework/derive/src/model/method.rs +++ b/framework/derive/src/model/method.rs @@ -77,6 +77,7 @@ impl Method { pub fn is_payable(&self) -> bool { match &self.public_role { PublicRole::Init(init_metadata) => init_metadata.payable.is_payable(), + PublicRole::Upgrade(upgrade_metadata) => upgrade_metadata.payable.is_payable(), PublicRole::Endpoint(endpoint_metadata) => endpoint_metadata.payable.is_payable(), PublicRole::Callback(_) | PublicRole::CallbackRaw | PublicRole::CallbackPromise(_) => { true @@ -88,6 +89,7 @@ impl Method { pub fn payable_metadata(&self) -> MethodPayableMetadata { match &self.public_role { PublicRole::Init(init_metadata) => init_metadata.payable.clone(), + PublicRole::Upgrade(upgrade_metadata) => upgrade_metadata.payable.clone(), PublicRole::Endpoint(endpoint_metadata) => endpoint_metadata.payable.clone(), PublicRole::Callback(_) | PublicRole::CallbackRaw | PublicRole::CallbackPromise(_) => { MethodPayableMetadata::AnyToken @@ -99,6 +101,7 @@ impl Method { pub fn is_allow_multiple_var_args(&self) -> bool { match &self.public_role { PublicRole::Init(init_metadata) => init_metadata.allow_multiple_var_args, + PublicRole::Upgrade(upgrade_metadata) => upgrade_metadata.allow_multiple_var_args, PublicRole::Endpoint(endpoint_metadata) => endpoint_metadata.allow_multiple_var_args, PublicRole::Callback(callback_metadata) | PublicRole::CallbackPromise(callback_metadata) => { diff --git a/framework/derive/src/parse/attributes/doc_attr.rs b/framework/derive/src/parse/attributes/doc_attr.rs index c2a670abb5..5c5ed4d41b 100644 --- a/framework/derive/src/parse/attributes/doc_attr.rs +++ b/framework/derive/src/parse/attributes/doc_attr.rs @@ -45,6 +45,24 @@ pub fn extract_doc(attrs: &[syn::Attribute]) -> Vec { .collect() } +pub fn extract_macro_attributes(attrs: &[syn::Attribute]) -> Vec { + let mut macro_attributes = Vec::new(); + + for a in attrs { + if let syn::Meta::List(list) = &a.meta { + if list.path.is_ident("derive") { + for token in list.tokens.clone().into_iter() { + if let proc_macro2::TokenTree::Ident(ident) = token { + macro_attributes.push(ident.to_string()); + } + } + } + } + } + + macro_attributes +} + fn remove_backslashes(input: &str) -> String { input .trim_matches('\"') diff --git a/framework/derive/src/parse/attributes/mod.rs b/framework/derive/src/parse/attributes/mod.rs index e355c78e61..e58c1a912e 100644 --- a/framework/derive/src/parse/attributes/mod.rs +++ b/framework/derive/src/parse/attributes/mod.rs @@ -11,7 +11,7 @@ mod trait_prop_names; mod util; pub use argument_attr::*; -pub use doc_attr::{extract_doc, OutputNameAttribute}; +pub use doc_attr::{extract_doc, extract_macro_attributes, OutputNameAttribute}; pub use endpoint_attr::*; pub use event_attr::*; pub use label_attr::*; diff --git a/framework/derive/src/parse/auto_impl_parse.rs b/framework/derive/src/parse/auto_impl_parse.rs index 11553794cd..24002e2139 100644 --- a/framework/derive/src/parse/auto_impl_parse.rs +++ b/framework/derive/src/parse/auto_impl_parse.rs @@ -4,17 +4,17 @@ use super::attributes::*; fn assert_no_other_auto_impl(method: &Method) { assert!( - method.implementation.is_no_implementation(), - "Only one auto-implementation can be specified at one time. Auto-implementations are: {}{}{}{}{}{}{}{}", - "`#[storage_get]`, ", - "`#[storage_set]`, ", - "`#[storage_mapper]`, ", - "`#[storage_is_empty]`, ", - "`#[storage_clear]`, ", - "`#[proxy]`, ", - "`#[module]`, ", - "`#[event]`." - ) + method.implementation.is_no_implementation(), + "Only one auto-implementation can be specified at one time. Auto-implementations are: {}{}{}{}{}{}{}{}", + "`#[storage_get]`, ", + "`#[storage_set]`, ", + "`#[storage_mapper]`, ", + "`#[storage_is_empty]`, ", + "`#[storage_clear]`, ", + "`#[proxy]`, ", + "`#[module]`, ", + "`#[event]`." + ) } pub fn process_event_attribute(attr: &syn::Attribute, method: &mut Method) -> bool { diff --git a/framework/derive/src/parse/endpoint_parse.rs b/framework/derive/src/parse/endpoint_parse.rs index 92fd4ff175..5edc30ad08 100644 --- a/framework/derive/src/parse/endpoint_parse.rs +++ b/framework/derive/src/parse/endpoint_parse.rs @@ -15,8 +15,8 @@ use super::{ fn check_single_role(method: &Method) { assert!(matches!(method.public_role, PublicRole::Private), - "Can only annotate with one of the following arguments: `#[init]`, `#[endpoint]`, `#[view]`, `#[callback]`, `#[callback_raw]`, `#[upgrade]`." - ); + "Can only annotate with one of the following arguments: `#[init]`, `#[endpoint]`, `#[view]`, `#[callback]`, `#[callback_raw]`, `#[upgrade]`." + ); } pub fn process_init_attribute( @@ -44,13 +44,8 @@ pub fn process_upgrade_attribute( let has_attr = is_upgrade(attr); if has_attr { check_single_role(&*method); - method.public_role = PublicRole::Endpoint(EndpointMetadata { - public_name: proc_macro2::Ident::new("upgrade", proc_macro2::Span::call_site()), + method.public_role = PublicRole::Upgrade(InitMetadata { payable: first_pass_data.payable.clone(), - only_owner: false, - only_admin: false, - only_user_account: false, - mutability: EndpointMutabilityMetadata::Mutable, allow_multiple_var_args: first_pass_data.allow_multiple_var_args, }); true diff --git a/framework/derive/src/parse/method_parse.rs b/framework/derive/src/parse/method_parse.rs index 267e9faa7b..a8c8a111c7 100644 --- a/framework/derive/src/parse/method_parse.rs +++ b/framework/derive/src/parse/method_parse.rs @@ -137,8 +137,8 @@ fn validate_method(method: &Method) { assert!( matches!( method.public_role, - PublicRole::Init(_) | PublicRole::Endpoint(_) | PublicRole::CallbackPromise(_) - ) || method.label_names.is_empty(), + PublicRole::Init(_) | PublicRole::Endpoint(_) | PublicRole::CallbackPromise(_) | PublicRole::Upgrade(_) + ) || method.label_names.is_empty(), "Labels can only be placed on endpoints, constructors, and promises callbacks. Method '{}' is neither.", &method.name.to_string() ) diff --git a/framework/derive/src/parse/payable_parse.rs b/framework/derive/src/parse/payable_parse.rs index 8d199b94a8..91deba4509 100644 --- a/framework/derive/src/parse/payable_parse.rs +++ b/framework/derive/src/parse/payable_parse.rs @@ -6,14 +6,14 @@ pub fn process_payable_attribute( pass_1_data: &mut MethodAttributesPass1, ) -> bool { PayableAttribute::parse(attr).map(|payable_attr| { - if let Some(identifier) = payable_attr.identifier { - pass_1_data.payable = parse_payable_identifier(identifier.as_str()); - } else { - panic!( - "Endpoint `payable` attribute requires one argument. Replace with `#[payable(\"*\")]` or `#[payable(\"EGLD\")]`. Method name: {}", - &pass_1_data.method_name); - } - }).is_some() + if let Some(identifier) = payable_attr.identifier { + pass_1_data.payable = parse_payable_identifier(identifier.as_str()); + } else { + panic!( + "Endpoint `payable` attribute requires one argument. Replace with `#[payable(\"*\")]` or `#[payable(\"EGLD\")]`. Method name: {}", + &pass_1_data.method_name); + } + }).is_some() } fn parse_payable_identifier(identifier: &str) -> MethodPayableMetadata { diff --git a/framework/derive/src/type_abi_derive.rs b/framework/derive/src/type_abi_derive.rs index efef94acb6..8c70b56af8 100644 --- a/framework/derive/src/type_abi_derive.rs +++ b/framework/derive/src/type_abi_derive.rs @@ -1,5 +1,6 @@ +use crate::parse::attributes::extract_macro_attributes; + use super::parse::attributes::extract_doc; -use proc_macro::TokenStream; use quote::quote; pub struct ExplicitDiscriminant { @@ -19,7 +20,7 @@ fn field_snippet(index: usize, field: &syn::Field) -> proc_macro2::TokenStream { field_descriptions.push(multiversx_sc::abi::StructFieldDescription::new( &[ #(#field_docs),* ], #field_name_str, - <#field_ty>::type_name(), + <#field_ty>::type_names(), )); <#field_ty>::provide_type_descriptions(accumulator); } @@ -43,24 +44,28 @@ fn fields_snippets(fields: &syn::Fields) -> Vec { } } -pub fn type_abi_derive(ast: &syn::DeriveInput) -> TokenStream { +pub fn type_abi_derive(input: proc_macro::TokenStream) -> proc_macro2::TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); let type_docs = extract_doc(ast.attrs.as_slice()); + let macro_attributes = extract_macro_attributes(ast.attrs.as_slice()); + let type_description_impl = match &ast.data { syn::Data::Struct(data_struct) => { let struct_field_snippets = fields_snippets(&data_struct.fields); quote! { fn provide_type_descriptions(accumulator: &mut TDC) { - let type_name = Self::type_name(); - if !accumulator.contains_type(&type_name) { - accumulator.reserve_type_name(type_name.clone()); + let type_names = Self::type_names(); + if !accumulator.contains_type(&type_names.abi) { + accumulator.reserve_type_name(type_names.clone()); let mut field_descriptions = multiversx_sc::types::heap::Vec::new(); #(#struct_field_snippets)* accumulator.insert( - type_name.clone(), + type_names.clone(), multiversx_sc::abi::TypeDescription::new( &[ #(#type_docs),* ], - type_name, + type_names, multiversx_sc::abi::TypeContents::Struct(field_descriptions), + &[ #(#macro_attributes),* ], ), ); } @@ -93,17 +98,18 @@ pub fn type_abi_derive(ast: &syn::DeriveInput) -> TokenStream { .collect(); quote! { fn provide_type_descriptions(accumulator: &mut TDC) { - let type_name = Self::type_name(); - if !accumulator.contains_type(&type_name) { - accumulator.reserve_type_name(type_name.clone()); + let type_names = Self::type_names(); + if !accumulator.contains_type(&type_names.abi) { + accumulator.reserve_type_name(type_names.clone()); let mut variant_descriptions = multiversx_sc::types::heap::Vec::new(); #(#enum_variant_snippets)* accumulator.insert( - type_name.clone(), + type_names.clone(), multiversx_sc::abi::TypeDescription::new( &[ #(#type_docs),* ], - type_name, + type_names, multiversx_sc::abi::TypeContents::Enum(variant_descriptions), + &[ #(#macro_attributes),* ], ), ); } @@ -116,16 +122,28 @@ pub fn type_abi_derive(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; let name_str = name.to_string(); let (impl_generics, ty_generics, where_clause) = &ast.generics.split_for_impl(); - let type_abi_impl = quote! { + quote! { + impl #impl_generics multiversx_sc::abi::TypeAbiFrom for #name #ty_generics #where_clause {} + impl #impl_generics multiversx_sc::abi::TypeAbiFrom<&Self> for #name #ty_generics #where_clause {} + impl #impl_generics multiversx_sc::abi::TypeAbi for #name #ty_generics #where_clause { + type Unmanaged = Self; + fn type_name() -> multiversx_sc::abi::TypeName { #name_str.into() } - #type_description_impl } - }; - type_abi_impl.into() + } +} + +pub fn type_abi_full(input: proc_macro::TokenStream) -> proc_macro2::TokenStream { + let input_conv = proc_macro2::TokenStream::from(input.clone()); + let derive_code = type_abi_derive(input); + quote! { + #input_conv + #derive_code + } } pub fn get_discriminant( diff --git a/framework/derive/src/validate/validate_method.rs b/framework/derive/src/validate/validate_method.rs index 9683e6c2ff..fafb2322e0 100644 --- a/framework/derive/src/validate/validate_method.rs +++ b/framework/derive/src/validate/validate_method.rs @@ -2,6 +2,7 @@ use super::reserved; use crate::model::{ArgPaymentMetadata, ContractTrait, Method, PublicRole}; const INIT_ENDPOINT_NAME: &str = "init"; +const UPGRADE_ENDPOINT_NAME: &str = "upgrade"; /// TODO: make it work with Result instead of panic pub fn validate_contract(contract_trait: &ContractTrait) { @@ -23,6 +24,10 @@ fn validate_method_name(m: &Method) { endpoint_name_str != INIT_ENDPOINT_NAME, "Cannot declare endpoint with name 'init'. Use #[init] instead." ); + assert!( + endpoint_name_str != UPGRADE_ENDPOINT_NAME, + "Cannot declare endpoint with name 'upgrade'. Use #[upgrade] instead." + ); assert!(!reserved::is_reserved(endpoint_name_str.as_str()), "Cannot declare endpoint with name '{endpoint_name_str}', because that name is reserved by the Arwen API."); } } @@ -73,7 +78,7 @@ fn validate_payment_args(m: &Method) { assert!(num_payment_token == 0, "`#[payment_token]` only allowed in payable endpoints, payable init or callbacks (method: `{}`)", m.name); } - if let PublicRole::Init(init_metadata) = &m.public_role { + if let PublicRole::Init(init_metadata) | PublicRole::Upgrade(init_metadata) = &m.public_role { assert!( init_metadata.payable.no_esdt(), "only EGLD payments currently allowed in constructors" diff --git a/framework/meta/Cargo.toml b/framework/meta/Cargo.toml index 65f1f192a3..805f3e7942 100644 --- a/framework/meta/Cargo.toml +++ b/framework/meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sc-meta" -version = "0.48.1" +version = "0.49.0-alpha.4" edition = "2021" authors = [ @@ -52,7 +52,7 @@ pathdiff = { version = "0.2.1", optional = true } common-path = { version = "1.0.0", optional = true } [dependencies.multiversx-sc] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../base" features = ["alloc", "num-bigint"] diff --git a/framework/meta/src/abi_json/contract_abi_json.rs b/framework/meta/src/abi_json/contract_abi_json.rs index c4f62916c3..58c0865eee 100644 --- a/framework/meta/src/abi_json/contract_abi_json.rs +++ b/framework/meta/src/abi_json/contract_abi_json.rs @@ -20,6 +20,10 @@ pub struct ContractAbiJson { #[serde(skip_serializing_if = "Option::is_none")] pub constructor: Option, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub upgrade_constructor: Option, + #[serde(default)] pub endpoints: Vec, @@ -48,6 +52,10 @@ impl From<&ContractAbi> for ContractAbiJson { docs: abi.docs.iter().map(|d| d.to_string()).collect(), name: abi.name.to_string(), constructor: abi.constructors.first().map(ConstructorAbiJson::from), + upgrade_constructor: abi + .upgrade_constructors + .first() + .map(ConstructorAbiJson::from), endpoints: abi.endpoints.iter().map(EndpointAbiJson::from).collect(), promises_callback_names: abi .promise_callbacks @@ -70,10 +78,10 @@ pub fn convert_type_descriptions_to_json( type_descriptions: &TypeDescriptionContainerImpl, ) -> BTreeMap { let mut types = BTreeMap::new(); - for (type_name, type_description) in type_descriptions.0.iter() { + for (type_names, type_description) in type_descriptions.0.iter() { if type_description.contents.is_specified() { types.insert( - type_name.clone(), + type_names.abi.clone(), TypeDescriptionJson::from(type_description), ); } diff --git a/framework/meta/src/abi_json/endpoint_abi_json.rs b/framework/meta/src/abi_json/endpoint_abi_json.rs index 5882fcd961..b6bd041713 100644 --- a/framework/meta/src/abi_json/endpoint_abi_json.rs +++ b/framework/meta/src/abi_json/endpoint_abi_json.rs @@ -19,7 +19,7 @@ impl From<&InputAbi> for InputAbiJson { fn from(abi: &InputAbi) -> Self { InputAbiJson { arg_name: abi.arg_name.to_string(), - type_name: abi.type_name.clone(), + type_name: abi.type_names.abi.clone(), multi_arg: if abi.multi_arg { Some(true) } else { None }, } } @@ -43,7 +43,7 @@ impl From<&OutputAbi> for OutputAbiJson { fn from(abi: &OutputAbi) -> Self { OutputAbiJson { output_name: abi.output_name.clone(), - type_name: abi.type_name.clone(), + type_name: abi.type_names.abi.clone(), multi_result: if abi.multi_result { Some(true) } else { None }, } } diff --git a/framework/meta/src/abi_json/type_abi_json.rs b/framework/meta/src/abi_json/type_abi_json.rs index 5602ae98cc..f26cc7086d 100644 --- a/framework/meta/src/abi_json/type_abi_json.rs +++ b/framework/meta/src/abi_json/type_abi_json.rs @@ -68,10 +68,10 @@ impl From<&TypeDescription> for TypeDescriptionJson { } impl TypeDescriptionJson { - pub fn to_type_description(&self, name: &str) -> TypeDescription { + pub fn to_type_description(&self, names: TypeNames) -> TypeDescription { TypeDescription { docs: self.docs.clone(), - name: name.to_string(), + names, contents: match self.content_type.as_str() { TYPE_DESCRIPTION_JSON_TYPE_STRUCT => TypeContents::Struct( self.fields @@ -87,6 +87,7 @@ impl TypeDescriptionJson { ), _ => TypeContents::NotSpecified, }, + macro_attributes: Vec::new(), } } } @@ -108,7 +109,7 @@ impl From<&StructFieldDescription> for StructFieldDescriptionJson { StructFieldDescriptionJson { docs: abi.docs.iter().map(|d| d.to_string()).collect(), name: abi.name.to_string(), - field_type: abi.field_type.clone(), + field_type: abi.field_type.abi.clone(), } } } @@ -118,7 +119,10 @@ impl StructFieldDescriptionJson { StructFieldDescription { docs: self.docs.clone(), name: self.name.clone(), - field_type: self.field_type.clone(), + field_type: TypeNames { + abi: self.field_type.clone(), + rust: "".into(), + }, } } } diff --git a/framework/meta/src/cli_args/cli_args_contract.rs b/framework/meta/src/cli_args/cli_args_contract.rs index 1853d64675..e05146a9bc 100644 --- a/framework/meta/src/cli_args/cli_args_contract.rs +++ b/framework/meta/src/cli_args/cli_args_contract.rs @@ -66,6 +66,12 @@ pub enum ContractCliAction { about = "Generates a snippets project, based on the contract ABI." )] GenerateSnippets(GenerateSnippetsArgs), + + #[command( + name = "proxy", + about = "Generates a proxy, based on the contract ABI." + )] + GenerateProxies, } impl CliArgsToRaw for ContractCliAction { @@ -97,6 +103,9 @@ impl CliArgsToRaw for ContractCliAction { raw.push("snippets".to_string()); raw.append(&mut args.to_raw()); }, + ContractCliAction::GenerateProxies => { + raw.push("proxy".to_string()); + }, } raw } diff --git a/framework/meta/src/cmd/contract.rs b/framework/meta/src/cmd/contract.rs index 215c394d63..8011d3f2e3 100644 --- a/framework/meta/src/cmd/contract.rs +++ b/framework/meta/src/cmd/contract.rs @@ -1,3 +1,4 @@ +mod generate_proxy; mod generate_snippets; mod meta_abi; mod meta_config; @@ -28,9 +29,10 @@ pub fn cli_main() { }, ContractCliAction::Clean => meta_config_opt.clean(), ContractCliAction::Update => meta_config_opt.update(), - ContractCliAction::GenerateSnippets(gs_args) => { - meta_config_opt.generate_rust_snippets(&gs_args) + ContractCliAction::GenerateSnippets(gs_arg) => { + meta_config_opt.generate_rust_snippets(&gs_arg) }, + ContractCliAction::GenerateProxies => meta_config_opt.generate_proxy(), } } diff --git a/framework/meta/src/cmd/contract/generate_proxy.rs b/framework/meta/src/cmd/contract/generate_proxy.rs new file mode 100644 index 0000000000..3a7443d612 --- /dev/null +++ b/framework/meta/src/cmd/contract/generate_proxy.rs @@ -0,0 +1,4 @@ +pub mod proxy_crate_gen; +pub mod proxy_gen_main; +mod proxy_generator; +mod proxy_process_type_name; diff --git a/framework/meta/src/cmd/contract/generate_proxy/proxy_crate_gen.rs b/framework/meta/src/cmd/contract/generate_proxy/proxy_crate_gen.rs new file mode 100644 index 0000000000..8b5960577d --- /dev/null +++ b/framework/meta/src/cmd/contract/generate_proxy/proxy_crate_gen.rs @@ -0,0 +1,8 @@ +use std::fs::File; + +#[must_use] +pub(crate) fn create_file(proxy_file_name: &str) -> File { + let file = format!("../{proxy_file_name}"); + + File::create(file).expect("could not write proxy file") +} diff --git a/framework/meta/src/cmd/contract/generate_proxy/proxy_gen_main.rs b/framework/meta/src/cmd/contract/generate_proxy/proxy_gen_main.rs new file mode 100644 index 0000000000..4ef8582bcb --- /dev/null +++ b/framework/meta/src/cmd/contract/generate_proxy/proxy_gen_main.rs @@ -0,0 +1,21 @@ +use crate::cmd::contract::sc_config::ProxyConfigSerde; + +use super::{ + super::meta_config::MetaConfig, proxy_crate_gen::create_file, proxy_generator::ProxyGenerator, +}; + +impl MetaConfig { + pub fn generate_proxy(&mut self) { + let default_proxy = ProxyConfigSerde::new(); + write_proxy_with_explicit_path(&default_proxy, self); + for proxy_config in self.sc_config.proxy_configs.clone() { + write_proxy_with_explicit_path(&proxy_config, self); + } + } +} + +fn write_proxy_with_explicit_path(proxy_config: &ProxyConfigSerde, meta_config: &mut MetaConfig) { + let mut file = create_file(&proxy_config.path); + let mut proxy_generator = ProxyGenerator::new(meta_config, &mut file, proxy_config); + proxy_generator.write_proxy_to_file(); +} diff --git a/framework/meta/src/cmd/contract/generate_proxy/proxy_generator.rs b/framework/meta/src/cmd/contract/generate_proxy/proxy_generator.rs new file mode 100644 index 0000000000..9c0e2a2479 --- /dev/null +++ b/framework/meta/src/cmd/contract/generate_proxy/proxy_generator.rs @@ -0,0 +1,695 @@ +use std::{fmt::Display, fs::File, io::Write}; + +use multiversx_sc::abi::{ + EndpointAbi, EnumVariantDescription, InputAbi, OutputAbi, StructFieldDescription, TypeContents, + TypeDescription, +}; + +use crate::cmd::contract::{meta_config::MetaConfig, sc_config::ProxyConfigSerde}; + +use super::proxy_process_type_name::{ + extract_paths, extract_struct_crate, process_rust_type, proxy_methods_type_name, + proxy_type_name, +}; + +const PRELUDE: &str = "// Code generated by the multiversx-sc proxy generator. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +#![allow(dead_code)] +#![allow(clippy::all)] +"; + +const IMPORTS: &str = "use multiversx_sc::proxy_imports::*;"; + +const ZERO: &str = "0"; + +/// Types defined in the framework don't need to be generated again in the proxy. +const TYPES_FROM_FRAMEWORK: &[&str] = &[ + "EsdtTokenPayment", + "EgldOrEsdtTokenPayment", + "EsdtTokenData", + "EgldOrEsdtTokenIdentifier", + "EgldOrEsdtTokenPayment", + "EgldOrMultiEsdtPayment", + "EsdtTokenData", + "EsdtLocalRole", + "EsdtTokenType", +]; + +pub struct ProxyGenerator<'a> { + pub meta_config: &'a MetaConfig, + pub file: Option<&'a mut File>, + pub proxy_config: &'a ProxyConfigSerde, +} + +impl<'a> ProxyGenerator<'a> { + pub fn new( + meta_config: &'a MetaConfig, + file: &'a mut File, + proxy_config: &'a ProxyConfigSerde, + ) -> Self { + Self { + meta_config, + file: Some(file), + proxy_config, + } + } + + fn write(&mut self, s: impl Display) { + let file = self.file.as_mut().expect("output not configured"); + write!(*file, "{s}").unwrap(); + } + + fn writeln(&mut self, s: impl Display) { + self.write(s); + self.write("\n"); + } + + pub fn write_proxy_to_file(&mut self) { + self.write_header(); + self.write_tx_proxy_type_def(); + self.write_impl_for_tx_proxy(); + self.write_struct_tx_proxy_methods(); + self.write_content(); + self.write_types(); + } + + fn write_header(&mut self) { + self.writeln(PRELUDE); + match &self.proxy_config.override_import { + Some(override_import) => self.writeln(override_import), + None => self.writeln(IMPORTS), + } + } + + fn write_tx_proxy_type_def(&mut self) { + let proxy_type_name = proxy_type_name(&self.meta_config.original_contract_abi.name); + self.writeln(format!( + r#" +pub struct {proxy_type_name};"# + )); + } + + fn write_impl_for_tx_proxy(&mut self) { + let proxy_type_name = proxy_type_name(&self.meta_config.original_contract_abi.name); + let proxy_methods_type_name = + proxy_methods_type_name(&self.meta_config.original_contract_abi.name); + self.writeln(format!( + r#" +impl TxProxyTrait for {proxy_type_name} +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{{ + type TxProxyMethods = {proxy_methods_type_name}; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods {{ + {proxy_methods_type_name} {{ wrapped_tx: tx }} + }} +}}"# + )); + } + + fn write_struct_tx_proxy_methods(&mut self) { + let proxy_methods_type_name = + proxy_methods_type_name(&self.meta_config.original_contract_abi.name); + self.writeln(format!( + r#" +pub struct {proxy_methods_type_name} +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{{ + wrapped_tx: Tx, +}}"# + )); + } + + fn write_content(&mut self) { + if !self + .meta_config + .original_contract_abi + .constructors + .is_empty() + { + self.write_constructors(); + } + + if !self + .meta_config + .original_contract_abi + .upgrade_constructors + .is_empty() + { + self.write_upgrades(); + } + + if !self.meta_config.original_contract_abi.endpoints.is_empty() { + self.write_endpoints(); + } + } + + fn write_types(&mut self) { + for (_, type_description) in &self.meta_config.original_contract_abi.type_descriptions.0 { + if self + .meta_config + .original_contract_abi + .get_crate_name_for_code() + != extract_struct_crate(type_description.names.rust.as_str()) + { + continue; + } + + let type_name = self.adjust_type_name_with_api(&type_description.names.rust); + if TYPES_FROM_FRAMEWORK.contains(&type_name.as_str()) { + continue; + } + + match &type_description.contents { + TypeContents::Enum(enum_variants) => { + self.write_enum(enum_variants, type_description, &type_name) + }, + TypeContents::Struct(struct_fields) => { + self.write_struct(struct_fields, type_description, &type_name) + }, + TypeContents::NotSpecified => {}, + TypeContents::ExplicitEnum(_) => {}, + } + } + } + + fn write_constructors(&mut self) { + let constructors: Vec = + self.meta_config.original_contract_abi.constructors.clone(); + + self.write_header_impl_constructor(); + for (i, constructor_abi) in constructors.into_iter().enumerate() { + if i > 0 { + self.writeln(""); + } + self.write_constructor_header(&constructor_abi); + self.write_constructor_content(constructor_abi.inputs); + self.write_end_of_function(); + } + + self.writeln("}"); + } + + fn write_upgrades(&mut self) { + self.write_header_impl_upgrade(); + for (i, upgrade) in self + .meta_config + .original_contract_abi + .upgrade_constructors + .clone() + .into_iter() + .enumerate() + { + if i > 0 { + self.writeln(""); + } + self.write_upgrade_header(&upgrade); + self.write_upgrade_content(upgrade.inputs); + self.write_end_of_function(); + } + + self.writeln("}"); + } + + fn write_endpoints(&mut self) { + let endpoints: Vec = self.meta_config.original_contract_abi.endpoints.clone(); + + self.write_header_impl_endpoints(); + for (i, endpoint_abi) in endpoints.into_iter().enumerate() { + if i > 0 { + self.writeln(""); + } + self.write_endpoint_header(&endpoint_abi); + self.write_endpoint_content(&endpoint_abi); + self.write_end_of_function(); + } + + self.writeln("}"); + } + + fn write_header_impl_constructor(&mut self) { + let proxy_methods_type_name = + proxy_methods_type_name(&self.meta_config.original_contract_abi.name); + self.writeln(format!( + r#" +#[rustfmt::skip] +impl {proxy_methods_type_name} +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{{"# + )); + } + + fn write_header_impl_upgrade(&mut self) { + let proxy_methods_type_name = + proxy_methods_type_name(&self.meta_config.original_contract_abi.name); + self.writeln(format!( + r#" +#[rustfmt::skip] +impl {proxy_methods_type_name} +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{{"# + )); + } + + fn write_header_impl_endpoints(&mut self) { + let proxy_methods_type_name = + proxy_methods_type_name(&self.meta_config.original_contract_abi.name); + self.writeln(format!( + r#" +#[rustfmt::skip] +impl {proxy_methods_type_name} +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{{"# + )); + } + + fn write_constructor_header(&mut self, constructor_abi: &EndpointAbi) { + self.write_fn_signature(constructor_abi); + self.write_constructor_output(&constructor_abi.outputs); + } + + fn write_upgrade_header(&mut self, constructor_abi: &EndpointAbi) { + self.write_fn_signature(constructor_abi); + self.write_upgrade_output(&constructor_abi.outputs); + } + + fn write_endpoint_header(&mut self, constructor_abi: &EndpointAbi) { + self.write_fn_signature(constructor_abi); + self.write_endpoint_output(&constructor_abi.outputs); + } + + fn write_constructor_content(&mut self, inputs: Vec) { + self.writeln( + " self.wrapped_tx + .raw_deploy()", + ); + for input in inputs.iter() { + self.writeln(format!(" .argument(&{})", input.arg_name)); + } + self.writeln(" .original_result()"); + } + + fn write_upgrade_content(&mut self, inputs: Vec) { + self.writeln( + " self.wrapped_tx + .raw_upgrade()", + ); + for input in inputs.iter() { + self.writeln(format!(" .argument(&{})", input.arg_name)); + } + self.writeln(" .original_result()"); + } + + fn write_endpoint_content(&mut self, endpoint: &EndpointAbi) { + self.writeln(format!( + " self.wrapped_tx + .raw_call(\"{}\")", + endpoint.name + )); + + for input in endpoint.inputs.iter() { + self.writeln(format!(" .argument(&{})", input.arg_name)); + } + + self.writeln(" .original_result()"); + } + + fn write_fn_signature(&mut self, endpoint: &EndpointAbi) { + self.write_endpoint_docs(&endpoint.docs); + self.write_function_header_endpoint(&endpoint.rust_method_name); + self.write_args(&endpoint.inputs); + self.write_parameters(&endpoint.inputs); + } + + fn write_endpoint_docs(&mut self, docs: &Vec) { + for doc in docs { + self.writeln(format!(" /// {doc} ")); + } + } + + fn write_function_header_endpoint(&mut self, rust_method_name: &String) { + self.write(format!(" pub fn {rust_method_name}")); + } + + fn write_args(&mut self, inputs: &[InputAbi]) { + if inputs.is_empty() { + return; + } + + self.writeln("<"); + + for (index, input) in inputs.iter().enumerate() { + self.write_argument(index, &input.type_names.rust); + } + + self.write(" >"); + } + + fn write_argument(&mut self, index: usize, rust_name: &str) { + let adjusted = self.adjust_type_name_with_env_api(rust_name); + self.writeln(format!(" Arg{index}: ProxyArg<{adjusted}>,")); + } + + fn write_parameters(&mut self, inputs: &[InputAbi]) { + self.writeln("("); + self.writeln(" self,"); + for (index, input) in inputs.iter().enumerate() { + self.writeln(format!(" {}: Arg{index},", &input.arg_name)); + } + self.write(" ) "); + } + + fn write_constructor_output(&mut self, outputs: &[OutputAbi]) { + self.write("-> TxProxyDeploy {"); + } + + fn write_upgrade_output(&mut self, outputs: &[OutputAbi]) { + self.write("-> TxProxyUpgrade {"); + } + + fn write_endpoint_output(&mut self, outputs: &[OutputAbi]) { + self.write("-> TxProxyCall {"); + } + + fn parse_and_write_outputs(&mut self, outputs: &[OutputAbi]) { + match outputs.len() { + 0 => { + self.write("()"); + }, + 1 => { + let adjusted = self.adjust_type_name_with_env_api(&outputs[0].type_names.rust); + self.write(adjusted); + }, + _ => { + self.write(format!("MultiValue{}<", outputs.len())); + for (i, output) in outputs.iter().enumerate() { + if i > 0 { + self.write(", "); + } + let adjusted = self.adjust_type_name_with_env_api(&output.type_names.rust); + self.write(adjusted); + } + self.write(">"); + }, + } + } + + fn write_enum( + &mut self, + enum_variants: &Vec, + type_description: &TypeDescription, + name: &str, + ) { + if self.enum_contains_struct_variant(enum_variants) { + self.write("\n#[rustfmt::skip]"); + } + + self.start_write_type("enum", type_description, name); + + if enum_variants.is_empty() { + self.writeln("}"); + return; + } + + self.writeln(""); + + for variant in enum_variants { + self.write(format!(" {}", variant.name)); + if variant.fields.is_empty() { + self.writeln(","); + continue; + } + + if variant.fields[0].name == ZERO { + self.write_tuple_in_variant(&variant.fields); + } else { + self.write_struct_in_variant(&variant.fields); + } + } + self.writeln("}"); + } + + fn write_struct( + &mut self, + struct_fields: &Vec, + type_description: &TypeDescription, + name: &str, + ) { + self.start_write_type("struct", type_description, name); + + if struct_fields.is_empty() { + self.writeln("}"); + return; + } + + self.writeln(""); + + for field in struct_fields { + let adjusted_type_name = self.adjust_type_name_with_api(&field.field_type.rust); + self.writeln(format!(" pub {}: {adjusted_type_name},", field.name)); + } + + self.writeln("}"); + } + + fn write_tuple_in_variant(&mut self, fields: &[StructFieldDescription]) { + self.write("("); + for (i, field) in fields.iter().enumerate() { + if i > 0 { + self.write(", "); + } + let adjusted_type_name = self.adjust_type_name_with_api(&field.field_type.rust); + self.write(adjusted_type_name); + } + + self.writeln("),"); + } + + fn write_struct_in_variant(&mut self, fields: &[StructFieldDescription]) { + self.writeln(" {"); + + for field in fields { + let adjusted_type_name = self.adjust_type_name_with_api(&field.field_type.rust); + self.writeln(format!(" {}: {adjusted_type_name},", field.name,)); + } + + self.writeln(" },"); + } + + pub fn clean_paths(&mut self, rust_type: &str) -> String { + let paths = extract_paths(rust_type); + + let processed_paths = self.process_paths(&paths); + + let processed_rust_type = process_rust_type(rust_type.to_string(), paths, processed_paths); + + self.rename_path_with_custome_config(&processed_rust_type) + } + + fn start_write_type( + &mut self, + type_type: &str, + type_description: &TypeDescription, + name: &str, + ) { + self.writeln(""); + self.writeln("#[type_abi]"); + self.write_macro_attributes(&type_description.macro_attributes); + self.write(format!(r#"pub {type_type} {name}"#)); + + if name.contains("") { + self.writeln( + " +where + Api: ManagedTypeApi,", + ); + } else { + self.write(" "); + } + + self.write("{"); + } + + pub fn write_macro_attributes(&mut self, macro_attributes: &[String]) { + if macro_attributes.is_empty() { + self.writeln("#[derive(TopEncode, TopDecode)]"); + } else { + self.writeln(format!("#[derive({})]", macro_attributes.join(", "))); + } + } + + fn adjust_type_name_with_env_api(&mut self, original_rust_name: &str) -> String { + self.clean_paths( + &original_rust_name + .replace("multiversx_sc::api::uncallable::UncallableApi", "Env::Api") + .replace("$API", "Env::Api"), + ) + } + + fn adjust_type_name_with_api(&mut self, original_rust_name: &str) -> String { + self.clean_paths( + &original_rust_name + .replace("multiversx_sc::api::uncallable::UncallableApi", "Api") + .replace("$API", "Api"), + ) + } + + fn write_end_of_function(&mut self) { + self.writeln(" }"); + } + + fn rename_path_with_custome_config(&self, processed_type: &str) -> String { + let mut renamed_processed_type = processed_type.to_owned(); + + if let Some(paths_rename) = &self.proxy_config.path_rename { + for path_rename in paths_rename { + if processed_type.contains(&path_rename.from) { + renamed_processed_type = + renamed_processed_type.replace(&path_rename.from, &path_rename.to); + } + } + } + + renamed_processed_type + } + + fn process_paths(&self, paths: &Vec) -> Vec { + let mut processed_paths: Vec = Vec::new(); + let crate_name = self + .meta_config + .original_contract_abi + .get_crate_name_for_code(); + + for path in paths { + let type_rust_name = path.split("::").last().unwrap(); + if crate_name == extract_struct_crate(path) + || TYPES_FROM_FRAMEWORK.contains(&type_rust_name) + { + processed_paths.push(type_rust_name.to_string()); + } else { + processed_paths.push(path.to_string()); + } + } + + processed_paths + } + + fn enum_contains_struct_variant(&self, enum_variants: &Vec) -> bool { + for variant in enum_variants { + if variant.fields.is_empty() { + continue; + } + + if variant.fields[0].name != ZERO { + return true; + } + } + + false + } +} + +#[cfg(test)] +pub mod tests { + use multiversx_sc::abi::{BuildInfoAbi, ContractAbi, ContractCrateBuildAbi, FrameworkBuildAbi}; + + use crate::cmd::contract::{meta_config::MetaConfig, sc_config::ProxyConfigSerde}; + + use super::ProxyGenerator; + + #[test] + fn clean_paths_unsanitized_test() { + let build_info = BuildInfoAbi { + contract_crate: ContractCrateBuildAbi { + name: "contract-crate", + version: "0.0.0", + git_version: "0.0.0", + }, + framework: FrameworkBuildAbi::create(), + }; + + let original_contract_abi = ContractAbi::new(build_info, &[""], "contract-crate", false); + let meta_config = MetaConfig::create(original_contract_abi, false); + let mut proxy_generator = ProxyGenerator { + meta_config: &meta_config, + file: None, + proxy_config: &ProxyConfigSerde::new(), + }; + + let cleaned_path_unsanitized = proxy_generator.clean_paths( + "(other_crate::contract_crate::TestStruct, Option>)", + ); + let expected_result_unsanitized = + "(other_crate::contract_crate::TestStruct, Option>)"; + + assert_eq!( + expected_result_unsanitized, + cleaned_path_unsanitized.as_str() + ); + } + + #[test] + fn clean_paths_sanitized_test() { + let build_info = BuildInfoAbi { + contract_crate: ContractCrateBuildAbi { + name: "contract-crate", + version: "0.0.0", + git_version: "0.0.0", + }, + framework: FrameworkBuildAbi::create(), + }; + + let original_contract_abi = ContractAbi::new(build_info, &[""], "contract-crate", false); + let meta_config = MetaConfig::create(original_contract_abi, false); + let mut proxy_generator = ProxyGenerator { + meta_config: &meta_config, + file: None, + proxy_config: &ProxyConfigSerde::new(), + }; + + let cleaned_path_sanitized = proxy_generator.clean_paths( + "(contract_crate::other_crate::TestStruct, Option>)", + ); + let expected_result_sanitized = "(TestStruct, Option>)"; + + assert_eq!(expected_result_sanitized, cleaned_path_sanitized.as_str()); + } +} diff --git a/framework/meta/src/cmd/contract/generate_proxy/proxy_process_type_name.rs b/framework/meta/src/cmd/contract/generate_proxy/proxy_process_type_name.rs new file mode 100644 index 0000000000..350243d662 --- /dev/null +++ b/framework/meta/src/cmd/contract/generate_proxy/proxy_process_type_name.rs @@ -0,0 +1,37 @@ +pub(super) fn proxy_type_name(contract_trait_name: &str) -> String { + format!("{contract_trait_name}Proxy") +} + +pub(super) fn proxy_methods_type_name(contract_trait_name: &str) -> String { + format!("{contract_trait_name}ProxyMethods") +} + +pub(super) fn extract_struct_crate(struct_path: &str) -> String { + let crate_name = struct_path.split("::").next().unwrap_or(struct_path); + crate_name.to_string() +} + +pub(super) fn process_rust_type( + rust_type: String, + paths: Vec, + processed_paths: Vec, +) -> String { + let mut processed_rust_type: String = rust_type.to_string().clone(); + for index in 0..paths.len() { + processed_rust_type = processed_rust_type.replace( + paths.get(index).unwrap(), + processed_paths.get(index).unwrap(), + ); + } + + processed_rust_type +} + +pub(super) fn extract_paths(rust_type: &str) -> Vec { + let delimiters = "<>,()[] "; + rust_type + .split(|c| delimiters.contains(c)) + .filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .collect() +} diff --git a/framework/meta/src/cmd/contract/generate_snippets/snippet_sc_functions_gen.rs b/framework/meta/src/cmd/contract/generate_snippets/snippet_sc_functions_gen.rs index 94b0cc8a43..ade7591547 100644 --- a/framework/meta/src/cmd/contract/generate_snippets/snippet_sc_functions_gen.rs +++ b/framework/meta/src/cmd/contract/generate_snippets/snippet_sc_functions_gen.rs @@ -133,7 +133,7 @@ fn write_endpoint_args_declaration(file: &mut File, inputs: &[InputAbi]) { } for input in inputs { - let rust_type = map_abi_type_to_rust_type(input.type_name.clone()); + let rust_type = map_abi_type_to_rust_type(input.type_names.abi.clone()); writeln!( file, " let {} = {};", @@ -205,7 +205,7 @@ fn write_contract_query(file: &mut File, endpoint_abi: &EndpointAbi) { .unwrap(); } -fn map_output_types_to_rust_types(outputs: &[OutputAbi]) -> String { +pub fn map_output_types_to_rust_types(outputs: &[OutputAbi]) -> String { let results_len = outputs.len(); if results_len == 0 { return "()".to_string(); @@ -220,7 +220,7 @@ fn map_output_types_to_rust_types(outputs: &[OutputAbi]) -> String { } for (i, output) in outputs.iter().enumerate() { - input_str += &output.type_name; + input_str += &output.type_names.abi; if i < results_len - 1 { input_str += ","; diff --git a/framework/meta/src/cmd/contract/generate_snippets/snippet_template_gen.rs b/framework/meta/src/cmd/contract/generate_snippets/snippet_template_gen.rs index 0feb12e562..093afa908c 100644 --- a/framework/meta/src/cmd/contract/generate_snippets/snippet_template_gen.rs +++ b/framework/meta/src/cmd/contract/generate_snippets/snippet_template_gen.rs @@ -12,19 +12,7 @@ pub(crate) fn write_snippet_imports(file: &mut File, contract_crate_name: &str) use {contract_crate_name}::ProxyTrait as _; use {contract_crate_name}::*; -use multiversx_sc_snippets::{{ - env_logger, - erdrs::wallet::Wallet, - multiversx_sc::{{codec::multi_types::*, types::*}}, - multiversx_sc_scenario::{{ - api::StaticApi, - bech32, - scenario_format::interpret_trait::{{InterpretableFrom, InterpreterContext}}, - scenario_model::*, - ContractInfo, - }}, - sdk, tokio, Interactor, -}}; +use multiversx_sc_snippets::imports::*; " ) .unwrap(); diff --git a/framework/meta/src/cmd/contract/generate_snippets/snippet_type_map.rs b/framework/meta/src/cmd/contract/generate_snippets/snippet_type_map.rs index 803f8c6b29..5e6e28423b 100644 --- a/framework/meta/src/cmd/contract/generate_snippets/snippet_type_map.rs +++ b/framework/meta/src/cmd/contract/generate_snippets/snippet_type_map.rs @@ -183,7 +183,7 @@ fn get_abi_type(abi_type_str: &str) -> AbiType { } } -fn handle_abi_type(type_string: &mut RustTypeString, abi_type_str: String) { +pub fn handle_abi_type(type_string: &mut RustTypeString, abi_type_str: String) { let abi_type = get_abi_type(&abi_type_str); match abi_type { AbiType::UserDefined(user_type) => { diff --git a/framework/meta/src/cmd/contract/sc_config.rs b/framework/meta/src/cmd/contract/sc_config.rs index 16ac60826e..2fac2e38eb 100644 --- a/framework/meta/src/cmd/contract/sc_config.rs +++ b/framework/meta/src/cmd/contract/sc_config.rs @@ -3,6 +3,7 @@ mod contract_variant_builder; mod contract_variant_settings; mod contract_variant_validate; mod sc_config_model; +mod sc_config_proxy; mod sc_config_serde; mod wasm_build; mod wasm_clean; @@ -12,6 +13,7 @@ mod wasm_update; pub use contract_variant::ContractVariant; pub use contract_variant_settings::{ContractVariantProfile, ContractVariantSettings}; pub use sc_config_model::ScConfig; +pub use sc_config_proxy::ProxyConfigSerde; pub use sc_config_serde::{ ContractVariantProfileSerde, ContractVariantSerde, MultiContractGeneralSettingsSerde, ScConfigSerde, diff --git a/framework/meta/src/cmd/contract/sc_config/contract_variant.rs b/framework/meta/src/cmd/contract/sc_config/contract_variant.rs index 6b6cf70cc4..feab3976cf 100644 --- a/framework/meta/src/cmd/contract/sc_config/contract_variant.rs +++ b/framework/meta/src/cmd/contract/sc_config/contract_variant.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use super::ContractVariantSettings; +use super::{contract_variant_builder::default_wasm_crate_name, ContractVariantSettings}; use crate::cli_args::BuildArgs; use multiversx_sc::abi::ContractAbi; @@ -35,6 +35,19 @@ pub struct ContractVariant { } impl ContractVariant { + pub fn default_from_abi(abi: &ContractAbi) -> Self { + let default_contract_config_name = abi.build_info.contract_crate.name.to_string(); + let wasm_crate_name = default_wasm_crate_name(&default_contract_config_name); + ContractVariant { + main: true, + settings: ContractVariantSettings::default(), + contract_id: default_contract_config_name.clone(), + contract_name: default_contract_config_name, + wasm_crate_name, + abi: abi.clone(), + } + } + pub fn public_name_snake_case(&self) -> String { self.contract_name.replace('-', "_") } @@ -154,6 +167,9 @@ impl ContractVariant { /// Should correspond to all wasm exported functions. pub fn all_exported_function_names(&self) -> Vec { let mut result = vec!["init".to_string()]; + if !self.abi.upgrade_constructors.is_empty() { + result.push("upgrade".to_string()) + } result.append(&mut self.endpoint_names()); if self.abi.has_callback { result.push("callBack".to_string()); @@ -169,6 +185,10 @@ impl std::fmt::Debug for ContractVariant { .field("config_name", &self.contract_id) .field("public_name", &self.contract_name) .field("num-constructors", &self.abi.constructors.len()) + .field( + "num-upgrade-constructors", + &self.abi.upgrade_constructors.len(), + ) .field("num-endpoints", &self.abi.endpoints.len()) .field("settings", &self.settings) .finish() diff --git a/framework/meta/src/cmd/contract/sc_config/contract_variant_builder.rs b/framework/meta/src/cmd/contract/sc_config/contract_variant_builder.rs index d447ab4a0a..bb6a439245 100644 --- a/framework/meta/src/cmd/contract/sc_config/contract_variant_builder.rs +++ b/framework/meta/src/cmd/contract/sc_config/contract_variant_builder.rs @@ -169,11 +169,13 @@ fn collect_add_endpoints( fn build_contract_abi(builder: ContractVariantBuilder, original_abi: &ContractAbi) -> ContractAbi { let mut constructors = Vec::new(); + let mut upgrade_constructors = Vec::new(); let mut endpoints = Vec::new(); let mut promise_callbacks = Vec::new(); for endpoint_abi in builder.collected_endpoints { match endpoint_abi.endpoint_type { multiversx_sc::abi::EndpointTypeAbi::Init => constructors.push(endpoint_abi), + multiversx_sc::abi::EndpointTypeAbi::Upgrade => upgrade_constructors.push(endpoint_abi), multiversx_sc::abi::EndpointTypeAbi::Endpoint => endpoints.push(endpoint_abi), multiversx_sc::abi::EndpointTypeAbi::PromisesCallback => { promise_callbacks.push(endpoint_abi) @@ -188,6 +190,7 @@ fn build_contract_abi(builder: ContractVariantBuilder, original_abi: &ContractAb docs: original_abi.docs.clone(), name: original_abi.name.clone(), constructors, + upgrade_constructors, endpoints, promise_callbacks, events: original_abi.events.clone(), @@ -197,7 +200,7 @@ fn build_contract_abi(builder: ContractVariantBuilder, original_abi: &ContractAb } } -fn default_wasm_crate_name(contract_name: &str) -> String { +pub(crate) fn default_wasm_crate_name(contract_name: &str) -> String { format!("{contract_name}-wasm") } @@ -233,7 +236,7 @@ fn set_main_contract_flag( ) } else { let first_contract = contracts.get_mut(0).unwrap_or_else(|| { - panic!("Cannot set default contract because no optput contract was specified.") + panic!("Cannot set default contract because no output contract was specified.") }); first_contract.main = true; } @@ -260,22 +263,42 @@ impl ScConfig { .iter() .map(ContractVariantBuilder::map_from_config) .collect(); - collect_unlabelled_endpoints(&mut contract_builders, original_abi); - collect_labelled_endpoints(&mut contract_builders, original_abi); - collect_add_endpoints(&mut contract_builders, original_abi); - process_labels_for_contracts(&mut contract_builders, &config.labels_for_contracts); + collect_and_process_endpoints( + &mut contract_builders, + original_abi, + &config.labels_for_contracts, + ); + let mut contracts: Vec = contract_builders .into_values() .map(|builder| build_contract(builder, original_abi)) .collect(); + if contracts.is_empty() { + contracts.push(ContractVariant::default_from_abi(original_abi)); + } set_main_contract_flag(&mut contracts, &config.settings.main); validate_contract_variants(&contracts); + let default_contract_config_name = config.settings.main.clone().unwrap_or_default(); ScConfig { - default_contract_config_name: config.settings.main.clone().unwrap_or_default(), + default_contract_config_name, contracts, + proxy_configs: config.proxy.clone(), } } +} + +fn collect_and_process_endpoints( + contract_builders: &mut HashMap, + original_abi: &ContractAbi, + labels_for_contracts: &HashMap>, +) { + collect_unlabelled_endpoints(contract_builders, original_abi); + collect_labelled_endpoints(contract_builders, original_abi); + collect_add_endpoints(contract_builders, original_abi); + process_labels_for_contracts(contract_builders, labels_for_contracts); +} +impl ScConfig { /// Provides the config for the cases where no `multicontract.toml` file is available. /// /// The default configuration contains a single main contract, with all endpoints. @@ -292,6 +315,7 @@ impl ScConfig { wasm_crate_name, abi: original_abi.clone(), }], + proxy_configs: Vec::new(), } } diff --git a/framework/meta/src/cmd/contract/sc_config/contract_variant_validate.rs b/framework/meta/src/cmd/contract/sc_config/contract_variant_validate.rs index a0c0acb886..7ea1572437 100644 --- a/framework/meta/src/cmd/contract/sc_config/contract_variant_validate.rs +++ b/framework/meta/src/cmd/contract/sc_config/contract_variant_validate.rs @@ -9,28 +9,24 @@ pub fn validate_contract_variant(contract_variant: &ContractVariant) -> Result<( } fn check_single_constructor(contract_variant: &ContractVariant) -> Result<(), String> { - match contract_variant.abi.constructors.len() { - 0 => if has_upgrade(contract_variant) { - Ok(()) - } else { - Err("Missing constructor. Add a method annotated with `#[init]`.".to_string()) - }, - 1 => Ok(()), - _ => Err("More than one contrctructor present. Exactly one method annotated with `#[init]` is required.".to_string()), + match ( + contract_variant.abi.constructors.len(), + contract_variant.abi.upgrade_constructors.len(), + ) { + (0, 0) => Err("Missing constructor. Add a method annotated with `#[init]`.".to_string()), + (1, 0) | (0, 1) | (1, 1) => Ok(()), + (_, _) => Err("More than two constructors present. Exactly one method annotated with `#[init]` and/or another optional `#[upgrade]` is required. ".to_string()), } } -fn has_upgrade(contract_variant: &ContractVariant) -> bool { - contract_variant - .abi - .endpoints - .iter() - .any(|endpoint| endpoint.name == "upgrade") -} - /// Note: promise callbacks not included, since they have `#[call_value]` arguments, that are currently not modelled. fn validate_contract_var_args(abi: &ContractAbi) -> Result<(), String> { - for endpoint_abi in abi.constructors.iter().chain(abi.endpoints.iter()) { + for endpoint_abi in abi + .constructors + .iter() + .chain(abi.upgrade_constructors.iter()) + .chain(abi.endpoints.iter()) + { validate_endpoint_var_args_number(endpoint_abi)?; validate_endpoint_var_args_order(endpoint_abi)?; } @@ -69,7 +65,7 @@ fn validate_endpoint_var_args_order(endpoint_abi: &EndpointAbi) -> Result<(), St #[cfg(test)] mod tests { - use multiversx_sc::abi::{InputAbi, TypeName}; + use multiversx_sc::abi::{InputAbi, TypeNames}; use super::*; @@ -78,12 +74,12 @@ mod tests { let mut endpoint_def = EndpointAbi::default(); let var_arg_1 = InputAbi { arg_name: "arg_1".to_string(), - type_name: TypeName::new(), + type_names: TypeNames::new(), multi_arg: true, }; let var_arg_2 = InputAbi { arg_name: "arg_2".to_string(), - type_name: TypeName::new(), + type_names: TypeNames::new(), multi_arg: true, }; endpoint_def.inputs.push(var_arg_1); @@ -103,12 +99,12 @@ mod tests { let mut endpoint_def = EndpointAbi::default(); let arg = InputAbi { arg_name: "arg_1".to_string(), - type_name: TypeName::new(), + type_names: TypeNames::new(), multi_arg: false, }; let var_arg_1 = InputAbi { arg_name: "arg_2".to_string(), - type_name: TypeName::new(), + type_names: TypeNames::new(), multi_arg: true, }; diff --git a/framework/meta/src/cmd/contract/sc_config/sc_config_model.rs b/framework/meta/src/cmd/contract/sc_config/sc_config_model.rs index 7f9ddbf5a9..076e91a2f7 100644 --- a/framework/meta/src/cmd/contract/sc_config/sc_config_model.rs +++ b/framework/meta/src/cmd/contract/sc_config/sc_config_model.rs @@ -1,4 +1,7 @@ -use super::{contract_variant_validate::validate_contract_variant, ContractVariant}; +use super::{ + contract_variant_validate::validate_contract_variant, sc_config_proxy::ProxyConfigSerde, + ContractVariant, +}; /// Allowed file names for the SC config. /// @@ -15,6 +18,7 @@ pub const SC_CONFIG_FILE_NAMES: &[&str] = &["sc-config.toml", "multicontract.tom pub struct ScConfig { pub default_contract_config_name: String, pub contracts: Vec, + pub proxy_configs: Vec, } impl ScConfig { diff --git a/framework/meta/src/cmd/contract/sc_config/sc_config_proxy.rs b/framework/meta/src/cmd/contract/sc_config/sc_config_proxy.rs new file mode 100644 index 0000000000..56c9a5257a --- /dev/null +++ b/framework/meta/src/cmd/contract/sc_config/sc_config_proxy.rs @@ -0,0 +1,37 @@ +use serde::Deserialize; + +const DEFAULT_PATH: &str = "/output/proxy.rs"; + +#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct ProxyConfigSerde { + #[serde(default)] + pub path: String, + + #[serde(default)] + #[serde(rename = "override-import")] + pub override_import: Option, + + #[serde(default)] + #[serde(rename = "path-rename")] + pub path_rename: Option>, +} + +impl ProxyConfigSerde { + pub fn new() -> Self { + Self { + path: DEFAULT_PATH.to_string(), + override_import: None, + path_rename: None, + } + } +} + +#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)] +pub struct PathRename { + #[serde(default)] + pub from: String, + + #[serde(default)] + pub to: String, +} diff --git a/framework/meta/src/cmd/contract/sc_config/sc_config_serde.rs b/framework/meta/src/cmd/contract/sc_config/sc_config_serde.rs index 4813fcfb09..c3c6b94d30 100644 --- a/framework/meta/src/cmd/contract/sc_config/sc_config_serde.rs +++ b/framework/meta/src/cmd/contract/sc_config/sc_config_serde.rs @@ -1,6 +1,8 @@ use serde::Deserialize; use std::collections::HashMap; +use super::ProxyConfigSerde; + #[derive(Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ScConfigSerde { @@ -9,6 +11,8 @@ pub struct ScConfigSerde { #[serde(default)] pub contracts: HashMap, #[serde(default)] + pub proxy: Vec, + #[serde(default)] #[serde(rename = "labels-for-contracts")] pub labels_for_contracts: HashMap>, } diff --git a/framework/meta/src/cmd/contract/sc_config/wasm_crate_gen.rs b/framework/meta/src/cmd/contract/sc_config/wasm_crate_gen.rs index 7dde9e9805..4117cc24f8 100644 --- a/framework/meta/src/cmd/contract/sc_config/wasm_crate_gen.rs +++ b/framework/meta/src/cmd/contract/sc_config/wasm_crate_gen.rs @@ -18,6 +18,7 @@ const PREFIX_AUTO_GENERATED: &str = "; const NUM_INIT: usize = 1; +const NUM_UPGRADE: usize = 1; const NUM_ASYNC_CB: usize = 1; const VER_1_71: &str = "1.71.0-nightly"; @@ -110,7 +111,17 @@ fn write_stat_comment(wasm_lib_file: &mut File, label: &str, number: usize) { impl ContractVariant { /// Writing some nicely formatted comments breaking down all exported functions. fn write_stat_comments(&self, wasm_lib_file: &mut File) { - write_stat_comment(wasm_lib_file, "Init:", NUM_INIT); + let mut total = self.abi.endpoints.len() + NUM_ASYNC_CB + self.abi.promise_callbacks.len(); + + if !self.abi.constructors.is_empty() { + write_stat_comment(wasm_lib_file, "Init:", NUM_INIT); + total += NUM_INIT; + } + if !self.abi.upgrade_constructors.is_empty() { + write_stat_comment(wasm_lib_file, "Upgrade:", NUM_UPGRADE); + total += NUM_UPGRADE; + } + write_stat_comment(wasm_lib_file, "Endpoints:", self.abi.endpoints.len()); if self.abi.has_callback { write_stat_comment(wasm_lib_file, "Async Callback:", NUM_ASYNC_CB); @@ -124,8 +135,6 @@ impl ContractVariant { self.abi.promise_callbacks.len(), ); } - let total = - self.abi.endpoints.len() + NUM_INIT + NUM_ASYNC_CB + self.abi.promise_callbacks.len(); write_stat_comment(wasm_lib_file, "Total number of exported functions:", total); } diff --git a/framework/meta/src/cmd/standalone/template/template_adjuster.rs b/framework/meta/src/cmd/standalone/template/template_adjuster.rs index 1182463c8f..c841c5d1f7 100644 --- a/framework/meta/src/cmd/standalone/template/template_adjuster.rs +++ b/framework/meta/src/cmd/standalone/template/template_adjuster.rs @@ -104,6 +104,8 @@ impl TemplateAdjuster { let old_name = self.metadata.name.to_case(Case::Snake); let new_package = format!("{new_name}::"); let old_package = format!("{old_name}::"); + let new_proxy_mod = format!("{new_name}_proxy"); + let old_proxy_mod = format!("{old_name}_proxy"); replace_in_files( &self.target.contract_dir(), @@ -111,8 +113,15 @@ impl TemplateAdjuster { &[ Query::substring(old_trait, &new_trait), Query::substring(&old_package, &new_package), + Query::substring(&old_proxy_mod, &new_proxy_mod), ][..], ); + + replace_in_files( + &self.target.contract_dir(), + "*sc-config.toml", + &[Query::substring(&old_proxy_mod, &new_proxy_mod)][..], + ); } fn rename_in_cargo_toml_root(&self) { diff --git a/framework/scenario/Cargo.toml b/framework/scenario/Cargo.toml index 45359208d8..d946575a3c 100644 --- a/framework/scenario/Cargo.toml +++ b/framework/scenario/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sc-scenario" -version = "0.48.1" +version = "0.49.0-alpha.4" edition = "2021" authors = [ @@ -40,12 +40,12 @@ path = "src/main.rs" run-go-tests = [] [dependencies.multiversx-sc] -version = "=0.48.1" +version = "=0.49.0-alpha.4" features = ["alloc", "num-bigint"] path = "../base" [dependencies.multiversx-sc-meta] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../meta" [dependencies.multiversx-chain-scenario-format] @@ -60,5 +60,5 @@ version = "=0.8.3" path = "../../vm" [dependencies.multiversx-sdk] -version = "=0.3.2" +version = "=0.4.0-alpha.4" path = "../../sdk/core" diff --git a/framework/scenario/src/api/impl_vh/static_api.rs b/framework/scenario/src/api/impl_vh/static_api.rs index ca1d8602e5..7e375a0c31 100644 --- a/framework/scenario/src/api/impl_vh/static_api.rs +++ b/framework/scenario/src/api/impl_vh/static_api.rs @@ -1,9 +1,9 @@ -use std::sync::Mutex; use multiversx_chain_vm::{ executor::VMHooks, vm_hooks::{StaticApiVMHooksHandler, VMHooksDispatcher, VMHooksHandler}, }; use multiversx_sc::{api::RawHandle, types::Address}; +use std::sync::Mutex; use crate::debug_executor::StaticVarData; diff --git a/framework/scenario/src/bech32.rs b/framework/scenario/src/bech32.rs index 4b72107bb8..aa224cee95 100644 --- a/framework/scenario/src/bech32.rs +++ b/framework/scenario/src/bech32.rs @@ -2,7 +2,8 @@ use bech32::{FromBase32, ToBase32, Variant}; use multiversx_sc::types::heap::Address; pub fn decode(bech32_address: &str) -> Address { - let (_, dest_address_bytes_u5, _) = bech32::decode(bech32_address).unwrap(); + let (_, dest_address_bytes_u5, _) = 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") diff --git a/framework/scenario/src/facade.rs b/framework/scenario/src/facade.rs index f53625895e..75a688a36a 100644 --- a/framework/scenario/src/facade.rs +++ b/framework/scenario/src/facade.rs @@ -1,11 +1,15 @@ mod contract_info; mod debugger_backend; +pub mod expr; +pub mod result_handlers; mod scenario_world; +mod scenario_world_register; mod scenario_world_runner; mod scenario_world_steps; mod scenario_world_steps_deprecated; mod scenario_world_whitebox; mod whitebox_contract; +pub mod world_tx; pub use contract_info::ContractInfo; pub use scenario_world::ScenarioWorld; diff --git a/framework/scenario/src/facade/contract_info.rs b/framework/scenario/src/facade/contract_info.rs index 35b3ee1afb..e7b4dd0190 100644 --- a/framework/scenario/src/facade/contract_info.rs +++ b/framework/scenario/src/facade/contract_info.rs @@ -1,9 +1,16 @@ +#![allow(deprecated)] // TODO: remove after deleting CodecFrom + use std::ops::{Deref, DerefMut}; +use multiversx_sc::{ + abi::TypeAbiFrom, + types::{AnnotatedValue, ManagedBuffer, TxEnv, TxFrom, TxFromSpecified, TxTo, TxToSpecified}, +}; + use crate::multiversx_sc::{ api::ManagedTypeApi, codec::{CodecFrom, EncodeErrorHandler, TopEncode, TopEncodeOutput}, - contract_base::ProxyObjBase, + contract_base::ProxyObjNew, types::{Address, ManagedAddress}, }; @@ -11,12 +18,15 @@ use crate::scenario::model::{AddressKey, AddressValue}; /// Bundles a representation of a contract with the contract proxy, /// so that it can be easily called in the context of a blockchain mock. -pub struct ContractInfo { +pub struct ContractInfo { pub scenario_address_expr: AddressKey, - proxy_inst: P, + proxy_inst: P::ProxyTo, } -impl ContractInfo

{ +impl

ContractInfo

+where + P: ProxyObjNew, +{ pub fn new(address_expr: A) -> Self where AddressKey: From, @@ -32,49 +42,59 @@ impl ContractInfo

{ pub fn to_address(&self) -> Address { self.scenario_address_expr.to_address() } + + /// For historical reasons the proxy consumes its address whenever it is called. + /// + /// When using it in tests, as part of `ContractInfo`, + /// it is convenient to refresh it before each call. + /// + /// It is sort of a hack, designed to optimize proxy use in contracts, + /// while making it easier to use in tests. + fn refresh_proxy_address(&mut self) { + self.proxy_inst = + P::new_proxy_obj().contract(self.scenario_address_expr.value.clone().into()); + } } -impl From<&ContractInfo

> for AddressKey { +impl From<&ContractInfo

> for AddressKey { fn from(from: &ContractInfo

) -> Self { from.scenario_address_expr.clone() } } -impl From> for AddressKey { +impl From> for AddressKey { fn from(from: ContractInfo

) -> Self { from.scenario_address_expr } } -impl From<&ContractInfo

> for AddressValue { +impl From<&ContractInfo

> for AddressValue { fn from(from: &ContractInfo

) -> Self { AddressValue::from(&from.scenario_address_expr) } } -impl From> for AddressValue { +impl From> for AddressValue { fn from(from: ContractInfo

) -> Self { AddressValue::from(&from.scenario_address_expr) } } -impl Deref for ContractInfo

{ - type Target = P; +impl Deref for ContractInfo

{ + type Target = P::ProxyTo; fn deref(&self) -> &Self::Target { &self.proxy_inst } } -impl DerefMut for ContractInfo

{ +impl DerefMut for ContractInfo

{ fn deref_mut(&mut self) -> &mut Self::Target { - let proxy_inst = core::mem::replace(&mut self.proxy_inst, P::new_proxy_obj()); - let proxy_inst = proxy_inst.contract(self.scenario_address_expr.value.clone().into()); - let _ = core::mem::replace(&mut self.proxy_inst, proxy_inst); + self.refresh_proxy_address(); &mut self.proxy_inst } } -impl TopEncode for ContractInfo

{ +impl TopEncode for ContractInfo

{ fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> where O: TopEncodeOutput, @@ -86,7 +106,54 @@ impl TopEncode for ContractInfo

{ } } -impl CodecFrom> for Address {} -impl CodecFrom<&ContractInfo

> for Address {} -impl CodecFrom> for ManagedAddress {} -impl CodecFrom<&ContractInfo

> for ManagedAddress {} +impl CodecFrom> for Address {} +impl CodecFrom<&ContractInfo

> for Address {} +impl CodecFrom> for ManagedAddress {} +impl CodecFrom<&ContractInfo

> for ManagedAddress {} + +impl TypeAbiFrom> for Address {} +impl TypeAbiFrom<&ContractInfo

> for Address {} +impl TypeAbiFrom> for ManagedAddress {} +impl TypeAbiFrom<&ContractInfo

> for ManagedAddress {} + +impl AnnotatedValue> for &ContractInfo

+where + Env: TxEnv, + P: ProxyObjNew, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.scenario_address_expr.original.as_str().into() + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + (&self.scenario_address_expr.value).into() + } +} + +impl TxFrom for &ContractInfo

+where + Env: TxEnv, + P: ProxyObjNew, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + (&self.scenario_address_expr.value).into() + } +} +impl TxFromSpecified for &ContractInfo

+where + Env: TxEnv, + P: ProxyObjNew, +{ +} +impl TxTo for &ContractInfo

+where + Env: TxEnv, + P: ProxyObjNew, +{ +} +impl TxToSpecified for &ContractInfo

+where + Env: TxEnv, + P: ProxyObjNew, +{ +} diff --git a/framework/scenario/src/facade/expr.rs b/framework/scenario/src/facade/expr.rs new file mode 100644 index 0000000000..2ca60a5192 --- /dev/null +++ b/framework/scenario/src/facade/expr.rs @@ -0,0 +1,11 @@ +mod bech32_address; +mod file_path; +mod mxsc_path; +mod num_expr; +mod register_code_source; + +pub use bech32_address::Bech32Address; +pub use file_path::FilePath; +pub use mxsc_path::MxscPath; +pub use num_expr::NumExpr; +pub use register_code_source::RegisterCodeSource; diff --git a/framework/scenario/src/facade/expr/bech32_address.rs b/framework/scenario/src/facade/expr/bech32_address.rs new file mode 100644 index 0000000000..76fca96c86 --- /dev/null +++ b/framework/scenario/src/facade/expr/bech32_address.rs @@ -0,0 +1,210 @@ +use std::fmt::Display; + +use crate::bech32; +use multiversx_sc::{ + abi::TypeAbiFrom, + api::ManagedTypeApi, + codec::*, + types::{ + Address, AnnotatedValue, ManagedAddress, ManagedBuffer, TxEnv, TxFrom, TxFromSpecified, + TxTo, TxToSpecified, + }, +}; +use serde::{Deserialize, Serialize}; + +const BECH32_PREFIX: &str = "bech32:"; + +/// Wraps and address, and presents it as a bech32 expression wherever possible. +/// +/// In order to avoid repeated conversions, it redundantly keeps the bech32 representation inside. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Bech32Address { + address: Address, + bech32: String, +} + +impl From

for Bech32Address { + fn from(value: Address) -> Self { + let bech32 = bech32::encode(&value); + Bech32Address { + address: value, + bech32, + } + } +} + +impl From<&Address> for Bech32Address { + fn from(value: &Address) -> Self { + let bech32 = bech32::encode(value); + Bech32Address { + address: value.clone(), + bech32, + } + } +} + +impl Bech32Address { + pub fn from_bech32_string(bech32: String) -> Self { + let address = bech32::decode(&bech32); + Bech32Address { address, bech32 } + } + + pub fn to_bech32_str(&self) -> &str { + &self.bech32 + } + + pub fn to_bech32_string(&self) -> String { + self.bech32.to_owned() + } + + pub fn to_hex(&self) -> String { + hex::encode(&self.address) + } + + pub fn as_address(&self) -> &Address { + &self.address + } + + pub fn to_address(&self) -> Address { + self.address.clone() + } + + pub fn into_address(self) -> Address { + self.address + } + + pub fn to_bech32_expr(&self) -> String { + format!("{BECH32_PREFIX}{}", &self.bech32) + } +} + +impl AnnotatedValue> for Bech32Address +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.to_bech32_expr().into() + } + + fn to_value(&self, env: &Env) -> ManagedAddress { + self.address.to_value(env) + } +} + +impl TxFrom for Bech32Address +where + Env: TxEnv, +{ + fn resolve_address(&self, env: &Env) -> ManagedAddress { + self.address.resolve_address(env) + } +} +impl TxFromSpecified for Bech32Address where Env: TxEnv {} +impl TxTo for Bech32Address where Env: TxEnv {} +impl TxToSpecified for Bech32Address where Env: TxEnv {} + +impl AnnotatedValue> for &Bech32Address +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.to_bech32_expr().into() + } + + fn to_value(&self, env: &Env) -> ManagedAddress { + self.address.to_value(env) + } +} + +impl TxFrom for &Bech32Address +where + Env: TxEnv, +{ + fn resolve_address(&self, env: &Env) -> ManagedAddress { + self.address.resolve_address(env) + } +} +impl TxFromSpecified for &Bech32Address where Env: TxEnv {} +impl TxTo for &Bech32Address where Env: TxEnv {} +impl TxToSpecified for &Bech32Address where Env: TxEnv {} + +impl Display for Bech32Address { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.bech32) + } +} + +impl NestedEncode for Bech32Address { + fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> + where + O: NestedEncodeOutput, + H: EncodeErrorHandler, + { + self.address.dep_encode_or_handle_err(dest, h) + } +} + +impl TopEncode for Bech32Address { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + self.address.top_encode_or_handle_err(output, h) + } +} + +impl NestedDecode for Bech32Address { + fn dep_decode_or_handle_err(input: &mut I, h: H) -> Result + where + I: NestedDecodeInput, + H: DecodeErrorHandler, + { + Ok(Bech32Address::from(Address::dep_decode_or_handle_err( + input, h, + )?)) + } +} + +impl TopDecode for Bech32Address { + fn top_decode_or_handle_err(input: I, h: H) -> Result + where + I: TopDecodeInput, + H: DecodeErrorHandler, + { + Ok(Bech32Address::from(Address::top_decode_or_handle_err( + input, h, + )?)) + } +} + +#[allow(deprecated)] +impl CodecFrom for ManagedAddress where M: ManagedTypeApi {} +#[allow(deprecated)] +impl CodecFrom<&Bech32Address> for ManagedAddress where M: ManagedTypeApi {} + +impl TypeAbiFrom for ManagedAddress where M: ManagedTypeApi {} +impl TypeAbiFrom<&Bech32Address> for ManagedAddress where M: ManagedTypeApi {} + +impl Serialize for Bech32Address { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.bech32.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for Bech32Address { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + // some old interactors have it serialized like this + let mut bech32 = String::deserialize(deserializer)?; + if let Some(stripped) = bech32.strip_prefix("bech32:") { + bech32 = stripped.to_owned(); + } + Ok(Bech32Address::from_bech32_string(bech32)) + } +} diff --git a/framework/scenario/src/facade/expr/file_path.rs b/framework/scenario/src/facade/expr/file_path.rs new file mode 100644 index 0000000000..8d779a6fd1 --- /dev/null +++ b/framework/scenario/src/facade/expr/file_path.rs @@ -0,0 +1,45 @@ +use multiversx_chain_scenario_format::{ + interpret_trait::InterpreterContext, value_interpreter::interpret_string, +}; +use multiversx_sc::types::{AnnotatedValue, ManagedBuffer, TxCodeValue}; + +use crate::{ScenarioTxEnv, ScenarioTxEnvData}; + +use super::RegisterCodeSource; + +const FILE_PREFIX: &str = "file:"; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct FilePath<'a>(pub &'a str); + +impl<'a> FilePath<'a> { + pub fn eval_to_expr(&self) -> String { + format!("{FILE_PREFIX}{}", self.0) + } + + pub fn resolve_contents(&self, context: &InterpreterContext) -> Vec { + interpret_string(&format!("{FILE_PREFIX}{}", self.0), context) + } +} + +impl<'a, Env> AnnotatedValue> for FilePath<'a> +where + Env: ScenarioTxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.eval_to_expr().into() + } + + fn to_value(&self, env: &Env) -> ManagedBuffer { + self.resolve_contents(&env.env_data().interpreter_context()) + .into() + } +} + +impl<'a, Env> TxCodeValue for FilePath<'a> where Env: ScenarioTxEnv {} + +impl<'a> RegisterCodeSource for FilePath<'a> { + fn into_code(self, env_data: ScenarioTxEnvData) -> Vec { + self.resolve_contents(&env_data.interpreter_context()) + } +} diff --git a/framework/scenario/src/facade/expr/mxsc_path.rs b/framework/scenario/src/facade/expr/mxsc_path.rs new file mode 100644 index 0000000000..465eb5f097 --- /dev/null +++ b/framework/scenario/src/facade/expr/mxsc_path.rs @@ -0,0 +1,67 @@ +use multiversx_chain_scenario_format::{ + interpret_trait::InterpreterContext, value_interpreter::interpret_string, +}; +use multiversx_sc::types::{AnnotatedValue, ManagedBuffer, TxCodeValue}; + +use crate::{ScenarioTxEnv, ScenarioTxEnvData}; + +use super::RegisterCodeSource; + +const MXSC_PREFIX: &str = "mxsc:"; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct MxscPath<'a> { + path: &'a str, +} + +impl<'a> MxscPath<'a> { + pub const fn new(path: &'a str) -> Self { + MxscPath { path } + } +} + +impl<'a> MxscPath<'a> { + pub fn eval_to_expr(&self) -> String { + format!("{MXSC_PREFIX}{}", self.path) + } + + pub fn resolve_contents(&self, context: &InterpreterContext) -> Vec { + interpret_string(&format!("{MXSC_PREFIX}{}", self.path), context) + } +} + +impl<'a, Env> AnnotatedValue> for MxscPath<'a> +where + Env: ScenarioTxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.eval_to_expr().into() + } + + fn to_value(&self, env: &Env) -> ManagedBuffer { + self.resolve_contents(&env.env_data().interpreter_context()) + .into() + } +} + +impl<'a, Env> TxCodeValue for MxscPath<'a> where Env: ScenarioTxEnv {} + +impl<'a> RegisterCodeSource for MxscPath<'a> { + fn into_code(self, env_data: ScenarioTxEnvData) -> Vec { + self.resolve_contents(&env_data.interpreter_context()) + } +} + +#[cfg(test)] +pub mod tests { + use crate::imports::MxscPath; + + fn assert_eq_eval(expr: &'static str, expected: &str) { + assert_eq!(&MxscPath::new(expr).eval_to_expr(), expected); + } + + #[test] + fn test_address_value() { + assert_eq_eval("output/adder.mxsc.json", "mxsc:output/adder.mxsc.json"); + } +} diff --git a/framework/scenario/src/facade/expr/num_expr.rs b/framework/scenario/src/facade/expr/num_expr.rs new file mode 100644 index 0000000000..704f52496b --- /dev/null +++ b/framework/scenario/src/facade/expr/num_expr.rs @@ -0,0 +1,49 @@ +use crate::ScenarioTxEnv; + +use multiversx_chain_scenario_format::{ + interpret_trait::InterpreterContext, value_interpreter::interpret_string, +}; +use multiversx_sc::{ + api::ManagedTypeApi, + types::{AnnotatedValue, BigUint, ManagedBuffer, TxEgldValue, TxGasValue}, +}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct NumExpr<'a>(pub &'a str); + +fn interpret_big_uint(s: &str) -> BigUint +where + Api: ManagedTypeApi, +{ + let bytes = interpret_string(s, &InterpreterContext::new()); + BigUint::from_bytes_be(&bytes) +} + +impl<'a, Env> AnnotatedValue> for NumExpr<'a> +where + Env: ScenarioTxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.0.into() + } + + fn to_value(&self, _env: &Env) -> BigUint { + interpret_big_uint(self.0) + } +} + +impl<'a, Env> AnnotatedValue for NumExpr<'a> +where + Env: ScenarioTxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer { + self.0.into() + } + + fn to_value(&self, _env: &Env) -> u64 { + interpret_big_uint::(self.0).to_u64().unwrap() + } +} + +impl<'a, Env> TxEgldValue for NumExpr<'a> where Env: ScenarioTxEnv {} +impl<'a, Env> TxGasValue for NumExpr<'a> where Env: ScenarioTxEnv {} diff --git a/framework/scenario/src/facade/expr/register_code_source.rs b/framework/scenario/src/facade/expr/register_code_source.rs new file mode 100644 index 0000000000..d586498a0f --- /dev/null +++ b/framework/scenario/src/facade/expr/register_code_source.rs @@ -0,0 +1,28 @@ +use multiversx_chain_scenario_format::value_interpreter::interpret_string; + +use crate::ScenarioTxEnvData; + +/// Used when registering a contract for debugging. +/// +/// Any type that implements this trait can be passed to the `register_contract` method, and to its variants. +pub trait RegisterCodeSource { + fn into_code(self, env_data: ScenarioTxEnvData) -> Vec; +} + +impl RegisterCodeSource for &str { + fn into_code(self, env_data: ScenarioTxEnvData) -> Vec { + interpret_string(self, &env_data.interpreter_context()) + } +} + +impl RegisterCodeSource for String { + fn into_code(self, env_data: ScenarioTxEnvData) -> Vec { + self.as_str().into_code(env_data) + } +} + +impl RegisterCodeSource for &String { + fn into_code(self, env_data: ScenarioTxEnvData) -> Vec { + self.as_str().into_code(env_data) + } +} diff --git a/framework/scenario/src/facade/result_handlers.rs b/framework/scenario/src/facade/result_handlers.rs new file mode 100644 index 0000000000..1893647b45 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers.rs @@ -0,0 +1,19 @@ +mod expect_error; +mod expect_message; +mod expect_status; +mod expect_value; +mod returns_message; +mod returns_new_bech32_address; +mod returns_new_token_identifier; +mod returns_status; +mod with_tx_raw_response; + +pub use expect_error::ExpectError; +pub use expect_message::ExpectMessage; +pub use expect_status::ExpectStatus; +pub use expect_value::ExpectValue; +pub use returns_message::ReturnsMessage; +pub use returns_new_bech32_address::ReturnsNewBech32Address; +pub use returns_new_token_identifier::ReturnsNewTokenIdentifier; +pub use returns_status::ReturnsStatus; +pub use with_tx_raw_response::WithRawTxResponse; diff --git a/framework/scenario/src/facade/result_handlers/expect_error.rs b/framework/scenario/src/facade/result_handlers/expect_error.rs new file mode 100644 index 0000000000..a06a227424 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/expect_error.rs @@ -0,0 +1,33 @@ +use multiversx_chain_scenario_format::serde_raw::ValueSubTree; +use multiversx_sc::types::{RHListItem, RHListItemExec, TxEnv}; + +use crate::scenario_model::{BytesValue, CheckValue, TxExpect, TxResponse}; + +/// Verifies that transaction result error matches the given one. +/// +/// Can only be used in tests and interactors, not available in contracts. +pub struct ExpectError<'a>(pub u64, pub &'a str); + +impl<'a, Env, Original> RHListItem for ExpectError<'a> +where + Env: TxEnv, +{ + type Returns = (); +} + +impl<'a, Env, Original> RHListItemExec for ExpectError<'a> +where + Env: TxEnv, +{ + fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { + prev.status = CheckValue::Equal(self.0.into()); + let expect_message_expr = BytesValue { + value: self.1.to_string().into_bytes(), + original: ValueSubTree::Str(format!("str:{}", self.1)), + }; + prev.message = CheckValue::Equal(expect_message_expr); + prev + } + + fn item_process_result(self, _: &TxResponse) -> Self::Returns {} +} diff --git a/framework/scenario/src/facade/result_handlers/expect_message.rs b/framework/scenario/src/facade/result_handlers/expect_message.rs new file mode 100644 index 0000000000..af5fa2a429 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/expect_message.rs @@ -0,0 +1,36 @@ +use multiversx_chain_scenario_format::serde_raw::ValueSubTree; +use multiversx_sc::types::{RHListItem, RHListItemExec, TxEnv}; + +use crate::scenario_model::{BytesValue, CheckValue, TxExpect, TxResponse, U64Value}; + +/// Verifies that transaction result message matches the given one. +/// +/// Can only be used in tests and interactors, not available in contracts. +pub struct ExpectMessage<'a>(pub &'a str); + +impl<'a, Env, Original> RHListItem for ExpectMessage<'a> +where + Env: TxEnv, +{ + type Returns = (); +} + +impl<'a, Env, Original> RHListItemExec for ExpectMessage<'a> +where + Env: TxEnv, +{ + fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { + if prev.status.is_equal_to(U64Value::empty()) { + prev.status = CheckValue::Star; + } + + let expect_message_expr = BytesValue { + value: self.0.to_string().into_bytes(), + original: ValueSubTree::Str(format!("str:{}", self.0)), + }; + prev.message = CheckValue::Equal(expect_message_expr); + prev + } + + fn item_process_result(self, _: &TxResponse) -> Self::Returns {} +} diff --git a/framework/scenario/src/facade/result_handlers/expect_status.rs b/framework/scenario/src/facade/result_handlers/expect_status.rs new file mode 100644 index 0000000000..127982739b --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/expect_status.rs @@ -0,0 +1,27 @@ +use multiversx_sc::types::{RHListItem, RHListItemExec, TxEnv}; + +use crate::scenario_model::{CheckValue, TxExpect, TxResponse}; + +/// Verifies that transaction result status matches the given one. +/// +/// Can only be used in tests and interactors, not available in contracts. +pub struct ExpectStatus(pub u64); + +impl RHListItem for ExpectStatus +where + Env: TxEnv, +{ + type Returns = (); +} + +impl RHListItemExec for ExpectStatus +where + Env: TxEnv, +{ + fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { + prev.status = CheckValue::Equal(self.0.into()); + prev + } + + fn item_process_result(self, _: &TxResponse) -> Self::Returns {} +} diff --git a/framework/scenario/src/facade/result_handlers/expect_value.rs b/framework/scenario/src/facade/result_handlers/expect_value.rs new file mode 100644 index 0000000000..582737cb84 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/expect_value.rs @@ -0,0 +1,41 @@ +use multiversx_sc::{ + abi::TypeAbiFrom, + codec::TopEncodeMulti, + types::{RHListItem, RHListItemExec, TxEnv}, +}; + +use crate::scenario_model::{BytesValue, CheckValue, TxExpect, TxResponse}; + +/// Verifies that transaction result matches the given value. +/// +/// Can only be used in tests and interactors, not available in contracts. +pub struct ExpectValue(pub T); + +impl RHListItem for ExpectValue +where + Env: TxEnv, + T: TopEncodeMulti, + Original: TypeAbiFrom, +{ + type Returns = (); +} + +impl RHListItemExec for ExpectValue +where + Env: TxEnv, + T: TopEncodeMulti, + Original: TypeAbiFrom, +{ + fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { + let mut encoded = Vec::>::new(); + self.0.multi_encode(&mut encoded).expect("encoding error"); + let out_values = encoded + .into_iter() + .map(|value| CheckValue::Equal(BytesValue::from(value))) + .collect(); + prev.out = CheckValue::Equal(out_values); + prev + } + + fn item_process_result(self, _: &TxResponse) -> Self::Returns {} +} diff --git a/framework/scenario/src/facade/result_handlers/returns_message.rs b/framework/scenario/src/facade/result_handlers/returns_message.rs new file mode 100644 index 0000000000..64164e05ef --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_message.rs @@ -0,0 +1,29 @@ +use multiversx_sc::types::{RHListItem, RHListItemExec, TxEnv}; + +use crate::scenario_model::{CheckValue, TxExpect, TxResponse}; + +/// Indicates that the error status will be returned. +/// +/// Can only be used in tests and interactors, not available in contracts. +pub struct ReturnsMessage; + +impl RHListItem for ReturnsMessage +where + Env: TxEnv, +{ + type Returns = String; +} + +impl RHListItemExec for ReturnsMessage +where + Env: TxEnv, +{ + fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { + prev.message = CheckValue::Star; + prev + } + + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + raw_result.tx_error.message.clone() + } +} diff --git a/framework/scenario/src/facade/result_handlers/returns_new_bech32_address.rs b/framework/scenario/src/facade/result_handlers/returns_new_bech32_address.rs new file mode 100644 index 0000000000..6e898c6088 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_new_bech32_address.rs @@ -0,0 +1,27 @@ +use multiversx_sc::types::{RHListItem, RHListItemExec, TxEnv}; + +use crate::{facade::expr::Bech32Address, scenario_model::TxResponse}; + +/// Indicates that the newly deployed address will be returned after a deploy. +pub struct ReturnsNewBech32Address; + +impl RHListItem for ReturnsNewBech32Address +where + Env: TxEnv, +{ + type Returns = Bech32Address; +} + +impl RHListItemExec for ReturnsNewBech32Address +where + Env: TxEnv, +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + let new_address = tx_response + .new_deployed_address + .clone() + .expect("missing returned address"); + + new_address.into() + } +} diff --git a/framework/scenario/src/facade/result_handlers/returns_new_token_identifier.rs b/framework/scenario/src/facade/result_handlers/returns_new_token_identifier.rs new file mode 100644 index 0000000000..a459706d22 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_new_token_identifier.rs @@ -0,0 +1,27 @@ +use multiversx_sc::types::RHListItemExec; + +use crate::{ + multiversx_sc::types::{RHListItem, TxEnv}, + scenario_model::TxResponse, +}; + +pub struct ReturnsNewTokenIdentifier; + +impl RHListItem for ReturnsNewTokenIdentifier +where + Env: TxEnv, +{ + type Returns = String; +} + +impl RHListItemExec for ReturnsNewTokenIdentifier +where + Env: TxEnv, +{ + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + raw_result + .new_issued_token_identifier + .clone() + .expect("missing returned token identifier") + } +} diff --git a/framework/scenario/src/facade/result_handlers/returns_status.rs b/framework/scenario/src/facade/result_handlers/returns_status.rs new file mode 100644 index 0000000000..184163619d --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_status.rs @@ -0,0 +1,36 @@ +use multiversx_sc::types::{RHListItem, RHListItemExec, TxEnv}; + +use crate::scenario_model::{CheckValue, TxExpect, TxResponse, U64Value}; + +/// Indicates that the error status will be returned. +/// +/// Can only be used in tests and interactors, not available in contracts. +pub struct ReturnsStatus; + +impl RHListItem for ReturnsStatus +where + Env: TxEnv, +{ + type Returns = u64; +} + +impl RHListItemExec for ReturnsStatus +where + Env: TxEnv, +{ + fn item_tx_expect(&self, mut prev: TxExpect) -> TxExpect { + if let CheckValue::Equal(U64Value { + value: 0, + original: _, + }) = prev.status + { + prev.status = CheckValue::Star; + } + + prev + } + + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + raw_result.tx_error.status + } +} diff --git a/framework/scenario/src/facade/result_handlers/with_tx_raw_response.rs b/framework/scenario/src/facade/result_handlers/with_tx_raw_response.rs new file mode 100644 index 0000000000..f67d3b0f48 --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/with_tx_raw_response.rs @@ -0,0 +1,30 @@ +use multiversx_sc::{ + codec::TopDecodeMulti, + types::{RHListItem, RHListItemExec, TxEnv}, +}; + +use crate::scenario_model::TxResponse; + +/// Wraps a closure that handles a `TxResponse` object. +pub struct WithRawTxResponse(pub F) +where + F: FnOnce(&TxResponse); + +impl RHListItem for WithRawTxResponse +where + Env: TxEnv, + F: FnOnce(&TxResponse), +{ + type Returns = (); +} + +impl RHListItemExec for WithRawTxResponse +where + Env: TxEnv, + Original: TopDecodeMulti, + F: FnOnce(&TxResponse), +{ + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + (self.0)(raw_result) + } +} diff --git a/framework/scenario/src/facade/scenario_world.rs b/framework/scenario/src/facade/scenario_world.rs index d760c1743a..f5b05024bd 100644 --- a/framework/scenario/src/facade/scenario_world.rs +++ b/framework/scenario/src/facade/scenario_world.rs @@ -1,17 +1,7 @@ -use multiversx_chain_scenario_format::interpret_trait::InterpretableFrom; use multiversx_chain_vm::world_mock::BlockchainState; -use multiversx_sc_meta::cmd::contract::sc_config::ContractVariant; use crate::{ - api::DebugApi, - debug_executor::ContractContainer, - multiversx_sc::{ - api, - contract_base::{CallableContractBuilder, ContractAbiProvider}, - }, scenario::{run_trace::ScenarioTrace, run_vm::ScenarioVMRunner}, - scenario_format::{interpret_trait::InterpreterContext, value_interpreter::interpret_string}, - scenario_model::BytesValue, vm_go_tool::run_mx_scenario_go, }; use multiversx_sc_meta::find_workspace::find_current_workspace; @@ -126,100 +116,6 @@ impl ScenarioWorld { &self.current_dir } - pub fn interpreter_context(&self) -> InterpreterContext { - InterpreterContext::default() - .with_dir(self.current_dir.clone()) - .with_allowed_missing_files() - } - - /// Convenient way of creating a code expression based on the current context - /// (i.e. with the paths resolved, as configured). - pub fn code_expression(&self, path: &str) -> BytesValue { - BytesValue::interpret_from(path, &self.interpreter_context()) - } - - pub fn register_contract_container( - &mut self, - expression: &str, - contract_container: ContractContainer, - ) { - let contract_bytes = interpret_string(expression, &self.interpreter_context()); - self.get_mut_debugger_backend() - .vm_runner - .contract_map_ref - .lock() - .register_contract(contract_bytes, contract_container); - } - - /// Links a contract path in a test to a contract implementation. - pub fn register_contract( - &mut self, - expression: &str, - contract_builder: B, - ) { - self.register_contract_container( - expression, - ContractContainer::new(contract_builder.new_contract_obj::(), None, false), - ) - } - - #[deprecated( - since = "0.37.0", - note = "Got renamed to `register_contract`, but not completely removed, in order to ease test migration. Please replace with `register_contract`." - )] - pub fn register_contract_builder( - &mut self, - expression: &str, - contract_builder: B, - ) { - self.register_contract(expression, contract_builder) - } - - /// Links a contract path in a test to a multi-contract output. - /// - /// This simulates the effects of building such a contract with only part of the endpoints. - pub fn register_partial_contract( - &mut self, - expression: &str, - contract_builder: B, - sub_contract_name: &str, - ) where - Abi: ContractAbiProvider, - B: CallableContractBuilder, - { - let multi_contract_config = - multiversx_sc_meta::multi_contract_config::(self.current_dir.as_path()); - let contract_variant = multi_contract_config.find_contract(sub_contract_name); - self.register_contract_variant(expression, contract_builder, contract_variant); - } - - /// Links a contract path in a test to a multi-contract output. - /// - /// This simulates the effects of building such a contract with only part of the endpoints. - pub fn register_contract_variant( - &mut self, - expression: &str, - contract_builder: B, - contract_variant: &ContractVariant, - ) where - B: CallableContractBuilder, - { - let contract_obj = if contract_variant.settings.external_view { - contract_builder.new_contract_obj::>() - } else { - contract_builder.new_contract_obj::() - }; - - self.register_contract_container( - expression, - ContractContainer::new( - contract_obj, - Some(contract_variant.all_exported_function_names()), - contract_variant.settings.panic_message, - ), - ); - } - /// Exports current scenario to a JSON file, as created. pub fn write_scenario_trace>(&mut self, file_path: P) { if let Some(trace) = &mut self.get_mut_debugger_backend().trace { diff --git a/framework/scenario/src/facade/scenario_world_register.rs b/framework/scenario/src/facade/scenario_world_register.rs new file mode 100644 index 0000000000..4fccdec3e6 --- /dev/null +++ b/framework/scenario/src/facade/scenario_world_register.rs @@ -0,0 +1,112 @@ +use crate::{ + api::DebugApi, + debug_executor::ContractContainer, + multiversx_sc::{ + api, + contract_base::{CallableContractBuilder, ContractAbiProvider}, + }, + scenario_format::interpret_trait::InterpreterContext, + scenario_model::BytesValue, + ScenarioWorld, +}; +use multiversx_chain_scenario_format::interpret_trait::InterpretableFrom; + +use multiversx_sc_meta::cmd::contract::sc_config::ContractVariant; + +use super::expr::RegisterCodeSource; + +impl ScenarioWorld { + pub fn interpreter_context(&self) -> InterpreterContext { + InterpreterContext::default() + .with_dir(self.current_dir.clone()) + .with_allowed_missing_files() + } + + /// Convenient way of creating a code expression based on the current context + /// (i.e. with the paths resolved, as configured). + pub fn code_expression(&self, path: &str) -> BytesValue { + BytesValue::interpret_from(path, &self.interpreter_context()) + } + + pub fn register_contract_container( + &mut self, + expression: impl RegisterCodeSource, + contract_container: ContractContainer, + ) { + let contract_bytes = expression.into_code(self.new_env_data()); + self.get_mut_debugger_backend() + .vm_runner + .contract_map_ref + .lock() + .register_contract(contract_bytes, contract_container); + } + + /// Links a contract path in a test to a contract implementation. + pub fn register_contract( + &mut self, + expression: impl RegisterCodeSource, + contract_builder: B, + ) { + self.register_contract_container( + expression, + ContractContainer::new(contract_builder.new_contract_obj::(), None, false), + ) + } + + #[deprecated( + since = "0.37.0", + note = "Got renamed to `register_contract`, but not completely removed, in order to ease test migration. Please replace with `register_contract`." + )] + pub fn register_contract_builder( + &mut self, + expression: &str, + contract_builder: B, + ) { + self.register_contract(expression, contract_builder) + } + + /// Links a contract path in a test to a multi-contract output. + /// + /// This simulates the effects of building such a contract with only part of the endpoints. + pub fn register_partial_contract( + &mut self, + expression: impl RegisterCodeSource, + contract_builder: B, + sub_contract_name: &str, + ) where + Abi: ContractAbiProvider, + B: CallableContractBuilder, + { + let multi_contract_config = + multiversx_sc_meta::multi_contract_config::(self.current_dir.as_path()); + let contract_variant = multi_contract_config.find_contract(sub_contract_name); + self.register_contract_variant(expression, contract_builder, contract_variant); + } + + /// Links a contract path in a test to a multi-contract output. + /// + /// This simulates the effects of building such a contract with only part of the endpoints. + pub fn register_contract_variant( + &mut self, + expression: impl RegisterCodeSource, + contract_builder: B, + contract_variant: &ContractVariant, + ) where + B: CallableContractBuilder, + { + let contract_obj = if contract_variant.settings.external_view { + contract_builder.new_contract_obj::>() + } else { + contract_builder.new_contract_obj::() + }; + + self.register_contract_container( + expression, + ContractContainer::new( + contract_obj, + Some(contract_variant.all_exported_function_names()), + contract_variant.settings.panic_message, + ), + ); + } +} diff --git a/framework/scenario/src/facade/scenario_world_steps.rs b/framework/scenario/src/facade/scenario_world_steps.rs index 37bc5e88c3..7f786d9e65 100644 --- a/framework/scenario/src/facade/scenario_world_steps.rs +++ b/framework/scenario/src/facade/scenario_world_steps.rs @@ -1,9 +1,15 @@ -use multiversx_sc::types::{heap::Address, ContractCall}; +#![allow(deprecated)] + +use multiversx_sc::{ + abi::TypeAbiFrom, + codec::TopDecodeMulti, + types::{heap::Address, ContractCall}, +}; use crate::{ api::StaticApi, facade::ScenarioWorld, - multiversx_sc::codec::{CodecFrom, TopEncodeMulti}, + multiversx_sc::codec::TopEncodeMulti, scenario::{model::*, ScenarioRunner}, }; @@ -29,6 +35,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_call_use_raw_response(&mut self, mut step: S, use_raw_response: F) -> &mut Self where S: AsMut, @@ -40,6 +50,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_call_use_result( &mut self, step: TypedScCall, @@ -47,7 +61,7 @@ impl ScenarioWorld { ) -> &mut Self where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, F: FnOnce(TypedResponse), { self.sc_call_use_raw_response(step, |response| { @@ -56,13 +70,17 @@ impl ScenarioWorld { }) } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_call_get_result( &mut self, mut step: TypedScCall, ) -> RequestedResult where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.run_sc_call_step(&mut step.sc_call_step); let response = unwrap_response(&step.sc_call_step.response); @@ -79,6 +97,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_query_use_raw_response(&mut self, mut step: S, use_raw_response: F) -> &mut Self where S: AsMut, @@ -91,6 +113,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_query_use_result( &mut self, step: TypedScQuery, @@ -98,7 +124,7 @@ impl ScenarioWorld { ) -> &mut Self where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, F: FnOnce(TypedResponse), { self.sc_query_use_raw_response(step, |response| { @@ -107,13 +133,17 @@ impl ScenarioWorld { }) } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_query_get_result( &mut self, mut step: TypedScQuery, ) -> RequestedResult where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.run_sc_query_step(&mut step.sc_query_step); let response = unwrap_response(&step.sc_query_step.response); @@ -129,7 +159,7 @@ impl ScenarioWorld { pub fn quick_query(&mut self, contract_call: CC) -> RequestedResult where CC: ContractCall, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.sc_query_get_result(ScQueryStep::new().call(contract_call)) } @@ -143,6 +173,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_deploy_use_raw_response( &mut self, mut step: S, @@ -159,6 +193,10 @@ impl ScenarioWorld { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_deploy_use_result( &mut self, step: TypedScDeploy, @@ -166,7 +204,7 @@ impl ScenarioWorld { ) -> &mut Self where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, F: FnOnce(Address, TypedResponse), { self.sc_deploy_use_raw_response(step, |response| { @@ -176,13 +214,17 @@ impl ScenarioWorld { }) } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub fn sc_deploy_get_result( &mut self, mut step: TypedScDeploy, ) -> (Address, RequestedResult) where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.run_sc_deploy_step(&mut step.sc_deploy_step); let response = unwrap_response(&step.sc_deploy_step.response); @@ -223,7 +265,7 @@ impl TypedScCallExecutor for ScenarioWorld { ) -> RequestedResult where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.sc_call_get_result(typed_sc_call) } @@ -236,7 +278,7 @@ impl TypedScDeployExecutor for ScenarioWorld { ) -> (Address, RequestedResult) where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.sc_deploy_get_result(typed_sc_call) } @@ -254,7 +296,7 @@ impl TypedScQueryExecutor for ScenarioWorld { ) -> RequestedResult where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.sc_query_get_result(typed_sc_query) } diff --git a/framework/scenario/src/facade/world_tx.rs b/framework/scenario/src/facade/world_tx.rs new file mode 100644 index 0000000000..a2d7373a42 --- /dev/null +++ b/framework/scenario/src/facade/world_tx.rs @@ -0,0 +1,11 @@ +mod scenario_check_state; +mod scenario_exec_call; +mod scenario_exec_deploy; +mod scenario_query_call; +mod scenario_rh_impl; +mod scenario_set_state; +mod scenario_tx_env; + +pub use scenario_exec_call::ScenarioEnvExec; +pub use scenario_query_call::ScenarioEnvQuery; +pub use scenario_tx_env::{ScenarioTxEnv, ScenarioTxEnvData, ScenarioTxRun}; diff --git a/framework/scenario/src/facade/world_tx/scenario_check_state.rs b/framework/scenario/src/facade/world_tx/scenario_check_state.rs new file mode 100644 index 0000000000..3f5423419a --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_check_state.rs @@ -0,0 +1,237 @@ +use std::collections::{btree_map::Entry, BTreeMap}; + +use multiversx_chain_scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}; +use multiversx_sc::{ + codec::{top_encode_to_vec_u8, TopEncode}, + types::{AnnotatedValue, BigUint, ManagedAddress, ManagedBuffer, TokenIdentifier}, +}; + +use crate::{ + api::StaticApi, + scenario::{ + tx_to_step::{ + address_annotated, big_uint_annotated, bytes_annotated, token_identifier_annotated, + u64_annotated, + }, + ScenarioRunner, + }, + scenario_model::{ + AddressKey, BytesKey, BytesValue, CheckAccount, CheckEsdt, CheckEsdtData, + CheckEsdtInstances, CheckEsdtMap, CheckEsdtMapContents, CheckStateStep, CheckStorage, + CheckStorageDetails, CheckValue, + }, + ScenarioTxEnvData, ScenarioWorld, +}; + +impl ScenarioWorld { + pub fn check_account(&mut self, address: A) -> CheckStateBuilder<'_> + where + A: AnnotatedValue>, + { + let address_value = address_annotated(&self.new_env_data(), &address); + CheckStateBuilder::new(self, address_value.into()) + } +} + +pub struct CheckStateBuilder<'w> { + world: &'w mut ScenarioWorld, + check_state_step: CheckStateStep, + current_account: CheckAccount, + current_address: AddressKey, +} + +impl<'w> CheckStateBuilder<'w> { + pub(crate) fn new(world: &'w mut ScenarioWorld, address: AddressKey) -> CheckStateBuilder<'w> { + let mut builder = CheckStateBuilder { + world, + check_state_step: CheckStateStep::new(), + current_account: CheckAccount::new(), + current_address: AddressKey::default(), + }; + builder.reset_account(address); + builder + } + + fn new_env_data(&self) -> ScenarioTxEnvData { + self.world.new_env_data() + } + + /// Starts building of a new account. + pub fn check_account(mut self, address: A) -> Self + where + A: AnnotatedValue>, + { + self.add_current_acount(); + let env = self.new_env_data(); + let address_value = address_annotated(&env, &address); + self.reset_account(address_value.into()); + self + } + + fn add_current_acount(&mut self) { + if let Entry::Vacant(entry) = self + .check_state_step + .accounts + .accounts + .entry(core::mem::take(&mut self.current_address)) + { + entry.insert(core::mem::take(&mut self.current_account)); + }; + } + + fn reset_account(&mut self, address: AddressKey) { + self.current_address = address; + self.current_account = CheckAccount::default(); + } + + /// Finished and sets all account in the blockchain mock. + fn commit_accounts(&mut self) { + self.add_current_acount(); + self.world.run_check_state_step(&self.check_state_step); + } + + /// Forces value drop and commit accounts. + pub fn commit(self) {} + + pub fn nonce(mut self, nonce: V) -> Self + where + V: AnnotatedValue, + { + let env = self.new_env_data(); + self.current_account.nonce = CheckValue::Equal(u64_annotated(&env, &nonce)); + self + } + + pub fn balance(mut self, balance: V) -> Self + where + V: AnnotatedValue>, + { + let env = self.new_env_data(); + self.current_account.balance = CheckValue::Equal(big_uint_annotated(&env, &balance)); + self + } + + pub fn code(mut self, code: V) -> Self + where + V: AnnotatedValue>, + { + let env = self.new_env_data(); + let code_value = bytes_annotated(&env, code); + + self.current_account.code = CheckValue::Equal(code_value); + self + } + + pub fn code_metadata(mut self, code_metadata_expr: V) -> Self + where + BytesValue: InterpretableFrom, + { + self.current_account.code_metadata = CheckValue::Equal(BytesValue::interpret_from( + code_metadata_expr, + &InterpreterContext::default(), + )); + self + } + + pub fn esdt_balance(mut self, token_id: K, balance: V) -> Self + where + K: AnnotatedValue>, + V: AnnotatedValue>, + { + let env = self.new_env_data(); + let token_id_key = token_identifier_annotated(&env, token_id); + let balance_value = big_uint_annotated(&env, &balance); + + match &mut self.current_account.esdt { + CheckEsdtMap::Unspecified | CheckEsdtMap::Star => { + let mut new_esdt_map = BTreeMap::new(); + let _ = new_esdt_map.insert(token_id_key, CheckEsdt::Short(balance_value)); + + let new_check_esdt_map = CheckEsdtMapContents { + contents: new_esdt_map, + other_esdts_allowed: true, + }; + + self.current_account.esdt = CheckEsdtMap::Equal(new_check_esdt_map); + }, + CheckEsdtMap::Equal(check_esdt_map) => { + if check_esdt_map.contents.contains_key(&token_id_key) { + let prev_entry = check_esdt_map.contents.get_mut(&token_id_key).unwrap(); + match prev_entry { + CheckEsdt::Short(prev_balance_check) => *prev_balance_check = balance_value, + CheckEsdt::Full(prev_esdt_check) => match prev_esdt_check.instances { + CheckEsdtInstances::Star => todo!(), + CheckEsdtInstances::Equal(_) => todo!(), + }, + } + } + }, + } + + self + } + + pub fn esdt_nft_balance_and_attributes( + mut self, + token_id: K, + nonce: N, + balance: V, + attributes: T, + ) -> Self + where + K: AnnotatedValue>, + N: AnnotatedValue, + V: AnnotatedValue>, + T: TopEncode, + { + let env = self.new_env_data(); + let token_id_key = token_identifier_annotated(&env, token_id); + let nonce_value = u64_annotated(&env, &nonce); + let balance_value = big_uint_annotated(&env, &balance); + let attributes_value = top_encode_to_vec_u8(&attributes).unwrap(); + + if let CheckEsdtMap::Unspecified = &self.current_account.esdt { + let mut check_esdt = CheckEsdt::Full(CheckEsdtData::default()); + + check_esdt.add_balance_and_attributes_check( + nonce_value, + balance_value, + attributes_value, + ); + + let mut new_esdt_map = BTreeMap::new(); + let _ = new_esdt_map.insert(token_id_key, check_esdt); + + let new_check_esdt_map = CheckEsdtMapContents { + contents: new_esdt_map, + other_esdts_allowed: true, + }; + + self.current_account.esdt = CheckEsdtMap::Equal(new_check_esdt_map); + } + + self + } + + pub fn check_storage(mut self, key: &str, value: &str) -> Self { + let mut details = match &self.current_account.storage { + CheckStorage::Star => CheckStorageDetails::default(), + CheckStorage::Equal(details) => details.clone(), + }; + details.storages.insert( + BytesKey::interpret_from(key, &InterpreterContext::default()), + CheckValue::Equal(BytesValue::interpret_from( + value, + &InterpreterContext::default(), + )), + ); + self.current_account.storage = CheckStorage::Equal(details); + self + } +} + +impl<'w> Drop for CheckStateBuilder<'w> { + fn drop(&mut self) { + self.commit_accounts(); + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_exec_call.rs b/framework/scenario/src/facade/world_tx/scenario_exec_call.rs new file mode 100644 index 0000000000..42a29ef378 --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_exec_call.rs @@ -0,0 +1,127 @@ +use multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + heap::H256, FunctionCall, ManagedAddress, ManagedBuffer, RHListExec, Tx, TxBaseWithEnv, + TxEnv, TxEnvMockDeployAddress, TxEnvWithTxHash, TxFromSpecified, TxGas, TxPayment, + TxToSpecified, + }, +}; + +use crate::{ + api::StaticApi, + scenario::tx_to_step::{address_annotated, TxToStep}, + scenario_model::{SetStateStep, TxExpect, TxResponse}, + ScenarioTxEnv, ScenarioTxRun, ScenarioWorld, +}; + +use super::ScenarioTxEnvData; + +/// Environment for executing transactions. +pub struct ScenarioEnvExec<'w> { + pub world: &'w mut ScenarioWorld, + pub data: ScenarioTxEnvData, +} + +impl<'w> TxEnv for ScenarioEnvExec<'w> { + type Api = StaticApi; + + type RHExpect = TxExpect; + + fn resolve_sender_address(&self) -> ManagedAddress { + panic!("Explicit sender address expected") + } + + fn default_gas_annotation(&self) -> ManagedBuffer { + self.data.default_gas_annotation() + } + + fn default_gas_value(&self) -> u64 { + self.data.default_gas_value() + } +} + +impl<'w> TxEnvMockDeployAddress for ScenarioEnvExec<'w> { + fn mock_deploy_new_address(&mut self, from: &From, new_address: NA) + where + From: TxFromSpecified, + NA: multiversx_sc::types::AnnotatedValue>, + { + let from_value = address_annotated(self, from); + let sender_nonce = self + .world + .get_state() + .accounts + .get(&from_value.to_vm_address()) + .expect("sender does not exist") + .nonce; + let new_address_value = address_annotated(self, &new_address); + + self.world.set_state_step(SetStateStep::new().new_address( + from_value, + sender_nonce, + new_address_value, + )); + } +} + +impl<'w> ScenarioTxEnv for ScenarioEnvExec<'w> { + fn env_data(&self) -> &ScenarioTxEnvData { + &self.data + } +} + +impl<'w, From, To, Payment, Gas, RH> ScenarioTxRun + for Tx, From, To, Payment, Gas, FunctionCall, RH> +where + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn run(self) -> Self::Returns { + let mut step_wrapper = self.tx_to_step(); + step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); + step_wrapper.env.world.sc_call(&mut step_wrapper.step); + step_wrapper.process_result() + } +} + +impl<'w> TxEnvWithTxHash for ScenarioEnvExec<'w> { + fn set_tx_hash(&mut self, tx_hash: H256) { + assert!(self.data.tx_hash.is_none(), "tx hash set twice"); + self.data.tx_hash = Some(tx_hash); + } +} + +impl ScenarioWorld { + pub fn tx(&mut self) -> TxBaseWithEnv> { + let data = self.new_env_data(); + let env = ScenarioEnvExec { world: self, data }; + Tx::new_with_env(env) + } + + pub fn chain_call(&mut self, f: F) -> &mut Self + where + From: TxFromSpecified, + To: TxToSpecified, + Payment: TxPayment, + Gas: TxGas, + RH: RHListExec, + F: FnOnce( + TxBaseWithEnv, + ) + -> Tx, RH>, + { + let env = self.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + let mut step_wrapper = tx.tx_to_step(); + self.sc_call(&mut step_wrapper.step); + step_wrapper.process_result(); + self + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs b/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs new file mode 100644 index 0000000000..40fbbaa878 --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs @@ -0,0 +1,74 @@ +use multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + Code, DeployCall, RHListExec, Tx, TxBaseWithEnv, TxCodeValue, TxFromSpecified, TxGas, + TxPayment, + }, +}; + +use crate::{ + scenario::tx_to_step::TxToStep, scenario_model::TxResponse, ScenarioEnvExec, ScenarioTxRun, + ScenarioWorld, +}; + +use super::ScenarioTxEnvData; + +impl<'w, From, Payment, Gas, CodeValue, RH> ScenarioTxRun + for Tx< + ScenarioEnvExec<'w>, + From, + (), + Payment, + Gas, + DeployCall, Code>, + RH, + > +where + From: TxFromSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn run(self) -> Self::Returns { + let mut step_wrapper = self.tx_to_step(); + step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); + step_wrapper.env.world.sc_deploy(&mut step_wrapper.step); + step_wrapper.process_result() + } +} + +impl ScenarioWorld { + pub fn chain_deploy(&mut self, f: F) -> &mut Self + where + From: TxFromSpecified, + Payment: TxPayment, + Gas: TxGas, + CodeValue: TxCodeValue, + RH: RHListExec, + F: FnOnce( + TxBaseWithEnv, + ) -> Tx< + ScenarioTxEnvData, + From, + (), + Payment, + Gas, + DeployCall>, + RH, + >, + { + let env = self.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + + let mut step_wrapper = tx.tx_to_step(); + self.sc_deploy(&mut step_wrapper.step); + step_wrapper.process_result(); + + self + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_query_call.rs b/framework/scenario/src/facade/world_tx/scenario_query_call.rs new file mode 100644 index 0000000000..dbcf3130f5 --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_query_call.rs @@ -0,0 +1,84 @@ +use multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + FunctionCall, ManagedAddress, ManagedBuffer, RHListExec, Tx, TxBaseWithEnv, TxEnv, + TxToSpecified, + }, +}; + +use crate::{ + api::StaticApi, + scenario::tx_to_step::TxToQueryStep, + scenario_model::{TxExpect, TxResponse}, + ScenarioTxEnv, ScenarioTxEnvData, ScenarioTxRun, ScenarioWorld, +}; + +pub struct ScenarioEnvQuery<'w> { + pub world: &'w mut ScenarioWorld, + pub data: ScenarioTxEnvData, +} + +impl<'w> TxEnv for ScenarioEnvQuery<'w> { + type Api = StaticApi; + + type RHExpect = TxExpect; + + fn resolve_sender_address(&self) -> ManagedAddress { + panic!("Explicit sender address expected") + } + + fn default_gas_annotation(&self) -> ManagedBuffer { + self.data.default_gas_annotation() + } + + fn default_gas_value(&self) -> u64 { + self.data.default_gas_value() + } +} + +impl<'w> ScenarioTxEnv for ScenarioEnvQuery<'w> { + fn env_data(&self) -> &ScenarioTxEnvData { + &self.data + } +} + +impl<'w, To, RH> ScenarioTxRun + for Tx, (), To, (), (), FunctionCall, RH> +where + To: TxToSpecified>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Returns = ::Unpacked; + + fn run(self) -> Self::Returns { + let mut step_wrapper = self.tx_to_query_step(); + step_wrapper.env.world.sc_query(&mut step_wrapper.step); + step_wrapper.process_result() + } +} + +impl ScenarioWorld { + pub fn query(&mut self) -> TxBaseWithEnv> { + let data = self.new_env_data(); + let env = ScenarioEnvQuery { world: self, data }; + Tx::new_with_env(env) + } + + pub fn chain_query(&mut self, f: F) -> &mut Self + where + To: TxToSpecified, + RH: RHListExec, + F: FnOnce( + TxBaseWithEnv, + ) -> Tx, RH>, + { + let env = self.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + let mut step_wrapper = tx.tx_to_query_step(); + self.sc_query(&mut step_wrapper.step); + step_wrapper.process_result(); + self + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_rh_impl.rs b/framework/scenario/src/facade/world_tx/scenario_rh_impl.rs new file mode 100644 index 0000000000..1aaaedae9f --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_rh_impl.rs @@ -0,0 +1,106 @@ +use multiversx_sc::{ + abi::{TypeAbi, TypeAbiFrom}, + codec::TopDecodeMulti, + types::{ + ManagedAddress, RHListItemExec, ReturnsNewAddress, ReturnsNewManagedAddress, ReturnsResult, + ReturnsResultAs, ReturnsResultUnmanaged, TxEnv, WithNewAddress, WithResultAs, + }, +}; + +use crate::scenario_model::{TxResponse, TypedResponse}; + +impl RHListItemExec for ReturnsResult +where + Env: TxEnv, + Original: TopDecodeMulti, +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + let response = TypedResponse::::from_raw(tx_response); + response + .result + .expect("ReturnsResult expects that transaction is successful") + } +} + +impl RHListItemExec for ReturnsResultAs +where + Env: TxEnv, + T: TopDecodeMulti + TypeAbiFrom, +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + let response = TypedResponse::::from_raw(tx_response); + response + .result + .expect("ReturnsResultAs expects that transaction is successful") + } +} + +impl RHListItemExec for ReturnsResultUnmanaged +where + Env: TxEnv, + Original: TypeAbi, + Original::Unmanaged: TopDecodeMulti, +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + let response = TypedResponse::::from_raw(tx_response); + response + .result + .expect("ReturnsResultUnmanaged expects that transaction is successful") + } +} + +impl RHListItemExec for WithResultAs +where + Env: TxEnv, + T: TopDecodeMulti + TypeAbiFrom, + F: FnOnce(T), +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + let response = TypedResponse::::from_raw(tx_response); + let value = response + .result + .expect("ReturnsResult expects that transaction is successful"); + (self.f)(value); + } +} + +impl RHListItemExec for ReturnsNewAddress +where + Env: TxEnv, +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + tx_response + .new_deployed_address + .clone() + .expect("missing returned address") + } +} + +impl RHListItemExec for ReturnsNewManagedAddress +where + Env: TxEnv, +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + let new_address = tx_response + .new_deployed_address + .clone() + .expect("missing returned address"); + + new_address.into() + } +} + +impl RHListItemExec for WithNewAddress +where + Env: TxEnv, + F: FnOnce(&ManagedAddress), +{ + fn item_process_result(self, tx_response: &TxResponse) -> Self::Returns { + let new_address = tx_response + .new_deployed_address + .clone() + .expect("missing returned address"); + + (self.f)(&ManagedAddress::from_address(&new_address)); + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_set_state.rs b/framework/scenario/src/facade/world_tx/scenario_set_state.rs new file mode 100644 index 0000000000..aa9a4ccd9b --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_set_state.rs @@ -0,0 +1,324 @@ +mod scenario_set_account; +mod scenario_set_block; +mod scenario_set_new_address; + +use crate::{ + imports::StaticApi, + scenario::{ + tx_to_step::{address_annotated, big_uint_annotated, u64_annotated}, + ScenarioRunner, + }, + scenario_model::{AddressKey, BigUintValue, NewAddress, SetStateStep}, + ScenarioTxEnvData, ScenarioWorld, +}; + +use multiversx_chain_vm::world_mock::EsdtInstanceMetadata; +use multiversx_sc::{ + proxy_imports::TopEncode, + types::{AnnotatedValue, BigUint, EsdtLocalRole, ManagedAddress}, +}; +use scenario_set_account::AccountItem; +use scenario_set_block::BlockItem; +use scenario_set_new_address::NewAddressItem; + +impl ScenarioWorld { + fn empty_builder(&mut self) -> SetStateBuilder<'_, ()> { + SetStateBuilder { + base: Some(SetStateBuilderBase::new(self)), + item: (), + } + } + + pub fn account(&mut self, address_expr: A) -> SetStateBuilder<'_, AccountItem> + where + A: AnnotatedValue>, + { + self.empty_builder().account(address_expr) + } + + pub fn new_address( + &mut self, + creator_address_expr: CA, + creator_nonce_expr: CN, + new_address_expr: NA, + ) -> SetStateBuilder<'_, NewAddressItem> + where + CA: AnnotatedValue>, + CN: AnnotatedValue, + NA: AnnotatedValue>, + { + self.empty_builder() + .new_address(creator_address_expr, creator_nonce_expr, new_address_expr) + } + + pub fn create_account_raw( + &mut self, + address: A, + egld_balance: V, + ) -> SetStateBuilder<'_, AccountItem> + where + A: AnnotatedValue>, + V: AnnotatedValue>, + { + self.empty_builder().account(address).balance(egld_balance) + } + + pub fn set_egld_balance(&mut self, address: A, balance: V) + where + A: AnnotatedValue>, + V: AnnotatedValue>, + { + let env = self.new_env_data(); + let address_value = address_annotated(&env, &address); + let balance_value = big_uint_annotated(&env, &balance); + let accounts = &mut self.get_mut_state().accounts; + for (vm_address_key, account) in accounts.iter_mut() { + if vm_address_key == &address_value.to_vm_address() { + account.egld_balance = balance_value.value.clone(); + } + } + } + + pub fn set_esdt_balance(&mut self, address: A, token_id: &[u8], balance: V) + where + A: AnnotatedValue>, + V: AnnotatedValue>, + { + let env = self.new_env_data(); + let address_value = address_annotated(&env, &address); + let balance_value = big_uint_annotated(&env, &balance); + let accounts = &mut self.get_mut_state().accounts; + for (vm_address, account) in accounts.iter_mut() { + if vm_address == &address_value.to_vm_address() { + account.esdt.set_esdt_balance( + token_id.to_vec(), + 0, + &balance_value.value, + EsdtInstanceMetadata::default(), + ) + } + } + } + + #[allow(clippy::too_many_arguments)] + pub fn set_nft_balance_all_properties( + &mut self, + address: A, + token_id: &[u8], + nonce: N, + balance: B, + attributes: T, + royalties: R, + creator: Option, + name: Option<&[u8]>, + hash: Option<&[u8]>, + uris: &[Vec], + ) where + A: AnnotatedValue>, + B: AnnotatedValue>, + N: AnnotatedValue, + R: AnnotatedValue, + C: AnnotatedValue>, + { + let env = self.new_env_data(); + let address_value = address_annotated(&env, &address); + let balance_value = big_uint_annotated(&env, &balance); + let nonce_value = u64_annotated(&env, &nonce); + let royalties_value = u64_annotated(&env, &royalties); + + let mut esdt_attributes = Vec::new(); + let _ = attributes.top_encode(&mut esdt_attributes); + let accounts = &mut self.get_mut_state().accounts; + for (vm_address, account) in accounts.iter_mut() { + if vm_address == &address_value.to_vm_address() { + account.esdt.set_esdt_balance( + token_id.to_vec(), + nonce_value.value, + &balance_value.value, + EsdtInstanceMetadata { + creator: creator + .as_ref() + .map(|c| address_annotated(&env, c).to_vm_address()), + attributes: esdt_attributes.clone(), + royalties: royalties_value.value, + name: name.unwrap_or_default().to_vec(), + hash: hash.map(|h| h.to_vec()), + uri: uris.to_vec(), + }, + ) + } + } + } + + pub fn set_developer_rewards(&mut self, address: A, developer_rewards: V) + where + AddressKey: From, + BigUintValue: From, + { + let accounts = &mut self.get_mut_state().accounts; + for (vm_address, account) in accounts.iter_mut() { + if vm_address == &AddressKey::from(address).to_vm_address() { + account.developer_rewards = BigUintValue::from(developer_rewards).value.clone(); + } + } + } + + pub fn set_esdt_local_roles(&mut self, address: A, token_id: &[u8], roles: &[EsdtLocalRole]) + where + A: AnnotatedValue>, + { + let env = self.new_env_data(); + let address_value = address_annotated(&env, &address); + let accounts = &mut self.get_mut_state().accounts; + for (vm_address, account) in accounts.iter_mut() { + if vm_address == &address_value.to_vm_address() { + account.esdt.set_roles( + token_id.to_vec(), + roles + .iter() + .map(|role| role.as_role_name().to_vec()) + .collect(), + ); + } + } + } + + pub fn current_block(&mut self) -> SetStateBuilder<'_, BlockItem> { + self.empty_builder().current_block() + } + + pub fn previous_block(&mut self) -> SetStateBuilder<'_, BlockItem> { + self.empty_builder().previous_block() + } +} + +pub trait SetStateBuilderItem { + fn commit_to_step(&mut self, step: &mut SetStateStep); +} + +impl SetStateBuilderItem for () { + fn commit_to_step(&mut self, _step: &mut SetStateStep) {} +} + +struct SetStateBuilderBase<'w> { + world: &'w mut ScenarioWorld, + set_state_step: SetStateStep, +} + +pub struct SetStateBuilder<'w, Current> +where + Current: SetStateBuilderItem, +{ + base: Option>, + item: Current, +} + +impl<'w> SetStateBuilderBase<'w> { + fn new(world: &'w mut ScenarioWorld) -> Self { + SetStateBuilderBase { + world, + set_state_step: SetStateStep::new(), + } + } + + fn start_account(&self, address: AddressKey) -> AccountItem { + assert!( + !self + .world + .get_debugger_backend() + .vm_runner + .blockchain_mock + .state + .account_exists(&address.to_vm_address()), + "updating existing accounts currently not supported" + ); + + AccountItem::new(address) + } +} + +impl<'w> SetStateBuilder<'w, ()> {} + +impl<'w, Item> SetStateBuilder<'w, Item> +where + Item: SetStateBuilderItem, +{ + fn new_env_data(&self) -> ScenarioTxEnvData { + self.base.as_ref().unwrap().world.new_env_data() + } + + /// Starts building of a new account. + pub fn account(mut self, address_expr: A) -> SetStateBuilder<'w, AccountItem> + where + A: AnnotatedValue>, + { + let mut base = core::mem::take(&mut self.base).unwrap(); + let env = base.world.new_env_data(); + let address_value = address_annotated(&env, &address_expr); + self.item.commit_to_step(&mut base.set_state_step); + let item = base.start_account(address_value.into()); + SetStateBuilder { + base: Some(base), + item, + } + } + + pub fn new_address( + mut self, + creator_address_expr: CA, + creator_nonce_expr: CN, + new_address_expr: NA, + ) -> SetStateBuilder<'w, NewAddressItem> + where + CA: AnnotatedValue>, + CN: AnnotatedValue, + NA: AnnotatedValue>, + { + let mut base = core::mem::take(&mut self.base).unwrap(); + self.item.commit_to_step(&mut base.set_state_step); + let env = base.world.new_env_data(); + SetStateBuilder { + base: Some(base), + item: NewAddressItem { + new_address: NewAddress { + creator_address: address_annotated(&env, &creator_address_expr), + creator_nonce: u64_annotated(&env, &creator_nonce_expr), + new_address: address_annotated(&env, &new_address_expr), + }, + }, + } + } + + pub fn current_block(&mut self) -> SetStateBuilder<'w, BlockItem> { + let mut base = core::mem::take(&mut self.base).unwrap(); + self.item.commit_to_step(&mut base.set_state_step); + SetStateBuilder { + base: Some(base), + item: BlockItem::new_current(), + } + } + + pub fn previous_block(&mut self) -> SetStateBuilder<'w, BlockItem> { + let mut base = core::mem::take(&mut self.base).unwrap(); + self.item.commit_to_step(&mut base.set_state_step); + SetStateBuilder { + base: Some(base), + item: BlockItem::new_prev(), + } + } + + /// Forces value drop and commit accounts. + pub fn commit(self) {} +} + +impl<'w, Current> Drop for SetStateBuilder<'w, Current> +where + Current: SetStateBuilderItem, +{ + fn drop(&mut self) { + if let Some(base) = &mut self.base { + self.item.commit_to_step(&mut base.set_state_step); + base.world.run_set_state_step(&base.set_state_step); + } + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_account.rs b/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_account.rs new file mode 100644 index 0000000000..f5590894e1 --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_account.rs @@ -0,0 +1,220 @@ +use std::collections::btree_map::Entry; + +use multiversx_sc::types::{ + AnnotatedValue, BigUint, ManagedAddress, ManagedBuffer, TokenIdentifier, +}; + +use crate::{ + imports::StaticApi, + scenario::tx_to_step::{ + address_annotated, big_uint_annotated, bytes_annotated, token_identifier_annotated, + u64_annotated, + }, + scenario_model::{Account, AddressKey, BytesKey, Esdt, EsdtObject, SetStateStep}, + ScenarioTxEnvData, +}; + +use super::{SetStateBuilder, SetStateBuilderItem}; + +pub struct AccountItem { + address: AddressKey, + account: Account, +} + +impl AccountItem { + pub fn new(address: AddressKey) -> Self { + AccountItem { + address, + account: Account::default(), + } + } +} + +impl SetStateBuilderItem for AccountItem { + fn commit_to_step(&mut self, step: &mut SetStateStep) { + if let Entry::Vacant(entry) = step.accounts.entry(core::mem::take(&mut self.address)) { + entry.insert(core::mem::take(&mut self.account)); + }; + } +} + +impl<'w> SetStateBuilder<'w, AccountItem> { + pub fn nonce(mut self, nonce: N) -> Self + where + N: AnnotatedValue, + { + let env = self.new_env_data(); + self.item.account.nonce = Some(u64_annotated(&env, &nonce)); + self + } + + pub fn balance(mut self, balance: V) -> Self + where + V: AnnotatedValue>, + { + let env = self.new_env_data(); + self.item.account.balance = Some(big_uint_annotated(&env, &balance)); + self + } + + pub fn esdt_balance(mut self, token_id: K, balance: V) -> Self + where + K: AnnotatedValue>, + V: AnnotatedValue>, + { + let env = self.new_env_data(); + let token_id_key = token_identifier_annotated(&env, token_id); + let balance_value = big_uint_annotated(&env, &balance); + + let esdt_data_ref = self.get_esdt_data_or_create(&token_id_key); + esdt_data_ref.set_balance(0u64, balance_value); + + self + } + + pub fn esdt_nft_balance( + mut self, + token_id: K, + nonce: N, + balance: V, + attributes: T, + ) -> Self + where + K: AnnotatedValue>, + N: AnnotatedValue, + V: AnnotatedValue>, + T: AnnotatedValue>, + { + let env = self.new_env_data(); + let token_id_key = token_identifier_annotated(&env, token_id); + let nonce_value = u64_annotated(&env, &nonce); + let balance_value = big_uint_annotated(&env, &balance); + let attributes_value = bytes_annotated(&env, attributes); + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id_key) + .get_mut_esdt_object(); + esdt_obj_ref.set_balance(nonce_value.clone(), balance_value); + + esdt_obj_ref.set_token_attributes(nonce_value, attributes_value); + + self + } + + #[allow(clippy::too_many_arguments)] + pub fn esdt_nft_all_properties( + mut self, + token_id: K, + nonce: N, + balance: V, + attributes: T, + royalties: R, + creator: Option, + hash: H, + uris: Vec, + ) -> Self + where + K: AnnotatedValue>, + N: AnnotatedValue, + V: AnnotatedValue>, + T: AnnotatedValue>, + C: AnnotatedValue>, + R: AnnotatedValue, + H: AnnotatedValue>, + U: AnnotatedValue>, + { + let env = self.new_env_data(); + let token_id_key = token_identifier_annotated(&env, token_id); + let nonce_value = u64_annotated(&env, &nonce); + let royalties_value = u64_annotated(&env, &royalties); + let balance_value = big_uint_annotated(&env, &balance); + let attributes_value = bytes_annotated(&env, attributes); + let creator_value = creator.as_ref().map(|c| address_annotated(&env, c)); + let hash_value = bytes_annotated(&env, hash); + let mut uris_value = Vec::new(); + for uri in uris { + let uri_value = bytes_annotated(&env, uri); + uris_value.push(uri_value); + } + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id_key) + .get_mut_esdt_object(); + + esdt_obj_ref.set_token_all_properties( + nonce_value, + balance_value, + Some(attributes_value), + royalties_value, + creator_value, + Some(hash_value), + uris_value, + ); + + self + } + + pub fn esdt_nft_last_nonce(mut self, token_id: K, last_nonce: N) -> Self + where + K: AnnotatedValue>, + N: AnnotatedValue, + { + let env = self.new_env_data(); + let token_id_key = token_identifier_annotated(&env, token_id); + let nonce_value = u64_annotated(&env, &last_nonce); + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id_key) + .get_mut_esdt_object(); + esdt_obj_ref.set_last_nonce(nonce_value); + + self + } + + // TODO: Find a better way to pass roles + pub fn esdt_roles(mut self, token_id: K, roles: Vec) -> Self + where + K: AnnotatedValue>, + { + let env = self.new_env_data(); + let token_id_key = token_identifier_annotated(&env, token_id); + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id_key) + .get_mut_esdt_object(); + esdt_obj_ref.set_roles(roles); + + self + } + + fn get_esdt_data_or_create(&mut self, token_id: &BytesKey) -> &mut Esdt { + if !self.item.account.esdt.contains_key(token_id) { + self.item + .account + .esdt + .insert(token_id.clone(), Esdt::Full(EsdtObject::default())); + } + + self.item.account.esdt.get_mut(token_id).unwrap() + } + + pub fn code(mut self, code: C) -> Self + where + C: AnnotatedValue>, + { + let env = self.new_env_data(); + let code_value = bytes_annotated(&env, code); + self.item.account.code = Some(code_value); + self + } + + pub fn owner(mut self, owner: V) -> Self + where + V: AnnotatedValue>, + { + let env = self.new_env_data(); + let owner_value = address_annotated(&env, &owner); + self.item.account.owner = Some(owner_value); + self + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_block.rs b/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_block.rs new file mode 100644 index 0000000000..3ef0d06cca --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_block.rs @@ -0,0 +1,107 @@ +use multiversx_sc::types::{AnnotatedValue, ManagedBuffer}; + +use crate::{ + imports::StaticApi, + scenario::tx_to_step::{bytes_annotated, u64_annotated}, + scenario_model::{BlockInfo, SetStateStep}, + ScenarioTxEnvData, +}; + +use super::{SetStateBuilder, SetStateBuilderItem}; + +pub enum BlockItemTarget { + Current, + Previous, +} + +pub struct BlockItem { + target: BlockItemTarget, + block_info: BlockInfo, +} + +impl BlockItem { + pub fn new_current() -> Self { + BlockItem { + target: BlockItemTarget::Current, + block_info: BlockInfo::default(), + } + } + + pub fn new_prev() -> Self { + BlockItem { + target: BlockItemTarget::Previous, + block_info: BlockInfo::default(), + } + } +} + +impl SetStateBuilderItem for BlockItem { + fn commit_to_step(&mut self, step: &mut SetStateStep) { + let block_info = core::mem::take(&mut self.block_info); + match self.target { + BlockItemTarget::Current => { + step.current_block_info = Box::new(Some(block_info)); + }, + BlockItemTarget::Previous => { + step.previous_block_info = Box::new(Some(block_info)); + }, + } + } +} + +impl<'w> SetStateBuilder<'w, BlockItem> { + pub fn block_epoch(mut self, block_epoch: N) -> Self + where + N: AnnotatedValue, + { + let env = self.new_env_data(); + let block_epoch_value = u64_annotated(&env, &block_epoch); + + self.item.block_info.block_epoch = Some(block_epoch_value); + self + } + + pub fn block_nonce(mut self, block_nonce: N) -> Self + where + N: AnnotatedValue, + { + let env = self.new_env_data(); + let block_nonce_value = u64_annotated(&env, &block_nonce); + + self.item.block_info.block_nonce = Some(block_nonce_value); + self + } + + pub fn block_round(mut self, block_round: N) -> Self + where + N: AnnotatedValue, + { + let env = self.new_env_data(); + let block_round_value = u64_annotated(&env, &block_round); + + self.item.block_info.block_round = Some(block_round_value); + self + } + + pub fn block_timestamp(mut self, block_timestamp: N) -> Self + where + N: AnnotatedValue, + { + let env = self.new_env_data(); + let block_timestamp_value = u64_annotated(&env, &block_timestamp); + + self.item.block_info.block_timestamp = Some(block_timestamp_value); + self + } + + pub fn block_random_seed(mut self, block_random_seed: B) -> Self + where + B: AnnotatedValue>, + { + let env = self.new_env_data(); + let block_random_seed_value = bytes_annotated(&env, block_random_seed); + + self.item.block_info.block_random_seed = Some(block_random_seed_value); + self + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_new_address.rs b/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_new_address.rs new file mode 100644 index 0000000000..35a8ae392b --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_set_state/scenario_set_new_address.rs @@ -0,0 +1,14 @@ +use crate::scenario_model::{NewAddress, SetStateStep}; + +use super::SetStateBuilderItem; + +pub struct NewAddressItem { + pub(super) new_address: NewAddress, +} + +impl SetStateBuilderItem for NewAddressItem { + fn commit_to_step(&mut self, step: &mut SetStateStep) { + step.new_addresses + .push(core::mem::take(&mut self.new_address)); + } +} diff --git a/framework/scenario/src/facade/world_tx/scenario_tx_env.rs b/framework/scenario/src/facade/world_tx/scenario_tx_env.rs new file mode 100644 index 0000000000..91aa212fc3 --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_tx_env.rs @@ -0,0 +1,66 @@ +use std::path::PathBuf; + +use multiversx_chain_scenario_format::interpret_trait::InterpreterContext; +use multiversx_sc::types::{ManagedAddress, ManagedBuffer, TxEnv, H256}; + +use crate::{api::StaticApi, scenario_model::TxExpect, ScenarioWorld}; + +/// Designates a tx environment suitable for running scenarios locally. +pub trait ScenarioTxEnv: TxEnv { + fn env_data(&self) -> &ScenarioTxEnvData; +} + +/// The actual data required to run a scenario locally. This is the minimal environment needed to run txs. +#[derive(Default, Debug, Clone)] +pub struct ScenarioTxEnvData { + pub context_path: PathBuf, + pub tx_hash: Option, +} + +impl TxEnv for ScenarioTxEnvData { + type Api = StaticApi; + + type RHExpect = TxExpect; + + fn resolve_sender_address(&self) -> ManagedAddress { + panic!("Explicit sender address expected") + } + + fn default_gas_annotation(&self) -> multiversx_sc::types::ManagedBuffer { + ManagedBuffer::from("5,000,000") + } + + fn default_gas_value(&self) -> u64 { + 5_000_000 + } +} + +impl ScenarioTxEnvData { + pub fn interpreter_context(&self) -> InterpreterContext { + InterpreterContext::default() + .with_dir(self.context_path.clone()) + .with_allowed_missing_files() + } +} + +impl ScenarioTxEnv for ScenarioTxEnvData { + fn env_data(&self) -> &ScenarioTxEnvData { + self + } +} + +impl ScenarioWorld { + pub(crate) fn new_env_data(&self) -> ScenarioTxEnvData { + ScenarioTxEnvData { + context_path: self.current_dir.clone(), + tx_hash: None, + } + } +} + +/// Provides a `run` method for transactions and steps. +pub trait ScenarioTxRun { + type Returns; + + fn run(self) -> Self::Returns; +} diff --git a/framework/scenario/src/imports.rs b/framework/scenario/src/imports.rs new file mode 100644 index 0000000000..9eac89fc70 --- /dev/null +++ b/framework/scenario/src/imports.rs @@ -0,0 +1,27 @@ +pub use crate::multiversx_sc::imports::*; + +pub use crate::multiversx_sc::codec::test_util::*; + +pub use crate::{ + api::{DebugApi, StaticApi}, + assert_values_eq, bech32, + facade::{ + expr::*, result_handlers::*, world_tx::*, ContractInfo, ScenarioWorld, WhiteboxContract, + }, + managed_address, managed_biguint, managed_buffer, managed_token_id, num_bigint, + num_bigint::BigUint as RustBigUint, + rust_biguint, + scenario::{ + model::{ + Account, AddressValue, BytesValue, CheckAccount, CheckStateStep, ScCallStep, + ScDeployStep, ScQueryStep, Scenario, SetStateStep, TransferStep, TxESDT, TxExpect, + TypedResponse, TypedScDeploy, + }, + ScenarioRunner, + }, + scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, + standalone::retrieve_account_as_scenario_set_state, + test_wallets, + whitebox_legacy::*, + ScenarioTxRun, +}; diff --git a/framework/scenario/src/lib.rs b/framework/scenario/src/lib.rs index 8e31b5bb6e..4d3fb3b1dc 100644 --- a/framework/scenario/src/lib.rs +++ b/framework/scenario/src/lib.rs @@ -8,7 +8,7 @@ pub mod display_util; mod facade; pub mod managed_test_util; pub mod scenario; -mod scenario_macros; +pub mod scenario_macros; pub mod standalone; pub mod test_wallets; mod vm_go_tool; @@ -39,10 +39,13 @@ pub use crate::scenario as mandos_system; // Re-exporting the whole mandos crate for easier use in tests. pub use multiversx_chain_scenario_format as scenario_format; -pub use facade::{ContractInfo, ScenarioWorld, WhiteboxContract}; +pub use facade::{result_handlers::*, world_tx::*, ContractInfo, ScenarioWorld, WhiteboxContract}; use std::path::Path; +/// Imports normally needed in integration tests, grouped together. +pub mod imports; + /// Legacy function for running a scenario test using the Go VM tool. /// /// Use `sc-meta test-gen` to replace all calls to it automatically. diff --git a/framework/scenario/src/scenario/mod.rs b/framework/scenario/src/scenario.rs similarity index 91% rename from framework/scenario/src/scenario/mod.rs rename to framework/scenario/src/scenario.rs index 3ffd41300f..70f8f5f285 100644 --- a/framework/scenario/src/scenario/mod.rs +++ b/framework/scenario/src/scenario.rs @@ -4,6 +4,7 @@ pub mod run_list; pub mod run_trace; pub mod run_vm; mod scenario_runner; +pub mod tx_to_step; pub use parse_util::{parse_scenario, parse_scenario_raw}; pub use scenario_runner::ScenarioRunner; diff --git a/framework/scenario/src/scenario/model/account_data/account.rs b/framework/scenario/src/scenario/model/account_data/account.rs index 8488017c4e..9748fdf7dc 100644 --- a/framework/scenario/src/scenario/model/account_data/account.rs +++ b/framework/scenario/src/scenario/model/account_data/account.rs @@ -86,14 +86,14 @@ impl Account { } #[allow(clippy::too_many_arguments)] - pub fn esdt_nft_all_properties( + pub fn esdt_nft_all_properties( mut self, token_id_expr: K, nonce_expr: N, balance_expr: V, opt_attributes_expr: Option, royalties_expr: N, - creator_expr: Option, + creator_expr: Option, hash_expr: Option, uris_expr: Vec, ) -> Self @@ -102,6 +102,7 @@ impl Account { U64Value: From, BigUintValue: From, BytesValue: From, + AddressValue: From, { let token_id = BytesKey::from(token_id_expr); diff --git a/framework/scenario/src/scenario/model/esdt_data/esdt_instance.rs b/framework/scenario/src/scenario/model/esdt_data/esdt_instance.rs index 8607937c6c..01e57394d2 100644 --- a/framework/scenario/src/scenario/model/esdt_data/esdt_instance.rs +++ b/framework/scenario/src/scenario/model/esdt_data/esdt_instance.rs @@ -4,13 +4,14 @@ use crate::{ interpret_trait::{InterpretableFrom, InterpreterContext, IntoRaw}, serde_raw::EsdtInstanceRaw, }, + scenario_model::AddressValue, }; #[derive(Debug, Default, Clone)] pub struct EsdtInstance { pub nonce: Option, pub balance: Option, - pub creator: Option, + pub creator: Option, pub royalties: Option, pub hash: Option, pub uri: Vec, @@ -41,7 +42,9 @@ impl InterpretableFrom for EsdtInstance { balance: from .balance .map(|b| BigUintValue::interpret_from(b, context)), - creator: from.creator.map(|b| BytesValue::interpret_from(b, context)), + creator: from + .creator + .map(|b| AddressValue::interpret_from(b, context)), royalties: from.royalties.map(|b| U64Value::interpret_from(b, context)), hash: from.hash.map(|b| BytesValue::interpret_from(b, context)), uri: from diff --git a/framework/scenario/src/scenario/model/esdt_data/esdt_object.rs b/framework/scenario/src/scenario/model/esdt_data/esdt_object.rs index f8298e2b8c..f9d65e4df9 100644 --- a/framework/scenario/src/scenario/model/esdt_data/esdt_object.rs +++ b/framework/scenario/src/scenario/model/esdt_data/esdt_object.rs @@ -1,5 +1,8 @@ use super::EsdtInstance; -use crate::scenario::model::{BigUintValue, BytesValue, U64Value}; +use crate::{ + scenario::model::{BigUintValue, BytesValue, U64Value}, + scenario_model::AddressValue, +}; #[derive(Debug, Default, Clone)] pub struct EsdtObject { @@ -53,19 +56,20 @@ impl EsdtObject { } #[allow(clippy::too_many_arguments)] - pub fn set_token_all_properties( + pub fn set_token_all_properties( &mut self, nonce_expr: N, balance_expr: V, opt_attributes_expr: Option, royalties_expr: N, - creator_expr: Option, + creator_expr: Option, hash_expr: Option, uris_expr: Vec, ) where U64Value: From, BigUintValue: From, BytesValue: From, + AddressValue: From, { let inst_for_nonce = self.get_or_insert_instance_for_nonce(nonce_expr); @@ -93,8 +97,8 @@ impl EsdtObject { } if let Some(creator_expr) = creator_expr { - let creator = BytesValue::from(creator_expr); - if !creator.value.is_empty() { + let creator = AddressValue::from(creator_expr); + if !creator.value.is_zero() { inst_for_nonce.creator = Some(creator); } else { inst_for_nonce.creator = None; diff --git a/framework/scenario/src/scenario/model/new_address.rs b/framework/scenario/src/scenario/model/new_address.rs index f4893978d1..3ef0ddba2c 100644 --- a/framework/scenario/src/scenario/model/new_address.rs +++ b/framework/scenario/src/scenario/model/new_address.rs @@ -5,7 +5,7 @@ use crate::scenario_format::{ use super::{AddressValue, U64Value}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct NewAddress { pub creator_address: AddressValue, pub creator_nonce: U64Value, diff --git a/framework/scenario/src/scenario/model/step/sc_call_step.rs b/framework/scenario/src/scenario/model/step/sc_call_step.rs index f18bf4c2c5..07bc120fea 100644 --- a/framework/scenario/src/scenario/model/step/sc_call_step.rs +++ b/framework/scenario/src/scenario/model/step/sc_call_step.rs @@ -1,4 +1,4 @@ -use multiversx_sc::types::H256; +use multiversx_sc::{abi::TypeAbiFrom, types::H256}; use crate::{ api::StaticApi, @@ -7,12 +7,10 @@ use crate::{ }; use crate::multiversx_sc::{ - codec::{CodecFrom, PanicErrorHandler, TopEncodeMulti}, + codec::{PanicErrorHandler, TopEncodeMulti}, types::{ContractCall, ManagedArgBuffer}, }; -use super::TypedScCall; - #[derive(Debug, Clone)] pub struct ScCallStep { pub id: String, @@ -136,9 +134,14 @@ impl ScCallStep { /// - "to" /// - "function" /// - "arguments" - pub fn call(mut self, contract_call: CC) -> TypedScCall + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] + #[allow(deprecated)] + pub fn call(mut self, contract_call: CC) -> super::TypedScCall where - CC: ContractCall, + CC: multiversx_sc::types::ContractCallBase, { let (to_str, function, egld_value_expr, scenario_args) = process_contract_call(contract_call); @@ -167,14 +170,15 @@ impl ScCallStep { since = "0.42.0", note = "Please use `call` followed by `expect`, there is no point in having a method that does both." )] + #[allow(deprecated)] pub fn call_expect( self, contract_call: CC, expected_value: ExpectedResult, - ) -> TypedScCall + ) -> super::TypedScCall where CC: ContractCall, - ExpectedResult: CodecFrom + TopEncodeMulti, + ExpectedResult: TypeAbiFrom + TopEncodeMulti, { self.call(contract_call).expect_value(expected_value) } @@ -220,11 +224,12 @@ impl AsMut for ScCallStep { /// - recipient, /// - endpoint name, /// - the arguments. +#[allow(deprecated)] pub(super) fn process_contract_call( contract_call: CC, ) -> (String, String, BigUintValue, Vec) where - CC: ContractCall, + CC: multiversx_sc::types::ContractCallBase, { let normalized_cc = contract_call.into_normalized(); let to_str = format!( diff --git a/framework/scenario/src/scenario/model/step/sc_deploy_step.rs b/framework/scenario/src/scenario/model/step/sc_deploy_step.rs index 0ade06fc0f..7e520e1a17 100644 --- a/framework/scenario/src/scenario/model/step/sc_deploy_step.rs +++ b/framework/scenario/src/scenario/model/step/sc_deploy_step.rs @@ -10,7 +10,7 @@ use crate::{ scenario_model::TxResponse, }; -use crate::multiversx_sc::types::{CodeMetadata, ContractDeploy}; +use crate::multiversx_sc::types::CodeMetadata; use super::{convert_call_args, TypedScDeploy}; @@ -98,11 +98,16 @@ impl ScDeployStep { /// Sets following fields based on the smart contract proxy: /// - "function" /// - "arguments" - pub fn call( - mut self, - contract_deploy: ContractDeploy, - ) -> TypedScDeploy { - let (_, mandos_args) = process_contract_deploy(contract_deploy); + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] + #[allow(deprecated)] + pub fn call(mut self, contract_deploy: CD) -> TypedScDeploy + where + CD: Into>, + { + let (_, mandos_args) = process_contract_deploy(contract_deploy.into()); for arg in mandos_args { self = self.argument(arg.as_str()); } @@ -149,8 +154,13 @@ impl AsMut for ScDeployStep { /// Extracts /// - (optional) recipient (needed for contract upgrade, not yet used); /// - the arguments. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] +#[allow(deprecated)] pub(crate) fn process_contract_deploy( - contract_deploy: ContractDeploy, + contract_deploy: multiversx_sc::types::ContractDeploy, ) -> (Option, Vec) { let to_str = contract_deploy .to diff --git a/framework/scenario/src/scenario/model/step/sc_query_step.rs b/framework/scenario/src/scenario/model/step/sc_query_step.rs index a3ada3b83b..8183dcd579 100644 --- a/framework/scenario/src/scenario/model/step/sc_query_step.rs +++ b/framework/scenario/src/scenario/model/step/sc_query_step.rs @@ -1,12 +1,9 @@ -use multiversx_sc::types::H256; +use multiversx_sc::{abi::TypeAbiFrom, types::H256}; use num_traits::Zero; use crate::{ api::StaticApi, - multiversx_sc::{ - codec::{CodecFrom, TopEncodeMulti}, - types::ContractCall, - }, + multiversx_sc::{codec::TopEncodeMulti, types::ContractCall}, scenario::model::{AddressValue, BytesValue, TxExpect, TxQuery}, scenario_model::TxResponse, }; @@ -65,9 +62,14 @@ impl ScQueryStep { /// - "to" /// - "function" /// - "arguments" + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] + #[allow(deprecated)] pub fn call(mut self, contract_call: CC) -> TypedScQuery where - CC: ContractCall, + CC: multiversx_sc::types::ContractCallBase, { let (to_str, function, egld_value_expr, mandos_args) = process_contract_call(contract_call); assert!( @@ -89,6 +91,11 @@ impl ScQueryStep { /// - "expect" /// - "out" /// - "status" set to 0 + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] + #[allow(deprecated)] pub fn call_expect( self, contract_call: CC, @@ -96,7 +103,7 @@ impl ScQueryStep { ) -> TypedScQuery where CC: ContractCall, - ExpectedResult: CodecFrom + TopEncodeMulti, + ExpectedResult: TypeAbiFrom + TopEncodeMulti, { let typed = self.call(contract_call); typed.expect_value(expected_value) diff --git a/framework/scenario/src/scenario/model/step/typed_sc_call.rs b/framework/scenario/src/scenario/model/step/typed_sc_call.rs index bf939ee590..e70e00aa64 100644 --- a/framework/scenario/src/scenario/model/step/typed_sc_call.rs +++ b/framework/scenario/src/scenario/model/step/typed_sc_call.rs @@ -1,8 +1,13 @@ +#![allow(deprecated)] + use std::marker::PhantomData; -use multiversx_sc::codec::PanicErrorHandler; +use multiversx_sc::{ + abi::TypeAbiFrom, + codec::{PanicErrorHandler, TopDecodeMulti}, +}; -use crate::multiversx_sc::codec::{CodecFrom, TopEncodeMulti}; +use crate::multiversx_sc::codec::TopEncodeMulti; use crate::{ scenario::model::{AddressValue, U64Value}, @@ -12,6 +17,10 @@ use crate::{ use super::{format_expect, ScCallStep}; /// `SCCallStep` with explicit return type. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] #[derive(Default, Debug)] pub struct TypedScCall { pub sc_call_step: ScCallStep, @@ -22,7 +31,7 @@ impl TypedScCall { pub fn result(&self) -> Result where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { let mut raw_result = self.response().out.clone(); Ok( @@ -109,7 +118,7 @@ impl TypedScCall { pub fn expect_value(self, expected_value: ExpectedResult) -> Self where OriginalResult: TopEncodeMulti, - ExpectedResult: CodecFrom + TopEncodeMulti, + ExpectedResult: TypeAbiFrom + TopEncodeMulti, { self.expect(format_expect(expected_value)) } @@ -144,14 +153,22 @@ impl From for TypedScCall { /// Helps with syntax. Allows the `TypedScCall` to call the `execute` operation directly. /// /// The trait defines the connection to the executor. +#[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." +)] pub trait TypedScCallExecutor { + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] fn execute_typed_sc_call( &mut self, typed_sc_call: TypedScCall, ) -> RequestedResult where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom; + RequestedResult: TopDecodeMulti + TypeAbiFrom; } impl TypedScCall @@ -164,7 +181,7 @@ where executor: &mut E, ) -> RequestedResult where - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { executor.execute_typed_sc_call(self) } diff --git a/framework/scenario/src/scenario/model/step/typed_sc_deploy.rs b/framework/scenario/src/scenario/model/step/typed_sc_deploy.rs index c440f9bd29..2fa49c188f 100644 --- a/framework/scenario/src/scenario/model/step/typed_sc_deploy.rs +++ b/framework/scenario/src/scenario/model/step/typed_sc_deploy.rs @@ -1,11 +1,14 @@ use std::marker::PhantomData; -use multiversx_sc::{codec::PanicErrorHandler, types::ContractDeploy}; +use multiversx_sc::{ + abi::TypeAbiFrom, + codec::{PanicErrorHandler, TopDecodeMulti}, +}; use crate::{ api::StaticApi, multiversx_sc::{ - codec::{CodecFrom, TopEncodeMulti}, + codec::TopEncodeMulti, types::{Address, CodeMetadata}, }, scenario_format::interpret_trait::InterpreterContext, @@ -14,7 +17,7 @@ use crate::{ use crate::scenario::model::{AddressValue, BigUintValue, TxExpect, U64Value}; -use super::{process_contract_deploy, ScDeployStep}; +use super::ScDeployStep; /// `ScDeployStep` with explicit return type. #[derive(Default, Debug)] @@ -27,7 +30,7 @@ impl TypedScDeploy { pub fn result(&self) -> Result where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { let mut raw_result = self.response().out.clone(); Ok( @@ -100,8 +103,16 @@ impl TypedScDeploy { /// Sets following fields based on the smart contract proxy: /// - "function" /// - "arguments" - pub fn call(mut self, contract_deploy: ContractDeploy) -> Self { - let (_, mandos_args) = process_contract_deploy(contract_deploy); + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] + #[allow(deprecated)] + pub fn call( + mut self, + contract_deploy: multiversx_sc::types::ContractDeploy, + ) -> Self { + let (_, mandos_args) = super::process_contract_deploy(contract_deploy); for arg in mandos_args { self.sc_deploy_step.tx.arguments.push(BytesValue::from(arg)); } @@ -145,7 +156,7 @@ pub trait TypedScDeployExecutor { ) -> (Address, RequestedResult) where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom; + RequestedResult: TopDecodeMulti + TypeAbiFrom; } impl TypedScDeploy @@ -158,7 +169,7 @@ where executor: &mut E, ) -> (Address, RequestedResult) where - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { executor.execute_typed_sc_deploy(self) } diff --git a/framework/scenario/src/scenario/model/step/typed_sc_query.rs b/framework/scenario/src/scenario/model/step/typed_sc_query.rs index 60b3b91818..3e7e819c4e 100644 --- a/framework/scenario/src/scenario/model/step/typed_sc_query.rs +++ b/framework/scenario/src/scenario/model/step/typed_sc_query.rs @@ -1,6 +1,8 @@ use std::marker::PhantomData; -use crate::multiversx_sc::codec::{CodecFrom, TopEncodeMulti}; +use multiversx_sc::{abi::TypeAbiFrom, codec::TopDecodeMulti}; + +use crate::multiversx_sc::codec::TopEncodeMulti; use crate::{ scenario::model::{AddressValue, BytesValue, TxExpect}, @@ -72,7 +74,7 @@ impl TypedScQuery { pub fn expect_value(self, expected_value: ExpectedResult) -> Self where OriginalResult: TopEncodeMulti, - ExpectedResult: CodecFrom + TopEncodeMulti, + ExpectedResult: TypeAbiFrom + TopEncodeMulti, { self.expect(format_expect(expected_value)) } @@ -105,7 +107,7 @@ pub trait TypedScQueryExecutor { ) -> RequestedResult where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom; + RequestedResult: TopDecodeMulti + TypeAbiFrom; } impl TypedScQuery @@ -118,7 +120,7 @@ where executor: &mut E, ) -> RequestedResult where - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { executor.execute_typed_sc_query(self) } diff --git a/framework/scenario/src/scenario/model/transaction/tx_call.rs b/framework/scenario/src/scenario/model/transaction/tx_call.rs index 102ef3ef4e..547466032e 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_call.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_call.rs @@ -1,6 +1,6 @@ use crate::{ api::StaticApi, - multiversx_sc::types::{ContractCall, ContractCallWithEgld, EsdtTokenPayment}, + multiversx_sc::types::{ContractCall, EsdtTokenPayment}, scenario::model::{AddressValue, BigUintValue, BytesValue, U64Value}, scenario_format::{ interpret_trait::{InterpretableFrom, InterpreterContext, IntoRaw}, @@ -87,8 +87,13 @@ impl IntoRaw for TxCall { } impl TxCall { - pub fn to_contract_call(&self) -> ContractCallWithEgld { - let mut contract_call = ContractCallWithEgld::new( + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] + #[allow(deprecated)] + pub fn to_contract_call(&self) -> multiversx_sc::types::ContractCallWithEgld { + let mut contract_call = multiversx_sc::types::ContractCallWithEgld::new( (&self.to.value).into(), self.function.as_bytes(), (&self.egld_value.value).into(), diff --git a/framework/scenario/src/scenario/model/transaction/tx_esdt.rs b/framework/scenario/src/scenario/model/transaction/tx_esdt.rs index cf17a76a19..67ccf99956 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_esdt.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_esdt.rs @@ -1,3 +1,5 @@ +use multiversx_sc::{api::ManagedTypeApi, types::EsdtTokenPayment}; + use crate::{ scenario::model::{BigUintValue, BytesValue, U64Value}, scenario_format::{ @@ -33,6 +35,18 @@ impl IntoRaw for TxESDT { } } +impl From> for TxESDT { + fn from(value: EsdtTokenPayment) -> Self { + TxESDT { + esdt_token_identifier: BytesValue::from( + value.token_identifier.as_managed_buffer().to_vec(), + ), + nonce: U64Value::from(value.token_nonce), + esdt_value: BigUintValue::from(value.amount), + } + } +} + fn interpret_esdt_token_identifier( esdt_token_identifier: Option, context: &InterpreterContext, diff --git a/framework/scenario/src/scenario/model/transaction/tx_expect.rs b/framework/scenario/src/scenario/model/transaction/tx_expect.rs index 6f64a471f0..d487a10db5 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_expect.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_expect.rs @@ -23,6 +23,12 @@ pub struct TxExpect { pub additional_error_message: String, } +impl Default for TxExpect { + fn default() -> Self { + Self::ok() + } +} + impl TxExpect { pub fn ok() -> Self { TxExpect { diff --git a/framework/scenario/src/scenario/model/transaction/tx_response.rs b/framework/scenario/src/scenario/model/transaction/tx_response.rs index 440db8258a..1465885476 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_response.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_response.rs @@ -1,5 +1,5 @@ use multiversx_chain_vm::{crypto_functions::keccak256, tx_mock::TxResult}; -use multiversx_sc::types::Address; +use multiversx_sc::types::{Address, ESDTSystemSCAddress}; use multiversx_sdk::{ data::transaction::{ApiLogs, ApiSmartContractResult, Events, TransactionOnNetwork}, utils::base64_decode, @@ -12,8 +12,6 @@ use super::{ const SC_DEPLOY_PROCESSING_TYPE: &str = "SCDeployment"; const LOG_IDENTIFIER_SIGNAL_ERROR: &str = "signalError"; -const SYSTEM_SC_BECH32: &str = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"; - #[derive(Debug, Default, Clone)] /// The response of a transaction. pub struct TxResponse { @@ -196,7 +194,7 @@ impl TxResponse { fn process_new_issued_token_identifier(mut self) -> Self { for scr in self.api_scrs.iter() { - if scr.sender.to_string() != SYSTEM_SC_BECH32 { + if scr.sender.to_bech32_string().unwrap() != ESDTSystemSCAddress.to_bech32_string() { continue; } @@ -208,11 +206,14 @@ impl TxResponse { 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@"); if !is_issue_fungible && !is_issue_semi_fungible && !is_issue_non_fungible && !is_register_meta_esdt + && !is_register_and_set_all_roles_esdt { continue; } @@ -253,2121 +254,3 @@ impl TxResponse { } } } - -#[cfg(test)] -mod tests { - use crate::scenario_model::TxResponse; - use multiversx_sc::types::Address; - use multiversx_sdk::data::transaction::{TransactionInfo, TransactionOnNetwork}; - - #[test] - fn test_deployed_address() { - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCDeployment", - "processingTypeOnDestination": "SCDeployment", - "hash": "07a176d1734d1901d396be344f97e1d80f076269e9559f9b2110f6f11c4f74de", - "nonce": 427, - "round": 2190715, - "epoch": 887, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu", - "sender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "data": "MDA2MTczNmQwMTAwMDAwMDAxOTgwMTE5NjAwMjdmN2YwMDYwMDE3ZjAxN2Y2MDAwMDA2MDAwMDE3ZjYwMDI3ZjdmMDE3ZjYwMDM3ZjdmN2YwMDYwMDE3ZjAwNjAwNDdmN2Y3ZjdmMDA2MDA1N2Y3ZjdmN2Y3ZjAwNjAwMzdmN2Y3ZjAxN2Y2MDA0N2Y3ZjdmN2YwMTdmNjAwMjdmN2UwMDYwMDE3ZjAxN2U2MDAyN2Y3ZjAxN2U2MDA1N2Y3ZjdlN2Y3ZjAxN2Y2MDA2N2U3ZjdmN2Y3ZjdmMDE3ZjYwMDE3ZTAwNjAwMDAxN2U2MDAxN2UwMTdmNjAwNDdmN2Y3ZTdmMDA2MDA1N2U3ZjdmN2Y3ZjAxN2Y2MDA0N2Y3ZjdmN2UwMDYwMDE3ZTAxN2U2MDA0N2Y3ZTdmN2YwMDYwMDI3ZTdmMDAwMmMxMDcyOTAzNjU2ZTc2MTI2ZDYxNmU2MTY3NjU2NDUzNjk2NzZlNjE2YzQ1NzI3MjZmNzIwMDA2MDM2NTZlNzYwZTYyNjk2NzQ5NmU3NDUzNjU3NDQ5NmU3NDM2MzQwMDBiMDM2NTZlNzYwOTYyNjk2NzQ5NmU3NDQxNjQ2NDAwMDUwMzY1NmU3NjBiNzM2OTY3NmU2MTZjNDU3MjcyNmY3MjAwMDAwMzY1NmU3NjBhNmQ0Mjc1NjY2NjY1NzI0ZTY1NzcwMDAzMDM2NTZlNzYwZDZkNDI3NTY2NjY2NTcyNDE3MDcwNjU2ZTY0MDAwNDAzNjU2ZTc2MDk2ZDQyNzU2NjY2NjU3MjQ1NzEwMDA0MDM2NTZlNzYwZDZkNDI3NTY2NjY2NTcyNDY2OTZlNjk3MzY4MDAwMTAzNjU2ZTc2MjI2ZDYxNmU2MTY3NjU2NDRkNzU2Yzc0Njk1NDcyNjE2ZTczNjY2NTcyNDU1MzQ0NTQ0ZTQ2NTQ0NTc4NjU2Mzc1NzQ2NTAwMGUwMzY1NmU3NjFiNmQ2MTZlNjE2NzY1NjQ0NTc4NjU2Mzc1NzQ2NTRmNmU0NDY1NzM3NDQzNmY2ZTc0NjU3ODc0MDAwZjAzNjU2ZTc2MGQ2ZDYxNmU2MTY3NjU2NDQzNjE2YzZjNjU3MjAwMDYwMzY1NmU3NjEwNmQ2MTZlNjE2NzY1NjQ1MzQzNDE2NDY0NzI2NTczNzMwMDA2MDM2NTZlNzYxMzZkNjE2ZTYxNjc2NTY0NGY3NzZlNjU3MjQxNjQ2NDcyNjU3MzczMDAwNjAzNjU2ZTc2MWM2ZDYxNmU2MTY3NjU2NDQ3NjU3NDRkNzU2Yzc0Njk0NTUzNDQ1NDQzNjE2YzZjNTY2MTZjNzU2NTAwMDYwMzY1NmU3NjEyNmQ0Mjc1NjY2NjY1NzI0NzY1NzQ0MTcyNjc3NTZkNjU2ZTc0MDAwNDAzNjU2ZTc2MTI2ZDQyNzU2NjY2NjU3MjQxNzA3MDY1NmU2NDQyNzk3NDY1NzMwMDA5MDM2NTZlNzYxOTYyNjk2NzQ5NmU3NDQ3NjU3NDU1NmU3MzY5Njc2ZTY1NjQ0MTcyNjc3NTZkNjU2ZTc0MDAwMDAzNjU2ZTc2MWI3MzZkNjE2YzZjNDk2ZTc0NDc2NTc0NTU2ZTczNjk2NzZlNjU2NDQxNzI2Nzc1NmQ2NTZlNzQwMDBjMDM2NTZlNzYxMDZkNDI3NTY2NjY2NTcyNDc2NTc0NGM2NTZlNjc3NDY4MDAwMTAzNjU2ZTc2MGY2NzY1NzQ0ZTc1NmQ0MTcyNjc3NTZkNjU2ZTc0NzMwMDAzMDM2NTZlNzYxNjczNmQ2MTZjNmM0OTZlNzQ0NjY5NmU2OTczNjg1NTZlNzM2OTY3NmU2NTY0MDAxMDAzNjU2ZTc2MDk2MjY5Njc0OTZlNzQ1Mzc1NjIwMDA1MDM2NTZlNzYwYTY3NjU3NDQ3NjE3MzRjNjU2Njc0MDAxMTAzNjU2ZTc2MGY2MzZjNjU2MTZlNTI2NTc0NzU3MjZlNDQ2MTc0NjEwMDAyMDM2NTZlNzYwZjZkNDI3NTY2NjY2NTcyNTM2NTc0NDI3OTc0NjU3MzAwMDkwMzY1NmU3NjA5NjI2OTY3NDk2ZTc0NDM2ZDcwMDAwNDAzNjU2ZTc2MGE2MjY5Njc0OTZlNzQ1NDQ0Njk3NjAwMDUwMzY1NmU3NjA5NjI2OTY3NDk2ZTc0NGQ3NTZjMDAwNTAzNjU2ZTc2MTk2ZDQyNzU2NjY2NjU3MjQ2NzI2ZjZkNDI2OTY3NDk2ZTc0NTU2ZTczNjk2NzZlNjU2NDAwMDQwMzY1NmU3NjE3NmQ0Mjc1NjY2NjY1NzI1NDZmNDI2OTY3NDk2ZTc0NTU2ZTczNjk2NzZlNjU2NDAwMDQwMzY1NmU3NjA5NjI2OTY3NDk2ZTc0NTA2Zjc3MDAwNTAzNjU2ZTc2MTQ2ZDQyNzU2NjY2NjU3MjQzNmY3MDc5NDI3OTc0NjU1MzZjNjk2MzY1MDAwYTAzNjU2ZTc2MTI2ZDQyNzU2NjY2NjU3MjUzNzQ2ZjcyNjE2NzY1NGM2ZjYxNjQwMDA0MDM2NTZlNzYxMzZkNDI3NTY2NjY2NTcyNTM3NDZmNzI2MTY3NjU1Mzc0NmY3MjY1MDAwNDAzNjU2ZTc2MGU2MzY4NjU2MzZiNGU2ZjUwNjE3OTZkNjU2ZTc0MDAwMjAzNjU2ZTc2MTc2ZDYxNmU2MTY3NjU2NDQ3NjU3NDQyNjE2MzZiNTQ3MjYxNmU3MzY2NjU3MjczMDAwMDAzNjU2ZTc2MGY2ZDYxNmU2MTY3NjU2NDU3NzI2OTc0NjU0YzZmNjcwMDAwMDM2NTZlNzYxNDYyNjk2NzQ5NmU3NDQ2Njk2ZTY5NzM2ODU1NmU3MzY5Njc2ZTY1NjQwMDA2MDM2NTZlNzYwNjY2Njk2ZTY5NzM2ODAwMDAwMzY1NmU3NjBhNjI2OTY3NDk2ZTc0NTM2OTY3NmUwMDAxMDM2NTZlNzYxMzZkNDI3NTY2NjY2NTcyNDc2NTc0NDI3OTc0NjU1MzZjNjk2MzY1MDAwYTAzZDMwMWQxMDEwMTAzMDgwMjAxMTIwMTA0MDAwMTA3MDYwNjA2MDAwNDAxMDkwMTAwMDEwMDAwMDAwMDEzMDMwMDE0MDMwMzAzMDIwMzAxMDcwNDAwMDMwOTAxMDkwOTA5MDAwNzA3MDEwMDA2MDYwMTA2MDYwYzA1MDEwODA1MDAwMTBiMDAwODA3MTUwNzA4MDgwMDBhMDAxNjAxMDEwNjAxMDAwMDAwMDUwMDAwMDEwMzAwMDYwMTAwMTcwNTA1MGEwNzA0MDAwNDBhMDAwNDA0MDQwMDA0MDQwNDA0MDQwMTAxMDAwNDBkMDcwNzA3MDgwYTAwMDUwMTAxMDUwNTA2MDEwMTAwMGIwYjAxMDEwMTAxMDEwNTBkMDEwNTAwMDAwMDA1MDUwMDAwMDAwMDAwMGMwNzA3MDcwNzAwMDAwODE4MDMwMzAzMDAwMzAzMDAwMTA0MDcwMzAzMDMwMzAxMDEwMzAzMDMwMzAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwODA4MDUwMzAxMDAwMzA2MTYwMzdmMDE0MTgwODAwODBiN2YwMDQxZTlkYjA4MGI3ZjAwNDFmMGRiMDgwYjA3YzcwNTIwMDY2ZDY1NmQ2ZjcyNzkwMjAwMDQ2OTZlNjk3NDAwZGIwMTA3NzU3MDY3NzI2MTY0NjUwMGRjMDEwNzY0NjU3MDZmNzM2OTc0MDBkZDAxMDg3NzY5NzQ2ODY0NzI2MTc3MDBkZTAxMDg2MzZmNmQ3MDZmNzU2ZTY0MDBkZjAxMGU2NzY1NzQ1NDZmNzQ2MTZjNDE3MzczNjU3NDczMDBlMDAxMGY2NzY1NzQ1NjYxNzU2Yzc0NDE2NDY0NzI2NTczNzMwMGUxMDExNzY3NjU3NDQxNzM3MzY1NzQ1NDZmNmI2NTZlNDk2NDY1NmU3NDY5NjY2OTY1NzIwMGUyMDExZDY3NjU3NDRkNmY2ZTY1Nzk0ZDYxNzI2YjY1NzQ1NDZmNmI2NTZlNDk2NDY1NmU3NDY5NjY2OTY1NzIwMGUzMDEyMjY3NjU3NDRkNmY2ZTY1Nzk0ZDYxNzI2YjY1NzQ1NTZlNjQ2NTcyNmM3OTY5NmU2NzQ5NjQ2NTZlNzQ2OTY2Njk2NTcyMDBlNDAxMWY2NzY1NzQ0MjZmNmY3Mzc0NjU3MjUzNzQ2MTZiNjU2NDU0NmY2YjY1NmU0OTY0NjU2ZTc0Njk2NjY5NjU3MjAwZTUwMTE0Njc2NTc0NDM2ZjZlNzQ3MjZmNmM2YzY1NzI0MTY0NjQ3MjY1NzM3MzAwZTYwMTE1Njc2NTc0NGQ2ZjZlNjU3OTRkNjE3MjZiNjU3NDQxNjQ2NDcyNjU3MzczMDBlNzAxMWQ2NzY1NzQ1NzcyNjE3MDcwNjU2NDQ1Njc2YzY0NDM2ZjZlNzQ3MjYxNjM3NDQxNjQ2NDcyNjU3MzczMDBlODAxMWQ2NzY1NzQ1NzcyNjE3MDcwNjU2NDQ1Njc2YzY0NTQ2ZjZiNjU2ZTQ5NjQ2NTZlNzQ2OTY2Njk2NTcyMDBlOTAxMTE2NzY1NzQ0MjZmNmY3Mzc0NjU3MjQxNjQ2NDcyNjU3MzczMDBlYTAxMTk2NzY1NzQ0MzZmNmQ3MDZmNzU2ZTY0NTg0NTc4NjM2ODYxNmU2NzY1NTM3NzYxNzA3MzAwZWIwMTE3Njc2NTc0NDM2ZjZkNzA2Zjc1NmU2NDQxNzM2ODczNzc2MTcwNTM3NzYxNzA3MzAwZWMwMTE2Njc2NTc0NDM2ZjZkNzA2Zjc1NmU2NDQ2NjU2NTczNTA2NTcyNjM2NTZlNzQwMGVkMDExOTY3NjU3NDUwNjU3MjY2NmY3MjZkNjE2ZTYzNjU0NjY1NjU3MzUwNjU3MjYzNjU2ZTc0MDBlZTAxMGU3Mzc0NjE2YjY1NDk2ZTQyNmY2ZjczNzQ2NTcyMDBlZjAxMWI3MjY1NjI2MTZjNjE2ZTYzNjU1MDZmNzI3NDY2NmY2YzY5NmY0OTZlNDI2ZjZmNzM3NDY1NzIwMGYwMDExMjc1NmU3Mzc0NjE2YjY1NDY3MjZmNmQ0MjZmNmY3Mzc0NjU3MjAwZjEwMTE4NjM2YzYxNjk2ZDRkNzU2Yzc0Njk3MDZjNjU0NjcyNmY2ZDQyNmY2ZjczNzQ2NTcyMDBmMjAxMTk3MzY1NzQ1MDY1NzI2NjZmNzI2ZDYxNmU2MzY1NDY2NTY1NzM1MDY1NzI2MzY1NmU3NDAwZjMwMTE2NzM2NTc0NDM2ZjZkNzA2Zjc1NmU2NDQ2NjU2NTczNTA2NTcyNjM2NTZlNzQwMGY0MDExMDczNjU3NDQzNmY2ZDcwNmY3NTZlNjQ1Mzc3NjE3MDczMDBmNTAxMGQ2NzY1NzQ0ZTYxNzQ3NTcyNjE2YzQxNTA1OTAwZjYwMTA4NjM2MTZjNmM0MjYxNjM2YjAwZjcwMTBhNWY1ZjY0NjE3NDYxNWY2NTZlNjQwMzAxMGI1ZjVmNjg2NTYxNzA1ZjYyNjE3MzY1MDMwMjBhOWFhOTAxZDEwMTE2MDEwMTdmMTAyYTIyMDE0MjAwMTAwMTIwMDEyMDAxMjAwMDEwMDIyMDAxMGIxOTAxMDE3ZjQxYzg4ZDA4NDFjODhkMDgyODAyMDA0MTAxNmIyMjAwMzYwMjAwMjAwMDBiMmUwMDAyNDAyMDAxMjAwMjRkMDQ0MDIwMDIyMDA0NGQwZDAxMTAyYzAwMGIxMDJjMDAwYjIwMDAyMDAyMjAwMTZiMzYwMjA0MjAwMDIwMDEyMDAzNmEzNjAyMDAwYjBiMDA0MWI4OGQwODQxMGUxMDAzMDAwYjEzMDEwMTdmMTAyYTIyMDEyMDAwYWQ0MmZmMDE4MzEwMDEyMDAxMGIyMTAxMDE3ZjEwMmEyMTAxMjAwMDQyMDA1MzA0NDA0MWIyODUwODQxMTExMDAzMDAwYjIwMDEyMDAwMTAwMTIwMDEwYjBmMDEwMTdmMTAwNDIyMDEyMDAwMTAwNTFhMjAwMTBiMGIwMDIwMDAyMDAxMTAwNjQxMDA0YTBiMmQwMTAxN2YyMzAwNDEyMDZiMjIwMjI0MDAyMDAyMjAwMDEwMzI0MWMwODAwODQxMDgxMDMzMjAwMjIwMDEzNjAyMTgyMDAyMTAzNDIwMDI0MTIwNmEyNDAwMGIxOTAwMjAwMDQxZmVmZmZmZmYwNzQ2MDQ0MDQxYzg4MDA4NDExOTEwMDMwMDBiMjAwMDBiMmEwMDIwMDIyMDAzMTA0ZDIxMDIxMDQzMjEwMzIwMDA0MjdmMzcwMzA4MjAwMDIwMDMzNjAyMDQyMDAwMjAwMjM2MDIwMDIwMDAyMDAxMzYwMjEwMGI3ZDAxMDM3ZjIzMDA0MTEwNmIyMjAxMjQwMDIwMDAyOTAzMDgxMDcxMjAwMDI4MDIxMDIwMDAyODAyMTgyMDAwMjgwMjAwMjAwMDI4MDIwNDEwNDUyMTAyMTAxNzQxMDAyMTAwMjAwMjEwMTIyMTAzMjAwMTQxMDAzNjAyMGMyMDAxMjAwMjM2MDIwNDIwMDEyMDAzNDEwMjc2MjIwMjM2MDIwODAzNDAyMDAwMjAwMjRmNDUwNDQwMjAwMTQxMDQ2YTEwNzUxYTIwMDEyODAyMDgyMTAyMjAwMTI4MDIwYzIxMDAwYzAxMGIwYjIwMDE0MTEwNmEyNDAwMGIzNjAxMDI3ZjIzMDA0MTEwNmIyMjAxMjQwMDIwMDE0MTA4NmExMDM2MjAwMTI4MDIwODIxMDIyMDAwMjAwMTJkMDAwYzQxMDE3MTNhMDAwNDIwMDAyMDAyMzYwMjAwMjAwMTQxMTA2YTI0MDAwYjZkMDEwMjdmMjMwMDQxMTA2YjIyMDEyNDAwMjAwMDAyN2Y0MWUwZGIwODJkMDAwMDIyMDI0NTA0NDA0MWUwZGIwODQxMDEzYTAwMDA0MWRjZGIwODQxMDAzNjAyMDAyMDAxNDEwODZhNDEwMDEwOWYwMTIwMDEyODAyMDgyMDAxMjgwMjBjNDFiODhkMDg0MTAwMTA1NzEwNDMwYzAxMGI0MWI4OGQwODQxMDAxMDRkMGIzNjAyMDAyMDAwMjAwMjQxMDE3MzNhMDAwNDIwMDE0MTEwNmEyNDAwMGIwYjAwMjAwMDIwMDExMDM4MTAwNzFhMGI0OTAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAxM2EwMDBjMjAwMjIwMDAzNjAyMDgyMDAyNDEwODZhMTBhNTAxMjAwMjI4MDIwODIwMDIyZDAwMGMwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAyNDExMDZhMjQwMDBiMGUwMDIwMDA0MThhODUwODQxMGIxMDNhMTAzYjBiMTMwMDIwMDAyMDAwMjAwMTIwMDIxMDUyMjAwMTIwMDIxMDg1MDEwYjBkMDAyMDAwMTAyYTIyMDAxMDFkMWEyMDAwMGIwYTAwMjAwMDEwM2QyMDAxMTAzZTBiMGYwMTAxN2YxMDJhMjIwMTIwMDAxMDFjMWEyMDAxMGI1MTAxMDI3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAwMTAxMjIyMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwYzIwMDEyMDAyNDEwYzZhNDEwNDEwYTMwMTIwMDEyMDAwMTBiZDAxMjAwMjQxMTA2YTI0MDAwYjBhMDAyMDAwMTAzZDIwMDExMDQwMGI1MTAxMDI3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAwMTAxMjIyMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwYzIwMDEyMDAyNDEwYzZhNDEwNDEwMGYxYTIwMDEyMDAwMTA4YjAxMjAwMjQxMTA2YTI0MDAwYjA5MDAyMDAwMjAwMTEwMDMwMDBiNTAwMTA0N2YxMDQzMjEwNjEwNDMyMTA3MjMwMDQxMTA2YjIyMDQyNDAwMTA0MzIxMDUyMDAxMTAyZjIxMDEyMDA0MjAwMzEwMjkzNjAyMGMyMDA0MjAwMjM3MDMwMDIwMDQyMDAxMzYwMjA4MjAwNTIwMDQxMDQ0MjAwMDIwMDU0MjAwMjAwNjIwMDcxMDA4MWEyMDA0NDExMDZhMjQwMDBiMTMwMTAxN2YxMDJhMjIwMDQxYjg4ZDA4NDEwMDEwMTgxYTIwMDAwYmQyMDEwMjAyN2YwMTdlMjMwMDQxMTA2YjIyMDMyNDAwMjAwMzIwMDEyODAyMDgyMjAyNDExODc0MjAwMjQxODBmZTAzNzE0MTA4NzQ3MjIwMDI0MTA4NzY0MTgwZmUwMzcxMjAwMjQxMTg3NjcyNzIzNjAyMDAyMDAzMjAwMTI4MDIwYzIyMDI0MTE4NzQyMDAyNDE4MGZlMDM3MTQxMDg3NDcyMjAwMjQxMDg3NjQxODBmZTAzNzEyMDAyNDExODc2NzI3MjM2MDIwYzIwMDMyMDAxMjkwMzAwMjIwNDQyMzg4NjIwMDQ0MjgwZmUwMzgzNDIyODg2ODQyMDA0NDI4MDgwZmMwNzgzNDIxODg2MjAwNDQyODA4MDgwZjgwZjgzNDIwODg2ODQ4NDIwMDQ0MjA4ODg0MjgwODA4MGY4MGY4MzIwMDQ0MjE4ODg0MjgwODBmYzA3ODM4NDIwMDQ0MjI4ODg0MjgwZmUwMzgzMjAwNDQyMzg4ODg0ODQ4NDM3MDIwNDIwMDAyMDAzNDExMDEwMGYxYTIwMDM0MTEwNmEyNDAwMGIxNTAwMjAwMDIwMDEyMDAyMjAwMzIwMDQxMDJhMjIwMTEwMDkxYTIwMDEwYjBjMDEwMTdmMTAyYTIyMDAxMDBhMjAwMDBiMGMwMTAxN2YxMDJhMjIwMDEwMGIyMDAwMGIwYzAxMDE3ZjEwMmEyMjAwMTAwYzIwMDAwYjE1MDAxMDQ4MTA0NjEwMzAwNDQwMGYwYjQxOTI4ZDA4NDEyNDEwMDMwMDBiMmIwMTAxN2Y0MWU4ZGIwODJkMDAwMDIyMDAwNDQwNDE2YjQxZmZmZmZmZmYwNzIwMDAxYjBmMGI0MWU4ZGIwODQxMDEzYTAwMDA0MTZiMTAwZDQxNmIwYjBkMDAyMDAwMTAyYTIyMDAxMDBlMWEyMDAwMGIyZTAxMDE3ZjQxZDU4MzA4NDExNzEwNGQyMjA0MjAwMDIwMDExMDBmMWEyMDA0NDFlYzgzMDg0MTAzMTAwZjFhMjAwNDIwMDIyMDAzMTAwZjFhMjAwNDEwMDAwMDBiMTEwMTAxN2YxMDJhMjIwMjIwMDAyMDAxMTAxODFhMjAwMjBiNDYwMTAxN2YyMzAwNDExMDZiMjIwMjI0MDAyMDAyMjAwMTQxMTg3NDIwMDE0MTgwZmUwMzcxNDEwODc0NzIyMDAxNDEwODc2NDE4MGZlMDM3MTIwMDE0MTE4NzY3MjcyMzYwMjBjMjAwMDIwMDI0MTBjNmE0MTA0MTAwZjFhMjAwMjQxMTA2YTI0MDAwYjBlMDEwMTdmNDEwMDEwMmEyMjAwMTAxMDIwMDAwYjFmMDAyMDAwMTA0YjIyMDAxMDEyNDEyMDQ3MDQ0MDIwMDEyMDAyNDFiMDg2MDg0MTEwMTA0YzAwMGIyMDAwMGJkOTAzMDEwOTdmMjMwMDQxNDA2YTIyMDEyNDAwMjAwMDEwNGIyMTAyMTA0MzIxMDYyMDAyMTAxMjIxMDAyMDAxNDEyNDZhNDEwMDNhMDAwMDIwMDE0MTIwNmEyMDAwMzYwMjAwMjAwMTIwMDIzNjAyMWMyMDAxMjAwMDM2MDIxODIwMDE0MTAwMzYwMjE0NDEwMDIxMDIwMzdmMjAwMDIwMDI0NjA0N2YyMDAxMmQwMDI0MDQ0MDQxZGNkYjA4NDEwMDM2MDIwMDQxZTBkYjA4NDEwMDNhMDAwMDBiMjAwMTQxNDA2YjI0MDAyMDA2MDUyMDAxNDExNDZhMjIwMDQxOTc4NzA4NDExNjEwM2EyMTA0MjAwMDQxOTc4NzA4NDExNjEwNTIyMTAwMTA0MzIxMDMwMzQwMjAwMDA0NDAyMDAxNDExNDZhMjIwNTQxOTc4NzA4NDExNjEwNTIyMTA3MjAwNTQxOTc4NzA4NDExNjEwNTMyMTA4MjAwNTQxOTc4NzA4NDExNjEwM2EyMTA5NDEwMDIxMDIwMjQwMDI0MDAyNDAyMDA1NDE5Nzg3MDg0MTE2MTA1NDQxZmYwMTcxMGUwMjAyMDEwMDBiNDE5Nzg3MDg0MTE2NDFlZDg2MDg0MTBkMTA0YzAwMGI0MTAxMjEwMjBiMjAwMTIwMDIzYTAwMzQyMDAxMjAwOTM2MDIzMDIwMDEyMDA4MzYwMjJjMjAwMTIwMDczNjAyMjgyMDAzMjAwMTQxMjg2YTEwNTUyMDAwNDEwMTZiMjEwMDBjMDEwYjBiMjAwMTQyMDAzNzAzMjgyMDAxMjAwNDQxMTg3NDIwMDQ0MTgwZmUwMzcxNDEwODc0NzIyMDA0NDEwODc2NDE4MGZlMDM3MTIwMDQ0MTE4NzY3MjcyMzYwMjNjMjAwMTQxMDg2YTIwMDE0MTI4NmEyMjAwNDEwMDQxMDQxMDU2MjAwMTI4MDIwODIwMDEyODAyMGMyMDAxNDEzYzZhMjIwMjQxMDQxMDU3MjAwMTIwMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIzYzIwMDEyMDAwNDEwNDQxMDgxMDU2MjAwMTI4MDIwMDIwMDEyODAyMDQyMDAyNDEwNDEwNTcyMDA2MjAwMDQxMDgxMDBmMWEyMDAxMjgwMjE0MjEwMjIwMDEyODAyMTgyMTAwMGMwMTBiMGIwYjM3MDIwMTdmMDE3ZTIzMDA0MTEwNmIyMjAzMjQwMDIwMDM0MTAwMzYwMjBjMjAwMDIwMDM0MTBjNmEyMjAwNDEwNDIwMDEyMDAyMTBjNTAxMjAwMDQxMDQxMGIxMDEyMDAzNDExMDZhMjQwMGE3MGIwZDAwMjAwMDQxMjAyMDAxMjAwMjEwODUwMTBiMzAwMTAxN2YyMzAwNDExMDZiMjIwMzI0MDAyMDAzNDEwMDNhMDAwZjIwMDAyMDAzNDEwZjZhNDEwMTIwMDEyMDAyMTBjNTAxMjAwMzJkMDAwZjIwMDM0MTEwNmEyNDAwMGJmNjAyMDEwNTdmMjMwMDQxZDAwMDZiMjIwMjI0MDAyMDAyNDIwMDM3MDAzNTIwMDI0MjAwMzcwMzMwMjAwMjIwMDEyODAyMDAyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyNDAyMDAyNDEyODZhMjAwMjQxMzA2YTIyMDU0MTAwNDEwNDEwOWIwMTIwMDIyODAyMjgyMDAyMjgwMjJjMjAwMjQxNDA2YjIyMDQ0MTA0MTA1NzIwMDI0MWM4MDA2YTQxMDAzYTAwMDAyMDAyNDIwMDM3MDM0MDIwMDIyMDAxMjgwMjA0MjIwMzQxMTg3NDIwMDM0MTgwZmUwMzcxNDEwODc0NzIyMDAzNDEwODc2NDE4MGZlMDM3MTIwMDM0MTE4NzY3MjcyMzYwMjRjMjAwMjQxMjA2YTIwMDQ0MTAwNDEwNDEwOWMwMTIwMDIyODAyMjAyMDAyMjgwMjI0MjAwMjQxY2MwMDZhMjIwNjQxMDQxMDU3MjAwMjIwMDE0MTA4NmEyODAyMDAyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyNGMyMDAyNDExODZhMjAwNDQxMDQ0MTA4MTA5YzAxMjAwMjI4MDIxODIwMDIyODAyMWMyMDA2NDEwNDEwNTcyMDAyMjAwMTQxMGM2YTJkMDAwMDNhMDA0YzIwMDI0MTEwNmEyMDA0NDEwODQxMDkxMDljMDEyMDAyMjgwMjEwMjAwMjI4MDIxNDIwMDY0MTAxMTA1NzIwMDI0MTA4NmEyMDA1NDEwNDQxMGQxMDliMDEyMDAyMjgwMjA4MjAwMjI4MDIwYzIwMDQ0MTA5MTA1NzIwMDAyMDA1NDEwZDEwMGYxYTIwMDI0MWQwMDA2YTI0MDAwYjBmMDAyMDAwMjAwMTIwMDIyMDAzNDEwODEwZjkwMTBiYjUwMjAxMDY3ZjIwMDEyMDAzNDYwNDQwMjAwMTIyMDM0MTEwNGYwNDQwMjAwMDQxMDAyMDAwNmI0MTAzNzEyMjA0NmEyMTA1MjAwNDA0NDAyMDAyMjEwMTAzNDAyMDAwMjAwMTJkMDAwMDNhMDAwMDIwMDE0MTAxNmEyMTAxMjAwMDQxMDE2YTIyMDAyMDA1NDkwZDAwMGIwYjIwMDUyMDAzMjAwNDZiMjIwMzQxN2M3MTIyMDY2YTIxMDAwMjQwMjAwMjIwMDQ2YTIyMDQ0MTAzNzEwNDQwMjAwNjQxMDA0YzBkMDEyMDA0NDEwMzc0MjIwMTQxMTg3MTIxMDcyMDA0NDE3YzcxMjIwODQxMDQ2YTIxMDI0MTAwMjAwMTZiNDExODcxMjEwOTIwMDgyODAyMDAyMTAxMDM0MDIwMDUyMDAxMjAwNzc2MjAwMjI4MDIwMDIyMDEyMDA5NzQ3MjM2MDIwMDIwMDI0MTA0NmEyMTAyMjAwNTQxMDQ2YTIyMDUyMDAwNDkwZDAwMGIwYzAxMGIyMDA2NDEwMDRjMGQwMDIwMDQyMTAyMDM0MDIwMDUyMDAyMjgwMjAwMzYwMjAwMjAwMjQxMDQ2YTIxMDIyMDA1NDEwNDZhMjIwNTIwMDA0OTBkMDAwYjBiMjAwMzQxMDM3MTIxMDMyMDA0MjAwNjZhMjEwMjBiMjAwMzA0NDAyMDAwMjAwMzZhMjEwMTAzNDAyMDAwMjAwMjJkMDAwMDNhMDAwMDIwMDI0MTAxNmEyMTAyMjAwMDQxMDE2YTIyMDAyMDAxNDkwZDAwMGIwYjBmMGIxMDJjMDAwYmEyMDMwMTA3N2YyMzAwNDE0MDZhMjIwMTI0MDAyMDAwMTA0YjIxMDIxMDQzMjEwNTIwMDIxMDEyMjEwMDIwMDE0MTJjNmE0MTAwM2EwMDAwMjAwMTQxMjg2YTIwMDAzNjAyMDAyMDAxMjAwMjM2MDIyNDIwMDEyMDAwMzYwMjIwMjAwMTQxMDAzNjAyMWM0MTAwMjEwMjAzN2YyMDAwMjAwMjQ2MDQ3ZjIwMDEyZDAwMmMwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAxNDE0MDZiMjQwMDIwMDUwNTIwMDE0MTFjNmEyMjAwNDFhZDg3MDg0MTE4MTAzYTIxMDMyMDAwNDFhZDg3MDg0MTE4MTA1MjIxMDAxMDQzMjEwMjAzNDAyMDAwMDQ0MDIwMDE0MTFjNmEyMjA0NDFhZDg3MDg0MTE4MTA1MjIxMDYyMDA0NDFhZDg3MDg0MTE4MTA1MzIxMDcyMDA0NDFhZDg3MDg0MTE4MTAzYTIxMDQyMDAxMjAwNjM2MDIzODIwMDEyMDA0MzYwMjM0MjAwMTIwMDczNjAyMzAyMDAyMjAwMTQxMzA2YTEwNTkyMDAwNDEwMTZiMjEwMDBjMDEwYjBiMjAwMTQyMDAzNzAzMzAyMDAxMjAwMzQxMTg3NDIwMDM0MTgwZmUwMzcxNDEwODc0NzIyMDAzNDEwODc2NDE4MGZlMDM3MTIwMDM0MTE4NzY3MjcyMzYwMjNjMjAwMTQxMTA2YTIwMDE0MTMwNmEyMjAwNDEwMDQxMDQxMDU2MjAwMTI4MDIxMDIwMDEyODAyMTQyMDAxNDEzYzZhMjIwMzQxMDQxMDU3MjAwMTIwMDI0MTE4NzQyMDAyNDE4MGZlMDM3MTQxMDg3NDcyMjAwMjQxMDg3NjQxODBmZTAzNzEyMDAyNDExODc2NzI3MjM2MDIzYzIwMDE0MTA4NmEyMDAwNDEwNDQxMDgxMDU2MjAwMTI4MDIwODIwMDEyODAyMGMyMDAzNDEwNDEwNTcyMDA1MjAwMDQxMDgxMDBmMWEyMDAxMjgwMjFjMjEwMjIwMDEyODAyMjAyMTAwMGMwMTBiMGIwYmI4MDIwMTA0N2YyMzAwNDE0MDZhMjIwMjI0MDAyMDAyNDEyODZhNDEwMDM2MDIwMDIwMDI0MjAwMzcwMzIwMjAwMjIwMDEyODAyMDgyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyMzAyMDAyNDExODZhMjAwMjQxMjA2YTIyMDU0MTAwNDEwNDEwOWEwMTIwMDIyODAyMTgyMDAyMjgwMjFjMjAwMjQxMzA2YTIyMDQ0MTA0MTA1NzIwMDI0MjAwMzcwMzMwMjAwMjIwMDEyODAyMDAyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyM2MyMDAyNDExMDZhMjAwNDQxMDA0MTA0MTA1NjIwMDIyODAyMTAyMDAyMjgwMjE0MjAwMjQxM2M2YTIyMDM0MTA0MTA1NzIwMDIyMDAxMjgwMjA0MjIwMTQxMTg3NDIwMDE0MTgwZmUwMzcxNDEwODc0NzIyMDAxNDEwODc2NDE4MGZlMDM3MTIwMDE0MTE4NzY3MjcyMzYwMjNjMjAwMjQxMDg2YTIwMDQ0MTA0NDEwODEwNTYyMDAyMjgwMjA4MjAwMjI4MDIwYzIwMDM0MTA0MTA1NzIwMDIyMDA1NDEwNDQxMGMxMDlhMDEyMDAyMjgwMjAwMjAwMjI4MDIwNDIwMDQ0MTA4MTA1NzIwMDAyMDA1NDEwYzEwMGYxYTIwMDI0MTQwNmIyNDAwMGIxNDAwMTAxMzIwMDA0NjA0NDAwZjBiNDE5Mjg0MDg0MTE5MTAwMzAwMGIwOTAwMjAwMDEwNWMxMDA3MWEwYjFkMDAyMDAwMTBhNzAxMjIwMDEwMTI0MTIwNDcwNDQwNDFiMDg2MDg0MTEwMTA4ODAxMDAwYjIwMDAwYjBhMDAyMDAwMTBhNzAxMTAwNzFhMGIwODAwMjAwMDEwNWYxMDE0MGI2MTAyMDI3ZjAxN2UyMzAwNDExMDZiMjIwMTI0MDAyMDAxNDIwMDM3MDMwODIwMDAxMGE3MDEyMjAwMTAxMjIyMDI0MTA5NGYwNDQwNDE5NTg1MDg0MTBlMTA4ODAxMDAwYjIwMDEyMDAxNDEwODZhMjAwMjEwYjAwMTIwMDA0MTAwMjAwMTI4MDIwMDIyMDAyMDAxMjgwMjA0MjIwMjEwOGEwMTFhMjAwMDIwMDIxMGIxMDEyMDAxNDExMDZhMjQwMDBiMWYwMDIwMDAyMDAxMjAwMjEwMTUyMDAwMTA2MTQxZmYwMTcxMDQ0MDBmMGI0MWFiODQwODQxMzAxMDAzMDAwYjE1MDA0MTAyNDEwMTIwMDAxMDI3MjIwMDFiNDEwMDIwMDA0MTAwNGUxYjBiZjgwMTAxMDQ3ZjIzMDA0MWQwMDA2YjIyMDUyNDAwMjAwNTIwMDQzNjAyMjgyMDA1NDEyMDZhNDFkYjg0MDg0MTE0MTA2MzIwMDUyODAyMjAyMTA3MjAwNTI4MDIyNDIyMDYyMDAzMTA2NDIwMDQxMDY1MjEwMzEwNDMyMjA4MjAwM2FkMTA2NjIwMDYyMDA4MTA0ZTIwMDUyMDA0MTAxMjM2MDIzNDIwMDU0MTAwMzYwMjMwMjAwNTIwMDU0MTI4NmEzNjAyMmMwMzQwMjAwNTQxMzg2YTIwMDU0MTJjNmExMDY3MjAwNTI5MDMzODUwMDQ0MDIwMDUyMDA3MjAwNjIwMDEyMDAyMTA2ODIwMDUyODAyMDQyMTAxMjAwMDIwMDUyODAyMDAzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MWQwMDA2YTI0MDAwNTIwMDUyODAyNGMyMTAzMjAwNTQxMTg2YTIwMDcyMDA2MjAwNTI4MDI0ODEwNjkyMDA1NDExMDZhMjAwNTI4MDIxODIwMDUyODAyMWMyMDA1MjkwMzQwMTA2YTIwMDU0MTA4NmEyMDA1MjgwMjEwMjAwNTI4MDIxNDIwMDMxMDZiMjAwNTI4MDIwYzIxMDYyMDA1MjgwMjA4MjEwNzBjMDEwYjBiMGIxODAwMjAwMTIwMDIxMDRkMjEwMTIwMDAxMDQzMzYwMjA0MjAwMDIwMDEzNjAyMDAwYjEwMDAxMDQzMWEyMDAwMjAwMTI4MDIwMDEwMmYxMDRlMGIwOTAwMjAwMDEwMTI0MTA0NzYwYjM4MDEwMTdmMjMwMDQxMTA2YjIyMDIyNDAwMjAwMjQyMDAzNzAzMDgyMDAyMjAwMTQxMDAyMDAyNDEwODZhMTA4MjAxMjAwMDIwMDIyODAyMDAyMDAyMjgwMjA0MTAxODFhMjAwMjQxMTA2YTI0MDAwYmE3MDEwMjA1N2YwMTdlMjMwMDQxMjA2YjIyMDIyNDAwMjAwMDIwMDEyODAyMDQyMjA0NDExMDZhMjIwNTIwMDEyODAyMDg0ZDA0N2UyMDAxMjgwMjAwMjAwMjQxMTA2YTQyMDAzNzAzMDAyMDAyNDIwMDM3MDMwODI4MDIwMDIwMDQyMDAyNDEwODZhMjIwMzQxMTAxMDZmMWEyMDAyNDEwMDM2MDIxYzIwMDMyMDAyNDExYzZhMjIwNjEwOTgwMTIxMDQyMDAzMjAwNjEwOTkwMTIxMDcyMDAwNDExNDZhMjAwMjQxMDg2YTIwMDI0MTFjNmExMDk4MDEzNjAyMDAyMDAwNDExMDZhMjAwNDM2MDIwMDIwMDAyMDA3MzcwMzA4MjAwMTIwMDUzNjAyMDQ0MjAxMDU0MjAwMGIzNzAzMDAyMDAyNDEyMDZhMjQwMDBiOTEwMTAxMDM3ZjIzMDA0MTEwNmIyMjA1MjQwMDAyNDAyMDAzMTAxMjQ1MGQwMDIwMDIyMDAzMTA2ZTIwMDQxMDEyMjEwNjQxMDAyMTAzMDM0MDIwMDM0MTA0NmEyMjA3MjAwNjRiMGQwMTIwMDU0MTAwMzYwMjBjMjAwNDIwMDMyMDA1NDEwYzZhNDEwNDEwNmYxYTIwMDIyMDA1MjgwMjBjMjIwMzQxMTg3NDIwMDM0MTgwZmUwMzcxNDEwODc0NzIyMDAzNDEwODc2NDE4MGZlMDM3MTIwMDM0MTE4NzY3MjcyMTA2ZTIwMDcyMTAzMGMwMDBiMDAwYjIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAyMDA1NDExMDZhMjQwMDBiMTYwMDIwMDIyMDAzMTA2ZTIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAwYjIwMDEwMTdmMTA0MzIyMDQyMDAzMTA2NjIwMDIyMDA0MTA0ZTIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAwYjE2MDAyMDAzMjAwMjEwNzAyMDAwMjAwMjM2MDIwNDIwMDAyMDAxMzYwMjAwMGJhMzAxMDEwMjdmMjMwMDQxMzA2YjIyMDUyNDAwMjAwNTQxMjg2YTQxZWY4NDA4NDEwZjEwNjMyMDA1NDEyMDZhMjAwNTI4MDIyODIwMDUyODAyMmMyMDA0MjgwMjA4MTA2OTIwMDU0MTE4NmEyMDA1MjgwMjIwMjAwNTI4MDIyNDIwMDQyOTAzMDAxMDZhMjAwNTQxMTA2YTIwMDUyODAyMTgyMDA1MjgwMjFjMjAwNDI4MDIwYzEwNmIyMDA1MjgwMjEwMjEwNDIwMDUyODAyMTQyMTA2MTA0MzFhMjAwNjIwMDMxMDJmMTA0ZTIwMDU0MTA4NmEyMDA0MjAwNjIwMDEyMDAyMTA2ODIwMDUyODAyMGMyMTAxMjAwMDIwMDUyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTMwNmEyNDAwMGI3MTAxMDE3ZjIzMDA0MTIwNmIyMjA1MjQwMDIwMDU0MTE4NmE0MWZlODQwODQxMGMxMDYzMjAwNTQxMTA2YTIwMDUyODAyMTgyMDA1MjgwMjFjMjAwMzEwNjkyMDA1NDEwODZhMjAwNTI4MDIxMDIwMDUyODAyMTQyMDA0MTA2YjIwMDUyMDA1MjgwMjA4MjAwNTI4MDIwYzIwMDEyMDAyMTA2ODIwMDUyODAyMDQyMTAxMjAwMDIwMDUyODAyMDAzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTIwNmEyNDAwMGIwZDAwMTA0MzFhMjAwMDIwMDExMDJmMTA0ZTBiMGQwMDIwMDAyMDAxMjAwMjIwMDMxMDhhMDEwYjBkMDAxMDQzMWEyMDAxMjAwMDEwM2QxMDRlMGIwZjAwMjAwMDQyN2Y1MTA0N2UxMDE2MDUyMDAwMGIwYjMwMDEwMTdlMjAwMDI5MDMwODIyMDE0MjdmNTEwNDdlMTAxNjA1MjAwMTBiMjAwMDI4MDIxMDIwMDAyODAyMTgyMDAwMjgwMjAwMjAwMDI4MDIwNDEwNDUxMDE3MTA3MzBiM2IwMTAyN2YyMzAwNDExMDZiMjIwMTI0MDAyMDAwMTAxMjIxMDIyMDAxNDEwMDM2MDIwYzIwMDEyMDAwMzYwMjA0MjAwMTIwMDI0MTAyNzYzNjAyMDgyMDAxNDEwNDZhMTA3NTEwM2IyMDAxNDExMDZhMjQwMDBiMjQwMDIwMDAyOTAzMDgxMDcxMjAwMDI4MDIxMDIwMDAyODAyMTgyMDAwMjgwMjAwMjAwMDI4MDIwNDEwNDUxMDE3MTAxMjFhMGI3ZDAxMDM3ZjIzMDA0MTEwNmIyMjAxMjQwMDIwMDAyODAyMDgyMTAzMjAwMTQxMDAzNjAyMGMyMDAwMjgwMjAwMjAwMzQxMDI3NDIwMDE0MTBjNmE0MTA0MTA2ZjQ1MDQ0MDIwMDEyODAyMGMyMTAyMjAwMDIwMDM0MTAxNmEzNjAyMDgyMDAyNDExODc0MjAwMjQxODBmZTAzNzE0MTA4NzQ3MjIwMDI0MTA4NzY0MTgwZmUwMzcxMjAwMjQxMTg3NjcyNzIxMDJmMjAwMTQxMTA2YTI0MDAwZjBiNDE4YTg1MDg0MTBiNDFlZjgzMDg0MTExMTA0YzAwMGI5MDAyMDIwMjdmMDE3ZTIzMDA0MWQwMDA2YjIyMDIyNDAwMjAwMTI5MDMwODIyMDQ0MjdmNTEwNDdlMTAxNjA1MjAwNDBiMjAwMTI4MDIxMDIwMDEyODAyMTgyMDAxMjgwMjAwMjAwMTI4MDIwNDEwNDUyMTAxMTAxNzIwMDExMDEyMjEwMzIwMDI0MTAwMzYwMjE0MjAwMjIwMDEzNjAyMGMyMDAyMjAwMzQxMDI3NjM2MDIxMDIwMDI0MTBjNmExMDc1MjIwMzEwMTIyMTAxMjAwMjQxM2M2YTQxMDAzYTAwMDAyMDAyNDEzODZhMjAwMTM2MDIwMDIwMDIyMDAzMzYwMjM0MjAwMjIwMDEzNjAyMzAyMDAyNDEwMDM2MDIyYzIwMDI0MTQwNmIyMDAyNDEyYzZhMTA3NzIwMDIyODAyMzAyMDAyMjgwMjJjNDYwNDQwMjAwMjQxMjA2YTIyMDEyMDAyNDFjODAwNmEyOTAzMDAzNzAzMDAyMDAyMjAwMjI5MDM0MDM3MDMxODIwMDIyZDAwM2MwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAwMjAwMjI5MDMxODM3MDMwMDIwMDA0MTA4NmEyMDAxMjkwMzAwMzcwMzAwMjAwMjQxZDAwMDZhMjQwMDBmMGI0MThhODUwODQxMGI0MTk1ODUwODQxMGUxMDRjMDAwYjMwMDIwMTdmMDE3ZTIwMDE0MThhODUwODQxMGIxMDNhMjEwMjIwMDExMGJlMDEyMTAzMjAwMDIwMDExMDM5MzYwMjBjMjAwMDIwMDIzNjAyMDgyMDAwMjAwMzM3MDMwMDBiMTAwMDEwNDMxYTIwMDAyMDAxMjgwMjAwMTAzZDEwNGUwYjBlMDAyMDAxNDUwNDQwMjAwMjIwMDAxMDcwMGIwYjgxMDEwMTA1N2YyMzAwNDExMDZiMjIwMzI0MDAxMDQzMTAyZjIxMDQyMDAxMjgwMjAwMTAxMjIxMDUwMzQwMjAwNTIwMDI0MTA0NmEyMjA2NGYwNDQwMjAwMzQxMDAzNjAyMGMyMDAxMjgwMjAwMjAwMjIwMDM0MTBjNmE0MTA0MTA2ZjFhMjAwMzI4MDIwYzIyMDI0MTE4NzQyMDAyNDE4MGZlMDM3MTQxMDg3NDcyMjAwMjQxMDg3NjQxODBmZTAzNzEyMDAyNDExODc2NzI3MjIwMDQxMDNmMjAwNjIxMDIwYzAxMGIwYjIwMDAyMDA0MTA0ZTIwMDM0MTEwNmEyNDAwMGI4MjAxMDEwNTdmMjMwMDQxMTA2YjIyMDMyNDAwMTA0MzEwMmYyMTA0MjAwMTI4MDIwMDEwMTIyMTA1MDM0MDIwMDUyMDAyNDEwNDZhMjIwNjRmMDQ0MDIwMDM0MTAwMzYwMjBjMjAwMTI4MDIwMDIwMDIyMDAzNDEwYzZhNDEwNDEwNmYxYTIwMDQyMDAzMjgwMjBjMjIwMjQxMTg3NDIwMDI0MTgwZmUwMzcxNDEwODc0NzIyMDAyNDEwODc2NDE4MGZlMDM3MTIwMDI0MTE4NzY3MjcyMTAwNTFhMjAwNjIxMDIwYzAxMGIwYjIwMDAyMDA0MTA0ZTIwMDM0MTEwNmEyNDAwMGI0ZDAxMDI3ZjIzMDA0MTIwNmIyMjAxMjQwMDEwN2QyMTAyMjAwMTQxMTA2YTIwMDA0MTEwNmEyOTAzMDAzNzAzMDAyMDAxNDEwODZhMjAwMDQxMDg2YTI5MDMwMDM3MDMwMDIwMDEyMDAyMzYwMjE4MjAwMTIwMDAyOTAzMDAzNzAzMDAyMDAxMTA3MjIwMDE0MTIwNmEyNDAwMGIwZTAxMDE3ZjEwMmEyMjAwNDIwMDEwMDEyMDAwMGI0ZjAxMDI3ZjIzMDA0MTIwNmIyMjAyMjQwMDEwN2QyMTAzMjAwMjQxMTA2YTIwMDE0MTEwNmEyOTAzMDAzNzAzMDAyMDAyNDEwODZhMjAwMTQxMDg2YTI5MDMwMDM3MDMwMDIwMDIyMDAzMzYwMjE4MjAwMjIwMDEyOTAzMDAzNzAzMDAyMDAwMjAwMjEwNzYyMDAyNDEyMDZhMjQwMDBiNGQwMTAyN2YyMzAwNDEyMDZiMjIwMTI0MDAxMDdkMjEwMjIwMDE0MTEwNmEyMDAwNDExMDZhMjkwMzAwMzcwMzAwMjAwMTQxMDg2YTIwMDA0MTA4NmEyOTAzMDAzNzAzMDAyMDAxMjAwMjM2MDIxODIwMDEyMDAwMjkwMzAwMzcwMzAwMjAwMTEwMzQyMDAxNDEyMDZhMjQwMDBiNzYwMjA1N2YwMTdlMjMwMDQxMTA2YjIyMDEyNDAwMTA3ZDIxMDIyMDAwMjgwMjEwMjEwMzIwMDAyODAyMDQyMTA0MjAwMDI4MDIwMDIxMDUyMDAwMjkwMzA4MjIwNjQyN2Y1MTA0N2UxMDE2MDUyMDA2MGIyMDAzMjAwMjIwMDUyMDA0MTA0NTIxMDAxMDE3MjAwMDEwMTIyMTAyMjAwMTQxMDAzNjAyMGMyMDAxMjAwMDM2MDIwNDIwMDEyMDAyNDEwMjc2MzYwMjA4MjAwMTQxMDQ2YTEwNzUxMDJmMjAwMTQxMTA2YTI0MDAwYjQ3MDEwMjdmMjMwMDQxMTA2YjIyMDIyNDAwMTA0MzIxMDMyMDAyNDIwMDM3MDMwODIwMDIyMDAxYWQ0MmZmMDE4MzQxMDEyMDAyNDEwODZhMTA4MjAxMjAwMzIwMDIyODAyMDAyMDAyMjgwMjA0MTAxODFhMjAwMDIwMDMxMDRlMjAwMjQxMTA2YTI0MDAwYjhmMDIwMjA0N2YwMTdlMjAwMzIwMDE0MjM4ODYyMDAxNDI4MGZlMDM4MzQyMjg4Njg0MjAwMTQyODA4MGZjMDc4MzQyMTg4NjIwMDE0MjgwODA4MGY4MGY4MzQyMDg4Njg0ODQyMDAxNDIwODg4NDI4MDgwODBmODBmODMyMDAxNDIxODg4NDI4MDgwZmMwNzgzODQyMDAxNDIzODg4MjIwODIwMDE0MjI4ODg0MjgwZmUwMzgzODQ4NDg0MzcwMDAwMDI0MDIwMDE1MDA0NDA0MWI4OGQwODIxMDMwYzAxMGIyMDAyMDQ0MDIwMDE0MjdmNTEwNDQwMjAwMzQxMDc2YTIxMDM0MTAxMjEwNDBjMDIwYjIwMDhhN2MwMjIwNTQxMDc3NTIxMDYyMDA1NDEwMDQ4MjEwNTBiMjAwNjQxZmYwMTcxMjEwNjAzNDAwMjQwMDI0MDIwMDQ0MTA4NDcwNDQwMjAwMzIwMDQ2YTJkMDAwMDIyMDcyMDA2NDYwZDAyMjAwMjQ1MjAwNzQxMDc3NjIwMDU0NjcyNDUwNDQwMjAwNDQxMDE2YjIyMDQ0MTA5NGYwZDAyMGIyMDAzMjAwNDZhMjEwMzQxMDgyMDA0NmIyMTA0MGMwNDBiMTAyYzAwMGIxMDJjMDAwYjIwMDQ0MTAxNmEyMTA0MGMwMDBiMDAwYjIwMDAyMDA0MzYwMjA0MjAwMDIwMDMzNjAyMDAwYmEzMDEwMjAzN2YwMTdlMjMwMDQxMTA2YjIyMDMyNDAwMDI3ZjIwMDIyOTAzMDA1MDA0NDAyMDAxMjgwMjEwMjEwNDIwMDMyMDAxMjgwMjAwMjAwMTI4MDIwNDIwMDIyODAyMDgyMDAyMjgwMjBjMTA2ZDIwMDMyODAyMDAyMTA1MjAwMzI4MDIwNDBjMDEwYjEwNDcyMTA0MjAwMzQxMDg2YTIwMDEyODAyMDAyMDAxMjgwMjA0MjAwMTI4MDIxMDIwMDIxMDZjMjAwMzI4MDIwODIxMDUyMDAzMjgwMjBjMGIyMTAyMjAwMTI5MDMwODIxMDYyMDAwMTA3ZDM2MDIxODIwMDAyMDA0MzYwMjEwMjAwMDIwMDYzNzAzMDgyMDAwMjAwMjM2MDIwNDIwMDAyMDA1MzYwMjAwMjAwMzQxMTA2YTI0MDAwYjNmMDEwMTdmMTA0MzIxMDMyMDAwMjAwMTI5MDMwMDM3MDMwMDIwMDA0MTEwNmEyMDAxNDExMDZhMjkwMzAwMzcwMzAwMjAwMDQxMDg2YTIwMDE0MTA4NmEyOTAzMDAzNzAzMDAyMDAzMjAwMjEwNDQyMDAwMjAwMzM2MDIxODBiNTIwMTAyN2YyMzAwNDExMDZiMjIwNDI0MDAyMDA0NDEwODZhMjAwMDI4MDIwODIwMDAyODAyMDAyMjA1MjAwMTEwODYwMTIwMDQyODAyMDg0MTAxNDYwNDQwMjAwNDI4MDIwYzIwMDAyMDAxMjAwNTZhMzYwMjAwMjAwNDQxMTA2YTI0MDAwZjBiMjAwMjIwMDM0MWEzODUwODQxMGYxMDRjMDAwYjFmMDAyMDAxMjAwMjIwMDMxMDA0MjIwMTEwMWYyMTAyMjAwMDIwMDEzNjAyMDQyMDAwMjAwMjQ1MzYwMjAwMGI0ZjAxMDM3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDI0MTA4NmEyMDAwMjgwMjA4MjAwMDI4MDIwMDIyMDMyMDAxMTA4NjAxMjAwMjI4MDIwODQxMDE0NjA0NDAyMDAyMjgwMjBjMjAwMDIwMDEyMDAzNmEzNjAyMDAyMDAyNDExMDZhMjQwMDBmMGI0MWEzODUwODQxMGYxMDg4MDEwMDBiMWEwMTAxN2Y0MWYxODUwODQxMTYxMDRkMjIwMjIwMDAyMDAxMTAwZjFhMjAwMjEwMDAwMDBiMTUwMDQxN2YyMDAwMjAwMTEwMTkyMjAwNDEwMDQ3MjAwMDQxMDA0ODFiMGIwZjAwMjAwMDIwMDEyMDAzMjAwMjEwMjg0MTAwNDcwYjA5MDAyMDAwMjAwMTEwMDUxYTBiMGMwMDIwMDAyMDAwMjAwMTEwMDIyMDAwMGIwYzAwMjAwMDIwMDAyMDAxMTAxYTIwMDAwYjBjMDAyMDAwMjAwMDIwMDExMDFiMjAwMDBiMGEwMDIwMDAyMDAwMjAwMTEwMDIwYjBjMDAyMDAwMjAwMDIwMDExMDYwMjAwMDBiMTAwMTAxN2YxMDJhMjIwMjIwMDAyMDAxMTAwMjIwMDIwYjEwMDEwMTdmMTAyYTIyMDIyMDAwMjAwMTEwMWIyMDAyMGIxMDAxMDE3ZjEwMmEyMjAyMjAwMDIwMDExMDYwMjAwMjBiMTkwMTAxN2YxMDJhMjEwMjQxNzIyMDAxYWQxMDAxMjAwMjIwMDA0MTcyMTAxZTIwMDIwYjBlMDEwMTdmMTA0MzIyMDEyMDAwMTA0NDIwMDEwYjRjMDEwMjdmMjMwMDQxMTA2YjIyMDEyNDAwMTA0MzIxMDIyMDAxMjAwMDQxMTg3NDIwMDA0MTgwZmUwMzcxNDEwODc0NzIyMDAwNDEwODc2NDE4MGZlMDM3MTIwMDA0MTE4NzY3MjcyMzYwMjBjMjAwMjIwMDE0MTBjNmE0MTA0MTAwZjFhMjAwMTQxMTA2YTI0MDAyMDAyMGI4NDAxMDIwNDdmMDE3ZTIzMDA0MTIwNmIyMjAyMjQwMDIwMDI0MTEwNmE0MjAwMzcwMzAwMjAwMjQyMDAzNzAzMDgyMDAxNDEwMDIwMDI0MTA4NmEyMjAzNDExMDEwNmYyMDAyNDEwMDM2MDIxYzIwMDMyMDAyNDExYzZhMjIwNDEwOTgwMTIxMDUyMDAzMjAwNDEwOTkwMTIxMDYyMDAyNDEwODZhMjAwMjQxMWM2YTEwOTgwMTIxMDMwNDQwNDFjMzg1MDg0MTFkMTAwMzAwMGIyMDAwMjAwMzM2MDIwYzIwMDAyMDA1MzYwMjA4MjAwMDIwMDYzNzAzMDAyMDAyNDEyMDZhMjQwMDBiNzQwMTAxN2YyMzAwNDExMDZiMjIwMjI0MDAyMDAyNDEwMDM2MDIwYzIwMDIyMDAwNDExMDIwMDEyODAyMDAyMjAwMjAwMDQxMDQ2YTIyMDAxMDlkMDEyMDAyNDEwYzZhNDEwNDIwMDIyODAyMDAyMDAyMjgwMjA0MTA1NzIwMDEyMDAwMzYwMjAwMjAwMjI4MDIwYzIxMDAyMDAyNDExMDZhMjQwMDIwMDA0MTE4NzQyMDAwNDE4MGZlMDM3MTQxMDg3NDcyMjAwMDQxMDg3NjQxODBmZTAzNzEyMDAwNDExODc2NzI3MjBiYTgwMTAyMDE3ZTAxN2YyMzAwNDExMDZiMjIwMzI0MDAyMDAzNDIwMDM3MDMwODIwMDMyMDAwNDExMDIwMDEyODAyMDAyMjAwMjAwMDQxMDg2YTIyMDAxMDlkMDEyMDAzNDEwODZhNDEwODIwMDMyODAyMDAyMDAzMjgwMjA0MTA1NzIwMDEyMDAwMzYwMjAwMjAwMzI5MDMwODIxMDIyMDAzNDExMDZhMjQwMDIwMDI0MjM4ODYyMDAyNDI4MGZlMDM4MzQyMjg4Njg0MjAwMjQyODA4MGZjMDc4MzQyMTg4NjIwMDI0MjgwODA4MGY4MGY4MzQyMDg4Njg0ODQyMDAyNDIwODg4NDI4MDgwODBmODBmODMyMDAyNDIxODg4NDI4MDgwZmMwNzgzODQyMDAyNDIyODg4NDI4MGZlMDM4MzIwMDI0MjM4ODg4NDg0ODQwYjBmMDAyMDAwMjAwMTIwMDIyMDAzNDEwYzEwZjkwMTBiMGYwMDIwMDAyMDAxMjAwMjIwMDM0MTBkMTBmOTAxMGIwZjAwMjAwMDIwMDEyMDAyMjAwMzQxMDkxMGY5MDEwYjJmMDAwMjQwMjAwMzIwMDQ0ZDA0NDAyMDAyMjAwNDQ5MGQwMTIwMDAyMDA0MjAwMzZiMzYwMjA0MjAwMDIwMDEyMDAzNmEzNjAyMDAwZjBiMTAyYzAwMGIxMDJjMDAwYmI0MDEwMTAzN2YyMzAwNDExMDZiMjIwNDI0MDAwMjdmMDI0MDIwMDAyZDAwMDg0NTA0NDAyMDAwMjgwMjAwMjIwNTEwMTIyMjA2NDE5MGNlMDA0YjBkMDE0MWUwZGIwODJkMDAwMDBkMDE0MWRjZGIwODIwMDYzNjAyMDA0MWUwZGIwODQxMDEzYTAwMDAyMDA0NDEwODZhMjAwNjEwOWYwMTIwMDU0MTAwMjAwNDI4MDIwODIwMDQyODAyMGMxMDZmMWEyMDAwNDEwMTNhMDAwODBiNDEwMTIwMDEyMDAzNmEyMjAwNDFkY2RiMDgyODAyMDA0YjBkMDExYTIwMDQyMDAxMjAwMDEwYTAwMTIwMDIyMDAzMjAwNDI4MDIwMDIwMDQyODAyMDQxMDU3NDEwMDBjMDEwYjIwMDA0MTAwM2EwMDA4MjAwNTIwMDEyMDAyMjAwMzEwNmYwYjIwMDQ0MTEwNmEyNDAwMGIzZTAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDI0MTA4NmE0MWNjOGQwODQxOTBjZTAwMjAwMTEwZDAwMTIwMDIyODAyMGMyMTAxMjAwMDIwMDIyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDI0MTEwNmEyNDAwMGIzMjAwMDI0MDIwMDEyMDAyNGQwNDQwMjAwMjQxOTBjZTAwNGQwZDAxMTAyYzAwMGIxMDJjMDAwYjIwMDAyMDAyMjAwMTZiMzYwMjA0MjAwMDIwMDE0MWNjOGQwODZhMzYwMjAwMGIxOTAwMjAwMDQxZmVmZmZmZmYwNzQ2MDQ0MDQxZTA4NTA4NDEwZDEwMDMwMDBiMjAwMDBiNGQwMTAxN2YyMzAwNDExMDZiMjIwMTI0MDAyMDAwMTAxMjQxMDQ0NjA0NDAyMDAxNDEwMDM2MDIwYzIwMDA0MTAwMjAwMTQxMGM2YTQxMDQxMDhhMDExYTQxZmVmZmZmZmYwNzIwMDAyMDAxMjgwMjBjNDFjNThlYjFhMjA0NDYxYjIxMDAwYjIwMDE0MTEwNmEyNDAwMjAwMDBiODAwMTAxMDI3ZjIzMDA0MTEwNmIyMjAzMjQwMDAyNDAwMjQwMjAwMDJkMDAwNDA0NDA0MTkwY2UwMDQxZGNkYjA4MjgwMjAwMjIwNDZiMjAwMjQ5MGQwMTIwMDM0MTA4NmEyMDA0MjAwMjIwMDQ2YTIyMDAxMGE0MDEyMDAzMjgwMjA4MjAwMzI4MDIwYzIwMDEyMDAyMTA1NzQxZGNkYjA4MjAwMDM2MDIwMDBjMDIwYjIwMDAyODAyMDAyMDAxMjAwMjEwMGYxYTBjMDEwYjIwMDAxMGE1MDEyMDAwMjgwMjAwMjAwMTIwMDIxMDBmMWEwYjIwMDM0MTEwNmEyNDAwMGIzZjAxMDE3ZjIzMDA0MTEwNmIyMjAzMjQwMDIwMDM0MTA4NmEyMDAxMjAwMjQxY2M4ZDA4NDE5MGNlMDAxMDJiMjAwMzI4MDIwYzIxMDEyMDAwMjAwMzI4MDIwODM2MDIwMDIwMDAyMDAxMzYwMjA0MjAwMzQxMTA2YTI0MDAwYjU4MDEwMjdmMjMwMDQxMTA2YjIyMDEyNDAwMjAwMDJkMDAwNDIwMDA0MTAwM2EwMDA0MDQ0MDIwMDE0MTA4NmE0MTAwNDFkY2RiMDgyODAyMDAxMGEwMDEyMDAwMjgwMjAwMjAwMTI4MDIwODIwMDEyODAyMGMxMDBmMWE0MWRjZGIwODQxMDAzNjAyMDA0MWUwZGIwODQxMDAzYTAwMDAwYjIwMDE0MTEwNmEyNDAwMGIwZDAwMjAwMDQxNjcxMDIwMWE0MTY3MTAxMjBiMGQwMDIwMDAxMDJhMjIwMDEwMjAxYTIwMDAwYjEyMDAyMDAwMTBhNjAxNDUwNDQwMjAwMDIwMDExMDIxMWEwYjBiMTIwMDIwMDAxMGE2MDE0NTA0NDAyMDAwMjAwMTEwYWEwMTBiMGIzODAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDI0MjAwMzcwMzA4MjAwMjIwMDE0MTAwMjAwMjQxMDg2YTEwODIwMTIwMDAyMDAyMjgwMjAwMjAwMjI4MDIwNDEwYjgwMTIwMDI0MTEwNmEyNDAwMGIwYTAwMjAwMDEwYTcwMTEwYTIwMTBiYjkwMTAxMDQ3ZjIzMDA0MTIwNmIyMjAxMjQwMDIwMDAxMGE3MDEyMTAyMTA0MzIxMDQyMDAyMTAxMjIxMDAyMDAxNDExMDZhNDEwMDNhMDAwMDIwMDE0MTBjNmEyMDAwMzYwMjAwMjAwMTIwMDIzNjAyMDgyMDAxMjAwMDM2MDIwNDIwMDE0MTAwMzYwMjAwMDM3ZjIwMDAyMDAzNDYwNDdmMjAwMTJkMDAxMDA0NDA0MWRjZGIwODQxMDAzNjAyMDA0MWUwZGIwODQxMDAzYTAwMDAwYjIwMDE0MTIwNmEyNDAwMjAwNDA1MjAwMTEwYWQwMTIxMDAyMDAxMTBhZTAxMjEwMjIwMDExMGFmMDEyMTAzMjAwMTIwMDAzNjAyMWMyMDAxMjAwMzM2MDIxODIwMDEyMDAyMzYwMjE0MjAwNDIwMDE0MTE0NmExMDU5MjAwMTI4MDIwMDIxMDMyMDAxMjgwMjA0MjEwMDBjMDEwYjBiMGIzMzAyMDE3ZjAxN2UyMzAwNDExMDZiMjIwMTI0MDAyMDAxNDEwMDM2MDIwYzIwMDAyMDAxNDEwYzZhMjIwMDQxMDQxMGIzMDEyMDAwNDEwNDEwYjEwMTIwMDE0MTEwNmEyNDAwYTcwYjA5MDAyMDAwNDEyMDEwODcwMTBiMGMwMDIwMDAyMDAwMTBhZDAxMTA4NzAxMGIzYTAxMDE3ZjIzMDA0MTEwNmIyMjAzMjQwMDIwMDM0MTA4NmEyMDAxNDEwODIwMDIxMGQwMDEyMDAzMjgwMjBjMjEwMTIwMDAyMDAzMjgwMjA4MzYwMjAwMjAwMDIwMDEzNjAyMDQyMDAzNDExMDZhMjQwMDBiMzQwMTAxN2UwMjQwMjAwMTQ1MGQwMDAzNDAyMDAxNDUwZDAxMjAwMTQxMDE2YjIxMDEyMDAwMzEwMDAwMjAwMjQyMDg4Njg0MjEwMjIwMDA0MTAxNmEyMTAwMGMwMDBiMDAwYjIwMDIwYmZkMDEwMTA2N2YyMzAwNDEzMDZiMjIwMTI0MDAyMDAwMTBhNzAxMjEwMjEwNDMyMTA0MjAwMjEwMTIyMTAwMjAwMTQxMTg2YTQxMDAzYTAwMDAyMDAxNDExNDZhMjAwMDM2MDIwMDIwMDEyMDAyMzYwMjEwMjAwMTIwMDAzNjAyMGMyMDAxNDEwMDM2MDIwODAzN2YyMDAwMjAwMzQ2MDQ3ZjIwMDEyZDAwMTgwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAxNDEzMDZhMjQwMDIwMDQwNTIwMDE0MTA4NmEyMjAyMTBhZDAxMjEwMzIwMDIxMGFlMDEyMTA1MjAwMjEwYWYwMTIxMDY0MTAwMjEwMDIwMDE0MTAwM2EwMDJmMjAwMjIwMDE0MTJmNmE0MTAxMTBiMzAxMDI0MDAyNDAwMjQwMjAwMTJkMDAyZjBlMDIwMjAxMDAwYjQxZWQ4NjA4NDEwZDEwODgwMTAwMGI0MTAxMjEwMDBiMjAwMTIwMDAzYTAwMjgyMDAxMjAwNjM2MDIyNDIwMDEyMDA1MzYwMjIwMjAwMTIwMDMzNjAyMWMyMDA0MjAwMTQxMWM2YTEwNTUyMDAxMjgwMjA4MjEwMzIwMDEyODAyMGMyMTAwMGMwMTBiMGIwYjJkMDAyMDAwNDEwODZhMjAwMDI4MDIwMDIwMDEyMDAyMTA5ZTAxMDQ0MDQxYTM4NTA4NDEwZjEwODgwMTAwMGIyMDAwMjAwMDI4MDIwMDIwMDI2YTM2MDIwMDBiODcwMTAxMDE3ZjIzMDA0MTMwNmIyMjAyMjQwMDIwMDIyMDAxMzYwMjA4MjAwMjEwMzUyMDAyMjAwMjJkMDAwNDNhMDAxMDIwMDIyMDAyMjgwMjAwMzYwMjBjMjAwMjIwMDExMDEyMzYwMjFjMjAwMjQxMDAzNjAyMTgyMDAyMjAwMjQxMDg2YTM2MDIxNDAzNDAyMDAyNDEyMDZhMjAwMjQxMTQ2YTEwYjUwMTIwMDIyZDAwMmM0MTAyNDY0NTA0NDAyMDAyNDEyMDZhMjAwMjQxMGM2YTEwYjYwMTBjMDEwYjBiMjAwMDIwMDIyODAyMGMyMDAyMmQwMDEwMTBiNzAxMjAwMjQxMzA2YTI0MDAwYmM1MDMwMTA3N2YyMzAwNDFkMDAwNmIyMjAyMjQwMDAyNDAyMDAxMjgwMjA0MjIwNDQxMGQ2YTIyMDgyMDAxMjgwMjA4NGQwNDQwMjAwMTI4MDIwMDIwMDI0MjAwMzcwMDM1MjAwMjQyMDAzNzAzMzAyODAyMDAyMDA0MjAwMjQxMzA2YTIyMDM0MTBkMTA2ZjFhMjAwMjQxMDAzNjAyNDAyMDAyNDEyODZhMjAwMzQxMDA0MTA0MTBiZjAxMjAwMjQxNDA2YjIyMDU0MTA0MjAwMjI4MDIyODIwMDIyODAyMmMxMDU3MjAwMjI4MDI0MDIxMDQyMDAyNDFjODAwNmE0MTAwM2EwMDAwMjAwMjQyMDAzNzAzNDAyMDAyNDEyMDZhMjAwMzQxMDQ0MTBkMTBiZjAxMjAwNTQxMDkyMDAyMjgwMjIwMjAwMjI4MDIyNDEwNTcyMDAyNDEwMDM2MDI0YzIwMDI0MTE4NmEyMDA1NDEwMDQxMDQxMGMwMDEyMDAyNDFjYzAwNmEyMjA3NDEwNDIwMDIyODAyMTgyMDAyMjgwMjFjMTA1NzIwMDIyODAyNGMyMTAzMjAwMjQxMDAzNjAyNGMyMDAyNDExMDZhMjAwNTQxMDQ0MTA4MTBjMDAxMjAwNzQxMDQyMDAyMjgwMjEwMjAwMjI4MDIxNDEwNTcyMDAyMjgwMjRjMjEwNjIwMDI0MTAwM2EwMDRjMjAwMjQxMDg2YTIwMDU0MTA4NDEwOTEwYzAwMTIwMDc0MTAxMjAwMjI4MDIwODIwMDIyODAyMGMxMDU3MjAwMDIwMDIyZDAwNGM0MTAwNDczYTAwMGMyMDAwMjAwNjQxMTg3NDIwMDY0MTgwZmUwMzcxNDEwODc0NzIyMDA2NDEwODc2NDE4MGZlMDM3MTIwMDY0MTE4NzY3MjcyMzYwMjA4MjAwMDIwMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwNDIwMDAyMDA0NDExODc0MjAwNDQxODBmZTAzNzE0MTA4NzQ3MjIwMDQ0MTA4NzY0MTgwZmUwMzcxMjAwNDQxMTg3NjcyNzIzNjAyMDAyMDAxMjAwODM2MDIwNDBjMDEwYjIwMDA0MTAyM2EwMDBjMGIyMDAyNDFkMDAwNmEyNDAwMGI0ZDAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDAyODAyMDAyMDAxMTBiYzAxMjAwMTIwMDAyODAyMDQxMGJkMDEyMDAwNDEwODZhMjgwMjAwMjAwMTEwM2UyMDAyMjAwMDQxMGM2YTJkMDAwMDNhMDAwZjIwMDEyMDAyNDEwZjZhNDEwMTEwYTMwMTIwMDI0MTEwNmEyNDAwMGIwZDAwMjAwMDIwMDEyMDAyMTAzODEwMjExYTBiMGQwMDIwMDAyMDAxMjAwMjEwNGQxMDIxMWEwYjg3MDEwMTAxN2YyMzAwNDEzMDZiMjIwMjI0MDAyMDAyMjAwMTM2MDIwODIwMDIxMDM1MjAwMjIwMDIyZDAwMDQzYTAwMTAyMDAyMjAwMjI4MDIwMDM2MDIwYzIwMDIyMDAxMTAxMjM2MDIxYzIwMDI0MTAwMzYwMjE4MjAwMjIwMDI0MTA4NmEzNjAyMTQyMDAyNDEyNDZhMjEwMTAzNDAyMDAyNDEyMDZhMjAwMjQxMTQ2YTEwYmEwMTIwMDIyODAyMjAwNDQwMjAwMTIwMDI0MTBjNmExMGJiMDEwYzAxMGIwYjIwMDAyMDAyMjgwMjBjMjAwMjJkMDAxMDEwYjcwMTIwMDI0MTMwNmEyNDAwMGI4OTAzMDEwNjdmMjMwMDQxNDA2YTIyMDIyNDAwMjAwMDIwMDEyODAyMDQyMjAzNDEwYzZhMjIwNjIwMDEyODAyMDg0ZDA0N2YyMDAxMjgwMjAwMjAwMjQxMjg2YTQxMDAzNjAyMDAyMDAyNDIwMDM3MDMyMDI4MDIwMDIwMDMyMDAyNDEyMDZhMjIwMzQxMGMxMDZmMWEyMDAyNDEwMDM2MDIzMDIwMDI0MTE4NmEyMDAzNDEwMDQxMDQxMGMxMDEyMDAyNDEzMDZhMjIwNTQxMDQyMDAyMjgwMjE4MjAwMjI4MDIxYzEwNTcyMDAyMjgwMjMwMjEwNDIwMDI0MjAwMzcwMzMwMjAwMjQxMTA2YTIwMDM0MTA0NDEwYzEwYzEwMTIwMDU0MTA4MjAwMjI4MDIxMDIwMDIyODAyMTQxMDU3MjAwMjQxMDAzNjAyM2MyMDAyNDEwODZhMjAwNTQxMDA0MTA0MTBjMjAxMjAwMjQxM2M2YTIyMDc0MTA0MjAwMjI4MDIwODIwMDIyODAyMGMxMDU3MjAwMjI4MDIzYzIxMDMyMDAyNDEwMDM2MDIzYzIwMDIyMDA1NDEwNDQxMDgxMGMyMDEyMDA3NDEwNDIwMDIyODAyMDAyMDAyMjgwMjA0MTA1NzIwMDIyODAyM2MyMTA1MjAwMDQxMGM2YTIwMDQ0MTE4NzQyMDA0NDE4MGZlMDM3MTQxMDg3NDcyMjAwNDQxMDg3NjQxODBmZTAzNzEyMDA0NDExODc2NzI3MjM2MDIwMDIwMDAyMDAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyMDQyMDAxMjAwNjM2MDIwNDIwMDA0MTA4NmEyMDA1NDExODc0MjAwNTQxODBmZTAzNzE0MTA4NzQ3MjIwMDU0MTA4NzY0MTgwZmUwMzcxMjAwNTQxMTg3NjcyNzIzNjAyMDA0MTAxMDU0MTAwMGIzNjAyMDAyMDAyNDE0MDZiMjQwMDBiMWYwMDIwMDAyODAyMDgyMDAxMTBiYzAxMjAwMTIwMDAyODAyMDAxMGJkMDEyMDAwMjgwMjA0MjAwMTEwM2UwYjQ2MDEwMTdmMjMwMDQxMTA2YjIyMDIyNDAwMjAwMjIwMDA0MTE4NzQyMDAwNDE4MGZlMDM3MTQxMDg3NDcyMjAwMDQxMDg3NjQxODBmZTAzNzEyMDAwNDExODc2NzI3MjM2MDIwYzIwMDEyMDAyNDEwYzZhNDEwNDEwYTMwMTIwMDI0MTEwNmEyNDAwMGI4MTAxMDEwMzdmMjMwMDQxMTA2YjIyMDIyNDAwMDI0MDAyNDAyMDAwMmQwMDA0MDQ0MDIwMDExMDEyMjIwNDQxOTBjZTAwNDFkY2RiMDgyODAyMDAyMjAzNmI0YjBkMDEyMDAyNDEwODZhMjAwMzIwMDMyMDA0NmEyMjAwMTBhNDAxMjAwMTQxMDAyMDAyMjgwMjA4MjAwMjI4MDIwYzEwNmYxYTQxZGNkYjA4MjAwMDM2MDIwMDBjMDIwYjIwMDAyODAyMDAyMDAxMTA4YjAxMGMwMTBiMjAwMDEwYTUwMTIwMDAyODAyMDAyMDAxMTA4YjAxMGIyMDAyNDExMDZhMjQwMDBiMzgwMjAxN2YwMTdlMjMwMDQxMTA2YjIyMDEyNDAwMjAwMTQyMDAzNzAzMDgyMDAwMjAwMTQxMDg2YTIyMDA0MTA4NDE4YTg1MDg0MTBiMTBjNTAxMjAwMDQxMDgxMGIxMDEyMDAxNDExMDZhMjQwMDBiMGYwMDIwMDAyMDAxMjAwMjIwMDM0MTBkMTBmODAxMGIwZjAwMjAwMDIwMDEyMDAyMjAwMzQxMDkxMGY4MDEwYjBmMDAyMDAwMjAwMTIwMDIyMDAzNDEwYzEwZjgwMTBiMGYwMDIwMDAyMDAxMjAwMjIwMDM0MTA4MTBmODAxMGI4MDAyMDEwNTdmMjMwMDQxMjA2YjIyMDIyNDAwMjAwMDIwMDEyODAyMDQyMjAzNDEwODZhMjIwNTIwMDEyODAyMDg0ZDA0N2YyMDAxMjgwMjAwMjAwMjQyMDAzNzAzMTAyODAyMDAyMDAzMjAwMjQxMTA2YTIyMDM0MTA4MTA2ZjFhMjAwMjQxMDAzNjAyMWMyMDAyNDEwODZhMjAwMzQxMDA0MTA0MTBjMjAxMjAwMjQxMWM2YTIyMDY0MTA0MjAwMjI4MDIwODIwMDIyODAyMGMxMDU3MjAwMjI4MDIxYzIxMDQyMDAyNDEwMDM2MDIxYzIwMDIyMDAzNDEwNDQxMDgxMGMyMDEyMDA2NDEwNDIwMDIyODAyMDAyMDAyMjgwMjA0MTA1NzIwMDIyODAyMWMyMTAzMjAwMDIwMDQ0MTE4NzQyMDA0NDE4MGZlMDM3MTQxMDg3NDcyMjAwNDQxMDg3NjQxODBmZTAzNzEyMDA0NDExODc2NzI3MjM2MDIwNDIwMDEyMDA1MzYwMjA0MjAwMDQxMDg2YTIwMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwMDQxMDEwNTQxMDAwYjM2MDIwMDIwMDI0MTIwNmEyNDAwMGI4YTAxMDEwNDdmMjMwMDQxMTA2YjIyMDMyNDAwMjAwMTI4MDIwNDIyMDI0MTA0NmEyMjA0MjAwMTI4MDIwODRiMDQ3ZjQxMDAwNTIwMDEyODAyMDAyMDAzNDEwMDM2MDIwYzI4MDIwMDIwMDIyMDAzNDEwYzZhNDEwNDEwNmYxYTIwMDMyODAyMGMyMTAyMjAwMTIwMDQzNjAyMDQyMDAyNDExODc0MjAwMjQxODBmZTAzNzE0MTA4NzQ3MjIwMDI0MTA4NzY0MTgwZmUwMzcxMjAwMjQxMTg3NjcyNzIyMTAyNDEwMTBiMjEwMTIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAyMDAzNDExMDZhMjQwMDBiMzAwMDIwMDA0MTA4NmEyMDAwMjgwMjAwMjAwMTIwMDIxMDllMDEwNDQwMjAwMzIwMDQ0MWEzODUwODQxMGYxMDRjMDAwYjIwMDAyMDAwMjgwMjAwMjAwMjZhMzYwMjAwMGI3ODAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAwNDIzODg2MjAwMDQyODBmZTAzODM0MjI4ODY4NDIwMDA0MjgwODBmYzA3ODM0MjE4ODYyMDAwNDI4MDgwODBmODBmODM0MjA4ODY4NDg0MjAwMDQyMDg4ODQyODA4MDgwZjgwZjgzMjAwMDQyMTg4ODQyODA4MGZjMDc4Mzg0MjAwMDQyMjg4ODQyODBmZTAzODMyMDAwNDIzODg4ODQ4NDg0MzcwMzA4MjAwMTIwMDI0MTA4NmE0MTA4MTBhMzAxMjAwMjQxMTA2YTI0MDAwYmQ2MDEwMTA2N2YyMzAwNDE0MDZhMjIwMDI0MDAxMGM4MDExMDVjMjEwMTIwMDAxMGM5MDExMDVjMzYwMjA4MjAwMDEwNDczNjAyMGMyMDAwNDEyODZhMjIwMjIwMDExMDMyNDFmNzgwMDg0MTEwMTAzMzIwMDAyODAyMmMyMjAxMjAwMDQxMDg2YTEwNjQyMDAxMjAwMDQxMGM2YTEwNjQyMDAwNDEyMDZhMjIwMTIwMDA0MTM4NmEyMjAzMjkwMzAwMzcwMzAwMjAwMDQxMTg2YTIyMDQyMDAwNDEzMDZhMjIwNTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzI4MzcwMzEwMjAwMDIwMDA0MTEwNmExMDdjMzYwMjA0MjAwMjEwYzkwMTEwNWMxMDMyNDFmNTgxMDg0MTE4MTAzMzIwMDAyODAyMmMyMDAwNDEwNDZhMTA3ODIwMDEyMDAzMjkwMzAwMzcwMzAwMjAwNDIwMDUyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDMyODM3MDMxMDIwMDA0MTEwNmExMDdjMjAwMDQxNDA2YjI0MDAwYjBhMDA0MTk1ODgwODQxMTIxMDRkMGIwYTAwNDE4MTg4MDg0MTE0MTA0ZDBiYTkwMzAyMDU3ZjAxN2UyMzAwNDE4MDAxNmIyMjAyMjQwMDEwY2IwMTEwYWIwMTIxMDMyMDAxMjgwMjBjMjEwNDIwMDEyOTAzMDAyMTA3MjAwMTI4MDIwODIxMDEwMjQwMjAwMzQxZmVmZmZmZmYwNzQ2MDQ0MDIwMDE0MWZlZmZmZmZmMDc0NjBkMDEyMDAxMTBhMTAxMjEwMTIwMDIyMDA0MzYwMjE0MjAwMjIwMDczNzAzMDgyMDAyMjAwMTM2MDIxMDEwY2MwMTEwNWMyMTAzMjAwNDEwMjkyMTA0MjAwMjQxZTAwMDZhMjIwMTIwMDMxMDMyNDFhMTgwMDg0MTBhMTAzMzIwMDI0MTQwNmIyMjAzMjAwMTIwMDI0MTA4NmExMDg0MDEyMDAxMjAwMzEwY2QwMTIwMDExMDM0NDIwMDIxMDc0MWZlZmZmZmZmMDcyMTAxMGIyMDAyNDFlMDAwNmEyMDAwMTAzMjQxYzA4MTA4NDExMjEwMzMyMDAyMjgwMjY0MWEyMDAyNDEyODZhMjIwMDIwMDI0MWYwMDA2YTIyMDUyOTAzMDAzNzAzMDAyMDAyNDEyMDZhMjIwMzIwMDI0MWU4MDA2YTIyMDYyOTAzMDAzNzAzMDAyMDAyMjAwMjI5MDM2MDM3MDMxODAyNDAyMDAxNDFmZWZmZmZmZjA3NDcwNDQwMjAwNTIwMDAyOTAzMDAzNzAzMDAyMDA2MjAwMzI5MDMwMDM3MDMwMDIwMDIyMDAyMjkwMzE4MzcwMzYwMjAwMjEwN2QzNjAyNzgyMDAxMTBhMTAxMjEwMDIwMDIyMDA0MzYwMjNjMjAwMjIwMDczNzAzMzAyMDAyMjAwMDM2MDIzODIwMDI0MTQwNmIyMDAyNDFlMDAwNmEyMDAyNDEzMDZhMTA4MzAxMGMwMTBiMjAwMjQxZDAwMDZhMjAwMDI5MDMwMDM3MDMwMDIwMDI0MWM4MDA2YTIwMDMyOTAzMDAzNzAzMDAyMDAyMjAwMjI5MDMxODM3MDM0MDIwMDIyMDA0MzYwMjU4MGIyMDAyNDFlMDAwNmEyMDAyNDE0MDZiMTA3NjIwMDI0MTgwMDE2YTI0MDAwZjBiNDFjYTg4MDg0MTFmMTA0MTAwMGIwYTAwNDFlODhjMDg0MTIyMTA0ZDBiMGEwMDQxZmE4NjA4NDExZDEwNGQwYmZmMDIwMjAzN2YwMjdlMjMwMDQxZDAwMDZiMjIwMjI0MDAyMDAyNDEzMDZhMjIwNDIwMDE0MTEwNmEyOTAzMDAzNzAzMDAyMDAyNDEyODZhMjIwMzIwMDE0MTA4NmEyOTAzMDAzNzAzMDAyMDAyMjAwMTI5MDMwMDM3MDMyMDIwMDIxMDdkMzYwMjM4MDI0MDAyNDAwMjQwMDI0MDIwMDEyODAyMTgyMjAxMTA2NTBlMDIwMTAyMDAwYjEwNDcyMTAzMjAwMjQxMDg2YTIwMDIyODAyMjAyMDAyMjgwMjI0MjAwNDIwMDExMDYyMjAwMjI5MDMwODIxMDUyMDAyMjkwMzI4MjEwNjIwMDAxMDdkMzYwMjE4MjAwMDIwMDMzNjAyMTAyMDAwMjAwNjM3MDMwODIwMDAyMDA1MzcwMzAwMGMwMjBiMjAwMDIwMDIyOTAzMjAzNzAzMDAyMDAwNDExODZhMjAwMjQxMzg2YTI5MDMwMDM3MDMwMDIwMDA0MTEwNmEyMDA0MjkwMzAwMzcwMzAwMjAwMDQxMDg2YTIwMDMyOTAzMDAzNzAzMDAwYzAxMGIyMDAyNDE0MDZiMjAwMTEwOTcwMTAyN2YyMDAyMjkwMzQwNTAwNDQwMjAwMjI4MDIzMDIxMDEyMDAyNDExMDZhMjAwMjI4MDIyMDIwMDIyODAyMjQyMDAyMjgwMjQ4MjAwMjI4MDI0YzEwNmQyMDAyMjgwMjEwMjEwMzIwMDIyODAyMTQwYzAxMGIxMDQ3MjEwMTIwMDI0MTE4NmEyMDAyMjgwMjIwMjAwMjI4MDIyNDIwMDIyODAyMzAyMDAyNDE0MDZiMTA2YzIwMDIyODAyMTgyMTAzMjAwMjI4MDIxYzBiMjEwNDIwMDIyOTAzMjgyMTA1MjAwMDEwN2QzNjAyMTgyMDAwMjAwMTM2MDIxMDIwMDAyMDA1MzcwMzA4MjAwMDIwMDQzNjAyMDQyMDAwMjAwMzM2MDIwMDBiMjAwMjQxZDAwMDZhMjQwMDBiMGQwMDIwMDAxMDYxNDFmZjAxNzE0MTAxNGIwYjE3MDAyMDAwMjgwMjAwMjAwMTI4MDIwMDEwODkwMTQxZmYwMTcxNDFmZjAxNDYwYjNiMDEwMTdmMjMwMDQxMTA2YjIyMDQyNDAwMjAwNDQxMDg2YTQxMDAyMDAzMjAwMTIwMDIxMDJiMjAwNDI4MDIwYzIxMDEyMDAwMjAwNDI4MDIwODM2MDIwMDIwMDAyMDAxMzYwMjA0MjAwNDQxMTA2YTI0MDAwYjBhMDA0MWJkODgwODQxMGQxMDRkMGIwYTAwNDFmMjg3MDg0MTBmMTA0ZDBiMGEwMDQxZGQ4NzA4NDExNTEwNGQwYjBhMDA0MWE3ODgwODQxMTYxMDRkMGIxOTAxMDE3ZjQxOTc4NzA4NDExNjEwNGQyMTAxMjAwMDI4MDIwMDIwMDExMDQwMjAwMTBiMTkwMTAxN2Y0MWFkODcwODQxMTgxMDRkMjEwMTIwMDAyODAyMDAyMDAxMTA0MDIwMDEwYjBhMDA0MWM1ODcwODQxMTgxMDRkMGIwYTAwNDE4ZjhjMDg0MTFkMTA0ZDBiMGEwMDQxYWM4YzA4NDExZDEwNGQwYjBhMDA0MWM5OGMwODQxMWYxMDRkMGJhNzA1MDIwZDdmMDI3ZTIzMDA0MTQwNmEyMjAwMjQwMDEwMjI0MTBhMTA1YTQxMDA0MWJkODgwODQxMGQxMDUwMjEwOTQxMDExMDRiMjEwMjQxMDI0MTk1ODgwODQxMTIxMDUwMjEwYTQxMDM0MTgxODgwODQxMTQxMDUwMjEwNTQxMDQ0MWYyODcwODQxMGYxMDUwMjEwNjQxMDUxMDExMjEwZDQxMDYxMDExMjEwZTQxMDcxMDU4MjEwNzQxMDgxMDUxMjEwODQxMDk0MWZhODYwODQxMWQxMDUwMjEwNDIwMDAyMDA4MzYwMjEwMjAwMDIwMDczNjAyMGMyMDA1MTAyZjEwMzIyMTAxNDFlNjgxMDg0MTBmMTA0ZDIxMDMxMDQzMjEwYjEwN2QyMTBjMTAxNjIwMDEyMDBjMjAwMzIwMGIxMDQ1MjEwMTEwMTcyMDAxMTAxMjIxMDMyMDAwNDEwMDM2MDIzMDIwMDAyMDAxMzYwMjI4MjAwMDIwMDM0MTAyNzYzNjAyMmMyMDAwNDEyODZhMjIwMzEwNzUxMDJmMTBhMjAxMjEwMTIwMDMyMDA0MTAyZjEwMmYxMDMyNDFhYjgwMDg0MTE1MTAzMzIwMDMxMDgwMDEyMTAzMDI0MDAyNDAyMDAxNDFmZWZmZmZmZjA3NDcwNDQwMjAwMTEwMmYxMGExMDEyMDAyMTAzMDBkMDE0MWU5ODgwODQxZDEwMDEwNDEwMDBiMjAwMjIwMDMxMDMwNDUwZDAxMGIxMGNjMDEyMDA0MTBhODAxMTBkOTAxMjAwMzEwYTgwMTAyNDAxMGNiMDEyMjA0MTBhNjAxMGQwMDIwMDE0MWZlZmZmZmZmMDc0NzA0NDAyMDA0MjAwMTEwMjExYTBjMDEwYjIwMDQ0MWVkODUwODQxMDQxMGI4MDEwYjEwZDEwMTIwMDkxMGE4MDExMGQ0MDEyMDAyMTBhODAxMTBjODAxMjAwYTEwYTgwMTEwYzkwMTIwMDUxMDJmMTBhODAxMTBkODAxMjAwMDQxMjg2YTIyMDEyMDA1MTAzMjQxYjY4MTA4NDEwYTEwMzMyMDAxMTA4MDAxMTBhODAxMTBkMjAxMjAwNjEwMmYxMGE4MDExMGRhMDEyMDAxMjAwNjEwMzI0MTg2ODMwODQxMGYxMDMzMjAwMTEwODAwMTEwYTgwMTIwMDAyMDA3MTAxMjM2MDIxYzIwMDA0MTAwMzYwMjE4MjAwMDIwMDA0MTBjNmEzNjAyMTQwMzQwMDI0MDIwMDA0MTI4NmEyMDAwNDExNDZhMTBjMzAxMjAwMDI4MDIyODQ1MDQ0MDIwMDAyMDA4MTAxMjM2MDIxYzIwMDA0MTAwMzYwMjE4MjAwMDIwMDA0MTEwNmEzNjAyMTQwMzQwMjAwMDQxMjg2YTIwMDA0MTE0NmExMGMzMDEyMDAwMjgwMjI4NDUwZDAyMjAwMDIwMDAyODAyMzAyMjAxMzYwMjI0MjAwMDIwMDAyODAyMmMzNjAyMjAyMDAwNDEyMDZhMTBkNTAxMjIwMjEwYTYwMTBkMDAyMDAyMjAwMTEwYjQwMTBjMDAwYjAwMGIyMDAwMjAwMDI4MDIzMDIyMDEzNjAyMjQyMDAwMjAwMDI4MDIyYzM2MDIyMDIwMDA0MTIwNmExMGQ2MDEyMjAyMTBhNjAxMGQwMTIwMDIyMDAxMTBiOTAxMGMwMTBiMGIxMGQzMDEyMDBkMTBhOTAxMTBkNzAxMjAwZTEwYTkwMTIwMDA0MTQwNmIyNDAwMGYwYjQxYmE4OTA4NDFjODAwMTA0MTAwMGIwODAwMTAyMjQxMDAxMDVhMGJjNzAxMDEwNTdmMjMwMDQxMzA2YjIyMDAyNDAwNDEwMDEwNWEwMjQwMDI0MDEwNDYxMGQxMDExMDVjMTAzMDA0NDAxMDQ2MTBkMTAxMTA1YzEwMzA0NTBkMDEyMDAwMTA0YTIyMDEzNjAyMDgxMGQ0MDExMGE3MDEyMTAyMTBjOTAxMTA1YzIxMDMyMDAwMjAwMTEwMTIzNjAyMTQyMDAwNDEwMDM2MDIxMDIwMDAyMDAwNDEwODZhMzYwMjBjMjAwMDQxMjA2YTIxMDEwMzQwMDI0MDIwMDA0MTE4NmEyMDAwNDEwYzZhMTA2NzIwMDAyOTAzMTg1MDBkMDAyMDAwMjgwMjJjMjAwMDI4MDIyODIwMDIxMDMwNDUwZDA0MTBjZTAxNDUwZDA0MjAwMzEwMmYyMDAxMTBjYTAxMGMwMTBiMGIyMDAwNDEzMDZhMjQwMDBmMGI0MTgyOGEwODQxMTYxMDQxMDAwYjQxODI4YTA4NDExNjEwNDEwMDBiNDE5ODhhMDg0MTBkMTA0MTAwMGJjNzA3MDIwOTdmMDE3ZTIzMDA0MTgwMDE2YjIyMDAyNDAwMTAyMjQxMDExMDVhMjAwMDEwNGYzNjAyMmMxMGQxMDExMDVjMjEwMTAyNDAwMjQwMDI0MDEwNDYyMjA3MjAwMTEwMzAwNDQwMjAwMDEwYzkwMTEwNWMyMjAxMzYwMjM0MjAwMDQxZTAwMDZhMjIwMjIwMDExMDJmMTAzMjQxOGQ4MjA4NDExODEwMzMyMDAwMjgwMjY0MjAwMDQxMmM2YTEwNzgyMDAwNDFkODAwNmEyMjAxMjAwMDQxZjAwMDZhMjIwNjI5MDMwMDM3MDMwMDIwMDA0MWQwMDA2YTIyMDMyMDAwNDFlODAwNmEyMjA0MjkwMzAwMzcwMzAwMjAwMDIwMDAyOTAzNjAzNzAzNDgyMDAwNDFjODAwNmEyMjA1MTA3YzIxMDgyMDAyMTBjODAxMTA1YzEwMzI0MWUxODAwODQxMGExMDMzMjAwMDI4MDI2NDIyMDIyMDAwNDEzNDZhMTA2NDIwMDI0MTAwMjAwODEwNzkyMDAxMjAwNjI5MDMwMDM3MDMwMDIwMDMyMDA0MjkwMzAwMzcwMzAwMjAwMDIwMDAyOTAzNjAzNzAzNDgyMDAwNDEzODZhMjAwNTEwN2UyMDAwMjgwMjQ0MTBjZTAxNDUwZDAxMjAwMDI4MDIzNDEwMzIyMTAxNDFhNTgyMDg0MTA2MTA0ZDIxMDQxMDQzMjIwMzQxMDEyMDAwMTA3OTEwNDMyMjAyMjAwMDQxMzg2YTEwNDQyMDAwMjAwMTM2MDI3MDIwMDA0MjdmMzcwMzY4MjAwMDIwMDMzNjAyNjQyMDAwMjAwNDM2MDI2MDIwMDAxMDdkMjIwNTM2MDI3ODAyNDAwMjQwMDI0MDAyNDAyMDAyMTA2NTBlMDIwMjAwMDEwYjIwMDA0MWM4MDA2YTIwMDIxMDk3MDEwMjdmMjAwMDI5MDM0ODUwMDQ0MDIwMDA0MTE4NmEyMDA0MjAwMzIwMDAyODAyNTAyMDAwMjgwMjU0MTA2ZDIwMDAyODAyMTgyMTA0MjAwMDI4MDIxYzBjMDEwYjEwNDcyMDAwNDEyMDZhMjAwNDIwMDMyMDAxMjAwMDQxYzgwMDZhMTA2YzIwMDAyODAyMjAyMTA0MjEwMTIwMDAyODAyMjQwYjIxMDMxMDdkMjEwNTBjMDEwYjEwNDcyMTAxMjAwMDQxMTA2YTIwMDQyMDAzMjAwNjIwMDIxMDYyMjAwMDI5MDM2ODIxMDkyMDAwMjgwMjE0MjEwMzIwMDAyODAyMTAyMTA0MTA3ZDIxMDUyMDA5NDI3ZjUyMGQwMTBiMTAxNjIxMDkwYjIwMDkyMDAxMjAwNTIwMDQyMDAzMTA0NTIxMDExMDE3MjAwMTEwMTIyMTAyMjAwMDQxMDAzNjAyNTAyMDAwMjAwMTM2MDI0ODIwMDAyMDAyNDEwMjc2MzYwMjRjMjAwMDQxYzgwMDZhMTA3NTIyMDIxMDEyMjEwMTIwMDA0MWYwMDA2YTQxMDAzYTAwMDAyMDAwNDFlYzAwNmEyMDAxMzYwMjAwMjAwMDIwMDIzNjAyNjgyMDAwMjAwMTM2MDI2NDIwMDA0MTAwMzYwMjYwMjAwMDQxZTAwMDZhMjIwMTQxOGE4NTA4NDEwYjEwM2ExMGEyMDEyMTAyMjAwMTEwYmUwMTIxMDkyMDAxMTAzOTIxMDEyMDAwMjgwMjY0MjAwMDI4MDI2MDQ3MGQwMjIwMDAyZDAwNzAwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIwMjQwMjAwMjQxZmVmZmZmZmYwNzQ3MDQ0MDIwMDIxMGExMDEyMTAzMGMwMTBiMTBkOTAxMTBhNzAxMjEwMzEwY2MwMTEwNWMyMDAxMTAyOTEwMzE0MjAwMjEwOTBiMjAwMTEwY2UwMTQ1MGQwMzIwMDcyMDAzMjAwOTIwMDExMDQyMjAwMDIwMDEzNjAyNmMyMDAwMjAwMzM2MDI2ODIwMDAyMDA5MzcwMzYwMjAwMDIwMDA0MWUwMDA2YTEwOTUwMTIyMDEzNjAyMzAyMDAwNDEwODZhMTAzNTIwMDAyMDAwMmQwMDBjM2EwMDNjMjAwMDIwMDAyODAyMDgzNjAyMzgyMDAwMjAwMTEwMTIzNjAyNTAyMDAwNDEwMDM2MDI0YzIwMDAyMDAwNDEzMDZhMzYwMjQ4MDM0MDIwMDA0MWUwMDA2YTIwMDA0MWM4MDA2YTEwNjcyMDAwMjkwMzYwNTA0NTA0NDAyMDAwMjgwMjc0MjAwMDI4MDI3MDIwMDA0MTM4NmEyMjAxMTAzZTIwMDAyOTAzNjgyMDAxMTBjNjAxMjAwMTEwM2MwYzAxMGIwYjIwMDAyODAyMzgyMDAwMmQwMDNjMTAzNzIwMDA0MTgwMDE2YTI0MDAwZjBiNDE4MjhhMDg0MTE2MTA0MTAwMGI0MWU3OGEwODQxMWYxMDQxMDAwYjQxOGE4NTA4NDEwYjQxOTU4NTA4NDEwZTEwNGMwMDBiNDE4NjhiMDg0MTFhMTA0MTAwMGJmMzFkMDIxNjdmMDI3ZTIzMDA0MWEwMDI2YjIyMDAyNDAwMTAyMjQxMDAxMDVhMTBjODAxMTA1YzIxMDEyMDAwMTBjOTAxMTA1YzIyMTQxMDJmMTA5NjAxMzYwMmYwMDEyMDAwMTA0MzM2MDJhMDAxMjAwMDQxODAwMjZhMjIwOTIwMDExMDMyNDFlYjgwMDg0MTBjMTAzMzIwMDAyODAyODQwMjIyMDE0MTAwMTA4MTAxMjAwMTQxMDExMDgxMDEyMDAxNDEwMDEwODEwMTIwMDEyMDAwNDFmMDAxNmEyMjExMTA3YjIwMDEyMDAwNDFhMDAxNmEyMjA3MTA3YjIwMDA0MWUwMDE2YTIyMDUyMDAwNDE5MDAyNmEyMjA0MjkwMzAwMzcwMzAwMjAwMDQxZDgwMTZhMjIwMjIwMDA0MTg4MDI2YTIyMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDEyMDAwNDFkMDAxNmEyMjA2MTA3ZjEwZDIwMTEwNWMyMTAxMjAwMDIwMTQxMDJmMTA5NjAxMzYwMmYwMDEyMDAwMTA0MzM2MDJhMDAxMjAwOTIwMDExMDMyNDFlYjgwMDg0MTBjMTAzMzIwMDAyODAyODQwMjIyMDE0MTAwMTA4MTAxMjAwMTIwMTExMDdiMjAwMTIwMDcxMDdiMjAwMTQxMDEyMDAwMTA3OTIwMDUyMDA0MjkwMzAwMzcwMzAwMjAwMjIwMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDEyMDA2MTA3ZjEwMmEyMjAzMTAyYTIyMDYxMDIzMjAwNjEwY2UwMTA0NDAxMGNjMDExMDVjMjAwNjEwMjkxMDMxMTBkOTAxMTBhNzAxMjEwMTIwMDAyMDA2MzYwMjhjMDIyMDAwNDIwMDM3MDM4MDAyMjAwMDIwMDEzNjAyODgwMjIwMDMyMDAwNDE4MDAyNmExMDQ0MGIyMDAwMjAwMzM2MDI5MDAxMDI0MDAyNDAwMjQwMjAwMzEwNjUwNDQwMTBkNDAxMTBhNzAxMjEwZTEwN2QyMTBkMjAwMDIwMDAyODAyOTAwMTEwMTIzNjAyOWMwMTIwMDA0MTAwMzYwMjk4MDEyMDAwMjAwMDQxOTAwMTZhMzYwMjk0MDEyMDAwNDE5MDAyNmEyMTBhMjAwMDQxYzAwMTZhMjEwZjIwMDA0MWE4MDE2YTIxMTUwMzQwMjAwMDQxYTAwMTZhMjAwMDQxOTQwMTZhMTA2NzIwMDAyOTAzYTAwMTUwMDQ0MDQyODA4MDkwYmJiYWQ2YWRmMDBkMTAyZTIxMDEyMDBkMTBkMzAxMTA1ZjEwMmUxMDkyMDEyMDAxMTA4ZDAxMjIwNTIwMGQxMGQ3MDExMDVmMTAyZTEwOTIwMTIwMDExMDhkMDEyMjA2MTA5MTAxMjAwZDEwODkwMTQxZmYwMTcxNDEwMjQ5MGQwNTIwMGQyMDA1MTA5MzAxMjAwNjEwOTAwMTIxMDIyMDBlMTAyZjIxMDEyMDAwMjAwMjEwMjkzNjAyOGMwMjIwMDA0MjAwMzcwMzgwMDIyMDAwMjAwMTM2MDI4ODAyMjAxNDIwMDA0MTgwMDI2YTEwY2EwMTIwMGUxMDJmMjEwMTIwMDUxMGNlMDEwNDQwMTA0NjIwMDE0MjAwMjAwNTEwNDIwYjIwMDYxMGNlMDEwNDQwMTA0ODIwMGU0MjAwMjAwNjEwNDIwYjEwNDMyMTA0MTA0MzEwMmYyMTA2MjAwMTQxZmVmZmZmZmYwNzQ2MGQwMzIwMDEyMDA2MTA0MDBjMDQwYjIwMGYyMDE1NDEwODZhMjkwMzAwMzcwMzAwMjAwMDIwMTUyOTAzMDAzNzAzYjgwMTIwMGYxMGQ2MDExMGFjMDEyMTEyMjAwZjEwZDUwMTEwYjIwMTIxMTMyMDBmMjgwMjAwMjEwYzIwMDAyODAyYzQwMTIxMDQyMDAwMjkwM2I4MDEyMTE2MjAxMjEwMTIyMTAxMjAxMzEwMTI0MTBkNmUyMDAxNDEwYzZlNmEyMTExNDEwMDIxMDEwMzQwMDI0MDAyNDAyMDAxMjAxMTQ3MDQ0MDIwMDE0MTAxNmEyMTA2NDEwMDIxMDIyMDEyMTAxMjIxMDUwMjQwMDI0MDAzNDAyMDAyNDEwYzZhMjIwMzIwMDU0YjBkMDEyMDAwNDE4ODAyNmEyMjA5NDEwMDM2MDIwMDIwMDA0MjAwMzcwMzgwMDIyMDEyMjAwMjIwMDA0MTgwMDI2YTIyMDI0MTBjMTA4YTAxMWEyMDAwNDEwMDM2MDJkMDAxMjAwMDQxODgwMTZhMjAwMjQxMDA0MTA0MTBjMTAxMjAwMDQxZDAwMTZhMjIwNzQxMDQyMDAwMjgwMjg4MDEyMDAwMjgwMjhjMDExMDU3MjAwMDI4MDJkMDAxMjEwODIwMDA0MjAwMzcwM2QwMDEyMDAwNDE4MDAxNmEyMDAyNDEwNDQxMGMxMGMxMDEyMDA3NDEwODIwMDAyODAyODAwMTIwMDAyODAyODQwMTEwNTcyMDAwNDEwMDM2MDJmMDAxMjAwMDQxZjgwMDZhMjAwNzQxMDA0MTA0MTBjMjAxMjAwMDQxZjAwMTZhMjIwMjQxMDQyMDAwMjgwMjc4MjAwMDI4MDI3YzEwNTcyMDAwMjgwMmYwMDEyMTBiMjAwMDQxMDAzNjAyZjAwMTIwMDA0MWYwMDA2YTIwMDc0MTA0NDEwODEwYzIwMTIwMDI0MTA0MjAwMDI4MDI3MDIwMDAyODAyNzQxMDU3MjAwMzIxMDIyMDA4NDExODc0MjAwODQxODBmZTAzNzE0MTA4NzQ3MjIwMDg0MTA4NzY0MTgwZmUwMzcxMjAwODQxMTg3NjcyNzIyMDAxNDcwZDAwMGIyMDAwMjgwMmYwMDEyMTAzMjAwYjQxMTg3NDIwMGI0MTgwZmUwMzcxNDEwODc0NzIyMDBiNDEwODc2NDE4MGZlMDM3MTIwMGI0MTE4NzY3MjcyMTAyZjIxMDEyMDAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIyMjA3MTAyZjIxMDU0MTAxMTAyZDIwMDA0MTgwMDI2YTIyMDMyMDAxMTAzMjQxZDk4NjA4NDExNDEwMzMyMDAwMjgwMjg0MDIyMjAxMjAwNTEwNmUyMDAxMTA3MDIwMDA0MWUwMDE2YTIyMDIyMDBhMjkwMzAwMzcwMzAwMjAwMDQxZDgwMTZhMjIwMTIwMDkyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDExMDQzMjEwNTIwMDAyMDA0MzYwMjhjMDIyMDAwMjAwYzM2MDI4ODAyMjAwMDIwMTYzNzAzODAwMjIwMDUyMDAzMTA0NDIwMGEyMDAyMjkwMzAwMzcwMzAwMjAwOTIwMDEyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDNkMDAxMzcwMzgwMDIyMDAwMTA3ZDM2MDI5ODAyMDI0MDAyNDAwMjQwMDI0MDIwMDUxMDY1MGUwMjAxMDIwMDBiMTA0NzIxMDEyMDAwNDFlODAwNmEyMDAwMjgwMjgwMDIyMDAwMjgwMjg0MDIyMDBhMjAwNTEwNjIyMDAwMjkwMzY4MjExNzIwMDAyOTAzODgwMjIxMTYyMDAwMTA3ZDM2MDJlODAxMjAwMDIwMDEzNjAyZTAwMTIwMDAyMDE2MzcwM2Q4MDEyMDAwMjAxNzM3MDNkMDAxMGMwMjBiMjAwMDQxZTgwMTZhMjAwMDQxOTgwMjZhMjkwMzAwMzcwMzAwMjAwMjIwMGEyOTAzMDAzNzAzMDAyMDAxMjAwOTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzgwMDIzNzAzZDAwMTBjMDEwYjIwMDA0MWYwMDE2YTIyMDEyMDA1MTA5NzAxMjAwMDQxZDAwMTZhMjAwMDQxODAwMjZhMjAwMTEwODMwMTBiMjAwMDQxODAwMjZhMjAwMDQxZDAwMTZhMTA3NjIwMDAyODAyODgwMjIyMGMyMDA3MTAzMDQ1MGQwMTIwMDAyODAyOGMwMjIxMDQyMDAwMjkwMzgwMDIyMTE2MjAwNjIxMDEwYzA1MGI0MTAwMjEwMjIwMTMxMDEyMjEwNTAzNDAyMDAyNDEwZDZhMjIwMzIwMDU0YjBkMDMyMDAwNDIwMDM3MDA4NTAyMjAwMDQyMDAzNzAzODAwMjIwMTMyMDAyMjAwMDQxODAwMjZhMjIwMjQxMGQxMDhhMDExYTIwMDA0MTAwMzYwMmQwMDEyMDAwNDFlMDAwNmEyMDAyNDEwMDQxMDQxMGJmMDEyMDAwNDFkMDAxNmEyMjA4NDEwNDIwMDAyODAyNjAyMDAwMjgwMjY0MTA1NzIwMDAyODAyZDAwMTIxMDkyMDAwNDFkODAxNmEyMjBiNDEwMDNhMDAwMDIwMDA0MjAwMzcwM2QwMDEyMDAwNDFkODAwNmEyMDAyNDEwNDQxMGQxMGJmMDEyMDA4NDEwOTIwMDAyODAyNTgyMDAwMjgwMjVjMTA1NzIwMDA0MTAwMzYwMmYwMDEyMDAwNDFkMDAwNmEyMDA4NDEwMDQxMDQxMGMwMDEyMDAwNDFmMDAxNmEyMjAyNDEwNDIwMDAyODAyNTAyMDAwMjgwMjU0MTA1NzIwMDAyODAyZjAwMTIxMTAyMDAwNDEwMDM2MDJmMDAxMjAwMDQxYzgwMDZhMjAwODQxMDQ0MTA4MTBjMDAxMjAwMjQxMDQyMDAwMjgwMjQ4MjAwMDI4MDI0YzEwNTcyMDAwMjgwMmYwMDEyMTA3MjAwMDQxMDAzYTAwZjAwMTIwMDA0MTQwNmIyMDA4NDEwODQxMDkxMGMwMDEyMDAyNDEwMTIwMDAyODAyNDAyMDAwMjgwMjQ0MTA1NzIwMDMyMTAyMjAwOTQxMTg3NDIwMDk0MTgwZmUwMzcxNDEwODc0NzIyMDA5NDEwODc2NDE4MGZlMDM3MTIwMDk0MTE4NzY3MjcyMjAwMTQ3MGQwMDBiMjAwMDJkMDBmMDAxMjAwNzQxMTg3NDIwMDc0MTgwZmUwMzcxNDEwODc0NzIyMDA3NDEwODc2NDE4MGZlMDM3MTIwMDc0MTE4NzY3MjcyMjEwODIwMGMxMDJmMjEwOTIwMDQxMDI5MjEwNzIwMTA0MTE4NzQyMDEwNDE4MGZlMDM3MTQxMDg3NDcyMjAxMDQxMDg3NjQxODBmZTAzNzEyMDEwNDExODc2NzI3MjEwMmYyMTA1NDUwNDQwNDEwMTEwMmQyMDAwNDE4MDAyNmEyMjAxMjAwNTEwMzI0MWE4ODYwODQxMDgxMDMzMjAwMDI4MDI4NDAyMTA3MDIwMDA0MWUwMDE2YTIyMDIyMDBhMjkwMzAwMzcwMzAwMjAwYjIwMDA0MTg4MDI2YTIyMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDExMDQzMjEwNDIwMDAyMDA3MzYwMjhjMDIyMDAwMjAwOTM2MDI4ODAyMjAwMDIwMTYzNzAzODAwMjIwMDQyMDAxMTA0NDIwMGEyMDAyMjkwMzAwMzcwMzAwMjAwMzIwMGIyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDNkMDAxMzcwMzgwMDIyMDAwMTA3ZDM2MDI5ODAyMDI0MDAyNDAwMjQwMDI0MDIwMDQxMDY1MGUwMjAxMDIwMDBiMTA0NzIxMDEyMDAwNDExMDZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwYTIwMDQxMDYyMjAwMDI5MDMxMDIxMTcyMDAwMjkwMzg4MDIyMTE2MjAwMDEwN2QzNjAyZTgwMTIwMDAyMDAxMzYwMmUwMDEyMDAwMjAxNjM3MDNkODAxMjAwMDIwMTczNzAzZDAwMTBjMDIwYjIwMDA0MWU4MDE2YTIwMDA0MTk4MDI2YTI5MDMwMDM3MDMwMDIwMDIyMDBhMjkwMzAwMzcwMzAwMjAwYjIwMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDEwYzAxMGIyMDAwNDFmMDAxNmEyMDA0MTA5NzAxMDI3ZjIwMDAyOTAzZjAwMTUwMDQ0MDIwMDAyODAyOTAwMjIxMDMyMDAwNDExODZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwMDI4MDJmODAxMjAwMDI4MDJmYzAxMTA2ZDIwMDAyODAyMWMyMTAyMjAwMDI4MDIxODBjMDEwYjEwNDcyMTAzMjAwMDQxMjA2YTIwMDAyODAyODAwMjIwMDAyODAyODQwMjIwMDAyODAyOTAwMjIwMDA0MWYwMDE2YTEwNmMyMDAwMjgwMjI0MjEwMjIwMDAyODAyMjAwYjIxMDEyMDAwMjkwMzg4MDIyMTE2MjAwMDEwN2QzNjAyZTgwMTIwMDAyMDAzMzYwMmUwMDEyMDAwMjAxNjM3MDNkODAxMjAwMDIwMDIzNjAyZDQwMTIwMDAyMDAxMzYwMmQwMDEwYjIwMDA0MWQwMDE2YTEwNzIyMTAzMjAwODEwMmYyMTAxMjAwMDIwMDMzNjAyOGMwMjIwMDA0MjAwMzcwMzgwMDIyMDAwMjAwMTM2MDI4ODAyMjAwMDQxODAwMjZhMTA5NTAxMjEwMTBjMDQwYjIwMDgxMDJmMjEwNDQxMDExMDJkMjAwNTEwMzIyMTAzNDFhODg2MDg0MTA4MTA0ZDIxMDExMDQzMjIwNTIwMDQxMDZlMjAwNTEwNzAxMDQzMjEwNDIwMDAyMDA3MzYwMjhjMDIyMDAwMjAwOTM2MDI4ODAyMjAwMDIwMTYzNzAzODAwMjIwMDQyMDAwNDE4MDAyNmExMDQ0MjAwMDIwMDMzNjAyOTAwMjIwMDA0MjdmMzcwMzg4MDIyMDAwMjAwNTM2MDI4NDAyMjAwMDIwMDEzNjAyODAwMjIwMDAxMDdkMzYwMjk4MDIwMjdmMDI3ZTAyNDAwMjQwMDI0MDIwMDQxMDY1MGUwMjAxMDIwMDBiMTA0NzIxMDIyMDAwNDEyODZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwYTIwMDQxMDYyMjAwMDI4MDIyYzIxMDMyMDAwMjgwMjI4MjEwMTIwMDAyOTAzODgwMjBjMDIwYjIwMDAyODAyOTAwMjIxMDIyMDAwMjkwMzg4MDIyMTE2MjAwMDI4MDI4NDAyMjEwMzIwMDAyODAyODAwMjIxMDEyMDAwMjgwMjk4MDIwYzAyMGIyMDAwNDFkMDAxNmEyMDA0MTA5NzAxMDI3ZjIwMDAyOTAzZDAwMTUwMDQ0MDIwMDAyODAyOTAwMjIxMDIyMDAwNDEzMDZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwMDI4MDJkODAxMjAwMDI4MDJkYzAxMTA2ZDIwMDAyODAyMzQyMTAzMjAwMDI4MDIzMDBjMDEwYjEwNDcyMTAyMjAwMDQxMzg2YTIwMDAyODAyODAwMjIwMDAyODAyODQwMjIwMDAyODAyOTAwMjIwMDA0MWQwMDE2YTEwNmMyMDAwMjgwMjNjMjEwMzIwMDAyODAyMzgwYjIxMDEyMDAwMjkwMzg4MDIwYjIxMTYxMDdkMGIyMTA0MjAxNjQyN2Y1MTA0N2UxMDE2MDUyMDE2MGIyMDAyMjAwNDIwMDEyMDAzMTA0NTIxMDMxMDE3NDEwMDIxMDIyMDAzMTAxMjIxMDEyMDAwNDEwMDM2MDJmODAxMjAwMDIwMDMzNjAyZjAwMTIwMDAyMDAxNDEwMjc2MzYwMmY0MDEyMDAwNDFmMDAxNmExMDc1MTAyZjIxMDQxMDQzMjEwMTIwMDQxMDEyMjEwMzIwMDA0MTAwM2EwMDkwMDIyMDAwMjAwMzM2MDI4YzAyMjAwMDIwMDQzNjAyODgwMjIwMDAyMDAzMzYwMjg0MDIyMDAwNDEwMDM2MDI4MDAyMDM0MDIwMDIyMDAzNDYwNDQwMjAwMDJkMDA5MDAyNDUwZDA1NDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGMwNTA1MjAwMDQxZDAwMTZhMjIwMzIwMDA0MTgwMDI2YTEwNzcyMDAxMjAwMzEwNDQyMDAwMjgwMjgwMDIyMTAyMjAwMDI4MDI4NDAyMjEwMzBjMDEwYjAwMGIwMDBiNDFjMDg2MDg0MTE5MTA0MTAwMGIyMDBjMjAwZTEwMzAwNDQwMjAwZDIwMDQxMDhmMDEwYzA0MGI0MWQ0OGEwODQxMTMxMDQxMDAwYjIwMDA0MTA4NmExMDM2MjAwMDIwMDAyZDAwMGMzYTAwODQwMjIwMDAyMDAwMjgwMjA4MzYwMjgwMDIyMDAwNDE4MDAyNmEyMjA2NDE4MDgwMDg0MTIxMTBhMzAxMjMwMDQxNDA2YTIyMDMyNDAwMjAwMzQxMDAyMDAzNmI0MTAzNzEyMjA0NmEyMTA3MjAwNDA0NDAyMDAzMjEwMjAzNDAyMDAyNDEwMDNhMDAwMDIwMDI0MTAxNmEyMjAyMjAwNzQ5MGQwMDBiMGIyMDA3NDFjMDAwMjAwNDZiMjIwNTQxN2M3MTIyMDQ2YTIxMDIyMDA0NDEwMDRhMDQ0MDAzNDAyMDA3NDEwMDM2MDIwMDIwMDc0MTA0NmEyMjA3MjAwMjQ5MGQwMDBiMGIyMDA1NDEwMzcxMjIwNDA0NDAyMDAyMjAwNDZhMjEwNDAzNDAyMDAyNDEwMDNhMDAwMDIwMDI0MTAxNmEyMjAyMjAwNDQ5MGQwMDBiMGIyMDA2MjAwMzAyN2YyMDAxMDQ0MDIwMDFhZDIxMTY0MTNmMjEwMTAyNDAwMzQwMjAxNjUwMGQwMTIwMDE0MTNmNGQwNDQwMjAwMTIwMDM2YTIwMTYyMDE2NDIwYTgwMjIxNjQyMGE3ZTdkYTc0MTMwNzIzYTAwMDAyMDAxNDEwMTZiMjEwMTBjMDEwYjBiMTAyYzAwMGIyMDAxNDEwMTZhMGMwMTBiMjAwMzQxMzAzYTAwM2Y0MTNmMGIyMjAxNmE0MWMwMDAyMDAxNmIxMGEzMDEyMDAzNDE0MDZiMjQwMDIwMDAyODAyODAwMjIwMDAyZDAwODQwMjEwMzgxMDAwMDAwYjIwMDAyMDAxMzYwMmNjMDExMDdkMjEwMjEwN2QyMTA0MjAwMDIwMDExMDEyMzYwMmQ4MDEyMDAwNDEwMDM2MDJkNDAxMjAwMDIwMDA0MWNjMDE2YTM2MDJkMDAxMDI0MDAzNDAwMjQwMjAwMDQxODAwMjZhMjAwMDQxZDAwMTZhMTA2NzIwMDAyOTAzODAwMjUwMGQwMDIwMDAyODAyOTQwMjIxMDUyMDAyMjEwMzIwMDAyODAyOTAwMjIyMDEyMDBjMTAzMDQ1MDQ0MDIwMDQyMTAzMjAwMTIwMDgxMDMwNDUwZDAzMGIyMDAzMjAwNTEwOGYwMTBjMDEwYjBiMjAwODEwMmYyMTBjNDIwMDIxMTYyMDA2MjEwMTBjMDEwYjBiMGI0MTg3ODYwODQxMjExMDQxMDAwYjQxYTU4YTA4NDExNTEwNDEwMDBiMjAwMDQxODA4MDgwMjAzNjAyZDAwMTIwMDYyMDAwNDFkMDAxNmE0MTA0MTAwZjFhMjAwNjQxZWQ4NTA4NDEwNDEwMGYxYTBiMjAwMDQyMDAzNzAzZDAwMTIwMDYyMDAwNDFkMDAxNmEyMjAzNDEwODEwMGYxYTIwMDUyMDA2MTAzZjIwMDQyMDA2MTA0ZTEwYzcwMTEwNDMyMjAxNDE4YThkMDg0MTA4MTA0ZDEwNGUyMDAyMTA0MzEwMmYyMjAyMTAzZjIwMDIxMDNmMjAwMTIwMDIxMDI0MjAwMDIwMDQzNjAyZDAwMTIwMDAyMDA0MTAxMjM2MDI4ODAyMjAwMDQxMDAzNjAyODQwMjIwMDAyMDAzMzYwMjgwMDIwMzQwMjAwMDIwMDA0MTgwMDI2YTEwYzQwMTIwMDAyODAyMDAwNDQwMjAwMDI4MDIwNDEwMDcxYTBjMDEwYjBiMjAwMDQxYTAwMjZhMjQwMDBmMGI0MWJhOGEwODQxMWExMDQxMDAwYjBkMDAxMDIyNDEwMDEwNWExMGM3MDExMDI1MGIwZDAwMTAyMjQxMDAxMDVhMTBkMTAxMTA1YjBiMGQwMDEwMjI0MTAwMTA1YTEwZDQwMTEwNWQwYjBkMDAxMDIyNDEwMDEwNWExMGQ4MDExMDVkMGIyYTAxMDE3ZjEwMjI0MTAwMTA1YTEwY2IwMTEwYWIwMTIyMDA0MWZlZmZmZmZmMDc0NzA0NDAyMDAwMTAwNzFhMGYwYjQxZWQ4NTA4NDEwNDEwMjYwYjBkMDAxMDIyNDEwMDEwNWExMGRhMDExMDVkMGIwZDAwMTAyMjQxMDAxMDVhMTBjODAxMTA1YjBiMGQwMDEwMjI0MTAwMTA1YTEwYzkwMTEwNWIwYjBkMDAxMDIyNDEwMDEwNWExMGNjMDExMDViMGIwZDAwMTAyMjQxMDAxMDVhMTBkOTAxMTA1ZDBiMGQwMDEwMjI0MTAwMTA1YTEwZDIwMTEwNWIwYmExMDEwMTAyN2YyMzAwNDE0MDZhMjIwMDI0MDAxMDIyNDEwMTEwNWEyMDAwNDEwMDEwNGIzNjAyMTQyMDAwMjAwMDQxMTQ2YTEwZDYwMTEwYWMwMTIyMDEzNjAyMTgyMDAwNDEwODZhMTAzNTIwMDAyMDAwMmQwMDBjM2EwMDIwMjAwMDIwMDAyODAyMDgzNjAyMWMyMDAwMjAwMTEwMTIzNjAyMmMyMDAwNDEwMDM2MDIyODIwMDAyMDAwNDExODZhMzYwMjI0MjAwMDQxMzQ2YTIxMDEwMzQwMjAwMDQxMzA2YTIwMDA0MTI0NmExMGJhMDEyMDAwMjgwMjMwMDQ0MDIwMDEyMDAwNDExYzZhMTBiYjAxMGMwMTBiMGIyMDAwMjgwMjFjMjAwMDJkMDAyMDEwMzcyMDAwNDE0MDZiMjQwMDBiYTAwMTAxMDI3ZjIzMDA0MTQwNmEyMjAwMjQwMDEwMjI0MTAxMTA1YTIwMDA0MTAwMTA0YjM2MDIxNDIwMDAyMDAwNDExNDZhMTBkNTAxMTBiMjAxMjIwMTM2MDIxODIwMDA0MTA4NmExMDM1MjAwMDIwMDAyZDAwMGMzYTAwMjAyMDAwMjAwMDI4MDIwODM2MDIxYzIwMDAyMDAxMTAxMjM2MDIyYzIwMDA0MTAwMzYwMjI4MjAwMDIwMDA0MTE4NmEzNjAyMjQwMzQwMjAwMDQxMzA2YTIwMDA0MTI0NmExMGI1MDEyMDAwMmQwMDNjNDEwMjQ3MDQ0MDIwMDA0MTMwNmEyMDAwNDExYzZhMTBiNjAxMGMwMTBiMGIyMDAwMjgwMjFjMjAwMDJkMDAyMDEwMzcyMDAwNDE0MDZiMjQwMDBiMGQwMDEwMjI0MTAwMTA1YTEwZDMwMTEwNWUwYjBkMDAxMDIyNDEwMDEwNWExMGQ3MDExMDVlMGJlMzAzMDIwNTdmMDI3ZTIzMDA0MTkwMDE2YjIyMDAyNDAwMTA0OTQxMDAxMDVhMjAwMDEwNGEyMjAxMzYwMjE0MDI0MDIwMDExMDY1NDEwMTQ2MDQ0MDIwMDExMDEyMjEwMTIwMDA0MTAwMzYwMjM0MjAwMDIwMDEzNjAyMzAyMDAwNDEwMDM2MDIyYzIwMDAyMDAwNDExNDZhMzYwMjI4MjAwMDQxM2M2YTIxMDIyMDAwNDFmNDAwNmEyMTAzMjAwMDQxZjgwMDZhMjEwMTAzNDAyMDAwNDFmMDAwNmEyMDAwNDEyODZhMTA2NzIwMDAyOTAzNzA1MDBkMDIyMDAwNDFlMDAwNmEyMDAxNDEwODZhMjkwMzAwMjIwNTM3MDMwMDIwMDAyMDAxMjkwMzAwMjIwNjM3MDM1ODIwMDAyMDAwMjgwMjM0MjIwNDQxMDE2YTM2MDIzNDIwMDM0MTA4NmEyMDA1MzcwMjAwMjAwMzIwMDYzNzAyMDAyMDAwNDE0MDZiMjAwMTI5MDIwMDM3MDMwMDIwMDA0MWM4MDA2YTIwMDA0MTgwMDE2YTI4MDIwMDM2MDIwMDIwMDAyMDAwMjkwMjcwMzcwMzM4MjAwNDQ1MDQ0MDIwMDA0MTIwNmEyMDAyNDEwODZhMjkwMjAwMzcwMzAwMjAwMDIwMDIyOTAyMDAzNzAzMTgwYzAxMGIwYjEwMmMwMDBiNDFiMzgzMDg0MTIyMTAwMzAwMGIyMDAwNDEwODZhMjIwMTIwMDA0MTIwNmEyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDMxODM3MDMwMDEwZGEwMTEwYTcwMTIxMDIyMDAxMjgwMjAwMjAwMjEwMzA0NTA0NDA0MTk4OGEwODQxMGQxMDQxMDAwYjEwZDIwMTEwNWMyMTAyMjAwMDEwNDMzNjAyMTgyMDAwMTA0MzM2MDIyODIwMDA0MWYwMDA2YTIyMDEyMDAyMTAzMjQxYTc4MzA4NDEwNTEwMzMyMDAwMjgwMjc0MjIwMjIwMDA0MTE4NmExMDdiMjAwMjIwMDA0MTI4NmExMDdhMjAwMDQxZTgwMDZhMjAwMDQxODAwMTZhMjkwMzAwMzcwMzAwMjAwMDQxZTAwMDZhMjAwMDQxZjgwMDZhMjkwMzAwMzcwMzAwMjAwMDIwMDAyOTAzNzAzNzAzNTgyMDAwNDEzODZhMjIwMjIwMDA0MWQ4MDA2YTIwMDAxMDg0MDEyMDAxMjAwMjEwY2QwMTIwMDExMDc0MjAwMDQxOTAwMTZhMjQwMDBiOGMwMTAxMDI3ZjIzMDA0MTQwNmEyMjAwMjQwMDEwNDk0MTAwMTA1YTEwZDIwMTEwNWMyMTAxMjAwMDEwNDMzNjAyMDAyMDAwMTA0MzM2MDIwNDIwMDA0MTA4NmEyMDAxMTAzMjQxOTU4MzA4NDExMjEwMzMyMDAwMjgwMjBjMjIwMTIwMDAxMDdiMjAwMTIwMDA0MTA0NmExMDdhMjAwMDQxMzA2YTIwMDA0MTE4NmEyOTAzMDAzNzAzMDAyMDAwNDEyODZhMjAwMDQxMTA2YTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzA4MzcwMzIwMjAwMDEwN2QzNjAyMzgyMDAwNDEyMDZhMTA3NDIwMDA0MTQwNmIyNDAwMGJmZjAxMDIwNTdmMDE3ZTIzMDA0MTMwNmIyMjAwMjQwMDEwMjIxMDQ5NDEwMTEwNWEyMDAwMTA0ZjM2MDIxMDEwZDIwMTEwNWMyMDAwMTA0MzM2MDIxNDIwMDAxMDQzMzYwMjE4MTAzMjIxMDI0MWFjODMwODQxMDcxMDRkMjEwMzEwNDMyMjAxMjAwMDQxMTA2YTEwNzgyMDAxMjAwMDQxMTQ2YTEwN2IyMDAxMjAwMDQxMTg2YTEwN2ExMDdkMjEwNDEwMTYyMDAyMjAwNDIwMDMyMDAxMTA0NTIxMDExMDE3MjAwMTEwMTIyMTAyMjAwMDQxMDAzNjAyMjQyMDAwMjAwMTM2MDIxYzIwMDAyMDAyNDEwMjc2MzYwMjIwMjAwMDQxMWM2YTEwNzUyMTAxMjAwMDQyMDAzNzAzMjgyMDAxMTAxMjIyMDI0MTA5NDkwNDQwMDI0MDIwMDA0MTA4NmEyMDAwNDEyODZhMjAwMjEwYjAwMTIwMDE0MTAwMjAwMDI4MDIwODIyMDEyMDAwMjgwMjBjMjIwMjEwOGEwMTFhMjAwMTIwMDIxMGIxMDEyMjA1NDI4MDgwODA4MDEwNWEwZDAwMjAwNTEwMTQyMDAwNDEzMDZhMjQwMDBmMGIwYjQxOGE4NTA4NDEwYjQxOTU4NTA4NDEwZTEwNGMwMDBiOTgwMzAyMDU3ZjAxN2UyMzAwNDFlMDAwNmIyMjAwMjQwMDEwMjIxMDQ5NDFlNGRiMDgxMDEzMzYwMjAwNDFlNGRiMDgyODAyMDA0MTAwNDgwNDQwNDFlZjgzMDg0MTExMTAwMzAwMGIyMDAwNDEwMDM2MDIzODEwNDMyMTAzMjAwMDQxMzg2YTIyMDQyODAyMDAyMTAxMDM0MDQxZTRkYjA4MjgwMjAwMjAwMTRhMDQ0MDIwMDQyMDAxNDEwMTZhMjIwMjM2MDIwMDIwMDMyMDAxMTA0YjEwNGUyMDAyMjEwMTBjMDEwYjBiMjAwMzIxMDE0MWU0ZGIwODI4MDIwMDIwMDAyODAyMzg0YTA0NDA0MTgwODQwODQxMTIxMDAzMDAwYjIwMDAyMDAxMzYwMjFjMjAwNDEwZDIwMTEwNWMxMDMyNDFmOTgyMDg0MTBkMTAzMzIwMDAyMDAxMTAxMjM2MDI1YzIwMDA0MTAwMzYwMjU4MjAwMDIwMDA0MTFjNmEzNjAyNTQyMDAwMjgwMjNjMjEwMTAzNDAyMDAwNDExMDZhMjAwMDQxZDQwMDZhMTBjNDAxMjAwMDI4MDIxMDA0NDAyMDAxMjAwMDI4MDIxNDEwNmUwYzAxMGIwYjIwMDA0MTI4NmEyMDAwNDE0MDZiMjkwMzAwMzcwMzAwMjAwMDQxMzA2YTIwMDA0MWM4MDA2YTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzM4MzcwMzIwMjAwMDQxMzg2YTIwMDA0MTIwNmExMDdlMDI0MDIwMDAyODAyNDQyMjAxMTBjZTAxNDUwNDQwMjAwMDI4MDI0MDIxMDIwYzAxMGIxMDQ2MjAwMDI4MDI0MDIyMDI0MjAwMjAwMTEwNDIwYjIwMDAyOTAzMzgyMDAwNDEwODZhMTAzNTIwMDAyMDAwMmQwMDBjM2EwMDNjMjAwMDIwMDAyODAyMDgzNjAyMzgyMDAyMjAwMDQxMzg2YTIyMDIxMDNlMjAwMjEwYzYwMTIwMDEyMDAyMTAzYzIwMDAyODAyMzgyMDAwMmQwMDNjMTAzNzIwMDA0MWUwMDA2YTI0MDAwYjMxMDEwMTdlMTAyMjEwNDk0MTAxMTA1YTQxMDAxMDExMjIwMDQyODE4MDkwYmJiYWQ2YWRmMDBkNWEwNDQwNDFlZjhiMDg0MTIwMTA0MTAwMGIxMGQ3MDEyMDAwMTBhYTAxMGIzMTAxMDE3ZTEwMjIxMDQ5NDEwMTEwNWE0MTAwMTAxMTIyMDA0MjgxODA5MGJiYmFkNmFkZjAwZDVhMDQ0MDQxZDI4YjA4NDExZDEwNDEwMDBiMTBkMzAxMjAwMDEwYWEwMTBiZTMwMTAxMDM3ZjIzMDA0MTMwNmIyMjAwMjQwMDEwMjIxMDQ5NDEwMjEwNWE0MTAwMTA1ODIxMDEyMDAwNDEwMTEwNTEyMjAyMzYwMjBjMjAwMDIwMDEzNjAyMDgyMDAwMjAwMTEwMTIzNjAyMTgyMDAwNDEwMDM2MDIxNDIwMDAyMDAwNDEwODZhMzYwMjEwMDM0MDIwMDA0MTFjNmEyMDAwNDExMDZhMTBjMzAxMjAwMDI4MDIxYzA0NDAyMDAwMjAwMDI4MDIyNDIyMDEzNjAyMmMyMDAwMjAwMDI4MDIyMDM2MDIyODIwMDA0MTI4NmExMGQ2MDEyMDAxMTBiOTAxMGMwMTA1MjAwMDIwMDIxMDEyMzYwMjE4MjAwMDQxMDAzNjAyMTQyMDAwMjAwMDQxMGM2YTM2MDIxMDAzNDAyMDAwNDExYzZhMjAwMDQxMTA2YTEwYzMwMTIwMDAyODAyMWMwNDQwMjAwMDIwMDAyODAyMjQyMjAxMzYwMjJjMjAwMDIwMDAyODAyMjAzNjAyMjgyMDAwNDEyODZhMTBkNTAxMjAwMTEwYjQwMTBjMDEwYjBiMjAwMDQxMzA2YTI0MDAwYjBiMGJhYTA3MDIwYjdmMDE3ZTIzMDA0MTMwNmIyMjAwMjQwMDEwMjI0MTAwMTA1YTEwYzkwMTEwNWMyMjA5MTAyZjEwMzIyMTAxNDFkMjgxMDg0MTE0MTA0ZDIxMDIxMDQzMjEwNjEwN2QyMTA3MTAxNjIwMDEyMDA3MjAwMjIwMDYxMDQ1MjEwMTEwMTcyMDAxMTAxMjIxMDIyMDAwNDEwMDM2MDIxMDIwMDAyMDAxMzYwMjA4MjAwMDIwMDI0MTAyNzYzNjAyMGMyMDAwNDEwODZhMTA3NTIyMDIxMDEyMjEwMTIwMDA0MTI4NmE0MTAwM2EwMDAwMjAwMDQxMjQ2YTIwMDEzNjAyMDAyMDAwMjAwMjM2MDIyMDIwMDAyMDAxMzYwMjFjMjAwMDQxMDAzNjAyMTgwMjQwMDI3ZjAyNDAwMjQwMjAwMTQ1MGQwMDAyNDAwMjQwMDI0MDIwMDA0MTE4NmE0MThhODUwODQxMGIxMDU0NDFmZjAxNzEwZTAyMDIwMTAwMGI0MThhODUwODQxMGI0MWVkODYwODQxMGQxMDRjMDAwYjQxMDEyMTAzMjAwMDQxMTg2YTQxOGE4NTA4NDEwYjEwNTMyMTAxMGIyMDAwMjgwMjFjMjAwMDI4MDIxODQ3MGQwMzIwMDAyZDAwMjgwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAzNDUwZDAwMjAwMDQxMTg2YTIyMDQyMDAxMTAyZjEwMzI0MWU0ODIwODQxMTUxMDMzMjAwMDIwMDQxMDdjMjIwMzM2MDIwMDIwMDQyMDAxMTAyZjEwMzI0MWIyODIwODQxMGIxMDMzMjAwMDQxMTg2YTEwN2M0MmJlOGE4NjBmMTAyZTEwOGUwMTIxMDYyMDA0MjAwMTEwMmYxMDMyNDFjOTgyMDg0MTBkMTAzMzIwMDA0MTE4NmExMDdjMjAwMzEwOTIwMTQyYmU4YTg2MGYxMDJlMTA4ZTAxNDEwYTEwMmQ0MTEyMTA5NDAxMTA4ZDAxMjEwNzIwMDQyMDAxMTAyZjEwMzI0MWJkODIwODQxMGMxMDMzMjAwMDQxMTg2YTEwN2M0MTBhMTAyZDQxMTIxMDk0MDEyMDAzMTA5MDAxMTA4ZTAxNDJiZThhODYwZjEwMmUxMDhlMDE0MTBhMTAyZDQxMTIxMDk0MDExMDhkMDEyMTBhMjAwNDIwMDkxMDJmMjIwMjEwMmYxMDMyNDE4NzgxMDg0MTBmMTAzMzIwMDAyMDAwNDExODZhMTA3YzIyMDUzNjAyMTQyMDA0MjAwMjEwMmYxMDMyNDFhYjgyMDg0MTA3MTAzMzIwMDA0MTE4NmExMDdjMjEwODIwMDQyMDAyMTAzMjQxYTY4MTA4NDExMDEwMzMyMDAwNDExODZhMTA3YzIxMDIyMDAwMjAwODIwMDUxMDkxMDEyMDAyMTA5MDAxMzYwMjA4MjAwNDIwMDExMDMyNDFkNjgyMDg0MTBlMTAzMzIwMDAyODAyMWMyMjAxMjAwMDQxMTQ2YTEwNzgyMDAxMjAwMDQxMDg2YTEwNzgyMDAwMjgwMjI4MjEwMjIwMDAyODAyMTgyMTA1MjAwMDI5MDMyMDEwN2QyMTA4MTA3MTIwMDIyMDA4MjAwNTIwMDExMDQ1MjEwMTEwMTcyMDAwMjAwMTEwNzMzNjAyMDQ0MjgwODA5MGJiYmFkNmFkZjAwZDEwMmUyMTAyMjAwMDEwN2QzNjAyMTgyMDAwNDEwNDZhMjAwNDEwY2YwMTIxMDUxMDdkMjIwMTIwMDUwZDAyMWEyMDAxMjAwMDI4MDIwNDEwODkwMTQxMDE2YTQxZmYwMTcxNDEwMTRkMDQ0MDIwMDA0MTA0NmEyMDAwMTBjZjAxMGQwMjIwMDAyODAyMDAyMTAzMGIyMDAwMjgwMjA0MjAwMzEwOTMwMTIwMGExMDhlMDEyMTAxNDEwYTEwMmQ0MTEyMTA5NDAxMjAwMDI4MDIwMDEwOTAwMTIxMDMyMDA2MjAwMjEwOTIwMTIwMDcyMDAyMTA5MjAxMTA4YzAxMjAwMTIwMDIxMDhlMDEyMDAzMTA4ZDAxMTA4YzAxMGMwMjBiNDFhMDhiMDg0MTMyMTA0MTAwMGIyMDAwMjgwMjA0MjAwNzEwOTIwMTIxMDEyMDA2MjAwMjEwOTIwMTIwMDEyMDAyMTA4ZTAxMjAwMDI4MDIwMDEwOGQwMTEwOGMwMTBiMjEwMTIwMDA0MTE4NmEyMjAzMjAwOTEwMzI0MTk2ODEwODQxMTAxMDMzMjAwMzEwN2MyMTAyNDEwYTEwMmQ0MTEyMTA5NDAxMjEwMzIwMDAyODAyMDQyMDAxMTA5MjAxMjAwMzIwMDIxMDkzMDExMDhlMDEyMDAzNDEwMzEwOTQwMTEwOGQwMTEwMjUyMDAwNDEzMDZhMjQwMDBmMGI0MThhODUwODQxMGI0MTk1ODUwODQxMGUxMDRjMDAwYjAzMDAwMTBiM2MwMTAxN2YyMzAwNDExMDZiMjIwNTI0MDAyMDA1NDEwODZhMjAwMTIwMDQyMDAyMjAwMzEwOWQwMTIwMDUyODAyMGMyMTAxMjAwMDIwMDUyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTEwNmEyNDAwMGIzYjAxMDE3ZjIzMDA0MTEwNmIyMjA1MjQwMDIwMDU0MTA4NmEyMDAyMjAwMzIwMDEyMDA0MTAyYjIwMDUyODAyMGMyMTAxMjAwMDIwMDUyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTEwNmEyNDAwMGIwYmRhMGQwMjAwNDE4MDgwMDgwYmM2MGQ0ZTZmMjA3Mzc3NjE3MDIwNmY3MDY1NzI2MTc0Njk2ZjZlMjA2NjZmNzU2ZTY0MjA2MTc0MjA2OTZlNjQ2NTc4MjA3NTZlNzc3MjYxNzA0NTY3NmM2NDY3NjU3NDU3NzI2MTcwNzA2NTY0NDU2NzZjNjQ1NDZmNmI2NTZlNDk2NDc3NzI2MTcwNDU2NzZjNjQ3MjY1NjM2OTcwNjk2NTZlNzQyMDYxNjQ2NDcyNjU3MzczMjA2ZTZmNzQyMDczNjU3NDY1Nzg2OTc0NGQ2MTcyNmI2NTc0NjM2YzYxNjk2ZDUyNjU3NzYxNzI2NDczNjc2NTc0NDE2MzYzNmY3NTZlNzQ1NDZmNmI2NTZlNzM2NzY1NzQ1NDZmNzQ2MTZjNDI2ZjcyNzI2Zjc3NzM2NzY1NzQ1MjY1NzM2NTcyNzY2NTQ2NjE2Mzc0NmY3MjY3NjU3NDU0NmY3NDYxNmM1MjY1NzM2NTcyNzY2NTczNjc2NTc0NTQ2ZjZiNjU2ZTQ5NjQ2ZDY5NmU3NDQxNmU2NDQ1NmU3NDY1NzI0ZDYxNzI2YjY1NzQ2NzY1NzQ0OTZlNzQ2NTcyNjU3Mzc0NTI2MTc0NjU0ZDZmNjQ2NTZjNjc2NTc0NTU2ZTY0NjU3MjZjNzk2OTZlNjc0OTY0NzQ2ZjZiNjU2ZTczNTQ2ZjU1NmU2NDY1NzI2Yzc5Njk2ZTY3NDE2ZDZmNzU2ZTc0NzU2ZTY0NjU3MjZjNzk2OTZlNjc0MTZkNmY3NTZlNzQ1NDZmNTQ2ZjZiNjU2ZTczNzI2NTY0NjU2NTZkNjc2NTc0NDM2MTczNjg2NzY1NzQ0MjYxNzM2NTUyNjE3NDY1Njc2NTc0NGM2MTczNzQ1MzZjNmY3MDY1Njc2NTc0NDY2OTcyNzM3NDUzNmM2ZjcwNjU2NzY1NzQ1NTc0Njk2YzY5N2E2MTc0Njk2ZjZlNjc2NTc0NGY3MDc0Njk2ZDYxNmM1NTc0Njk2YzY5N2E2MTc0Njk2ZjZlNjM2YzYxNjk2ZDRkNzU2Yzc0Njk3MDZjNjU2NzY1NzQ1Mzc0NjE2YjY1NTQ2ZjZiNjU2ZTQ5NjQ3MjY1NjI2MTZjNjE2ZTYzNjU1MDZmNzI3NDY2NmY2YzY5NmY3Mzc0NjE2YjY1NzU2ZTczNzQ2MTZiNjU2OTZlNjM2ZjcyNzI2NTYzNzQyMDZlNzU2ZDYyNjU3MjIwNmY2NjIwNDU1MzQ0NTQyMDc0NzI2MTZlNzM2NjY1NzI3MzYxNzI2Nzc1NmQ2NTZlNzQyMDY0NjU2MzZmNjQ2NTIwNjU3MjcyNmY3MjIwMjgyOTNhMjA3NDZmNmYyMDY2NjU3NzIwNjE3MjY3NzU2ZDY1NmU3NDczNzQ2ZjZmMjA2ZDYxNmU3OTIwNjE3MjY3NzU2ZDY1NmU3NDczNzc3MjZmNmU2NzIwNmU3NTZkNjI2NTcyMjA2ZjY2MjA2MTcyNjc3NTZkNjU2ZTc0NzM2MzYxNmU2ZTZmNzQyMDczNzU2Mjc0NzI2MTYzNzQyMDYyNjU2MzYxNzU3MzY1MjA3MjY1NzM3NTZjNzQyMDc3NmY3NTZjNjQyMDYyNjUyMDZlNjU2NzYxNzQ2OTc2NjU0ZDc1NmM3NDY5NDU1MzQ0NTQ0ZTQ2NTQ1NDcyNjE2ZTczNjY2NTcyNDU1MzQ0NTQ0ZTQ2NTQ1NDcyNjE2ZTczNjY2NTcyNDU1MzQ0NTQ1NDcyNjE2ZTczNjY2NTcyNzM3OTZlNjMyMDcyNjU3Mzc1NmM3NDY5NmU3MDc1NzQyMDc0NmY2ZjIwNmM2ZjZlNjc2OTZlNzA3NTc0MjA3NDZmNmYyMDczNjg2ZjcyNzQ2MzYxNzM3NDIwNzQ2ZjIwNjkzNjM0MjA2NTcyNzI2ZjcyNGQ2MTZlNjE2NzY1NjQ1NjY1NjMyMDY5NmU2NDY1NzgyMDZmNzU3NDIwNmY2NjIwNzI2MTZlNjc2NTQ1NTM0NDU0MjA2NTc4NzA2NTYzNzQ2NTY0NDU0NzRjNDQ3Mzc0NmY3MjYxNjc2NTIwNjQ2NTYzNmY2NDY1MjA2NTcyNzI2ZjcyM2EyMDc1NmU2YjZlNmY3NzZlMjA3MjY1NjM2NTY5NzY2NTY0MjA3NDZmNmI2NTZlMjA2MTY2NzQ2NTcyMjA3Mzc3NjE3MDY1Nzg2MzY4NjE2ZTY3NjU2MjYxNjQyMDYxNzI3MjYxNzkyMDZjNjU2ZTY3NzQ2ODc3NzI2ZjZlNjcyMDcyNjU3NDc1NzI2ZTY1NjQyMDczNzc2MTcwMjA3NDZmNmI2NTZlNzM3NzYxNzA1NDZmNmI2NTZlNzM0NjY5Nzg2NTY0NDk2ZTcwNzU3NDY5NmU3NjYxNmM2OTY0MjA3NjYxNmM3NTY1Nzc3MjYxNzA3MDY1NjQ1ZjY1Njc2YzY0NWY2MzZmNmU3NDcyNjE2Mzc0NWY2MTY0NjQ3MjY1NzM3MzYzNmY2ZDcwNmY3NTZlNjQ1ZjYxNzM2ODczNzc2MTcwNWY3Mzc3NjE3MDczNjM2ZjZkNzA2Zjc1NmU2NDVmNzg2NTc4NjM2ODYxNmU2NzY1NWY3Mzc3NjE3MDczNzA2NTcyNjY2ZjcyNmQ2MTZlNjM2NTVmNjY2NTY1NzM1ZjcwNjU3MjYzNjU2ZTc0NjM2ZjZkNzA2Zjc1NmU2NDVmNjY2NTY1NzM1ZjcwNjU3MjYzNjU2ZTc0NjI2ZjZmNzM3NDY1NzI1ZjYxNjQ2NDcyNjU3MzczNmQ2ZjZlNjU3OTVmNmQ2MTcyNmI2NTc0NWY2MTY0NjQ3MjY1NzM3MzYzNmY2ZTc0NzI2ZjZjNmM2NTcyNWY2MTY0NjQ3MjY1NzM3MzYxNzM3MzY1NzQ1Zjc0NmY2YjY1NmU1ZjY5NjQ2NTZlNzQ2OTY2Njk2NTcyNzY2MTc1NmM3NDVmNjE2NDY0NzI2NTczNzM3MDYxNzk2ZDY1NmU3NDIwNzM2ODZmNzU2YzY0MjA2MjY1MjA2MTZlMjA0NTUzNDQ1NDIwNzQ2ZjZiNjU2ZTU0Njg2NTIwNjE3MzczNjU3NDIwNzQ2ZjZiNjU2ZTIwNjk2NDY1NmU3NDY5NjY2OTY1NzIyMDYxNmU2NDIwNzQ2ODY1MjA2ZDZmNmU2NTc5MjA2ZDYxNzI2YjY1NzQyMDc1NmU2NDY1NzI2Yzc5Njk2ZTY3MjA2OTY0NjU2ZTc0Njk2NjY5NjU3MjIwNjQ2ZjZlMjc3NDIwNmQ2MTc0NjM2ODU3Njg2NTZlMjA3NDYxNzI2NzY1NzQ2OTZlNjcyMDYxNmUyMDQ1NDc0YzQ0MjA2ZDYxNzI2YjY1NzQyMDc0Njg2NTIwNjE3MzczNjU3NDIwNzQ2ZjZiNjU2ZTIwNjk2NDY1NmU3NDY5NjY2OTY1NzIyMDczNjg2Zjc1NmM2NDIwNjI2NTIwNTc0NTQ3NGM0NDQzNjE2YzZjNjU3MjIwNzM2ODZmNzU2YzY0MjA2MjY1MjA3NjYxNzU2Yzc0Nzc3MjZmNmU2NzIwNzA2MTc5NmQ2NTZlNzQ2ZTZmMjA3MjY1Nzc2MTcyNjQyMDc0NmYyMDYzNmY2ZDcwNmY3NTZlNjQ2ZTZmMjA2YzY1NjY3NDIwNjE2ZDZmNzU2ZTc0MjA3NDZmMjA2MzZmNmQ3MDZmNzU2ZTY0Nzc3MjZmNmU2NzIwNzM3NzYxNzA3MDY1NjQyMDc0NmY2YjY1NmU2ZTZmMjA2NTc4Njk3NDIwNmQ2MTcyNmI2NTc0MjA3MDYxNzk2ZDY1NmU3NDIwNzI2NTYzNjU2OTc2NjU2NDZlNmYyMDcyNjU2NDY1NjU2ZDIwNzA2MTc5NmQ2NTZlNzQyMDcyNjU2MzY1Njk3NjY1NjQ0ZTZmMjA2OTZlNzQ2NTcyNjU3Mzc0MjA3MjYxNzQ2NTIwNmQ2ZjY0NjU2YzIwNzA3MjY1NzM2NTZlNzQyMDZmNmUyMDc0Njg2NTIwNmQ2ZjZlNjU3OTIwNmQ2MTcyNmI2NTc0NmU2NTc3MjA2MzZmNmQ3MDZmNzU2ZTY0MjA2NjY1NjU3MzIwNjU3ODYzNjU2NTY0MjAzMTMwMzAyNTZlNjU3NzIwNzA2NTcyNjY2ZjcyNmQ2MTZlNjM2NTIwNjY2NTY1NzMyMDY1Nzg2MzY1NjU2NDIwMzEzMDMwMjU2ZDZmNmU2NTc5NWY2ZDYxNzI2YjY1NzQ1Zjc0NmY2YjY1NmU1ZjY5NjQ2NTZlNzQ2OTY2Njk2NTcyNzc3MjYxNzA3MDY1NjQ1ZjY1Njc2YzY0NWY3NDZmNmI2NTZlNWY2OTY0NjU2ZTc0Njk2NjY5NjU3MjYyNmY2ZjczNzQ2NTcyNWY3Mzc0NjE2YjY1NjQ1Zjc0NmY2YjY1NmU1ZjY5NjQ2NTZlNzQ2OTY2Njk2NTcyNmQ2ZjZlNjU3OTVmNmQ2MTcyNmI2NTc0NWY3NTZlNjQ2NTcyNmM3OTY5NmU2NzVmNjk2NDY1NmU3NDY5NjY2OTY1NzI2MzZmNmQ3MDZmNzU2ZTY0NDU2ZTY0NzA2ZjY5NmU3NDIwNjM2MTZlMjA2ZjZlNmM3OTIwNjI2NTIwNjM2MTZjNmM2NTY0MjA2Mjc5MjA2Zjc3NmU2NTcyMDAwMDcwNjE2ZTY5NjMyMDZmNjM2Mzc1NzI3MjY1NjQwMDQxYzg4ZDA4MGIwNDljZmZmZmZmQDA1MDBAMDEwMEAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwQDU3NDU0NzRjNDQyZDYxMzIzODYzMzUzOUAwMDAwMDAwMDAwMDAwMDAwMDUwMGEzYjY2NjkwMmQ1ZjRiYmYwZmY5Mzc0OGZiOTE1YWViNDMxMjRjYmY2NTA5QDAwMDAwMDAwMDAwMDAwMDAwNTAwMzJkZTRmNDBmMTdhMmY0MWM0ZTQwYzIxZjU5NmUzNmE4NDY5OTRlMzY1MDlAMDAwMDAwMDAwMDAwMDAwMDA1MDBmODgzNjY4NmY3YzZjMGYxM2Q3Mjc1MTUxYjc4ZjU5ZjhmMmY3MjlhNjUwOUBAQEBAMDAwMDAwMDAwMDAwMDAwMDA1MDAwYjFlNWIyNDQzMjUwOTU4NDlmNGUzNzEzNDY2MWQ1YmZkY2Q5MjVlN2NlYg==", - "signature": "edf0ec99b6f60414fa5e36d40cfb1d0075d01fd7c4ad7ba59bbe62b8b48eb892beb0c18bba203ff32b83827c3953847b190cdc89a4806f4615565dc2b3b5940f", - "sourceShard": 1, - "destinationShard": 1, - "blockNonce": 2127577, - "blockHash": "e3aea17b5345b45f61b233834d3b4ba0ac6f2b7d53eb3f1b1cf2bf0534ba567f", - "notarizedAtSourceInMetaNonce": 2129029, - "NotarizedAtSourceInMetaHash": "73ee8458f55bf5c9ea4a9974c0c838ced51a236c2b13238761f444598f40575e", - "notarizedAtDestinationInMetaNonce": 2129029, - "notarizedAtDestinationInMetaHash": "73ee8458f55bf5c9ea4a9974c0c838ced51a236c2b13238761f444598f40575e", - "miniblockType": "TxBlock", - "miniblockHash": "cc7e81e68269c2c633daf997fd2d52fc82d8ba3bb699d7e75250008bd9b7aa29", - "hyperblockNonce": 2129029, - "hyperblockHash": "73ee8458f55bf5c9ea4a9974c0c838ced51a236c2b13238761f444598f40575e", - "timestamp": 1707144290, - "status": "success", - "operation": "scDeploy", - "initiallyPaidFee": "82333950000000000", - "chainID": "D", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" -} - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - let opt_address = tx_response.new_deployed_address.map(|e| { - multiversx_sdk::data::address::Address::from_bytes(*e.as_array()) - .to_bech32_string() - .unwrap() - }); - - let expected = - Some("erd1qqqqqqqqqqqqqpgqwpdf84ggxzqzmr2zmw959q4nlf9nz562q33sak25ze".to_string()); - - assert_eq!(opt_address, expected) - } - - #[test] - fn test_deployed_address_should_be_none_if_not_a_sc_deployment_tx() { - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "BuiltInFunctionCall", - "processingTypeOnDestination": "SCInvoking", - "hash": "238ad6dbe75dab1d53caeb9cabd584aabc6fc113c849a983afef5a5e439ce9e5", - "nonce": 13, - "round": 2192628, - "epoch": 888, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgqydwpdrplefjlwp3sp9xmn3vevdxdelfkwmfsw6e5xw", - "sender": "erd179xw6t04ug48m74jzyw9zq028hv66jhqayelzpzvgds0ptnzmckq2jf07f", - "gasPrice": 1000000000, - "gasLimit": 20000000, - "data": "RVNEVFRyYW5zZmVyQDRmNTU1MjRmMmQ2NDM4MzEzNzMxNjZAMDI0NmQyZDBiNmI1ZjBANjI3NTc5QDFiYzE2ZDY3NGVjODAwMDA=", - "signature": "ce984b4d785ccc7aca4b1cdea57ddcd568a502209f81e6b5bc678e1dd52b78d764fe46ea3ff77b926eb9f70eb52ae8f3f2afa2e9d0efa82655e361641458b900", - "sourceShard": 0, - "destinationShard": 1, - "blockNonce": 2129490, - "blockHash": "0ab10909b27565c5b7b59e8e1ee4a68d7046f49225fcde4c12d4b1ea3f512b8a", - "notarizedAtSourceInMetaNonce": 2130938, - "NotarizedAtSourceInMetaHash": "0c545160fd37f09f0196505b9cd2e730596bcd99438978a5bb415b9e1be1849d", - "notarizedAtDestinationInMetaNonce": 2130942, - "notarizedAtDestinationInMetaHash": "1ddd6b7aeeff824b5d11f2936a6284e470fc5abe41e34a8df229b719dc1a537d", - "miniblockType": "TxBlock", - "miniblockHash": "dc8ae41e1ae321c0fccbeb807194d11ff6e0f4ed71163764d850f1daaa60bd22", - "hyperblockNonce": 2130942, - "hyperblockHash": "1ddd6b7aeeff824b5d11f2936a6284e470fc5abe41e34a8df229b719dc1a537d", - "timestamp": 1707155768, - "status": "success", - "tokens": [ - "OURO-d8171f" - ], - "esdtValues": [ - "640821212132848" - ], - "operation": "ESDTTransfer", - "function": "buy", - "initiallyPaidFee": "359390000000000", - "chainID": "D", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" -} - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - let opt_address = tx_response.new_deployed_address; - - let expected: Option
= None; - - assert_eq!(opt_address, expected) - } - - #[test] - fn test_with_tx_that_has_sc_result() { - // transaction data from the devnet, an artificial "10" result has been appended on the original result - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "BuiltInFunctionCall", - "processingTypeOnDestination": "SCInvoking", - "hash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "nonce": 30, - "round": 7639115, - "epoch": 6333, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "sender": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "gasPrice": 1000000000, - "gasLimit": 25500000, - "gasUsed": 15297149, - "data": "RVNEVFRyYW5zZmVyQDQ4NTQ0ZDJkNjY2NTMxNjYzNjM5QDBkZTBiNmIzYTc2NDAwMDBANzM3NzYxNzA1NDZmNmI2NTZlNzM0NjY5Nzg2NTY0NDk2ZTcwNzU3NEA1NzQ1NDc0YzQ0MmQ2NDM3NjMzNjYyNjJAMDM3Yzc3OGZjY2U5YzU1Yg==", - "signature": "e912fae4b7a9e51ddf316a5e82a0f457d453a62e3c17477f5d6175e1b33c5e92ddb187d65f54cf3131a0603321290279a0456c20778039f2ab09b54e33c60f0d", - "sourceShard": 2, - "destinationShard": 1, - "blockNonce": 7585351, - "blockHash": "e456f38f11fec78ed26d5fda068e912739dceedb2e5ce559bf17614b8386c039", - "notarizedAtSourceInMetaNonce": 7601495, - "NotarizedAtSourceInMetaHash": "e28c6011d4b3f73f3945cae70ff251e675dfea331a70077c5ab3310e3101af17", - "notarizedAtDestinationInMetaNonce": 7601499, - "notarizedAtDestinationInMetaHash": "333d4266614e981cc1c5654f85ef496038a8cddac46dfc0ad0b7c44c37ab489d", - "miniblockType": "TxBlock", - "miniblockHash": "13e041f32fde79ebf1abdcfe692e99516f9ec6778dcb917251b440daa7f1210a", - "hyperblockNonce": 7601499, - "hyperblockHash": "333d4266614e981cc1c5654f85ef496038a8cddac46dfc0ad0b7c44c37ab489d", - "timestamp": 1694386290, - "smartContractResults": [ - { - "hash": "a23faa3c80bae0b968f007ff0fad3afdec05b4e71d749c3d583dec10c6eb05a2", - "nonce": 0, - "value": 0, - "receiver": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "data": "ESDTTransfer@5745474c442d643763366262@03856446ff9a304b", - "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "logs": { - "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "identifier": "ESDTTransfer", - "topics": [ - "V0VHTEQtZDdjNmJi", - "", - "A4VkRv+aMEs=", - "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOY=" - ], - "data": null - }, - { - "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "identifier": "writeLog", - "topics": [ - "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOs=" - ], - "data": "QDZmNmI=" - }, - { - "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "identifier": "completedTxEvent", - "topics": [ - "1AWL08E9sLFIMsfFj+Fj2y9Xn/ZUQ4BYa4on2ItKUHA=" - ], - "data": null - } - ] - }, - "tokens": [ - "WEGLD-d7c6bb" - ], - "esdtValues": [ - "253719210115084363" - ], - "operation": "ESDTTransfer" - }, - { - "hash": "b7b4d15917fd215399d8e772c3c4e732008baaedc2b8172f71c91708ba7523f0", - "nonce": 31, - "value": 102028510000000, - "receiver": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "data": "@6f6b@0000000c5745474c442d64376336626200000000000000000000000803856446ff9a304b@10", - "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "logs": { - "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "events": [ - { - "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "identifier": "completedTxEvent", - "topics": [ - "1AWL08E9sLFIMsfFj+Fj2y9Xn/ZUQ4BYa4on2ItKUHA=" - ], - "data": null - } - ] - }, - "operation": "transfer", - "isRefund": true - }, - { - "hash": "05a766ca05d2053d1c0fbeb1797116474a06c86402a3bfd6c132c9a24cfa1bb0", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "data": "swapTokensFixedInput@5745474c442d643763366262@037c778fcce9c55b", - "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "gasLimit": 25050500, - "gasPrice": 1000000000, - "callType": 0, - "operation": "transfer", - "function": "swapTokensFixedInput" - }, - { - "hash": "4e639c80822d5d7780c8326d683fa9cd6d59649d14122dfabc5a96dda36da527", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgquu5rsa4ee6l4azz6vdu4hjp8z4p6tt8m0n4suht3dy", - "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "data": "ESDTTransfer@5745474c442d643763366262@e7730d1ef1b0@737761704e6f466565416e64466f7277617264@4d45582d646332383963@0000000000000000000000000000000000000000000000000000000000000000", - "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "tokens": [ - "WEGLD-d7c6bb" - ], - "esdtValues": [ - "254481327387056" - ], - "operation": "ESDTTransfer", - "function": "swapNoFeeAndForward" - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "events": [ - { - "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", - "identifier": "ESDTTransfer", - "topics": [ - "SFRNLWZlMWY2OQ==", - "", - "DeC2s6dkAAA=", - "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOs=" - ], - "data": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "identifier": "ESDTTransfer", - "topics": [ - "V0VHTEQtZDdjNmJi", - "", - "53MNHvGw", - "AAAAAAAAAAAFAOcoOHa5zr9eiFpjeVvIJxVDpaz7fOs=" - ], - "data": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgquu5rsa4ee6l4azz6vdu4hjp8z4p6tt8m0n4suht3dy", - "identifier": "ESDTLocalBurn", - "topics": [ - "TUVYLWRjMjg5Yw==", - "", - "AuMDPq1jy03x" - ], - "data": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgquu5rsa4ee6l4azz6vdu4hjp8z4p6tt8m0n4suht3dy", - "identifier": "swapNoFeeAndForward", - "topics": [ - "c3dhcF9ub19mZWVfYW5kX2ZvcndhcmQ=", - "TUVYLWRjMjg5Yw==", - "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOs=", - "GL0=" - ], - "data": "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOsAAAAMV0VHTEQtZDdjNmJiAAAABudzDR7xsAAAAApNRVgtZGMyODljAAAACQLjAz6tY8tN8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzvkcAAAAAAAAYvQAAAABk/khy" - }, - { - "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "identifier": "ESDTTransfer", - "topics": [ - "V0VHTEQtZDdjNmJi", - "", - "A4VkRv+aMEs=", - "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOY=" - ], - "data": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", - "identifier": "swapTokensFixedInput", - "topics": [ - "c3dhcA==", - "SFRNLWZlMWY2OQ==", - "V0VHTEQtZDdjNmJi", - "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOY=", - "GL0=" - ], - "data": "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOYAAAAKSFRNLWZlMWY2OQAAAAgN4Lazp2QAAAAAAAxXRUdMRC1kN2M2YmIAAAAIA4VkRv+aMEsAAAAHA41+pMaAAAAAAAoofxtJRPkr8X9kAAAACgpOPCsHUu261HUAAAAAAHO+RwAAAAAAABi9AAAAAGT+SHI=" - } - ] - }, - "status": "success", - "tokens": [ - "HTM-fe1f69" - ], - "esdtValues": [ - "1000000000000000000" - ], - "operation": "ESDTTransfer", - "function": "swapTokensFixedInput", - "initiallyPaidFee": "502005000000000", - "fee": "399976490000000", - "chainID": "D", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" - } - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Vec> = vec![ - hex::decode("0000000c5745474c442d64376336626200000000000000000000000803856446ff9a304b") - .unwrap(), - hex::decode("10").unwrap(), - ]; - - assert_eq!(tx_response.out, expected) - } - - #[test] - fn test_with_tx_that_has_no_sc_result() { - // transaction data from the devnet - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "6afac3ec13c89cc56154d06efdb457a24f58361699eee00a48202a8f8adc8c8a", - "nonce": 17, - "round": 7548071, - "epoch": 6257, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "gasUsed": 600000000, - "data": "cmV0dXJuVHdvVTY0", - "signature": "f3a3ca96a78c90c9cf1b08541e1777010f0176a5e1e525e631155b2784932cbfd74c9168d03ba201fd5434d1a1b4789895ddade9883eca2ee9e0bce18468fb00", - "sourceShard": 0, - "destinationShard": 0, - "blockNonce": 7502091, - "blockHash": "5ec66c651cb1514cba200e7e80a4491880f0db678ce7631c397872e3842f0aa2", - "notarizedAtSourceInMetaNonce": 7510505, - "NotarizedAtSourceInMetaHash": "8410309ec5b988af79b4dcfb44fd4729d46874ebd796672c78e417e314409051", - "notarizedAtDestinationInMetaNonce": 7510505, - "notarizedAtDestinationInMetaHash": "8410309ec5b988af79b4dcfb44fd4729d46874ebd796672c78e417e314409051", - "miniblockType": "TxBlock", - "miniblockHash": "fb150e515449c9b658879ed06f256b429239cbe78ec2c2821deb4b283ff21554", - "hyperblockNonce": 7510505, - "hyperblockHash": "8410309ec5b988af79b4dcfb44fd4729d46874ebd796672c78e417e314409051", - "timestamp": 1693840026, - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "identifier": "writeLog", - "topics": [ - "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk5OTMyMDAwLCBnYXMgdXNlZCA9IDE4NDE2NjU=" - ], - "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" - }, - { - "address": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "identifier": "completedTxEvent", - "topics": [ - "avrD7BPInMVhVNBu/bRXok9YNhaZ7uAKSCAqj4rcjIo=" - ], - "data": null - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "returnTwoU64", - "initiallyPaidFee": "6067320000000000", - "fee": "6067320000000000", - "chainID": "D", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" - } - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Vec> = vec![ - hex::decode("0a").unwrap(), - hex::decode("0218711a00").unwrap(), - ]; - - assert_eq!(tx_response.out, expected) - } - - #[test] - fn test_with_multi_contract_same_shard_tx_that_has_no_sc_result() { - // transaction data from the devnet - // context : user -> A --call--> B, B returns a MultiValue2, A returns the B's returned value - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "e914857f1bfd003ba411bae372266703e5f706fa412c378feb37faa5e18c3d73", - "nonce": 49, - "round": 7646960, - "epoch": 6339, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", - "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "gasUsed": 600000000, - "data": "Y2FsbEFub3RoZXJDb250cmFjdFJldHVyblR3b1U2NEAwMDAwMDAwMDAwMDAwMDAwMDUwMEFDRkY2QjdBNEVCODEwMUE4REU3RkY3RjVEMkMwQkYzRTRENjNGNDdBNzND", - "signature": "53cc6496647287d735bd7950f4ec79d7b51f884defda1d6d840d722b7d0d869900ccecc01602da7a7c717955e8d4ed0711b92acd980d64ed6eebd6eaed0c4608", - "sourceShard": 0, - "destinationShard": 0, - "blockNonce": 7600794, - "blockHash": "77eb0904e56d6dd596c0d72821cf33b326fde383e72903ca4df5c2f200b0ea75", - "notarizedAtSourceInMetaNonce": 7609344, - "NotarizedAtSourceInMetaHash": "12df3fe65cacde2c9742b9506ac2261d34f3c72d690301192fd8016430d51913", - "notarizedAtDestinationInMetaNonce": 7609344, - "notarizedAtDestinationInMetaHash": "12df3fe65cacde2c9742b9506ac2261d34f3c72d690301192fd8016430d51913", - "miniblockType": "TxBlock", - "miniblockHash": "03219ac7427f7511687f0768c722c759c1b1428b2664b44a0cbe2072154851ee", - "hyperblockNonce": 7609344, - "hyperblockHash": "12df3fe65cacde2c9742b9506ac2261d34f3c72d690301192fd8016430d51913", - "timestamp": 1694433360, - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", - "identifier": "writeLog", - "topics": [ - "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk5ODA2MDAwLCBnYXMgdXNlZCA9IDM4NDcyNDA=" - ], - "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" - }, - { - "address": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", - "identifier": "completedTxEvent", - "topics": [ - "6RSFfxv9ADukEbrjciZnA+X3BvpBLDeP6zf6peGMPXM=" - ], - "data": null - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "callAnotherContractReturnTwoU64", - "initiallyPaidFee": "6192060000000000", - "fee": "6192060000000000", - "chainID": "D", - "version": 2, - "options": 0 - } - }, - "error": "", - "code": "successful" - } - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Vec> = vec![ - hex::decode("0a").unwrap(), - hex::decode("0218711a00").unwrap(), - ]; - - assert_eq!(tx_response.out, expected) - } - - #[test] - fn test_with_multi_contract_cross_shard_tx_that_has_no_callback() { - // transaction data from the devnet - // context : user -> A --async call--> B, no callback - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", - "nonce": 51, - "round": 7647523, - "epoch": 6340, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "gasUsed": 600000000, - "data": "YXN5bmNDYWxsQW5vdGhlckNvbnRyYWN0UmV0dXJuVHdvVTY0Tm9DYWxsYmFja0AwMDAwMDAwMDAwMDAwMDAwMDUwMEFDRkY2QjdBNEVCODEwMUE4REU3RkY3RjVEMkMwQkYzRTRENjNGNDdBNzND", - "signature": "0fc30cddaa8e5365662a14344e3434cbccf287f357be99b3ed4add182f64dded774ec0d095ab1589e7c6c07e00de3b7239efc96eb2e0e97b48c1ef87084cec01", - "sourceShard": 0, - "destinationShard": 1, - "blockNonce": 7593758, - "blockHash": "a828c0ca58ef1c8aff60e512ab59f18204f1915d4a6c8285cfceb1c5725b88e8", - "notarizedAtSourceInMetaNonce": 7609903, - "NotarizedAtSourceInMetaHash": "4e90fe45c2fdccd5cf6977c1422e5f4ffa41c4e9f31fb4a50c20455f87df1e99", - "notarizedAtDestinationInMetaNonce": 7609907, - "notarizedAtDestinationInMetaHash": "10b8666a44411c3babbe20af7154fb3d47efcb1cb10d955523ec68fece26e517", - "miniblockType": "TxBlock", - "miniblockHash": "4ff4bb1ac88911d617c9b0342aeb5158db78490c2fe414cad08adcc584a77be7", - "hyperblockNonce": 7609907, - "hyperblockHash": "10b8666a44411c3babbe20af7154fb3d47efcb1cb10d955523ec68fece26e517", - "timestamp": 1694436738, - "smartContractResults": [ - { - "hash": "462b56a1530e6070dc7c15f755e51a97a6972c8cd7891f3be4635b93211890c5", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "sender": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "data": "@00@0a@0218711a00", - "prevTxHash": "41d56fdacf3e14de67e821427c732b62ebfa07c82d2e5db6de75fe3a1c828d9b", - "originalTxHash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", - "gasLimit": 595637825, - "gasPrice": 1000000000, - "callType": 2, - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "writeLog", - "topics": [ - "AAAAAAAAAAAFAP/Aj4ZNGKlpx2+xeJLdoJbREzb20P0=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk1NjM3ODI1LCBnYXMgdXNlZCA9IDIxNjE3NzA=" - ], - "data": "QDZmNmI=" - }, - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "completedTxEvent", - "topics": [ - "QdVv2s8+FN5n6CFCfHMrYuv6B8gtLl223nX+OhyCjZs=" - ], - "data": null - } - ] - }, - "operation": "transfer" - }, - { - "hash": "41d56fdacf3e14de67e821427c732b62ebfa07c82d2e5db6de75fe3a1c828d9b", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "sender": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "data": "returnTwoU64@4f3c60", - "prevTxHash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", - "originalTxHash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", - "gasLimit": 597479490, - "gasPrice": 1000000000, - "callType": 1, - "operation": "transfer", - "function": "returnTwoU64" - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "writeLog", - "topics": [ - "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=" - ], - "data": "QDZmNmI=" - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "asyncCallAnotherContractReturnTwoU64NoCallback", - "initiallyPaidFee": "6214335000000000", - "fee": "6214335000000000", - "chainID": "D", - "version": 2, - "options": 0 - } - }, - "error": "", - "code": "successful" - } - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Vec> = vec![]; - - assert_eq!(tx_response.out, expected) - } - - #[test] - fn test_with_multi_contract_cross_shard_tx_that_has_non_returning_callback() { - // transaction data from the devnet - // context : user -> A --async call--> B --callback--> A, the callback returns () - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", - "nonce": 52, - "round": 7647560, - "epoch": 6340, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "gasUsed": 600000000, - "data": "YXN5bmNDYWxsQW5vdGhlckNvbnRyYWN0UmV0dXJuVHdvVTY0V2l0aE5vblJldHVybmluZ0NhbGxiYWNrQDAwMDAwMDAwMDAwMDAwMDAwNTAwQUNGRjZCN0E0RUI4MTAxQThERTdGRjdGNUQyQzBCRjNFNEQ2M0Y0N0E3M0M=", - "signature": "3918fce429b2059b2321b709011079755dbb835e12839278ee510e4741180540e80c6111eea1d3312b2c63446de08b20e01f6040358fa94d1633c355bb65bc0f", - "sourceShard": 0, - "destinationShard": 1, - "blockNonce": 7593795, - "blockHash": "c17e727f90025225670b7852ea9807c67753c9b3f21b6ec7cc40077e3849a8b7", - "notarizedAtSourceInMetaNonce": 7609940, - "NotarizedAtSourceInMetaHash": "c67b5c550986cfd6c94d00f4b90234eb38ee196ff0d79a00d916f3bd24be272c", - "notarizedAtDestinationInMetaNonce": 7609944, - "notarizedAtDestinationInMetaHash": "d59b7398d962ce3119679af59d5d74e10083e62c3ee2b15421cc0d607979ca18", - "miniblockType": "TxBlock", - "miniblockHash": "2977affeffeb6cf41117bed442662021cb713528cdb1d0dce4537b01caeb8e0b", - "hyperblockNonce": 7609944, - "hyperblockHash": "d59b7398d962ce3119679af59d5d74e10083e62c3ee2b15421cc0d607979ca18", - "timestamp": 1694436960, - "smartContractResults": [ - { - "hash": "fe7474188d5ca4b84c7577f03fc778d22d53c070dfcb05a9cda840229d30e4d3", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "sender": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "data": "returnTwoU64@4f3c60", - "prevTxHash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", - "originalTxHash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", - "gasLimit": 596979545, - "gasPrice": 1000000000, - "callType": 1, - "operation": "transfer", - "function": "returnTwoU64" - }, - { - "hash": "948dc6702b376d1e043db8de2f87ca12907c342f54cfad7dfebadf59145ca3ac", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "sender": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "data": "@00@0a@0218711a00", - "prevTxHash": "fe7474188d5ca4b84c7577f03fc778d22d53c070dfcb05a9cda840229d30e4d3", - "originalTxHash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", - "gasLimit": 595137880, - "gasPrice": 1000000000, - "callType": 2, - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "writeLog", - "topics": [ - "AAAAAAAAAAAFAP/Aj4ZNGKlpx2+xeJLdoJbREzb20P0=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk1MTM3ODgwLCBnYXMgdXNlZCA9IDIyODg1NTA=" - ], - "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" - }, - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "completedTxEvent", - "topics": [ - "/nR0GI1cpLhMdXfwP8d40i1TwHDfywWpzahAIp0w5NM=" - ], - "data": null - } - ] - }, - "operation": "transfer" - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "writeLog", - "topics": [ - "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=" - ], - "data": "QDZmNmI=" - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "asyncCallAnotherContractReturnTwoU64WithNonReturningCallback", - "initiallyPaidFee": "6235125000000000", - "fee": "6235125000000000", - "chainID": "D", - "version": 2, - "options": 0 - } - }, - "error": "", - "code": "successful" - } - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Vec> = vec![]; - - assert_eq!(tx_response.out, expected) - } - - #[test] - fn test_with_multi_contract_cross_shard_tx_that_has_returning_callback() { - // transaction data from the devnet - // context : user -> A --async call--> B --callback--> A, the callback returns a MultiValue2 - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", - "nonce": 53, - "round": 7647583, - "epoch": 6340, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "gasUsed": 600000000, - "data": "YXN5bmNDYWxsQW5vdGhlckNvbnRyYWN0UmV0dXJuVHdvVTY0V2l0aFJldHVybmluZ0NhbGxiYWNrQDAwMDAwMDAwMDAwMDAwMDAwNTAwQUNGRjZCN0E0RUI4MTAxQThERTdGRjdGNUQyQzBCRjNFNEQ2M0Y0N0E3M0M=", - "signature": "858958d4aaf9cb0220ab2933edad3f65e1cb4c58aa7940cb0f40b489d0bd9fdf5c4736a40d6e813743ee622bb91e9f86eacf01b9a31e0ff53f9c84f13c500304", - "sourceShard": 0, - "destinationShard": 1, - "blockNonce": 7593818, - "blockHash": "b19f97110ca38d3cb15f802a00ab403491b0e5804ebc701527ab50064dc06825", - "notarizedAtSourceInMetaNonce": 7609963, - "NotarizedAtSourceInMetaHash": "4d9db6de610ca778114d44fe91dd036fac7c375c373ae9e77130d3fb9efc8391", - "notarizedAtDestinationInMetaNonce": 7609967, - "notarizedAtDestinationInMetaHash": "a4573d388c31860f9bd6f9507b65d1b3130e445abcada538f10704feba4614e7", - "miniblockType": "TxBlock", - "miniblockHash": "530f5fa3c7af474a187caca8dcea02a7a155017414147871d083bed5c49ec8f5", - "hyperblockNonce": 7609967, - "hyperblockHash": "a4573d388c31860f9bd6f9507b65d1b3130e445abcada538f10704feba4614e7", - "timestamp": 1694437098, - "smartContractResults": [ - { - "hash": "065291164a8acd27c26b5a8f09664810081fda18cd54fca635196cf9b200297a", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "sender": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "data": "returnTwoU64@4f3c60", - "prevTxHash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", - "originalTxHash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", - "gasLimit": 596994205, - "gasPrice": 1000000000, - "callType": 1, - "operation": "transfer", - "function": "returnTwoU64" - }, - { - "hash": "bc31cb153ae615204625df84fe9ae3a159aa412b7342f3dca958dd5517a08197", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "sender": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", - "data": "@00@0a@0218711a00", - "prevTxHash": "065291164a8acd27c26b5a8f09664810081fda18cd54fca635196cf9b200297a", - "originalTxHash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", - "gasLimit": 595152540, - "gasPrice": 1000000000, - "callType": 2, - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "writeLog", - "topics": [ - "AAAAAAAAAAAFAP/Aj4ZNGKlpx2+xeJLdoJbREzb20P0=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk1MTUyNTQwLCBnYXMgdXNlZCA9IDIyODgwMTU=" - ], - "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" - }, - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "completedTxEvent", - "topics": [ - "BlKRFkqKzSfCa1qPCWZIEAgf2hjNVPymNRls+bIAKXo=" - ], - "data": null - } - ] - }, - "operation": "transfer" - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", - "identifier": "writeLog", - "topics": [ - "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=" - ], - "data": "QDZmNmI=" - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "asyncCallAnotherContractReturnTwoU64WithReturningCallback", - "initiallyPaidFee": "6230670000000000", - "fee": "6230670000000000", - "chainID": "D", - "version": 2, - "options": 0 - } - }, - "error": "", - "code": "successful" - } - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Vec> = vec![]; - - assert_eq!(tx_response.out, expected) - } - - #[test] - fn test_process_issued_token_identifier_fungible() { - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", - "nonce": 61, - "round": 173598, - "epoch": 72, - "value": "50000000000000000", - "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "sender": "erd1x39tc3q3nn72ecjnmcz7x0qp09kp97t080x99dgyhx7zh95j0n4szskhlv", - "gasPrice": 1000000000, - "gasLimit": 100000000, - "gasUsed": 100000000, - "data": "aXNzdWVMcFRva2VuQDAwMDAwMDAwMDAwMDAwMDAwNTAwMTM5ZWQ3YWU0YWEwMzc5MmU2YmNiMzMyMzk0YTQwZmU3NDZlZWZhNDdjZWJANDU0NzRjNDQ0ZDQ1NTg0YzUwQDQ1NDc0YzQ0NGQ0NTU4", - "signature": "b5049d2906adc1305a6a8d0f42749254ca6259c6996d9a35e7dc7528b3c87b48a421879aff70bc6d81483a7559b75e5dcf9be499dcb7d57aa9f25c79ac2ad40d", - "sourceShard": 1, - "destinationShard": 1, - "blockNonce": 173354, - "blockHash": "09d85ac264a54e12e7613395211c53fe0ee5a7d3b7111bf5fec1d02794caaacd", - "notarizedAtSourceInMetaNonce": 173321, - "NotarizedAtSourceInMetaHash": "64a83759da97fe8305cd4cda4b518f2d41ef0a8f3995d264460821edad45e09e", - "notarizedAtDestinationInMetaNonce": 173321, - "notarizedAtDestinationInMetaHash": "64a83759da97fe8305cd4cda4b518f2d41ef0a8f3995d264460821edad45e09e", - "miniblockType": "TxBlock", - "miniblockHash": "7f45eee4e35ffc1fbce66b92e4dd2aeae2acb092416aa5aa775b96493256b81d", - "hyperblockNonce": 173321, - "hyperblockHash": "64a83759da97fe8305cd4cda4b518f2d41ef0a8f3995d264460821edad45e09e", - "timestamp": 1695041588, - "smartContractResults": [ - { - "hash": "bce3d0dceb0b3e5c8c5780d7da3755c3f7492d551685d493a73bf66ebd36754b", - "nonce": 0, - "value": 50000000000000000, - "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "sender": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "data": "issue@45474c444d45584c50@45474c444d4558@03e8@12@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e4d696e74@74727565@63616e4275726e@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565@65ba30", - "prevTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", - "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", - "gasLimit": 89624222, - "gasPrice": 1000000000, - "callType": 1, - "originalSender": "erd1x39tc3q3nn72ecjnmcz7x0qp09kp97t080x99dgyhx7zh95j0n4szskhlv", - "operation": "transfer", - "function": "issue" - }, - { - "hash": "2a452ff652791d79be5f6933fb583cc5503e876893e54b3b51381a92aa2e904d", - "nonce": 0, - "value": 0, - "receiver": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "ESDTSetBurnRoleForAll@45474c444d45582d393563366435", - "prevTxHash": "bce3d0dceb0b3e5c8c5780d7da3755c3f7492d551685d493a73bf66ebd36754b", - "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "logs": { - "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", - "events": [ - { - "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", - "identifier": "completedTxEvent", - "topics": [ - "vOPQ3OsLPlyMV4DX2jdVw/dJLVUWhdSTpzv2br02dUs=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "transfer" - }, - { - "hash": "2c84740ccb3376ea9fa00dab6c6c93fe7a35ee0a1d6dbfa0a1e61064853b0874", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "ESDTTransfer@45474c444d45582d393563366435@03e8@00", - "prevTxHash": "bce3d0dceb0b3e5c8c5780d7da3755c3f7492d551685d493a73bf66ebd36754b", - "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", - "gasLimit": 39624222, - "gasPrice": 1000000000, - "callType": 2, - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "identifier": "ESDTTransfer", - "topics": [ - "RUdMRE1FWC05NWM2ZDU=", - "", - "A+g=", - "AAAAAAAAAAAFAO+ux8+3RD51ieGHV10Z68X293CYfOs=" - ], - "data": null, - "additionalData": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "identifier": "completedTxEvent", - "topics": [ - "vOPQ3OsLPlyMV4DX2jdVw/dJLVUWhdSTpzv2br02dUs=" - ], - "data": null, - "additionalData": null - } - ] - }, - "tokens": [ - "EGLDMEX-95c6d5" - ], - "esdtValues": [ - "1000" - ], - "operation": "ESDTTransfer", - "function": "\u0000" - }, - { - "hash": "c9dfc4de3c3cee319123087a4f5dd03cc051e728ec6070707a63ea977b535227", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "sender": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "data": "\u0000", - "prevTxHash": "2c84740ccb3376ea9fa00dab6c6c93fe7a35ee0a1d6dbfa0a1e61064853b0874", - "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", - "gasLimit": 39424222, - "gasPrice": 1000000000, - "callType": 2, - "operation": "transfer", - "function": "\u0000" - }, - { - "hash": "609c3a8e1903680fef1f6d9e47527b1b5c1259664b868af600162120ce0b8192", - "nonce": 1, - "value": 300925400000000, - "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "sender": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "data": "@6f6b", - "prevTxHash": "2c84740ccb3376ea9fa00dab6c6c93fe7a35ee0a1d6dbfa0a1e61064853b0874", - "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "operation": "transfer", - "isRefund": true - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "identifier": "transferValueOnly", - "topics": [ - "AAAAAAAAAAAFAO+ux8+3RD51ieGHV10Z68X293CYfOs=", - "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=", - "saK8LsUAAA==" - ], - "data": null, - "additionalData": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", - "identifier": "writeLog", - "topics": [ - "NEq8RBGc/KziU94F4zwBeWwS+W87zFK1BLm8K5aSfOs=" - ], - "data": "QDZmNmI=", - "additionalData": null - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "issueLpToken", - "initiallyPaidFee": "1214335000000000", - "fee": "1214335000000000", - "chainID": "D", - "version": 2, - "options": 0 - } - }, - "error": "", - "code": "successful" -} - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Option = Some("EGLDMEX-95c6d5".to_string()); - - assert_eq!(tx_response.new_issued_token_identifier, expected) - } - - #[test] - fn test_process_issued_token_identifier_semi_fungible() { - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", - "nonce": 65, - "round": 8422527, - "epoch": 584, - "value": "50000000000000000", - "receiver": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "sender": "erd1x3g000ew7zzv6kyqhj9jl2wy5g6cc72qahvvxz29zv76jwq6ssvqt0d998", - "gasPrice": 1000000000, - "gasLimit": 80000000, - "gasUsed": 80000000, - "data": "aXNzdWVUb2tlbkA0NDZmNzA2NTU0NjU3Mzc0QDQ0NGY1MDQ1NTQ0NTUzNTQ=", - "signature": "0191848976e930996f6c62d4921e732f9b0ada8b41ca3b5b63d6bfd304fd44c2a1e8e6643479618ba4a764a36e87f53882b4f707600d5b7d476f2fdd2bac040e", - "sourceShard": 0, - "destinationShard": 0, - "blockNonce": 8420241, - "blockHash": "4d302220f6015876c95e7961b770cc67f8ab63c5f0ab69b4d6c2fb15c8bc23bd", - "notarizedAtSourceInMetaNonce": 8403647, - "NotarizedAtSourceInMetaHash": "f8b83b6d38fa45dacc167b15c93dd07ee5c40db906de34f26e11e7a24f539e30", - "notarizedAtDestinationInMetaNonce": 8403647, - "notarizedAtDestinationInMetaHash": "f8b83b6d38fa45dacc167b15c93dd07ee5c40db906de34f26e11e7a24f539e30", - "miniblockType": "TxBlock", - "miniblockHash": "b7b8fc9f3b81d7daae1113cbf73457e16ee31f3a864ef3729a1a21f3a929e112", - "hyperblockNonce": 8403647, - "hyperblockHash": "f8b83b6d38fa45dacc167b15c93dd07ee5c40db906de34f26e11e7a24f539e30", - "timestamp": 1646652762, - "smartContractResults": [ - { - "hash": "9aecf3bd5dd5c706a28d1cc7059ac20db74340f136816f667dbefcc58daa3aba", - "nonce": 0, - "value": 50000000000000000, - "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "sender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "data": "issueSemiFungible@446f706554657374@444f504554455354@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565@5ca148", - "prevTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", - "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", - "gasLimit": 75958360, - "gasPrice": 1000000000, - "callType": 1, - "originalSender": "erd1x3g000ew7zzv6kyqhj9jl2wy5g6cc72qahvvxz29zv76jwq6ssvqt0d998", - "operation": "transfer", - "function": "issueSemiFungible" - }, - { - "hash": "aacfe9088bb9d2d5b3fbe9cab2b2f1c6a7e9cbab2f1a41020e2c819fc9b43570", - "nonce": 66, - "value": 0, - "receiver": "erd1x3g000ew7zzv6kyqhj9jl2wy5g6cc72qahvvxz29zv76jwq6ssvqt0d998", - "sender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "data": "@6f6b", - "prevTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", - "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "operation": "transfer" - }, - { - "hash": "3f6f0f3de9e942884e7e1592823a7db7ce935a3f9d3359d8c1ee98a5645332d8", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "@00@444f5045544553542d373732303063", - "prevTxHash": "9aecf3bd5dd5c706a28d1cc7059ac20db74340f136816f667dbefcc58daa3aba", - "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", - "gasLimit": 25958360, - "gasPrice": 1000000000, - "callType": 2, - "originalSender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "identifier": "completedTxEvent", - "topics": [ - "muzzvV3VxwaijRzHBZrCDbdDQPE2gW9mfb78xY2qOro=" - ], - "data": null - } - ] - }, - "operation": "transfer" - }, - { - "hash": "c6e4f7c5da455009fb4f6967ce8a273a97b826aa617fa798ffd0cf17bde6b97a", - "nonce": 1, - "value": 225516180000000, - "receiver": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "sender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "data": "@6f6b", - "prevTxHash": "3f6f0f3de9e942884e7e1592823a7db7ce935a3f9d3359d8c1ee98a5645332d8", - "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "operation": "transfer", - "isRefund": true - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "identifier": "transferValueOnly", - "topics": [ - "AAAAAAAAAAAFAH6d74PDz8xLqvowrlOA5lVDBMUghBg=", - "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=", - "saK8LsUAAA==" - ], - "data": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", - "identifier": "writeLog", - "topics": [ - "NFD3vy7whM1YgLyLL6nEojWMeUDt2MMJRRM9qTgahBg=" - ], - "data": "QDZmNmI=" - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "issueToken", - "initiallyPaidFee": "914840000000000", - "fee": "914840000000000", - "chainID": "1", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" -} - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Option = Some("DOPETEST-77200c".to_string()); - - assert_eq!(tx_response.new_issued_token_identifier, expected) - } - - #[test] - fn test_process_issued_token_identifier_non_fungible() { - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "nonce": 16, - "round": 820170, - "epoch": 341, - "value": "50000000000000000", - "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "sender": "erd162knt53z7m0f9jjms9wxphr3q9d7zu4ky85xs2cc0ekrqz7k4fdq85lkuc", - "gasPrice": 1000000000, - "gasLimit": 200000000, - "gasUsed": 200000000, - "data": "aXNzdWVUb2tlbkA2NzY1NmU2NTdhNzk3M0A0NzQ1NGU=", - "signature": "e80d45f4de419799a2bbff1cae1235521c8eef1853ee45b02f95c2da74ce50d241bf75b6ab0c650245562700862ea9759caad40f3e381ac0c4d82cfe56e67c09", - "sourceShard": 2, - "destinationShard": 2, - "blockNonce": 819313, - "blockHash": "a1db4ef13f07b86678000df9cc78f244d83dcc35ae51de545f333bf616930d39", - "notarizedAtSourceInMetaNonce": 819396, - "NotarizedAtSourceInMetaHash": "6d9e511e46d318aa5b77cbfdfde14d2ce8515ce4e954b286f130a6b518ddf26a", - "notarizedAtDestinationInMetaNonce": 819396, - "notarizedAtDestinationInMetaHash": "6d9e511e46d318aa5b77cbfdfde14d2ce8515ce4e954b286f130a6b518ddf26a", - "miniblockType": "TxBlock", - "miniblockHash": "afdb278522181aeb9b12f08840e6c534e398e6af9c7f757548308e300e7ec4e9", - "hyperblockNonce": 819396, - "hyperblockHash": "6d9e511e46d318aa5b77cbfdfde14d2ce8515ce4e954b286f130a6b518ddf26a", - "timestamp": 1698921020, - "smartContractResults": [ - { - "hash": "6fe0cc002802af1744f394eee4a69224b5e775961d8386e04e7a5b9242f7ff65", - "nonce": 0, - "value": 50000000000000000, - "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "sender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "data": "issueNonFungible@67656e657a7973@47454e@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@66616c7365@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@74727565@5e30e4", - "prevTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "gasLimit": 196098365, - "gasPrice": 1000000000, - "callType": 1, - "originalSender": "erd162knt53z7m0f9jjms9wxphr3q9d7zu4ky85xs2cc0ekrqz7k4fdq85lkuc", - "operation": "transfer", - "function": "issueNonFungible" - }, - { - "hash": "98afe82512c79f1caaf171bd5919ee469d11ba0c4f725aefcab834278c0f1e58", - "nonce": 0, - "value": 0, - "receiver": "erd1lllllllllllllllllllllllllllllllllllllllllllllllllupq9x7ny0", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "ESDTSetBurnRoleForAll@47454e2d383638353933", - "prevTxHash": "6fe0cc002802af1744f394eee4a69224b5e775961d8386e04e7a5b9242f7ff65", - "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "logs": { - "address": "erd1lllllllllllllllllllllllllllllllllllllllllllllllllupq9x7ny0", - "events": [ - { - "address": "erd1lllllllllllllllllllllllllllllllllllllllllllllllllupq9x7ny0", - "identifier": "completedTxEvent", - "topics": [ - "b+DMACgCrxdE85Tu5KaSJLXndZYdg4bgTnpbkkL3/2U=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "transfer" - }, - { - "hash": "83494ad9369738b574a7266cbfb12ce63ccf634950cd6b0ec16107b8fb42f8f6", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "sender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "data": "setSpecialRole@47454e2d383638353933@00000000000000000500de51fa8943c26e6933419f9bb7ceb79b7ff4f7bbaa5a@45534454526f6c654e4654437265617465@5e30e4", - "prevTxHash": "112d18ec0364b4700b1bfb3df517c80dba547a53373ece2a9e71acd5266e7b64", - "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "gasLimit": 142399698, - "gasPrice": 1000000000, - "callType": 1, - "operation": "transfer", - "function": "setSpecialRole" - }, - { - "hash": "112d18ec0364b4700b1bfb3df517c80dba547a53373ece2a9e71acd5266e7b64", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "@00@47454e2d383638353933", - "prevTxHash": "6fe0cc002802af1744f394eee4a69224b5e775961d8386e04e7a5b9242f7ff65", - "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "gasLimit": 146098365, - "gasPrice": 1000000000, - "callType": 2, - "originalSender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "identifier": "writeLog", - "topics": [ - "AAAAAAAAAAAFAN5R+olDwm5pM0Gfm7fOt5t/9Pe7qlo=" - ], - "data": "QDZmNmI=", - "additionalData": null - } - ] - }, - "operation": "transfer" - }, - { - "hash": "db5d74970374337956fa61fb4fd90057b3f6a82ea3e259b389934b71a1652e5f", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "ESDTSetRole@47454e2d383638353933@45534454526f6c654e4654437265617465", - "prevTxHash": "83494ad9369738b574a7266cbfb12ce63ccf634950cd6b0ec16107b8fb42f8f6", - "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "identifier": "ESDTSetRole", - "topics": [ - "R0VOLTg2ODU5Mw==", - "", - "", - "RVNEVFJvbGVORlRDcmVhdGU=" - ], - "data": null, - "additionalData": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "identifier": "completedTxEvent", - "topics": [ - "g0lK2TaXOLV0pyZsv7Es5jzPY0lQzWsOwWEHuPtC+PY=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "ESDTSetRole", - "function": "ESDTSetRole" - }, - { - "hash": "a6a665f47977a59c4c2baf460281fc938e04ae0f87ac2e78040a14ae27822701", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "@00", - "prevTxHash": "83494ad9369738b574a7266cbfb12ce63ccf634950cd6b0ec16107b8fb42f8f6", - "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", - "gasLimit": 92399698, - "gasPrice": 1000000000, - "callType": 2, - "originalSender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "identifier": "writeLog", - "topics": [ - "AAAAAAAAAAAFAN5R+olDwm5pM0Gfm7fOt5t/9Pe7qlo=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gOTIzOTk2OTgsIGdhcyB1c2VkID0gMzE0MTg4MA==" - ], - "data": "QDZmNmI=", - "additionalData": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "identifier": "completedTxEvent", - "topics": [ - "g0lK2TaXOLV0pyZsv7Es5jzPY0lQzWsOwWEHuPtC+PY=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "transfer" - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "identifier": "transferValueOnly", - "topics": [ - "AAAAAAAAAAAFAN5R+olDwm5pM0Gfm7fOt5t/9Pe7qlo=", - "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=", - "saK8LsUAAA==" - ], - "data": null, - "additionalData": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", - "identifier": "writeLog", - "topics": [ - "0q010iL23pLKW4FcYNxxAVvhcrYh6GgrGH5sMAvWqlo=" - ], - "data": "QDZmNmI=", - "additionalData": null - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "issueToken", - "initiallyPaidFee": "2097020000000000", - "fee": "2097020000000000", - "chainID": "D", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" -} - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Option = Some("GEN-868593".to_string()); - - assert_eq!(tx_response.new_issued_token_identifier, expected) - } - - #[test] - fn test_process_issued_token_identifier_meta_esdt() { - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", - "nonce": 419, - "round": 1787093, - "epoch": 744, - "value": "50000000000000000", - "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "sender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "gasUsed": 157220928, - "data": "ZGVwbG95QXNoc3dhcExQQUNTdHJhdGVneUA0MTRjNTAyZDYzNjE2NTYxNjMzNUA0MTU0NTMyZDM0NjMzMDM5MzIzMEAwM2U4QDAzZThAQDNiOWFjYTAwQDAwMDAwMDAwMDAwMDAwMDAwNTAwOTU3MzkwYWVkYTQzMmY1MmE0MTFkNTE5NzRmZTkzZDQwZDI3NzMzZTA0NjNAMDAwMDAwMDAwMDAwMDAwMDA1MDBkMTJjYzczY2JkYTZmMjY1OWM5NTllNWQ1NzU4YWY5MmNhMTM4NDg2NTIzM0AwMDAwMDAwMDAwMDAwMDAwMDUwMDUxZGY3MTc1OGNmMmFjYTViNDZkZWQ4MTU1OGI1NTE1ZGMyOWYzZjM1MjMzQEAwMDAwMDAwMDAwMDAwMDAwMDUwMDdlNGExZGZjNDM3Y2VkNDlkYjlmMTYzNzk4NDE2Yjg0YWMyMWQ0Yzk3Y2ViMDAwMDAwMGM1NzQ1NDc0YzQ0MmQ2MTMyMzg2MzM1MzkwMDAwMDAwMDAwMDAwMDAwMDUwMGE4YmE5ZTY4NjI2YmJjOTkzZmQ3OTVlOGJiNmY0Nzk0M2IyZjVmZmE3Y2ViMDAwMDAwMGE1NTU0NGIyZDMxMzQ2NDM1Mzc2NEAwMDAwMDAwMTAwMDAwMDAwMDAwMDAwMDAwNTAwNTFkZjcxNzU4Y2YyYWNhNWI0NmRlZDgxNTU4YjU1MTVkYzI5ZjNmMzUyMzMwMDAwMDAwYjQyNTU1MzQ0MmQ2NDM0NjMzMDMxMzQwMDAwMDAwMDAwQDAxODZhMEAyNzEw", - "signature": "4648af0b96eb430e4986b9fb760549742de09c809b46b984e5d995c898d80c25bfc0717c30da34bd89cd3005d98ee895afa39ee588b7b74b4807c63cbeade807", - "sourceShard": 1, - "destinationShard": 1, - "blockNonce": 1785520, - "blockHash": "8f926a5d79fa84bc69949a21bfbba17447091a8a074ac172fa0b88e4475a1214", - "notarizedAtSourceInMetaNonce": 1785568, - "NotarizedAtSourceInMetaHash": "eebd1aa5c3dde083f9c367242c054affedd36bfc95f7bcc1d4e2d90beb5754e9", - "notarizedAtDestinationInMetaNonce": 1785568, - "notarizedAtDestinationInMetaHash": "eebd1aa5c3dde083f9c367242c054affedd36bfc95f7bcc1d4e2d90beb5754e9", - "miniblockType": "TxBlock", - "miniblockHash": "b85d82db6d69cbc1911b3455d2837eeb3170b391926efa2eacb4d9c8e3c96ee4", - "hyperblockNonce": 1785568, - "hyperblockHash": "eebd1aa5c3dde083f9c367242c054affedd36bfc95f7bcc1d4e2d90beb5754e9", - "timestamp": 1704722558, - "smartContractResults": [ - { - "hash": "ea9a96c079e66249e6b73c0341991dad96ca81f855f2fc4abe0d432be117a882", - "nonce": 420, - "value": 4427790720000000, - "receiver": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "data": "@6f6b", - "prevTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", - "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "operation": "transfer", - "isRefund": true - }, - { - "hash": "6082975132a2c9d8197dfd0f9852b454ad344740eebdbdf93f620b2796ab723b", - "nonce": 0, - "value": 50000000000000000, - "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "data": "registerMetaESDT@415453417368537761704c5041435661756c74@4156415348@12@63616e467265657a65@66616c7365@63616e57697065@66616c7365@63616e5061757365@66616c7365@63616e5472616e736665724e4654437265617465526f6c65@66616c7365@63616e4368616e67654f776e6572@66616c7365@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@74727565@9eb30a87c92674ab1469700c0b385b3850e86de80f87dec6cf3213c7e379a646@408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43@03eb4a30", - "prevTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", - "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", - "gasLimit": 125751600, - "gasPrice": 1000000000, - "callType": 1, - "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "operation": "transfer", - "function": "registerMetaESDT" - }, - { - "hash": "290f85d7ec2f7d5797510290358e9e0f76bb880451efaacb0d69280b8d94c67a", - "nonce": 0, - "value": 0, - "receiver": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "ESDTSetBurnRoleForAll@41564153482d376438623564", - "prevTxHash": "6082975132a2c9d8197dfd0f9852b454ad344740eebdbdf93f620b2796ab723b", - "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "logs": { - "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", - "events": [ - { - "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", - "identifier": "completedTxEvent", - "topics": [ - "YIKXUTKiydgZff0PmFK0VK00R0Duvb35P2ILJ5arcjs=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "transfer" - }, - { - "hash": "1aa62a6251edd216bd4e5ae59f7e676d5d2f88597685e0ec0e25ac4434bfccdb", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "@00@41564153482d376438623564@d0644194444642fd16ee156307f6fda0e8f8baf4c496e1a1dc85e027ecc08a4a@9eb30a87c92674ab1469700c0b385b3850e86de80f87dec6cf3213c7e379a646@408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43@00", - "prevTxHash": "6082975132a2c9d8197dfd0f9852b454ad344740eebdbdf93f620b2796ab723b", - "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", - "gasLimit": 75751600, - "gasPrice": 1000000000, - "callType": 2, - "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "writeLog", - "topics": [ - "AAAAAAAAAAAFAH6UefeHERqHcLpMz2gC3xXGhFsJBGM=", - "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNzU3NTE2MDAsIGdhcyB1c2VkID0gNDE3NjA1OQ==" - ], - "data": "QDZmNmI=", - "additionalData": [ - "QDZmNmI=" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "completedTxEvent", - "topics": [ - "YIKXUTKiydgZff0PmFK0VK00R0Duvb35P2ILJ5arcjs=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "transfer" - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=" - ], - "data": "RGVwbG95RnJvbVNvdXJjZQ==", - "additionalData": [ - "RGVwbG95RnJvbVNvdXJjZQ==", - "aW5pdA==", - "QUxQLWNhZWFjNQ==", - "QVRTLTRjMDkyMA==", - "A+g=", - "A+g=", - "", - "O5rKAA==" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAFADJ0SE0vUW6bO5SurLeFIMfK/HtBBGM=" - ], - "data": "RGVwbG95RnJvbVNvdXJjZQ==", - "additionalData": [ - "RGVwbG95RnJvbVNvdXJjZQ==", - "aW5pdA==", - "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=", - "AAAAAAAAAAAFAJVzkK7aQy9SpBHVGXT+k9QNJ3M+BGM=", - "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=", - "AAAAAAAAAAAFAFHfcXWM8qyltG3tgVWLVRXcKfPzUjM=", - "", - "AAAAAAAAAAAFAH5KHfxDfO1J258WN5hBa4SsIdTJfOsAAAAMV0VHTEQtYTI4YzU5AAAAAAAAAAAFAKi6nmhia7yZP9eV6LtvR5Q7L1/6fOsAAAAKVVRLLTE0ZDU3ZA==", - "AAAAAQAAAAAAAAAABQBR33F1jPKspbRt7YFVi1UV3Cnz81IzAAAAC0JVU0QtZDRjMDE0AAAAAAA=", - "AYag", - "JxA=" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=" - ], - "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "additionalData": [ - "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "Z2V0RmFybWluZ1Rva2VuSWQ=" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=" - ], - "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "additionalData": [ - "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "Z2V0RmFybVRva2VuSWQ=" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=" - ], - "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "additionalData": [ - "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "Z2V0UmV3YXJkVG9rZW5JZA==" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "transferValueOnly", - "topics": [ - "saK8LsUAAA==", - "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=" - ], - "data": "QXN5bmNDYWxs", - "additionalData": [ - "QXN5bmNDYWxs", - "cmVnaXN0ZXJNZXRhRVNEVA==", - "QVRTQXNoU3dhcExQQUNWYXVsdA==", - "QVZBU0g=", - "Eg==", - "Y2FuRnJlZXpl", - "ZmFsc2U=", - "Y2FuV2lwZQ==", - "ZmFsc2U=", - "Y2FuUGF1c2U=", - "ZmFsc2U=", - "Y2FuVHJhbnNmZXJORlRDcmVhdGVSb2xl", - "ZmFsc2U=", - "Y2FuQ2hhbmdlT3duZXI=", - "ZmFsc2U=", - "Y2FuVXBncmFkZQ==", - "ZmFsc2U=", - "Y2FuQWRkU3BlY2lhbFJvbGVz", - "dHJ1ZQ==" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", - "identifier": "SCDeploy", - "topics": [ - "AAAAAAAAAAAFADJ0SE0vUW6bO5SurLeFIMfK/HtBBGM=", - "AAAAAAAAAAAFAH6UefeHERqHcLpMz2gC3xXGhFsJBGM=", - "fvRqbue54Womde/CN2IkRGkrx8tsU+xkLvi3+uwMkhY=" - ], - "data": null, - "additionalData": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", - "identifier": "SCDeploy", - "topics": [ - "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=", - "AAAAAAAAAAAFAH6UefeHERqHcLpMz2gC3xXGhFsJBGM=", - "E3blQfRJfCKLWDr06Od703DSZenIzq8KND+xUjmGY/M=" - ], - "data": null, - "additionalData": null - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "deployAshswapLPACStrategy", - "initiallyPaidFee": "6936045000000000", - "fee": "2508254280000000", - "chainID": "D", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" -} - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Option = Some("AVASH-7d8b5d".to_string()); - - assert_eq!(tx_response.new_issued_token_identifier, expected) - } - - #[test] - fn test_set_special_roles_should_not_process_issued_token_identifier() { - let data = r#" - { - "data": { - "transaction": { - "type": "normal", - "processingTypeOnSource": "SCInvoking", - "processingTypeOnDestination": "SCInvoking", - "hash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "nonce": 420, - "round": 1787109, - "epoch": 744, - "value": "0", - "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "sender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "gasPrice": 1000000000, - "gasLimit": 600000000, - "gasUsed": 129636807, - "data": "ZmluaXNoVmF1bHREZXBsb3ltZW50cw==", - "signature": "dca943ef1a788bfa6cb0e9aa3900b8340e4908075cbfefaa2a66688f6f0c0fed349edb2eb48eec427cd9098822fba875e4d66072fbdb44cb7f4c1a416736e20c", - "sourceShard": 1, - "destinationShard": 1, - "blockNonce": 1785536, - "blockHash": "93ca539e81612768b67a85b7135f7c104e76bec031a758a6b1782910ae49dd8f", - "notarizedAtSourceInMetaNonce": 1785584, - "NotarizedAtSourceInMetaHash": "71d17afe660282bb42de1ea3eec3e3534a179bd32aa1471c2861ce411bf30552", - "notarizedAtDestinationInMetaNonce": 1785584, - "notarizedAtDestinationInMetaHash": "71d17afe660282bb42de1ea3eec3e3534a179bd32aa1471c2861ce411bf30552", - "miniblockType": "TxBlock", - "miniblockHash": "f8c60565af746e92d2c9c09a92734e5eb8da7e42c67a86854c93b349bfe287eb", - "hyperblockNonce": 1785584, - "hyperblockHash": "71d17afe660282bb42de1ea3eec3e3534a179bd32aa1471c2861ce411bf30552", - "timestamp": 1704722654, - "smartContractResults": [ - { - "hash": "c3ce9c364de3823ffae250c2bfb40aaf2b18f771ed4bd37bf788ad83a2c651f3", - "nonce": 421, - "value": 4703631930000000, - "receiver": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "data": "@6f6b", - "prevTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "operation": "transfer", - "isRefund": true - }, - { - "hash": "50f9c25a1402ce6d87ae9f890659c8a67462292e471e02c74d64ff7ba1995e60", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "data": "setSpecialRole@41564153482d376438623564@00000000000000000500d00cc0e63887ff6b792d34234a44e7ac6b575d4b0463@45534454526f6c654e4654437265617465@45534454526f6c654e46544164645175616e74697479@45534454526f6c654e46544275726e@0192c6db2c69f50b6968fb22ac558337a851719519cfd1e6bbf79a07bbcf18bc@cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0@03eb4a30", - "prevTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "gasLimit": 125751600, - "gasPrice": 1000000000, - "callType": 1, - "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "operation": "transfer", - "function": "setSpecialRole" - }, - { - "hash": "d6a5824a60b6c9050462c3f5a02ace00c36e8b4ba1958d132bd394e2ed1e7226", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "ESDTSetRole@41564153482d376438623564@45534454526f6c654e4654437265617465@45534454526f6c654e46544164645175616e74697479@45534454526f6c654e46544275726e", - "prevTxHash": "50f9c25a1402ce6d87ae9f890659c8a67462292e471e02c74d64ff7ba1995e60", - "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", - "identifier": "ESDTSetRole", - "topics": [ - "QVZBU0gtN2Q4YjVk", - "", - "", - "RVNEVFJvbGVORlRDcmVhdGU=", - "RVNEVFJvbGVORlRBZGRRdWFudGl0eQ==", - "RVNEVFJvbGVORlRCdXJu" - ], - "data": null, - "additionalData": null - }, - { - "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", - "identifier": "completedTxEvent", - "topics": [ - "UPnCWhQCzm2Hrp+JBlnIpnRiKS5HHgLHTWT/e6GZXmA=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "ESDTSetRole", - "function": "ESDTSetRole" - }, - { - "hash": "bf1b8b4b301ff548368dfd972896489d5e2a088d5cbdfa1bfe2421cc7f641f7a", - "nonce": 0, - "value": 0, - "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - "data": "@00@a68d44c751eba85db0713db8dc9c10c78749189ec0d6f1af5fc67bb656c1254b@0192c6db2c69f50b6968fb22ac558337a851719519cfd1e6bbf79a07bbcf18bc@cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0@00", - "prevTxHash": "50f9c25a1402ce6d87ae9f890659c8a67462292e471e02c74d64ff7ba1995e60", - "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "gasLimit": 75751600, - "gasPrice": 1000000000, - "callType": 2, - "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=" - ], - "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "additionalData": [ - "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "c2V0U2hhcmVUb2tlbklkZW50aWZpZXI=", - "QVZBU0gtN2Q4YjVk" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=" - ], - "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "additionalData": [ - "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", - "c2V0U3RyYXRlZ3lBZGRyZXNz", - "AAAAAAAAAAAFADJ0SE0vUW6bO5SurLeFIMfK/HtBBGM=" - ] - }, - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "completedTxEvent", - "topics": [ - "UPnCWhQCzm2Hrp+JBlnIpnRiKS5HHgLHTWT/e6GZXmA=" - ], - "data": null, - "additionalData": null - } - ] - }, - "operation": "transfer" - }, - { - "hash": "9d75a398545f488d4764149245e6ec3101debfce99477c353ac11c3239acd897", - "nonce": 1, - "value": 648519550000000, - "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "data": "@6f6b", - "prevTxHash": "bf1b8b4b301ff548368dfd972896489d5e2a088d5cbdfa1bfe2421cc7f641f7a", - "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", - "gasLimit": 0, - "gasPrice": 1000000000, - "callType": 0, - "operation": "transfer", - "isRefund": true - } - ], - "logs": { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "events": [ - { - "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", - "identifier": "transferValueOnly", - "topics": [ - "", - "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=" - ], - "data": "QXN5bmNDYWxs", - "additionalData": [ - "QXN5bmNDYWxs", - "c2V0U3BlY2lhbFJvbGU=", - "QVZBU0gtN2Q4YjVk", - "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=", - "RVNEVFJvbGVORlRDcmVhdGU=", - "RVNEVFJvbGVORlRBZGRRdWFudGl0eQ==", - "RVNEVFJvbGVORlRCdXJu" - ] - } - ] - }, - "status": "success", - "operation": "transfer", - "function": "finishVaultDeployments", - "initiallyPaidFee": "6082170000000000", - "fee": "1378538070000000", - "chainID": "D", - "version": 1, - "options": 0 - } - }, - "error": "", - "code": "successful" -} - "#; - - let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) - .unwrap() - .data - .unwrap() - .transaction; - let tx_response = TxResponse::from_network_tx(tx_on_network); - - let expected: Option = None; - - assert_eq!(tx_response.new_issued_token_identifier, expected) - } -} diff --git a/framework/scenario/src/scenario/model/value/address_key.rs b/framework/scenario/src/scenario/model/value/address_key.rs index 5bbc1d79ae..f54e05b2f3 100644 --- a/framework/scenario/src/scenario/model/value/address_key.rs +++ b/framework/scenario/src/scenario/model/value/address_key.rs @@ -1,6 +1,8 @@ +use multiversx_sc::types::{Address, TestAddress, TestSCAddress}; + use super::{value_from_slice, AddressValue}; use crate::{ - multiversx_sc::types::Address, + facade::expr::Bech32Address, scenario_format::{ interpret_trait::{InterpretableFrom, InterpreterContext, IntoRaw}, value_interpreter::interpret_string, @@ -114,3 +116,39 @@ impl From<&Address> for AddressKey { } } } + +impl From<&Bech32Address> for AddressKey { + fn from(from: &Bech32Address) -> Self { + AddressKey { + value: from.to_address().clone(), + original: from.to_bech32_expr(), + } + } +} + +impl From for AddressKey { + fn from(from: Bech32Address) -> Self { + AddressKey { + original: from.to_bech32_expr(), + value: from.into_address(), + } + } +} + +impl From> for AddressKey { + fn from(from: TestAddress) -> Self { + AddressKey { + value: from.eval_to_array().into(), + original: from.eval_to_expr(), + } + } +} + +impl From> for AddressKey { + fn from(from: TestSCAddress) -> Self { + AddressKey { + value: from.eval_to_array().into(), + original: from.eval_to_expr(), + } + } +} diff --git a/framework/scenario/src/scenario/model/value/address_value.rs b/framework/scenario/src/scenario/model/value/address_value.rs index 85886e4cf8..fdde631ede 100644 --- a/framework/scenario/src/scenario/model/value/address_value.rs +++ b/framework/scenario/src/scenario/model/value/address_value.rs @@ -1,11 +1,18 @@ +use multiversx_sc::{ + api::ManagedTypeApi, + types::{AnnotatedValue, ManagedAddress, ManagedBuffer, TxEnv, TxFrom, TxFromSpecified}, +}; use std::fmt; -use crate::multiversx_sc::types::Address; +use crate::multiversx_sc::types::{Address, TestAddress, TestSCAddress}; -use crate::scenario_format::{ - interpret_trait::{InterpretableFrom, InterpreterContext, IntoRaw}, - serde_raw::ValueSubTree, - value_interpreter::{interpret_string, interpret_subtree}, +use crate::{ + facade::expr::Bech32Address, + scenario_format::{ + interpret_trait::{InterpretableFrom, InterpreterContext, IntoRaw}, + serde_raw::ValueSubTree, + value_interpreter::{interpret_string, interpret_subtree}, + }, }; use super::AddressKey; @@ -107,8 +114,124 @@ impl From<&Address> for AddressValue { } } +impl From<&Bech32Address> for AddressValue { + fn from(from: &Bech32Address) -> Self { + AddressValue { + value: from.to_address().clone(), + original: ValueSubTree::Str(from.to_bech32_expr()), + } + } +} + +impl From for AddressValue { + fn from(from: Bech32Address) -> Self { + AddressValue { + original: ValueSubTree::Str(from.to_bech32_expr()), + value: from.into_address(), + } + } +} + impl From<&str> for AddressValue { fn from(from: &str) -> Self { AddressValue::interpret_from(from, &InterpreterContext::default()) } } + +impl From> for AddressValue { + fn from(from: TestAddress) -> Self { + AddressValue { + value: from.eval_to_array().into(), + original: ValueSubTree::Str(from.eval_to_expr()), + } + } +} + +impl From> for AddressValue { + fn from(from: TestSCAddress) -> Self { + AddressValue { + value: from.eval_to_array().into(), + original: ValueSubTree::Str(from.eval_to_expr()), + } + } +} + +impl From<&AddressValue> for ManagedAddress +where + M: ManagedTypeApi, +{ + #[inline] + fn from(address_value: &AddressValue) -> Self { + ManagedAddress::from_address(&address_value.value) + } +} + +impl TxFrom for AddressValue +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + self.into() + } +} + +impl AnnotatedValue> for AddressValue +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> multiversx_sc::types::ManagedBuffer { + ManagedBuffer::from(self.original.to_string()) + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + ManagedAddress::from_address(&self.value) + } + + fn into_value(self, _env: &Env) -> ManagedAddress { + ManagedAddress::from_address(&self.value) + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&ManagedAddress) -> R, + { + f(&ManagedAddress::from_address(&self.value)) + } +} + +impl AnnotatedValue> for &AddressValue +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> multiversx_sc::types::ManagedBuffer { + ManagedBuffer::from(self.original.to_string()) + } + + fn to_value(&self, _env: &Env) -> ManagedAddress { + ManagedAddress::from_address(&self.value) + } + + fn into_value(self, _env: &Env) -> ManagedAddress { + ManagedAddress::from_address(&self.value) + } + + fn with_value_ref(&self, _env: &Env, f: F) -> R + where + F: FnOnce(&ManagedAddress) -> R, + { + f(&ManagedAddress::from_address(&self.value)) + } +} + +impl TxFromSpecified for AddressValue where Env: TxEnv {} + +impl TxFrom for &AddressValue +where + Env: TxEnv, +{ + fn resolve_address(&self, _env: &Env) -> ManagedAddress { + ManagedAddress::from_address(&self.value) + } +} + +impl TxFromSpecified for &AddressValue where Env: TxEnv {} diff --git a/framework/scenario/src/scenario/model/value/value_check.rs b/framework/scenario/src/scenario/model/value/value_check.rs index 5299aa9e1b..9091f73594 100644 --- a/framework/scenario/src/scenario/model/value/value_check.rs +++ b/framework/scenario/src/scenario/model/value/value_check.rs @@ -21,6 +21,10 @@ where pub fn is_star(&self) -> bool { matches!(self, CheckValue::Star) } + + pub fn is_equal_to(&self, _value: T) -> bool { + matches!(self, CheckValue::Equal(_value)) + } } impl InterpretableFrom for CheckValue diff --git a/framework/scenario/src/scenario/model/value/value_set_big_uint.rs b/framework/scenario/src/scenario/model/value/value_set_big_uint.rs index c21c913851..003370509d 100644 --- a/framework/scenario/src/scenario/model/value/value_set_big_uint.rs +++ b/framework/scenario/src/scenario/model/value/value_set_big_uint.rs @@ -95,7 +95,7 @@ impl From<&BigUint> for BigUintValue { impl From> for BigUintValue { fn from(from: crate::multiversx_sc::types::BigUint) -> Self { - let value = BigUint::from_bytes_be(from.to_bytes_be().as_slice()); + let value = from.to_alloc(); BigUintValue { original: ValueSubTree::Str(value.to_string()), value, @@ -103,6 +103,17 @@ impl From> for BigUin } } +impl From> + for BigUintValue +{ + fn from(from: crate::multiversx_sc::types::AnnotatedEgldPayment) -> Self { + BigUintValue { + value: from.value.to_alloc(), + original: ValueSubTree::Str(from.annotation.to_string()), + } + } +} + impl From<&str> for BigUintValue { fn from(from: &str) -> Self { BigUintValue::interpret_from(from, &InterpreterContext::default()) diff --git a/framework/scenario/src/scenario/model/value/value_set_bytes.rs b/framework/scenario/src/scenario/model/value/value_set_bytes.rs index 33fb896d01..627f2ace9c 100644 --- a/framework/scenario/src/scenario/model/value/value_set_bytes.rs +++ b/framework/scenario/src/scenario/model/value/value_set_bytes.rs @@ -1,3 +1,5 @@ +use multiversx_sc::types::{AnnotatedValue, ManagedBuffer, TxCodeValue, TxEnv}; + use crate::scenario_format::{ interpret_trait::{InterpretableFrom, InterpreterContext, IntoRaw}, serde_raw::ValueSubTree, @@ -134,3 +136,33 @@ impl fmt::Display for BytesValue { self.original.fmt(f) } } + +impl AnnotatedValue> for BytesValue +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer<::Api> { + self.original.to_concatenated_string().into() + } + + fn to_value(&self, _env: &Env) -> ManagedBuffer { + self.value.clone().into() + } +} + +impl TxCodeValue for BytesValue where Env: TxEnv {} + +impl AnnotatedValue> for &BytesValue +where + Env: TxEnv, +{ + fn annotation(&self, _env: &Env) -> ManagedBuffer<::Api> { + self.original.to_concatenated_string().into() + } + + fn to_value(&self, _env: &Env) -> ManagedBuffer { + self.value.clone().into() + } +} + +impl TxCodeValue for &BytesValue where Env: TxEnv {} diff --git a/framework/scenario/src/scenario/model/value/value_set_u64.rs b/framework/scenario/src/scenario/model/value/value_set_u64.rs index 1fdabe5cf7..b332543116 100644 --- a/framework/scenario/src/scenario/model/value/value_set_u64.rs +++ b/framework/scenario/src/scenario/model/value/value_set_u64.rs @@ -36,6 +36,15 @@ impl Default for U64Value { } } +impl InterpretableFrom for U64Value { + fn interpret_from(from: u64, _context: &InterpreterContext) -> Self { + U64Value { + value: from, + original: ValueSubTree::Str(from.to_string()), + } + } +} + impl InterpretableFrom for U64Value { fn interpret_from(from: ValueSubTree, context: &InterpreterContext) -> Self { let bytes = interpret_subtree(&from, context); diff --git a/framework/scenario/src/scenario/run_vm/sc_call.rs b/framework/scenario/src/scenario/run_vm/sc_call.rs index abbe9ee6ff..0a66578eaf 100644 --- a/framework/scenario/src/scenario/run_vm/sc_call.rs +++ b/framework/scenario/src/scenario/run_vm/sc_call.rs @@ -1,6 +1,6 @@ use crate::{ - multiversx_sc::codec::{CodecFrom, PanicErrorHandler, TopEncodeMulti}, - scenario::model::{ScCallStep, TxESDT, TypedScCall}, + multiversx_sc::codec::{PanicErrorHandler, TopEncodeMulti}, + scenario::model::{ScCallStep, TxESDT}, scenario_model::TxResponse, }; @@ -8,6 +8,7 @@ use multiversx_chain_vm::{ tx_execution::execute_current_tx_context_input, tx_mock::{TxInput, TxResult, TxTokenTransfer}, }; +use multiversx_sc::{abi::TypeAbiFrom, codec::TopDecodeMulti}; use super::{check_tx_output, tx_input_util::generate_tx_hash, ScenarioVMRunner}; @@ -28,13 +29,18 @@ impl ScenarioVMRunner { /// /// It takes the `contract_call` argument separately from the SC call step, /// so we can benefit from type inference in the result. + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] + #[allow(deprecated)] pub fn perform_sc_call_get_result( &mut self, - typed_sc_call: TypedScCall, + typed_sc_call: crate::scenario_model::TypedScCall, ) -> RequestedResult where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { let sc_call_step: ScCallStep = typed_sc_call.into(); let tx_result = diff --git a/framework/scenario/src/scenario/run_vm/set_state.rs b/framework/scenario/src/scenario/run_vm/set_state.rs index 187ba21e83..8284d42422 100644 --- a/framework/scenario/src/scenario/run_vm/set_state.rs +++ b/framework/scenario/src/scenario/run_vm/set_state.rs @@ -1,7 +1,7 @@ use crate::scenario::model::SetStateStep; use multiversx_chain_vm::{ - types::{VMAddress, VMCodeMetadata}, + types::VMCodeMetadata, world_mock::{ AccountData, AccountEsdt, BlockInfo as CrateBlockInfo, BlockchainState, EsdtData, EsdtInstance, EsdtInstanceMetadata, EsdtInstances, EsdtRoles, @@ -155,7 +155,7 @@ fn convert_scenario_esdt_instance_to_world_mock( creator: scenario_esdt .creator .as_ref() - .map(|creator| VMAddress::from_slice(creator.value.as_slice())), + .map(|creator| creator.to_vm_address()), royalties: scenario_esdt .royalties .as_ref() diff --git a/framework/scenario/src/scenario/tx_to_step.rs b/framework/scenario/src/scenario/tx_to_step.rs new file mode 100644 index 0000000000..82e236e48b --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step.rs @@ -0,0 +1,11 @@ +mod step_annotation; +mod step_wrapper; +mod tx_to_step_call; +mod tx_to_step_deploy; +mod tx_to_step_query; +mod tx_to_step_trait; +mod tx_to_step_transfer; + +pub use step_annotation::*; +pub use step_wrapper::{StepWithResponse, StepWrapper}; +pub use tx_to_step_trait::*; diff --git a/framework/scenario/src/scenario/tx_to_step/step_annotation.rs b/framework/scenario/src/scenario/tx_to_step/step_annotation.rs new file mode 100644 index 0000000000..2a5a2dac51 --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step/step_annotation.rs @@ -0,0 +1,87 @@ +use multiversx_chain_scenario_format::serde_raw::ValueSubTree; +use multiversx_sc::types::{ + AnnotatedValue, BigUint, Code, ManagedAddress, ManagedBuffer, TokenIdentifier, TxCodeValue, + TxEnv, TxGas, +}; + +use crate::scenario_model::{AddressValue, BigUintValue, BytesKey, BytesValue, U64Value}; + +pub fn address_annotated(env: &Env, from: &Addr) -> AddressValue +where + Env: TxEnv, + Addr: AnnotatedValue>, +{ + let annotation = from.annotation(env).to_string(); + AddressValue { + value: from.to_value(env).to_address(), + original: ValueSubTree::Str(annotation), + } +} + +pub fn u64_annotated(env: &Env, from: &T) -> U64Value +where + Env: TxEnv, + T: AnnotatedValue, +{ + let annotation = from.annotation(env).to_string(); + U64Value { + value: from.to_value(env), + original: ValueSubTree::Str(annotation), + } +} + +pub fn big_uint_annotated(env: &Env, from: &T) -> BigUintValue +where + Env: TxEnv, + T: AnnotatedValue>, +{ + let annotation = from.annotation(env).to_string(); + BigUintValue { + value: from.to_value(env).to_alloc(), + original: ValueSubTree::Str(annotation), + } +} + +pub fn bytes_annotated(env: &Env, value: T) -> BytesValue +where + Env: TxEnv, + T: AnnotatedValue>, +{ + let annotation = value.annotation(env).to_string(); + BytesValue { + value: value.into_value(env).to_vec(), + original: ValueSubTree::Str(annotation), + } +} + +pub fn token_identifier_annotated(env: &Env, value: T) -> BytesKey +where + Env: TxEnv, + T: AnnotatedValue>, +{ + let annotation = value.annotation(env).to_string(); + BytesKey { + value: value.into_value(env).into_managed_buffer().to_vec(), + original: annotation, + } +} + +pub fn code_annotated(env: &Env, code: Code) -> BytesValue +where + Env: TxEnv, + CodeValue: TxCodeValue, +{ + bytes_annotated(env, code.0) +} + +pub fn gas_annotated(env: &Env, gas: Gas) -> U64Value +where + Env: TxEnv, + Gas: TxGas, +{ + let annotation = gas.gas_annotation(env).to_string(); + U64Value { + value: gas.gas_value(env), + original: ValueSubTree::Str(annotation), + } +} diff --git a/framework/scenario/src/scenario/tx_to_step/step_wrapper.rs b/framework/scenario/src/scenario/tx_to_step/step_wrapper.rs new file mode 100644 index 0000000000..9d9a0199d5 --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step/step_wrapper.rs @@ -0,0 +1,48 @@ +use multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{RHListExec, TxEnv}, +}; + +use crate::scenario_model::{ScCallStep, ScDeployStep, ScQueryStep, TxResponse}; + +pub struct StepWrapper { + pub env: Env, + pub step: Step, + pub result_handler: RH, +} + +impl StepWrapper +where + Env: TxEnv, + Step: StepWithResponse, + RH: RHListExec, + RH::ListReturns: NestedTupleFlatten, +{ + pub fn process_result(self) -> ::Unpacked { + let response = self.step.into_response(); + let tuple_result = self.result_handler.list_process_result(&response); + tuple_result.flatten_unpack() + } +} + +pub trait StepWithResponse { + fn into_response(self) -> TxResponse; +} + +impl StepWithResponse for ScCallStep { + fn into_response(self) -> TxResponse { + self.response.expect("SC call step did not return result") + } +} + +impl StepWithResponse for ScDeployStep { + fn into_response(self) -> TxResponse { + self.response.expect("SC deploy step did not return result") + } +} + +impl StepWithResponse for ScQueryStep { + fn into_response(self) -> TxResponse { + self.response.expect("SC query step did not return result") + } +} diff --git a/framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs b/framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs new file mode 100644 index 0000000000..7daa8ac810 --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs @@ -0,0 +1,77 @@ +use multiversx_sc::types::{ + FunctionCall, RHListExec, Tx, TxEnv, TxFromSpecified, TxGas, TxPayment, TxToSpecified, +}; + +use crate::scenario_model::{ScCallStep, TxESDT, TxExpect, TxResponse}; + +use super::{address_annotated, gas_annotated, StepWrapper, TxToStep}; + +impl TxToStep + for Tx, RH> +where + Env: TxEnv, + From: TxFromSpecified, + To: TxToSpecified, + Payment: TxPayment, + Gas: TxGas, + RH: RHListExec, +{ + type Step = ScCallStep; + + fn tx_to_step(self) -> StepWrapper { + let mut step = tx_to_sc_call_step( + &self.env, + self.from, + self.to, + self.payment, + self.gas, + self.data, + ); + step.expect = Some(self.result_handler.list_tx_expect()); + + StepWrapper { + env: self.env, + step, + result_handler: self.result_handler, + } + } +} + +pub fn tx_to_sc_call_step( + env: &Env, + from: From, + to: To, + payment: Payment, + gas: Gas, + data: FunctionCall, +) -> ScCallStep +where + Env: TxEnv, + From: TxFromSpecified, + To: TxToSpecified, + Payment: TxPayment, + Gas: TxGas, +{ + let mut step = ScCallStep::new() + .from(address_annotated(env, &from)) + .to(address_annotated(env, &to)) + .function(data.function_name.to_string().as_str()); + for arg in data.arg_buffer.iter_buffers() { + step.tx.arguments.push(arg.to_vec().into()); + } + + step.tx.gas_limit = gas_annotated(env, gas); + + 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/scenario/src/scenario/tx_to_step/tx_to_step_deploy.rs b/framework/scenario/src/scenario/tx_to_step/tx_to_step_deploy.rs new file mode 100644 index 0000000000..4e49be51b4 --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_deploy.rs @@ -0,0 +1,63 @@ +use multiversx_sc::types::{ + Code, DeployCall, RHListExec, Tx, TxCodeValue, TxEnv, TxFromSpecified, TxGas, TxPayment, +}; + +use crate::scenario_model::{ScDeployStep, TxExpect, TxResponse}; + +use super::{address_annotated, code_annotated, gas_annotated, StepWrapper, TxToStep}; + +impl TxToStep + for Tx>, RH> +where + Env: TxEnv, + From: TxFromSpecified, + Payment: TxPayment, + Gas: TxGas, + CodeValue: TxCodeValue, + RH: RHListExec, +{ + type Step = ScDeployStep; + + fn tx_to_step(self) -> StepWrapper { + let mut step = + tx_to_sc_deploy_step(&self.env, self.from, self.payment, self.gas, self.data); + step.expect = Some(self.result_handler.list_tx_expect()); + + StepWrapper { + env: self.env, + step, + result_handler: self.result_handler, + } + } +} + +pub fn tx_to_sc_deploy_step( + env: &Env, + from: From, + payment: Payment, + gas: Gas, + data: DeployCall>, +) -> ScDeployStep +where + Env: TxEnv, + From: TxFromSpecified, + Payment: TxPayment, + Gas: TxGas, + CodeValue: TxCodeValue, +{ + let mut step = ScDeployStep::new() + .from(address_annotated(env, &from)) + .code(code_annotated(env, data.code_source)); + for arg in data.arg_buffer.iter_buffers() { + step.tx.arguments.push(arg.to_vec().into()); + } + + step.tx.gas_limit = gas_annotated(env, gas); + + 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(); + } + + step +} diff --git a/framework/scenario/src/scenario/tx_to_step/tx_to_step_query.rs b/framework/scenario/src/scenario/tx_to_step/tx_to_step_query.rs new file mode 100644 index 0000000000..aaeb3b70c3 --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_query.rs @@ -0,0 +1,40 @@ +use multiversx_sc::types::{FunctionCall, RHListExec, Tx, TxEnv, TxToSpecified}; + +use crate::scenario_model::{ScQueryStep, TxExpect, TxResponse}; + +use super::{address_annotated, StepWrapper, TxToQueryStep}; + +impl TxToQueryStep for Tx, RH> +where + Env: TxEnv, + To: TxToSpecified, + RH: RHListExec, +{ + type Step = ScQueryStep; + + fn tx_to_query_step(self) -> StepWrapper { + let mut step = tx_to_sc_query_step(&self.env, self.to, self.data); + step.expect = Some(self.result_handler.list_tx_expect()); + + StepWrapper { + env: self.env, + step, + result_handler: self.result_handler, + } + } +} + +pub fn tx_to_sc_query_step(env: &Env, to: To, data: FunctionCall) -> ScQueryStep +where + Env: TxEnv, + To: TxToSpecified, +{ + let mut step = ScQueryStep::new() + .to(address_annotated(env, &to)) + .function(data.function_name.to_string().as_str()); + for arg in data.arg_buffer.iter_buffers() { + step.tx.arguments.push(arg.to_vec().into()); + } + + step +} diff --git a/framework/scenario/src/scenario/tx_to_step/tx_to_step_trait.rs b/framework/scenario/src/scenario/tx_to_step/tx_to_step_trait.rs new file mode 100644 index 0000000000..60615e6bb5 --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_trait.rs @@ -0,0 +1,13 @@ +use super::StepWrapper; + +pub trait TxToStep { + type Step; + + fn tx_to_step(self) -> StepWrapper; +} + +pub trait TxToQueryStep { + type Step; + + fn tx_to_query_step(self) -> StepWrapper; +} 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 new file mode 100644 index 0000000000..d2bf9636c9 --- /dev/null +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_transfer.rs @@ -0,0 +1,54 @@ +use multiversx_sc::types::{Tx, TxEnv, TxFromSpecified, TxGas, TxPayment, TxToSpecified}; + +use crate::scenario_model::TransferStep; + +use super::{address_annotated, gas_annotated, StepWrapper, TxToStep}; + +impl TxToStep for Tx +where + Env: TxEnv, + From: TxFromSpecified, + To: TxToSpecified, + Payment: TxPayment, + Gas: TxGas, +{ + type Step = TransferStep; + + fn tx_to_step(self) -> StepWrapper { + let step = tx_to_transfer_step(&self.env, self.from, self.to, self.payment, self.gas); + + StepWrapper { + env: self.env, + step, + result_handler: self.result_handler, + } + } +} + +pub fn tx_to_transfer_step( + env: &Env, + from: From, + to: To, + payment: Payment, + gas: Gas, +) -> TransferStep +where + Env: TxEnv, + From: TxFromSpecified, + To: TxToSpecified, + Payment: TxPayment, + Gas: TxGas, +{ + let mut step = TransferStep::new() + .from(address_annotated(env, &from)) + .to(address_annotated(env, &to)); + + step.tx.gas_limit = gas_annotated(env, gas); + + 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(); + } + + step +} diff --git a/framework/scenario/src/standalone/account_tool.rs b/framework/scenario/src/standalone/account_tool.rs index c1f4c5f605..1ea1e2f6b4 100644 --- a/framework/scenario/src/standalone/account_tool.rs +++ b/framework/scenario/src/standalone/account_tool.rs @@ -1,142 +1,97 @@ -use super::scenario_cli::AccountArgs; -use multiversx_chain_scenario_format::serde_raw::{ - AccountRaw, EsdtFullRaw, EsdtInstanceRaw, EsdtRaw, ScenarioRaw, StepRaw, ValueSubTree, +use crate::{ + imports::Bech32Address, + scenario_model::{Account, BytesKey, BytesValue, Scenario, SetStateStep}, }; + +use multiversx_chain_scenario_format::interpret_trait::IntoRaw; use multiversx_sdk::{ blockchain::CommunicationProxy, data::{address::Address, esdt::EsdtBalance}, }; use std::collections::{BTreeMap, HashMap}; -pub async fn print_account_as_scenario_set_state(api: String, args: &AccountArgs) { - let scenario_raw = - retrieve_account_as_scenario_set_state(api, args.address.clone(), false).await; - println!("{}", scenario_raw.to_json_string()); +pub async fn print_account_as_scenario_set_state( + api: &CommunicationProxy, + address: &Bech32Address, +) { + let set_state = retrieve_account_as_scenario_set_state(api, address).await; + let scenario = build_scenario(set_state); + println!("{}", scenario.into_raw().to_json_string()); +} + +fn build_scenario(set_state: SetStateStep) -> Scenario { + Scenario { + name: None, + comment: None, + check_gas: None, + steps: vec![crate::scenario_model::Step::SetState(set_state)], + } } pub async fn retrieve_account_as_scenario_set_state( - api: String, - addr: String, - hex_encoded: bool, -) -> ScenarioRaw { - let address = Address::from_bech32_string(&addr).unwrap(); - let blockchain = CommunicationProxy::new(api); - let account = blockchain.get_account(&address).await.unwrap(); + api: &CommunicationProxy, + address: &Bech32Address, +) -> SetStateStep { + let sdk_address = Address::from_bech32_string(address.to_bech32_str()).unwrap(); + let sdk_account = api.get_account(&sdk_address).await.unwrap(); - let account_esdt = blockchain - .get_account_esdt_tokens(&address) + let account_esdt = api + .get_account_esdt_tokens(&sdk_address) .await - .unwrap_or_else(|err| panic!("failed to retrieve ESDT tokens for address {addr}: {err}")); - let account_esdt_roles = blockchain - .get_account_esdt_roles(&address) + .unwrap_or_else(|err| { + panic!("failed to retrieve ESDT tokens for address {address}: {err}") + }); + let account_esdt_roles = api + .get_account_esdt_roles(&sdk_address) .await - .unwrap_or_else(|err| panic!("failed to retrieve ESDT roles for address {addr}: {err}")); - let account_storage = blockchain - .get_account_storage_keys(&address) + .unwrap_or_else(|err| panic!("failed to retrieve ESDT roles for address {address}: {err}")); + let account_storage = api + .get_account_storage_keys(&sdk_address) .await - .unwrap_or_else(|err| panic!("failed to retrieve storage for address {addr}: {err}")); + .unwrap_or_else(|err| panic!("failed to retrieve storage for address {address}: {err}")); - let addr_pretty = if !hex_encoded { - if account.code.is_empty() { - format!("address:{addr}") - } else { - format!("sc:{addr}") - } - } else { - format!("0x{}", hex::encode(address.to_bytes())) - }; - - let mut accounts = BTreeMap::new(); - accounts.insert( - addr_pretty, - AccountRaw { - nonce: Some(ValueSubTree::Str(account.nonce.to_string())), - balance: Some(ValueSubTree::Str(account.balance.to_string())), - esdt: convert_esdt(account_esdt, account_esdt_roles), - username: Some(ValueSubTree::Str(account.username.to_string())), - storage: convert_storage(account_storage), - comment: None, - code: retrieve_code(account.code), - code_metadata: None, // TODO: retrieve code metadata - owner: None, - developer_rewards: None, - }, + let account_state = set_account( + sdk_account, + account_storage, + account_esdt, + account_esdt_roles, ); - ScenarioRaw { - check_gas: None, - comment: None, - gas_schedule: None, - name: None, - steps: vec![StepRaw::SetState { - accounts, - block_hashes: Vec::new(), - new_addresses: Vec::new(), - new_token_identifiers: Vec::new(), - comment: None, - current_block_info: None, - previous_block_info: None, - }], - } + let set_state_step = SetStateStep::new(); + set_state_step.put_account(address, account_state) } -fn retrieve_code(code: String) -> Option { - if code.is_empty() { - None - } else { - Some(ValueSubTree::Str(format!("0x{code}"))) - } -} - -fn convert_storage(account_storage: HashMap) -> BTreeMap { - account_storage - .into_iter() - .filter(|(k, _)| !k.starts_with("454c524f4e44")) - .map(|(k, v)| (format!("0x{k}"), ValueSubTree::Str(format!("0x{v}")))) - .collect() -} +pub fn set_account( + account: multiversx_sdk::data::account::Account, + account_storage: HashMap, + account_esdt: HashMap, + account_esdt_roles: HashMap>, +) -> Account { + let mut account_state = Account::new() + .nonce(account.nonce) + .balance(account.balance.as_str()) + .code(account.code); + account_state.username = Some(account.username.as_str().into()); + account_state.storage = convert_storage(account_storage); -fn convert_esdt( - sdk_esdt: HashMap, - sdk_esdt_roles: HashMap>, -) -> BTreeMap { - let mut result = BTreeMap::new(); - for (key, value) in sdk_esdt.into_iter() { - let (token_identifier, nonce) = split_token_identifer_nonce(key); - let esdt_raw = result - .entry(format!("str:{}", token_identifier.clone())) - .or_insert(EsdtRaw::Full(EsdtFullRaw::default())); - if let EsdtRaw::Full(esdt_full_raw) = esdt_raw { - esdt_full_raw.instances.push(EsdtInstanceRaw { - nonce: Some(ValueSubTree::Str(nonce.to_string())), - balance: Some(ValueSubTree::Str(value.balance)), - // TODO: add creator, royalties, etc ... - ..Default::default() - }); - } + for (_, esdt_balance) in account_esdt.iter() { + account_state = account_state.esdt_balance( + format!("str:{}", esdt_balance.token_identifier).as_str(), + esdt_balance.balance.as_str(), + ); } - for (key, roles) in sdk_esdt_roles.into_iter() { - let (token_identifier, _) = split_token_identifer_nonce(key); - let esdt_raw = result - .entry(format!("str:{}", token_identifier.clone())) - .or_insert(EsdtRaw::Full(EsdtFullRaw::default())); - if let EsdtRaw::Full(esdt_full_raw) = esdt_raw { - esdt_full_raw.roles = roles; - } + for (token_id, esdt_roles) in account_esdt_roles { + account_state = account_state.esdt_roles(token_id.as_str(), esdt_roles); } - result + account_state } -fn split_token_identifer_nonce(full_identifier: String) -> (String, u64) { - let tokens = full_identifier.split('-').collect::>(); - match tokens.len() { - 2 => (full_identifier, 0), - 3 => ( - format!("{}-{}", tokens[0], tokens[1]), - u64::from_str_radix(tokens[2], 16).unwrap(), - ), - _ => panic!("could not process token identifier: {full_identifier}"), - } +fn convert_storage(account_storage: HashMap) -> BTreeMap { + account_storage + .into_iter() + .filter(|(k, _)| !k.starts_with("454c524f4e44")) + .map(|(k, v)| (BytesKey::from(k.as_str()), BytesValue::from(v))) + .collect() } diff --git a/framework/scenario/src/standalone/scenario_cli.rs b/framework/scenario/src/standalone/scenario_cli.rs index c7049728f4..624b316ef0 100644 --- a/framework/scenario/src/standalone/scenario_cli.rs +++ b/framework/scenario/src/standalone/scenario_cli.rs @@ -1,4 +1,7 @@ use clap::{Args, Parser, Subcommand}; +use multiversx_sdk::blockchain::CommunicationProxy; + +use crate::imports::Bech32Address; use super::account_tool; @@ -34,10 +37,14 @@ pub struct AccountArgs { /// Entry point in the program when calling it as a standalone tool. pub async fn cli_main() { let cli_args = ScenarioCliArgs::parse(); - let api = cli_args.api.expect("API needs tp be specified"); + let api = CommunicationProxy::new(cli_args.api.expect("API needs tp be specified")); match &cli_args.command { Some(ScenarioCliAction::Account(args)) => { - account_tool::print_account_as_scenario_set_state(api, args).await; + account_tool::print_account_as_scenario_set_state( + &api, + &Bech32Address::from_bech32_string(args.address.to_string()), + ) + .await; }, None => {}, } diff --git a/framework/scenario/src/whitebox_legacy.rs b/framework/scenario/src/whitebox_legacy.rs index aec0d8c980..9d90a4cb7e 100644 --- a/framework/scenario/src/whitebox_legacy.rs +++ b/framework/scenario/src/whitebox_legacy.rs @@ -1,5 +1,3 @@ -#![allow(deprecated)] - mod address_factory; mod contract_obj_wrapper; mod mandos_generator; diff --git a/framework/scenario/src/whitebox_legacy/contract_obj_wrapper.rs b/framework/scenario/src/whitebox_legacy/contract_obj_wrapper.rs index edb4f8f019..b88377b98d 100644 --- a/framework/scenario/src/whitebox_legacy/contract_obj_wrapper.rs +++ b/framework/scenario/src/whitebox_legacy/contract_obj_wrapper.rs @@ -16,9 +16,8 @@ use multiversx_chain_scenario_format::interpret_trait::InterpretableFrom; use multiversx_chain_vm::{ tx_mock::{TxContext, TxContextStack, TxFunctionName, TxResult}, types::VMAddress, - world_mock::EsdtInstanceMetadata, }; -use multiversx_sc::types::H256; +use multiversx_sc::types::{BigUint, H256}; use num_traits::Zero; use super::{ @@ -180,7 +179,8 @@ impl BlockchainStateWrapper { impl BlockchainStateWrapper { pub fn create_user_account(&mut self, egld_balance: &num_bigint::BigUint) -> Address { let address = self.address_factory.new_address(); - self.create_account_raw(&address, egld_balance, None, None, None); + self.world + .create_account_raw(&address, BigUint::from(egld_balance)); address } @@ -190,7 +190,8 @@ impl BlockchainStateWrapper { address: &Address, egld_balance: &num_bigint::BigUint, ) { - self.create_account_raw(address, egld_balance, None, None, None); + self.world + .create_account_raw(address, BigUint::from(egld_balance)); } pub fn create_sc_account( @@ -288,15 +289,8 @@ impl BlockchainStateWrapper { _sc_identifier: Option>, _sc_mandos_path_expr: Option>, ) { - let vm_address = to_vm_address(address); - if self.world.get_state().account_exists(&vm_address) { - panic!("Address already used: {:?}", address_to_hex(address)); - } - - let account = Account::new().balance(egld_balance); - self.world - .set_state_step(SetStateStep::new().put_account(address, account)); + .create_account_raw(address, BigUint::from(egld_balance)); } // Has to be used before perfoming a deploy from a SC @@ -344,19 +338,7 @@ impl BlockchainStateWrapper { } pub fn set_egld_balance(&mut self, address: &Address, balance: &num_bigint::BigUint) { - let vm_address = to_vm_address(address); - match self.world.get_mut_state().accounts.get_mut(&vm_address) { - Some(acc) => { - acc.egld_balance = balance.clone(); - - self.add_mandos_set_account(address); - }, - - None => panic!( - "set_egld_balance: Account {:?} does not exist", - address_to_hex(address) - ), - } + self.world.set_egld_balance(address, BigUint::from(balance)); } pub fn set_esdt_balance( @@ -365,23 +347,8 @@ impl BlockchainStateWrapper { token_id: &[u8], balance: &num_bigint::BigUint, ) { - let vm_address = to_vm_address(address); - match self.world.get_mut_state().accounts.get_mut(&vm_address) { - Some(acc) => { - acc.esdt.set_esdt_balance( - token_id.to_vec(), - 0, - balance, - EsdtInstanceMetadata::default(), - ); - - self.add_mandos_set_account(address); - }, - None => panic!( - "set_esdt_balance: Account {:?} does not exist", - address_to_hex(address) - ), - } + self.world + .set_esdt_balance(address, token_id, BigUint::from(balance)); } pub fn set_nft_balance( @@ -392,14 +359,14 @@ impl BlockchainStateWrapper { balance: &num_bigint::BigUint, attributes: &T, ) { - self.set_nft_balance_all_properties( + self.world.set_nft_balance_all_properties( address, token_id, nonce, - balance, + BigUint::from(balance), attributes, 0, - None, + None::
, None, None, &[], @@ -411,18 +378,8 @@ impl BlockchainStateWrapper { address: &Address, developer_rewards: num_bigint::BigUint, ) { - let vm_address: VMAddress = to_vm_address(address); - match self.world.get_mut_state().accounts.get_mut(&vm_address) { - Some(acc) => { - acc.developer_rewards = developer_rewards; - - self.add_mandos_set_account(address); - }, - None => panic!( - "set_developer_rewards: Account {:?} does not exist", - address_to_hex(address) - ), - } + self.world + .set_developer_rewards(address, &developer_rewards); } #[allow(clippy::too_many_arguments)] @@ -439,30 +396,18 @@ impl BlockchainStateWrapper { hash: Option<&[u8]>, uris: &[Vec], ) { - let vm_address = to_vm_address(address); - match self.world.get_mut_state().accounts.get_mut(&vm_address) { - Some(acc) => { - acc.esdt.set_esdt_balance( - token_id.to_vec(), - nonce, - balance, - EsdtInstanceMetadata { - creator: creator.map(to_vm_address), - attributes: serialize_attributes(attributes), - royalties, - name: name.unwrap_or_default().to_vec(), - hash: hash.map(|h| h.to_vec()), - uri: uris.to_vec(), - }, - ); - - self.add_mandos_set_account(address); - }, - None => panic!( - "set_nft_balance: Account {:?} does not exist", - address_to_hex(address) - ), - } + self.world.set_nft_balance_all_properties( + address, + token_id, + nonce, + BigUint::from(balance), + attributes, + royalties, + creator, + name, + hash, + uris, + ); } pub fn set_esdt_local_roles( @@ -471,22 +416,7 @@ impl BlockchainStateWrapper { token_id: &[u8], roles: &[EsdtLocalRole], ) { - let vm_address = to_vm_address(address); - match self.world.get_mut_state().accounts.get_mut(&vm_address) { - Some(acc) => { - let mut roles_raw = Vec::new(); - for role in roles { - roles_raw.push(role.as_role_name().to_vec()); - } - acc.esdt.set_roles(token_id.to_vec(), roles_raw); - - self.add_mandos_set_account(address); - }, - None => panic!( - "set_esdt_local_roles: Account {:?} does not exist", - address_to_hex(address) - ), - } + self.world.set_esdt_local_roles(address, token_id, roles); } pub fn set_block_epoch(&mut self, block_epoch: u64) { @@ -856,15 +786,6 @@ fn address_to_hex(address: &Address) -> String { hex::encode(address.as_bytes()) } -fn serialize_attributes(attributes: &T) -> Vec { - let mut serialized_attributes = Vec::new(); - if let Result::Err(err) = attributes.top_encode(&mut serialized_attributes) { - panic!("Failed to encode attributes: {err:?}") - } - - serialized_attributes -} - fn print_token_balance_raw( token_nonce: u64, token_balance: &num_bigint::BigUint, diff --git a/framework/scenario/tests/contract_call_test.rs b/framework/scenario/tests/contract_call_test.rs index cacd39fd96..b6ff5ea1fb 100644 --- a/framework/scenario/tests/contract_call_test.rs +++ b/framework/scenario/tests/contract_call_test.rs @@ -3,6 +3,7 @@ use multiversx_sc_scenario::scenario_model::ScCallStep; use num_traits::Zero; #[test] +#[allow(deprecated)] fn test_contract_call_multi_esdt() { let tx = ScCallStep::new() .from("address:sender") diff --git a/framework/scenario/tests/contract_without_macros.rs b/framework/scenario/tests/contract_without_macros.rs index 0252be4b1e..cf9033b529 100644 --- a/framework/scenario/tests/contract_without_macros.rs +++ b/framework/scenario/tests/contract_without_macros.rs @@ -7,9 +7,10 @@ // and maintenance. #![allow(unused)] +#![allow(deprecated)] // TODO: unified syntax use multiversx_sc::{ - contract_base::ProxyObjBase, + contract_base::ProxyObjNew, types::{BigInt, ManagedAddress}, }; use multiversx_sc_scenario::api::{SingleTxApi, StaticApi}; @@ -330,8 +331,7 @@ mod sample_adder { where A: multiversx_sc::api::VMApi + 'static, { - pub address: - multiversx_sc::types::ManagedOption>, + _phantom: core::marker::PhantomData, } impl multiversx_sc::contract_base::ProxyObjBase for Proxy @@ -339,17 +339,63 @@ mod sample_adder { A: multiversx_sc::api::VMApi + 'static, { type Api = A; + type To = (); + + fn extract_opt_address( + &mut self, + ) -> multiversx_sc::types::ManagedOption< + Self::Api, + multiversx_sc::types::ManagedAddress, + > { + multiversx_sc::types::ManagedOption::none() + } + + fn extract_address(&mut self) -> multiversx_sc::types::ManagedAddress { + multiversx_sc::api::ErrorApiImpl::signal_error( + &::error_api_impl(), + multiversx_sc::err_msg::RECIPIENT_ADDRESS_NOT_SET.as_bytes(), + ) + } + + fn extract_proxy_to(&mut self) -> Self::To {} + } + + impl multiversx_sc::contract_base::ProxyObjNew for Proxy + where + A: multiversx_sc::api::VMApi + 'static, + { + type ProxyTo = ProxyTo; fn new_proxy_obj() -> Self { Proxy { - address: multiversx_sc::types::ManagedOption::none(), + _phantom: core::marker::PhantomData, } } - fn contract(mut self, address: multiversx_sc::types::ManagedAddress) -> Self { - self.address = multiversx_sc::types::ManagedOption::some(address); - self + fn contract( + mut self, + address: multiversx_sc::types::ManagedAddress, + ) -> Self::ProxyTo { + ProxyTo { + address: multiversx_sc::types::ManagedOption::some(address), + } } + } + + pub struct ProxyTo + where + A: multiversx_sc::api::VMApi + 'static, + { + pub address: + multiversx_sc::types::ManagedOption>, + } + + impl multiversx_sc::contract_base::ProxyObjBase for ProxyTo + where + A: multiversx_sc::api::VMApi + 'static, + { + type Api = A; + type To = multiversx_sc::types::ManagedAddress; fn extract_opt_address( &mut self, @@ -370,11 +416,17 @@ mod sample_adder { ); address.unwrap_or_sc_panic(multiversx_sc::err_msg::RECIPIENT_ADDRESS_NOT_SET) } + + fn extract_proxy_to(&mut self) -> Self::To { + self.extract_address() + } } impl super::module_1::ProxyTrait for Proxy where A: multiversx_sc::api::VMApi {} + impl super::module_1::ProxyTrait for ProxyTo where A: multiversx_sc::api::VMApi {} impl ProxyTrait for Proxy where A: multiversx_sc::api::VMApi {} + impl ProxyTrait for ProxyTo where A: multiversx_sc::api::VMApi {} pub struct CallbackProxyObj where diff --git a/framework/scenario/tests/derive_managed_vec_item_struct_1_test.rs b/framework/scenario/tests/derive_managed_vec_item_struct_1_test.rs index f69056f5d6..1673008017 100644 --- a/framework/scenario/tests/derive_managed_vec_item_struct_1_test.rs +++ b/framework/scenario/tests/derive_managed_vec_item_struct_1_test.rs @@ -39,13 +39,13 @@ fn struct_1_encode_decode_skips_reserialization() { }; #[rustfmt::skip] - let bytes_1 = &[ - /* u_8 */ 0x01, - /* u_16 */ 0x00, 0x02, - /* u_32 */ 0x00, 0x00, 0x00, 0x03, - /* u_64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - /* bool */ 0x01, - ]; + let bytes_1 = &[ + /* u_8 */ 0x01, + /* u_16 */ 0x00, 0x02, + /* u_32 */ 0x00, 0x00, 0x00, 0x03, + /* u_64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + /* bool */ 0x01, + ]; check_top_encode_decode(s.clone(), bytes_1); check_dep_encode_decode(s, bytes_1); diff --git a/framework/scenario/tests/derive_managed_vec_item_struct_2_test.rs b/framework/scenario/tests/derive_managed_vec_item_struct_2_test.rs index 3adfbb34bd..90db2ddddc 100644 --- a/framework/scenario/tests/derive_managed_vec_item_struct_2_test.rs +++ b/framework/scenario/tests/derive_managed_vec_item_struct_2_test.rs @@ -39,15 +39,15 @@ fn struct_to_bytes_writer() { }; #[rustfmt::skip] - let expected_payload = &[ - /* u_8 */ 0x01, - /* u_16 */ 0x00, 0x02, - /* u_32 */ 0x00, 0x00, 0x00, 0x03, - /* u_64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - /* bool */ 0x01, + let expected_payload = &[ + /* u_8 */ 0x01, + /* u_16 */ 0x00, 0x02, + /* u_32 */ 0x00, 0x00, 0x00, 0x03, + /* u_64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + /* bool */ 0x01, /* opt */ 0x01, 0x05, /* arr */ 0x61, 0x11, 0x62, 0x22, - ]; + ]; ::to_byte_writer(&s, |bytes| { assert_eq!(bytes, &expected_payload[..]); @@ -67,15 +67,15 @@ fn struct_2_from_bytes_reader() { }; #[rustfmt::skip] - let payload = &[ - /* u_8 */ 0x01, - /* u_16 */ 0x00, 0x02, - /* u_32 */ 0x00, 0x00, 0x00, 0x03, - /* u_64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - /* bool */ 0x00, + let payload = &[ + /* u_8 */ 0x01, + /* u_16 */ 0x00, 0x02, + /* u_32 */ 0x00, 0x00, 0x00, 0x03, + /* u_64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + /* bool */ 0x00, /* opt */ 0x01, 0x05, /* arr */ 0x61, 0x11, 0x62, 0x22, - ]; + ]; let struct_from_bytes = ::from_byte_reader(|bytes| { diff --git a/framework/scenario/tests/test_tx_deployed_address.rs b/framework/scenario/tests/test_tx_deployed_address.rs new file mode 100644 index 0000000000..b040ace618 --- /dev/null +++ b/framework/scenario/tests/test_tx_deployed_address.rs @@ -0,0 +1,133 @@ +use multiversx_sc::types::Address; +use multiversx_sc_scenario::scenario_model::TxResponse; +use multiversx_sdk::data::transaction::{TransactionInfo, TransactionOnNetwork}; + +#[test] +fn test_deployed_address() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCDeployment", + "processingTypeOnDestination": "SCDeployment", + "hash": "07a176d1734d1901d396be344f97e1d80f076269e9559f9b2110f6f11c4f74de", + "nonce": 427, + "round": 2190715, + "epoch": 887, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6gq4hu", + "sender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "data": "MDA2MTczNmQwMTAwMDAwMDAxOTgwMTE5NjAwMjdmN2YwMDYwMDE3ZjAxN2Y2MDAwMDA2MDAwMDE3ZjYwMDI3ZjdmMDE3ZjYwMDM3ZjdmN2YwMDYwMDE3ZjAwNjAwNDdmN2Y3ZjdmMDA2MDA1N2Y3ZjdmN2Y3ZjAwNjAwMzdmN2Y3ZjAxN2Y2MDA0N2Y3ZjdmN2YwMTdmNjAwMjdmN2UwMDYwMDE3ZjAxN2U2MDAyN2Y3ZjAxN2U2MDA1N2Y3ZjdlN2Y3ZjAxN2Y2MDA2N2U3ZjdmN2Y3ZjdmMDE3ZjYwMDE3ZTAwNjAwMDAxN2U2MDAxN2UwMTdmNjAwNDdmN2Y3ZTdmMDA2MDA1N2U3ZjdmN2Y3ZjAxN2Y2MDA0N2Y3ZjdmN2UwMDYwMDE3ZTAxN2U2MDA0N2Y3ZTdmN2YwMDYwMDI3ZTdmMDAwMmMxMDcyOTAzNjU2ZTc2MTI2ZDYxNmU2MTY3NjU2NDUzNjk2NzZlNjE2YzQ1NzI3MjZmNzIwMDA2MDM2NTZlNzYwZTYyNjk2NzQ5NmU3NDUzNjU3NDQ5NmU3NDM2MzQwMDBiMDM2NTZlNzYwOTYyNjk2NzQ5NmU3NDQxNjQ2NDAwMDUwMzY1NmU3NjBiNzM2OTY3NmU2MTZjNDU3MjcyNmY3MjAwMDAwMzY1NmU3NjBhNmQ0Mjc1NjY2NjY1NzI0ZTY1NzcwMDAzMDM2NTZlNzYwZDZkNDI3NTY2NjY2NTcyNDE3MDcwNjU2ZTY0MDAwNDAzNjU2ZTc2MDk2ZDQyNzU2NjY2NjU3MjQ1NzEwMDA0MDM2NTZlNzYwZDZkNDI3NTY2NjY2NTcyNDY2OTZlNjk3MzY4MDAwMTAzNjU2ZTc2MjI2ZDYxNmU2MTY3NjU2NDRkNzU2Yzc0Njk1NDcyNjE2ZTczNjY2NTcyNDU1MzQ0NTQ0ZTQ2NTQ0NTc4NjU2Mzc1NzQ2NTAwMGUwMzY1NmU3NjFiNmQ2MTZlNjE2NzY1NjQ0NTc4NjU2Mzc1NzQ2NTRmNmU0NDY1NzM3NDQzNmY2ZTc0NjU3ODc0MDAwZjAzNjU2ZTc2MGQ2ZDYxNmU2MTY3NjU2NDQzNjE2YzZjNjU3MjAwMDYwMzY1NmU3NjEwNmQ2MTZlNjE2NzY1NjQ1MzQzNDE2NDY0NzI2NTczNzMwMDA2MDM2NTZlNzYxMzZkNjE2ZTYxNjc2NTY0NGY3NzZlNjU3MjQxNjQ2NDcyNjU3MzczMDAwNjAzNjU2ZTc2MWM2ZDYxNmU2MTY3NjU2NDQ3NjU3NDRkNzU2Yzc0Njk0NTUzNDQ1NDQzNjE2YzZjNTY2MTZjNzU2NTAwMDYwMzY1NmU3NjEyNmQ0Mjc1NjY2NjY1NzI0NzY1NzQ0MTcyNjc3NTZkNjU2ZTc0MDAwNDAzNjU2ZTc2MTI2ZDQyNzU2NjY2NjU3MjQxNzA3MDY1NmU2NDQyNzk3NDY1NzMwMDA5MDM2NTZlNzYxOTYyNjk2NzQ5NmU3NDQ3NjU3NDU1NmU3MzY5Njc2ZTY1NjQ0MTcyNjc3NTZkNjU2ZTc0MDAwMDAzNjU2ZTc2MWI3MzZkNjE2YzZjNDk2ZTc0NDc2NTc0NTU2ZTczNjk2NzZlNjU2NDQxNzI2Nzc1NmQ2NTZlNzQwMDBjMDM2NTZlNzYxMDZkNDI3NTY2NjY2NTcyNDc2NTc0NGM2NTZlNjc3NDY4MDAwMTAzNjU2ZTc2MGY2NzY1NzQ0ZTc1NmQ0MTcyNjc3NTZkNjU2ZTc0NzMwMDAzMDM2NTZlNzYxNjczNmQ2MTZjNmM0OTZlNzQ0NjY5NmU2OTczNjg1NTZlNzM2OTY3NmU2NTY0MDAxMDAzNjU2ZTc2MDk2MjY5Njc0OTZlNzQ1Mzc1NjIwMDA1MDM2NTZlNzYwYTY3NjU3NDQ3NjE3MzRjNjU2Njc0MDAxMTAzNjU2ZTc2MGY2MzZjNjU2MTZlNTI2NTc0NzU3MjZlNDQ2MTc0NjEwMDAyMDM2NTZlNzYwZjZkNDI3NTY2NjY2NTcyNTM2NTc0NDI3OTc0NjU3MzAwMDkwMzY1NmU3NjA5NjI2OTY3NDk2ZTc0NDM2ZDcwMDAwNDAzNjU2ZTc2MGE2MjY5Njc0OTZlNzQ1NDQ0Njk3NjAwMDUwMzY1NmU3NjA5NjI2OTY3NDk2ZTc0NGQ3NTZjMDAwNTAzNjU2ZTc2MTk2ZDQyNzU2NjY2NjU3MjQ2NzI2ZjZkNDI2OTY3NDk2ZTc0NTU2ZTczNjk2NzZlNjU2NDAwMDQwMzY1NmU3NjE3NmQ0Mjc1NjY2NjY1NzI1NDZmNDI2OTY3NDk2ZTc0NTU2ZTczNjk2NzZlNjU2NDAwMDQwMzY1NmU3NjA5NjI2OTY3NDk2ZTc0NTA2Zjc3MDAwNTAzNjU2ZTc2MTQ2ZDQyNzU2NjY2NjU3MjQzNmY3MDc5NDI3OTc0NjU1MzZjNjk2MzY1MDAwYTAzNjU2ZTc2MTI2ZDQyNzU2NjY2NjU3MjUzNzQ2ZjcyNjE2NzY1NGM2ZjYxNjQwMDA0MDM2NTZlNzYxMzZkNDI3NTY2NjY2NTcyNTM3NDZmNzI2MTY3NjU1Mzc0NmY3MjY1MDAwNDAzNjU2ZTc2MGU2MzY4NjU2MzZiNGU2ZjUwNjE3OTZkNjU2ZTc0MDAwMjAzNjU2ZTc2MTc2ZDYxNmU2MTY3NjU2NDQ3NjU3NDQyNjE2MzZiNTQ3MjYxNmU3MzY2NjU3MjczMDAwMDAzNjU2ZTc2MGY2ZDYxNmU2MTY3NjU2NDU3NzI2OTc0NjU0YzZmNjcwMDAwMDM2NTZlNzYxNDYyNjk2NzQ5NmU3NDQ2Njk2ZTY5NzM2ODU1NmU3MzY5Njc2ZTY1NjQwMDA2MDM2NTZlNzYwNjY2Njk2ZTY5NzM2ODAwMDAwMzY1NmU3NjBhNjI2OTY3NDk2ZTc0NTM2OTY3NmUwMDAxMDM2NTZlNzYxMzZkNDI3NTY2NjY2NTcyNDc2NTc0NDI3OTc0NjU1MzZjNjk2MzY1MDAwYTAzZDMwMWQxMDEwMTAzMDgwMjAxMTIwMTA0MDAwMTA3MDYwNjA2MDAwNDAxMDkwMTAwMDEwMDAwMDAwMDEzMDMwMDE0MDMwMzAzMDIwMzAxMDcwNDAwMDMwOTAxMDkwOTA5MDAwNzA3MDEwMDA2MDYwMTA2MDYwYzA1MDEwODA1MDAwMTBiMDAwODA3MTUwNzA4MDgwMDBhMDAxNjAxMDEwNjAxMDAwMDAwMDUwMDAwMDEwMzAwMDYwMTAwMTcwNTA1MGEwNzA0MDAwNDBhMDAwNDA0MDQwMDA0MDQwNDA0MDQwMTAxMDAwNDBkMDcwNzA3MDgwYTAwMDUwMTAxMDUwNTA2MDEwMTAwMGIwYjAxMDEwMTAxMDEwNTBkMDEwNTAwMDAwMDA1MDUwMDAwMDAwMDAwMGMwNzA3MDcwNzAwMDAwODE4MDMwMzAzMDAwMzAzMDAwMTA0MDcwMzAzMDMwMzAxMDEwMzAzMDMwMzAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwMjAyMDIwODA4MDUwMzAxMDAwMzA2MTYwMzdmMDE0MTgwODAwODBiN2YwMDQxZTlkYjA4MGI3ZjAwNDFmMGRiMDgwYjA3YzcwNTIwMDY2ZDY1NmQ2ZjcyNzkwMjAwMDQ2OTZlNjk3NDAwZGIwMTA3NzU3MDY3NzI2MTY0NjUwMGRjMDEwNzY0NjU3MDZmNzM2OTc0MDBkZDAxMDg3NzY5NzQ2ODY0NzI2MTc3MDBkZTAxMDg2MzZmNmQ3MDZmNzU2ZTY0MDBkZjAxMGU2NzY1NzQ1NDZmNzQ2MTZjNDE3MzczNjU3NDczMDBlMDAxMGY2NzY1NzQ1NjYxNzU2Yzc0NDE2NDY0NzI2NTczNzMwMGUxMDExNzY3NjU3NDQxNzM3MzY1NzQ1NDZmNmI2NTZlNDk2NDY1NmU3NDY5NjY2OTY1NzIwMGUyMDExZDY3NjU3NDRkNmY2ZTY1Nzk0ZDYxNzI2YjY1NzQ1NDZmNmI2NTZlNDk2NDY1NmU3NDY5NjY2OTY1NzIwMGUzMDEyMjY3NjU3NDRkNmY2ZTY1Nzk0ZDYxNzI2YjY1NzQ1NTZlNjQ2NTcyNmM3OTY5NmU2NzQ5NjQ2NTZlNzQ2OTY2Njk2NTcyMDBlNDAxMWY2NzY1NzQ0MjZmNmY3Mzc0NjU3MjUzNzQ2MTZiNjU2NDU0NmY2YjY1NmU0OTY0NjU2ZTc0Njk2NjY5NjU3MjAwZTUwMTE0Njc2NTc0NDM2ZjZlNzQ3MjZmNmM2YzY1NzI0MTY0NjQ3MjY1NzM3MzAwZTYwMTE1Njc2NTc0NGQ2ZjZlNjU3OTRkNjE3MjZiNjU3NDQxNjQ2NDcyNjU3MzczMDBlNzAxMWQ2NzY1NzQ1NzcyNjE3MDcwNjU2NDQ1Njc2YzY0NDM2ZjZlNzQ3MjYxNjM3NDQxNjQ2NDcyNjU3MzczMDBlODAxMWQ2NzY1NzQ1NzcyNjE3MDcwNjU2NDQ1Njc2YzY0NTQ2ZjZiNjU2ZTQ5NjQ2NTZlNzQ2OTY2Njk2NTcyMDBlOTAxMTE2NzY1NzQ0MjZmNmY3Mzc0NjU3MjQxNjQ2NDcyNjU3MzczMDBlYTAxMTk2NzY1NzQ0MzZmNmQ3MDZmNzU2ZTY0NTg0NTc4NjM2ODYxNmU2NzY1NTM3NzYxNzA3MzAwZWIwMTE3Njc2NTc0NDM2ZjZkNzA2Zjc1NmU2NDQxNzM2ODczNzc2MTcwNTM3NzYxNzA3MzAwZWMwMTE2Njc2NTc0NDM2ZjZkNzA2Zjc1NmU2NDQ2NjU2NTczNTA2NTcyNjM2NTZlNzQwMGVkMDExOTY3NjU3NDUwNjU3MjY2NmY3MjZkNjE2ZTYzNjU0NjY1NjU3MzUwNjU3MjYzNjU2ZTc0MDBlZTAxMGU3Mzc0NjE2YjY1NDk2ZTQyNmY2ZjczNzQ2NTcyMDBlZjAxMWI3MjY1NjI2MTZjNjE2ZTYzNjU1MDZmNzI3NDY2NmY2YzY5NmY0OTZlNDI2ZjZmNzM3NDY1NzIwMGYwMDExMjc1NmU3Mzc0NjE2YjY1NDY3MjZmNmQ0MjZmNmY3Mzc0NjU3MjAwZjEwMTE4NjM2YzYxNjk2ZDRkNzU2Yzc0Njk3MDZjNjU0NjcyNmY2ZDQyNmY2ZjczNzQ2NTcyMDBmMjAxMTk3MzY1NzQ1MDY1NzI2NjZmNzI2ZDYxNmU2MzY1NDY2NTY1NzM1MDY1NzI2MzY1NmU3NDAwZjMwMTE2NzM2NTc0NDM2ZjZkNzA2Zjc1NmU2NDQ2NjU2NTczNTA2NTcyNjM2NTZlNzQwMGY0MDExMDczNjU3NDQzNmY2ZDcwNmY3NTZlNjQ1Mzc3NjE3MDczMDBmNTAxMGQ2NzY1NzQ0ZTYxNzQ3NTcyNjE2YzQxNTA1OTAwZjYwMTA4NjM2MTZjNmM0MjYxNjM2YjAwZjcwMTBhNWY1ZjY0NjE3NDYxNWY2NTZlNjQwMzAxMGI1ZjVmNjg2NTYxNzA1ZjYyNjE3MzY1MDMwMjBhOWFhOTAxZDEwMTE2MDEwMTdmMTAyYTIyMDE0MjAwMTAwMTIwMDEyMDAxMjAwMDEwMDIyMDAxMGIxOTAxMDE3ZjQxYzg4ZDA4NDFjODhkMDgyODAyMDA0MTAxNmIyMjAwMzYwMjAwMjAwMDBiMmUwMDAyNDAyMDAxMjAwMjRkMDQ0MDIwMDIyMDA0NGQwZDAxMTAyYzAwMGIxMDJjMDAwYjIwMDAyMDAyMjAwMTZiMzYwMjA0MjAwMDIwMDEyMDAzNmEzNjAyMDAwYjBiMDA0MWI4OGQwODQxMGUxMDAzMDAwYjEzMDEwMTdmMTAyYTIyMDEyMDAwYWQ0MmZmMDE4MzEwMDEyMDAxMGIyMTAxMDE3ZjEwMmEyMTAxMjAwMDQyMDA1MzA0NDA0MWIyODUwODQxMTExMDAzMDAwYjIwMDEyMDAwMTAwMTIwMDEwYjBmMDEwMTdmMTAwNDIyMDEyMDAwMTAwNTFhMjAwMTBiMGIwMDIwMDAyMDAxMTAwNjQxMDA0YTBiMmQwMTAxN2YyMzAwNDEyMDZiMjIwMjI0MDAyMDAyMjAwMDEwMzI0MWMwODAwODQxMDgxMDMzMjAwMjIwMDEzNjAyMTgyMDAyMTAzNDIwMDI0MTIwNmEyNDAwMGIxOTAwMjAwMDQxZmVmZmZmZmYwNzQ2MDQ0MDQxYzg4MDA4NDExOTEwMDMwMDBiMjAwMDBiMmEwMDIwMDIyMDAzMTA0ZDIxMDIxMDQzMjEwMzIwMDA0MjdmMzcwMzA4MjAwMDIwMDMzNjAyMDQyMDAwMjAwMjM2MDIwMDIwMDAyMDAxMzYwMjEwMGI3ZDAxMDM3ZjIzMDA0MTEwNmIyMjAxMjQwMDIwMDAyOTAzMDgxMDcxMjAwMDI4MDIxMDIwMDAyODAyMTgyMDAwMjgwMjAwMjAwMDI4MDIwNDEwNDUyMTAyMTAxNzQxMDAyMTAwMjAwMjEwMTIyMTAzMjAwMTQxMDAzNjAyMGMyMDAxMjAwMjM2MDIwNDIwMDEyMDAzNDEwMjc2MjIwMjM2MDIwODAzNDAyMDAwMjAwMjRmNDUwNDQwMjAwMTQxMDQ2YTEwNzUxYTIwMDEyODAyMDgyMTAyMjAwMTI4MDIwYzIxMDAwYzAxMGIwYjIwMDE0MTEwNmEyNDAwMGIzNjAxMDI3ZjIzMDA0MTEwNmIyMjAxMjQwMDIwMDE0MTA4NmExMDM2MjAwMTI4MDIwODIxMDIyMDAwMjAwMTJkMDAwYzQxMDE3MTNhMDAwNDIwMDAyMDAyMzYwMjAwMjAwMTQxMTA2YTI0MDAwYjZkMDEwMjdmMjMwMDQxMTA2YjIyMDEyNDAwMjAwMDAyN2Y0MWUwZGIwODJkMDAwMDIyMDI0NTA0NDA0MWUwZGIwODQxMDEzYTAwMDA0MWRjZGIwODQxMDAzNjAyMDAyMDAxNDEwODZhNDEwMDEwOWYwMTIwMDEyODAyMDgyMDAxMjgwMjBjNDFiODhkMDg0MTAwMTA1NzEwNDMwYzAxMGI0MWI4OGQwODQxMDAxMDRkMGIzNjAyMDAyMDAwMjAwMjQxMDE3MzNhMDAwNDIwMDE0MTEwNmEyNDAwMGIwYjAwMjAwMDIwMDExMDM4MTAwNzFhMGI0OTAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAxM2EwMDBjMjAwMjIwMDAzNjAyMDgyMDAyNDEwODZhMTBhNTAxMjAwMjI4MDIwODIwMDIyZDAwMGMwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAyNDExMDZhMjQwMDBiMGUwMDIwMDA0MThhODUwODQxMGIxMDNhMTAzYjBiMTMwMDIwMDAyMDAwMjAwMTIwMDIxMDUyMjAwMTIwMDIxMDg1MDEwYjBkMDAyMDAwMTAyYTIyMDAxMDFkMWEyMDAwMGIwYTAwMjAwMDEwM2QyMDAxMTAzZTBiMGYwMTAxN2YxMDJhMjIwMTIwMDAxMDFjMWEyMDAxMGI1MTAxMDI3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAwMTAxMjIyMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwYzIwMDEyMDAyNDEwYzZhNDEwNDEwYTMwMTIwMDEyMDAwMTBiZDAxMjAwMjQxMTA2YTI0MDAwYjBhMDAyMDAwMTAzZDIwMDExMDQwMGI1MTAxMDI3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAwMTAxMjIyMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwYzIwMDEyMDAyNDEwYzZhNDEwNDEwMGYxYTIwMDEyMDAwMTA4YjAxMjAwMjQxMTA2YTI0MDAwYjA5MDAyMDAwMjAwMTEwMDMwMDBiNTAwMTA0N2YxMDQzMjEwNjEwNDMyMTA3MjMwMDQxMTA2YjIyMDQyNDAwMTA0MzIxMDUyMDAxMTAyZjIxMDEyMDA0MjAwMzEwMjkzNjAyMGMyMDA0MjAwMjM3MDMwMDIwMDQyMDAxMzYwMjA4MjAwNTIwMDQxMDQ0MjAwMDIwMDU0MjAwMjAwNjIwMDcxMDA4MWEyMDA0NDExMDZhMjQwMDBiMTMwMTAxN2YxMDJhMjIwMDQxYjg4ZDA4NDEwMDEwMTgxYTIwMDAwYmQyMDEwMjAyN2YwMTdlMjMwMDQxMTA2YjIyMDMyNDAwMjAwMzIwMDEyODAyMDgyMjAyNDExODc0MjAwMjQxODBmZTAzNzE0MTA4NzQ3MjIwMDI0MTA4NzY0MTgwZmUwMzcxMjAwMjQxMTg3NjcyNzIzNjAyMDAyMDAzMjAwMTI4MDIwYzIyMDI0MTE4NzQyMDAyNDE4MGZlMDM3MTQxMDg3NDcyMjAwMjQxMDg3NjQxODBmZTAzNzEyMDAyNDExODc2NzI3MjM2MDIwYzIwMDMyMDAxMjkwMzAwMjIwNDQyMzg4NjIwMDQ0MjgwZmUwMzgzNDIyODg2ODQyMDA0NDI4MDgwZmMwNzgzNDIxODg2MjAwNDQyODA4MDgwZjgwZjgzNDIwODg2ODQ4NDIwMDQ0MjA4ODg0MjgwODA4MGY4MGY4MzIwMDQ0MjE4ODg0MjgwODBmYzA3ODM4NDIwMDQ0MjI4ODg0MjgwZmUwMzgzMjAwNDQyMzg4ODg0ODQ4NDM3MDIwNDIwMDAyMDAzNDExMDEwMGYxYTIwMDM0MTEwNmEyNDAwMGIxNTAwMjAwMDIwMDEyMDAyMjAwMzIwMDQxMDJhMjIwMTEwMDkxYTIwMDEwYjBjMDEwMTdmMTAyYTIyMDAxMDBhMjAwMDBiMGMwMTAxN2YxMDJhMjIwMDEwMGIyMDAwMGIwYzAxMDE3ZjEwMmEyMjAwMTAwYzIwMDAwYjE1MDAxMDQ4MTA0NjEwMzAwNDQwMGYwYjQxOTI4ZDA4NDEyNDEwMDMwMDBiMmIwMTAxN2Y0MWU4ZGIwODJkMDAwMDIyMDAwNDQwNDE2YjQxZmZmZmZmZmYwNzIwMDAxYjBmMGI0MWU4ZGIwODQxMDEzYTAwMDA0MTZiMTAwZDQxNmIwYjBkMDAyMDAwMTAyYTIyMDAxMDBlMWEyMDAwMGIyZTAxMDE3ZjQxZDU4MzA4NDExNzEwNGQyMjA0MjAwMDIwMDExMDBmMWEyMDA0NDFlYzgzMDg0MTAzMTAwZjFhMjAwNDIwMDIyMDAzMTAwZjFhMjAwNDEwMDAwMDBiMTEwMTAxN2YxMDJhMjIwMjIwMDAyMDAxMTAxODFhMjAwMjBiNDYwMTAxN2YyMzAwNDExMDZiMjIwMjI0MDAyMDAyMjAwMTQxMTg3NDIwMDE0MTgwZmUwMzcxNDEwODc0NzIyMDAxNDEwODc2NDE4MGZlMDM3MTIwMDE0MTE4NzY3MjcyMzYwMjBjMjAwMDIwMDI0MTBjNmE0MTA0MTAwZjFhMjAwMjQxMTA2YTI0MDAwYjBlMDEwMTdmNDEwMDEwMmEyMjAwMTAxMDIwMDAwYjFmMDAyMDAwMTA0YjIyMDAxMDEyNDEyMDQ3MDQ0MDIwMDEyMDAyNDFiMDg2MDg0MTEwMTA0YzAwMGIyMDAwMGJkOTAzMDEwOTdmMjMwMDQxNDA2YTIyMDEyNDAwMjAwMDEwNGIyMTAyMTA0MzIxMDYyMDAyMTAxMjIxMDAyMDAxNDEyNDZhNDEwMDNhMDAwMDIwMDE0MTIwNmEyMDAwMzYwMjAwMjAwMTIwMDIzNjAyMWMyMDAxMjAwMDM2MDIxODIwMDE0MTAwMzYwMjE0NDEwMDIxMDIwMzdmMjAwMDIwMDI0NjA0N2YyMDAxMmQwMDI0MDQ0MDQxZGNkYjA4NDEwMDM2MDIwMDQxZTBkYjA4NDEwMDNhMDAwMDBiMjAwMTQxNDA2YjI0MDAyMDA2MDUyMDAxNDExNDZhMjIwMDQxOTc4NzA4NDExNjEwM2EyMTA0MjAwMDQxOTc4NzA4NDExNjEwNTIyMTAwMTA0MzIxMDMwMzQwMjAwMDA0NDAyMDAxNDExNDZhMjIwNTQxOTc4NzA4NDExNjEwNTIyMTA3MjAwNTQxOTc4NzA4NDExNjEwNTMyMTA4MjAwNTQxOTc4NzA4NDExNjEwM2EyMTA5NDEwMDIxMDIwMjQwMDI0MDAyNDAyMDA1NDE5Nzg3MDg0MTE2MTA1NDQxZmYwMTcxMGUwMjAyMDEwMDBiNDE5Nzg3MDg0MTE2NDFlZDg2MDg0MTBkMTA0YzAwMGI0MTAxMjEwMjBiMjAwMTIwMDIzYTAwMzQyMDAxMjAwOTM2MDIzMDIwMDEyMDA4MzYwMjJjMjAwMTIwMDczNjAyMjgyMDAzMjAwMTQxMjg2YTEwNTUyMDAwNDEwMTZiMjEwMDBjMDEwYjBiMjAwMTQyMDAzNzAzMjgyMDAxMjAwNDQxMTg3NDIwMDQ0MTgwZmUwMzcxNDEwODc0NzIyMDA0NDEwODc2NDE4MGZlMDM3MTIwMDQ0MTE4NzY3MjcyMzYwMjNjMjAwMTQxMDg2YTIwMDE0MTI4NmEyMjAwNDEwMDQxMDQxMDU2MjAwMTI4MDIwODIwMDEyODAyMGMyMDAxNDEzYzZhMjIwMjQxMDQxMDU3MjAwMTIwMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIzYzIwMDEyMDAwNDEwNDQxMDgxMDU2MjAwMTI4MDIwMDIwMDEyODAyMDQyMDAyNDEwNDEwNTcyMDA2MjAwMDQxMDgxMDBmMWEyMDAxMjgwMjE0MjEwMjIwMDEyODAyMTgyMTAwMGMwMTBiMGIwYjM3MDIwMTdmMDE3ZTIzMDA0MTEwNmIyMjAzMjQwMDIwMDM0MTAwMzYwMjBjMjAwMDIwMDM0MTBjNmEyMjAwNDEwNDIwMDEyMDAyMTBjNTAxMjAwMDQxMDQxMGIxMDEyMDAzNDExMDZhMjQwMGE3MGIwZDAwMjAwMDQxMjAyMDAxMjAwMjEwODUwMTBiMzAwMTAxN2YyMzAwNDExMDZiMjIwMzI0MDAyMDAzNDEwMDNhMDAwZjIwMDAyMDAzNDEwZjZhNDEwMTIwMDEyMDAyMTBjNTAxMjAwMzJkMDAwZjIwMDM0MTEwNmEyNDAwMGJmNjAyMDEwNTdmMjMwMDQxZDAwMDZiMjIwMjI0MDAyMDAyNDIwMDM3MDAzNTIwMDI0MjAwMzcwMzMwMjAwMjIwMDEyODAyMDAyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyNDAyMDAyNDEyODZhMjAwMjQxMzA2YTIyMDU0MTAwNDEwNDEwOWIwMTIwMDIyODAyMjgyMDAyMjgwMjJjMjAwMjQxNDA2YjIyMDQ0MTA0MTA1NzIwMDI0MWM4MDA2YTQxMDAzYTAwMDAyMDAyNDIwMDM3MDM0MDIwMDIyMDAxMjgwMjA0MjIwMzQxMTg3NDIwMDM0MTgwZmUwMzcxNDEwODc0NzIyMDAzNDEwODc2NDE4MGZlMDM3MTIwMDM0MTE4NzY3MjcyMzYwMjRjMjAwMjQxMjA2YTIwMDQ0MTAwNDEwNDEwOWMwMTIwMDIyODAyMjAyMDAyMjgwMjI0MjAwMjQxY2MwMDZhMjIwNjQxMDQxMDU3MjAwMjIwMDE0MTA4NmEyODAyMDAyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyNGMyMDAyNDExODZhMjAwNDQxMDQ0MTA4MTA5YzAxMjAwMjI4MDIxODIwMDIyODAyMWMyMDA2NDEwNDEwNTcyMDAyMjAwMTQxMGM2YTJkMDAwMDNhMDA0YzIwMDI0MTEwNmEyMDA0NDEwODQxMDkxMDljMDEyMDAyMjgwMjEwMjAwMjI4MDIxNDIwMDY0MTAxMTA1NzIwMDI0MTA4NmEyMDA1NDEwNDQxMGQxMDliMDEyMDAyMjgwMjA4MjAwMjI4MDIwYzIwMDQ0MTA5MTA1NzIwMDAyMDA1NDEwZDEwMGYxYTIwMDI0MWQwMDA2YTI0MDAwYjBmMDAyMDAwMjAwMTIwMDIyMDAzNDEwODEwZjkwMTBiYjUwMjAxMDY3ZjIwMDEyMDAzNDYwNDQwMjAwMTIyMDM0MTEwNGYwNDQwMjAwMDQxMDAyMDAwNmI0MTAzNzEyMjA0NmEyMTA1MjAwNDA0NDAyMDAyMjEwMTAzNDAyMDAwMjAwMTJkMDAwMDNhMDAwMDIwMDE0MTAxNmEyMTAxMjAwMDQxMDE2YTIyMDAyMDA1NDkwZDAwMGIwYjIwMDUyMDAzMjAwNDZiMjIwMzQxN2M3MTIyMDY2YTIxMDAwMjQwMjAwMjIwMDQ2YTIyMDQ0MTAzNzEwNDQwMjAwNjQxMDA0YzBkMDEyMDA0NDEwMzc0MjIwMTQxMTg3MTIxMDcyMDA0NDE3YzcxMjIwODQxMDQ2YTIxMDI0MTAwMjAwMTZiNDExODcxMjEwOTIwMDgyODAyMDAyMTAxMDM0MDIwMDUyMDAxMjAwNzc2MjAwMjI4MDIwMDIyMDEyMDA5NzQ3MjM2MDIwMDIwMDI0MTA0NmEyMTAyMjAwNTQxMDQ2YTIyMDUyMDAwNDkwZDAwMGIwYzAxMGIyMDA2NDEwMDRjMGQwMDIwMDQyMTAyMDM0MDIwMDUyMDAyMjgwMjAwMzYwMjAwMjAwMjQxMDQ2YTIxMDIyMDA1NDEwNDZhMjIwNTIwMDA0OTBkMDAwYjBiMjAwMzQxMDM3MTIxMDMyMDA0MjAwNjZhMjEwMjBiMjAwMzA0NDAyMDAwMjAwMzZhMjEwMTAzNDAyMDAwMjAwMjJkMDAwMDNhMDAwMDIwMDI0MTAxNmEyMTAyMjAwMDQxMDE2YTIyMDAyMDAxNDkwZDAwMGIwYjBmMGIxMDJjMDAwYmEyMDMwMTA3N2YyMzAwNDE0MDZhMjIwMTI0MDAyMDAwMTA0YjIxMDIxMDQzMjEwNTIwMDIxMDEyMjEwMDIwMDE0MTJjNmE0MTAwM2EwMDAwMjAwMTQxMjg2YTIwMDAzNjAyMDAyMDAxMjAwMjM2MDIyNDIwMDEyMDAwMzYwMjIwMjAwMTQxMDAzNjAyMWM0MTAwMjEwMjAzN2YyMDAwMjAwMjQ2MDQ3ZjIwMDEyZDAwMmMwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAxNDE0MDZiMjQwMDIwMDUwNTIwMDE0MTFjNmEyMjAwNDFhZDg3MDg0MTE4MTAzYTIxMDMyMDAwNDFhZDg3MDg0MTE4MTA1MjIxMDAxMDQzMjEwMjAzNDAyMDAwMDQ0MDIwMDE0MTFjNmEyMjA0NDFhZDg3MDg0MTE4MTA1MjIxMDYyMDA0NDFhZDg3MDg0MTE4MTA1MzIxMDcyMDA0NDFhZDg3MDg0MTE4MTAzYTIxMDQyMDAxMjAwNjM2MDIzODIwMDEyMDA0MzYwMjM0MjAwMTIwMDczNjAyMzAyMDAyMjAwMTQxMzA2YTEwNTkyMDAwNDEwMTZiMjEwMDBjMDEwYjBiMjAwMTQyMDAzNzAzMzAyMDAxMjAwMzQxMTg3NDIwMDM0MTgwZmUwMzcxNDEwODc0NzIyMDAzNDEwODc2NDE4MGZlMDM3MTIwMDM0MTE4NzY3MjcyMzYwMjNjMjAwMTQxMTA2YTIwMDE0MTMwNmEyMjAwNDEwMDQxMDQxMDU2MjAwMTI4MDIxMDIwMDEyODAyMTQyMDAxNDEzYzZhMjIwMzQxMDQxMDU3MjAwMTIwMDI0MTE4NzQyMDAyNDE4MGZlMDM3MTQxMDg3NDcyMjAwMjQxMDg3NjQxODBmZTAzNzEyMDAyNDExODc2NzI3MjM2MDIzYzIwMDE0MTA4NmEyMDAwNDEwNDQxMDgxMDU2MjAwMTI4MDIwODIwMDEyODAyMGMyMDAzNDEwNDEwNTcyMDA1MjAwMDQxMDgxMDBmMWEyMDAxMjgwMjFjMjEwMjIwMDEyODAyMjAyMTAwMGMwMTBiMGIwYmI4MDIwMTA0N2YyMzAwNDE0MDZhMjIwMjI0MDAyMDAyNDEyODZhNDEwMDM2MDIwMDIwMDI0MjAwMzcwMzIwMjAwMjIwMDEyODAyMDgyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyMzAyMDAyNDExODZhMjAwMjQxMjA2YTIyMDU0MTAwNDEwNDEwOWEwMTIwMDIyODAyMTgyMDAyMjgwMjFjMjAwMjQxMzA2YTIyMDQ0MTA0MTA1NzIwMDI0MjAwMzcwMzMwMjAwMjIwMDEyODAyMDAyMjAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyM2MyMDAyNDExMDZhMjAwNDQxMDA0MTA0MTA1NjIwMDIyODAyMTAyMDAyMjgwMjE0MjAwMjQxM2M2YTIyMDM0MTA0MTA1NzIwMDIyMDAxMjgwMjA0MjIwMTQxMTg3NDIwMDE0MTgwZmUwMzcxNDEwODc0NzIyMDAxNDEwODc2NDE4MGZlMDM3MTIwMDE0MTE4NzY3MjcyMzYwMjNjMjAwMjQxMDg2YTIwMDQ0MTA0NDEwODEwNTYyMDAyMjgwMjA4MjAwMjI4MDIwYzIwMDM0MTA0MTA1NzIwMDIyMDA1NDEwNDQxMGMxMDlhMDEyMDAyMjgwMjAwMjAwMjI4MDIwNDIwMDQ0MTA4MTA1NzIwMDAyMDA1NDEwYzEwMGYxYTIwMDI0MTQwNmIyNDAwMGIxNDAwMTAxMzIwMDA0NjA0NDAwZjBiNDE5Mjg0MDg0MTE5MTAwMzAwMGIwOTAwMjAwMDEwNWMxMDA3MWEwYjFkMDAyMDAwMTBhNzAxMjIwMDEwMTI0MTIwNDcwNDQwNDFiMDg2MDg0MTEwMTA4ODAxMDAwYjIwMDAwYjBhMDAyMDAwMTBhNzAxMTAwNzFhMGIwODAwMjAwMDEwNWYxMDE0MGI2MTAyMDI3ZjAxN2UyMzAwNDExMDZiMjIwMTI0MDAyMDAxNDIwMDM3MDMwODIwMDAxMGE3MDEyMjAwMTAxMjIyMDI0MTA5NGYwNDQwNDE5NTg1MDg0MTBlMTA4ODAxMDAwYjIwMDEyMDAxNDEwODZhMjAwMjEwYjAwMTIwMDA0MTAwMjAwMTI4MDIwMDIyMDAyMDAxMjgwMjA0MjIwMjEwOGEwMTFhMjAwMDIwMDIxMGIxMDEyMDAxNDExMDZhMjQwMDBiMWYwMDIwMDAyMDAxMjAwMjEwMTUyMDAwMTA2MTQxZmYwMTcxMDQ0MDBmMGI0MWFiODQwODQxMzAxMDAzMDAwYjE1MDA0MTAyNDEwMTIwMDAxMDI3MjIwMDFiNDEwMDIwMDA0MTAwNGUxYjBiZjgwMTAxMDQ3ZjIzMDA0MWQwMDA2YjIyMDUyNDAwMjAwNTIwMDQzNjAyMjgyMDA1NDEyMDZhNDFkYjg0MDg0MTE0MTA2MzIwMDUyODAyMjAyMTA3MjAwNTI4MDIyNDIyMDYyMDAzMTA2NDIwMDQxMDY1MjEwMzEwNDMyMjA4MjAwM2FkMTA2NjIwMDYyMDA4MTA0ZTIwMDUyMDA0MTAxMjM2MDIzNDIwMDU0MTAwMzYwMjMwMjAwNTIwMDU0MTI4NmEzNjAyMmMwMzQwMjAwNTQxMzg2YTIwMDU0MTJjNmExMDY3MjAwNTI5MDMzODUwMDQ0MDIwMDUyMDA3MjAwNjIwMDEyMDAyMTA2ODIwMDUyODAyMDQyMTAxMjAwMDIwMDUyODAyMDAzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MWQwMDA2YTI0MDAwNTIwMDUyODAyNGMyMTAzMjAwNTQxMTg2YTIwMDcyMDA2MjAwNTI4MDI0ODEwNjkyMDA1NDExMDZhMjAwNTI4MDIxODIwMDUyODAyMWMyMDA1MjkwMzQwMTA2YTIwMDU0MTA4NmEyMDA1MjgwMjEwMjAwNTI4MDIxNDIwMDMxMDZiMjAwNTI4MDIwYzIxMDYyMDA1MjgwMjA4MjEwNzBjMDEwYjBiMGIxODAwMjAwMTIwMDIxMDRkMjEwMTIwMDAxMDQzMzYwMjA0MjAwMDIwMDEzNjAyMDAwYjEwMDAxMDQzMWEyMDAwMjAwMTI4MDIwMDEwMmYxMDRlMGIwOTAwMjAwMDEwMTI0MTA0NzYwYjM4MDEwMTdmMjMwMDQxMTA2YjIyMDIyNDAwMjAwMjQyMDAzNzAzMDgyMDAyMjAwMTQxMDAyMDAyNDEwODZhMTA4MjAxMjAwMDIwMDIyODAyMDAyMDAyMjgwMjA0MTAxODFhMjAwMjQxMTA2YTI0MDAwYmE3MDEwMjA1N2YwMTdlMjMwMDQxMjA2YjIyMDIyNDAwMjAwMDIwMDEyODAyMDQyMjA0NDExMDZhMjIwNTIwMDEyODAyMDg0ZDA0N2UyMDAxMjgwMjAwMjAwMjQxMTA2YTQyMDAzNzAzMDAyMDAyNDIwMDM3MDMwODI4MDIwMDIwMDQyMDAyNDEwODZhMjIwMzQxMTAxMDZmMWEyMDAyNDEwMDM2MDIxYzIwMDMyMDAyNDExYzZhMjIwNjEwOTgwMTIxMDQyMDAzMjAwNjEwOTkwMTIxMDcyMDAwNDExNDZhMjAwMjQxMDg2YTIwMDI0MTFjNmExMDk4MDEzNjAyMDAyMDAwNDExMDZhMjAwNDM2MDIwMDIwMDAyMDA3MzcwMzA4MjAwMTIwMDUzNjAyMDQ0MjAxMDU0MjAwMGIzNzAzMDAyMDAyNDEyMDZhMjQwMDBiOTEwMTAxMDM3ZjIzMDA0MTEwNmIyMjA1MjQwMDAyNDAyMDAzMTAxMjQ1MGQwMDIwMDIyMDAzMTA2ZTIwMDQxMDEyMjEwNjQxMDAyMTAzMDM0MDIwMDM0MTA0NmEyMjA3MjAwNjRiMGQwMTIwMDU0MTAwMzYwMjBjMjAwNDIwMDMyMDA1NDEwYzZhNDEwNDEwNmYxYTIwMDIyMDA1MjgwMjBjMjIwMzQxMTg3NDIwMDM0MTgwZmUwMzcxNDEwODc0NzIyMDAzNDEwODc2NDE4MGZlMDM3MTIwMDM0MTE4NzY3MjcyMTA2ZTIwMDcyMTAzMGMwMDBiMDAwYjIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAyMDA1NDExMDZhMjQwMDBiMTYwMDIwMDIyMDAzMTA2ZTIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAwYjIwMDEwMTdmMTA0MzIyMDQyMDAzMTA2NjIwMDIyMDA0MTA0ZTIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAwYjE2MDAyMDAzMjAwMjEwNzAyMDAwMjAwMjM2MDIwNDIwMDAyMDAxMzYwMjAwMGJhMzAxMDEwMjdmMjMwMDQxMzA2YjIyMDUyNDAwMjAwNTQxMjg2YTQxZWY4NDA4NDEwZjEwNjMyMDA1NDEyMDZhMjAwNTI4MDIyODIwMDUyODAyMmMyMDA0MjgwMjA4MTA2OTIwMDU0MTE4NmEyMDA1MjgwMjIwMjAwNTI4MDIyNDIwMDQyOTAzMDAxMDZhMjAwNTQxMTA2YTIwMDUyODAyMTgyMDA1MjgwMjFjMjAwNDI4MDIwYzEwNmIyMDA1MjgwMjEwMjEwNDIwMDUyODAyMTQyMTA2MTA0MzFhMjAwNjIwMDMxMDJmMTA0ZTIwMDU0MTA4NmEyMDA0MjAwNjIwMDEyMDAyMTA2ODIwMDUyODAyMGMyMTAxMjAwMDIwMDUyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTMwNmEyNDAwMGI3MTAxMDE3ZjIzMDA0MTIwNmIyMjA1MjQwMDIwMDU0MTE4NmE0MWZlODQwODQxMGMxMDYzMjAwNTQxMTA2YTIwMDUyODAyMTgyMDA1MjgwMjFjMjAwMzEwNjkyMDA1NDEwODZhMjAwNTI4MDIxMDIwMDUyODAyMTQyMDA0MTA2YjIwMDUyMDA1MjgwMjA4MjAwNTI4MDIwYzIwMDEyMDAyMTA2ODIwMDUyODAyMDQyMTAxMjAwMDIwMDUyODAyMDAzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTIwNmEyNDAwMGIwZDAwMTA0MzFhMjAwMDIwMDExMDJmMTA0ZTBiMGQwMDIwMDAyMDAxMjAwMjIwMDMxMDhhMDEwYjBkMDAxMDQzMWEyMDAxMjAwMDEwM2QxMDRlMGIwZjAwMjAwMDQyN2Y1MTA0N2UxMDE2MDUyMDAwMGIwYjMwMDEwMTdlMjAwMDI5MDMwODIyMDE0MjdmNTEwNDdlMTAxNjA1MjAwMTBiMjAwMDI4MDIxMDIwMDAyODAyMTgyMDAwMjgwMjAwMjAwMDI4MDIwNDEwNDUxMDE3MTA3MzBiM2IwMTAyN2YyMzAwNDExMDZiMjIwMTI0MDAyMDAwMTAxMjIxMDIyMDAxNDEwMDM2MDIwYzIwMDEyMDAwMzYwMjA0MjAwMTIwMDI0MTAyNzYzNjAyMDgyMDAxNDEwNDZhMTA3NTEwM2IyMDAxNDExMDZhMjQwMDBiMjQwMDIwMDAyOTAzMDgxMDcxMjAwMDI4MDIxMDIwMDAyODAyMTgyMDAwMjgwMjAwMjAwMDI4MDIwNDEwNDUxMDE3MTAxMjFhMGI3ZDAxMDM3ZjIzMDA0MTEwNmIyMjAxMjQwMDIwMDAyODAyMDgyMTAzMjAwMTQxMDAzNjAyMGMyMDAwMjgwMjAwMjAwMzQxMDI3NDIwMDE0MTBjNmE0MTA0MTA2ZjQ1MDQ0MDIwMDEyODAyMGMyMTAyMjAwMDIwMDM0MTAxNmEzNjAyMDgyMDAyNDExODc0MjAwMjQxODBmZTAzNzE0MTA4NzQ3MjIwMDI0MTA4NzY0MTgwZmUwMzcxMjAwMjQxMTg3NjcyNzIxMDJmMjAwMTQxMTA2YTI0MDAwZjBiNDE4YTg1MDg0MTBiNDFlZjgzMDg0MTExMTA0YzAwMGI5MDAyMDIwMjdmMDE3ZTIzMDA0MWQwMDA2YjIyMDIyNDAwMjAwMTI5MDMwODIyMDQ0MjdmNTEwNDdlMTAxNjA1MjAwNDBiMjAwMTI4MDIxMDIwMDEyODAyMTgyMDAxMjgwMjAwMjAwMTI4MDIwNDEwNDUyMTAxMTAxNzIwMDExMDEyMjEwMzIwMDI0MTAwMzYwMjE0MjAwMjIwMDEzNjAyMGMyMDAyMjAwMzQxMDI3NjM2MDIxMDIwMDI0MTBjNmExMDc1MjIwMzEwMTIyMTAxMjAwMjQxM2M2YTQxMDAzYTAwMDAyMDAyNDEzODZhMjAwMTM2MDIwMDIwMDIyMDAzMzYwMjM0MjAwMjIwMDEzNjAyMzAyMDAyNDEwMDM2MDIyYzIwMDI0MTQwNmIyMDAyNDEyYzZhMTA3NzIwMDIyODAyMzAyMDAyMjgwMjJjNDYwNDQwMjAwMjQxMjA2YTIyMDEyMDAyNDFjODAwNmEyOTAzMDAzNzAzMDAyMDAyMjAwMjI5MDM0MDM3MDMxODIwMDIyZDAwM2MwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAwMjAwMjI5MDMxODM3MDMwMDIwMDA0MTA4NmEyMDAxMjkwMzAwMzcwMzAwMjAwMjQxZDAwMDZhMjQwMDBmMGI0MThhODUwODQxMGI0MTk1ODUwODQxMGUxMDRjMDAwYjMwMDIwMTdmMDE3ZTIwMDE0MThhODUwODQxMGIxMDNhMjEwMjIwMDExMGJlMDEyMTAzMjAwMDIwMDExMDM5MzYwMjBjMjAwMDIwMDIzNjAyMDgyMDAwMjAwMzM3MDMwMDBiMTAwMDEwNDMxYTIwMDAyMDAxMjgwMjAwMTAzZDEwNGUwYjBlMDAyMDAxNDUwNDQwMjAwMjIwMDAxMDcwMGIwYjgxMDEwMTA1N2YyMzAwNDExMDZiMjIwMzI0MDAxMDQzMTAyZjIxMDQyMDAxMjgwMjAwMTAxMjIxMDUwMzQwMjAwNTIwMDI0MTA0NmEyMjA2NGYwNDQwMjAwMzQxMDAzNjAyMGMyMDAxMjgwMjAwMjAwMjIwMDM0MTBjNmE0MTA0MTA2ZjFhMjAwMzI4MDIwYzIyMDI0MTE4NzQyMDAyNDE4MGZlMDM3MTQxMDg3NDcyMjAwMjQxMDg3NjQxODBmZTAzNzEyMDAyNDExODc2NzI3MjIwMDQxMDNmMjAwNjIxMDIwYzAxMGIwYjIwMDAyMDA0MTA0ZTIwMDM0MTEwNmEyNDAwMGI4MjAxMDEwNTdmMjMwMDQxMTA2YjIyMDMyNDAwMTA0MzEwMmYyMTA0MjAwMTI4MDIwMDEwMTIyMTA1MDM0MDIwMDUyMDAyNDEwNDZhMjIwNjRmMDQ0MDIwMDM0MTAwMzYwMjBjMjAwMTI4MDIwMDIwMDIyMDAzNDEwYzZhNDEwNDEwNmYxYTIwMDQyMDAzMjgwMjBjMjIwMjQxMTg3NDIwMDI0MTgwZmUwMzcxNDEwODc0NzIyMDAyNDEwODc2NDE4MGZlMDM3MTIwMDI0MTE4NzY3MjcyMTAwNTFhMjAwNjIxMDIwYzAxMGIwYjIwMDAyMDA0MTA0ZTIwMDM0MTEwNmEyNDAwMGI0ZDAxMDI3ZjIzMDA0MTIwNmIyMjAxMjQwMDEwN2QyMTAyMjAwMTQxMTA2YTIwMDA0MTEwNmEyOTAzMDAzNzAzMDAyMDAxNDEwODZhMjAwMDQxMDg2YTI5MDMwMDM3MDMwMDIwMDEyMDAyMzYwMjE4MjAwMTIwMDAyOTAzMDAzNzAzMDAyMDAxMTA3MjIwMDE0MTIwNmEyNDAwMGIwZTAxMDE3ZjEwMmEyMjAwNDIwMDEwMDEyMDAwMGI0ZjAxMDI3ZjIzMDA0MTIwNmIyMjAyMjQwMDEwN2QyMTAzMjAwMjQxMTA2YTIwMDE0MTEwNmEyOTAzMDAzNzAzMDAyMDAyNDEwODZhMjAwMTQxMDg2YTI5MDMwMDM3MDMwMDIwMDIyMDAzMzYwMjE4MjAwMjIwMDEyOTAzMDAzNzAzMDAyMDAwMjAwMjEwNzYyMDAyNDEyMDZhMjQwMDBiNGQwMTAyN2YyMzAwNDEyMDZiMjIwMTI0MDAxMDdkMjEwMjIwMDE0MTEwNmEyMDAwNDExMDZhMjkwMzAwMzcwMzAwMjAwMTQxMDg2YTIwMDA0MTA4NmEyOTAzMDAzNzAzMDAyMDAxMjAwMjM2MDIxODIwMDEyMDAwMjkwMzAwMzcwMzAwMjAwMTEwMzQyMDAxNDEyMDZhMjQwMDBiNzYwMjA1N2YwMTdlMjMwMDQxMTA2YjIyMDEyNDAwMTA3ZDIxMDIyMDAwMjgwMjEwMjEwMzIwMDAyODAyMDQyMTA0MjAwMDI4MDIwMDIxMDUyMDAwMjkwMzA4MjIwNjQyN2Y1MTA0N2UxMDE2MDUyMDA2MGIyMDAzMjAwMjIwMDUyMDA0MTA0NTIxMDAxMDE3MjAwMDEwMTIyMTAyMjAwMTQxMDAzNjAyMGMyMDAxMjAwMDM2MDIwNDIwMDEyMDAyNDEwMjc2MzYwMjA4MjAwMTQxMDQ2YTEwNzUxMDJmMjAwMTQxMTA2YTI0MDAwYjQ3MDEwMjdmMjMwMDQxMTA2YjIyMDIyNDAwMTA0MzIxMDMyMDAyNDIwMDM3MDMwODIwMDIyMDAxYWQ0MmZmMDE4MzQxMDEyMDAyNDEwODZhMTA4MjAxMjAwMzIwMDIyODAyMDAyMDAyMjgwMjA0MTAxODFhMjAwMDIwMDMxMDRlMjAwMjQxMTA2YTI0MDAwYjhmMDIwMjA0N2YwMTdlMjAwMzIwMDE0MjM4ODYyMDAxNDI4MGZlMDM4MzQyMjg4Njg0MjAwMTQyODA4MGZjMDc4MzQyMTg4NjIwMDE0MjgwODA4MGY4MGY4MzQyMDg4Njg0ODQyMDAxNDIwODg4NDI4MDgwODBmODBmODMyMDAxNDIxODg4NDI4MDgwZmMwNzgzODQyMDAxNDIzODg4MjIwODIwMDE0MjI4ODg0MjgwZmUwMzgzODQ4NDg0MzcwMDAwMDI0MDIwMDE1MDA0NDA0MWI4OGQwODIxMDMwYzAxMGIyMDAyMDQ0MDIwMDE0MjdmNTEwNDQwMjAwMzQxMDc2YTIxMDM0MTAxMjEwNDBjMDIwYjIwMDhhN2MwMjIwNTQxMDc3NTIxMDYyMDA1NDEwMDQ4MjEwNTBiMjAwNjQxZmYwMTcxMjEwNjAzNDAwMjQwMDI0MDIwMDQ0MTA4NDcwNDQwMjAwMzIwMDQ2YTJkMDAwMDIyMDcyMDA2NDYwZDAyMjAwMjQ1MjAwNzQxMDc3NjIwMDU0NjcyNDUwNDQwMjAwNDQxMDE2YjIyMDQ0MTA5NGYwZDAyMGIyMDAzMjAwNDZhMjEwMzQxMDgyMDA0NmIyMTA0MGMwNDBiMTAyYzAwMGIxMDJjMDAwYjIwMDQ0MTAxNmEyMTA0MGMwMDBiMDAwYjIwMDAyMDA0MzYwMjA0MjAwMDIwMDMzNjAyMDAwYmEzMDEwMjAzN2YwMTdlMjMwMDQxMTA2YjIyMDMyNDAwMDI3ZjIwMDIyOTAzMDA1MDA0NDAyMDAxMjgwMjEwMjEwNDIwMDMyMDAxMjgwMjAwMjAwMTI4MDIwNDIwMDIyODAyMDgyMDAyMjgwMjBjMTA2ZDIwMDMyODAyMDAyMTA1MjAwMzI4MDIwNDBjMDEwYjEwNDcyMTA0MjAwMzQxMDg2YTIwMDEyODAyMDAyMDAxMjgwMjA0MjAwMTI4MDIxMDIwMDIxMDZjMjAwMzI4MDIwODIxMDUyMDAzMjgwMjBjMGIyMTAyMjAwMTI5MDMwODIxMDYyMDAwMTA3ZDM2MDIxODIwMDAyMDA0MzYwMjEwMjAwMDIwMDYzNzAzMDgyMDAwMjAwMjM2MDIwNDIwMDAyMDA1MzYwMjAwMjAwMzQxMTA2YTI0MDAwYjNmMDEwMTdmMTA0MzIxMDMyMDAwMjAwMTI5MDMwMDM3MDMwMDIwMDA0MTEwNmEyMDAxNDExMDZhMjkwMzAwMzcwMzAwMjAwMDQxMDg2YTIwMDE0MTA4NmEyOTAzMDAzNzAzMDAyMDAzMjAwMjEwNDQyMDAwMjAwMzM2MDIxODBiNTIwMTAyN2YyMzAwNDExMDZiMjIwNDI0MDAyMDA0NDEwODZhMjAwMDI4MDIwODIwMDAyODAyMDAyMjA1MjAwMTEwODYwMTIwMDQyODAyMDg0MTAxNDYwNDQwMjAwNDI4MDIwYzIwMDAyMDAxMjAwNTZhMzYwMjAwMjAwNDQxMTA2YTI0MDAwZjBiMjAwMjIwMDM0MWEzODUwODQxMGYxMDRjMDAwYjFmMDAyMDAxMjAwMjIwMDMxMDA0MjIwMTEwMWYyMTAyMjAwMDIwMDEzNjAyMDQyMDAwMjAwMjQ1MzYwMjAwMGI0ZjAxMDM3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDI0MTA4NmEyMDAwMjgwMjA4MjAwMDI4MDIwMDIyMDMyMDAxMTA4NjAxMjAwMjI4MDIwODQxMDE0NjA0NDAyMDAyMjgwMjBjMjAwMDIwMDEyMDAzNmEzNjAyMDAyMDAyNDExMDZhMjQwMDBmMGI0MWEzODUwODQxMGYxMDg4MDEwMDBiMWEwMTAxN2Y0MWYxODUwODQxMTYxMDRkMjIwMjIwMDAyMDAxMTAwZjFhMjAwMjEwMDAwMDBiMTUwMDQxN2YyMDAwMjAwMTEwMTkyMjAwNDEwMDQ3MjAwMDQxMDA0ODFiMGIwZjAwMjAwMDIwMDEyMDAzMjAwMjEwMjg0MTAwNDcwYjA5MDAyMDAwMjAwMTEwMDUxYTBiMGMwMDIwMDAyMDAwMjAwMTEwMDIyMDAwMGIwYzAwMjAwMDIwMDAyMDAxMTAxYTIwMDAwYjBjMDAyMDAwMjAwMDIwMDExMDFiMjAwMDBiMGEwMDIwMDAyMDAwMjAwMTEwMDIwYjBjMDAyMDAwMjAwMDIwMDExMDYwMjAwMDBiMTAwMTAxN2YxMDJhMjIwMjIwMDAyMDAxMTAwMjIwMDIwYjEwMDEwMTdmMTAyYTIyMDIyMDAwMjAwMTEwMWIyMDAyMGIxMDAxMDE3ZjEwMmEyMjAyMjAwMDIwMDExMDYwMjAwMjBiMTkwMTAxN2YxMDJhMjEwMjQxNzIyMDAxYWQxMDAxMjAwMjIwMDA0MTcyMTAxZTIwMDIwYjBlMDEwMTdmMTA0MzIyMDEyMDAwMTA0NDIwMDEwYjRjMDEwMjdmMjMwMDQxMTA2YjIyMDEyNDAwMTA0MzIxMDIyMDAxMjAwMDQxMTg3NDIwMDA0MTgwZmUwMzcxNDEwODc0NzIyMDAwNDEwODc2NDE4MGZlMDM3MTIwMDA0MTE4NzY3MjcyMzYwMjBjMjAwMjIwMDE0MTBjNmE0MTA0MTAwZjFhMjAwMTQxMTA2YTI0MDAyMDAyMGI4NDAxMDIwNDdmMDE3ZTIzMDA0MTIwNmIyMjAyMjQwMDIwMDI0MTEwNmE0MjAwMzcwMzAwMjAwMjQyMDAzNzAzMDgyMDAxNDEwMDIwMDI0MTA4NmEyMjAzNDExMDEwNmYyMDAyNDEwMDM2MDIxYzIwMDMyMDAyNDExYzZhMjIwNDEwOTgwMTIxMDUyMDAzMjAwNDEwOTkwMTIxMDYyMDAyNDEwODZhMjAwMjQxMWM2YTEwOTgwMTIxMDMwNDQwNDFjMzg1MDg0MTFkMTAwMzAwMGIyMDAwMjAwMzM2MDIwYzIwMDAyMDA1MzYwMjA4MjAwMDIwMDYzNzAzMDAyMDAyNDEyMDZhMjQwMDBiNzQwMTAxN2YyMzAwNDExMDZiMjIwMjI0MDAyMDAyNDEwMDM2MDIwYzIwMDIyMDAwNDExMDIwMDEyODAyMDAyMjAwMjAwMDQxMDQ2YTIyMDAxMDlkMDEyMDAyNDEwYzZhNDEwNDIwMDIyODAyMDAyMDAyMjgwMjA0MTA1NzIwMDEyMDAwMzYwMjAwMjAwMjI4MDIwYzIxMDAyMDAyNDExMDZhMjQwMDIwMDA0MTE4NzQyMDAwNDE4MGZlMDM3MTQxMDg3NDcyMjAwMDQxMDg3NjQxODBmZTAzNzEyMDAwNDExODc2NzI3MjBiYTgwMTAyMDE3ZTAxN2YyMzAwNDExMDZiMjIwMzI0MDAyMDAzNDIwMDM3MDMwODIwMDMyMDAwNDExMDIwMDEyODAyMDAyMjAwMjAwMDQxMDg2YTIyMDAxMDlkMDEyMDAzNDEwODZhNDEwODIwMDMyODAyMDAyMDAzMjgwMjA0MTA1NzIwMDEyMDAwMzYwMjAwMjAwMzI5MDMwODIxMDIyMDAzNDExMDZhMjQwMDIwMDI0MjM4ODYyMDAyNDI4MGZlMDM4MzQyMjg4Njg0MjAwMjQyODA4MGZjMDc4MzQyMTg4NjIwMDI0MjgwODA4MGY4MGY4MzQyMDg4Njg0ODQyMDAyNDIwODg4NDI4MDgwODBmODBmODMyMDAyNDIxODg4NDI4MDgwZmMwNzgzODQyMDAyNDIyODg4NDI4MGZlMDM4MzIwMDI0MjM4ODg4NDg0ODQwYjBmMDAyMDAwMjAwMTIwMDIyMDAzNDEwYzEwZjkwMTBiMGYwMDIwMDAyMDAxMjAwMjIwMDM0MTBkMTBmOTAxMGIwZjAwMjAwMDIwMDEyMDAyMjAwMzQxMDkxMGY5MDEwYjJmMDAwMjQwMjAwMzIwMDQ0ZDA0NDAyMDAyMjAwNDQ5MGQwMTIwMDAyMDA0MjAwMzZiMzYwMjA0MjAwMDIwMDEyMDAzNmEzNjAyMDAwZjBiMTAyYzAwMGIxMDJjMDAwYmI0MDEwMTAzN2YyMzAwNDExMDZiMjIwNDI0MDAwMjdmMDI0MDIwMDAyZDAwMDg0NTA0NDAyMDAwMjgwMjAwMjIwNTEwMTIyMjA2NDE5MGNlMDA0YjBkMDE0MWUwZGIwODJkMDAwMDBkMDE0MWRjZGIwODIwMDYzNjAyMDA0MWUwZGIwODQxMDEzYTAwMDAyMDA0NDEwODZhMjAwNjEwOWYwMTIwMDU0MTAwMjAwNDI4MDIwODIwMDQyODAyMGMxMDZmMWEyMDAwNDEwMTNhMDAwODBiNDEwMTIwMDEyMDAzNmEyMjAwNDFkY2RiMDgyODAyMDA0YjBkMDExYTIwMDQyMDAxMjAwMDEwYTAwMTIwMDIyMDAzMjAwNDI4MDIwMDIwMDQyODAyMDQxMDU3NDEwMDBjMDEwYjIwMDA0MTAwM2EwMDA4MjAwNTIwMDEyMDAyMjAwMzEwNmYwYjIwMDQ0MTEwNmEyNDAwMGIzZTAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDI0MTA4NmE0MWNjOGQwODQxOTBjZTAwMjAwMTEwZDAwMTIwMDIyODAyMGMyMTAxMjAwMDIwMDIyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDI0MTEwNmEyNDAwMGIzMjAwMDI0MDIwMDEyMDAyNGQwNDQwMjAwMjQxOTBjZTAwNGQwZDAxMTAyYzAwMGIxMDJjMDAwYjIwMDAyMDAyMjAwMTZiMzYwMjA0MjAwMDIwMDE0MWNjOGQwODZhMzYwMjAwMGIxOTAwMjAwMDQxZmVmZmZmZmYwNzQ2MDQ0MDQxZTA4NTA4NDEwZDEwMDMwMDBiMjAwMDBiNGQwMTAxN2YyMzAwNDExMDZiMjIwMTI0MDAyMDAwMTAxMjQxMDQ0NjA0NDAyMDAxNDEwMDM2MDIwYzIwMDA0MTAwMjAwMTQxMGM2YTQxMDQxMDhhMDExYTQxZmVmZmZmZmYwNzIwMDAyMDAxMjgwMjBjNDFjNThlYjFhMjA0NDYxYjIxMDAwYjIwMDE0MTEwNmEyNDAwMjAwMDBiODAwMTAxMDI3ZjIzMDA0MTEwNmIyMjAzMjQwMDAyNDAwMjQwMjAwMDJkMDAwNDA0NDA0MTkwY2UwMDQxZGNkYjA4MjgwMjAwMjIwNDZiMjAwMjQ5MGQwMTIwMDM0MTA4NmEyMDA0MjAwMjIwMDQ2YTIyMDAxMGE0MDEyMDAzMjgwMjA4MjAwMzI4MDIwYzIwMDEyMDAyMTA1NzQxZGNkYjA4MjAwMDM2MDIwMDBjMDIwYjIwMDAyODAyMDAyMDAxMjAwMjEwMGYxYTBjMDEwYjIwMDAxMGE1MDEyMDAwMjgwMjAwMjAwMTIwMDIxMDBmMWEwYjIwMDM0MTEwNmEyNDAwMGIzZjAxMDE3ZjIzMDA0MTEwNmIyMjAzMjQwMDIwMDM0MTA4NmEyMDAxMjAwMjQxY2M4ZDA4NDE5MGNlMDAxMDJiMjAwMzI4MDIwYzIxMDEyMDAwMjAwMzI4MDIwODM2MDIwMDIwMDAyMDAxMzYwMjA0MjAwMzQxMTA2YTI0MDAwYjU4MDEwMjdmMjMwMDQxMTA2YjIyMDEyNDAwMjAwMDJkMDAwNDIwMDA0MTAwM2EwMDA0MDQ0MDIwMDE0MTA4NmE0MTAwNDFkY2RiMDgyODAyMDAxMGEwMDEyMDAwMjgwMjAwMjAwMTI4MDIwODIwMDEyODAyMGMxMDBmMWE0MWRjZGIwODQxMDAzNjAyMDA0MWUwZGIwODQxMDAzYTAwMDAwYjIwMDE0MTEwNmEyNDAwMGIwZDAwMjAwMDQxNjcxMDIwMWE0MTY3MTAxMjBiMGQwMDIwMDAxMDJhMjIwMDEwMjAxYTIwMDAwYjEyMDAyMDAwMTBhNjAxNDUwNDQwMjAwMDIwMDExMDIxMWEwYjBiMTIwMDIwMDAxMGE2MDE0NTA0NDAyMDAwMjAwMTEwYWEwMTBiMGIzODAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDI0MjAwMzcwMzA4MjAwMjIwMDE0MTAwMjAwMjQxMDg2YTEwODIwMTIwMDAyMDAyMjgwMjAwMjAwMjI4MDIwNDEwYjgwMTIwMDI0MTEwNmEyNDAwMGIwYTAwMjAwMDEwYTcwMTEwYTIwMTBiYjkwMTAxMDQ3ZjIzMDA0MTIwNmIyMjAxMjQwMDIwMDAxMGE3MDEyMTAyMTA0MzIxMDQyMDAyMTAxMjIxMDAyMDAxNDExMDZhNDEwMDNhMDAwMDIwMDE0MTBjNmEyMDAwMzYwMjAwMjAwMTIwMDIzNjAyMDgyMDAxMjAwMDM2MDIwNDIwMDE0MTAwMzYwMjAwMDM3ZjIwMDAyMDAzNDYwNDdmMjAwMTJkMDAxMDA0NDA0MWRjZGIwODQxMDAzNjAyMDA0MWUwZGIwODQxMDAzYTAwMDAwYjIwMDE0MTIwNmEyNDAwMjAwNDA1MjAwMTEwYWQwMTIxMDAyMDAxMTBhZTAxMjEwMjIwMDExMGFmMDEyMTAzMjAwMTIwMDAzNjAyMWMyMDAxMjAwMzM2MDIxODIwMDEyMDAyMzYwMjE0MjAwNDIwMDE0MTE0NmExMDU5MjAwMTI4MDIwMDIxMDMyMDAxMjgwMjA0MjEwMDBjMDEwYjBiMGIzMzAyMDE3ZjAxN2UyMzAwNDExMDZiMjIwMTI0MDAyMDAxNDEwMDM2MDIwYzIwMDAyMDAxNDEwYzZhMjIwMDQxMDQxMGIzMDEyMDAwNDEwNDEwYjEwMTIwMDE0MTEwNmEyNDAwYTcwYjA5MDAyMDAwNDEyMDEwODcwMTBiMGMwMDIwMDAyMDAwMTBhZDAxMTA4NzAxMGIzYTAxMDE3ZjIzMDA0MTEwNmIyMjAzMjQwMDIwMDM0MTA4NmEyMDAxNDEwODIwMDIxMGQwMDEyMDAzMjgwMjBjMjEwMTIwMDAyMDAzMjgwMjA4MzYwMjAwMjAwMDIwMDEzNjAyMDQyMDAzNDExMDZhMjQwMDBiMzQwMTAxN2UwMjQwMjAwMTQ1MGQwMDAzNDAyMDAxNDUwZDAxMjAwMTQxMDE2YjIxMDEyMDAwMzEwMDAwMjAwMjQyMDg4Njg0MjEwMjIwMDA0MTAxNmEyMTAwMGMwMDBiMDAwYjIwMDIwYmZkMDEwMTA2N2YyMzAwNDEzMDZiMjIwMTI0MDAyMDAwMTBhNzAxMjEwMjEwNDMyMTA0MjAwMjEwMTIyMTAwMjAwMTQxMTg2YTQxMDAzYTAwMDAyMDAxNDExNDZhMjAwMDM2MDIwMDIwMDEyMDAyMzYwMjEwMjAwMTIwMDAzNjAyMGMyMDAxNDEwMDM2MDIwODAzN2YyMDAwMjAwMzQ2MDQ3ZjIwMDEyZDAwMTgwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAxNDEzMDZhMjQwMDIwMDQwNTIwMDE0MTA4NmEyMjAyMTBhZDAxMjEwMzIwMDIxMGFlMDEyMTA1MjAwMjEwYWYwMTIxMDY0MTAwMjEwMDIwMDE0MTAwM2EwMDJmMjAwMjIwMDE0MTJmNmE0MTAxMTBiMzAxMDI0MDAyNDAwMjQwMjAwMTJkMDAyZjBlMDIwMjAxMDAwYjQxZWQ4NjA4NDEwZDEwODgwMTAwMGI0MTAxMjEwMDBiMjAwMTIwMDAzYTAwMjgyMDAxMjAwNjM2MDIyNDIwMDEyMDA1MzYwMjIwMjAwMTIwMDMzNjAyMWMyMDA0MjAwMTQxMWM2YTEwNTUyMDAxMjgwMjA4MjEwMzIwMDEyODAyMGMyMTAwMGMwMTBiMGIwYjJkMDAyMDAwNDEwODZhMjAwMDI4MDIwMDIwMDEyMDAyMTA5ZTAxMDQ0MDQxYTM4NTA4NDEwZjEwODgwMTAwMGIyMDAwMjAwMDI4MDIwMDIwMDI2YTM2MDIwMDBiODcwMTAxMDE3ZjIzMDA0MTMwNmIyMjAyMjQwMDIwMDIyMDAxMzYwMjA4MjAwMjEwMzUyMDAyMjAwMjJkMDAwNDNhMDAxMDIwMDIyMDAyMjgwMjAwMzYwMjBjMjAwMjIwMDExMDEyMzYwMjFjMjAwMjQxMDAzNjAyMTgyMDAyMjAwMjQxMDg2YTM2MDIxNDAzNDAyMDAyNDEyMDZhMjAwMjQxMTQ2YTEwYjUwMTIwMDIyZDAwMmM0MTAyNDY0NTA0NDAyMDAyNDEyMDZhMjAwMjQxMGM2YTEwYjYwMTBjMDEwYjBiMjAwMDIwMDIyODAyMGMyMDAyMmQwMDEwMTBiNzAxMjAwMjQxMzA2YTI0MDAwYmM1MDMwMTA3N2YyMzAwNDFkMDAwNmIyMjAyMjQwMDAyNDAyMDAxMjgwMjA0MjIwNDQxMGQ2YTIyMDgyMDAxMjgwMjA4NGQwNDQwMjAwMTI4MDIwMDIwMDI0MjAwMzcwMDM1MjAwMjQyMDAzNzAzMzAyODAyMDAyMDA0MjAwMjQxMzA2YTIyMDM0MTBkMTA2ZjFhMjAwMjQxMDAzNjAyNDAyMDAyNDEyODZhMjAwMzQxMDA0MTA0MTBiZjAxMjAwMjQxNDA2YjIyMDU0MTA0MjAwMjI4MDIyODIwMDIyODAyMmMxMDU3MjAwMjI4MDI0MDIxMDQyMDAyNDFjODAwNmE0MTAwM2EwMDAwMjAwMjQyMDAzNzAzNDAyMDAyNDEyMDZhMjAwMzQxMDQ0MTBkMTBiZjAxMjAwNTQxMDkyMDAyMjgwMjIwMjAwMjI4MDIyNDEwNTcyMDAyNDEwMDM2MDI0YzIwMDI0MTE4NmEyMDA1NDEwMDQxMDQxMGMwMDEyMDAyNDFjYzAwNmEyMjA3NDEwNDIwMDIyODAyMTgyMDAyMjgwMjFjMTA1NzIwMDIyODAyNGMyMTAzMjAwMjQxMDAzNjAyNGMyMDAyNDExMDZhMjAwNTQxMDQ0MTA4MTBjMDAxMjAwNzQxMDQyMDAyMjgwMjEwMjAwMjI4MDIxNDEwNTcyMDAyMjgwMjRjMjEwNjIwMDI0MTAwM2EwMDRjMjAwMjQxMDg2YTIwMDU0MTA4NDEwOTEwYzAwMTIwMDc0MTAxMjAwMjI4MDIwODIwMDIyODAyMGMxMDU3MjAwMDIwMDIyZDAwNGM0MTAwNDczYTAwMGMyMDAwMjAwNjQxMTg3NDIwMDY0MTgwZmUwMzcxNDEwODc0NzIyMDA2NDEwODc2NDE4MGZlMDM3MTIwMDY0MTE4NzY3MjcyMzYwMjA4MjAwMDIwMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwNDIwMDAyMDA0NDExODc0MjAwNDQxODBmZTAzNzE0MTA4NzQ3MjIwMDQ0MTA4NzY0MTgwZmUwMzcxMjAwNDQxMTg3NjcyNzIzNjAyMDAyMDAxMjAwODM2MDIwNDBjMDEwYjIwMDA0MTAyM2EwMDBjMGIyMDAyNDFkMDAwNmEyNDAwMGI0ZDAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDAyODAyMDAyMDAxMTBiYzAxMjAwMTIwMDAyODAyMDQxMGJkMDEyMDAwNDEwODZhMjgwMjAwMjAwMTEwM2UyMDAyMjAwMDQxMGM2YTJkMDAwMDNhMDAwZjIwMDEyMDAyNDEwZjZhNDEwMTEwYTMwMTIwMDI0MTEwNmEyNDAwMGIwZDAwMjAwMDIwMDEyMDAyMTAzODEwMjExYTBiMGQwMDIwMDAyMDAxMjAwMjEwNGQxMDIxMWEwYjg3MDEwMTAxN2YyMzAwNDEzMDZiMjIwMjI0MDAyMDAyMjAwMTM2MDIwODIwMDIxMDM1MjAwMjIwMDIyZDAwMDQzYTAwMTAyMDAyMjAwMjI4MDIwMDM2MDIwYzIwMDIyMDAxMTAxMjM2MDIxYzIwMDI0MTAwMzYwMjE4MjAwMjIwMDI0MTA4NmEzNjAyMTQyMDAyNDEyNDZhMjEwMTAzNDAyMDAyNDEyMDZhMjAwMjQxMTQ2YTEwYmEwMTIwMDIyODAyMjAwNDQwMjAwMTIwMDI0MTBjNmExMGJiMDEwYzAxMGIwYjIwMDAyMDAyMjgwMjBjMjAwMjJkMDAxMDEwYjcwMTIwMDI0MTMwNmEyNDAwMGI4OTAzMDEwNjdmMjMwMDQxNDA2YTIyMDIyNDAwMjAwMDIwMDEyODAyMDQyMjAzNDEwYzZhMjIwNjIwMDEyODAyMDg0ZDA0N2YyMDAxMjgwMjAwMjAwMjQxMjg2YTQxMDAzNjAyMDAyMDAyNDIwMDM3MDMyMDI4MDIwMDIwMDMyMDAyNDEyMDZhMjIwMzQxMGMxMDZmMWEyMDAyNDEwMDM2MDIzMDIwMDI0MTE4NmEyMDAzNDEwMDQxMDQxMGMxMDEyMDAyNDEzMDZhMjIwNTQxMDQyMDAyMjgwMjE4MjAwMjI4MDIxYzEwNTcyMDAyMjgwMjMwMjEwNDIwMDI0MjAwMzcwMzMwMjAwMjQxMTA2YTIwMDM0MTA0NDEwYzEwYzEwMTIwMDU0MTA4MjAwMjI4MDIxMDIwMDIyODAyMTQxMDU3MjAwMjQxMDAzNjAyM2MyMDAyNDEwODZhMjAwNTQxMDA0MTA0MTBjMjAxMjAwMjQxM2M2YTIyMDc0MTA0MjAwMjI4MDIwODIwMDIyODAyMGMxMDU3MjAwMjI4MDIzYzIxMDMyMDAyNDEwMDM2MDIzYzIwMDIyMDA1NDEwNDQxMDgxMGMyMDEyMDA3NDEwNDIwMDIyODAyMDAyMDAyMjgwMjA0MTA1NzIwMDIyODAyM2MyMTA1MjAwMDQxMGM2YTIwMDQ0MTE4NzQyMDA0NDE4MGZlMDM3MTQxMDg3NDcyMjAwNDQxMDg3NjQxODBmZTAzNzEyMDA0NDExODc2NzI3MjM2MDIwMDIwMDAyMDAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIzNjAyMDQyMDAxMjAwNjM2MDIwNDIwMDA0MTA4NmEyMDA1NDExODc0MjAwNTQxODBmZTAzNzE0MTA4NzQ3MjIwMDU0MTA4NzY0MTgwZmUwMzcxMjAwNTQxMTg3NjcyNzIzNjAyMDA0MTAxMDU0MTAwMGIzNjAyMDAyMDAyNDE0MDZiMjQwMDBiMWYwMDIwMDAyODAyMDgyMDAxMTBiYzAxMjAwMTIwMDAyODAyMDAxMGJkMDEyMDAwMjgwMjA0MjAwMTEwM2UwYjQ2MDEwMTdmMjMwMDQxMTA2YjIyMDIyNDAwMjAwMjIwMDA0MTE4NzQyMDAwNDE4MGZlMDM3MTQxMDg3NDcyMjAwMDQxMDg3NjQxODBmZTAzNzEyMDAwNDExODc2NzI3MjM2MDIwYzIwMDEyMDAyNDEwYzZhNDEwNDEwYTMwMTIwMDI0MTEwNmEyNDAwMGI4MTAxMDEwMzdmMjMwMDQxMTA2YjIyMDIyNDAwMDI0MDAyNDAyMDAwMmQwMDA0MDQ0MDIwMDExMDEyMjIwNDQxOTBjZTAwNDFkY2RiMDgyODAyMDAyMjAzNmI0YjBkMDEyMDAyNDEwODZhMjAwMzIwMDMyMDA0NmEyMjAwMTBhNDAxMjAwMTQxMDAyMDAyMjgwMjA4MjAwMjI4MDIwYzEwNmYxYTQxZGNkYjA4MjAwMDM2MDIwMDBjMDIwYjIwMDAyODAyMDAyMDAxMTA4YjAxMGMwMTBiMjAwMDEwYTUwMTIwMDAyODAyMDAyMDAxMTA4YjAxMGIyMDAyNDExMDZhMjQwMDBiMzgwMjAxN2YwMTdlMjMwMDQxMTA2YjIyMDEyNDAwMjAwMTQyMDAzNzAzMDgyMDAwMjAwMTQxMDg2YTIyMDA0MTA4NDE4YTg1MDg0MTBiMTBjNTAxMjAwMDQxMDgxMGIxMDEyMDAxNDExMDZhMjQwMDBiMGYwMDIwMDAyMDAxMjAwMjIwMDM0MTBkMTBmODAxMGIwZjAwMjAwMDIwMDEyMDAyMjAwMzQxMDkxMGY4MDEwYjBmMDAyMDAwMjAwMTIwMDIyMDAzNDEwYzEwZjgwMTBiMGYwMDIwMDAyMDAxMjAwMjIwMDM0MTA4MTBmODAxMGI4MDAyMDEwNTdmMjMwMDQxMjA2YjIyMDIyNDAwMjAwMDIwMDEyODAyMDQyMjAzNDEwODZhMjIwNTIwMDEyODAyMDg0ZDA0N2YyMDAxMjgwMjAwMjAwMjQyMDAzNzAzMTAyODAyMDAyMDAzMjAwMjQxMTA2YTIyMDM0MTA4MTA2ZjFhMjAwMjQxMDAzNjAyMWMyMDAyNDEwODZhMjAwMzQxMDA0MTA0MTBjMjAxMjAwMjQxMWM2YTIyMDY0MTA0MjAwMjI4MDIwODIwMDIyODAyMGMxMDU3MjAwMjI4MDIxYzIxMDQyMDAyNDEwMDM2MDIxYzIwMDIyMDAzNDEwNDQxMDgxMGMyMDEyMDA2NDEwNDIwMDIyODAyMDAyMDAyMjgwMjA0MTA1NzIwMDIyODAyMWMyMTAzMjAwMDIwMDQ0MTE4NzQyMDA0NDE4MGZlMDM3MTQxMDg3NDcyMjAwNDQxMDg3NjQxODBmZTAzNzEyMDA0NDExODc2NzI3MjM2MDIwNDIwMDEyMDA1MzYwMjA0MjAwMDQxMDg2YTIwMDM0MTE4NzQyMDAzNDE4MGZlMDM3MTQxMDg3NDcyMjAwMzQxMDg3NjQxODBmZTAzNzEyMDAzNDExODc2NzI3MjM2MDIwMDQxMDEwNTQxMDAwYjM2MDIwMDIwMDI0MTIwNmEyNDAwMGI4YTAxMDEwNDdmMjMwMDQxMTA2YjIyMDMyNDAwMjAwMTI4MDIwNDIyMDI0MTA0NmEyMjA0MjAwMTI4MDIwODRiMDQ3ZjQxMDAwNTIwMDEyODAyMDAyMDAzNDEwMDM2MDIwYzI4MDIwMDIwMDIyMDAzNDEwYzZhNDEwNDEwNmYxYTIwMDMyODAyMGMyMTAyMjAwMTIwMDQzNjAyMDQyMDAyNDExODc0MjAwMjQxODBmZTAzNzE0MTA4NzQ3MjIwMDI0MTA4NzY0MTgwZmUwMzcxMjAwMjQxMTg3NjcyNzIyMTAyNDEwMTBiMjEwMTIwMDAyMDAyMzYwMjA0MjAwMDIwMDEzNjAyMDAyMDAzNDExMDZhMjQwMDBiMzAwMDIwMDA0MTA4NmEyMDAwMjgwMjAwMjAwMTIwMDIxMDllMDEwNDQwMjAwMzIwMDQ0MWEzODUwODQxMGYxMDRjMDAwYjIwMDAyMDAwMjgwMjAwMjAwMjZhMzYwMjAwMGI3ODAxMDE3ZjIzMDA0MTEwNmIyMjAyMjQwMDIwMDIyMDAwNDIzODg2MjAwMDQyODBmZTAzODM0MjI4ODY4NDIwMDA0MjgwODBmYzA3ODM0MjE4ODYyMDAwNDI4MDgwODBmODBmODM0MjA4ODY4NDg0MjAwMDQyMDg4ODQyODA4MDgwZjgwZjgzMjAwMDQyMTg4ODQyODA4MGZjMDc4Mzg0MjAwMDQyMjg4ODQyODBmZTAzODMyMDAwNDIzODg4ODQ4NDg0MzcwMzA4MjAwMTIwMDI0MTA4NmE0MTA4MTBhMzAxMjAwMjQxMTA2YTI0MDAwYmQ2MDEwMTA2N2YyMzAwNDE0MDZhMjIwMDI0MDAxMGM4MDExMDVjMjEwMTIwMDAxMGM5MDExMDVjMzYwMjA4MjAwMDEwNDczNjAyMGMyMDAwNDEyODZhMjIwMjIwMDExMDMyNDFmNzgwMDg0MTEwMTAzMzIwMDAyODAyMmMyMjAxMjAwMDQxMDg2YTEwNjQyMDAxMjAwMDQxMGM2YTEwNjQyMDAwNDEyMDZhMjIwMTIwMDA0MTM4NmEyMjAzMjkwMzAwMzcwMzAwMjAwMDQxMTg2YTIyMDQyMDAwNDEzMDZhMjIwNTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzI4MzcwMzEwMjAwMDIwMDA0MTEwNmExMDdjMzYwMjA0MjAwMjEwYzkwMTEwNWMxMDMyNDFmNTgxMDg0MTE4MTAzMzIwMDAyODAyMmMyMDAwNDEwNDZhMTA3ODIwMDEyMDAzMjkwMzAwMzcwMzAwMjAwNDIwMDUyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDMyODM3MDMxMDIwMDA0MTEwNmExMDdjMjAwMDQxNDA2YjI0MDAwYjBhMDA0MTk1ODgwODQxMTIxMDRkMGIwYTAwNDE4MTg4MDg0MTE0MTA0ZDBiYTkwMzAyMDU3ZjAxN2UyMzAwNDE4MDAxNmIyMjAyMjQwMDEwY2IwMTEwYWIwMTIxMDMyMDAxMjgwMjBjMjEwNDIwMDEyOTAzMDAyMTA3MjAwMTI4MDIwODIxMDEwMjQwMjAwMzQxZmVmZmZmZmYwNzQ2MDQ0MDIwMDE0MWZlZmZmZmZmMDc0NjBkMDEyMDAxMTBhMTAxMjEwMTIwMDIyMDA0MzYwMjE0MjAwMjIwMDczNzAzMDgyMDAyMjAwMTM2MDIxMDEwY2MwMTEwNWMyMTAzMjAwNDEwMjkyMTA0MjAwMjQxZTAwMDZhMjIwMTIwMDMxMDMyNDFhMTgwMDg0MTBhMTAzMzIwMDI0MTQwNmIyMjAzMjAwMTIwMDI0MTA4NmExMDg0MDEyMDAxMjAwMzEwY2QwMTIwMDExMDM0NDIwMDIxMDc0MWZlZmZmZmZmMDcyMTAxMGIyMDAyNDFlMDAwNmEyMDAwMTAzMjQxYzA4MTA4NDExMjEwMzMyMDAyMjgwMjY0MWEyMDAyNDEyODZhMjIwMDIwMDI0MWYwMDA2YTIyMDUyOTAzMDAzNzAzMDAyMDAyNDEyMDZhMjIwMzIwMDI0MWU4MDA2YTIyMDYyOTAzMDAzNzAzMDAyMDAyMjAwMjI5MDM2MDM3MDMxODAyNDAyMDAxNDFmZWZmZmZmZjA3NDcwNDQwMjAwNTIwMDAyOTAzMDAzNzAzMDAyMDA2MjAwMzI5MDMwMDM3MDMwMDIwMDIyMDAyMjkwMzE4MzcwMzYwMjAwMjEwN2QzNjAyNzgyMDAxMTBhMTAxMjEwMDIwMDIyMDA0MzYwMjNjMjAwMjIwMDczNzAzMzAyMDAyMjAwMDM2MDIzODIwMDI0MTQwNmIyMDAyNDFlMDAwNmEyMDAyNDEzMDZhMTA4MzAxMGMwMTBiMjAwMjQxZDAwMDZhMjAwMDI5MDMwMDM3MDMwMDIwMDI0MWM4MDA2YTIwMDMyOTAzMDAzNzAzMDAyMDAyMjAwMjI5MDMxODM3MDM0MDIwMDIyMDA0MzYwMjU4MGIyMDAyNDFlMDAwNmEyMDAyNDE0MDZiMTA3NjIwMDI0MTgwMDE2YTI0MDAwZjBiNDFjYTg4MDg0MTFmMTA0MTAwMGIwYTAwNDFlODhjMDg0MTIyMTA0ZDBiMGEwMDQxZmE4NjA4NDExZDEwNGQwYmZmMDIwMjAzN2YwMjdlMjMwMDQxZDAwMDZiMjIwMjI0MDAyMDAyNDEzMDZhMjIwNDIwMDE0MTEwNmEyOTAzMDAzNzAzMDAyMDAyNDEyODZhMjIwMzIwMDE0MTA4NmEyOTAzMDAzNzAzMDAyMDAyMjAwMTI5MDMwMDM3MDMyMDIwMDIxMDdkMzYwMjM4MDI0MDAyNDAwMjQwMDI0MDIwMDEyODAyMTgyMjAxMTA2NTBlMDIwMTAyMDAwYjEwNDcyMTAzMjAwMjQxMDg2YTIwMDIyODAyMjAyMDAyMjgwMjI0MjAwNDIwMDExMDYyMjAwMjI5MDMwODIxMDUyMDAyMjkwMzI4MjEwNjIwMDAxMDdkMzYwMjE4MjAwMDIwMDMzNjAyMTAyMDAwMjAwNjM3MDMwODIwMDAyMDA1MzcwMzAwMGMwMjBiMjAwMDIwMDIyOTAzMjAzNzAzMDAyMDAwNDExODZhMjAwMjQxMzg2YTI5MDMwMDM3MDMwMDIwMDA0MTEwNmEyMDA0MjkwMzAwMzcwMzAwMjAwMDQxMDg2YTIwMDMyOTAzMDAzNzAzMDAwYzAxMGIyMDAyNDE0MDZiMjAwMTEwOTcwMTAyN2YyMDAyMjkwMzQwNTAwNDQwMjAwMjI4MDIzMDIxMDEyMDAyNDExMDZhMjAwMjI4MDIyMDIwMDIyODAyMjQyMDAyMjgwMjQ4MjAwMjI4MDI0YzEwNmQyMDAyMjgwMjEwMjEwMzIwMDIyODAyMTQwYzAxMGIxMDQ3MjEwMTIwMDI0MTE4NmEyMDAyMjgwMjIwMjAwMjI4MDIyNDIwMDIyODAyMzAyMDAyNDE0MDZiMTA2YzIwMDIyODAyMTgyMTAzMjAwMjI4MDIxYzBiMjEwNDIwMDIyOTAzMjgyMTA1MjAwMDEwN2QzNjAyMTgyMDAwMjAwMTM2MDIxMDIwMDAyMDA1MzcwMzA4MjAwMDIwMDQzNjAyMDQyMDAwMjAwMzM2MDIwMDBiMjAwMjQxZDAwMDZhMjQwMDBiMGQwMDIwMDAxMDYxNDFmZjAxNzE0MTAxNGIwYjE3MDAyMDAwMjgwMjAwMjAwMTI4MDIwMDEwODkwMTQxZmYwMTcxNDFmZjAxNDYwYjNiMDEwMTdmMjMwMDQxMTA2YjIyMDQyNDAwMjAwNDQxMDg2YTQxMDAyMDAzMjAwMTIwMDIxMDJiMjAwNDI4MDIwYzIxMDEyMDAwMjAwNDI4MDIwODM2MDIwMDIwMDAyMDAxMzYwMjA0MjAwNDQxMTA2YTI0MDAwYjBhMDA0MWJkODgwODQxMGQxMDRkMGIwYTAwNDFmMjg3MDg0MTBmMTA0ZDBiMGEwMDQxZGQ4NzA4NDExNTEwNGQwYjBhMDA0MWE3ODgwODQxMTYxMDRkMGIxOTAxMDE3ZjQxOTc4NzA4NDExNjEwNGQyMTAxMjAwMDI4MDIwMDIwMDExMDQwMjAwMTBiMTkwMTAxN2Y0MWFkODcwODQxMTgxMDRkMjEwMTIwMDAyODAyMDAyMDAxMTA0MDIwMDEwYjBhMDA0MWM1ODcwODQxMTgxMDRkMGIwYTAwNDE4ZjhjMDg0MTFkMTA0ZDBiMGEwMDQxYWM4YzA4NDExZDEwNGQwYjBhMDA0MWM5OGMwODQxMWYxMDRkMGJhNzA1MDIwZDdmMDI3ZTIzMDA0MTQwNmEyMjAwMjQwMDEwMjI0MTBhMTA1YTQxMDA0MWJkODgwODQxMGQxMDUwMjEwOTQxMDExMDRiMjEwMjQxMDI0MTk1ODgwODQxMTIxMDUwMjEwYTQxMDM0MTgxODgwODQxMTQxMDUwMjEwNTQxMDQ0MWYyODcwODQxMGYxMDUwMjEwNjQxMDUxMDExMjEwZDQxMDYxMDExMjEwZTQxMDcxMDU4MjEwNzQxMDgxMDUxMjEwODQxMDk0MWZhODYwODQxMWQxMDUwMjEwNDIwMDAyMDA4MzYwMjEwMjAwMDIwMDczNjAyMGMyMDA1MTAyZjEwMzIyMTAxNDFlNjgxMDg0MTBmMTA0ZDIxMDMxMDQzMjEwYjEwN2QyMTBjMTAxNjIwMDEyMDBjMjAwMzIwMGIxMDQ1MjEwMTEwMTcyMDAxMTAxMjIxMDMyMDAwNDEwMDM2MDIzMDIwMDAyMDAxMzYwMjI4MjAwMDIwMDM0MTAyNzYzNjAyMmMyMDAwNDEyODZhMjIwMzEwNzUxMDJmMTBhMjAxMjEwMTIwMDMyMDA0MTAyZjEwMmYxMDMyNDFhYjgwMDg0MTE1MTAzMzIwMDMxMDgwMDEyMTAzMDI0MDAyNDAyMDAxNDFmZWZmZmZmZjA3NDcwNDQwMjAwMTEwMmYxMGExMDEyMDAyMTAzMDBkMDE0MWU5ODgwODQxZDEwMDEwNDEwMDBiMjAwMjIwMDMxMDMwNDUwZDAxMGIxMGNjMDEyMDA0MTBhODAxMTBkOTAxMjAwMzEwYTgwMTAyNDAxMGNiMDEyMjA0MTBhNjAxMGQwMDIwMDE0MWZlZmZmZmZmMDc0NzA0NDAyMDA0MjAwMTEwMjExYTBjMDEwYjIwMDQ0MWVkODUwODQxMDQxMGI4MDEwYjEwZDEwMTIwMDkxMGE4MDExMGQ0MDEyMDAyMTBhODAxMTBjODAxMjAwYTEwYTgwMTEwYzkwMTIwMDUxMDJmMTBhODAxMTBkODAxMjAwMDQxMjg2YTIyMDEyMDA1MTAzMjQxYjY4MTA4NDEwYTEwMzMyMDAxMTA4MDAxMTBhODAxMTBkMjAxMjAwNjEwMmYxMGE4MDExMGRhMDEyMDAxMjAwNjEwMzI0MTg2ODMwODQxMGYxMDMzMjAwMTEwODAwMTEwYTgwMTIwMDAyMDA3MTAxMjM2MDIxYzIwMDA0MTAwMzYwMjE4MjAwMDIwMDA0MTBjNmEzNjAyMTQwMzQwMDI0MDIwMDA0MTI4NmEyMDAwNDExNDZhMTBjMzAxMjAwMDI4MDIyODQ1MDQ0MDIwMDAyMDA4MTAxMjM2MDIxYzIwMDA0MTAwMzYwMjE4MjAwMDIwMDA0MTEwNmEzNjAyMTQwMzQwMjAwMDQxMjg2YTIwMDA0MTE0NmExMGMzMDEyMDAwMjgwMjI4NDUwZDAyMjAwMDIwMDAyODAyMzAyMjAxMzYwMjI0MjAwMDIwMDAyODAyMmMzNjAyMjAyMDAwNDEyMDZhMTBkNTAxMjIwMjEwYTYwMTBkMDAyMDAyMjAwMTEwYjQwMTBjMDAwYjAwMGIyMDAwMjAwMDI4MDIzMDIyMDEzNjAyMjQyMDAwMjAwMDI4MDIyYzM2MDIyMDIwMDA0MTIwNmExMGQ2MDEyMjAyMTBhNjAxMGQwMTIwMDIyMDAxMTBiOTAxMGMwMTBiMGIxMGQzMDEyMDBkMTBhOTAxMTBkNzAxMjAwZTEwYTkwMTIwMDA0MTQwNmIyNDAwMGYwYjQxYmE4OTA4NDFjODAwMTA0MTAwMGIwODAwMTAyMjQxMDAxMDVhMGJjNzAxMDEwNTdmMjMwMDQxMzA2YjIyMDAyNDAwNDEwMDEwNWEwMjQwMDI0MDEwNDYxMGQxMDExMDVjMTAzMDA0NDAxMDQ2MTBkMTAxMTA1YzEwMzA0NTBkMDEyMDAwMTA0YTIyMDEzNjAyMDgxMGQ0MDExMGE3MDEyMTAyMTBjOTAxMTA1YzIxMDMyMDAwMjAwMTEwMTIzNjAyMTQyMDAwNDEwMDM2MDIxMDIwMDAyMDAwNDEwODZhMzYwMjBjMjAwMDQxMjA2YTIxMDEwMzQwMDI0MDIwMDA0MTE4NmEyMDAwNDEwYzZhMTA2NzIwMDAyOTAzMTg1MDBkMDAyMDAwMjgwMjJjMjAwMDI4MDIyODIwMDIxMDMwNDUwZDA0MTBjZTAxNDUwZDA0MjAwMzEwMmYyMDAxMTBjYTAxMGMwMTBiMGIyMDAwNDEzMDZhMjQwMDBmMGI0MTgyOGEwODQxMTYxMDQxMDAwYjQxODI4YTA4NDExNjEwNDEwMDBiNDE5ODhhMDg0MTBkMTA0MTAwMGJjNzA3MDIwOTdmMDE3ZTIzMDA0MTgwMDE2YjIyMDAyNDAwMTAyMjQxMDExMDVhMjAwMDEwNGYzNjAyMmMxMGQxMDExMDVjMjEwMTAyNDAwMjQwMDI0MDEwNDYyMjA3MjAwMTEwMzAwNDQwMjAwMDEwYzkwMTEwNWMyMjAxMzYwMjM0MjAwMDQxZTAwMDZhMjIwMjIwMDExMDJmMTAzMjQxOGQ4MjA4NDExODEwMzMyMDAwMjgwMjY0MjAwMDQxMmM2YTEwNzgyMDAwNDFkODAwNmEyMjAxMjAwMDQxZjAwMDZhMjIwNjI5MDMwMDM3MDMwMDIwMDA0MWQwMDA2YTIyMDMyMDAwNDFlODAwNmEyMjA0MjkwMzAwMzcwMzAwMjAwMDIwMDAyOTAzNjAzNzAzNDgyMDAwNDFjODAwNmEyMjA1MTA3YzIxMDgyMDAyMTBjODAxMTA1YzEwMzI0MWUxODAwODQxMGExMDMzMjAwMDI4MDI2NDIyMDIyMDAwNDEzNDZhMTA2NDIwMDI0MTAwMjAwODEwNzkyMDAxMjAwNjI5MDMwMDM3MDMwMDIwMDMyMDA0MjkwMzAwMzcwMzAwMjAwMDIwMDAyOTAzNjAzNzAzNDgyMDAwNDEzODZhMjAwNTEwN2UyMDAwMjgwMjQ0MTBjZTAxNDUwZDAxMjAwMDI4MDIzNDEwMzIyMTAxNDFhNTgyMDg0MTA2MTA0ZDIxMDQxMDQzMjIwMzQxMDEyMDAwMTA3OTEwNDMyMjAyMjAwMDQxMzg2YTEwNDQyMDAwMjAwMTM2MDI3MDIwMDA0MjdmMzcwMzY4MjAwMDIwMDMzNjAyNjQyMDAwMjAwNDM2MDI2MDIwMDAxMDdkMjIwNTM2MDI3ODAyNDAwMjQwMDI0MDAyNDAyMDAyMTA2NTBlMDIwMjAwMDEwYjIwMDA0MWM4MDA2YTIwMDIxMDk3MDEwMjdmMjAwMDI5MDM0ODUwMDQ0MDIwMDA0MTE4NmEyMDA0MjAwMzIwMDAyODAyNTAyMDAwMjgwMjU0MTA2ZDIwMDAyODAyMTgyMTA0MjAwMDI4MDIxYzBjMDEwYjEwNDcyMDAwNDEyMDZhMjAwNDIwMDMyMDAxMjAwMDQxYzgwMDZhMTA2YzIwMDAyODAyMjAyMTA0MjEwMTIwMDAyODAyMjQwYjIxMDMxMDdkMjEwNTBjMDEwYjEwNDcyMTAxMjAwMDQxMTA2YTIwMDQyMDAzMjAwNjIwMDIxMDYyMjAwMDI5MDM2ODIxMDkyMDAwMjgwMjE0MjEwMzIwMDAyODAyMTAyMTA0MTA3ZDIxMDUyMDA5NDI3ZjUyMGQwMTBiMTAxNjIxMDkwYjIwMDkyMDAxMjAwNTIwMDQyMDAzMTA0NTIxMDExMDE3MjAwMTEwMTIyMTAyMjAwMDQxMDAzNjAyNTAyMDAwMjAwMTM2MDI0ODIwMDAyMDAyNDEwMjc2MzYwMjRjMjAwMDQxYzgwMDZhMTA3NTIyMDIxMDEyMjEwMTIwMDA0MWYwMDA2YTQxMDAzYTAwMDAyMDAwNDFlYzAwNmEyMDAxMzYwMjAwMjAwMDIwMDIzNjAyNjgyMDAwMjAwMTM2MDI2NDIwMDA0MTAwMzYwMjYwMjAwMDQxZTAwMDZhMjIwMTQxOGE4NTA4NDEwYjEwM2ExMGEyMDEyMTAyMjAwMTEwYmUwMTIxMDkyMDAxMTAzOTIxMDEyMDAwMjgwMjY0MjAwMDI4MDI2MDQ3MGQwMjIwMDAyZDAwNzAwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIwMjQwMjAwMjQxZmVmZmZmZmYwNzQ3MDQ0MDIwMDIxMGExMDEyMTAzMGMwMTBiMTBkOTAxMTBhNzAxMjEwMzEwY2MwMTEwNWMyMDAxMTAyOTEwMzE0MjAwMjEwOTBiMjAwMTEwY2UwMTQ1MGQwMzIwMDcyMDAzMjAwOTIwMDExMDQyMjAwMDIwMDEzNjAyNmMyMDAwMjAwMzM2MDI2ODIwMDAyMDA5MzcwMzYwMjAwMDIwMDA0MWUwMDA2YTEwOTUwMTIyMDEzNjAyMzAyMDAwNDEwODZhMTAzNTIwMDAyMDAwMmQwMDBjM2EwMDNjMjAwMDIwMDAyODAyMDgzNjAyMzgyMDAwMjAwMTEwMTIzNjAyNTAyMDAwNDEwMDM2MDI0YzIwMDAyMDAwNDEzMDZhMzYwMjQ4MDM0MDIwMDA0MWUwMDA2YTIwMDA0MWM4MDA2YTEwNjcyMDAwMjkwMzYwNTA0NTA0NDAyMDAwMjgwMjc0MjAwMDI4MDI3MDIwMDA0MTM4NmEyMjAxMTAzZTIwMDAyOTAzNjgyMDAxMTBjNjAxMjAwMTEwM2MwYzAxMGIwYjIwMDAyODAyMzgyMDAwMmQwMDNjMTAzNzIwMDA0MTgwMDE2YTI0MDAwZjBiNDE4MjhhMDg0MTE2MTA0MTAwMGI0MWU3OGEwODQxMWYxMDQxMDAwYjQxOGE4NTA4NDEwYjQxOTU4NTA4NDEwZTEwNGMwMDBiNDE4NjhiMDg0MTFhMTA0MTAwMGJmMzFkMDIxNjdmMDI3ZTIzMDA0MWEwMDI2YjIyMDAyNDAwMTAyMjQxMDAxMDVhMTBjODAxMTA1YzIxMDEyMDAwMTBjOTAxMTA1YzIyMTQxMDJmMTA5NjAxMzYwMmYwMDEyMDAwMTA0MzM2MDJhMDAxMjAwMDQxODAwMjZhMjIwOTIwMDExMDMyNDFlYjgwMDg0MTBjMTAzMzIwMDAyODAyODQwMjIyMDE0MTAwMTA4MTAxMjAwMTQxMDExMDgxMDEyMDAxNDEwMDEwODEwMTIwMDEyMDAwNDFmMDAxNmEyMjExMTA3YjIwMDEyMDAwNDFhMDAxNmEyMjA3MTA3YjIwMDA0MWUwMDE2YTIyMDUyMDAwNDE5MDAyNmEyMjA0MjkwMzAwMzcwMzAwMjAwMDQxZDgwMTZhMjIwMjIwMDA0MTg4MDI2YTIyMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDEyMDAwNDFkMDAxNmEyMjA2MTA3ZjEwZDIwMTEwNWMyMTAxMjAwMDIwMTQxMDJmMTA5NjAxMzYwMmYwMDEyMDAwMTA0MzM2MDJhMDAxMjAwOTIwMDExMDMyNDFlYjgwMDg0MTBjMTAzMzIwMDAyODAyODQwMjIyMDE0MTAwMTA4MTAxMjAwMTIwMTExMDdiMjAwMTIwMDcxMDdiMjAwMTQxMDEyMDAwMTA3OTIwMDUyMDA0MjkwMzAwMzcwMzAwMjAwMjIwMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDEyMDA2MTA3ZjEwMmEyMjAzMTAyYTIyMDYxMDIzMjAwNjEwY2UwMTA0NDAxMGNjMDExMDVjMjAwNjEwMjkxMDMxMTBkOTAxMTBhNzAxMjEwMTIwMDAyMDA2MzYwMjhjMDIyMDAwNDIwMDM3MDM4MDAyMjAwMDIwMDEzNjAyODgwMjIwMDMyMDAwNDE4MDAyNmExMDQ0MGIyMDAwMjAwMzM2MDI5MDAxMDI0MDAyNDAwMjQwMjAwMzEwNjUwNDQwMTBkNDAxMTBhNzAxMjEwZTEwN2QyMTBkMjAwMDIwMDAyODAyOTAwMTEwMTIzNjAyOWMwMTIwMDA0MTAwMzYwMjk4MDEyMDAwMjAwMDQxOTAwMTZhMzYwMjk0MDEyMDAwNDE5MDAyNmEyMTBhMjAwMDQxYzAwMTZhMjEwZjIwMDA0MWE4MDE2YTIxMTUwMzQwMjAwMDQxYTAwMTZhMjAwMDQxOTQwMTZhMTA2NzIwMDAyOTAzYTAwMTUwMDQ0MDQyODA4MDkwYmJiYWQ2YWRmMDBkMTAyZTIxMDEyMDBkMTBkMzAxMTA1ZjEwMmUxMDkyMDEyMDAxMTA4ZDAxMjIwNTIwMGQxMGQ3MDExMDVmMTAyZTEwOTIwMTIwMDExMDhkMDEyMjA2MTA5MTAxMjAwZDEwODkwMTQxZmYwMTcxNDEwMjQ5MGQwNTIwMGQyMDA1MTA5MzAxMjAwNjEwOTAwMTIxMDIyMDBlMTAyZjIxMDEyMDAwMjAwMjEwMjkzNjAyOGMwMjIwMDA0MjAwMzcwMzgwMDIyMDAwMjAwMTM2MDI4ODAyMjAxNDIwMDA0MTgwMDI2YTEwY2EwMTIwMGUxMDJmMjEwMTIwMDUxMGNlMDEwNDQwMTA0NjIwMDE0MjAwMjAwNTEwNDIwYjIwMDYxMGNlMDEwNDQwMTA0ODIwMGU0MjAwMjAwNjEwNDIwYjEwNDMyMTA0MTA0MzEwMmYyMTA2MjAwMTQxZmVmZmZmZmYwNzQ2MGQwMzIwMDEyMDA2MTA0MDBjMDQwYjIwMGYyMDE1NDEwODZhMjkwMzAwMzcwMzAwMjAwMDIwMTUyOTAzMDAzNzAzYjgwMTIwMGYxMGQ2MDExMGFjMDEyMTEyMjAwZjEwZDUwMTEwYjIwMTIxMTMyMDBmMjgwMjAwMjEwYzIwMDAyODAyYzQwMTIxMDQyMDAwMjkwM2I4MDEyMTE2MjAxMjEwMTIyMTAxMjAxMzEwMTI0MTBkNmUyMDAxNDEwYzZlNmEyMTExNDEwMDIxMDEwMzQwMDI0MDAyNDAyMDAxMjAxMTQ3MDQ0MDIwMDE0MTAxNmEyMTA2NDEwMDIxMDIyMDEyMTAxMjIxMDUwMjQwMDI0MDAzNDAyMDAyNDEwYzZhMjIwMzIwMDU0YjBkMDEyMDAwNDE4ODAyNmEyMjA5NDEwMDM2MDIwMDIwMDA0MjAwMzcwMzgwMDIyMDEyMjAwMjIwMDA0MTgwMDI2YTIyMDI0MTBjMTA4YTAxMWEyMDAwNDEwMDM2MDJkMDAxMjAwMDQxODgwMTZhMjAwMjQxMDA0MTA0MTBjMTAxMjAwMDQxZDAwMTZhMjIwNzQxMDQyMDAwMjgwMjg4MDEyMDAwMjgwMjhjMDExMDU3MjAwMDI4MDJkMDAxMjEwODIwMDA0MjAwMzcwM2QwMDEyMDAwNDE4MDAxNmEyMDAyNDEwNDQxMGMxMGMxMDEyMDA3NDEwODIwMDAyODAyODAwMTIwMDAyODAyODQwMTEwNTcyMDAwNDEwMDM2MDJmMDAxMjAwMDQxZjgwMDZhMjAwNzQxMDA0MTA0MTBjMjAxMjAwMDQxZjAwMTZhMjIwMjQxMDQyMDAwMjgwMjc4MjAwMDI4MDI3YzEwNTcyMDAwMjgwMmYwMDEyMTBiMjAwMDQxMDAzNjAyZjAwMTIwMDA0MWYwMDA2YTIwMDc0MTA0NDEwODEwYzIwMTIwMDI0MTA0MjAwMDI4MDI3MDIwMDAyODAyNzQxMDU3MjAwMzIxMDIyMDA4NDExODc0MjAwODQxODBmZTAzNzE0MTA4NzQ3MjIwMDg0MTA4NzY0MTgwZmUwMzcxMjAwODQxMTg3NjcyNzIyMDAxNDcwZDAwMGIyMDAwMjgwMmYwMDEyMTAzMjAwYjQxMTg3NDIwMGI0MTgwZmUwMzcxNDEwODc0NzIyMDBiNDEwODc2NDE4MGZlMDM3MTIwMGI0MTE4NzY3MjcyMTAyZjIxMDEyMDAzNDExODc0MjAwMzQxODBmZTAzNzE0MTA4NzQ3MjIwMDM0MTA4NzY0MTgwZmUwMzcxMjAwMzQxMTg3NjcyNzIyMjA3MTAyZjIxMDU0MTAxMTAyZDIwMDA0MTgwMDI2YTIyMDMyMDAxMTAzMjQxZDk4NjA4NDExNDEwMzMyMDAwMjgwMjg0MDIyMjAxMjAwNTEwNmUyMDAxMTA3MDIwMDA0MWUwMDE2YTIyMDIyMDBhMjkwMzAwMzcwMzAwMjAwMDQxZDgwMTZhMjIwMTIwMDkyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDExMDQzMjEwNTIwMDAyMDA0MzYwMjhjMDIyMDAwMjAwYzM2MDI4ODAyMjAwMDIwMTYzNzAzODAwMjIwMDUyMDAzMTA0NDIwMGEyMDAyMjkwMzAwMzcwMzAwMjAwOTIwMDEyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDNkMDAxMzcwMzgwMDIyMDAwMTA3ZDM2MDI5ODAyMDI0MDAyNDAwMjQwMDI0MDIwMDUxMDY1MGUwMjAxMDIwMDBiMTA0NzIxMDEyMDAwNDFlODAwNmEyMDAwMjgwMjgwMDIyMDAwMjgwMjg0MDIyMDBhMjAwNTEwNjIyMDAwMjkwMzY4MjExNzIwMDAyOTAzODgwMjIxMTYyMDAwMTA3ZDM2MDJlODAxMjAwMDIwMDEzNjAyZTAwMTIwMDAyMDE2MzcwM2Q4MDEyMDAwMjAxNzM3MDNkMDAxMGMwMjBiMjAwMDQxZTgwMTZhMjAwMDQxOTgwMjZhMjkwMzAwMzcwMzAwMjAwMjIwMGEyOTAzMDAzNzAzMDAyMDAxMjAwOTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzgwMDIzNzAzZDAwMTBjMDEwYjIwMDA0MWYwMDE2YTIyMDEyMDA1MTA5NzAxMjAwMDQxZDAwMTZhMjAwMDQxODAwMjZhMjAwMTEwODMwMTBiMjAwMDQxODAwMjZhMjAwMDQxZDAwMTZhMTA3NjIwMDAyODAyODgwMjIyMGMyMDA3MTAzMDQ1MGQwMTIwMDAyODAyOGMwMjIxMDQyMDAwMjkwMzgwMDIyMTE2MjAwNjIxMDEwYzA1MGI0MTAwMjEwMjIwMTMxMDEyMjEwNTAzNDAyMDAyNDEwZDZhMjIwMzIwMDU0YjBkMDMyMDAwNDIwMDM3MDA4NTAyMjAwMDQyMDAzNzAzODAwMjIwMTMyMDAyMjAwMDQxODAwMjZhMjIwMjQxMGQxMDhhMDExYTIwMDA0MTAwMzYwMmQwMDEyMDAwNDFlMDAwNmEyMDAyNDEwMDQxMDQxMGJmMDEyMDAwNDFkMDAxNmEyMjA4NDEwNDIwMDAyODAyNjAyMDAwMjgwMjY0MTA1NzIwMDAyODAyZDAwMTIxMDkyMDAwNDFkODAxNmEyMjBiNDEwMDNhMDAwMDIwMDA0MjAwMzcwM2QwMDEyMDAwNDFkODAwNmEyMDAyNDEwNDQxMGQxMGJmMDEyMDA4NDEwOTIwMDAyODAyNTgyMDAwMjgwMjVjMTA1NzIwMDA0MTAwMzYwMmYwMDEyMDAwNDFkMDAwNmEyMDA4NDEwMDQxMDQxMGMwMDEyMDAwNDFmMDAxNmEyMjAyNDEwNDIwMDAyODAyNTAyMDAwMjgwMjU0MTA1NzIwMDAyODAyZjAwMTIxMTAyMDAwNDEwMDM2MDJmMDAxMjAwMDQxYzgwMDZhMjAwODQxMDQ0MTA4MTBjMDAxMjAwMjQxMDQyMDAwMjgwMjQ4MjAwMDI4MDI0YzEwNTcyMDAwMjgwMmYwMDEyMTA3MjAwMDQxMDAzYTAwZjAwMTIwMDA0MTQwNmIyMDA4NDEwODQxMDkxMGMwMDEyMDAyNDEwMTIwMDAyODAyNDAyMDAwMjgwMjQ0MTA1NzIwMDMyMTAyMjAwOTQxMTg3NDIwMDk0MTgwZmUwMzcxNDEwODc0NzIyMDA5NDEwODc2NDE4MGZlMDM3MTIwMDk0MTE4NzY3MjcyMjAwMTQ3MGQwMDBiMjAwMDJkMDBmMDAxMjAwNzQxMTg3NDIwMDc0MTgwZmUwMzcxNDEwODc0NzIyMDA3NDEwODc2NDE4MGZlMDM3MTIwMDc0MTE4NzY3MjcyMjEwODIwMGMxMDJmMjEwOTIwMDQxMDI5MjEwNzIwMTA0MTE4NzQyMDEwNDE4MGZlMDM3MTQxMDg3NDcyMjAxMDQxMDg3NjQxODBmZTAzNzEyMDEwNDExODc2NzI3MjEwMmYyMTA1NDUwNDQwNDEwMTEwMmQyMDAwNDE4MDAyNmEyMjAxMjAwNTEwMzI0MWE4ODYwODQxMDgxMDMzMjAwMDI4MDI4NDAyMTA3MDIwMDA0MWUwMDE2YTIyMDIyMDBhMjkwMzAwMzcwMzAwMjAwYjIwMDA0MTg4MDI2YTIyMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDExMDQzMjEwNDIwMDAyMDA3MzYwMjhjMDIyMDAwMjAwOTM2MDI4ODAyMjAwMDIwMTYzNzAzODAwMjIwMDQyMDAxMTA0NDIwMGEyMDAyMjkwMzAwMzcwMzAwMjAwMzIwMGIyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDNkMDAxMzcwMzgwMDIyMDAwMTA3ZDM2MDI5ODAyMDI0MDAyNDAwMjQwMDI0MDIwMDQxMDY1MGUwMjAxMDIwMDBiMTA0NzIxMDEyMDAwNDExMDZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwYTIwMDQxMDYyMjAwMDI5MDMxMDIxMTcyMDAwMjkwMzg4MDIyMTE2MjAwMDEwN2QzNjAyZTgwMTIwMDAyMDAxMzYwMmUwMDEyMDAwMjAxNjM3MDNkODAxMjAwMDIwMTczNzAzZDAwMTBjMDIwYjIwMDA0MWU4MDE2YTIwMDA0MTk4MDI2YTI5MDMwMDM3MDMwMDIwMDIyMDBhMjkwMzAwMzcwMzAwMjAwYjIwMDMyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDM4MDAyMzcwM2QwMDEwYzAxMGIyMDAwNDFmMDAxNmEyMDA0MTA5NzAxMDI3ZjIwMDAyOTAzZjAwMTUwMDQ0MDIwMDAyODAyOTAwMjIxMDMyMDAwNDExODZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwMDI4MDJmODAxMjAwMDI4MDJmYzAxMTA2ZDIwMDAyODAyMWMyMTAyMjAwMDI4MDIxODBjMDEwYjEwNDcyMTAzMjAwMDQxMjA2YTIwMDAyODAyODAwMjIwMDAyODAyODQwMjIwMDAyODAyOTAwMjIwMDA0MWYwMDE2YTEwNmMyMDAwMjgwMjI0MjEwMjIwMDAyODAyMjAwYjIxMDEyMDAwMjkwMzg4MDIyMTE2MjAwMDEwN2QzNjAyZTgwMTIwMDAyMDAzMzYwMmUwMDEyMDAwMjAxNjM3MDNkODAxMjAwMDIwMDIzNjAyZDQwMTIwMDAyMDAxMzYwMmQwMDEwYjIwMDA0MWQwMDE2YTEwNzIyMTAzMjAwODEwMmYyMTAxMjAwMDIwMDMzNjAyOGMwMjIwMDA0MjAwMzcwMzgwMDIyMDAwMjAwMTM2MDI4ODAyMjAwMDQxODAwMjZhMTA5NTAxMjEwMTBjMDQwYjIwMDgxMDJmMjEwNDQxMDExMDJkMjAwNTEwMzIyMTAzNDFhODg2MDg0MTA4MTA0ZDIxMDExMDQzMjIwNTIwMDQxMDZlMjAwNTEwNzAxMDQzMjEwNDIwMDAyMDA3MzYwMjhjMDIyMDAwMjAwOTM2MDI4ODAyMjAwMDIwMTYzNzAzODAwMjIwMDQyMDAwNDE4MDAyNmExMDQ0MjAwMDIwMDMzNjAyOTAwMjIwMDA0MjdmMzcwMzg4MDIyMDAwMjAwNTM2MDI4NDAyMjAwMDIwMDEzNjAyODAwMjIwMDAxMDdkMzYwMjk4MDIwMjdmMDI3ZTAyNDAwMjQwMDI0MDIwMDQxMDY1MGUwMjAxMDIwMDBiMTA0NzIxMDIyMDAwNDEyODZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwYTIwMDQxMDYyMjAwMDI4MDIyYzIxMDMyMDAwMjgwMjI4MjEwMTIwMDAyOTAzODgwMjBjMDIwYjIwMDAyODAyOTAwMjIxMDIyMDAwMjkwMzg4MDIyMTE2MjAwMDI4MDI4NDAyMjEwMzIwMDAyODAyODAwMjIxMDEyMDAwMjgwMjk4MDIwYzAyMGIyMDAwNDFkMDAxNmEyMDA0MTA5NzAxMDI3ZjIwMDAyOTAzZDAwMTUwMDQ0MDIwMDAyODAyOTAwMjIxMDIyMDAwNDEzMDZhMjAwMDI4MDI4MDAyMjAwMDI4MDI4NDAyMjAwMDI4MDJkODAxMjAwMDI4MDJkYzAxMTA2ZDIwMDAyODAyMzQyMTAzMjAwMDI4MDIzMDBjMDEwYjEwNDcyMTAyMjAwMDQxMzg2YTIwMDAyODAyODAwMjIwMDAyODAyODQwMjIwMDAyODAyOTAwMjIwMDA0MWQwMDE2YTEwNmMyMDAwMjgwMjNjMjEwMzIwMDAyODAyMzgwYjIxMDEyMDAwMjkwMzg4MDIwYjIxMTYxMDdkMGIyMTA0MjAxNjQyN2Y1MTA0N2UxMDE2MDUyMDE2MGIyMDAyMjAwNDIwMDEyMDAzMTA0NTIxMDMxMDE3NDEwMDIxMDIyMDAzMTAxMjIxMDEyMDAwNDEwMDM2MDJmODAxMjAwMDIwMDMzNjAyZjAwMTIwMDAyMDAxNDEwMjc2MzYwMmY0MDEyMDAwNDFmMDAxNmExMDc1MTAyZjIxMDQxMDQzMjEwMTIwMDQxMDEyMjEwMzIwMDA0MTAwM2EwMDkwMDIyMDAwMjAwMzM2MDI4YzAyMjAwMDIwMDQzNjAyODgwMjIwMDAyMDAzMzYwMjg0MDIyMDAwNDEwMDM2MDI4MDAyMDM0MDIwMDIyMDAzNDYwNDQwMjAwMDJkMDA5MDAyNDUwZDA1NDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGMwNTA1MjAwMDQxZDAwMTZhMjIwMzIwMDA0MTgwMDI2YTEwNzcyMDAxMjAwMzEwNDQyMDAwMjgwMjgwMDIyMTAyMjAwMDI4MDI4NDAyMjEwMzBjMDEwYjAwMGIwMDBiNDFjMDg2MDg0MTE5MTA0MTAwMGIyMDBjMjAwZTEwMzAwNDQwMjAwZDIwMDQxMDhmMDEwYzA0MGI0MWQ0OGEwODQxMTMxMDQxMDAwYjIwMDA0MTA4NmExMDM2MjAwMDIwMDAyZDAwMGMzYTAwODQwMjIwMDAyMDAwMjgwMjA4MzYwMjgwMDIyMDAwNDE4MDAyNmEyMjA2NDE4MDgwMDg0MTIxMTBhMzAxMjMwMDQxNDA2YTIyMDMyNDAwMjAwMzQxMDAyMDAzNmI0MTAzNzEyMjA0NmEyMTA3MjAwNDA0NDAyMDAzMjEwMjAzNDAyMDAyNDEwMDNhMDAwMDIwMDI0MTAxNmEyMjAyMjAwNzQ5MGQwMDBiMGIyMDA3NDFjMDAwMjAwNDZiMjIwNTQxN2M3MTIyMDQ2YTIxMDIyMDA0NDEwMDRhMDQ0MDAzNDAyMDA3NDEwMDM2MDIwMDIwMDc0MTA0NmEyMjA3MjAwMjQ5MGQwMDBiMGIyMDA1NDEwMzcxMjIwNDA0NDAyMDAyMjAwNDZhMjEwNDAzNDAyMDAyNDEwMDNhMDAwMDIwMDI0MTAxNmEyMjAyMjAwNDQ5MGQwMDBiMGIyMDA2MjAwMzAyN2YyMDAxMDQ0MDIwMDFhZDIxMTY0MTNmMjEwMTAyNDAwMzQwMjAxNjUwMGQwMTIwMDE0MTNmNGQwNDQwMjAwMTIwMDM2YTIwMTYyMDE2NDIwYTgwMjIxNjQyMGE3ZTdkYTc0MTMwNzIzYTAwMDAyMDAxNDEwMTZiMjEwMTBjMDEwYjBiMTAyYzAwMGIyMDAxNDEwMTZhMGMwMTBiMjAwMzQxMzAzYTAwM2Y0MTNmMGIyMjAxNmE0MWMwMDAyMDAxNmIxMGEzMDEyMDAzNDE0MDZiMjQwMDIwMDAyODAyODAwMjIwMDAyZDAwODQwMjEwMzgxMDAwMDAwYjIwMDAyMDAxMzYwMmNjMDExMDdkMjEwMjEwN2QyMTA0MjAwMDIwMDExMDEyMzYwMmQ4MDEyMDAwNDEwMDM2MDJkNDAxMjAwMDIwMDA0MWNjMDE2YTM2MDJkMDAxMDI0MDAzNDAwMjQwMjAwMDQxODAwMjZhMjAwMDQxZDAwMTZhMTA2NzIwMDAyOTAzODAwMjUwMGQwMDIwMDAyODAyOTQwMjIxMDUyMDAyMjEwMzIwMDAyODAyOTAwMjIyMDEyMDBjMTAzMDQ1MDQ0MDIwMDQyMTAzMjAwMTIwMDgxMDMwNDUwZDAzMGIyMDAzMjAwNTEwOGYwMTBjMDEwYjBiMjAwODEwMmYyMTBjNDIwMDIxMTYyMDA2MjEwMTBjMDEwYjBiMGI0MTg3ODYwODQxMjExMDQxMDAwYjQxYTU4YTA4NDExNTEwNDEwMDBiMjAwMDQxODA4MDgwMjAzNjAyZDAwMTIwMDYyMDAwNDFkMDAxNmE0MTA0MTAwZjFhMjAwNjQxZWQ4NTA4NDEwNDEwMGYxYTBiMjAwMDQyMDAzNzAzZDAwMTIwMDYyMDAwNDFkMDAxNmEyMjAzNDEwODEwMGYxYTIwMDUyMDA2MTAzZjIwMDQyMDA2MTA0ZTEwYzcwMTEwNDMyMjAxNDE4YThkMDg0MTA4MTA0ZDEwNGUyMDAyMTA0MzEwMmYyMjAyMTAzZjIwMDIxMDNmMjAwMTIwMDIxMDI0MjAwMDIwMDQzNjAyZDAwMTIwMDAyMDA0MTAxMjM2MDI4ODAyMjAwMDQxMDAzNjAyODQwMjIwMDAyMDAzMzYwMjgwMDIwMzQwMjAwMDIwMDA0MTgwMDI2YTEwYzQwMTIwMDAyODAyMDAwNDQwMjAwMDI4MDIwNDEwMDcxYTBjMDEwYjBiMjAwMDQxYTAwMjZhMjQwMDBmMGI0MWJhOGEwODQxMWExMDQxMDAwYjBkMDAxMDIyNDEwMDEwNWExMGM3MDExMDI1MGIwZDAwMTAyMjQxMDAxMDVhMTBkMTAxMTA1YjBiMGQwMDEwMjI0MTAwMTA1YTEwZDQwMTEwNWQwYjBkMDAxMDIyNDEwMDEwNWExMGQ4MDExMDVkMGIyYTAxMDE3ZjEwMjI0MTAwMTA1YTEwY2IwMTEwYWIwMTIyMDA0MWZlZmZmZmZmMDc0NzA0NDAyMDAwMTAwNzFhMGYwYjQxZWQ4NTA4NDEwNDEwMjYwYjBkMDAxMDIyNDEwMDEwNWExMGRhMDExMDVkMGIwZDAwMTAyMjQxMDAxMDVhMTBjODAxMTA1YjBiMGQwMDEwMjI0MTAwMTA1YTEwYzkwMTEwNWIwYjBkMDAxMDIyNDEwMDEwNWExMGNjMDExMDViMGIwZDAwMTAyMjQxMDAxMDVhMTBkOTAxMTA1ZDBiMGQwMDEwMjI0MTAwMTA1YTEwZDIwMTEwNWIwYmExMDEwMTAyN2YyMzAwNDE0MDZhMjIwMDI0MDAxMDIyNDEwMTEwNWEyMDAwNDEwMDEwNGIzNjAyMTQyMDAwMjAwMDQxMTQ2YTEwZDYwMTEwYWMwMTIyMDEzNjAyMTgyMDAwNDEwODZhMTAzNTIwMDAyMDAwMmQwMDBjM2EwMDIwMjAwMDIwMDAyODAyMDgzNjAyMWMyMDAwMjAwMTEwMTIzNjAyMmMyMDAwNDEwMDM2MDIyODIwMDAyMDAwNDExODZhMzYwMjI0MjAwMDQxMzQ2YTIxMDEwMzQwMjAwMDQxMzA2YTIwMDA0MTI0NmExMGJhMDEyMDAwMjgwMjMwMDQ0MDIwMDEyMDAwNDExYzZhMTBiYjAxMGMwMTBiMGIyMDAwMjgwMjFjMjAwMDJkMDAyMDEwMzcyMDAwNDE0MDZiMjQwMDBiYTAwMTAxMDI3ZjIzMDA0MTQwNmEyMjAwMjQwMDEwMjI0MTAxMTA1YTIwMDA0MTAwMTA0YjM2MDIxNDIwMDAyMDAwNDExNDZhMTBkNTAxMTBiMjAxMjIwMTM2MDIxODIwMDA0MTA4NmExMDM1MjAwMDIwMDAyZDAwMGMzYTAwMjAyMDAwMjAwMDI4MDIwODM2MDIxYzIwMDAyMDAxMTAxMjM2MDIyYzIwMDA0MTAwMzYwMjI4MjAwMDIwMDA0MTE4NmEzNjAyMjQwMzQwMjAwMDQxMzA2YTIwMDA0MTI0NmExMGI1MDEyMDAwMmQwMDNjNDEwMjQ3MDQ0MDIwMDA0MTMwNmEyMDAwNDExYzZhMTBiNjAxMGMwMTBiMGIyMDAwMjgwMjFjMjAwMDJkMDAyMDEwMzcyMDAwNDE0MDZiMjQwMDBiMGQwMDEwMjI0MTAwMTA1YTEwZDMwMTEwNWUwYjBkMDAxMDIyNDEwMDEwNWExMGQ3MDExMDVlMGJlMzAzMDIwNTdmMDI3ZTIzMDA0MTkwMDE2YjIyMDAyNDAwMTA0OTQxMDAxMDVhMjAwMDEwNGEyMjAxMzYwMjE0MDI0MDIwMDExMDY1NDEwMTQ2MDQ0MDIwMDExMDEyMjEwMTIwMDA0MTAwMzYwMjM0MjAwMDIwMDEzNjAyMzAyMDAwNDEwMDM2MDIyYzIwMDAyMDAwNDExNDZhMzYwMjI4MjAwMDQxM2M2YTIxMDIyMDAwNDFmNDAwNmEyMTAzMjAwMDQxZjgwMDZhMjEwMTAzNDAyMDAwNDFmMDAwNmEyMDAwNDEyODZhMTA2NzIwMDAyOTAzNzA1MDBkMDIyMDAwNDFlMDAwNmEyMDAxNDEwODZhMjkwMzAwMjIwNTM3MDMwMDIwMDAyMDAxMjkwMzAwMjIwNjM3MDM1ODIwMDAyMDAwMjgwMjM0MjIwNDQxMDE2YTM2MDIzNDIwMDM0MTA4NmEyMDA1MzcwMjAwMjAwMzIwMDYzNzAyMDAyMDAwNDE0MDZiMjAwMTI5MDIwMDM3MDMwMDIwMDA0MWM4MDA2YTIwMDA0MTgwMDE2YTI4MDIwMDM2MDIwMDIwMDAyMDAwMjkwMjcwMzcwMzM4MjAwNDQ1MDQ0MDIwMDA0MTIwNmEyMDAyNDEwODZhMjkwMjAwMzcwMzAwMjAwMDIwMDIyOTAyMDAzNzAzMTgwYzAxMGIwYjEwMmMwMDBiNDFiMzgzMDg0MTIyMTAwMzAwMGIyMDAwNDEwODZhMjIwMTIwMDA0MTIwNmEyOTAzMDAzNzAzMDAyMDAwMjAwMDI5MDMxODM3MDMwMDEwZGEwMTEwYTcwMTIxMDIyMDAxMjgwMjAwMjAwMjEwMzA0NTA0NDA0MTk4OGEwODQxMGQxMDQxMDAwYjEwZDIwMTEwNWMyMTAyMjAwMDEwNDMzNjAyMTgyMDAwMTA0MzM2MDIyODIwMDA0MWYwMDA2YTIyMDEyMDAyMTAzMjQxYTc4MzA4NDEwNTEwMzMyMDAwMjgwMjc0MjIwMjIwMDA0MTE4NmExMDdiMjAwMjIwMDA0MTI4NmExMDdhMjAwMDQxZTgwMDZhMjAwMDQxODAwMTZhMjkwMzAwMzcwMzAwMjAwMDQxZTAwMDZhMjAwMDQxZjgwMDZhMjkwMzAwMzcwMzAwMjAwMDIwMDAyOTAzNzAzNzAzNTgyMDAwNDEzODZhMjIwMjIwMDA0MWQ4MDA2YTIwMDAxMDg0MDEyMDAxMjAwMjEwY2QwMTIwMDExMDc0MjAwMDQxOTAwMTZhMjQwMDBiOGMwMTAxMDI3ZjIzMDA0MTQwNmEyMjAwMjQwMDEwNDk0MTAwMTA1YTEwZDIwMTEwNWMyMTAxMjAwMDEwNDMzNjAyMDAyMDAwMTA0MzM2MDIwNDIwMDA0MTA4NmEyMDAxMTAzMjQxOTU4MzA4NDExMjEwMzMyMDAwMjgwMjBjMjIwMTIwMDAxMDdiMjAwMTIwMDA0MTA0NmExMDdhMjAwMDQxMzA2YTIwMDA0MTE4NmEyOTAzMDAzNzAzMDAyMDAwNDEyODZhMjAwMDQxMTA2YTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzA4MzcwMzIwMjAwMDEwN2QzNjAyMzgyMDAwNDEyMDZhMTA3NDIwMDA0MTQwNmIyNDAwMGJmZjAxMDIwNTdmMDE3ZTIzMDA0MTMwNmIyMjAwMjQwMDEwMjIxMDQ5NDEwMTEwNWEyMDAwMTA0ZjM2MDIxMDEwZDIwMTEwNWMyMDAwMTA0MzM2MDIxNDIwMDAxMDQzMzYwMjE4MTAzMjIxMDI0MWFjODMwODQxMDcxMDRkMjEwMzEwNDMyMjAxMjAwMDQxMTA2YTEwNzgyMDAxMjAwMDQxMTQ2YTEwN2IyMDAxMjAwMDQxMTg2YTEwN2ExMDdkMjEwNDEwMTYyMDAyMjAwNDIwMDMyMDAxMTA0NTIxMDExMDE3MjAwMTEwMTIyMTAyMjAwMDQxMDAzNjAyMjQyMDAwMjAwMTM2MDIxYzIwMDAyMDAyNDEwMjc2MzYwMjIwMjAwMDQxMWM2YTEwNzUyMTAxMjAwMDQyMDAzNzAzMjgyMDAxMTAxMjIyMDI0MTA5NDkwNDQwMDI0MDIwMDA0MTA4NmEyMDAwNDEyODZhMjAwMjEwYjAwMTIwMDE0MTAwMjAwMDI4MDIwODIyMDEyMDAwMjgwMjBjMjIwMjEwOGEwMTFhMjAwMTIwMDIxMGIxMDEyMjA1NDI4MDgwODA4MDEwNWEwZDAwMjAwNTEwMTQyMDAwNDEzMDZhMjQwMDBmMGIwYjQxOGE4NTA4NDEwYjQxOTU4NTA4NDEwZTEwNGMwMDBiOTgwMzAyMDU3ZjAxN2UyMzAwNDFlMDAwNmIyMjAwMjQwMDEwMjIxMDQ5NDFlNGRiMDgxMDEzMzYwMjAwNDFlNGRiMDgyODAyMDA0MTAwNDgwNDQwNDFlZjgzMDg0MTExMTAwMzAwMGIyMDAwNDEwMDM2MDIzODEwNDMyMTAzMjAwMDQxMzg2YTIyMDQyODAyMDAyMTAxMDM0MDQxZTRkYjA4MjgwMjAwMjAwMTRhMDQ0MDIwMDQyMDAxNDEwMTZhMjIwMjM2MDIwMDIwMDMyMDAxMTA0YjEwNGUyMDAyMjEwMTBjMDEwYjBiMjAwMzIxMDE0MWU0ZGIwODI4MDIwMDIwMDAyODAyMzg0YTA0NDA0MTgwODQwODQxMTIxMDAzMDAwYjIwMDAyMDAxMzYwMjFjMjAwNDEwZDIwMTEwNWMxMDMyNDFmOTgyMDg0MTBkMTAzMzIwMDAyMDAxMTAxMjM2MDI1YzIwMDA0MTAwMzYwMjU4MjAwMDIwMDA0MTFjNmEzNjAyNTQyMDAwMjgwMjNjMjEwMTAzNDAyMDAwNDExMDZhMjAwMDQxZDQwMDZhMTBjNDAxMjAwMDI4MDIxMDA0NDAyMDAxMjAwMDI4MDIxNDEwNmUwYzAxMGIwYjIwMDA0MTI4NmEyMDAwNDE0MDZiMjkwMzAwMzcwMzAwMjAwMDQxMzA2YTIwMDA0MWM4MDA2YTI5MDMwMDM3MDMwMDIwMDAyMDAwMjkwMzM4MzcwMzIwMjAwMDQxMzg2YTIwMDA0MTIwNmExMDdlMDI0MDIwMDAyODAyNDQyMjAxMTBjZTAxNDUwNDQwMjAwMDI4MDI0MDIxMDIwYzAxMGIxMDQ2MjAwMDI4MDI0MDIyMDI0MjAwMjAwMTEwNDIwYjIwMDAyOTAzMzgyMDAwNDEwODZhMTAzNTIwMDAyMDAwMmQwMDBjM2EwMDNjMjAwMDIwMDAyODAyMDgzNjAyMzgyMDAyMjAwMDQxMzg2YTIyMDIxMDNlMjAwMjEwYzYwMTIwMDEyMDAyMTAzYzIwMDAyODAyMzgyMDAwMmQwMDNjMTAzNzIwMDA0MWUwMDA2YTI0MDAwYjMxMDEwMTdlMTAyMjEwNDk0MTAxMTA1YTQxMDAxMDExMjIwMDQyODE4MDkwYmJiYWQ2YWRmMDBkNWEwNDQwNDFlZjhiMDg0MTIwMTA0MTAwMGIxMGQ3MDEyMDAwMTBhYTAxMGIzMTAxMDE3ZTEwMjIxMDQ5NDEwMTEwNWE0MTAwMTAxMTIyMDA0MjgxODA5MGJiYmFkNmFkZjAwZDVhMDQ0MDQxZDI4YjA4NDExZDEwNDEwMDBiMTBkMzAxMjAwMDEwYWEwMTBiZTMwMTAxMDM3ZjIzMDA0MTMwNmIyMjAwMjQwMDEwMjIxMDQ5NDEwMjEwNWE0MTAwMTA1ODIxMDEyMDAwNDEwMTEwNTEyMjAyMzYwMjBjMjAwMDIwMDEzNjAyMDgyMDAwMjAwMTEwMTIzNjAyMTgyMDAwNDEwMDM2MDIxNDIwMDAyMDAwNDEwODZhMzYwMjEwMDM0MDIwMDA0MTFjNmEyMDAwNDExMDZhMTBjMzAxMjAwMDI4MDIxYzA0NDAyMDAwMjAwMDI4MDIyNDIyMDEzNjAyMmMyMDAwMjAwMDI4MDIyMDM2MDIyODIwMDA0MTI4NmExMGQ2MDEyMDAxMTBiOTAxMGMwMTA1MjAwMDIwMDIxMDEyMzYwMjE4MjAwMDQxMDAzNjAyMTQyMDAwMjAwMDQxMGM2YTM2MDIxMDAzNDAyMDAwNDExYzZhMjAwMDQxMTA2YTEwYzMwMTIwMDAyODAyMWMwNDQwMjAwMDIwMDAyODAyMjQyMjAxMzYwMjJjMjAwMDIwMDAyODAyMjAzNjAyMjgyMDAwNDEyODZhMTBkNTAxMjAwMTEwYjQwMTBjMDEwYjBiMjAwMDQxMzA2YTI0MDAwYjBiMGJhYTA3MDIwYjdmMDE3ZTIzMDA0MTMwNmIyMjAwMjQwMDEwMjI0MTAwMTA1YTEwYzkwMTEwNWMyMjA5MTAyZjEwMzIyMTAxNDFkMjgxMDg0MTE0MTA0ZDIxMDIxMDQzMjEwNjEwN2QyMTA3MTAxNjIwMDEyMDA3MjAwMjIwMDYxMDQ1MjEwMTEwMTcyMDAxMTAxMjIxMDIyMDAwNDEwMDM2MDIxMDIwMDAyMDAxMzYwMjA4MjAwMDIwMDI0MTAyNzYzNjAyMGMyMDAwNDEwODZhMTA3NTIyMDIxMDEyMjEwMTIwMDA0MTI4NmE0MTAwM2EwMDAwMjAwMDQxMjQ2YTIwMDEzNjAyMDAyMDAwMjAwMjM2MDIyMDIwMDAyMDAxMzYwMjFjMjAwMDQxMDAzNjAyMTgwMjQwMDI3ZjAyNDAwMjQwMjAwMTQ1MGQwMDAyNDAwMjQwMDI0MDIwMDA0MTE4NmE0MThhODUwODQxMGIxMDU0NDFmZjAxNzEwZTAyMDIwMTAwMGI0MThhODUwODQxMGI0MWVkODYwODQxMGQxMDRjMDAwYjQxMDEyMTAzMjAwMDQxMTg2YTQxOGE4NTA4NDEwYjEwNTMyMTAxMGIyMDAwMjgwMjFjMjAwMDI4MDIxODQ3MGQwMzIwMDAyZDAwMjgwNDQwNDFkY2RiMDg0MTAwMzYwMjAwNDFlMGRiMDg0MTAwM2EwMDAwMGIyMDAzNDUwZDAwMjAwMDQxMTg2YTIyMDQyMDAxMTAyZjEwMzI0MWU0ODIwODQxMTUxMDMzMjAwMDIwMDQxMDdjMjIwMzM2MDIwMDIwMDQyMDAxMTAyZjEwMzI0MWIyODIwODQxMGIxMDMzMjAwMDQxMTg2YTEwN2M0MmJlOGE4NjBmMTAyZTEwOGUwMTIxMDYyMDA0MjAwMTEwMmYxMDMyNDFjOTgyMDg0MTBkMTAzMzIwMDA0MTE4NmExMDdjMjAwMzEwOTIwMTQyYmU4YTg2MGYxMDJlMTA4ZTAxNDEwYTEwMmQ0MTEyMTA5NDAxMTA4ZDAxMjEwNzIwMDQyMDAxMTAyZjEwMzI0MWJkODIwODQxMGMxMDMzMjAwMDQxMTg2YTEwN2M0MTBhMTAyZDQxMTIxMDk0MDEyMDAzMTA5MDAxMTA4ZTAxNDJiZThhODYwZjEwMmUxMDhlMDE0MTBhMTAyZDQxMTIxMDk0MDExMDhkMDEyMTBhMjAwNDIwMDkxMDJmMjIwMjEwMmYxMDMyNDE4NzgxMDg0MTBmMTAzMzIwMDAyMDAwNDExODZhMTA3YzIyMDUzNjAyMTQyMDA0MjAwMjEwMmYxMDMyNDFhYjgyMDg0MTA3MTAzMzIwMDA0MTE4NmExMDdjMjEwODIwMDQyMDAyMTAzMjQxYTY4MTA4NDExMDEwMzMyMDAwNDExODZhMTA3YzIxMDIyMDAwMjAwODIwMDUxMDkxMDEyMDAyMTA5MDAxMzYwMjA4MjAwNDIwMDExMDMyNDFkNjgyMDg0MTBlMTAzMzIwMDAyODAyMWMyMjAxMjAwMDQxMTQ2YTEwNzgyMDAxMjAwMDQxMDg2YTEwNzgyMDAwMjgwMjI4MjEwMjIwMDAyODAyMTgyMTA1MjAwMDI5MDMyMDEwN2QyMTA4MTA3MTIwMDIyMDA4MjAwNTIwMDExMDQ1MjEwMTEwMTcyMDAwMjAwMTEwNzMzNjAyMDQ0MjgwODA5MGJiYmFkNmFkZjAwZDEwMmUyMTAyMjAwMDEwN2QzNjAyMTgyMDAwNDEwNDZhMjAwNDEwY2YwMTIxMDUxMDdkMjIwMTIwMDUwZDAyMWEyMDAxMjAwMDI4MDIwNDEwODkwMTQxMDE2YTQxZmYwMTcxNDEwMTRkMDQ0MDIwMDA0MTA0NmEyMDAwMTBjZjAxMGQwMjIwMDAyODAyMDAyMTAzMGIyMDAwMjgwMjA0MjAwMzEwOTMwMTIwMGExMDhlMDEyMTAxNDEwYTEwMmQ0MTEyMTA5NDAxMjAwMDI4MDIwMDEwOTAwMTIxMDMyMDA2MjAwMjEwOTIwMTIwMDcyMDAyMTA5MjAxMTA4YzAxMjAwMTIwMDIxMDhlMDEyMDAzMTA4ZDAxMTA4YzAxMGMwMjBiNDFhMDhiMDg0MTMyMTA0MTAwMGIyMDAwMjgwMjA0MjAwNzEwOTIwMTIxMDEyMDA2MjAwMjEwOTIwMTIwMDEyMDAyMTA4ZTAxMjAwMDI4MDIwMDEwOGQwMTEwOGMwMTBiMjEwMTIwMDA0MTE4NmEyMjAzMjAwOTEwMzI0MTk2ODEwODQxMTAxMDMzMjAwMzEwN2MyMTAyNDEwYTEwMmQ0MTEyMTA5NDAxMjEwMzIwMDAyODAyMDQyMDAxMTA5MjAxMjAwMzIwMDIxMDkzMDExMDhlMDEyMDAzNDEwMzEwOTQwMTEwOGQwMTEwMjUyMDAwNDEzMDZhMjQwMDBmMGI0MThhODUwODQxMGI0MTk1ODUwODQxMGUxMDRjMDAwYjAzMDAwMTBiM2MwMTAxN2YyMzAwNDExMDZiMjIwNTI0MDAyMDA1NDEwODZhMjAwMTIwMDQyMDAyMjAwMzEwOWQwMTIwMDUyODAyMGMyMTAxMjAwMDIwMDUyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTEwNmEyNDAwMGIzYjAxMDE3ZjIzMDA0MTEwNmIyMjA1MjQwMDIwMDU0MTA4NmEyMDAyMjAwMzIwMDEyMDA0MTAyYjIwMDUyODAyMGMyMTAxMjAwMDIwMDUyODAyMDgzNjAyMDAyMDAwMjAwMTM2MDIwNDIwMDU0MTEwNmEyNDAwMGIwYmRhMGQwMjAwNDE4MDgwMDgwYmM2MGQ0ZTZmMjA3Mzc3NjE3MDIwNmY3MDY1NzI2MTc0Njk2ZjZlMjA2NjZmNzU2ZTY0MjA2MTc0MjA2OTZlNjQ2NTc4MjA3NTZlNzc3MjYxNzA0NTY3NmM2NDY3NjU3NDU3NzI2MTcwNzA2NTY0NDU2NzZjNjQ1NDZmNmI2NTZlNDk2NDc3NzI2MTcwNDU2NzZjNjQ3MjY1NjM2OTcwNjk2NTZlNzQyMDYxNjQ2NDcyNjU3MzczMjA2ZTZmNzQyMDczNjU3NDY1Nzg2OTc0NGQ2MTcyNmI2NTc0NjM2YzYxNjk2ZDUyNjU3NzYxNzI2NDczNjc2NTc0NDE2MzYzNmY3NTZlNzQ1NDZmNmI2NTZlNzM2NzY1NzQ1NDZmNzQ2MTZjNDI2ZjcyNzI2Zjc3NzM2NzY1NzQ1MjY1NzM2NTcyNzY2NTQ2NjE2Mzc0NmY3MjY3NjU3NDU0NmY3NDYxNmM1MjY1NzM2NTcyNzY2NTczNjc2NTc0NTQ2ZjZiNjU2ZTQ5NjQ2ZDY5NmU3NDQxNmU2NDQ1NmU3NDY1NzI0ZDYxNzI2YjY1NzQ2NzY1NzQ0OTZlNzQ2NTcyNjU3Mzc0NTI2MTc0NjU0ZDZmNjQ2NTZjNjc2NTc0NTU2ZTY0NjU3MjZjNzk2OTZlNjc0OTY0NzQ2ZjZiNjU2ZTczNTQ2ZjU1NmU2NDY1NzI2Yzc5Njk2ZTY3NDE2ZDZmNzU2ZTc0NzU2ZTY0NjU3MjZjNzk2OTZlNjc0MTZkNmY3NTZlNzQ1NDZmNTQ2ZjZiNjU2ZTczNzI2NTY0NjU2NTZkNjc2NTc0NDM2MTczNjg2NzY1NzQ0MjYxNzM2NTUyNjE3NDY1Njc2NTc0NGM2MTczNzQ1MzZjNmY3MDY1Njc2NTc0NDY2OTcyNzM3NDUzNmM2ZjcwNjU2NzY1NzQ1NTc0Njk2YzY5N2E2MTc0Njk2ZjZlNjc2NTc0NGY3MDc0Njk2ZDYxNmM1NTc0Njk2YzY5N2E2MTc0Njk2ZjZlNjM2YzYxNjk2ZDRkNzU2Yzc0Njk3MDZjNjU2NzY1NzQ1Mzc0NjE2YjY1NTQ2ZjZiNjU2ZTQ5NjQ3MjY1NjI2MTZjNjE2ZTYzNjU1MDZmNzI3NDY2NmY2YzY5NmY3Mzc0NjE2YjY1NzU2ZTczNzQ2MTZiNjU2OTZlNjM2ZjcyNzI2NTYzNzQyMDZlNzU2ZDYyNjU3MjIwNmY2NjIwNDU1MzQ0NTQyMDc0NzI2MTZlNzM2NjY1NzI3MzYxNzI2Nzc1NmQ2NTZlNzQyMDY0NjU2MzZmNjQ2NTIwNjU3MjcyNmY3MjIwMjgyOTNhMjA3NDZmNmYyMDY2NjU3NzIwNjE3MjY3NzU2ZDY1NmU3NDczNzQ2ZjZmMjA2ZDYxNmU3OTIwNjE3MjY3NzU2ZDY1NmU3NDczNzc3MjZmNmU2NzIwNmU3NTZkNjI2NTcyMjA2ZjY2MjA2MTcyNjc3NTZkNjU2ZTc0NzM2MzYxNmU2ZTZmNzQyMDczNzU2Mjc0NzI2MTYzNzQyMDYyNjU2MzYxNzU3MzY1MjA3MjY1NzM3NTZjNzQyMDc3NmY3NTZjNjQyMDYyNjUyMDZlNjU2NzYxNzQ2OTc2NjU0ZDc1NmM3NDY5NDU1MzQ0NTQ0ZTQ2NTQ1NDcyNjE2ZTczNjY2NTcyNDU1MzQ0NTQ0ZTQ2NTQ1NDcyNjE2ZTczNjY2NTcyNDU1MzQ0NTQ1NDcyNjE2ZTczNjY2NTcyNzM3OTZlNjMyMDcyNjU3Mzc1NmM3NDY5NmU3MDc1NzQyMDc0NmY2ZjIwNmM2ZjZlNjc2OTZlNzA3NTc0MjA3NDZmNmYyMDczNjg2ZjcyNzQ2MzYxNzM3NDIwNzQ2ZjIwNjkzNjM0MjA2NTcyNzI2ZjcyNGQ2MTZlNjE2NzY1NjQ1NjY1NjMyMDY5NmU2NDY1NzgyMDZmNzU3NDIwNmY2NjIwNzI2MTZlNjc2NTQ1NTM0NDU0MjA2NTc4NzA2NTYzNzQ2NTY0NDU0NzRjNDQ3Mzc0NmY3MjYxNjc2NTIwNjQ2NTYzNmY2NDY1MjA2NTcyNzI2ZjcyM2EyMDc1NmU2YjZlNmY3NzZlMjA3MjY1NjM2NTY5NzY2NTY0MjA3NDZmNmI2NTZlMjA2MTY2NzQ2NTcyMjA3Mzc3NjE3MDY1Nzg2MzY4NjE2ZTY3NjU2MjYxNjQyMDYxNzI3MjYxNzkyMDZjNjU2ZTY3NzQ2ODc3NzI2ZjZlNjcyMDcyNjU3NDc1NzI2ZTY1NjQyMDczNzc2MTcwMjA3NDZmNmI2NTZlNzM3NzYxNzA1NDZmNmI2NTZlNzM0NjY5Nzg2NTY0NDk2ZTcwNzU3NDY5NmU3NjYxNmM2OTY0MjA3NjYxNmM3NTY1Nzc3MjYxNzA3MDY1NjQ1ZjY1Njc2YzY0NWY2MzZmNmU3NDcyNjE2Mzc0NWY2MTY0NjQ3MjY1NzM3MzYzNmY2ZDcwNmY3NTZlNjQ1ZjYxNzM2ODczNzc2MTcwNWY3Mzc3NjE3MDczNjM2ZjZkNzA2Zjc1NmU2NDVmNzg2NTc4NjM2ODYxNmU2NzY1NWY3Mzc3NjE3MDczNzA2NTcyNjY2ZjcyNmQ2MTZlNjM2NTVmNjY2NTY1NzM1ZjcwNjU3MjYzNjU2ZTc0NjM2ZjZkNzA2Zjc1NmU2NDVmNjY2NTY1NzM1ZjcwNjU3MjYzNjU2ZTc0NjI2ZjZmNzM3NDY1NzI1ZjYxNjQ2NDcyNjU3MzczNmQ2ZjZlNjU3OTVmNmQ2MTcyNmI2NTc0NWY2MTY0NjQ3MjY1NzM3MzYzNmY2ZTc0NzI2ZjZjNmM2NTcyNWY2MTY0NjQ3MjY1NzM3MzYxNzM3MzY1NzQ1Zjc0NmY2YjY1NmU1ZjY5NjQ2NTZlNzQ2OTY2Njk2NTcyNzY2MTc1NmM3NDVmNjE2NDY0NzI2NTczNzM3MDYxNzk2ZDY1NmU3NDIwNzM2ODZmNzU2YzY0MjA2MjY1MjA2MTZlMjA0NTUzNDQ1NDIwNzQ2ZjZiNjU2ZTU0Njg2NTIwNjE3MzczNjU3NDIwNzQ2ZjZiNjU2ZTIwNjk2NDY1NmU3NDY5NjY2OTY1NzIyMDYxNmU2NDIwNzQ2ODY1MjA2ZDZmNmU2NTc5MjA2ZDYxNzI2YjY1NzQyMDc1NmU2NDY1NzI2Yzc5Njk2ZTY3MjA2OTY0NjU2ZTc0Njk2NjY5NjU3MjIwNjQ2ZjZlMjc3NDIwNmQ2MTc0NjM2ODU3Njg2NTZlMjA3NDYxNzI2NzY1NzQ2OTZlNjcyMDYxNmUyMDQ1NDc0YzQ0MjA2ZDYxNzI2YjY1NzQyMDc0Njg2NTIwNjE3MzczNjU3NDIwNzQ2ZjZiNjU2ZTIwNjk2NDY1NmU3NDY5NjY2OTY1NzIyMDczNjg2Zjc1NmM2NDIwNjI2NTIwNTc0NTQ3NGM0NDQzNjE2YzZjNjU3MjIwNzM2ODZmNzU2YzY0MjA2MjY1MjA3NjYxNzU2Yzc0Nzc3MjZmNmU2NzIwNzA2MTc5NmQ2NTZlNzQ2ZTZmMjA3MjY1Nzc2MTcyNjQyMDc0NmYyMDYzNmY2ZDcwNmY3NTZlNjQ2ZTZmMjA2YzY1NjY3NDIwNjE2ZDZmNzU2ZTc0MjA3NDZmMjA2MzZmNmQ3MDZmNzU2ZTY0Nzc3MjZmNmU2NzIwNzM3NzYxNzA3MDY1NjQyMDc0NmY2YjY1NmU2ZTZmMjA2NTc4Njk3NDIwNmQ2MTcyNmI2NTc0MjA3MDYxNzk2ZDY1NmU3NDIwNzI2NTYzNjU2OTc2NjU2NDZlNmYyMDcyNjU2NDY1NjU2ZDIwNzA2MTc5NmQ2NTZlNzQyMDcyNjU2MzY1Njk3NjY1NjQ0ZTZmMjA2OTZlNzQ2NTcyNjU3Mzc0MjA3MjYxNzQ2NTIwNmQ2ZjY0NjU2YzIwNzA3MjY1NzM2NTZlNzQyMDZmNmUyMDc0Njg2NTIwNmQ2ZjZlNjU3OTIwNmQ2MTcyNmI2NTc0NmU2NTc3MjA2MzZmNmQ3MDZmNzU2ZTY0MjA2NjY1NjU3MzIwNjU3ODYzNjU2NTY0MjAzMTMwMzAyNTZlNjU3NzIwNzA2NTcyNjY2ZjcyNmQ2MTZlNjM2NTIwNjY2NTY1NzMyMDY1Nzg2MzY1NjU2NDIwMzEzMDMwMjU2ZDZmNmU2NTc5NWY2ZDYxNzI2YjY1NzQ1Zjc0NmY2YjY1NmU1ZjY5NjQ2NTZlNzQ2OTY2Njk2NTcyNzc3MjYxNzA3MDY1NjQ1ZjY1Njc2YzY0NWY3NDZmNmI2NTZlNWY2OTY0NjU2ZTc0Njk2NjY5NjU3MjYyNmY2ZjczNzQ2NTcyNWY3Mzc0NjE2YjY1NjQ1Zjc0NmY2YjY1NmU1ZjY5NjQ2NTZlNzQ2OTY2Njk2NTcyNmQ2ZjZlNjU3OTVmNmQ2MTcyNmI2NTc0NWY3NTZlNjQ2NTcyNmM3OTY5NmU2NzVmNjk2NDY1NmU3NDY5NjY2OTY1NzI2MzZmNmQ3MDZmNzU2ZTY0NDU2ZTY0NzA2ZjY5NmU3NDIwNjM2MTZlMjA2ZjZlNmM3OTIwNjI2NTIwNjM2MTZjNmM2NTY0MjA2Mjc5MjA2Zjc3NmU2NTcyMDAwMDcwNjE2ZTY5NjMyMDZmNjM2Mzc1NzI3MjY1NjQwMDQxYzg4ZDA4MGIwNDljZmZmZmZmQDA1MDBAMDEwMEAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwQDU3NDU0NzRjNDQyZDYxMzIzODYzMzUzOUAwMDAwMDAwMDAwMDAwMDAwMDUwMGEzYjY2NjkwMmQ1ZjRiYmYwZmY5Mzc0OGZiOTE1YWViNDMxMjRjYmY2NTA5QDAwMDAwMDAwMDAwMDAwMDAwNTAwMzJkZTRmNDBmMTdhMmY0MWM0ZTQwYzIxZjU5NmUzNmE4NDY5OTRlMzY1MDlAMDAwMDAwMDAwMDAwMDAwMDA1MDBmODgzNjY4NmY3YzZjMGYxM2Q3Mjc1MTUxYjc4ZjU5ZjhmMmY3MjlhNjUwOUBAQEBAMDAwMDAwMDAwMDAwMDAwMDA1MDAwYjFlNWIyNDQzMjUwOTU4NDlmNGUzNzEzNDY2MWQ1YmZkY2Q5MjVlN2NlYg==", + "signature": "edf0ec99b6f60414fa5e36d40cfb1d0075d01fd7c4ad7ba59bbe62b8b48eb892beb0c18bba203ff32b83827c3953847b190cdc89a4806f4615565dc2b3b5940f", + "sourceShard": 1, + "destinationShard": 1, + "blockNonce": 2127577, + "blockHash": "e3aea17b5345b45f61b233834d3b4ba0ac6f2b7d53eb3f1b1cf2bf0534ba567f", + "notarizedAtSourceInMetaNonce": 2129029, + "NotarizedAtSourceInMetaHash": "73ee8458f55bf5c9ea4a9974c0c838ced51a236c2b13238761f444598f40575e", + "notarizedAtDestinationInMetaNonce": 2129029, + "notarizedAtDestinationInMetaHash": "73ee8458f55bf5c9ea4a9974c0c838ced51a236c2b13238761f444598f40575e", + "miniblockType": "TxBlock", + "miniblockHash": "cc7e81e68269c2c633daf997fd2d52fc82d8ba3bb699d7e75250008bd9b7aa29", + "hyperblockNonce": 2129029, + "hyperblockHash": "73ee8458f55bf5c9ea4a9974c0c838ced51a236c2b13238761f444598f40575e", + "timestamp": 1707144290, + "status": "success", + "operation": "scDeploy", + "initiallyPaidFee": "82333950000000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + let opt_address = tx_response.new_deployed_address.map(|e| { + multiversx_sdk::data::address::Address::from_bytes(*e.as_array()) + .to_bech32_string() + .unwrap() + }); + + let expected = + Some("erd1qqqqqqqqqqqqqpgqwpdf84ggxzqzmr2zmw959q4nlf9nz562q33sak25ze".to_string()); + + assert_eq!(opt_address, expected) +} + +#[test] +fn test_deployed_address_should_be_none_if_not_a_sc_deployment_tx() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "BuiltInFunctionCall", + "processingTypeOnDestination": "SCInvoking", + "hash": "238ad6dbe75dab1d53caeb9cabd584aabc6fc113c849a983afef5a5e439ce9e5", + "nonce": 13, + "round": 2192628, + "epoch": 888, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgqydwpdrplefjlwp3sp9xmn3vevdxdelfkwmfsw6e5xw", + "sender": "erd179xw6t04ug48m74jzyw9zq028hv66jhqayelzpzvgds0ptnzmckq2jf07f", + "gasPrice": 1000000000, + "gasLimit": 20000000, + "data": "RVNEVFRyYW5zZmVyQDRmNTU1MjRmMmQ2NDM4MzEzNzMxNjZAMDI0NmQyZDBiNmI1ZjBANjI3NTc5QDFiYzE2ZDY3NGVjODAwMDA=", + "signature": "ce984b4d785ccc7aca4b1cdea57ddcd568a502209f81e6b5bc678e1dd52b78d764fe46ea3ff77b926eb9f70eb52ae8f3f2afa2e9d0efa82655e361641458b900", + "sourceShard": 0, + "destinationShard": 1, + "blockNonce": 2129490, + "blockHash": "0ab10909b27565c5b7b59e8e1ee4a68d7046f49225fcde4c12d4b1ea3f512b8a", + "notarizedAtSourceInMetaNonce": 2130938, + "NotarizedAtSourceInMetaHash": "0c545160fd37f09f0196505b9cd2e730596bcd99438978a5bb415b9e1be1849d", + "notarizedAtDestinationInMetaNonce": 2130942, + "notarizedAtDestinationInMetaHash": "1ddd6b7aeeff824b5d11f2936a6284e470fc5abe41e34a8df229b719dc1a537d", + "miniblockType": "TxBlock", + "miniblockHash": "dc8ae41e1ae321c0fccbeb807194d11ff6e0f4ed71163764d850f1daaa60bd22", + "hyperblockNonce": 2130942, + "hyperblockHash": "1ddd6b7aeeff824b5d11f2936a6284e470fc5abe41e34a8df229b719dc1a537d", + "timestamp": 1707155768, + "status": "success", + "tokens": [ + "OURO-d8171f" + ], + "esdtValues": [ + "640821212132848" + ], + "operation": "ESDTTransfer", + "function": "buy", + "initiallyPaidFee": "359390000000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + let opt_address = tx_response.new_deployed_address; + + let expected: Option
= None; + + assert_eq!(opt_address, expected) +} diff --git a/framework/scenario/tests/test_tx_issued_token_identifier.rs b/framework/scenario/tests/test_tx_issued_token_identifier.rs new file mode 100644 index 0000000000..2d0ccffa84 --- /dev/null +++ b/framework/scenario/tests/test_tx_issued_token_identifier.rs @@ -0,0 +1,1422 @@ +use multiversx_sc_scenario::scenario_model::TxResponse; +use multiversx_sdk::data::transaction::{TransactionInfo, TransactionOnNetwork}; + +#[test] +fn test_process_issued_token_identifier_fungible() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", + "nonce": 61, + "round": 173598, + "epoch": 72, + "value": "50000000000000000", + "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "sender": "erd1x39tc3q3nn72ecjnmcz7x0qp09kp97t080x99dgyhx7zh95j0n4szskhlv", + "gasPrice": 1000000000, + "gasLimit": 100000000, + "gasUsed": 100000000, + "data": "aXNzdWVMcFRva2VuQDAwMDAwMDAwMDAwMDAwMDAwNTAwMTM5ZWQ3YWU0YWEwMzc5MmU2YmNiMzMyMzk0YTQwZmU3NDZlZWZhNDdjZWJANDU0NzRjNDQ0ZDQ1NTg0YzUwQDQ1NDc0YzQ0NGQ0NTU4", + "signature": "b5049d2906adc1305a6a8d0f42749254ca6259c6996d9a35e7dc7528b3c87b48a421879aff70bc6d81483a7559b75e5dcf9be499dcb7d57aa9f25c79ac2ad40d", + "sourceShard": 1, + "destinationShard": 1, + "blockNonce": 173354, + "blockHash": "09d85ac264a54e12e7613395211c53fe0ee5a7d3b7111bf5fec1d02794caaacd", + "notarizedAtSourceInMetaNonce": 173321, + "NotarizedAtSourceInMetaHash": "64a83759da97fe8305cd4cda4b518f2d41ef0a8f3995d264460821edad45e09e", + "notarizedAtDestinationInMetaNonce": 173321, + "notarizedAtDestinationInMetaHash": "64a83759da97fe8305cd4cda4b518f2d41ef0a8f3995d264460821edad45e09e", + "miniblockType": "TxBlock", + "miniblockHash": "7f45eee4e35ffc1fbce66b92e4dd2aeae2acb092416aa5aa775b96493256b81d", + "hyperblockNonce": 173321, + "hyperblockHash": "64a83759da97fe8305cd4cda4b518f2d41ef0a8f3995d264460821edad45e09e", + "timestamp": 1695041588, + "smartContractResults": [ + { + "hash": "bce3d0dceb0b3e5c8c5780d7da3755c3f7492d551685d493a73bf66ebd36754b", + "nonce": 0, + "value": 50000000000000000, + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "sender": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "data": "issue@45474c444d45584c50@45474c444d4558@03e8@12@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e4d696e74@74727565@63616e4275726e@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565@65ba30", + "prevTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", + "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", + "gasLimit": 89624222, + "gasPrice": 1000000000, + "callType": 1, + "originalSender": "erd1x39tc3q3nn72ecjnmcz7x0qp09kp97t080x99dgyhx7zh95j0n4szskhlv", + "operation": "transfer", + "function": "issue" + }, + { + "hash": "2a452ff652791d79be5f6933fb583cc5503e876893e54b3b51381a92aa2e904d", + "nonce": 0, + "value": 0, + "receiver": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTSetBurnRoleForAll@45474c444d45582d393563366435", + "prevTxHash": "bce3d0dceb0b3e5c8c5780d7da3755c3f7492d551685d493a73bf66ebd36754b", + "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "logs": { + "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", + "events": [ + { + "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", + "identifier": "completedTxEvent", + "topics": [ + "vOPQ3OsLPlyMV4DX2jdVw/dJLVUWhdSTpzv2br02dUs=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer" + }, + { + "hash": "2c84740ccb3376ea9fa00dab6c6c93fe7a35ee0a1d6dbfa0a1e61064853b0874", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTTransfer@45474c444d45582d393563366435@03e8@00", + "prevTxHash": "bce3d0dceb0b3e5c8c5780d7da3755c3f7492d551685d493a73bf66ebd36754b", + "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", + "gasLimit": 39624222, + "gasPrice": 1000000000, + "callType": 2, + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "identifier": "ESDTTransfer", + "topics": [ + "RUdMRE1FWC05NWM2ZDU=", + "", + "A+g=", + "AAAAAAAAAAAFAO+ux8+3RD51ieGHV10Z68X293CYfOs=" + ], + "data": null, + "additionalData": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "identifier": "completedTxEvent", + "topics": [ + "vOPQ3OsLPlyMV4DX2jdVw/dJLVUWhdSTpzv2br02dUs=" + ], + "data": null, + "additionalData": null + } + ] + }, + "tokens": [ + "EGLDMEX-95c6d5" + ], + "esdtValues": [ + "1000" + ], + "operation": "ESDTTransfer", + "function": "\u0000" + }, + { + "hash": "c9dfc4de3c3cee319123087a4f5dd03cc051e728ec6070707a63ea977b535227", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "sender": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "data": "\u0000", + "prevTxHash": "2c84740ccb3376ea9fa00dab6c6c93fe7a35ee0a1d6dbfa0a1e61064853b0874", + "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", + "gasLimit": 39424222, + "gasPrice": 1000000000, + "callType": 2, + "operation": "transfer", + "function": "\u0000" + }, + { + "hash": "609c3a8e1903680fef1f6d9e47527b1b5c1259664b868af600162120ce0b8192", + "nonce": 1, + "value": 300925400000000, + "receiver": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "sender": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "data": "@6f6b", + "prevTxHash": "2c84740ccb3376ea9fa00dab6c6c93fe7a35ee0a1d6dbfa0a1e61064853b0874", + "originalTxHash": "b78170cc5ca5ba441ea46fe84540db9610ccab243ccd4cd3cd976e170c4864c8", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer", + "isRefund": true + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "identifier": "transferValueOnly", + "topics": [ + "AAAAAAAAAAAFAO+ux8+3RD51ieGHV10Z68X293CYfOs=", + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=", + "saK8LsUAAA==" + ], + "data": null, + "additionalData": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgqa7hv0nahgsl8tz0psat46x0tchm0wuyc0n4s6q28ad", + "identifier": "writeLog", + "topics": [ + "NEq8RBGc/KziU94F4zwBeWwS+W87zFK1BLm8K5aSfOs=" + ], + "data": "QDZmNmI=", + "additionalData": null + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "issueLpToken", + "initiallyPaidFee": "1214335000000000", + "fee": "1214335000000000", + "chainID": "D", + "version": 2, + "options": 0 + } + }, + "error": "", + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Option = Some("EGLDMEX-95c6d5".to_string()); + + assert_eq!(tx_response.new_issued_token_identifier, expected) +} + +#[test] +fn test_process_issued_token_identifier_semi_fungible() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", + "nonce": 65, + "round": 8422527, + "epoch": 584, + "value": "50000000000000000", + "receiver": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "sender": "erd1x3g000ew7zzv6kyqhj9jl2wy5g6cc72qahvvxz29zv76jwq6ssvqt0d998", + "gasPrice": 1000000000, + "gasLimit": 80000000, + "gasUsed": 80000000, + "data": "aXNzdWVUb2tlbkA0NDZmNzA2NTU0NjU3Mzc0QDQ0NGY1MDQ1NTQ0NTUzNTQ=", + "signature": "0191848976e930996f6c62d4921e732f9b0ada8b41ca3b5b63d6bfd304fd44c2a1e8e6643479618ba4a764a36e87f53882b4f707600d5b7d476f2fdd2bac040e", + "sourceShard": 0, + "destinationShard": 0, + "blockNonce": 8420241, + "blockHash": "4d302220f6015876c95e7961b770cc67f8ab63c5f0ab69b4d6c2fb15c8bc23bd", + "notarizedAtSourceInMetaNonce": 8403647, + "NotarizedAtSourceInMetaHash": "f8b83b6d38fa45dacc167b15c93dd07ee5c40db906de34f26e11e7a24f539e30", + "notarizedAtDestinationInMetaNonce": 8403647, + "notarizedAtDestinationInMetaHash": "f8b83b6d38fa45dacc167b15c93dd07ee5c40db906de34f26e11e7a24f539e30", + "miniblockType": "TxBlock", + "miniblockHash": "b7b8fc9f3b81d7daae1113cbf73457e16ee31f3a864ef3729a1a21f3a929e112", + "hyperblockNonce": 8403647, + "hyperblockHash": "f8b83b6d38fa45dacc167b15c93dd07ee5c40db906de34f26e11e7a24f539e30", + "timestamp": 1646652762, + "smartContractResults": [ + { + "hash": "9aecf3bd5dd5c706a28d1cc7059ac20db74340f136816f667dbefcc58daa3aba", + "nonce": 0, + "value": 50000000000000000, + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "sender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "data": "issueSemiFungible@446f706554657374@444f504554455354@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565@5ca148", + "prevTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", + "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", + "gasLimit": 75958360, + "gasPrice": 1000000000, + "callType": 1, + "originalSender": "erd1x3g000ew7zzv6kyqhj9jl2wy5g6cc72qahvvxz29zv76jwq6ssvqt0d998", + "operation": "transfer", + "function": "issueSemiFungible" + }, + { + "hash": "aacfe9088bb9d2d5b3fbe9cab2b2f1c6a7e9cbab2f1a41020e2c819fc9b43570", + "nonce": 66, + "value": 0, + "receiver": "erd1x3g000ew7zzv6kyqhj9jl2wy5g6cc72qahvvxz29zv76jwq6ssvqt0d998", + "sender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "data": "@6f6b", + "prevTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", + "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer" + }, + { + "hash": "3f6f0f3de9e942884e7e1592823a7db7ce935a3f9d3359d8c1ee98a5645332d8", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "@00@444f5045544553542d373732303063", + "prevTxHash": "9aecf3bd5dd5c706a28d1cc7059ac20db74340f136816f667dbefcc58daa3aba", + "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", + "gasLimit": 25958360, + "gasPrice": 1000000000, + "callType": 2, + "originalSender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "identifier": "completedTxEvent", + "topics": [ + "muzzvV3VxwaijRzHBZrCDbdDQPE2gW9mfb78xY2qOro=" + ], + "data": null + } + ] + }, + "operation": "transfer" + }, + { + "hash": "c6e4f7c5da455009fb4f6967ce8a273a97b826aa617fa798ffd0cf17bde6b97a", + "nonce": 1, + "value": 225516180000000, + "receiver": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "sender": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "data": "@6f6b", + "prevTxHash": "3f6f0f3de9e942884e7e1592823a7db7ce935a3f9d3359d8c1ee98a5645332d8", + "originalTxHash": "0634b9c1db9fd6bfa065fc937d51cec37958fd5d33d0c934a0da3d27776a33ae", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer", + "isRefund": true + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "identifier": "transferValueOnly", + "topics": [ + "AAAAAAAAAAAFAH6d74PDz8xLqvowrlOA5lVDBMUghBg=", + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=", + "saK8LsUAAA==" + ], + "data": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgq06w7lq7relxyh2h6xzh98q8x24psf3fqssvqn4ptek", + "identifier": "writeLog", + "topics": [ + "NFD3vy7whM1YgLyLL6nEojWMeUDt2MMJRRM9qTgahBg=" + ], + "data": "QDZmNmI=" + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "issueToken", + "initiallyPaidFee": "914840000000000", + "fee": "914840000000000", + "chainID": "1", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Option = Some("DOPETEST-77200c".to_string()); + + assert_eq!(tx_response.new_issued_token_identifier, expected) +} + +#[test] +fn test_process_issued_token_identifier_non_fungible() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "nonce": 16, + "round": 820170, + "epoch": 341, + "value": "50000000000000000", + "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "sender": "erd162knt53z7m0f9jjms9wxphr3q9d7zu4ky85xs2cc0ekrqz7k4fdq85lkuc", + "gasPrice": 1000000000, + "gasLimit": 200000000, + "gasUsed": 200000000, + "data": "aXNzdWVUb2tlbkA2NzY1NmU2NTdhNzk3M0A0NzQ1NGU=", + "signature": "e80d45f4de419799a2bbff1cae1235521c8eef1853ee45b02f95c2da74ce50d241bf75b6ab0c650245562700862ea9759caad40f3e381ac0c4d82cfe56e67c09", + "sourceShard": 2, + "destinationShard": 2, + "blockNonce": 819313, + "blockHash": "a1db4ef13f07b86678000df9cc78f244d83dcc35ae51de545f333bf616930d39", + "notarizedAtSourceInMetaNonce": 819396, + "NotarizedAtSourceInMetaHash": "6d9e511e46d318aa5b77cbfdfde14d2ce8515ce4e954b286f130a6b518ddf26a", + "notarizedAtDestinationInMetaNonce": 819396, + "notarizedAtDestinationInMetaHash": "6d9e511e46d318aa5b77cbfdfde14d2ce8515ce4e954b286f130a6b518ddf26a", + "miniblockType": "TxBlock", + "miniblockHash": "afdb278522181aeb9b12f08840e6c534e398e6af9c7f757548308e300e7ec4e9", + "hyperblockNonce": 819396, + "hyperblockHash": "6d9e511e46d318aa5b77cbfdfde14d2ce8515ce4e954b286f130a6b518ddf26a", + "timestamp": 1698921020, + "smartContractResults": [ + { + "hash": "6fe0cc002802af1744f394eee4a69224b5e775961d8386e04e7a5b9242f7ff65", + "nonce": 0, + "value": 50000000000000000, + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "sender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "data": "issueNonFungible@67656e657a7973@47454e@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@66616c7365@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@74727565@5e30e4", + "prevTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "gasLimit": 196098365, + "gasPrice": 1000000000, + "callType": 1, + "originalSender": "erd162knt53z7m0f9jjms9wxphr3q9d7zu4ky85xs2cc0ekrqz7k4fdq85lkuc", + "operation": "transfer", + "function": "issueNonFungible" + }, + { + "hash": "98afe82512c79f1caaf171bd5919ee469d11ba0c4f725aefcab834278c0f1e58", + "nonce": 0, + "value": 0, + "receiver": "erd1lllllllllllllllllllllllllllllllllllllllllllllllllupq9x7ny0", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTSetBurnRoleForAll@47454e2d383638353933", + "prevTxHash": "6fe0cc002802af1744f394eee4a69224b5e775961d8386e04e7a5b9242f7ff65", + "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "logs": { + "address": "erd1lllllllllllllllllllllllllllllllllllllllllllllllllupq9x7ny0", + "events": [ + { + "address": "erd1lllllllllllllllllllllllllllllllllllllllllllllllllupq9x7ny0", + "identifier": "completedTxEvent", + "topics": [ + "b+DMACgCrxdE85Tu5KaSJLXndZYdg4bgTnpbkkL3/2U=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer" + }, + { + "hash": "83494ad9369738b574a7266cbfb12ce63ccf634950cd6b0ec16107b8fb42f8f6", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "sender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "data": "setSpecialRole@47454e2d383638353933@00000000000000000500de51fa8943c26e6933419f9bb7ceb79b7ff4f7bbaa5a@45534454526f6c654e4654437265617465@5e30e4", + "prevTxHash": "112d18ec0364b4700b1bfb3df517c80dba547a53373ece2a9e71acd5266e7b64", + "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "gasLimit": 142399698, + "gasPrice": 1000000000, + "callType": 1, + "operation": "transfer", + "function": "setSpecialRole" + }, + { + "hash": "112d18ec0364b4700b1bfb3df517c80dba547a53373ece2a9e71acd5266e7b64", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "@00@47454e2d383638353933", + "prevTxHash": "6fe0cc002802af1744f394eee4a69224b5e775961d8386e04e7a5b9242f7ff65", + "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "gasLimit": 146098365, + "gasPrice": 1000000000, + "callType": 2, + "originalSender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAN5R+olDwm5pM0Gfm7fOt5t/9Pe7qlo=" + ], + "data": "QDZmNmI=", + "additionalData": null + } + ] + }, + "operation": "transfer" + }, + { + "hash": "db5d74970374337956fa61fb4fd90057b3f6a82ea3e259b389934b71a1652e5f", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTSetRole@47454e2d383638353933@45534454526f6c654e4654437265617465", + "prevTxHash": "83494ad9369738b574a7266cbfb12ce63ccf634950cd6b0ec16107b8fb42f8f6", + "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "identifier": "ESDTSetRole", + "topics": [ + "R0VOLTg2ODU5Mw==", + "", + "", + "RVNEVFJvbGVORlRDcmVhdGU=" + ], + "data": null, + "additionalData": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "identifier": "completedTxEvent", + "topics": [ + "g0lK2TaXOLV0pyZsv7Es5jzPY0lQzWsOwWEHuPtC+PY=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "ESDTSetRole", + "function": "ESDTSetRole" + }, + { + "hash": "a6a665f47977a59c4c2baf460281fc938e04ae0f87ac2e78040a14ae27822701", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "@00", + "prevTxHash": "83494ad9369738b574a7266cbfb12ce63ccf634950cd6b0ec16107b8fb42f8f6", + "originalTxHash": "d296186b432d7e7937bde37d725cd52b765ef334c00b95adcb079933bc2277bb", + "gasLimit": 92399698, + "gasPrice": 1000000000, + "callType": 2, + "originalSender": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAN5R+olDwm5pM0Gfm7fOt5t/9Pe7qlo=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gOTIzOTk2OTgsIGdhcyB1c2VkID0gMzE0MTg4MA==" + ], + "data": "QDZmNmI=", + "additionalData": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "identifier": "completedTxEvent", + "topics": [ + "g0lK2TaXOLV0pyZsv7Es5jzPY0lQzWsOwWEHuPtC+PY=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "identifier": "transferValueOnly", + "topics": [ + "AAAAAAAAAAAFAN5R+olDwm5pM0Gfm7fOt5t/9Pe7qlo=", + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=", + "saK8LsUAAA==" + ], + "data": null, + "additionalData": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgqmegl4z2rcfhxjv6pn7dm0n4hndllfaam4fdqwqxld8", + "identifier": "writeLog", + "topics": [ + "0q010iL23pLKW4FcYNxxAVvhcrYh6GgrGH5sMAvWqlo=" + ], + "data": "QDZmNmI=", + "additionalData": null + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "issueToken", + "initiallyPaidFee": "2097020000000000", + "fee": "2097020000000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Option = Some("GEN-868593".to_string()); + + assert_eq!(tx_response.new_issued_token_identifier, expected) +} + +#[test] +fn test_process_issued_token_identifier_meta_esdt() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", + "nonce": 419, + "round": 1787093, + "epoch": 744, + "value": "50000000000000000", + "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "sender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "gasUsed": 157220928, + "data": "ZGVwbG95QXNoc3dhcExQQUNTdHJhdGVneUA0MTRjNTAyZDYzNjE2NTYxNjMzNUA0MTU0NTMyZDM0NjMzMDM5MzIzMEAwM2U4QDAzZThAQDNiOWFjYTAwQDAwMDAwMDAwMDAwMDAwMDAwNTAwOTU3MzkwYWVkYTQzMmY1MmE0MTFkNTE5NzRmZTkzZDQwZDI3NzMzZTA0NjNAMDAwMDAwMDAwMDAwMDAwMDA1MDBkMTJjYzczY2JkYTZmMjY1OWM5NTllNWQ1NzU4YWY5MmNhMTM4NDg2NTIzM0AwMDAwMDAwMDAwMDAwMDAwMDUwMDUxZGY3MTc1OGNmMmFjYTViNDZkZWQ4MTU1OGI1NTE1ZGMyOWYzZjM1MjMzQEAwMDAwMDAwMDAwMDAwMDAwMDUwMDdlNGExZGZjNDM3Y2VkNDlkYjlmMTYzNzk4NDE2Yjg0YWMyMWQ0Yzk3Y2ViMDAwMDAwMGM1NzQ1NDc0YzQ0MmQ2MTMyMzg2MzM1MzkwMDAwMDAwMDAwMDAwMDAwMDUwMGE4YmE5ZTY4NjI2YmJjOTkzZmQ3OTVlOGJiNmY0Nzk0M2IyZjVmZmE3Y2ViMDAwMDAwMGE1NTU0NGIyZDMxMzQ2NDM1Mzc2NEAwMDAwMDAwMTAwMDAwMDAwMDAwMDAwMDAwNTAwNTFkZjcxNzU4Y2YyYWNhNWI0NmRlZDgxNTU4YjU1MTVkYzI5ZjNmMzUyMzMwMDAwMDAwYjQyNTU1MzQ0MmQ2NDM0NjMzMDMxMzQwMDAwMDAwMDAwQDAxODZhMEAyNzEw", + "signature": "4648af0b96eb430e4986b9fb760549742de09c809b46b984e5d995c898d80c25bfc0717c30da34bd89cd3005d98ee895afa39ee588b7b74b4807c63cbeade807", + "sourceShard": 1, + "destinationShard": 1, + "blockNonce": 1785520, + "blockHash": "8f926a5d79fa84bc69949a21bfbba17447091a8a074ac172fa0b88e4475a1214", + "notarizedAtSourceInMetaNonce": 1785568, + "NotarizedAtSourceInMetaHash": "eebd1aa5c3dde083f9c367242c054affedd36bfc95f7bcc1d4e2d90beb5754e9", + "notarizedAtDestinationInMetaNonce": 1785568, + "notarizedAtDestinationInMetaHash": "eebd1aa5c3dde083f9c367242c054affedd36bfc95f7bcc1d4e2d90beb5754e9", + "miniblockType": "TxBlock", + "miniblockHash": "b85d82db6d69cbc1911b3455d2837eeb3170b391926efa2eacb4d9c8e3c96ee4", + "hyperblockNonce": 1785568, + "hyperblockHash": "eebd1aa5c3dde083f9c367242c054affedd36bfc95f7bcc1d4e2d90beb5754e9", + "timestamp": 1704722558, + "smartContractResults": [ + { + "hash": "ea9a96c079e66249e6b73c0341991dad96ca81f855f2fc4abe0d432be117a882", + "nonce": 420, + "value": 4427790720000000, + "receiver": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "data": "@6f6b", + "prevTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", + "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer", + "isRefund": true + }, + { + "hash": "6082975132a2c9d8197dfd0f9852b454ad344740eebdbdf93f620b2796ab723b", + "nonce": 0, + "value": 50000000000000000, + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "data": "registerMetaESDT@415453417368537761704c5041435661756c74@4156415348@12@63616e467265657a65@66616c7365@63616e57697065@66616c7365@63616e5061757365@66616c7365@63616e5472616e736665724e4654437265617465526f6c65@66616c7365@63616e4368616e67654f776e6572@66616c7365@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@74727565@9eb30a87c92674ab1469700c0b385b3850e86de80f87dec6cf3213c7e379a646@408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43@03eb4a30", + "prevTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", + "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", + "gasLimit": 125751600, + "gasPrice": 1000000000, + "callType": 1, + "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "operation": "transfer", + "function": "registerMetaESDT" + }, + { + "hash": "290f85d7ec2f7d5797510290358e9e0f76bb880451efaacb0d69280b8d94c67a", + "nonce": 0, + "value": 0, + "receiver": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTSetBurnRoleForAll@41564153482d376438623564", + "prevTxHash": "6082975132a2c9d8197dfd0f9852b454ad344740eebdbdf93f620b2796ab723b", + "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "logs": { + "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", + "events": [ + { + "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqsl6e366", + "identifier": "completedTxEvent", + "topics": [ + "YIKXUTKiydgZff0PmFK0VK00R0Duvb35P2ILJ5arcjs=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer" + }, + { + "hash": "1aa62a6251edd216bd4e5ae59f7e676d5d2f88597685e0ec0e25ac4434bfccdb", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "@00@41564153482d376438623564@d0644194444642fd16ee156307f6fda0e8f8baf4c496e1a1dc85e027ecc08a4a@9eb30a87c92674ab1469700c0b385b3850e86de80f87dec6cf3213c7e379a646@408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43@00", + "prevTxHash": "6082975132a2c9d8197dfd0f9852b454ad344740eebdbdf93f620b2796ab723b", + "originalTxHash": "408433c5db749f4666bee6a8b599944071bf493c43ff5f01282a74c22ea2ea43", + "gasLimit": 75751600, + "gasPrice": 1000000000, + "callType": 2, + "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAH6UefeHERqHcLpMz2gC3xXGhFsJBGM=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNzU3NTE2MDAsIGdhcyB1c2VkID0gNDE3NjA1OQ==" + ], + "data": "QDZmNmI=", + "additionalData": [ + "QDZmNmI=" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "completedTxEvent", + "topics": [ + "YIKXUTKiydgZff0PmFK0VK00R0Duvb35P2ILJ5arcjs=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=" + ], + "data": "RGVwbG95RnJvbVNvdXJjZQ==", + "additionalData": [ + "RGVwbG95RnJvbVNvdXJjZQ==", + "aW5pdA==", + "QUxQLWNhZWFjNQ==", + "QVRTLTRjMDkyMA==", + "A+g=", + "A+g=", + "", + "O5rKAA==" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFADJ0SE0vUW6bO5SurLeFIMfK/HtBBGM=" + ], + "data": "RGVwbG95RnJvbVNvdXJjZQ==", + "additionalData": [ + "RGVwbG95RnJvbVNvdXJjZQ==", + "aW5pdA==", + "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=", + "AAAAAAAAAAAFAJVzkK7aQy9SpBHVGXT+k9QNJ3M+BGM=", + "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=", + "AAAAAAAAAAAFAFHfcXWM8qyltG3tgVWLVRXcKfPzUjM=", + "", + "AAAAAAAAAAAFAH5KHfxDfO1J258WN5hBa4SsIdTJfOsAAAAMV0VHTEQtYTI4YzU5AAAAAAAAAAAFAKi6nmhia7yZP9eV6LtvR5Q7L1/6fOsAAAAKVVRLLTE0ZDU3ZA==", + "AAAAAQAAAAAAAAAABQBR33F1jPKspbRt7YFVi1UV3Cnz81IzAAAAC0JVU0QtZDRjMDE0AAAAAAA=", + "AYag", + "JxA=" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=" + ], + "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "additionalData": [ + "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "Z2V0RmFybWluZ1Rva2VuSWQ=" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=" + ], + "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "additionalData": [ + "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "Z2V0RmFybVRva2VuSWQ=" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFANEsxzy9pvJlnJWeXVdYr5LKE4SGUjM=" + ], + "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "additionalData": [ + "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "Z2V0UmV3YXJkVG9rZW5JZA==" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "transferValueOnly", + "topics": [ + "saK8LsUAAA==", + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=" + ], + "data": "QXN5bmNDYWxs", + "additionalData": [ + "QXN5bmNDYWxs", + "cmVnaXN0ZXJNZXRhRVNEVA==", + "QVRTQXNoU3dhcExQQUNWYXVsdA==", + "QVZBU0g=", + "Eg==", + "Y2FuRnJlZXpl", + "ZmFsc2U=", + "Y2FuV2lwZQ==", + "ZmFsc2U=", + "Y2FuUGF1c2U=", + "ZmFsc2U=", + "Y2FuVHJhbnNmZXJORlRDcmVhdGVSb2xl", + "ZmFsc2U=", + "Y2FuQ2hhbmdlT3duZXI=", + "ZmFsc2U=", + "Y2FuVXBncmFkZQ==", + "ZmFsc2U=", + "Y2FuQWRkU3BlY2lhbFJvbGVz", + "dHJ1ZQ==" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqxf6ysnf029hfkwu546kt0pfqcl90c76pq33s0a320f", + "identifier": "SCDeploy", + "topics": [ + "AAAAAAAAAAAFADJ0SE0vUW6bO5SurLeFIMfK/HtBBGM=", + "AAAAAAAAAAAFAH6UefeHERqHcLpMz2gC3xXGhFsJBGM=", + "fvRqbue54Womde/CN2IkRGkrx8tsU+xkLvi3+uwMkhY=" + ], + "data": null, + "additionalData": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", + "identifier": "SCDeploy", + "topics": [ + "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=", + "AAAAAAAAAAAFAH6UefeHERqHcLpMz2gC3xXGhFsJBGM=", + "E3blQfRJfCKLWDr06Od703DSZenIzq8KND+xUjmGY/M=" + ], + "data": null, + "additionalData": null + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "deployAshswapLPACStrategy", + "initiallyPaidFee": "6936045000000000", + "fee": "2508254280000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Option = Some("AVASH-7d8b5d".to_string()); + + assert_eq!(tx_response.new_issued_token_identifier, expected) +} + +#[test] +fn test_set_special_roles_should_not_process_issued_token_identifier() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "nonce": 420, + "round": 1787109, + "epoch": 744, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "sender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "gasUsed": 129636807, + "data": "ZmluaXNoVmF1bHREZXBsb3ltZW50cw==", + "signature": "dca943ef1a788bfa6cb0e9aa3900b8340e4908075cbfefaa2a66688f6f0c0fed349edb2eb48eec427cd9098822fba875e4d66072fbdb44cb7f4c1a416736e20c", + "sourceShard": 1, + "destinationShard": 1, + "blockNonce": 1785536, + "blockHash": "93ca539e81612768b67a85b7135f7c104e76bec031a758a6b1782910ae49dd8f", + "notarizedAtSourceInMetaNonce": 1785584, + "NotarizedAtSourceInMetaHash": "71d17afe660282bb42de1ea3eec3e3534a179bd32aa1471c2861ce411bf30552", + "notarizedAtDestinationInMetaNonce": 1785584, + "notarizedAtDestinationInMetaHash": "71d17afe660282bb42de1ea3eec3e3534a179bd32aa1471c2861ce411bf30552", + "miniblockType": "TxBlock", + "miniblockHash": "f8c60565af746e92d2c9c09a92734e5eb8da7e42c67a86854c93b349bfe287eb", + "hyperblockNonce": 1785584, + "hyperblockHash": "71d17afe660282bb42de1ea3eec3e3534a179bd32aa1471c2861ce411bf30552", + "timestamp": 1704722654, + "smartContractResults": [ + { + "hash": "c3ce9c364de3823ffae250c2bfb40aaf2b18f771ed4bd37bf788ad83a2c651f3", + "nonce": 421, + "value": 4703631930000000, + "receiver": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "data": "@6f6b", + "prevTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer", + "isRefund": true + }, + { + "hash": "50f9c25a1402ce6d87ae9f890659c8a67462292e471e02c74d64ff7ba1995e60", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "data": "setSpecialRole@41564153482d376438623564@00000000000000000500d00cc0e63887ff6b792d34234a44e7ac6b575d4b0463@45534454526f6c654e4654437265617465@45534454526f6c654e46544164645175616e74697479@45534454526f6c654e46544275726e@0192c6db2c69f50b6968fb22ac558337a851719519cfd1e6bbf79a07bbcf18bc@cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0@03eb4a30", + "prevTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "gasLimit": 125751600, + "gasPrice": 1000000000, + "callType": 1, + "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "operation": "transfer", + "function": "setSpecialRole" + }, + { + "hash": "d6a5824a60b6c9050462c3f5a02ace00c36e8b4ba1958d132bd394e2ed1e7226", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTSetRole@41564153482d376438623564@45534454526f6c654e4654437265617465@45534454526f6c654e46544164645175616e74697479@45534454526f6c654e46544275726e", + "prevTxHash": "50f9c25a1402ce6d87ae9f890659c8a67462292e471e02c74d64ff7ba1995e60", + "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", + "identifier": "ESDTSetRole", + "topics": [ + "QVZBU0gtN2Q4YjVk", + "", + "", + "RVNEVFJvbGVORlRDcmVhdGU=", + "RVNEVFJvbGVORlRBZGRRdWFudGl0eQ==", + "RVNEVFJvbGVORlRCdXJu" + ], + "data": null, + "additionalData": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgq6qxvpe3csllkk7fdxs3553884344wh2tq33sakulat", + "identifier": "completedTxEvent", + "topics": [ + "UPnCWhQCzm2Hrp+JBlnIpnRiKS5HHgLHTWT/e6GZXmA=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "ESDTSetRole", + "function": "ESDTSetRole" + }, + { + "hash": "bf1b8b4b301ff548368dfd972896489d5e2a088d5cbdfa1bfe2421cc7f641f7a", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "@00@a68d44c751eba85db0713db8dc9c10c78749189ec0d6f1af5fc67bb656c1254b@0192c6db2c69f50b6968fb22ac558337a851719519cfd1e6bbf79a07bbcf18bc@cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0@00", + "prevTxHash": "50f9c25a1402ce6d87ae9f890659c8a67462292e471e02c74d64ff7ba1995e60", + "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "gasLimit": 75751600, + "gasPrice": 1000000000, + "callType": 2, + "originalSender": "erd1j6kua7p67qnaw3y4sudmk25xsuv4k8ws6pwvax8fd2vtmuc3q33s840l87", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=" + ], + "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "additionalData": [ + "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "c2V0U2hhcmVUb2tlbklkZW50aWZpZXI=", + "QVZBU0gtN2Q4YjVk" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=" + ], + "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "additionalData": [ + "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "c2V0U3RyYXRlZ3lBZGRyZXNz", + "AAAAAAAAAAAFADJ0SE0vUW6bO5SurLeFIMfK/HtBBGM=" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "completedTxEvent", + "topics": [ + "UPnCWhQCzm2Hrp+JBlnIpnRiKS5HHgLHTWT/e6GZXmA=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer" + }, + { + "hash": "9d75a398545f488d4764149245e6ec3101debfce99477c353ac11c3239acd897", + "nonce": 1, + "value": 648519550000000, + "receiver": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "sender": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "data": "@6f6b", + "prevTxHash": "bf1b8b4b301ff548368dfd972896489d5e2a088d5cbdfa1bfe2421cc7f641f7a", + "originalTxHash": "cbb1f866da564a04332297dfc4f637be2e50e62bbf4441bf42247ad429747ce0", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer", + "isRefund": true + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq0628nau8zydgwu96fn8ksqklzhrggkcfq33sm4vmwv", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=" + ], + "data": "QXN5bmNDYWxs", + "additionalData": [ + "QXN5bmNDYWxs", + "c2V0U3BlY2lhbFJvbGU=", + "QVZBU0gtN2Q4YjVk", + "AAAAAAAAAAAFANAMwOY4h/9reS00I0pE56xrV11LBGM=", + "RVNEVFJvbGVORlRDcmVhdGU=", + "RVNEVFJvbGVORlRBZGRRdWFudGl0eQ==", + "RVNEVFJvbGVORlRCdXJu" + ] + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "finishVaultDeployments", + "initiallyPaidFee": "6082170000000000", + "fee": "1378538070000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Option = None; + + assert_eq!(tx_response.new_issued_token_identifier, expected) +} + +#[test] +fn test_multisig_issue_nft_and_set_all_roles() { + let data = r#" +{ + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd", + "nonce": 53, + "round": 3050972, + "epoch": 1246, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "sender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "gasPrice": 1000000000, + "gasLimit": 80000000, + "gasUsed": 80000000, + "data": "cGVyZm9ybUFjdGlvbkAwMQ==", + "signature": "cb67645595cee5f7967d8d85af05bb7db73e80d9b97611796819249d87cd174b69b4abfc2a3fbe52df1aec965bdea921f7eb34d2b1118aa480699ad1dc85790a", + "sourceShard": 0, + "destinationShard": 0, + "blockNonce": 2984930, + "blockHash": "644ae8703b826a23e89429953919ec37f875e34a547ea9f7edd53fb71a99c746", + "notarizedAtSourceInMetaNonce": 2988311, + "NotarizedAtSourceInMetaHash": "4f608a72e654dd9f466801cd489be8ee1a73fbcd77b128559cd46182d3b9455a", + "notarizedAtDestinationInMetaNonce": 2988311, + "notarizedAtDestinationInMetaHash": "4f608a72e654dd9f466801cd489be8ee1a73fbcd77b128559cd46182d3b9455a", + "miniblockType": "TxBlock", + "miniblockHash": "c5a73671bc1d37835ddd15b926157721bc83203ec4e00cd48ae0d46015cb5f0b", + "hyperblockNonce": 2988311, + "hyperblockHash": "4f608a72e654dd9f466801cd489be8ee1a73fbcd77b128559cd46182d3b9455a", + "timestamp": 1712305832, + "smartContractResults": [ + { + "hash": "b0b3c8df519c33b314c0ee3d25abae6f17c4432fb3382676ce17a42690811cff", + "nonce": 0, + "value": 50000000000000000, + "receiver": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "sender": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "data": "registerAndSetAllRoles@54657374436f6c6c656374696f6e31@54455354434f4c4c31@4e4654@@98fa4ff554b9c6990ce577fbb816a271f690dcbd6b148f6583fe7692868ae538@08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd@5e2338", + "prevTxHash": "08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd", + "originalTxHash": "08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd", + "gasLimit": 73052300, + "gasPrice": 1000000000, + "callType": 1, + "originalSender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "operation": "transfer", + "function": "registerAndSetAllRoles" + }, + { + "hash": "5ae4f74e134e4fa63c8b92e06ff12b2a4b544233d01d80db6a922af35ee55356", + "nonce": 1, + "value": 196430610000000, + "receiver": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "sender": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "data": "@6f6b", + "prevTxHash": "c4a24b01b48d32308636310e2d335d6ed1f34dcbdfc1133aed7995e78e831c18", + "originalTxHash": "08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer", + "isRefund": true + }, + { + "hash": "7589c1ad622d8a9ab2f186731fc82aeeab0aea5a8198cb94b6eba85a966e7962", + "nonce": 0, + "value": 0, + "receiver": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqq2m3f0f", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTSetBurnRoleForAll@54455354434f4c4c312d356161383063", + "prevTxHash": "b0b3c8df519c33b314c0ee3d25abae6f17c4432fb3382676ce17a42690811cff", + "originalTxHash": "08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "originalSender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "logs": { + "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqq2m3f0f", + "events": [ + { + "address": "erd1llllllllllllllllllllllllllllllllllllllllllllllllluqq2m3f0f", + "identifier": "completedTxEvent", + "topics": [ + "sLPI31GcM7MUwO49JauubxfEQy+zOCZ2zhekJpCBHP8=" + ] + } + ] + }, + "operation": "transfer" + }, + { + "hash": "86d1ec3365ea1311dbde2f2366de4ea8627d7e49c29a974578c0869b66903cbc", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "ESDTSetRole@54455354434f4c4c312d356161383063@45534454526f6c654e4654437265617465@45534454526f6c654e46544275726e@45534454526f6c654e465455706461746541747472696275746573@45534454526f6c654e4654416464555249", + "prevTxHash": "b0b3c8df519c33b314c0ee3d25abae6f17c4432fb3382676ce17a42690811cff", + "originalTxHash": "08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "originalSender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "ESDTSetRole", + "topics": [ + "VEVTVENPTEwxLTVhYTgwYw==", + "", + "", + "RVNEVFJvbGVORlRDcmVhdGU=", + "RVNEVFJvbGVORlRCdXJu", + "RVNEVFJvbGVORlRVcGRhdGVBdHRyaWJ1dGVz", + "RVNEVFJvbGVORlRBZGRVUkk=" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "completedTxEvent", + "topics": [ + "sLPI31GcM7MUwO49JauubxfEQy+zOCZ2zhekJpCBHP8=" + ] + } + ] + }, + "operation": "ESDTSetRole", + "function": "ESDTSetRole" + }, + { + "hash": "c4a24b01b48d32308636310e2d335d6ed1f34dcbdfc1133aed7995e78e831c18", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "sender": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + "data": "@00@54455354434f4c4c312d356161383063@3ec73c55022548038bbe06c0639156b3db70b7c770955e340f14fcfcd45df06a@98fa4ff554b9c6990ce577fbb816a271f690dcbd6b148f6583fe7692868ae538@08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd@00", + "prevTxHash": "b0b3c8df519c33b314c0ee3d25abae6f17c4432fb3382676ce17a42690811cff", + "originalTxHash": "08582bc19734ad82d7390be88463c948e5d9f026f4b8f0bfc57620957c3433bd", + "gasLimit": 23052300, + "gasPrice": 1000000000, + "callType": 2, + "originalSender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "callBack", + "topics": [ + "YXN5bmNDYWxsU3VjY2Vzcw==", + "VEVTVENPTEwxLTVhYTgwYw==" + ], + "additionalData": [ + "" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "completedTxEvent", + "topics": [ + "sLPI31GcM7MUwO49JauubxfEQy+zOCZ2zhekJpCBHP8=" + ] + } + ] + }, + "operation": "transfer" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "performAction", + "topics": [ + "c3RhcnRQZXJmb3JtQWN0aW9u" + ], + "data": "AAAAAQYAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAL//wAAAAexorwuxQAAAAAAFnJlZ2lzdGVyQW5kU2V0QWxsUm9sZXMAAAAEAAAAD1Rlc3RDb2xsZWN0aW9uMQAAAAlURVNUQ09MTDEAAAADTkZUAAAAAAAAAATjKv7ckE/hk5dGrZc76zg1Y89jZCumabMED5uUKKXtYLE6AXQjw2bK/4zs+3ehJhChMPSIgTQSLHk3/q4NbX0XOvjZyUI7JXfGJSciwdkCEqQRH3ID+XRPdvz6HQoxADOyoRVVzlIeSUTgmrF1SdhbSH3NJshLUBejnjGjZwiJug==", + "additionalData": [ + "AAAAAQYAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAL//wAAAAexorwuxQAAAAAAFnJlZ2lzdGVyQW5kU2V0QWxsUm9sZXMAAAAEAAAAD1Rlc3RDb2xsZWN0aW9uMQAAAAlURVNUQ09MTDEAAAADTkZUAAAAAAAAAATjKv7ckE/hk5dGrZc76zg1Y89jZCumabMED5uUKKXtYLE6AXQjw2bK/4zs+3ehJhChMPSIgTQSLHk3/q4NbX0XOvjZyUI7JXfGJSciwdkCEqQRH3ID+XRPdvz6HQoxADOyoRVVzlIeSUTgmrF1SdhbSH3NJshLUBejnjGjZwiJug==" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "performAction", + "topics": [ + "cGVyZm9ybUFzeW5jQ2FsbA==", + "AQ==", + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=", + "saK8LsUAAA==", + "BGa4HQ==", + "cmVnaXN0ZXJBbmRTZXRBbGxSb2xlcw==", + "VGVzdENvbGxlY3Rpb24x", + "VEVTVENPTEwx", + "TkZU", + "" + ], + "additionalData": [ + "" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "transferValueOnly", + "topics": [ + "saK8LsUAAA==", + "AAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAC//8=" + ], + "data": "QXN5bmNDYWxs", + "additionalData": [ + "QXN5bmNDYWxs", + "cmVnaXN0ZXJBbmRTZXRBbGxSb2xlcw==", + "VGVzdENvbGxlY3Rpb24x", + "VEVTVENPTEwx", + "TkZU", + "" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqrp3n58vp2dmcaur4whazxngvuhac4xwqa4sq2pjl73", + "identifier": "writeLog", + "topics": [ + "4yr+3JBP4ZOXRq2XO+s4NWPPY2QrpmmzBA+blCil7WA=" + ], + "data": "QDZmNmI=", + "additionalData": [ + "QDZmNmI=" + ] + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "performAction", + "initiallyPaidFee": "873260000000000", + "fee": "873260000000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "code": "successful" +} + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected = Some("TESTCOLL1-5aa80c".to_string()); + + assert_eq!(tx_response.new_issued_token_identifier, expected) +} diff --git a/framework/scenario/tests/test_tx_multi_contract_sc_result.rs b/framework/scenario/tests/test_tx_multi_contract_sc_result.rs new file mode 100644 index 0000000000..8d45dfff0c --- /dev/null +++ b/framework/scenario/tests/test_tx_multi_contract_sc_result.rs @@ -0,0 +1,477 @@ +use multiversx_sc_scenario::scenario_model::TxResponse; +use multiversx_sdk::data::transaction::{TransactionInfo, TransactionOnNetwork}; + +#[test] +fn test_with_multi_contract_same_shard_tx_that_has_no_sc_result() { + // transaction data from the devnet + // context : user -> A --call--> B, B returns a MultiValue2, A returns the B's returned value + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "e914857f1bfd003ba411bae372266703e5f706fa412c378feb37faa5e18c3d73", + "nonce": 49, + "round": 7646960, + "epoch": 6339, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", + "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "gasUsed": 600000000, + "data": "Y2FsbEFub3RoZXJDb250cmFjdFJldHVyblR3b1U2NEAwMDAwMDAwMDAwMDAwMDAwMDUwMEFDRkY2QjdBNEVCODEwMUE4REU3RkY3RjVEMkMwQkYzRTRENjNGNDdBNzND", + "signature": "53cc6496647287d735bd7950f4ec79d7b51f884defda1d6d840d722b7d0d869900ccecc01602da7a7c717955e8d4ed0711b92acd980d64ed6eebd6eaed0c4608", + "sourceShard": 0, + "destinationShard": 0, + "blockNonce": 7600794, + "blockHash": "77eb0904e56d6dd596c0d72821cf33b326fde383e72903ca4df5c2f200b0ea75", + "notarizedAtSourceInMetaNonce": 7609344, + "NotarizedAtSourceInMetaHash": "12df3fe65cacde2c9742b9506ac2261d34f3c72d690301192fd8016430d51913", + "notarizedAtDestinationInMetaNonce": 7609344, + "notarizedAtDestinationInMetaHash": "12df3fe65cacde2c9742b9506ac2261d34f3c72d690301192fd8016430d51913", + "miniblockType": "TxBlock", + "miniblockHash": "03219ac7427f7511687f0768c722c759c1b1428b2664b44a0cbe2072154851ee", + "hyperblockNonce": 7609344, + "hyperblockHash": "12df3fe65cacde2c9742b9506ac2261d34f3c72d690301192fd8016430d51913", + "timestamp": 1694433360, + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", + "identifier": "writeLog", + "topics": [ + "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk5ODA2MDAwLCBnYXMgdXNlZCA9IDM4NDcyNDA=" + ], + "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" + }, + { + "address": "erd1qqqqqqqqqqqqqpgqshqmekudxlxwp0d9j368etjamr5dw7k45u7qx40w6h", + "identifier": "completedTxEvent", + "topics": [ + "6RSFfxv9ADukEbrjciZnA+X3BvpBLDeP6zf6peGMPXM=" + ], + "data": null + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "callAnotherContractReturnTwoU64", + "initiallyPaidFee": "6192060000000000", + "fee": "6192060000000000", + "chainID": "D", + "version": 2, + "options": 0 + } + }, + "error": "", + "code": "successful" + } + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Vec> = vec![ + hex::decode("0a").unwrap(), + hex::decode("0218711a00").unwrap(), + ]; + + assert_eq!(tx_response.out, expected) +} + +#[test] +fn test_with_multi_contract_cross_shard_tx_that_has_no_callback() { + // transaction data from the devnet + // context : user -> A --async call--> B, no callback + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", + "nonce": 51, + "round": 7647523, + "epoch": 6340, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "gasUsed": 600000000, + "data": "YXN5bmNDYWxsQW5vdGhlckNvbnRyYWN0UmV0dXJuVHdvVTY0Tm9DYWxsYmFja0AwMDAwMDAwMDAwMDAwMDAwMDUwMEFDRkY2QjdBNEVCODEwMUE4REU3RkY3RjVEMkMwQkYzRTRENjNGNDdBNzND", + "signature": "0fc30cddaa8e5365662a14344e3434cbccf287f357be99b3ed4add182f64dded774ec0d095ab1589e7c6c07e00de3b7239efc96eb2e0e97b48c1ef87084cec01", + "sourceShard": 0, + "destinationShard": 1, + "blockNonce": 7593758, + "blockHash": "a828c0ca58ef1c8aff60e512ab59f18204f1915d4a6c8285cfceb1c5725b88e8", + "notarizedAtSourceInMetaNonce": 7609903, + "NotarizedAtSourceInMetaHash": "4e90fe45c2fdccd5cf6977c1422e5f4ffa41c4e9f31fb4a50c20455f87df1e99", + "notarizedAtDestinationInMetaNonce": 7609907, + "notarizedAtDestinationInMetaHash": "10b8666a44411c3babbe20af7154fb3d47efcb1cb10d955523ec68fece26e517", + "miniblockType": "TxBlock", + "miniblockHash": "4ff4bb1ac88911d617c9b0342aeb5158db78490c2fe414cad08adcc584a77be7", + "hyperblockNonce": 7609907, + "hyperblockHash": "10b8666a44411c3babbe20af7154fb3d47efcb1cb10d955523ec68fece26e517", + "timestamp": 1694436738, + "smartContractResults": [ + { + "hash": "462b56a1530e6070dc7c15f755e51a97a6972c8cd7891f3be4635b93211890c5", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "sender": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "data": "@00@0a@0218711a00", + "prevTxHash": "41d56fdacf3e14de67e821427c732b62ebfa07c82d2e5db6de75fe3a1c828d9b", + "originalTxHash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", + "gasLimit": 595637825, + "gasPrice": 1000000000, + "callType": 2, + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAP/Aj4ZNGKlpx2+xeJLdoJbREzb20P0=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk1NjM3ODI1LCBnYXMgdXNlZCA9IDIxNjE3NzA=" + ], + "data": "QDZmNmI=" + }, + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "completedTxEvent", + "topics": [ + "QdVv2s8+FN5n6CFCfHMrYuv6B8gtLl223nX+OhyCjZs=" + ], + "data": null + } + ] + }, + "operation": "transfer" + }, + { + "hash": "41d56fdacf3e14de67e821427c732b62ebfa07c82d2e5db6de75fe3a1c828d9b", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "sender": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "data": "returnTwoU64@4f3c60", + "prevTxHash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", + "originalTxHash": "4d50a055663dfee2479851684d7fb83cf00695b6f03f4dbbdf0f9232477cafc4", + "gasLimit": 597479490, + "gasPrice": 1000000000, + "callType": 1, + "operation": "transfer", + "function": "returnTwoU64" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "writeLog", + "topics": [ + "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=" + ], + "data": "QDZmNmI=" + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "asyncCallAnotherContractReturnTwoU64NoCallback", + "initiallyPaidFee": "6214335000000000", + "fee": "6214335000000000", + "chainID": "D", + "version": 2, + "options": 0 + } + }, + "error": "", + "code": "successful" + } + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Vec> = vec![]; + + assert_eq!(tx_response.out, expected) +} + +#[test] +fn test_with_multi_contract_cross_shard_tx_that_has_non_returning_callback() { + // transaction data from the devnet + // context : user -> A --async call--> B --callback--> A, the callback returns () + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", + "nonce": 52, + "round": 7647560, + "epoch": 6340, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "gasUsed": 600000000, + "data": "YXN5bmNDYWxsQW5vdGhlckNvbnRyYWN0UmV0dXJuVHdvVTY0V2l0aE5vblJldHVybmluZ0NhbGxiYWNrQDAwMDAwMDAwMDAwMDAwMDAwNTAwQUNGRjZCN0E0RUI4MTAxQThERTdGRjdGNUQyQzBCRjNFNEQ2M0Y0N0E3M0M=", + "signature": "3918fce429b2059b2321b709011079755dbb835e12839278ee510e4741180540e80c6111eea1d3312b2c63446de08b20e01f6040358fa94d1633c355bb65bc0f", + "sourceShard": 0, + "destinationShard": 1, + "blockNonce": 7593795, + "blockHash": "c17e727f90025225670b7852ea9807c67753c9b3f21b6ec7cc40077e3849a8b7", + "notarizedAtSourceInMetaNonce": 7609940, + "NotarizedAtSourceInMetaHash": "c67b5c550986cfd6c94d00f4b90234eb38ee196ff0d79a00d916f3bd24be272c", + "notarizedAtDestinationInMetaNonce": 7609944, + "notarizedAtDestinationInMetaHash": "d59b7398d962ce3119679af59d5d74e10083e62c3ee2b15421cc0d607979ca18", + "miniblockType": "TxBlock", + "miniblockHash": "2977affeffeb6cf41117bed442662021cb713528cdb1d0dce4537b01caeb8e0b", + "hyperblockNonce": 7609944, + "hyperblockHash": "d59b7398d962ce3119679af59d5d74e10083e62c3ee2b15421cc0d607979ca18", + "timestamp": 1694436960, + "smartContractResults": [ + { + "hash": "fe7474188d5ca4b84c7577f03fc778d22d53c070dfcb05a9cda840229d30e4d3", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "sender": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "data": "returnTwoU64@4f3c60", + "prevTxHash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", + "originalTxHash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", + "gasLimit": 596979545, + "gasPrice": 1000000000, + "callType": 1, + "operation": "transfer", + "function": "returnTwoU64" + }, + { + "hash": "948dc6702b376d1e043db8de2f87ca12907c342f54cfad7dfebadf59145ca3ac", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "sender": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "data": "@00@0a@0218711a00", + "prevTxHash": "fe7474188d5ca4b84c7577f03fc778d22d53c070dfcb05a9cda840229d30e4d3", + "originalTxHash": "4f7f19e448176e4d47a0f844cbd6bdb1b6c68035dafe927e8249ed60af1c3b17", + "gasLimit": 595137880, + "gasPrice": 1000000000, + "callType": 2, + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAP/Aj4ZNGKlpx2+xeJLdoJbREzb20P0=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk1MTM3ODgwLCBnYXMgdXNlZCA9IDIyODg1NTA=" + ], + "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" + }, + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "completedTxEvent", + "topics": [ + "/nR0GI1cpLhMdXfwP8d40i1TwHDfywWpzahAIp0w5NM=" + ], + "data": null + } + ] + }, + "operation": "transfer" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "writeLog", + "topics": [ + "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=" + ], + "data": "QDZmNmI=" + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "asyncCallAnotherContractReturnTwoU64WithNonReturningCallback", + "initiallyPaidFee": "6235125000000000", + "fee": "6235125000000000", + "chainID": "D", + "version": 2, + "options": 0 + } + }, + "error": "", + "code": "successful" + } + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Vec> = vec![]; + + assert_eq!(tx_response.out, expected) +} + +#[test] +fn test_with_multi_contract_cross_shard_tx_that_has_returning_callback() { + // transaction data from the devnet + // context : user -> A --async call--> B --callback--> A, the callback returns a MultiValue2 + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", + "nonce": 53, + "round": 7647583, + "epoch": 6340, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "gasUsed": 600000000, + "data": "YXN5bmNDYWxsQW5vdGhlckNvbnRyYWN0UmV0dXJuVHdvVTY0V2l0aFJldHVybmluZ0NhbGxiYWNrQDAwMDAwMDAwMDAwMDAwMDAwNTAwQUNGRjZCN0E0RUI4MTAxQThERTdGRjdGNUQyQzBCRjNFNEQ2M0Y0N0E3M0M=", + "signature": "858958d4aaf9cb0220ab2933edad3f65e1cb4c58aa7940cb0f40b489d0bd9fdf5c4736a40d6e813743ee622bb91e9f86eacf01b9a31e0ff53f9c84f13c500304", + "sourceShard": 0, + "destinationShard": 1, + "blockNonce": 7593818, + "blockHash": "b19f97110ca38d3cb15f802a00ab403491b0e5804ebc701527ab50064dc06825", + "notarizedAtSourceInMetaNonce": 7609963, + "NotarizedAtSourceInMetaHash": "4d9db6de610ca778114d44fe91dd036fac7c375c373ae9e77130d3fb9efc8391", + "notarizedAtDestinationInMetaNonce": 7609967, + "notarizedAtDestinationInMetaHash": "a4573d388c31860f9bd6f9507b65d1b3130e445abcada538f10704feba4614e7", + "miniblockType": "TxBlock", + "miniblockHash": "530f5fa3c7af474a187caca8dcea02a7a155017414147871d083bed5c49ec8f5", + "hyperblockNonce": 7609967, + "hyperblockHash": "a4573d388c31860f9bd6f9507b65d1b3130e445abcada538f10704feba4614e7", + "timestamp": 1694437098, + "smartContractResults": [ + { + "hash": "065291164a8acd27c26b5a8f09664810081fda18cd54fca635196cf9b200297a", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "sender": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "data": "returnTwoU64@4f3c60", + "prevTxHash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", + "originalTxHash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", + "gasLimit": 596994205, + "gasPrice": 1000000000, + "callType": 1, + "operation": "transfer", + "function": "returnTwoU64" + }, + { + "hash": "bc31cb153ae615204625df84fe9ae3a159aa412b7342f3dca958dd5517a08197", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "sender": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "data": "@00@0a@0218711a00", + "prevTxHash": "065291164a8acd27c26b5a8f09664810081fda18cd54fca635196cf9b200297a", + "originalTxHash": "f34e136ca81c0e32f6fb532b753612715675073f3718b5db009bb275d246fd7a", + "gasLimit": 595152540, + "gasPrice": 1000000000, + "callType": 2, + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAP/Aj4ZNGKlpx2+xeJLdoJbREzb20P0=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk1MTUyNTQwLCBnYXMgdXNlZCA9IDIyODgwMTU=" + ], + "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" + }, + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "completedTxEvent", + "topics": [ + "BlKRFkqKzSfCa1qPCWZIEAgf2hjNVPymNRls+bIAKXo=" + ], + "data": null + } + ] + }, + "operation": "transfer" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqllqglpjdrz5kn3m0k9uf9hdqjmg3xdhk6r7se3wvlk", + "identifier": "writeLog", + "topics": [ + "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=" + ], + "data": "QDZmNmI=" + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "asyncCallAnotherContractReturnTwoU64WithReturningCallback", + "initiallyPaidFee": "6230670000000000", + "fee": "6230670000000000", + "chainID": "D", + "version": 2, + "options": 0 + } + }, + "error": "", + "code": "successful" + } + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Vec> = vec![]; + + assert_eq!(tx_response.out, expected) +} diff --git a/framework/scenario/tests/test_tx_multiple_sc_results.rs b/framework/scenario/tests/test_tx_multiple_sc_results.rs new file mode 100644 index 0000000000..6322b0a7bb --- /dev/null +++ b/framework/scenario/tests/test_tx_multiple_sc_results.rs @@ -0,0 +1,287 @@ +use multiversx_sc_scenario::scenario_model::{is_out_scr, TxResponse}; +use multiversx_sdk::data::transaction::{TransactionInfo, TransactionOnNetwork}; + +#[test] +fn test_transaction_multiple_sc_results() { + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "BuiltInFunctionCall", + "processingTypeOnDestination": "SCInvoking", + "hash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "nonce": 236, + "round": 3353069, + "epoch": 1371, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "sender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "gasPrice": 1000000000, + "gasLimit": 100000000, + "gasUsed": 12767998, + "data": "RVNEVFRyYW5zZmVyQDU1NTQ0YjJkMzEzNDY0MzUzNzY0QDhhYzcyMzA0ODllODAwMDBANzM3NzYxNzA1NDZmNmI2NTZlNzM0NjY5Nzg2NTY0NDk2ZTcwNzU3NEA1NzQ1NDc0YzQ0MmQ2MTMyMzg2MzM1MzlAZThkNGE1MTAwMA==", + "signature": "caed340339e3ae17a92783f5f08f96ac875885e44c25510cd11251ce23f22994985a6605c4d36f841b7110288a5e928f624f150a66a9de8ade36b68028a9af09", + "sourceShard": 0, + "destinationShard": 1, + "blockNonce": 3288476, + "blockHash": "0e70ea5fb26c58b1029c84e24eb9a661272b6253d30c668af91f167bfd67b2b0", + "notarizedAtSourceInMetaNonce": 3290316, + "NotarizedAtSourceInMetaHash": "8200662ca3ade8fa8e1dd3a4184b0a74d4c43de8f4153170a506f60c94ad3e8b", + "notarizedAtDestinationInMetaNonce": 3290320, + "notarizedAtDestinationInMetaHash": "e5f332a8f2070fd1c4ff90f5dc1ee691f36e4ecb9cb5c37e8e7c8595036c3792", + "miniblockType": "TxBlock", + "miniblockHash": "d271ad87c6cf8653cc950272f3ee5e976820ada80468518fa35fe45b6e33dca8", + "hyperblockNonce": 3290320, + "hyperblockHash": "e5f332a8f2070fd1c4ff90f5dc1ee691f36e4ecb9cb5c37e8e7c8595036c3792", + "timestamp": 1714118414, + "smartContractResults": [ + { + "hash": "c0e63f1018ece1036e3e6dc405553e5f6badfe0f5d2a104f4cd4457a872d02f9", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "sender": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "data": "swapTokensFixedInput@5745474c442d613238633539@e8d4a51000", + "prevTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "originalTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "gasLimit": 99559500, + "gasPrice": 1000000000, + "callType": 0, + "originalSender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "operation": "transfer", + "function": "swapTokensFixedInput" + }, + { + "hash": "40078cec63b6e0d0d9522ea5e6d2d0cb6f21ebae981f354de3dc3545ac2928ad", + "nonce": 0, + "value": 0, + "receiver": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "sender": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "data": "ESDTTransfer@5745474c442d613238633539@9b35e4dd3902b9", + "prevTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "originalTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "originalSender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "logs": { + "address": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "identifier": "ESDTTransfer", + "topics": [ + "V0VHTEQtYTI4YzU5", + "", + "mzXk3TkCuQ==", + "4yr+3JBP4ZOXRq2XO+s4NWPPY2QrpmmzBA+blCil7WA=" + ], + "data": null, + "additionalData": [ + "", + "RVNEVFRyYW5zZmVy", + "V0VHTEQtYTI4YzU5", + "mzXk3TkCuQ==" + ] + }, + { + "address": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAKi6nmhia7yZP9eV6LtvR5Q7L1/6fOs=" + ], + "data": "QDZmNmI=", + "additionalData": [ + "QDZmNmI=" + ] + }, + { + "address": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "identifier": "completedTxEvent", + "topics": [ + "xtxxjFbIeVFW2Ef0+XaPKxl2pRbTkP3OD1uLrRrDzOU=" + ], + "data": null, + "additionalData": null + } + ] + }, + "tokens": [ + "WEGLD-a28c59" + ], + "esdtValues": [ + "43687878470468281" + ], + "operation": "ESDTTransfer" + }, + { + "hash": "26487a550721b8282ceafe603bb4d53ee93929ffd9ded39b08e7422adb4d8795", + "nonce": 237, + "value": 872320020000000, + "receiver": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "sender": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "data": "@6f6b@0000000c5745474c442d6132386335390000000000000000000000079b35e4dd3902b9", + "prevTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "originalTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "logs": { + "address": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "events": [ + { + "address": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "identifier": "completedTxEvent", + "topics": [ + "xtxxjFbIeVFW2Ef0+XaPKxl2pRbTkP3OD1uLrRrDzOU=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer", + "isRefund": true + }, + { + "hash": "798ba4333a7cedb62f811d942dedb8c0c09bf9945a0d2ccede2eaed967eba135", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqw88ux2l44eufvwz2uhvduhq03g8pxc4j0n4s0frzjz", + "sender": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "data": "ESDTTransfer@55544b2d313464353764@2d79883d2000@6465706f7369745377617046656573", + "prevTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "originalTxHash": "c6dc718c56c8795156d847f4f9768f2b1976a516d390fdce0f5b8bad1ac3cce5", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "originalSender": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "tokens": [ + "UTK-14d57d" + ], + "esdtValues": [ + "50000000000000" + ], + "operation": "ESDTTransfer", + "function": "depositSwapFees" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "events": [ + { + "address": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa", + "identifier": "ESDTTransfer", + "topics": [ + "VVRLLTE0ZDU3ZA==", + "", + "iscjBInoAAA=", + "AAAAAAAAAAAFAKi6nmhia7yZP9eV6LtvR5Q7L1/6fOs=" + ], + "data": null, + "additionalData": [ + "", + "RVNEVFRyYW5zZmVy", + "VVRLLTE0ZDU3ZA==", + "iscjBInoAAA=", + "c3dhcFRva2Vuc0ZpeGVkSW5wdXQ=", + "V0VHTEQtYTI4YzU5", + "6NSlEAA=" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "identifier": "ESDTTransfer", + "topics": [ + "VVRLLTE0ZDU3ZA==", + "", + "LXmIPSAA", + "AAAAAAAAAAAFAHHPwyv1rniWOErl2N5cD4oOE2KyfOs=" + ], + "data": "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "additionalData": [ + "RXhlY3V0ZU9uRGVzdENvbnRleHQ=", + "RVNEVFRyYW5zZmVy", + "VVRLLTE0ZDU3ZA==", + "LXmIPSAA", + "ZGVwb3NpdFN3YXBGZWVz" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqw88ux2l44eufvwz2uhvduhq03g8pxc4j0n4s0frzjz", + "identifier": "depositSwapFees", + "topics": [ + "ZGVwb3NpdF9zd2FwX2ZlZXNfZXZlbnQ=", + "AAAAAAAAAAAFAKi6nmhia7yZP9eV6LtvR5Q7L1/6fOs=", + "ug==", + "AAAAClVUSy0xNGQ1N2QAAAAAAAAAAAAAAAYteYg9IAA=" + ], + "data": null, + "additionalData": [ + "" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "identifier": "ESDTTransfer", + "topics": [ + "V0VHTEQtYTI4YzU5", + "", + "mzXk3TkCuQ==", + "4yr+3JBP4ZOXRq2XO+s4NWPPY2QrpmmzBA+blCil7WA=" + ], + "data": "RGlyZWN0Q2FsbA==", + "additionalData": [ + "RGlyZWN0Q2FsbA==", + "RVNEVFRyYW5zZmVy", + "V0VHTEQtYTI4YzU5", + "mzXk3TkCuQ==" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgq4zafu6rzdw7fj07hjh5tkm68jsaj7hl60n4s8py4ra", + "identifier": "swapTokensFixedInput", + "topics": [ + "c3dhcA==", + "VVRLLTE0ZDU3ZA==", + "V0VHTEQtYTI4YzU5", + "4yr+3JBP4ZOXRq2XO+s4NWPPY2QrpmmzBA+blCil7WA=", + "BVs=" + ], + "data": "4yr+3JBP4ZOXRq2XO+s4NWPPY2QrpmmzBA+blCil7WAAAAAKVVRLLTE0ZDU3ZAAAAAiKxyMEiegAAAAAAAxXRUdMRC1hMjhjNTkAAAAHmzXk3TkCuQAAAAcjhvJvwQAAAAAACwGBykedC25GCD5kAAAACgGwxHNBlOj27dQAAAAAADItnAAAAAAAAAVbAAAAAGYrXw4=", + "additionalData": [ + "4yr+3JBP4ZOXRq2XO+s4NWPPY2QrpmmzBA+blCil7WAAAAAKVVRLLTE0ZDU3ZAAAAAiKxyMEiegAAAAAAAxXRUdMRC1hMjhjNTkAAAAHmzXk3TkCuQAAAAcjhvJvwQAAAAAACwGBykedC25GCD5kAAAACgGwxHNBlOj27dQAAAAAADItnAAAAAAAAAVbAAAAAGYrXw4=" + ] + } + ] + }, + "status": "success", + "tokens": [ + "UTK-14d57d" + ], + "esdtValues": [ + "10000000000000000000" + ], + "operation": "ESDTTransfer", + "function": "swapTokensFixedInput", + "initiallyPaidFee": "1238095000000000", + "fee": "365774980000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" + }"#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + assert_eq!(tx_response.api_scrs.len(), 4usize); + assert!(is_out_scr(&tx_response.api_scrs.get(2).unwrap())); +} diff --git a/framework/scenario/tests/test_tx_sc_result.rs b/framework/scenario/tests/test_tx_sc_result.rs new file mode 100644 index 0000000000..561712300c --- /dev/null +++ b/framework/scenario/tests/test_tx_sc_result.rs @@ -0,0 +1,350 @@ +use multiversx_sc_scenario::scenario_model::TxResponse; +use multiversx_sdk::data::transaction::{TransactionInfo, TransactionOnNetwork}; + +#[test] +fn test_with_tx_that_has_sc_result() { + // transaction data from the devnet, an artificial "10" result has been appended on the original result + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "BuiltInFunctionCall", + "processingTypeOnDestination": "SCInvoking", + "hash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "nonce": 30, + "round": 7639115, + "epoch": 6333, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "sender": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "gasPrice": 1000000000, + "gasLimit": 25500000, + "gasUsed": 15297149, + "data": "RVNEVFRyYW5zZmVyQDQ4NTQ0ZDJkNjY2NTMxNjYzNjM5QDBkZTBiNmIzYTc2NDAwMDBANzM3NzYxNzA1NDZmNmI2NTZlNzM0NjY5Nzg2NTY0NDk2ZTcwNzU3NEA1NzQ1NDc0YzQ0MmQ2NDM3NjMzNjYyNjJAMDM3Yzc3OGZjY2U5YzU1Yg==", + "signature": "e912fae4b7a9e51ddf316a5e82a0f457d453a62e3c17477f5d6175e1b33c5e92ddb187d65f54cf3131a0603321290279a0456c20778039f2ab09b54e33c60f0d", + "sourceShard": 2, + "destinationShard": 1, + "blockNonce": 7585351, + "blockHash": "e456f38f11fec78ed26d5fda068e912739dceedb2e5ce559bf17614b8386c039", + "notarizedAtSourceInMetaNonce": 7601495, + "NotarizedAtSourceInMetaHash": "e28c6011d4b3f73f3945cae70ff251e675dfea331a70077c5ab3310e3101af17", + "notarizedAtDestinationInMetaNonce": 7601499, + "notarizedAtDestinationInMetaHash": "333d4266614e981cc1c5654f85ef496038a8cddac46dfc0ad0b7c44c37ab489d", + "miniblockType": "TxBlock", + "miniblockHash": "13e041f32fde79ebf1abdcfe692e99516f9ec6778dcb917251b440daa7f1210a", + "hyperblockNonce": 7601499, + "hyperblockHash": "333d4266614e981cc1c5654f85ef496038a8cddac46dfc0ad0b7c44c37ab489d", + "timestamp": 1694386290, + "smartContractResults": [ + { + "hash": "a23faa3c80bae0b968f007ff0fad3afdec05b4e71d749c3d583dec10c6eb05a2", + "nonce": 0, + "value": 0, + "receiver": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "data": "ESDTTransfer@5745474c442d643763366262@03856446ff9a304b", + "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "logs": { + "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "identifier": "ESDTTransfer", + "topics": [ + "V0VHTEQtZDdjNmJi", + "", + "A4VkRv+aMEs=", + "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOY=" + ], + "data": null + }, + { + "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOs=" + ], + "data": "QDZmNmI=" + }, + { + "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "identifier": "completedTxEvent", + "topics": [ + "1AWL08E9sLFIMsfFj+Fj2y9Xn/ZUQ4BYa4on2ItKUHA=" + ], + "data": null + } + ] + }, + "tokens": [ + "WEGLD-d7c6bb" + ], + "esdtValues": [ + "253719210115084363" + ], + "operation": "ESDTTransfer" + }, + { + "hash": "b7b4d15917fd215399d8e772c3c4e732008baaedc2b8172f71c91708ba7523f0", + "nonce": 31, + "value": 102028510000000, + "receiver": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "data": "@6f6b@0000000c5745474c442d64376336626200000000000000000000000803856446ff9a304b@10", + "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "logs": { + "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "events": [ + { + "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "identifier": "completedTxEvent", + "topics": [ + "1AWL08E9sLFIMsfFj+Fj2y9Xn/ZUQ4BYa4on2ItKUHA=" + ], + "data": null + } + ] + }, + "operation": "transfer", + "isRefund": true + }, + { + "hash": "05a766ca05d2053d1c0fbeb1797116474a06c86402a3bfd6c132c9a24cfa1bb0", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "data": "swapTokensFixedInput@5745474c442d643763366262@037c778fcce9c55b", + "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "gasLimit": 25050500, + "gasPrice": 1000000000, + "callType": 0, + "operation": "transfer", + "function": "swapTokensFixedInput" + }, + { + "hash": "4e639c80822d5d7780c8326d683fa9cd6d59649d14122dfabc5a96dda36da527", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgquu5rsa4ee6l4azz6vdu4hjp8z4p6tt8m0n4suht3dy", + "sender": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "data": "ESDTTransfer@5745474c442d643763366262@e7730d1ef1b0@737761704e6f466565416e64466f7277617264@4d45582d646332383963@0000000000000000000000000000000000000000000000000000000000000000", + "prevTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "originalTxHash": "d4058bd3c13db0b14832c7c58fe163db2f579ff6544380586b8a27d88b4a5070", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "tokens": [ + "WEGLD-d7c6bb" + ], + "esdtValues": [ + "254481327387056" + ], + "operation": "ESDTTransfer", + "function": "swapNoFeeAndForward" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "events": [ + { + "address": "erd14r7m6drneg69jyxvxxnrsss6x5gg2cqqwreyhdwanj0fcza0ynnq5jmy4g", + "identifier": "ESDTTransfer", + "topics": [ + "SFRNLWZlMWY2OQ==", + "", + "DeC2s6dkAAA=", + "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOs=" + ], + "data": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "identifier": "ESDTTransfer", + "topics": [ + "V0VHTEQtZDdjNmJi", + "", + "53MNHvGw", + "AAAAAAAAAAAFAOcoOHa5zr9eiFpjeVvIJxVDpaz7fOs=" + ], + "data": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgquu5rsa4ee6l4azz6vdu4hjp8z4p6tt8m0n4suht3dy", + "identifier": "ESDTLocalBurn", + "topics": [ + "TUVYLWRjMjg5Yw==", + "", + "AuMDPq1jy03x" + ], + "data": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgquu5rsa4ee6l4azz6vdu4hjp8z4p6tt8m0n4suht3dy", + "identifier": "swapNoFeeAndForward", + "topics": [ + "c3dhcF9ub19mZWVfYW5kX2ZvcndhcmQ=", + "TUVYLWRjMjg5Yw==", + "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOs=", + "GL0=" + ], + "data": "AAAAAAAAAAAFAKVe/p1dXpaw/INtyTPaxf3N3LaNfOsAAAAMV0VHTEQtZDdjNmJiAAAABudzDR7xsAAAAApNRVgtZGMyODljAAAACQLjAz6tY8tN8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzvkcAAAAAAAAYvQAAAABk/khy" + }, + { + "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "identifier": "ESDTTransfer", + "topics": [ + "V0VHTEQtZDdjNmJi", + "", + "A4VkRv+aMEs=", + "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOY=" + ], + "data": null + }, + { + "address": "erd1qqqqqqqqqqqqqpgq5400a82at6ttplyrdhyn8kk9lhxaed5d0n4s9s77kz", + "identifier": "swapTokensFixedInput", + "topics": [ + "c3dhcA==", + "SFRNLWZlMWY2OQ==", + "V0VHTEQtZDdjNmJi", + "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOY=", + "GL0=" + ], + "data": "qP29NHPKNFkQzDGmOEIaNRCFYABw8ku13ZyenAuvJOYAAAAKSFRNLWZlMWY2OQAAAAgN4Lazp2QAAAAAAAxXRUdMRC1kN2M2YmIAAAAIA4VkRv+aMEsAAAAHA41+pMaAAAAAAAoofxtJRPkr8X9kAAAACgpOPCsHUu261HUAAAAAAHO+RwAAAAAAABi9AAAAAGT+SHI=" + } + ] + }, + "status": "success", + "tokens": [ + "HTM-fe1f69" + ], + "esdtValues": [ + "1000000000000000000" + ], + "operation": "ESDTTransfer", + "function": "swapTokensFixedInput", + "initiallyPaidFee": "502005000000000", + "fee": "399976490000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" + } + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Vec> = vec![ + hex::decode("0000000c5745474c442d64376336626200000000000000000000000803856446ff9a304b") + .unwrap(), + hex::decode("10").unwrap(), + ]; + + assert_eq!(tx_response.out, expected) +} + +#[test] +fn test_with_tx_that_has_no_sc_result() { + // transaction data from the devnet + let data = r#" + { + "data": { + "transaction": { + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "hash": "6afac3ec13c89cc56154d06efdb457a24f58361699eee00a48202a8f8adc8c8a", + "nonce": 17, + "round": 7548071, + "epoch": 6257, + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "sender": "erd1uh67c2lkhyj4vh73akv7jky9sfgvus8awwcj64uju69mmfne5u7q299t7g", + "gasPrice": 1000000000, + "gasLimit": 600000000, + "gasUsed": 600000000, + "data": "cmV0dXJuVHdvVTY0", + "signature": "f3a3ca96a78c90c9cf1b08541e1777010f0176a5e1e525e631155b2784932cbfd74c9168d03ba201fd5434d1a1b4789895ddade9883eca2ee9e0bce18468fb00", + "sourceShard": 0, + "destinationShard": 0, + "blockNonce": 7502091, + "blockHash": "5ec66c651cb1514cba200e7e80a4491880f0db678ce7631c397872e3842f0aa2", + "notarizedAtSourceInMetaNonce": 7510505, + "NotarizedAtSourceInMetaHash": "8410309ec5b988af79b4dcfb44fd4729d46874ebd796672c78e417e314409051", + "notarizedAtDestinationInMetaNonce": 7510505, + "notarizedAtDestinationInMetaHash": "8410309ec5b988af79b4dcfb44fd4729d46874ebd796672c78e417e314409051", + "miniblockType": "TxBlock", + "miniblockHash": "fb150e515449c9b658879ed06f256b429239cbe78ec2c2821deb4b283ff21554", + "hyperblockNonce": 7510505, + "hyperblockHash": "8410309ec5b988af79b4dcfb44fd4729d46874ebd796672c78e417e314409051", + "timestamp": 1693840026, + "logs": { + "address": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "identifier": "writeLog", + "topics": [ + "5fXsK/a5JVZf0e2Z6ViFglDOQP1zsS1XkuaLvaZ5pzw=", + "QHRvbyBtdWNoIGdhcyBwcm92aWRlZCBmb3IgcHJvY2Vzc2luZzogZ2FzIHByb3ZpZGVkID0gNTk5OTMyMDAwLCBnYXMgdXNlZCA9IDE4NDE2NjU=" + ], + "data": "QDZmNmJAMGFAMDIxODcxMWEwMA==" + }, + { + "address": "erd1qqqqqqqqqqqqqpgq4nlkk7jwhqgp4r08lal46tqt70jdv0685u7qrr3l2d", + "identifier": "completedTxEvent", + "topics": [ + "avrD7BPInMVhVNBu/bRXok9YNhaZ7uAKSCAqj4rcjIo=" + ], + "data": null + } + ] + }, + "status": "success", + "operation": "transfer", + "function": "returnTwoU64", + "initiallyPaidFee": "6067320000000000", + "fee": "6067320000000000", + "chainID": "D", + "version": 1, + "options": 0 + } + }, + "error": "", + "code": "successful" + } + "#; + + let tx_on_network: TransactionOnNetwork = serde_json::from_str::(data) + .unwrap() + .data + .unwrap() + .transaction; + let tx_response = TxResponse::from_network_tx(tx_on_network); + + let expected: Vec> = vec![ + hex::decode("0a").unwrap(), + hex::decode("0218711a00").unwrap(), + ]; + + assert_eq!(tx_response.out, expected) +} diff --git a/framework/snippets/Cargo.toml b/framework/snippets/Cargo.toml index 65fbf71a37..954ebb2ea9 100644 --- a/framework/snippets/Cargo.toml +++ b/framework/snippets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sc-snippets" -version = "0.48.1" +version = "0.49.0-alpha.4" edition = "2021" authors = ["MultiversX "] @@ -20,11 +20,12 @@ base64 = "0.21.5" log = "0.4.17" env_logger = "0.11" futures = "0.3" +rand = "0.8.5" [dependencies.multiversx-sc-scenario] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../scenario" [dependencies.multiversx-sdk] -version = "=0.3.2" +version = "=0.4.0-alpha.4" path = "../../sdk/core" diff --git a/framework/snippets/src/imports.rs b/framework/snippets/src/imports.rs new file mode 100644 index 0000000000..b031e0769c --- /dev/null +++ b/framework/snippets/src/imports.rs @@ -0,0 +1,6 @@ +pub use crate::multiversx_sc_scenario::imports::*; + +pub use crate::{dns_address_for_name, Interactor, InteractorPrepareAsync, StepBuffer}; + +pub use env_logger; +pub use tokio; diff --git a/framework/snippets/src/interactor.rs b/framework/snippets/src/interactor.rs index 7034932d91..35d53a4a86 100644 --- a/framework/snippets/src/interactor.rs +++ b/framework/snippets/src/interactor.rs @@ -1,4 +1,5 @@ use multiversx_sc_scenario::{ + imports::{retrieve_account_as_scenario_set_state, Bech32Address, ScenarioRunner}, mandos_system::{run_list::ScenarioRunnerList, run_trace::ScenarioTraceFile}, multiversx_sc::types::Address, scenario_model::AddressValue, @@ -8,7 +9,11 @@ use multiversx_sdk::{ data::{address::Address as ErdrsAddress, network_config::NetworkConfig}, wallet::Wallet, }; -use std::{collections::HashMap, path::Path, time::Duration}; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, + time::Duration, +}; use crate::Sender; @@ -22,6 +27,8 @@ pub struct Interactor { pub(crate) waiting_time_ms: u64, pub pre_runners: ScenarioRunnerList, pub post_runners: ScenarioRunnerList, + + pub current_dir: PathBuf, } impl Interactor { @@ -35,6 +42,7 @@ impl Interactor { waiting_time_ms: 0, pre_runners: ScenarioRunnerList::empty(), post_runners: ScenarioRunnerList::empty(), + current_dir: PathBuf::default(), } } @@ -60,6 +68,12 @@ impl Interactor { self.post_runners.push(ScenarioTraceFile::new(path)); self } + + pub async fn retrieve_account(&mut self, wallet_address: &Bech32Address) { + let set_state = retrieve_account_as_scenario_set_state(&self.proxy, wallet_address).await; + self.pre_runners.run_set_state_step(&set_state); + self.post_runners.run_set_state_step(&set_state); + } } pub(crate) fn mandos_to_erdrs_address(mandos_address: &AddressValue) -> ErdrsAddress { diff --git a/framework/snippets/src/interactor_retrieve.rs b/framework/snippets/src/interactor_retrieve.rs index c19392095a..8b9e0031ab 100644 --- a/framework/snippets/src/interactor_retrieve.rs +++ b/framework/snippets/src/interactor_retrieve.rs @@ -1,64 +1,67 @@ use crate::Interactor; use log::info; use multiversx_sdk::data::transaction::TransactionOnNetwork; -use std::time::Duration; +use rand::Rng; +use std::time::{Duration, Instant}; -const TX_GET_RESULTS_NUM_RETRIES: usize = 8; -const EXTRA_WAITING_TIME_MS: Duration = Duration::from_millis(8000); -const WAITING_TIME_MS: Duration = Duration::from_secs(25); -const WAIT: u64 = 1000; +const INITIAL_BACKOFF_DELAY: f32 = 1.4; +const MAX_RETRIES: usize = 8; +const MAX_BACKOFF_DELAY: Duration = Duration::from_secs(6); impl Interactor { /// Retrieves a transaction from the network. pub(crate) async fn retrieve_tx_on_network(&self, tx_hash: String) -> TransactionOnNetwork { - let mut waiting_time_ms = 0; - let mut break_outer = false; - sleep(&mut waiting_time_ms, WAITING_TIME_MS).await; - - let tx = 'outer: loop { - let mut retries = TX_GET_RESULTS_NUM_RETRIES; - let mut wait = WAIT; - loop { - let tx_info_result = self.proxy.get_transaction_info_with_results(&tx_hash).await; - match tx_info_result { - Ok(tx) => { - if break_outer { - break 'outer tx; - } - - // reset waiting time - waiting_time_ms = WAITING_TIME_MS.as_millis() as u64; - - tokio::time::sleep(EXTRA_WAITING_TIME_MS).await; - break_outer = true; + let mut rng = rand::thread_rng(); + let mut retries = 0; + let mut backoff_delay = Duration::from_secs_f32(INITIAL_BACKOFF_DELAY); + let start_time = Instant::now(); + loop { + match self.proxy.get_transaction_status(&tx_hash).await { + Ok(status) => { + // checks if transaction status is final + match status.as_str() { + "success" | "fail" => { + // retrieve transaction info with results + let transaction_info_with_results = self + .proxy + .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; + }, + _ => { + continue; + }, + } + }, + Err(err) => { + retries += 1; + if retries >= MAX_RETRIES { + info!("Transaction failed, max retries exceeded: {}", err); + println!("Transaction failed, max retries exceeded: {}", err); break; - }, - Err(err) => { - assert!( - retries > 0, - "still no answer after {TX_GET_RESULTS_NUM_RETRIES} retries" - ); + } - info!( - "tx result fetch error after {} ms: {}", - self.waiting_time_ms, err - ); - retries -= 1; - sleep(&mut waiting_time_ms, Duration::from_millis(wait)).await; - wait *= 2; - }, - } + let backoff_time = backoff_delay + .mul_f32(rng.gen_range(0.8..1.2)) + .min(MAX_BACKOFF_DELAY); + tokio::time::sleep(backoff_time).await; + backoff_delay *= 2; // exponential backoff + }, } - }; + } - info!("tx with results: {:#?}", tx); - tx + // retries have been exhausted + let elapsed_time = start_time.elapsed(); + println!( + "Fetching transaction failed and retries exhausted, returning default transaction. Total elapsed time: {:?}", + elapsed_time + ); + TransactionOnNetwork::default() } } - -/// Sleeps for the given duration and adds the duration to the waiting time. -pub async fn sleep(waiting_time_ms: &mut u64, duration: Duration) { - *waiting_time_ms += duration.as_millis() as u64; - tokio::time::sleep(duration).await; -} diff --git a/framework/snippets/src/interactor_scenario.rs b/framework/snippets/src/interactor_scenario.rs new file mode 100644 index 0000000000..8449bf9edc --- /dev/null +++ b/framework/snippets/src/interactor_scenario.rs @@ -0,0 +1,5 @@ +mod interactor_sc_call; +mod interactor_sc_deploy; +mod interactor_sc_extra; +mod interactor_transfer; +mod interactor_vm_query; diff --git a/framework/snippets/src/interactor_sc_call.rs b/framework/snippets/src/interactor_scenario/interactor_sc_call.rs similarity index 94% rename from framework/snippets/src/interactor_sc_call.rs rename to framework/snippets/src/interactor_scenario/interactor_sc_call.rs index a0e0498ae9..d01e4af590 100644 --- a/framework/snippets/src/interactor_sc_call.rs +++ b/framework/snippets/src/interactor_scenario/interactor_sc_call.rs @@ -2,7 +2,6 @@ use crate::{address_h256_to_erdrs, mandos_to_erdrs_address, Interactor}; use log::info; use multiversx_sc_scenario::{ api::StaticApi, - multiversx_sc::types::ContractCallWithEgld, scenario::ScenarioRunner, scenario_model::{ScCallStep, SetStateStep, TxCall, TxResponse}, }; @@ -45,6 +44,7 @@ impl Interactor { tx_hash } + #[allow(deprecated)] // TODO pub(crate) fn tx_call_to_blockchain_tx(&self, tx_call: &TxCall) -> Transaction { let contract_call = tx_call.to_contract_call(); let contract_call_tx_data = contract_call_to_tx_data(&contract_call); @@ -70,7 +70,10 @@ impl Interactor { } } -fn contract_call_to_tx_data(contract_call: &ContractCallWithEgld) -> String { +#[allow(deprecated)] // TODO +fn contract_call_to_tx_data( + contract_call: &multiversx_sc_scenario::imports::ContractCallWithEgld, +) -> String { let mut result = String::from_utf8( contract_call .basic diff --git a/framework/snippets/src/interactor_sc_deploy.rs b/framework/snippets/src/interactor_scenario/interactor_sc_deploy.rs similarity index 90% rename from framework/snippets/src/interactor_sc_deploy.rs rename to framework/snippets/src/interactor_scenario/interactor_sc_deploy.rs index 63e8ae80db..87d17dff7f 100644 --- a/framework/snippets/src/interactor_sc_deploy.rs +++ b/framework/snippets/src/interactor_scenario/interactor_sc_deploy.rs @@ -1,7 +1,7 @@ use crate::{mandos_to_erdrs_address, Interactor}; use log::info; use multiversx_sc_scenario::{ - bech32, + imports::Bech32Address, mandos_system::ScenarioRunner, scenario_model::{ScDeployStep, SetStateStep, TxResponse}, }; @@ -64,14 +64,11 @@ impl Interactor { .new_deployed_address .clone() .unwrap(); + let deploy_address_bech32 = Bech32Address::from(deploy_address); - let set_state_step = SetStateStep::new().new_address( - addr, - nonce, - format!("0x{}", hex::encode(&deploy_address)).as_str(), - ); + let set_state_step = SetStateStep::new().new_address(addr, nonce, &deploy_address_bech32); - println!("deploy address: {}", bech32::encode(&deploy_address)); + println!("deploy address: {deploy_address_bech32}"); self.pre_runners.run_set_state_step(&set_state_step); self.post_runners.run_set_state_step(&set_state_step); diff --git a/framework/snippets/src/interactor_sc_extra.rs b/framework/snippets/src/interactor_scenario/interactor_sc_extra.rs similarity index 71% rename from framework/snippets/src/interactor_sc_extra.rs rename to framework/snippets/src/interactor_scenario/interactor_sc_extra.rs index 177b38d4e1..44e5efa744 100644 --- a/framework/snippets/src/interactor_sc_extra.rs +++ b/framework/snippets/src/interactor_scenario/interactor_sc_extra.rs @@ -1,9 +1,12 @@ +#![allow(deprecated)] + use crate::Interactor; use multiversx_sc_scenario::{ api::StaticApi, multiversx_sc::{ - codec::{CodecFrom, TopEncodeMulti}, - types::{Address, ContractCall}, + abi::TypeAbiFrom, + codec::{TopDecodeMulti, TopEncodeMulti}, + types::{Address, ContractCallBase}, }, scenario_model::{ ScCallStep, ScDeployStep, ScQueryStep, TxResponse, TypedResponse, TypedScCall, @@ -12,6 +15,10 @@ use multiversx_sc_scenario::{ }; impl Interactor { + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_call_use_raw_response( &mut self, mut step: S, @@ -27,6 +34,10 @@ impl Interactor { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_call_use_result( &mut self, step: TypedScCall, @@ -34,26 +45,34 @@ impl Interactor { ) -> &mut Self where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, F: FnOnce(TypedResponse), { use_result(self.sc_call_get_result(step).await); self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_call_get_result( &mut self, mut step: TypedScCall, ) -> TypedResponse where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.sc_call(step.as_mut()).await; let response = unwrap_response(&step.as_mut().response); TypedResponse::from_raw(response) } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_query_use_raw_response( &mut self, mut step: S, @@ -69,6 +88,10 @@ impl Interactor { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_query_use_result( &mut self, step: TypedScQuery, @@ -76,30 +99,38 @@ impl Interactor { ) -> &mut Self where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, F: FnOnce(TypedResponse), { use_result(self.sc_query_get_result(step).await); self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_query_get_result( &mut self, mut step: TypedScQuery, ) -> TypedResponse where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.sc_query(step.as_mut()).await; let response = unwrap_response(&step.sc_query_step.response); TypedResponse::from_raw(response) } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn quick_query(&mut self, contract_call: CC) -> RequestedResult where - CC: ContractCall, - RequestedResult: CodecFrom, + CC: ContractCallBase, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { let mut typed_sc_query = ScQueryStep::new().call(contract_call); self.sc_query(&mut typed_sc_query).await; @@ -108,6 +139,10 @@ impl Interactor { typed_response.result.unwrap() } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_deploy_use_raw_response( &mut self, mut step: S, @@ -123,6 +158,10 @@ impl Interactor { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_deploy_use_result( &mut self, step: TypedScDeploy, @@ -130,7 +169,7 @@ impl Interactor { ) -> &mut Self where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, F: FnOnce(Address, TypedResponse), { let (new_address, response) = self.sc_deploy_get_result(step).await; @@ -138,13 +177,17 @@ impl Interactor { self } + #[deprecated( + since = "0.49.0", + note = "Please use the unified transaction syntax instead." + )] pub async fn sc_deploy_get_result( &mut self, mut step: TypedScDeploy, ) -> (Address, TypedResponse) where OriginalResult: TopEncodeMulti, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.sc_deploy(step.as_mut()).await; let response = unwrap_response(&step.sc_deploy_step.response); diff --git a/framework/snippets/src/interactor_sc_transfer.rs b/framework/snippets/src/interactor_scenario/interactor_transfer.rs similarity index 100% rename from framework/snippets/src/interactor_sc_transfer.rs rename to framework/snippets/src/interactor_scenario/interactor_transfer.rs diff --git a/framework/snippets/src/interactor_vm_query.rs b/framework/snippets/src/interactor_scenario/interactor_vm_query.rs similarity index 90% rename from framework/snippets/src/interactor_vm_query.rs rename to framework/snippets/src/interactor_scenario/interactor_vm_query.rs index 56a54961d2..15de064d95 100644 --- a/framework/snippets/src/interactor_vm_query.rs +++ b/framework/snippets/src/interactor_scenario/interactor_vm_query.rs @@ -1,9 +1,11 @@ +#![allow(deprecated)] + use crate::{address_h256_to_erdrs, Interactor}; use log::info; use multiversx_sc_scenario::{ api::StaticApi, mandos_system::ScenarioRunner, - multiversx_sc::{codec::CodecFrom, types::ContractCall}, + multiversx_sc::{abi::TypeAbiFrom, codec::TopDecodeMulti, types::ContractCall}, scenario_model::{ScQueryStep, TxResponse}, }; use multiversx_sdk::{data::vm::VmValueRequest, utils::base64_decode}; @@ -50,7 +52,7 @@ impl Interactor { pub async fn vm_query(&mut self, contract_call: CC) -> RequestedResult where CC: ContractCall, - RequestedResult: CodecFrom, + RequestedResult: TopDecodeMulti + TypeAbiFrom, { self.quick_query(contract_call).await } diff --git a/framework/snippets/src/interactor_tx.rs b/framework/snippets/src/interactor_tx.rs new file mode 100644 index 0000000000..2c8bed0fda --- /dev/null +++ b/framework/snippets/src/interactor_tx.rs @@ -0,0 +1,17 @@ +#![allow(unused_imports)] // TEMP + +mod interactor_exec_call; +mod interactor_exec_deploy; +mod interactor_exec_env; +mod interactor_exec_step; +mod interactor_exec_transf; +mod interactor_prepare_async; +mod interactor_query_call; +mod interactor_query_env; +mod interactor_query_step; + +pub use interactor_exec_env::InteractorExecEnv; +pub use interactor_exec_step::InteractorExecStep; +pub use interactor_prepare_async::InteractorPrepareAsync; +pub use interactor_query_env::InteractorQueryEnv; +pub use interactor_query_step::InteractorQueryStep; diff --git a/framework/snippets/src/interactor_tx/interactor_exec_call.rs b/framework/snippets/src/interactor_tx/interactor_exec_call.rs new file mode 100644 index 0000000000..71ff47c043 --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_exec_call.rs @@ -0,0 +1,76 @@ +use multiversx_sc_scenario::{ + api::StaticApi, + multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + FunctionCall, RHListExec, Tx, TxBaseWithEnv, TxFromSpecified, TxGas, TxPayment, + TxToSpecified, + }, + }, + scenario::tx_to_step::TxToStep, + scenario_model::{ScCallStep, TxResponse}, + ScenarioTxEnvData, +}; + +use crate::Interactor; + +use super::{InteractorExecEnv, InteractorExecStep, InteractorPrepareAsync}; + +impl<'w, From, To, Payment, Gas, RH> InteractorPrepareAsync + for Tx, From, To, Payment, Gas, FunctionCall, RH> +where + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Exec = InteractorExecStep<'w, ScCallStep, RH>; + + fn prepare_async(self) -> Self::Exec { + InteractorExecStep { + step_wrapper: self.tx_to_step(), + } + } +} + +impl<'w, RH> InteractorExecStep<'w, ScCallStep, RH> +where + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + pub async fn run(mut self) -> ::Unpacked { + self.step_wrapper + .env + .world + .sc_call(&mut self.step_wrapper.step) + .await; + self.step_wrapper.process_result() + } +} + +impl Interactor { + pub async fn chain_call(&mut self, f: F) -> &mut Self + where + From: TxFromSpecified, + To: TxToSpecified, + Payment: TxPayment, + Gas: TxGas, + RH: RHListExec, + F: FnOnce( + TxBaseWithEnv, + ) + -> Tx, RH>, + { + let env = self.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + + let mut step_wrapper = tx.tx_to_step(); + self.sc_call(&mut step_wrapper.step).await; + step_wrapper.process_result(); + + self + } +} diff --git a/framework/snippets/src/interactor_tx/interactor_exec_deploy.rs b/framework/snippets/src/interactor_tx/interactor_exec_deploy.rs new file mode 100644 index 0000000000..30e30a34ab --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_exec_deploy.rs @@ -0,0 +1,122 @@ +use multiversx_sc_scenario::{ + multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + Code, DeployCall, RHListExec, Tx, TxBaseWithEnv, TxCodeValue, TxFromSpecified, TxGas, + TxPayment, + }, + }, + scenario::tx_to_step::TxToStep, + scenario_model::{ScDeployStep, TxResponse}, + ScenarioTxEnvData, +}; + +use crate::Interactor; + +use super::{InteractorExecEnv, InteractorExecStep, InteractorPrepareAsync}; + +impl<'w, From, Payment, Gas, CodeValue, RH> InteractorPrepareAsync + for Tx< + InteractorExecEnv<'w>, + From, + (), + Payment, + Gas, + DeployCall, Code>, + RH, + > +where + From: TxFromSpecified>, + Payment: TxPayment>, + Gas: TxGas>, + CodeValue: TxCodeValue>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Exec = InteractorExecStep<'w, ScDeployStep, RH>; + + fn prepare_async(self) -> Self::Exec { + InteractorExecStep { + step_wrapper: self.tx_to_step(), + } + } +} + +impl<'w, RH> InteractorExecStep<'w, ScDeployStep, RH> +where + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + pub async fn run(mut self) -> ::Unpacked { + self.step_wrapper + .env + .world + .sc_deploy(&mut self.step_wrapper.step) + .await; + self.step_wrapper.process_result() + } +} + +impl Interactor { + pub async fn chain_deploy(&mut self, f: F) -> &mut Self + where + From: TxFromSpecified, + Payment: TxPayment, + Gas: TxGas, + CodeValue: TxCodeValue, + RH: RHListExec, + F: FnOnce( + TxBaseWithEnv, + ) -> Tx< + ScenarioTxEnvData, + From, + (), + Payment, + Gas, + DeployCall>, + RH, + >, + { + let env = self.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + + let mut step_wrapper = tx.tx_to_step(); + self.sc_deploy(&mut step_wrapper.step).await; + step_wrapper.process_result(); + + self + } + + pub async fn run_deploy( + &mut self, + f: F, + ) -> ::Unpacked + where + From: TxFromSpecified, + Payment: TxPayment, + Gas: TxGas, + CodeValue: TxCodeValue, + RH: RHListExec, + RH::ListReturns: NestedTupleFlatten, + F: FnOnce( + TxBaseWithEnv, + ) -> Tx< + ScenarioTxEnvData, + From, + (), + Payment, + Gas, + DeployCall>, + RH, + >, + { + let env = self.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + + let mut step_wrapper = tx.tx_to_step(); + self.sc_deploy(&mut step_wrapper.step).await; + step_wrapper.process_result() + } +} diff --git a/framework/snippets/src/interactor_tx/interactor_exec_env.rs b/framework/snippets/src/interactor_tx/interactor_exec_env.rs new file mode 100644 index 0000000000..935164f7eb --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_exec_env.rs @@ -0,0 +1,46 @@ +use multiversx_sc_scenario::{ + api::StaticApi, + multiversx_sc::types::{ManagedAddress, ManagedBuffer, Tx, TxBaseWithEnv, TxEnv}, + scenario_model::TxExpect, + ScenarioTxEnv, ScenarioTxEnvData, +}; + +use crate::Interactor; + +impl Interactor { + pub fn tx(&mut self) -> TxBaseWithEnv> { + let data = self.new_env_data(); + let env = InteractorExecEnv { world: self, data }; + Tx::new_with_env(env) + } +} + +/// Environment for executing transactions. +pub struct InteractorExecEnv<'w> { + pub world: &'w mut Interactor, + pub data: ScenarioTxEnvData, +} + +impl<'w> TxEnv for InteractorExecEnv<'w> { + type Api = StaticApi; + + type RHExpect = TxExpect; + + fn resolve_sender_address(&self) -> ManagedAddress { + panic!("Explicit sender address expected") + } + + fn default_gas_annotation(&self) -> ManagedBuffer { + self.data.default_gas_annotation() + } + + fn default_gas_value(&self) -> u64 { + self.data.default_gas_value() + } +} + +impl<'w> ScenarioTxEnv for InteractorExecEnv<'w> { + fn env_data(&self) -> &ScenarioTxEnvData { + &self.data + } +} diff --git a/framework/snippets/src/interactor_tx/interactor_exec_step.rs b/framework/snippets/src/interactor_tx/interactor_exec_step.rs new file mode 100644 index 0000000000..3becfe81d9 --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_exec_step.rs @@ -0,0 +1,15 @@ +use multiversx_sc_scenario::{ + multiversx_sc::{tuple_util::NestedTupleFlatten, types::RHListExec}, + scenario::tx_to_step::StepWrapper, + scenario_model::TxResponse, +}; + +use super::InteractorExecEnv; + +pub struct InteractorExecStep<'w, Step, RH> +where + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + pub(crate) step_wrapper: StepWrapper, Step, RH>, +} diff --git a/framework/snippets/src/interactor_tx/interactor_exec_transf.rs b/framework/snippets/src/interactor_tx/interactor_exec_transf.rs new file mode 100644 index 0000000000..a19d54548d --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_exec_transf.rs @@ -0,0 +1,34 @@ +use multiversx_sc_scenario::{ + multiversx_sc::types::{Tx, TxFromSpecified, TxGas, TxPayment, TxToSpecified}, + scenario::tx_to_step::TxToStep, + scenario_model::TransferStep, +}; + +use super::{InteractorExecEnv, InteractorExecStep, InteractorPrepareAsync}; + +impl<'w, From, To, Payment, Gas> InteractorPrepareAsync + for Tx, From, To, Payment, Gas, (), ()> +where + From: TxFromSpecified>, + To: TxToSpecified>, + Payment: TxPayment>, + Gas: TxGas>, +{ + type Exec = InteractorExecStep<'w, TransferStep, ()>; + + fn prepare_async(self) -> Self::Exec { + InteractorExecStep { + step_wrapper: self.tx_to_step(), + } + } +} + +impl<'w> InteractorExecStep<'w, TransferStep, ()> { + pub async fn run(self) { + self.step_wrapper + .env + .world + .transfer(self.step_wrapper.step) + .await; + } +} diff --git a/framework/snippets/src/interactor_tx/interactor_prepare_async.rs b/framework/snippets/src/interactor_tx/interactor_prepare_async.rs new file mode 100644 index 0000000000..43ca7c403c --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_prepare_async.rs @@ -0,0 +1,18 @@ +use multiversx_sc_scenario::ScenarioTxEnvData; + +use crate::Interactor; + +impl Interactor { + pub(crate) fn new_env_data(&self) -> ScenarioTxEnvData { + ScenarioTxEnvData { + context_path: self.current_dir.clone(), + tx_hash: None, + } + } +} + +pub trait InteractorPrepareAsync { + type Exec; + + fn prepare_async(self) -> Self::Exec; +} diff --git a/framework/snippets/src/interactor_tx/interactor_query_call.rs b/framework/snippets/src/interactor_tx/interactor_query_call.rs new file mode 100644 index 0000000000..55421743c5 --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_query_call.rs @@ -0,0 +1,65 @@ +use multiversx_sc_scenario::{ + api::StaticApi, + multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{FunctionCall, RHListExec, Tx, TxBaseWithEnv, TxToSpecified}, + }, + scenario::tx_to_step::TxToQueryStep, + scenario_model::TxResponse, + ScenarioTxEnvData, +}; + +use crate::Interactor; + +use super::{InteractorPrepareAsync, InteractorQueryEnv, InteractorQueryStep}; + +impl<'w, To, RH> InteractorPrepareAsync + for Tx, (), To, (), (), FunctionCall, RH> +where + To: TxToSpecified>, + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + type Exec = InteractorQueryStep<'w, RH>; + + fn prepare_async(self) -> Self::Exec { + InteractorQueryStep { + step_wrapper: self.tx_to_query_step(), + } + } +} + +impl<'w, RH> InteractorQueryStep<'w, RH> +where + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + pub async fn run(mut self) -> ::Unpacked { + self.step_wrapper + .env + .world + .sc_query(&mut self.step_wrapper.step) + .await; + self.step_wrapper.process_result() + } +} + +impl Interactor { + pub async fn chain_query(&mut self, f: F) -> &mut Self + where + To: TxToSpecified, + RH: RHListExec, + F: FnOnce( + TxBaseWithEnv, + ) -> Tx, RH>, + { + let env = self.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + + let mut step_wrapper = tx.tx_to_query_step(); + self.sc_query(&mut step_wrapper.step).await; + step_wrapper.process_result(); + self + } +} diff --git a/framework/snippets/src/interactor_tx/interactor_query_env.rs b/framework/snippets/src/interactor_tx/interactor_query_env.rs new file mode 100644 index 0000000000..1fa1142111 --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_query_env.rs @@ -0,0 +1,45 @@ +use multiversx_sc_scenario::{ + api::StaticApi, + multiversx_sc::types::{ManagedAddress, ManagedBuffer, Tx, TxBaseWithEnv, TxEnv}, + scenario_model::TxExpect, + ScenarioTxEnv, ScenarioTxEnvData, +}; + +use crate::Interactor; + +impl Interactor { + pub fn query(&mut self) -> TxBaseWithEnv> { + let data = self.new_env_data(); + let env = InteractorQueryEnv { world: self, data }; + Tx::new_with_env(env) + } +} + +pub struct InteractorQueryEnv<'w> { + pub world: &'w mut Interactor, + pub data: ScenarioTxEnvData, +} + +impl<'w> TxEnv for InteractorQueryEnv<'w> { + type Api = StaticApi; + + type RHExpect = TxExpect; + + fn resolve_sender_address(&self) -> ManagedAddress { + panic!("Explicit sender address expected") + } + + fn default_gas_annotation(&self) -> ManagedBuffer { + self.data.default_gas_annotation() + } + + fn default_gas_value(&self) -> u64 { + self.data.default_gas_value() + } +} + +impl<'w> ScenarioTxEnv for InteractorQueryEnv<'w> { + fn env_data(&self) -> &ScenarioTxEnvData { + &self.data + } +} diff --git a/framework/snippets/src/interactor_tx/interactor_query_step.rs b/framework/snippets/src/interactor_tx/interactor_query_step.rs new file mode 100644 index 0000000000..81c7542add --- /dev/null +++ b/framework/snippets/src/interactor_tx/interactor_query_step.rs @@ -0,0 +1,15 @@ +use multiversx_sc_scenario::{ + multiversx_sc::{tuple_util::NestedTupleFlatten, types::RHListExec}, + scenario::tx_to_step::StepWrapper, + scenario_model::{ScQueryStep, TxResponse}, +}; + +use super::InteractorQueryEnv; + +pub struct InteractorQueryStep<'w, RH> +where + RH: RHListExec>, + RH::ListReturns: NestedTupleFlatten, +{ + pub(crate) step_wrapper: StepWrapper, ScQueryStep, RH>, +} diff --git a/framework/snippets/src/lib.rs b/framework/snippets/src/lib.rs index 2081c11a58..b94a6517d9 100644 --- a/framework/snippets/src/lib.rs +++ b/framework/snippets/src/lib.rs @@ -1,26 +1,23 @@ mod interactor; mod interactor_dns; -mod interactor_multi_sc_exec; -mod interactor_multi_sc_process; mod interactor_retrieve; -mod interactor_sc_call; -mod interactor_sc_deploy; -mod interactor_sc_extra; -mod interactor_sc_transfer; +mod interactor_scenario; mod interactor_sender; -mod interactor_tx_spec; -mod interactor_vm_query; -mod step_buffer; +mod interactor_tx; +mod multi; pub use env_logger; pub use hex; pub use interactor::*; pub use interactor_dns::*; pub use interactor_sender::*; -pub use interactor_tx_spec::*; +pub use interactor_tx::*; pub use log; +pub use multi::*; pub use multiversx_sc_scenario::{self, multiversx_sc}; pub use multiversx_sdk as erdrs; // TODO: remove pub use multiversx_sdk as sdk; -pub use step_buffer::*; pub use tokio; + +/// Imports normally needed in interactors, grouped together. +pub mod imports; diff --git a/framework/snippets/src/multi.rs b/framework/snippets/src/multi.rs new file mode 100644 index 0000000000..973b159858 --- /dev/null +++ b/framework/snippets/src/multi.rs @@ -0,0 +1,9 @@ +mod homogenous_tx_buffer; +mod interactor_multi_sc_exec; +mod interactor_multi_sc_process; +mod interactor_step; +mod step_buffer; + +pub use homogenous_tx_buffer::HomogenousTxBuffer; +pub use interactor_step::InteractorStep; +pub use step_buffer::StepBuffer; diff --git a/framework/snippets/src/multi/homogenous_tx_buffer.rs b/framework/snippets/src/multi/homogenous_tx_buffer.rs new file mode 100644 index 0000000000..da177d1658 --- /dev/null +++ b/framework/snippets/src/multi/homogenous_tx_buffer.rs @@ -0,0 +1,65 @@ +use multiversx_sc_scenario::{ + multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{RHListExec, TxBaseWithEnv}, + }, + scenario::tx_to_step::{StepWithResponse, StepWrapper, TxToStep}, + scenario_model::TxResponse, + ScenarioTxEnvData, +}; + +use crate::{Interactor, InteractorExecEnv, InteractorStep, StepBuffer}; + +pub struct HomogenousTxBuffer<'w, Step, RH> { + env: InteractorExecEnv<'w>, + steps: Vec>, +} + +impl Interactor { + /// Creates a buffer that can hold multiple transactions, and then execute them all at once. + /// + /// This buffer holds transactions of the same type (call/deploy) and with identical result handler types. + /// Therefore, after execution, all results will have the same type. + pub fn homogenous_call_buffer(&mut self) -> HomogenousTxBuffer<'_, Step, RH> { + let data = self.new_env_data(); + let env = InteractorExecEnv { world: self, data }; + HomogenousTxBuffer { + env, + steps: Vec::new(), + } + } +} + +impl<'w, Step, RH> HomogenousTxBuffer<'w, Step, RH> +where + Step: InteractorStep + StepWithResponse, + RH: RHListExec, + RH::ListReturns: NestedTupleFlatten, +{ + pub fn push_tx(&mut self, f: F) -> &mut Self + where + Tx: TxToStep, + F: FnOnce(TxBaseWithEnv) -> Tx, + { + let env = self.env.world.new_env_data(); + let tx_base = TxBaseWithEnv::new_with_env(env); + let tx = f(tx_base); + + self.steps.push(tx.tx_to_step()); + + self + } + + pub async fn run(mut self) -> Vec<::Unpacked> { + let mut step_buffer = StepBuffer::default(); + for step in &mut self.steps { + step_buffer.refs.push(&mut step.step); + } + self.env.world.multi_sc_exec(step_buffer).await; + + self.steps + .into_iter() + .map(|step| step.process_result()) + .collect() + } +} diff --git a/framework/snippets/src/interactor_multi_sc_exec.rs b/framework/snippets/src/multi/interactor_multi_sc_exec.rs similarity index 80% rename from framework/snippets/src/interactor_multi_sc_exec.rs rename to framework/snippets/src/multi/interactor_multi_sc_exec.rs index b8035fbae6..d99df9c807 100644 --- a/framework/snippets/src/interactor_multi_sc_exec.rs +++ b/framework/snippets/src/multi/interactor_multi_sc_exec.rs @@ -1,8 +1,5 @@ -use crate::{ - interactor_multi_sc_process::{update_nonces_and_sign_tx, SenderSet, Txs}, - Interactor, StepBuffer, TransactionSpec, -}; - +use super::interactor_multi_sc_process::{update_nonces_and_sign_tx, SenderSet, Txs}; +use crate::{Interactor, InteractorStep, StepBuffer}; use multiversx_sc_scenario::scenario_model::TxResponse; use multiversx_sdk::data::transaction::Transaction; @@ -32,7 +29,7 @@ impl Interactor { for sc_call_step in &mut buffer.refs { let mut transaction = sc_call_step.to_transaction(self); - let sender_address = &sc_call_step.to_address().value; + let sender_address = &sc_call_step.sender_address().value; let sender = self .sender_map .get_mut(sender_address) @@ -45,11 +42,11 @@ impl Interactor { } } -fn retrieve_senders(sc_call_steps: &[&mut dyn TransactionSpec]) -> SenderSet { +fn retrieve_senders(sc_call_steps: &[&mut dyn InteractorStep]) -> SenderSet { let mut senders = SenderSet::new(); for sc_call_step in sc_call_steps { - let sender_address = &sc_call_step.to_address().value; + let sender_address = &sc_call_step.sender_address().value; senders.insert(sender_address.clone()); } senders diff --git a/framework/snippets/src/interactor_multi_sc_process.rs b/framework/snippets/src/multi/interactor_multi_sc_process.rs similarity index 100% rename from framework/snippets/src/interactor_multi_sc_process.rs rename to framework/snippets/src/multi/interactor_multi_sc_process.rs diff --git a/framework/snippets/src/interactor_tx_spec.rs b/framework/snippets/src/multi/interactor_step.rs similarity index 79% rename from framework/snippets/src/interactor_tx_spec.rs rename to framework/snippets/src/multi/interactor_step.rs index 7463d37c5e..be172bbb82 100644 --- a/framework/snippets/src/interactor_tx_spec.rs +++ b/framework/snippets/src/multi/interactor_step.rs @@ -6,22 +6,23 @@ use multiversx_sdk::data::transaction::Transaction; use crate::Interactor; -pub trait TransactionSpec { +/// Describes a scenario step that can be executed in an interactor. +pub trait InteractorStep { fn to_transaction(&self, interactor: &Interactor) -> Transaction; - fn to_address(&self) -> &AddressValue; + fn sender_address(&self) -> &AddressValue; fn run_step(&mut self, step_runner: &mut dyn ScenarioRunner); fn set_response(&mut self, tx_response: TxResponse); } -impl TransactionSpec for ScCallStep { +impl InteractorStep for ScCallStep { fn to_transaction(&self, interactor: &Interactor) -> Transaction { interactor.tx_call_to_blockchain_tx(&self.tx) } - fn to_address(&self) -> &AddressValue { + fn sender_address(&self) -> &AddressValue { &self.tx.from } @@ -35,12 +36,12 @@ impl TransactionSpec for ScCallStep { } } -impl TransactionSpec for ScDeployStep { +impl InteractorStep for ScDeployStep { fn to_transaction(&self, interactor: &Interactor) -> Transaction { interactor.sc_deploy_to_blockchain_tx(self) } - fn to_address(&self) -> &AddressValue { + fn sender_address(&self) -> &AddressValue { &self.tx.from } diff --git a/framework/snippets/src/step_buffer.rs b/framework/snippets/src/multi/step_buffer.rs similarity index 89% rename from framework/snippets/src/step_buffer.rs rename to framework/snippets/src/multi/step_buffer.rs index f4956ff3a0..529b790ff5 100644 --- a/framework/snippets/src/step_buffer.rs +++ b/framework/snippets/src/multi/step_buffer.rs @@ -1,10 +1,10 @@ use multiversx_sc_scenario::scenario_model::{ScCallStep, ScDeployStep}; -use crate::TransactionSpec; +use crate::InteractorStep; #[derive(Default)] pub struct StepBuffer<'a> { - pub refs: Vec<&'a mut dyn TransactionSpec>, + pub refs: Vec<&'a mut dyn InteractorStep>, } impl<'a> StepBuffer<'a> { @@ -54,7 +54,7 @@ impl<'a> StepBuffer<'a> { buffer } - pub fn to_refs_vec(&'a self) -> Vec<&'a dyn TransactionSpec> { + pub fn to_refs_vec(&'a self) -> Vec<&'a dyn InteractorStep> { self.refs.iter().map(|r| &**r).collect() } } diff --git a/framework/wasm-adapter/Cargo.toml b/framework/wasm-adapter/Cargo.toml index 6a0814f0c7..8db81d396e 100644 --- a/framework/wasm-adapter/Cargo.toml +++ b/framework/wasm-adapter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sc-wasm-adapter" -version = "0.48.1" +version = "0.49.0-alpha.4" edition = "2021" authors = [ @@ -22,5 +22,5 @@ categories = [ ] [dependencies.multiversx-sc] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../base" diff --git a/sdk/core/Cargo.toml b/sdk/core/Cargo.toml index c3f7aefd73..88b496cd3d 100644 --- a/sdk/core/Cargo.toml +++ b/sdk/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "multiversx-sdk" -version = "0.3.2" +version = "0.4.0-alpha.4" edition = "2021" authors = [ diff --git a/sdk/core/src/data/address.rs b/sdk/core/src/data/address.rs index 9612157326..8c4af1fb37 100644 --- a/sdk/core/src/data/address.rs +++ b/sdk/core/src/data/address.rs @@ -63,6 +63,12 @@ impl Debug for Address { } } +impl Default for Address { + fn default() -> Self { + Address::from_bytes([0u8; 32]) + } +} + impl Serialize for Address { fn serialize(&self, serializer: S) -> Result where diff --git a/sdk/core/src/data/transaction.rs b/sdk/core/src/data/transaction.rs index 452f0d3679..ed0a51b8df 100644 --- a/sdk/core/src/data/transaction.rs +++ b/sdk/core/src/data/transaction.rs @@ -48,7 +48,7 @@ pub struct ResponseTxCost { } // TransactionOnNetwork holds a transaction's info entry in a hyper block -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] pub struct TransactionOnNetwork { #[serde(rename = "type")] @@ -67,19 +67,19 @@ pub struct TransactionOnNetwork { pub destination_shard: u32, pub block_nonce: u64, pub block_hash: String, - pub notarized_at_source_in_meta_nonce: u64, + pub notarized_at_source_in_meta_nonce: Option, #[serde(rename = "NotarizedAtSourceInMetaHash")] - pub notarized_at_source_in_meta_hash: String, - pub notarized_at_destination_in_meta_nonce: u64, - pub notarized_at_destination_in_meta_hash: String, + pub notarized_at_source_in_meta_hash: Option, + pub notarized_at_destination_in_meta_nonce: Option, + pub notarized_at_destination_in_meta_hash: Option, pub processing_type_on_destination: String, pub miniblock_type: String, pub miniblock_hash: String, pub timestamp: u64, pub data: Option, pub status: String, - pub hyperblock_nonce: u64, - pub hyperblock_hash: String, + pub hyperblock_nonce: Option, + pub hyperblock_hash: Option, pub smart_contract_results: Option>, pub logs: Option, } @@ -132,6 +132,7 @@ pub struct TransactionInfoData { // TransactionInfo holds a transaction info response from the network #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TransactionInfo { + #[serde(default)] pub error: String, pub code: String, pub data: Option, diff --git a/tools/mxpy-snippet-generator/Cargo.toml b/tools/mxpy-snippet-generator/Cargo.toml index 243e1e83ca..8390f16c01 100644 --- a/tools/mxpy-snippet-generator/Cargo.toml +++ b/tools/mxpy-snippet-generator/Cargo.toml @@ -10,7 +10,7 @@ name = "mxpy-snippet-generator" path = "src/mxpy_snippet_generator.rs" [dependencies.multiversx-sc] -version = "0.48.1" +version = "0.49.0-alpha.4" path = "../../framework/base" [dependencies] diff --git a/tools/rust-debugger/format-tests/Cargo.toml b/tools/rust-debugger/format-tests/Cargo.toml index 85d2128bee..b44925e9d1 100644 --- a/tools/rust-debugger/format-tests/Cargo.toml +++ b/tools/rust-debugger/format-tests/Cargo.toml @@ -9,11 +9,11 @@ name = "format-tests" path = "src/format_tests.rs" [dependencies.multiversx-sc] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../../../framework/base" [dependencies.multiversx-sc-scenario] -version = "=0.48.1" +version = "=0.49.0-alpha.4" path = "../../../framework/scenario" [dependencies.multiversx-chain-vm] diff --git a/tools/rust-debugger/format-tests/src/format_tests.rs b/tools/rust-debugger/format-tests/src/format_tests.rs index 9595691c66..5df781b92b 100644 --- a/tools/rust-debugger/format-tests/src/format_tests.rs +++ b/tools/rust-debugger/format-tests/src/format_tests.rs @@ -1,14 +1,14 @@ use multiversx_sc::{ codec::multi_types::OptionalValue, - esdt::ESDTSystemSmartContractProxy, types::{ heap::{Address, BoxedBytes}, - BigFloat, BigInt, BigUint, EgldOrEsdtTokenIdentifier, EsdtTokenPayment, ManagedAddress, - ManagedBuffer, ManagedByteArray, ManagedOption, ManagedType, ManagedVec, TokenIdentifier, + BigFloat, BigInt, BigUint, ESDTSystemSCAddress, EgldOrEsdtTokenIdentifier, + EsdtTokenPayment, ManagedAddress, ManagedBuffer, ManagedByteArray, ManagedOption, + ManagedType, ManagedVec, TokenIdentifier, }, }; use multiversx_sc_scenario::{ - api::{DebugHandle, DebugApi}, + api::{DebugApi, DebugHandle}, num_bigint::{BigInt as RustBigInt, BigUint as RustBigUint}, }; @@ -65,8 +65,7 @@ fn main() { let token_identifier: TokenIdentifier = TokenIdentifier::from("MYTOK-123456"); push!(to_check, token_identifier, "\"MYTOK-123456\""); - let system_sc = ESDTSystemSmartContractProxy::::new_proxy_obj(); - let managed_address = system_sc.esdt_system_sc_address(); + let managed_address = ESDTSystemSCAddress.to_managed_address::(); push!( to_check, managed_address, diff --git a/vm/src/world_mock/account_data.rs b/vm/src/world_mock/account_data.rs index 343c49bb8d..9268c4535c 100644 --- a/vm/src/world_mock/account_data.rs +++ b/vm/src/world_mock/account_data.rs @@ -61,13 +61,13 @@ impl fmt::Display for AccountData { write!( f, "AccountData {{ - nonce: {}, - balance: {}, - esdt: [{} ], - username: {}, - storage: [{} ], - developerRewards: {}, - }}", + nonce: {}, + balance: {}, + esdt: [{} ], + username: {}, + storage: [{} ], + developerRewards: {}, + }}", self.nonce, self.egld_balance, self.esdt, diff --git a/vm/src/world_mock/blockchain_state.rs b/vm/src/world_mock/blockchain_state.rs index 28a339f54b..6890517215 100644 --- a/vm/src/world_mock/blockchain_state.rs +++ b/vm/src/world_mock/blockchain_state.rs @@ -1,7 +1,6 @@ -use std::{collections::HashMap, fmt::Debug}; - use num_bigint::BigUint; use num_traits::Zero; +use std::{collections::HashMap, fmt::Debug}; use crate::{tx_mock::BlockchainUpdate, types::VMAddress};