diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 202f45a8..bed0c289 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -4,8 +4,11 @@ on: push: branches: - main + - feat/* pull_request: - branches: [ main ] + branches: + - main + - feat/* permissions: checks: write @@ -14,9 +17,8 @@ permissions: jobs: contracts: name: Contracts - uses: multiversx/mx-sc-actions/.github/workflows/contracts.yml@v2.3.0 + uses: multiversx/mx-sc-actions/.github/workflows/contracts.yml@v3.3.1 with: - rust-toolchain: nightly-2023-04-24 - vmtools-version: v1.4.60 + rust-toolchain: stable secrets: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index afe4d97a..4547f03a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,8 +9,7 @@ permissions: jobs: build: - uses: multiversx/mx-sc-actions/.github/workflows/reproducible-build.yml@v2.2.6 + uses: multiversx/mx-sc-actions/.github/workflows/reproducible-build.yml@v3.3.1 with: - image_tag: v4.1.4 + image_tag: v8.0.1 attach_to_existing_release: true - skip_preliminary_checks: true diff --git a/.gitignore b/.gitignore index 736952ce..3d5b3fa7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,6 @@ # will have compiled files and executables /target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock -!**/wasm*/Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..d0da69a5 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1477 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bridge-proxy" +version = "0.0.0" +dependencies = [ + "bridged-tokens-wrapper", + "crowdfunding-esdt", + "esdt-safe", + "eth-address", + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "num-bigint", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "bridge-proxy-meta" +version = "0.0.0" +dependencies = [ + "bridge-proxy", + "multiversx-sc-meta-lib", +] + +[[package]] +name = "bridged-tokens-wrapper" +version = "0.0.0" +dependencies = [ + "eth-address", + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "bridged-tokens-wrapper-meta" +version = "0.0.0" +dependencies = [ + "bridged-tokens-wrapper", + "multiversx-sc-meta-lib", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crowdfunding-esdt" +version = "0.0.0" +source = "git+https://github.com/multiversx/mx-contracts-rs?rev=d91bbff#d91bbff295295c2f7e2baf1cd569dd5693ddfb56" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "esdt-safe" +version = "0.0.0" +dependencies = [ + "eth-address", + "fee-estimator-module", + "max-bridged-amount-module", + "multiversx-price-aggregator-sc", + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "esdt-safe-meta" +version = "0.0.0" +dependencies = [ + "esdt-safe", + "multiversx-sc-meta-lib", +] + +[[package]] +name = "eth-address" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "fee-estimator-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-scenario", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[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 = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "max-bridged-amount-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-scenario", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "multi-transfer-esdt" +version = "0.0.0" +dependencies = [ + "bridge-proxy", + "bridged-tokens-wrapper", + "esdt-safe", + "eth-address", + "max-bridged-amount-module", + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "multi-transfer-esdt-meta" +version = "0.0.0" +dependencies = [ + "multi-transfer-esdt", + "multiversx-sc-meta-lib", +] + +[[package]] +name = "multisig" +version = "0.0.0" +dependencies = [ + "bridge-proxy", + "bridged-tokens-wrapper", + "esdt-safe", + "eth-address", + "fee-estimator-module", + "max-bridged-amount-module", + "multi-transfer-esdt", + "multiversx-price-aggregator-sc", + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "multisig-meta" +version = "0.0.0" +dependencies = [ + "multisig", + "multiversx-sc-meta-lib", +] + +[[package]] +name = "multiversx-chain-scenario-format" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921a66f6db5ffff311e355d42a49fd49baf72d7a6a6215b0484dcd9d8dd512a3" +dependencies = [ + "bech32", + "hex", + "num-bigint", + "num-traits", + "serde", + "serde_json", + "sha3", +] + +[[package]] +name = "multiversx-chain-vm" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d91b6ce610a3ac1272f0813284a3f03a34d55db2f86cddaff357bf651074ee" +dependencies = [ + "bitflags", + "colored", + "ed25519-dalek", + "hex", + "hex-literal", + "itertools", + "multiversx-chain-vm-executor", + "num-bigint", + "num-traits", + "rand 0.8.5", + "rand_seeder", + "sha2 0.10.8", + "sha3", +] + +[[package]] +name = "multiversx-chain-vm-executor" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b59072fa0624b55ae5ae3fa6bfa91515bbeb4ac440214bc4a509e2c8806d6e9f" + +[[package]] +name = "multiversx-price-aggregator-sc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea572ebab3a6addd937cad829076b13e320851503fb6adf1ad66f544b2bf100" +dependencies = [ + "arrayvec", + "getrandom 0.2.15", + "multiversx-sc", + "multiversx-sc-modules", + "rand 0.8.5", +] + +[[package]] +name = "multiversx-sc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "num-bigint", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-meta-lib" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8deccfcc760b8fd281e2603268fa1a453ed65e4caac7a51a2d71c40cec37ae3" +dependencies = [ + "clap", + "colored", + "convert_case", + "hex", + "lazy_static", + "multiversx-sc", + "rustc_version", + "semver", + "serde", + "serde_json", + "toml", + "wasmparser", + "wasmprinter", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-scenario" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3024d52e2cb7d455f5a560218be8968e446eabc7c31dc9fc479c329f45e05e" +dependencies = [ + "base64", + "bech32", + "colored", + "hex", + "itertools", + "log", + "multiversx-chain-scenario-format", + "multiversx-chain-vm", + "multiversx-chain-vm-executor", + "multiversx-sc", + "multiversx-sc-meta-lib", + "num-bigint", + "num-traits", + "pathdiff", + "serde", + "serde_json", + "sha2 0.10.8", + "unwrap-infallible", +] + +[[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-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "pathdiff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_seeder" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "test-caller" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "test-caller-meta" +version = "0.0.0" +dependencies = [ + "multiversx-sc-meta-lib", + "test-caller", +] + +[[package]] +name = "token-module" +version = "0.0.0" +dependencies = [ + "fee-estimator-module", + "multiversx-sc", + "multiversx-sc-scenario", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "transaction" +version = "0.0.0" +dependencies = [ + "eth-address", + "multiversx-sc", +] + +[[package]] +name = "tx-batch-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-scenario", + "transaction", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "wasmparser" +version = "0.214.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5309c1090e3e84dad0d382f42064e9933fdaedb87e468cc239f0eabea73ddcb6" +dependencies = [ + "ahash", + "bitflags", + "hashbrown 0.14.5", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "wasmprinter" +version = "0.214.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58d4f2b3f7bd2ba10f99e03f885ff90d5db3455e163bccecebbbf60406bd8980" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index f9432301..2c45d19e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,7 @@ [workspace] members = [ + "bridge-proxy", + "bridge-proxy/meta", "esdt-safe", "esdt-safe/meta", "multi-transfer-esdt", @@ -7,5 +9,7 @@ members = [ "multisig", "multisig/meta", "bridged-tokens-wrapper", - "bridged-tokens-wrapper/meta" + "bridged-tokens-wrapper/meta", + "test-caller", + "test-caller/meta" ] diff --git a/bridge-proxy/.gitignore b/bridge-proxy/.gitignore new file mode 100644 index 00000000..2c76bc98 --- /dev/null +++ b/bridge-proxy/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The mxpy output +/output*/ diff --git a/bridge-proxy/Cargo.toml b/bridge-proxy/Cargo.toml new file mode 100644 index 00000000..dcd40cbb --- /dev/null +++ b/bridge-proxy/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "bridge-proxy" +version = "0.0.0" +authors = ["Costin CarabaČ™ "] +edition = "2018" +publish = false + +[lib] +path = "src/bridge-proxy.rs" + +[dependencies.transaction] +path = "../common/transaction" + +[dependencies.eth-address] +path = "../common/eth-address" + +[dependencies.token-module] +path = "../common/token-module" + +[dependencies.tx-batch-module] +path = "../common/tx-batch-module" + +[dependencies.esdt-safe] +path = "../esdt-safe" + +[dependencies.bridged-tokens-wrapper] +path = "../bridged-tokens-wrapper" + +[dependencies.multiversx-sc] +version = "=0.52.3" + +[dependencies.multiversx-sc-modules] +version = "0.52.3" + +[dependencies.crowdfunding-esdt] +git = "https://github.com/multiversx/mx-contracts-rs" +rev = "d91bbff" + +[dev-dependencies] +num-bigint = "0.4.2" + +[dev-dependencies.multiversx-sc-scenario] +version = "=0.52.3" diff --git a/bridge-proxy/meta/Cargo.toml b/bridge-proxy/meta/Cargo.toml new file mode 100644 index 00000000..9e646b0b --- /dev/null +++ b/bridge-proxy/meta/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "bridge-proxy-meta" +version = "0.0.0" +edition = "2018" +publish = false +authors = ["you"] + +[dev-dependencies] + +[dependencies.bridge-proxy] +path = ".." + +[dependencies.multiversx-sc-meta-lib] +version = "=0.52.3" diff --git a/bridge-proxy/meta/src/main.rs b/bridge-proxy/meta/src/main.rs new file mode 100644 index 00000000..4e648642 --- /dev/null +++ b/bridge-proxy/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta_lib::cli_main::(); +} diff --git a/bridge-proxy/multiversx.json b/bridge-proxy/multiversx.json new file mode 100644 index 00000000..73655396 --- /dev/null +++ b/bridge-proxy/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/bridge-proxy/sc-config.toml b/bridge-proxy/sc-config.toml new file mode 100644 index 00000000..91f6f1ee --- /dev/null +++ b/bridge-proxy/sc-config.toml @@ -0,0 +1,10 @@ +[settings] + +[[proxy]] +path = "../multi-transfer-esdt/src/bridge_proxy_contract_proxy.rs" + +[[proxy]] +path = "../multisig/src/bridge_proxy_contract_proxy.rs" + +[[proxy]] +path = "./src/bridge_proxy_contract_proxy.rs" \ No newline at end of file diff --git a/bridge-proxy/scenarios/bridge_proxy_execute_crowdfunding.scen.json b/bridge-proxy/scenarios/bridge_proxy_execute_crowdfunding.scen.json new file mode 100644 index 00000000..f2a48dfc --- /dev/null +++ b/bridge-proxy/scenarios/bridge_proxy_execute_crowdfunding.scen.json @@ -0,0 +1,236 @@ +{ + "steps": [ + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:bridge-proxy" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:output/bridge-proxy.mxsc.json", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "2", + "newAddress": "sc:crowfunding" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:tests/test-contract/crowdfunding-esdt.mxsc.json", + "arguments": [ + "0x07d0", + "0x093a80", + "0x4252494447452d313233343536" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "setBridgedTokensWrapperAddress", + "arguments": [ + "0x00000000000000000500627269646765642d746f6b656e732d77726170706572" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "function": "whitelistToken", + "arguments": [ + "0x4252494447452d313233343536", + "0x12", + "0x574252494447452d313233343536" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "function": "addWrappedToken", + "arguments": [ + "0x574252494447452d313233343536", + "0x12" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "esdtValue": [ + { + "tokenIdentifier": "0x4252494447452d313233343536", + "value": "5000" + } + ], + "function": "depositLiquidity", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multi-transfer", + "to": "sc:bridge-proxy", + "esdtValue": [ + { + "tokenIdentifier": "0x4252494447452d313233343536", + "value": "500" + } + ], + "function": "deposit", + "arguments": [ + "0x30313032303330343035303630373038303931300000000000000000050063726f7766756e64696e675f5f5f5f5f5f5f5f5f5f5f0000000d4252494447452d3132333435360000000201f4000000000000000101000000150000000466756e6400000000009896800100000000", + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:bridge-proxy", + "function": "getPendingTransactionById", + "arguments": [ + "0x01" + ] + }, + "expect": { + "out": [ + "0x30313032303330343035303630373038303931300000000000000000050063726f7766756e64696e675f5f5f5f5f5f5f5f5f5f5f0000000d4252494447452d3132333435360000000201f4000000000000000101000000150000000466756e6400000000009896800100000000" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "execute", + "arguments": [ + "0x01" + ], + "gasLimit": "200000000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:crowfunding", + "function": "getCurrentFunds", + "arguments": [] + }, + "expect": { + "out": [ + "0x01f4" + ], + "status": "0" + } + } + ] +} diff --git a/bridge-proxy/src/bridge-proxy.rs b/bridge-proxy/src/bridge-proxy.rs new file mode 100644 index 00000000..17f5bec7 --- /dev/null +++ b/bridge-proxy/src/bridge-proxy.rs @@ -0,0 +1,221 @@ +#![no_std] +use multiversx_sc::imports::*; + +pub mod bridge_proxy_contract_proxy; +pub mod bridged_tokens_wrapper_proxy; +pub mod config; +pub mod esdt_safe_proxy; + +use transaction::{CallData, EthTransaction}; +const MIN_GAS_LIMIT_FOR_SC_CALL: u64 = 10_000_000; +const MAX_GAS_LIMIT_FOR_SC_CALL: u64 = 249999999; +const DEFAULT_GAS_LIMIT_FOR_REFUND_CALLBACK: u64 = 20_000_000; // 20 million +const DELAY_BEFORE_OWNER_CAN_CANCEL_TRANSACTION: u64 = 300; + +#[multiversx_sc::contract] +pub trait BridgeProxyContract: + config::ConfigModule + + multiversx_sc_modules::pause::PauseModule +{ + #[init] + fn init(&self, opt_multi_transfer_address: OptionalValue) { + self.set_multi_transfer_contract_address(opt_multi_transfer_address); + self.set_paused(true); + } + + #[upgrade] + fn upgrade(&self) { + self.set_paused(true); + } + + #[payable("*")] + #[endpoint] + fn deposit(&self, eth_tx: EthTransaction, batch_id: u64) { + self.require_not_paused(); + let caller = self.blockchain().get_caller(); + let payment = self.call_value().single_esdt(); + require!( + caller == self.multi_transfer_address().get(), + "Only MultiTransfer can do deposits" + ); + let next_tx_id = self.get_next_tx_id(); + self.pending_transactions().insert(next_tx_id, eth_tx); + self.payments(next_tx_id).set(&payment); + self.batch_id(next_tx_id).set(batch_id); + } + + #[endpoint(execute)] + fn execute(&self, tx_id: usize) { + self.require_not_paused(); + require!( + self.ongoing_execution(tx_id).is_empty(), + "Transaction is already being executed" + ); + let tx = self.get_pending_transaction_by_id(tx_id); + let payment = self.payments(tx_id).get(); + + require!(payment.amount != 0, "No amount bridged"); + + let call_data: CallData = if tx.call_data.is_some() { + let unwraped_call_data = unsafe { tx.call_data.unwrap_no_check() }; + + let Ok(call_data) = CallData::top_decode(unwraped_call_data) else { + self.finish_execute_gracefully(tx_id); + return; + }; + + call_data + } else { + CallData::default() + }; + + if call_data.endpoint.is_empty() + || call_data.gas_limit < MIN_GAS_LIMIT_FOR_SC_CALL + || call_data.gas_limit > MAX_GAS_LIMIT_FOR_SC_CALL + { + self.finish_execute_gracefully(tx_id); + return; + } + + let gas_left = self.blockchain().get_gas_left(); + require!( + gas_left > call_data.gas_limit + DEFAULT_GAS_LIMIT_FOR_REFUND_CALLBACK, + "Not enough gas to execute" + ); + + let tx_call = self + .tx() + .to(&tx.to) + .raw_call(call_data.endpoint) + .gas(call_data.gas_limit) + .callback(self.callbacks().execution_callback(tx_id)) + .with_extra_gas_for_callback(DEFAULT_GAS_LIMIT_FOR_REFUND_CALLBACK) + .with_esdt_transfer(payment); + + let tx_call = if call_data.args.is_some() { + let args = unsafe { call_data.args.unwrap_no_check() }; + tx_call.arguments_raw(args.into()) + } else { + tx_call + }; + + let block_round = self.blockchain().get_block_round(); + self.ongoing_execution(tx_id).set(block_round); + tx_call.register_promise(); + } + + // TODO: will activate endpoint in a future release + // #[endpoint(cancel)] + fn cancel(&self, tx_id: usize) { + let tx_start_round = self.ongoing_execution(tx_id).get(); + let current_block_round = self.blockchain().get_block_round(); + require!( + current_block_round - tx_start_round > DELAY_BEFORE_OWNER_CAN_CANCEL_TRANSACTION, + "Transaction can't be cancelled yet" + ); + + let tx = self.get_pending_transaction_by_id(tx_id); + let payment = self.payments(tx_id).get(); + self.tx().to(tx.to).payment(payment).transfer(); + self.cleanup_transaction(tx_id); + } + #[promises_callback] + fn execution_callback(&self, #[call_result] result: ManagedAsyncCallResult<()>, tx_id: usize) { + if result.is_err() { + self.refund_transaction(tx_id); + } + self.cleanup_transaction(tx_id); + } + + fn refund_transaction(&self, tx_id: usize) { + let tx = self.get_pending_transaction_by_id(tx_id); + let esdt_safe_contract_address = self.esdt_safe_contract_address().get(); + + let unwrapped_token = self.unwrap_token(&tx.token_id, tx_id); + let batch_id = self.batch_id(tx_id).get(); + self.tx() + .to(esdt_safe_contract_address) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .create_transaction( + tx.from, + OptionalValue::Some(esdt_safe_proxy::RefundInfo { + address: tx.to, + initial_batch_id: batch_id, + initial_nonce: tx.tx_nonce, + }), + ) + .single_esdt( + &unwrapped_token.token_identifier, + unwrapped_token.token_nonce, + &unwrapped_token.amount, + ) + .sync_call(); + } + + fn unwrap_token(&self, requested_token: &TokenIdentifier, tx_id: usize) -> EsdtTokenPayment { + let payment = self.payments(tx_id).get(); + let bridged_tokens_wrapper_address = self.bridged_tokens_wrapper_address().get(); + + if requested_token == &payment.token_identifier { + return payment; + } + + let transfers = self + .tx() + .to(&bridged_tokens_wrapper_address) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unwrap_token(requested_token) + .single_esdt( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ) + .returns(ReturnsBackTransfers) + .sync_call(); + + require!( + transfers.total_egld_amount == 0, + "Expected only one esdt payment" + ); + require!( + transfers.esdt_payments.len() == 1, + "Expected only one esdt payment" + ); + transfers.esdt_payments.get(0) + } + + fn finish_execute_gracefully(&self, tx_id: usize) { + self.refund_transaction(tx_id); + self.cleanup_transaction(tx_id); + } + + fn cleanup_transaction(&self, tx_id: usize) { + self.pending_transactions().remove(&tx_id); + self.ongoing_execution(tx_id).clear(); + } + + fn get_next_tx_id(&self) -> usize { + let mut next_tx_id = self.highest_tx_id().get(); + next_tx_id += 1; + self.highest_tx_id().set(next_tx_id); + next_tx_id + } + + #[view(getPendingTransactionById)] + fn get_pending_transaction_by_id(&self, tx_id: usize) -> EthTransaction { + let tx = self.pending_transactions().get(&tx_id); + require!(tx.is_some(), "Invalid tx id"); + tx.unwrap() + } + + #[view(getPendingTransactions)] + fn get_pending_transactions( + &self, + ) -> MultiValueEncoded>> { + let mut transactions = MultiValueEncoded::new(); + for (tx_id, tx) in self.pending_transactions().iter() { + transactions.push(MultiValue2((tx_id, tx))); + } + transactions + } +} diff --git a/bridge-proxy/src/bridge_proxy_contract_proxy.rs b/bridge-proxy/src/bridge_proxy_contract_proxy.rs new file mode 100644 index 00000000..3cb21d18 --- /dev/null +++ b/bridge-proxy/src/bridge_proxy_contract_proxy.rs @@ -0,0 +1,239 @@ +// 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 BridgeProxyContractProxy; + +impl TxProxyTrait for BridgeProxyContractProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = BridgeProxyContractProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + BridgeProxyContractProxyMethods { wrapped_tx: tx } + } +} + +pub struct BridgeProxyContractProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + opt_multi_transfer_address: Arg0, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&opt_multi_transfer_address) + .original_result() + } +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn deposit< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + eth_tx: Arg0, + batch_id: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("deposit") + .argument(ð_tx) + .argument(&batch_id) + .original_result() + } + + pub fn execute< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("execute") + .argument(&tx_id) + .original_result() + } + + pub fn get_pending_transaction_by_id< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPendingTransactionById") + .argument(&tx_id) + .original_result() + } + + pub fn get_pending_transactions( + self, + ) -> TxTypedCall>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPendingTransactions") + .original_result() + } + + pub fn set_multi_transfer_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_multi_transfer_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferAddress") + .argument(&opt_multi_transfer_address) + .original_result() + } + + pub fn set_bridged_tokens_wrapper_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgedTokensWrapperAddress") + .argument(&opt_address) + .original_result() + } + + pub fn set_esdt_safe_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEsdtSafeAddress") + .argument(&opt_address) + .original_result() + } + + pub fn multi_transfer_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferAddress") + .original_result() + } + + pub fn bridged_tokens_wrapper_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgedTokensWrapperAddress") + .original_result() + } + + pub fn esdt_safe_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEsdtSafeContractAddress") + .original_result() + } + + pub fn highest_tx_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("highestTxId") + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} diff --git a/bridge-proxy/src/bridged_tokens_wrapper_proxy.rs b/bridge-proxy/src/bridged_tokens_wrapper_proxy.rs new file mode 100644 index 00000000..ac306e11 --- /dev/null +++ b/bridge-proxy/src/bridged_tokens_wrapper_proxy.rs @@ -0,0 +1,298 @@ +// 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 BridgedTokensWrapperProxy; + +impl TxProxyTrait for BridgedTokensWrapperProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = BridgedTokensWrapperProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + BridgedTokensWrapperProxyMethods { wrapped_tx: tx } + } +} + +pub struct BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn add_wrapped_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + universal_bridged_token_ids: Arg0, + num_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addWrappedToken") + .argument(&universal_bridged_token_ids) + .argument(&num_decimals) + .original_result() + } + + pub fn update_wrapped_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + universal_bridged_token_ids: Arg0, + num_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateWrappedToken") + .argument(&universal_bridged_token_ids) + .argument(&num_decimals) + .original_result() + } + + pub fn remove_wrapped_token< + Arg0: ProxyArg>, + >( + self, + universal_bridged_token_ids: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeWrappedToken") + .argument(&universal_bridged_token_ids) + .original_result() + } + + pub fn whitelist_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + chain_specific_token_id: Arg0, + chain_specific_token_decimals: Arg1, + universal_bridged_token_ids: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("whitelistToken") + .argument(&chain_specific_token_id) + .argument(&chain_specific_token_decimals) + .argument(&universal_bridged_token_ids) + .original_result() + } + + pub fn update_whitelisted_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + chain_specific_token_id: Arg0, + chain_specific_token_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateWhitelistedToken") + .argument(&chain_specific_token_id) + .argument(&chain_specific_token_decimals) + .original_result() + } + + pub fn blacklist_token< + Arg0: ProxyArg>, + >( + self, + chain_specific_token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("blacklistToken") + .argument(&chain_specific_token_id) + .original_result() + } + + pub fn deposit_liquidity( + self, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("depositLiquidity") + .original_result() + } + + /// Will wrap what it can, and send back the rest unchanged + pub fn wrap_tokens( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .raw_call("wrapTokens") + .original_result() + } + + pub fn unwrap_token< + Arg0: ProxyArg>, + >( + self, + requested_token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("unwrapToken") + .argument(&requested_token) + .original_result() + } + + pub fn unwrap_token_create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + requested_token: Arg0, + safe_address: Arg1, + to: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("unwrapTokenCreateTransaction") + .argument(&requested_token) + .argument(&safe_address) + .argument(&to) + .original_result() + } + + pub fn universal_bridged_token_ids( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getUniversalBridgedTokenIds") + .original_result() + } + + pub fn token_liquidity< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokenLiquidity") + .argument(&token) + .original_result() + } + + pub fn chain_specific_to_universal_mapping< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getChainSpecificToUniversalMapping") + .argument(&token) + .original_result() + } + + pub fn chain_specific_token_ids< + Arg0: ProxyArg>, + >( + self, + universal_token_id: Arg0, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getchainSpecificTokenIds") + .argument(&universal_token_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} diff --git a/bridge-proxy/src/config.rs b/bridge-proxy/src/config.rs new file mode 100644 index 00000000..6c81b837 --- /dev/null +++ b/bridge-proxy/src/config.rs @@ -0,0 +1,85 @@ +use multiversx_sc::imports::*; + +use transaction::EthTransaction; + +#[multiversx_sc::module] +pub trait ConfigModule { + #[only_owner] + #[endpoint(setMultiTransferAddress)] + fn set_multi_transfer_contract_address( + &self, + opt_multi_transfer_address: OptionalValue, + ) { + match opt_multi_transfer_address { + OptionalValue::Some(sc_addr) => { + require!( + self.blockchain().is_smart_contract(&sc_addr), + "Invalid multi-transfer address" + ); + self.multi_transfer_address().set(&sc_addr); + } + OptionalValue::None => self.multi_transfer_address().clear(), + } + } + + #[only_owner] + #[endpoint(setBridgedTokensWrapperAddress)] + fn set_bridged_tokens_wrapper_contract_address( + &self, + opt_address: OptionalValue, + ) { + match opt_address { + OptionalValue::Some(sc_addr) => { + require!( + self.blockchain().is_smart_contract(&sc_addr), + "Invalid bridged tokens wrapper address" + ); + self.bridged_tokens_wrapper_address().set(&sc_addr); + } + OptionalValue::None => self.bridged_tokens_wrapper_address().clear(), + } + } + + #[only_owner] + #[endpoint(setEsdtSafeAddress)] + fn set_esdt_safe_contract_address(&self, opt_address: OptionalValue) { + match opt_address { + OptionalValue::Some(sc_addr) => { + require!( + self.blockchain().is_smart_contract(&sc_addr), + "Invalid bridged tokens wrapper address" + ); + self.esdt_safe_contract_address().set(&sc_addr); + } + OptionalValue::None => self.esdt_safe_contract_address().clear(), + } + } + + #[view(getMultiTransferAddress)] + #[storage_mapper("multiTransferAddress")] + fn multi_transfer_address(&self) -> SingleValueMapper; + + #[view(getBridgedTokensWrapperAddress)] + #[storage_mapper("bridgedTokensWrapperAddress")] + fn bridged_tokens_wrapper_address(&self) -> SingleValueMapper; + + #[view(getEsdtSafeContractAddress)] + #[storage_mapper("esdtSafeContractAddress")] + fn esdt_safe_contract_address(&self) -> SingleValueMapper; + + #[storage_mapper("pending_transactions")] + fn pending_transactions(&self) -> MapMapper>; + + #[storage_mapper("payments")] + fn payments(&self, tx_id: usize) -> SingleValueMapper>; + + #[storage_mapper("batch_id")] + fn batch_id(&self, tx_id: usize) -> SingleValueMapper; + + #[view(highestTxId)] + #[storage_mapper("highest_tx_id")] + fn highest_tx_id(&self) -> SingleValueMapper; + + #[storage_mapper("ongoingExecution")] + fn ongoing_execution(&self, tx_id: usize) -> SingleValueMapper; +} diff --git a/bridge-proxy/src/crowdfunding_esdt_proxy.rs b/bridge-proxy/src/crowdfunding_esdt_proxy.rs new file mode 100644 index 00000000..aabd42cc --- /dev/null +++ b/bridge-proxy/src/crowdfunding_esdt_proxy.rs @@ -0,0 +1,157 @@ +// 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, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("fund") + .original_result() + } + + pub fn status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("status") + .original_result() + } + + pub fn get_current_funds( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentFunds") + .original_result() + } + + pub fn claim( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("claim") + .original_result() + } + + pub fn target( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTarget") + .original_result() + } + + pub fn deadline( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getDeadline") + .original_result() + } + + pub fn deposit< + Arg0: ProxyArg>, + >( + self, + donor: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getDeposit") + .argument(&donor) + .original_result() + } + + pub fn cf_token_identifier( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCrowdfundingTokenIdentifier") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, PartialEq, Eq, Clone, Copy, Debug)] +pub enum Status { + FundingPeriod, + Successful, + Failed, +} diff --git a/bridge-proxy/src/esdt_safe_proxy.rs b/bridge-proxy/src/esdt_safe_proxy.rs new file mode 100644 index 00000000..3832da69 --- /dev/null +++ b/bridge-proxy/src/esdt_safe_proxy.rs @@ -0,0 +1,810 @@ +// 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 EsdtSafeProxy; + +impl TxProxyTrait for EsdtSafeProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = EsdtSafeProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + EsdtSafeProxyMethods { wrapped_tx: tx } + } +} + +pub struct EsdtSafeProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + /// fee_estimator_contract_address - The address of a Price Aggregator contract, + /// which will get the price of token A in token B + /// + /// eth_tx_gas_limit - The gas limit that will be used for transactions on the ETH side. + /// Will be used to compute the fees for the transfer + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + eth_tx_gas_limit: Arg2, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + bridge_proxy_contract_address: Arg2, + eth_tx_gas_limit: Arg3, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(&bridge_proxy_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Sets the statuses for the transactions, after they were executed on the Ethereum side. + /// + /// Only TransactionStatus::Executed (3) and TransactionStatus::Rejected (4) values are allowed. + /// Number of provided statuses must be equal to number of transactions in the batch. + pub fn set_transaction_batch_status< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + batch_id: Arg0, + tx_statuses: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTransactionBatchStatus") + .argument(&batch_id) + .argument(&tx_statuses) + .original_result() + } + + /// Converts failed Ethereum -> MultiversX transactions to MultiversX -> Ethereum transaction. + /// This is done every now and then to refund the tokens. + /// + /// As with normal MultiversX -> Ethereum transactions, a part of the tokens will be + /// subtracted to pay for the fees + pub fn add_refund_batch< + Arg0: ProxyArg>>, + >( + self, + refund_transactions: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addRefundBatch") + .argument(&refund_transactions) + .original_result() + } + + /// Create an MultiversX -> Ethereum transaction. Only fungible tokens are accepted. + /// + /// Every transfer will have a part of the tokens subtracted as fees. + /// The fee amount depends on the global eth_tx_gas_limit + /// and the current GWEI price, respective to the bridged token + /// + /// fee_amount = price_per_gas_unit * eth_tx_gas_limit + pub fn create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + opt_refund_info: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("createTransaction") + .argument(&to) + .argument(&opt_refund_info) + .original_result() + } + + /// Claim funds for failed MultiversX -> Ethereum transactions. + /// These are not sent automatically to prevent the contract getting stuck. + /// For example, if the receiver is a SC, a frozen account, etc. + pub fn claim_refund< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("claimRefund") + .argument(&token_id) + .original_result() + } + + pub fn set_bridged_tokens_wrapper_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgedTokensWrapperAddress") + .argument(&opt_address) + .original_result() + } + + pub fn set_bridge_proxy_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgeProxyContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn withdraw_refund_fees_for_ethereum< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawRefundFeesForEthereum") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn withdraw_transaction_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawTransactionFees") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn compute_total_amounts_from_index< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + start_index: Arg0, + end_index: Arg1, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("computeTotalAmmountsFromIndex") + .argument(&start_index) + .argument(&end_index) + .original_result() + } + + /// Query function that lists all refund amounts for a user. + /// Useful for knowing which token IDs to pass to the claimRefund endpoint. + pub fn get_refund_amounts< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundAmounts") + .argument(&address) + .original_result() + } + + pub fn get_total_refund_amounts( + self, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalRefundAmounts") + .original_result() + } + + pub fn get_refund_fees_for_ethereum< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundFeesForEthereum") + .argument(&token_id) + .original_result() + } + + pub fn get_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn bridged_tokens_wrapper_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgedTokensWrapperAddress") + .original_result() + } + + pub fn bridge_proxy_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgeProxyContractAddress") + .original_result() + } + + pub fn set_fee_estimator_contract_address< + Arg0: ProxyArg>, + >( + self, + new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setFeeEstimatorContractAddress") + .argument(&new_address) + .original_result() + } + + pub fn set_eth_tx_gas_limit< + Arg0: ProxyArg>, + >( + self, + new_limit: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEthTxGasLimit") + .argument(&new_limit) + .original_result() + } + + /// Default price being used if the aggregator lacks a mapping for this token + /// or the aggregator address is not set + pub fn set_default_price_per_gas_unit< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + default_price_per_gas_unit: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setDefaultPricePerGasUnit") + .argument(&token_id) + .argument(&default_price_per_gas_unit) + .original_result() + } + + /// Token ticker being used when querying the aggregator for GWEI prices + pub fn set_token_ticker< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + ticker: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTokenTicker") + .argument(&token_id) + .argument(&ticker) + .original_result() + } + + /// Returns the fee for the given token ID (the fee amount is in the given token) + pub fn calculate_required_fee< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("calculateRequiredFee") + .argument(&token_id) + .original_result() + } + + pub fn fee_estimator_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeEstimatorContractAddress") + .original_result() + } + + pub fn default_price_per_gas_unit< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getDefaultPricePerGasUnit") + .argument(&token_id) + .original_result() + } + + pub fn eth_tx_gas_limit( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEthTxGasLimit") + .original_result() + } + + /// Distributes the accumulated fees to the given addresses. + /// Expected arguments are pairs of (address, percentage), + /// where percentages must add up to the PERCENTAGE_TOTAL constant + pub fn distribute_fees< + Arg0: ProxyArg>>, + >( + self, + address_percentage_pairs: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributeFees") + .argument(&address_percentage_pairs) + .original_result() + } + + pub fn add_token_to_whitelist< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg>, + Arg7: ProxyArg>>, + >( + self, + token_id: Arg0, + ticker: Arg1, + mint_burn_token: Arg2, + native_token: Arg3, + total_balance: Arg4, + mint_balance: Arg5, + burn_balance: Arg6, + opt_default_price_per_gas_unit: Arg7, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addTokenToWhitelist") + .argument(&token_id) + .argument(&ticker) + .argument(&mint_burn_token) + .argument(&native_token) + .argument(&total_balance) + .argument(&mint_balance) + .argument(&burn_balance) + .argument(&opt_default_price_per_gas_unit) + .original_result() + } + + pub fn remove_token_from_whitelist< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeTokenFromWhitelist") + .argument(&token_id) + .original_result() + } + + pub fn get_tokens< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokens") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("initSupply") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply_mint_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_id: Arg0, + mint_amount: Arg1, + burn_amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("initSupplyMintBurn") + .argument(&token_id) + .argument(&mint_amount) + .argument(&burn_amount) + .original_result() + } + + pub fn set_multi_transfer_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn token_whitelist( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAllKnownTokens") + .original_result() + } + + pub fn native_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isNativeToken") + .argument(&token) + .original_result() + } + + pub fn mint_burn_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isMintBurnToken") + .argument(&token) + .original_result() + } + + pub fn multi_transfer_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferContractAddress") + .original_result() + } + + pub fn accumulated_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAccumulatedTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn total_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalBalances") + .argument(&token_id) + .original_result() + } + + pub fn mint_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMintBalances") + .argument(&token_id) + .original_result() + } + + pub fn burn_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBurnBalances") + .argument(&token_id) + .original_result() + } + + pub fn set_max_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + pub fn set_max_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + pub fn get_current_tx_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentTxBatch") + .original_result() + } + + pub fn get_first_batch_any_status( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchAnyStatus") + .original_result() + } + + pub fn get_batch< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatch") + .argument(&batch_id) + .original_result() + } + + pub fn get_batch_status< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatchStatus") + .argument(&batch_id) + .original_result() + } + + pub fn first_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchId") + .original_result() + } + + pub fn last_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastBatchId") + .original_result() + } + + pub fn set_max_bridged_amount< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxBridgedAmount") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + pub fn max_bridged_amount< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMaxBridgedAmount") + .argument(&token_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, ManagedVecItem, PartialEq)] +pub struct RefundInfo +where + Api: ManagedTypeApi, +{ + pub address: ManagedAddress, + pub initial_batch_id: u64, + pub initial_nonce: u64, +} diff --git a/bridge-proxy/tests/bridge_proxy_blackbox_test.rs b/bridge-proxy/tests/bridge_proxy_blackbox_test.rs new file mode 100644 index 00000000..c4693ecc --- /dev/null +++ b/bridge-proxy/tests/bridge_proxy_blackbox_test.rs @@ -0,0 +1,497 @@ +#![allow(unused)] + +use std::collections::LinkedList; +use std::ops::Add; + +use bridge_proxy::{bridge_proxy_contract_proxy, config::ProxyTrait as _}; +use bridge_proxy::{bridged_tokens_wrapper_proxy, ProxyTrait}; + +use crowdfunding_esdt::crowdfunding_esdt_proxy; +use multiversx_sc::codec::NestedEncode; +use multiversx_sc::contract_base::ManagedSerializer; +use multiversx_sc::sc_print; +use multiversx_sc::types::{ + EgldOrEsdtTokenIdentifier, EsdtTokenPayment, ManagedOption, ReturnsNewAddress, TestAddress, + TestSCAddress, TestTokenIdentifier, +}; +use multiversx_sc::{ + api::{HandleConstraints, ManagedTypeApi}, + codec::{ + multi_types::{MultiValueVec, OptionalValue}, + TopEncodeMultiOutput, + }, + storage::mappers::SingleValue, + types::{ + Address, BigUint, CodeMetadata, ManagedAddress, ManagedArgBuffer, ManagedBuffer, + ManagedByteArray, ManagedVec, TokenIdentifier, + }, +}; +use multiversx_sc_scenario::imports::MxscPath; +use multiversx_sc_scenario::{ + api::StaticApi, + rust_biguint, + scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, + scenario_model::*, + ContractInfo, ScenarioWorld, +}; +use multiversx_sc_scenario::{ExpectValue, ScenarioTxRun}; + +use eth_address::*; +use transaction::{CallData, EthTransaction}; + +const BRIDGE_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("BRIDGE-123456"); +const WBRIDGE_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("WBRIDGE-123456"); + +const GAS_LIMIT: u64 = 10_000_000; +const CF_DEADLINE: u64 = 7 * 24 * 60 * 60; // 1 week in seconds + +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const BRIDGE_PROXY_ADDRESS: TestSCAddress = TestSCAddress::new("bridge-proxy"); +const CROWDFUNDING_ADDRESS: TestSCAddress = TestSCAddress::new("crowfunding"); +const MULTI_TRANSFER_ADDRESS: TestSCAddress = TestSCAddress::new("multi-transfer"); +const ESDT_SAFE_ADDRESS: TestSCAddress = TestSCAddress::new("esdt-safe"); +const BRIDGED_TOKENS_WRAPPER_ADDRESS: TestSCAddress = TestSCAddress::new("bridged-tokens-wrapper"); + +const BRIDGE_PROXY_PATH_EXPR: MxscPath = MxscPath::new("output/bridge-proxy.mxsc.json"); +const CROWDFUNDING_PATH_EXPR: MxscPath = + MxscPath::new("tests/test-contract/crowdfunding-esdt.mxsc.json"); +const MULTI_TRANSFER_PATH_EXPR: &str = + "mxsc:../multi-transfer-esdt/output/multi-transfer-esdt.mxsc.json"; +const ESDT_SAFE_PATH_EXPR: &str = "mxsc:../esdt-safe/output/esdt-safe.mxsc.json"; +const BRIDGED_TOKENS_WRAPPER_CODE_PATH_EXPR: MxscPath = + MxscPath::new("../bridged-tokens-wrapper/output/bridged-tokens-wrapper.mxsc.json"); + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract(BRIDGE_PROXY_PATH_EXPR, bridge_proxy::ContractBuilder); + blockchain.register_contract(CROWDFUNDING_PATH_EXPR, crowdfunding_esdt::ContractBuilder); + blockchain.register_contract( + BRIDGED_TOKENS_WRAPPER_CODE_PATH_EXPR, + bridged_tokens_wrapper::ContractBuilder, + ); + blockchain.register_contract(ESDT_SAFE_PATH_EXPR, esdt_safe::ContractBuilder); + + blockchain +} + +type BridgeProxyContract = ContractInfo>; +type CrowdfundingContract = ContractInfo>; +type BridgedTokensWrapperContract = ContractInfo>; + +struct BridgeProxyTestState { + world: ScenarioWorld, +} + +impl BridgeProxyTestState { + fn new() -> Self { + let mut world = world(); + let multi_transfer_code = world.code_expression(MULTI_TRANSFER_PATH_EXPR); + let esdt_safe_code = world.code_expression(ESDT_SAFE_PATH_EXPR); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .esdt_balance(TokenIdentifier::from(BRIDGE_TOKEN_ID), 10_000u64) + .account(MULTI_TRANSFER_ADDRESS) + .esdt_balance(TokenIdentifier::from(WBRIDGE_TOKEN_ID), 10_000u64) + .esdt_balance(TokenIdentifier::from(BRIDGE_TOKEN_ID), 10_000u64) + .code(multi_transfer_code) + .account(ESDT_SAFE_ADDRESS) + .code(esdt_safe_code); + + let roles = vec![ + "ESDTRoleLocalMint".to_string(), + "ESDTRoleLocalBurn".to_string(), + ]; + world + .account(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .esdt_roles(WBRIDGE_TOKEN_ID, roles.clone()) + .esdt_roles(BRIDGE_TOKEN_ID, roles) + .esdt_balance(TokenIdentifier::from(WBRIDGE_TOKEN_ID), 10_000u64) + .esdt_balance(TokenIdentifier::from(BRIDGE_TOKEN_ID), 10_000u64) + .code(BRIDGED_TOKENS_WRAPPER_CODE_PATH_EXPR) + .owner(OWNER_ADDRESS); + + Self { world } + } + + fn bridge_proxy_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .init(OptionalValue::Some(MULTI_TRANSFER_ADDRESS)) + .code(BRIDGE_PROXY_PATH_EXPR) + .new_address(BRIDGE_PROXY_ADDRESS) + .run(); + + self + } + + fn bridged_tokens_wrapper_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .init() + .code(BRIDGED_TOKENS_WRAPPER_CODE_PATH_EXPR) + .new_address(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .run(); + + self + } + + fn deploy_crowdfunding(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .init( + 2_000u32, + CF_DEADLINE, + EgldOrEsdtTokenIdentifier::esdt(BRIDGE_TOKEN_ID), + ) + .code(CROWDFUNDING_PATH_EXPR) + .new_address(CROWDFUNDING_ADDRESS) + .run(); + self + } + + fn config_bridge(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .set_bridged_tokens_wrapper_contract_address(OptionalValue::Some( + BRIDGED_TOKENS_WRAPPER_ADDRESS, + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .whitelist_token(BRIDGE_TOKEN_ID, 18u32, WBRIDGE_TOKEN_ID) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .add_wrapped_token(WBRIDGE_TOKEN_ID, 18u32) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .deposit_liquidity() + .single_esdt( + &TokenIdentifier::from(BRIDGE_TOKEN_ID), + 0u64, + &BigUint::from(5_000u64), + ) + .run(); + + self + } +} + +#[test] +fn deploy_test() { + let mut test = BridgeProxyTestState::new(); + + test.bridge_proxy_deploy(); + test.deploy_crowdfunding(); + test.config_bridge(); +} + +#[test] +fn bridge_proxy_execute_crowdfunding_test() { + let mut test = BridgeProxyTestState::new(); + + test.world.start_trace(); + + test.bridge_proxy_deploy(); + test.deploy_crowdfunding(); + test.config_bridge(); + + let mut args = ManagedVec::new(); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from("fund"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + + let call_data: ManagedBuffer = + ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()), + token_id: BRIDGE_TOKEN_ID.into(), + amount: BigUint::from(500u64), + tx_nonce: 1u64, + call_data: ManagedOption::some(call_data), + }; + + test.world + .tx() + .from(MULTI_TRANSFER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .deposit(ð_tx, 1u64) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(BRIDGE_TOKEN_ID), + 0, + &BigUint::from(500u64), + ) + .run(); + + test.world + .query() + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .get_pending_transaction_by_id(1u32) + .returns(ExpectValue(eth_tx)) + .run(); + + test.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .gas(200_000_000) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .execute(1u32) + .run(); + + test.world + .query() + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .get_current_funds() + .returns(ExpectValue(500u64)) + .run(); + + test.world + .write_scenario_trace("scenarios/bridge_proxy_execute_crowdfunding.scen.json"); +} + +#[test] +fn multiple_deposit_test() { + let mut test = BridgeProxyTestState::new(); + + test.bridge_proxy_deploy(); + test.deploy_crowdfunding(); + test.config_bridge(); + + let mut args = ManagedVec::new(); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from(b"fund"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + let call_data = ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx1 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()), + token_id: BRIDGE_TOKEN_ID.into(), + amount: BigUint::from(500u64), + tx_nonce: 1u64, + call_data: ManagedOption::some(call_data.clone()), + }; + + let eth_tx2 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()), + token_id: BRIDGE_TOKEN_ID.into(), + amount: BigUint::from(500u64), + tx_nonce: 2u64, + call_data: ManagedOption::some(call_data), + }; + + test.world + .tx() + .from(MULTI_TRANSFER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .deposit(ð_tx1, 1u64) + .single_esdt( + &TokenIdentifier::from(BRIDGE_TOKEN_ID), + 0u64, + &BigUint::from(500u64), + ) + .run(); + + test.world + .tx() + .from(MULTI_TRANSFER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .deposit(ð_tx2, 1u64) + .single_esdt( + &TokenIdentifier::from(BRIDGE_TOKEN_ID), + 0u64, + &BigUint::from(500u64), + ) + .run(); + + test.world + .query() + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .get_pending_transaction_by_id(1u32) + .returns(ExpectValue(eth_tx1)) + .run(); + + test.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .gas(200_000_000) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .execute(1u32) + .run(); + + test.world + .query() + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .get_current_funds() + .returns(ExpectValue(500u64)) + .run(); + + test.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .gas(200_000_000) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .execute(2u32) + .run(); + + test.world + .query() + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .get_current_funds() + .returns(ExpectValue(BigUint::from(1_000u32))) + .run(); + + test.world + .query() + .to(CROWDFUNDING_ADDRESS) + .typed(crowdfunding_esdt_proxy::CrowdfundingProxy) + .get_current_funds() + .returns(ExpectValue(1_000u64)) + .run(); +} + +#[test] +fn test_highest_tx_id() { + let mut test = BridgeProxyTestState::new(); + + test.bridge_proxy_deploy(); + test.deploy_crowdfunding(); + test.config_bridge(); + + let mut args = ManagedVec::new(); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from(b"fund"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + let call_data = ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + // Generate 1600 transactions + let mut transactions = Vec::new(); + for i in 1..=1600 { + let eth_tx = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(CROWDFUNDING_ADDRESS.eval_to_array()), + token_id: BRIDGE_TOKEN_ID.into(), + amount: BigUint::from(5u64), + tx_nonce: i as u64, + call_data: ManagedOption::some(call_data.clone()), + }; + transactions.push(eth_tx); + } + test.world + .query() + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .highest_tx_id() + .returns(ExpectValue(0usize)) + .run(); + + // Deposit all transactions + let mut expected_tx_id = 1usize; + for tx in &transactions { + test.world + .tx() + .from(MULTI_TRANSFER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .deposit(tx, 1u64) + .single_esdt( + &TokenIdentifier::from(BRIDGE_TOKEN_ID), + 0u64, + &BigUint::from(5u64), + ) + .run(); + + test.world + .query() + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .highest_tx_id() + .returns(ExpectValue(expected_tx_id)) + .run(); + expected_tx_id += 1; + } + + // Execute all transactions + for i in (1..=1600usize).rev() { + test.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .gas(200_000_000) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .execute(i) + .run(); + } +} diff --git a/bridge-proxy/tests/test-contract/crowdfunding-esdt.mxsc.json b/bridge-proxy/tests/test-contract/crowdfunding-esdt.mxsc.json new file mode 100644 index 00000000..90e0d0fe --- /dev/null +++ b/bridge-proxy/tests/test-contract/crowdfunding-esdt.mxsc.json @@ -0,0 +1,196 @@ +{ + "buildInfo": { + "rustc": { + "version": "1.79.0", + "commitHash": "129f3b9964af4d4a709d1383930ade12dfe7c081", + "commitDate": "2024-06-10", + "channel": "Stable", + "short": "rustc 1.79.0 (129f3b996 2024-06-10)" + }, + "contractCrate": { + "name": "crowdfunding-esdt", + "version": "0.0.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.52.3" + } + }, + "abi": { + "name": "Crowdfunding", + "constructor": { + "inputs": [ + { + "name": "target", + "type": "BigUint" + }, + { + "name": "deadline", + "type": "u64" + }, + { + "name": "token_identifier", + "type": "EgldOrEsdtTokenIdentifier" + } + ], + "outputs": [] + }, + "endpoints": [ + { + "name": "fund", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [], + "outputs": [] + }, + { + "name": "status", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "Status" + } + ] + }, + { + "name": "getCurrentFunds", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "claim", + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "getTarget", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "getDeadline", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u64" + } + ] + }, + { + "name": "getDeposit", + "mutability": "readonly", + "inputs": [ + { + "name": "donor", + "type": "Address" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "name": "getCrowdfundingTokenIdentifier", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "EgldOrEsdtTokenIdentifier" + } + ] + } + ], + "esdtAttributes": [], + "hasCallback": false, + "types": { + "Status": { + "type": "enum", + "variants": [ + { + "name": "FundingPeriod", + "discriminant": 0 + }, + { + "name": "Successful", + "discriminant": 1 + }, + { + "name": "Failed", + "discriminant": 2 + } + ] + } + } + }, + "code": "0061736d0100000001540f60017f017f60027f7f017f60017f006000006000017f60027f7f0060037f7f7f017f60037f7f7f0060017f017e60057f7f7e7f7f017f60027f7e0060057f7f7f7e7f006000017e60017e0060047f7f7f7f017f02b1072603656e760e626967496e74536574496e743634000a03656e7609626967496e74416464000703656e760b7369676e616c4572726f72000503656e76096d4275666665724571000103656e760d6d616e6167656443616c6c6572000203656e76106d616e61676564534341646472657373000203656e76126d427566666572417070656e644279746573000603656e76126d616e616765645369676e616c4572726f72000203656e76106d4275666665724765744c656e677468000003656e7619626967496e74476574556e7369676e6564417267756d656e74000503656e761b736d616c6c496e74476574556e7369676e6564417267756d656e74000803656e760f6765744e756d417267756d656e7473000403656e7614626967496e7446696e697368556e7369676e6564000203656e761b6d616e616765645472616e7366657256616c756545786563757465000903656e760a6d4275666665724e6577000403656e760d6d427566666572417070656e64000103656e76226d616e616765644d756c74695472616e73666572455344544e465445786563757465000903656e760a626967496e745369676e000003656e760f6d4275666665725365744279746573000603656e76126d42756666657253746f726167654c6f6164000103656e76196d42756666657246726f6d426967496e74556e7369676e6564000103656e76136d42756666657253746f7261676553746f7265000103656e76176d427566666572546f426967496e74556e7369676e6564000103656e76126d427566666572476574417267756d656e74000103656e7618626967496e7447657445787465726e616c42616c616e6365000503656e760f6d4275666665724765744279746573000103656e761c626967496e744765744553445445787465726e616c42616c616e6365000b03656e7611676574426c6f636b54696d657374616d70000c03656e7609626967496e74436d70000103656e760e636865636b4e6f5061796d656e74000303656e761776616c6964617465546f6b656e4964656e746966696572000003656e761c6d616e616765644765744d756c74694553445443616c6c56616c7565000203656e7612626967496e7447657443616c6c56616c7565000203656e7616736d616c6c496e7446696e697368556e7369676e6564000d03656e76136d616e616765644f776e657241646472657373000203656e760d6d42756666657246696e697368000003656e760666696e697368000503656e76136d42756666657247657442797465536c696365000e0326250004010504010000020200020400060005080007040402040404000303030303030303030305030100030616037f01418080080b7f0041d983080b7f0041e083080b07a9010d066d656d6f7279020004696e697400410466756e6400420673746174757300430f67657443757272656e7446756e6473004405636c61696d00450967657454617267657400460b676574446561646c696e6500470a6765744465706f73697400481e67657443726f776466756e64696e67546f6b656e4964656e74696669657200490863616c6c4261636b004a0a5f5f646174615f656e6403010b5f5f686561705f6261736503020ae611251601017f1027220142001000200120012000100120010b1901017f419083084190830828020041016b220036020020000b0b0020002001100341004a0b0900200020011002000b0c01017f10272200100420000b1101017f102722022000200110121a20020b0d0020001027220010171a20000b4a01017f230041106b220124002000100841044604402001410036020c20002001410c6a410410341a41feffffff072000200128020c41c58eb1a204461b21000b200141106a240020000b1400100b20004604400f0b41bc800841191002000b080020001030100c0b0f00200010351027220010161a20000bb60202017e077f230041106b2203240020002802102104200028020c21022000290300210120002802082100103221051032210602402000280200220841feffffff0746044020042802002002280200420020052006100d1a0c010b10322107100e22002008100f1a2002280200102621022003200142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc07838420014228884280fe038320014238888484843702042003200041187420004180fe03714108747220004108764180fe0371200041187672723602002003200241187420024180fe03714108747220024108764180fe03712002411876727236020c20072003411010061a2004280200200742002005200610101a0b200341106a24000b1101017f102722004101410010121a20000b1300417f20001011220041004720004100481b0b0f00200041002002200110254100470b0d0020001027220010131a20000b1401017f10272202200110141a2000200210151a0bc00102037f017e230041106b22012400200142003703082000103522031008220241094f044041848108411b102b22012000100f1a200141b98008410310061a200141d58008410e10061a20011007000b2003200120026b41106a200210341a20012903082104200141106a2400200442388620044280fe0383422886842004428080fc0783421886200442808080f80f834208868484200442088842808080f80f832004421888428080fc07838420044228884280fe038320044238888484840b080020001035102d0b0d00200020012002102b10151a0b5801047f103b103821011027220010052000210210272100200141feffffff074604402002103c419983082000101820000f0b2001100821032002103c200141b9830810191a4199830841b98308200342002000101a20000b0a0041f78208410f102b0b0b0020004199830810191a0b3201017f101b103e10375a047f41014102417f103a103f1030101c220041004720004100481b41ff01714102491b0541000b0b0a0041e982084108102b0b0a0041f182084106102b0b1501017f418683084107102b22012000100f1a20010bfe0202047f037e230041106b22032400101d4103102e4100102722021009200221004101100a21044102102c102d2102024002402000103341ff01714101460440103f20001036101b20045a0d01103e2003200442388620044280fe0383422886842004428080fc0783421886200442808080f80f834208868484200442088842808080f80f832004421888428080fc07838420044238882205200442288822064280fe0383848484370308410020055022002004423088a741ff01711b220120006a410020012006a741ff01711b22006a410020002004422088a741ff01711b22006a410020002004a722004118761b22016a41002001200041107641ff01711b22016a41002001200041087641ff01711b6a2200200341086a6a410820006b1039200241feffffff074622014504402002101e450d030b103b2100024020014504402000200210151a0c010b200041808108410410390b200341106a24000f0b41d48108411a1029000b41ee8108411d1029000b418b820841161029000bfd0201047f230041106b220224004100102e416b21000240419883082d000022010440416b41ffffffff0720011b21000c010b4198830841013a0000416b101f0b024002400240027f024002400240200010084104760e020102000b4180800841221002000b417521010240419483082d000022000440417541ffffffff0720001b21010c010b4194830841013a0000417510200b20011026210141feffffff070c010b200241086a42003703002002420037030020002002411010340d01200228020c220141187420014180fe03714108747220014108764180fe03712001411876727221012002280200220041187420004180fe03714108747220004108764180fe0371200041187672720b2100103d41ff01710d01103b103822032000470440200041feffffff0746200341feffffff0746720d03200020031028450d030b102a1040220310302200200020011001200320001036200241106a24000f0b41e38008411d1002000b41af8108411a1029000b41c98108410b1029000b1100101d4100102e103dad42ff018310210b0c00101d4100102e103a100c0b8a0201037f230041306b22002400101d4100102e02400240024002400240103d41ff017141016b0e020102000b41a18208411c1029000b2000102a220136020c102722021022200120021028450d022000103b10383602102000103a360214200042003703182000200041146a3602242000200041106a36022020002000410c6a360228200041186a10310c010b2000102a220136020c200020011040103022023602102002103341ff01714101470d002000103b103836021420011040416c4101410010121a416c10151a200042003703182000200041106a3602242000200041146a36022020002000410c6a360228200041186a10310b200041306a24000f0b41bd820841271029000b0c00101d4100102e103f102f0b0e00101d4100102e103e103710210b4c01017f101d4101102e4100102c22001008412047044041a280084117102b220041e48208410510061a200041b98008410310061a2000419f8108411010061a20001007000b20001040102f0b2801017f101d4100102e103b1038220041feffffff07470440200010231a0f0b41808108410410240b02000b0ba1030200418080080b8d03696e636f7272656374206e756d626572206f662045534454207472616e7366657273617267756d656e74206465636f6465206572726f722028293a2077726f6e67206e756d626572206f6620617267756d656e7473696e70757420746f6f206c6f6e674d616e6167656456656320696e646578206f7574206f662072616e676545474c4473746f72616765206465636f6465206572726f7220286b65793a20626164206172726179206c656e67746863616e6e6f742066756e6420616674657220646561646c696e6577726f6e6720746f6b656e546172676574206d757374206265206d6f7265207468616e2030446561646c696e652063616e277420626520696e207468652070617374496e76616c696420746f6b656e2070726f766964656463616e6e6f7420636c61696d206265666f726520646561646c696e656f6e6c79206f776e65722063616e20636c61696d207375636365737366756c2066756e64696e67646f6e6f72646561646c696e65746172676574746f6b656e4964656e7469666965726465706f73697400419083080b0438ffffff", + "report": { + "imports": [ + "bigIntAdd", + "bigIntCmp", + "bigIntFinishUnsigned", + "bigIntGetCallValue", + "bigIntGetESDTExternalBalance", + "bigIntGetExternalBalance", + "bigIntGetUnsignedArgument", + "bigIntSetInt64", + "bigIntSign", + "checkNoPayment", + "finish", + "getBlockTimestamp", + "getNumArguments", + "mBufferAppend", + "mBufferAppendBytes", + "mBufferEq", + "mBufferFinish", + "mBufferFromBigIntUnsigned", + "mBufferGetArgument", + "mBufferGetByteSlice", + "mBufferGetBytes", + "mBufferGetLength", + "mBufferNew", + "mBufferSetBytes", + "mBufferStorageLoad", + "mBufferStorageStore", + "mBufferToBigIntUnsigned", + "managedCaller", + "managedGetMultiESDTCallValue", + "managedMultiTransferESDTNFTExecute", + "managedOwnerAddress", + "managedSCAddress", + "managedSignalError", + "managedTransferValueExecute", + "signalError", + "smallIntFinishUnsigned", + "smallIntGetUnsignedArgument", + "validateTokenIdentifier" + ], + "isMemGrow": false, + "eiCheck": { + "eiVersion": "1.3", + "ok": true + }, + "codeReport": { + "path": "../output/crowdfunding-esdt.wasm", + "size": 3984, + "hasAllocator": false, + "hasPanic": "none" + } + } +} diff --git a/bridge-proxy/wasm/Cargo.lock b/bridge-proxy/wasm/Cargo.lock new file mode 100644 index 00000000..f273f040 --- /dev/null +++ b/bridge-proxy/wasm/Cargo.lock @@ -0,0 +1,476 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bridge-proxy" +version = "0.0.0" +dependencies = [ + "bridged-tokens-wrapper", + "crowdfunding-esdt", + "esdt-safe", + "eth-address", + "multiversx-sc", + "multiversx-sc-modules", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "bridge-proxy-wasm" +version = "0.0.0" +dependencies = [ + "bridge-proxy", + "multiversx-sc-wasm-adapter", +] + +[[package]] +name = "bridged-tokens-wrapper" +version = "0.0.0" +dependencies = [ + "eth-address", + "multiversx-sc", + "multiversx-sc-modules", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crowdfunding-esdt" +version = "0.0.0" +source = "git+https://github.com/multiversx/mx-contracts-rs?rev=d91bbff#d91bbff295295c2f7e2baf1cd569dd5693ddfb56" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "esdt-safe" +version = "0.0.0" +dependencies = [ + "eth-address", + "fee-estimator-module", + "max-bridged-amount-module", + "multiversx-price-aggregator-sc", + "multiversx-sc", + "multiversx-sc-modules", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "eth-address" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "fee-estimator-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[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 = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "max-bridged-amount-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-price-aggregator-sc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea572ebab3a6addd937cad829076b13e320851503fb6adf1ad66f544b2bf100" +dependencies = [ + "arrayvec", + "getrandom", + "multiversx-sc", + "multiversx-sc-modules", + "rand", +] + +[[package]] +name = "multiversx-sc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed13aaca9cbdbc6911174cd3029e750a7563d85dd3daaa1107b1fd31c7f17245" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "token-module" +version = "0.0.0" +dependencies = [ + "fee-estimator-module", + "multiversx-sc", +] + +[[package]] +name = "transaction" +version = "0.0.0" +dependencies = [ + "eth-address", + "multiversx-sc", +] + +[[package]] +name = "tx-batch-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "transaction", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/bridge-proxy/wasm/Cargo.toml b/bridge-proxy/wasm/Cargo.toml new file mode 100644 index 00000000..53e14637 --- /dev/null +++ b/bridge-proxy/wasm/Cargo.toml @@ -0,0 +1,34 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "bridge-proxy-wasm" +version = "0.0.0" +edition = "2018" +publish = false + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" +overflow-checks = false + +[profile.dev] +panic = "abort" + +[dependencies.bridge-proxy] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "=0.52.3" + +[workspace] +members = ["."] diff --git a/bridge-proxy/wasm/src/lib.rs b/bridge-proxy/wasm/src/lib.rs new file mode 100644 index 00000000..7036dacd --- /dev/null +++ b/bridge-proxy/wasm/src/lib.rs @@ -0,0 +1,42 @@ +// Code generated by the multiversx-sc build system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Upgrade: 1 +// Endpoints: 14 +// Async Callback (empty): 1 +// Promise callbacks: 1 +// Total number of exported functions: 18 + +#![no_std] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + bridge_proxy + ( + init => init + upgrade => upgrade + deposit => deposit + execute => execute + getPendingTransactionById => get_pending_transaction_by_id + getPendingTransactions => get_pending_transactions + setMultiTransferAddress => set_multi_transfer_contract_address + setBridgedTokensWrapperAddress => set_bridged_tokens_wrapper_contract_address + setEsdtSafeAddress => set_esdt_safe_contract_address + getMultiTransferAddress => multi_transfer_address + getBridgedTokensWrapperAddress => bridged_tokens_wrapper_address + getEsdtSafeContractAddress => esdt_safe_contract_address + highestTxId => highest_tx_id + pause => pause_endpoint + unpause => unpause_endpoint + isPaused => paused_status + execution_callback => execution_callback + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {} diff --git a/bridged-tokens-wrapper/Cargo.toml b/bridged-tokens-wrapper/Cargo.toml index 94e3a1f4..1c6e1682 100644 --- a/bridged-tokens-wrapper/Cargo.toml +++ b/bridged-tokens-wrapper/Cargo.toml @@ -11,11 +11,20 @@ path = "src/lib.rs" [dependencies.transaction] path = "../common/transaction" +[dependencies.eth-address] +path = "../common/eth-address" + +[dependencies.token-module] +path = "../common/token-module" + +[dependencies.tx-batch-module] +path = "../common/tx-batch-module" + [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" [dependencies.multiversx-sc-modules] -version = "0.45.2" +version = "=0.52.3" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/bridged-tokens-wrapper/meta/Cargo.toml b/bridged-tokens-wrapper/meta/Cargo.toml index 0c7eaff8..7668f9a6 100644 --- a/bridged-tokens-wrapper/meta/Cargo.toml +++ b/bridged-tokens-wrapper/meta/Cargo.toml @@ -7,6 +7,6 @@ publish = false [dependencies.bridged-tokens-wrapper] path = ".." -[dependencies.multiversx-sc-meta] -version = "0.45.2" +[dependencies.multiversx-sc-meta-lib] +version = "=0.52.3" default-features = false diff --git a/bridged-tokens-wrapper/meta/src/main.rs b/bridged-tokens-wrapper/meta/src/main.rs index ac93d248..659e8bab 100644 --- a/bridged-tokens-wrapper/meta/src/main.rs +++ b/bridged-tokens-wrapper/meta/src/main.rs @@ -1,3 +1,3 @@ fn main() { - multiversx_sc_meta::cli_main::(); + multiversx_sc_meta_lib::cli_main::(); } diff --git a/bridged-tokens-wrapper/sc-config.toml b/bridged-tokens-wrapper/sc-config.toml new file mode 100644 index 00000000..dc186997 --- /dev/null +++ b/bridged-tokens-wrapper/sc-config.toml @@ -0,0 +1,10 @@ +[settings] + +[[proxy]] +path = "../multi-transfer-esdt/src/bridged_tokens_wrapper_proxy.rs" + +[[proxy]] +path = "../multisig/src/bridged_tokens_wrapper_proxy.rs" + +[[proxy]] +path = "../bridge-proxy/src/bridged_tokens_wrapper_proxy.rs" \ No newline at end of file diff --git a/bridged-tokens-wrapper/mandos/add_wrapped_token.scen.json b/bridged-tokens-wrapper/scenarios/add_wrapped_token.scen.json similarity index 100% rename from bridged-tokens-wrapper/mandos/add_wrapped_token.scen.json rename to bridged-tokens-wrapper/scenarios/add_wrapped_token.scen.json diff --git a/bridged-tokens-wrapper/mandos/blacklist_token.scen.json b/bridged-tokens-wrapper/scenarios/blacklist_token.scen.json similarity index 100% rename from bridged-tokens-wrapper/mandos/blacklist_token.scen.json rename to bridged-tokens-wrapper/scenarios/blacklist_token.scen.json diff --git a/bridged-tokens-wrapper/mandos/remove_wrapped_token.scen.json b/bridged-tokens-wrapper/scenarios/remove_wrapped_token.scen.json similarity index 100% rename from bridged-tokens-wrapper/mandos/remove_wrapped_token.scen.json rename to bridged-tokens-wrapper/scenarios/remove_wrapped_token.scen.json diff --git a/bridged-tokens-wrapper/mandos/setup.scen.json b/bridged-tokens-wrapper/scenarios/setup.scen.json similarity index 100% rename from bridged-tokens-wrapper/mandos/setup.scen.json rename to bridged-tokens-wrapper/scenarios/setup.scen.json diff --git a/bridged-tokens-wrapper/mandos/unwrap_token.scen.json b/bridged-tokens-wrapper/scenarios/unwrap_token.scen.json similarity index 100% rename from bridged-tokens-wrapper/mandos/unwrap_token.scen.json rename to bridged-tokens-wrapper/scenarios/unwrap_token.scen.json diff --git a/bridged-tokens-wrapper/mandos/whitelist_token.scen.json b/bridged-tokens-wrapper/scenarios/whitelist_token.scen.json similarity index 100% rename from bridged-tokens-wrapper/mandos/whitelist_token.scen.json rename to bridged-tokens-wrapper/scenarios/whitelist_token.scen.json diff --git a/bridged-tokens-wrapper/mandos/wrap_token.scen.json b/bridged-tokens-wrapper/scenarios/wrap_token.scen.json similarity index 100% rename from bridged-tokens-wrapper/mandos/wrap_token.scen.json rename to bridged-tokens-wrapper/scenarios/wrap_token.scen.json diff --git a/bridged-tokens-wrapper/src/dfp_big_uint.rs b/bridged-tokens-wrapper/src/dfp_big_uint.rs index a70839f5..0a7c0090 100644 --- a/bridged-tokens-wrapper/src/dfp_big_uint.rs +++ b/bridged-tokens-wrapper/src/dfp_big_uint.rs @@ -1,5 +1,4 @@ -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::imports::*; #[derive(Clone, PartialEq, Eq)] pub struct DFPBigUint { diff --git a/bridged-tokens-wrapper/src/esdt_safe_proxy.rs b/bridged-tokens-wrapper/src/esdt_safe_proxy.rs new file mode 100644 index 00000000..3832da69 --- /dev/null +++ b/bridged-tokens-wrapper/src/esdt_safe_proxy.rs @@ -0,0 +1,810 @@ +// 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 EsdtSafeProxy; + +impl TxProxyTrait for EsdtSafeProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = EsdtSafeProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + EsdtSafeProxyMethods { wrapped_tx: tx } + } +} + +pub struct EsdtSafeProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + /// fee_estimator_contract_address - The address of a Price Aggregator contract, + /// which will get the price of token A in token B + /// + /// eth_tx_gas_limit - The gas limit that will be used for transactions on the ETH side. + /// Will be used to compute the fees for the transfer + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + eth_tx_gas_limit: Arg2, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + bridge_proxy_contract_address: Arg2, + eth_tx_gas_limit: Arg3, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(&bridge_proxy_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Sets the statuses for the transactions, after they were executed on the Ethereum side. + /// + /// Only TransactionStatus::Executed (3) and TransactionStatus::Rejected (4) values are allowed. + /// Number of provided statuses must be equal to number of transactions in the batch. + pub fn set_transaction_batch_status< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + batch_id: Arg0, + tx_statuses: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTransactionBatchStatus") + .argument(&batch_id) + .argument(&tx_statuses) + .original_result() + } + + /// Converts failed Ethereum -> MultiversX transactions to MultiversX -> Ethereum transaction. + /// This is done every now and then to refund the tokens. + /// + /// As with normal MultiversX -> Ethereum transactions, a part of the tokens will be + /// subtracted to pay for the fees + pub fn add_refund_batch< + Arg0: ProxyArg>>, + >( + self, + refund_transactions: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addRefundBatch") + .argument(&refund_transactions) + .original_result() + } + + /// Create an MultiversX -> Ethereum transaction. Only fungible tokens are accepted. + /// + /// Every transfer will have a part of the tokens subtracted as fees. + /// The fee amount depends on the global eth_tx_gas_limit + /// and the current GWEI price, respective to the bridged token + /// + /// fee_amount = price_per_gas_unit * eth_tx_gas_limit + pub fn create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + opt_refund_info: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("createTransaction") + .argument(&to) + .argument(&opt_refund_info) + .original_result() + } + + /// Claim funds for failed MultiversX -> Ethereum transactions. + /// These are not sent automatically to prevent the contract getting stuck. + /// For example, if the receiver is a SC, a frozen account, etc. + pub fn claim_refund< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("claimRefund") + .argument(&token_id) + .original_result() + } + + pub fn set_bridged_tokens_wrapper_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgedTokensWrapperAddress") + .argument(&opt_address) + .original_result() + } + + pub fn set_bridge_proxy_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgeProxyContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn withdraw_refund_fees_for_ethereum< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawRefundFeesForEthereum") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn withdraw_transaction_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawTransactionFees") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn compute_total_amounts_from_index< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + start_index: Arg0, + end_index: Arg1, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("computeTotalAmmountsFromIndex") + .argument(&start_index) + .argument(&end_index) + .original_result() + } + + /// Query function that lists all refund amounts for a user. + /// Useful for knowing which token IDs to pass to the claimRefund endpoint. + pub fn get_refund_amounts< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundAmounts") + .argument(&address) + .original_result() + } + + pub fn get_total_refund_amounts( + self, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalRefundAmounts") + .original_result() + } + + pub fn get_refund_fees_for_ethereum< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundFeesForEthereum") + .argument(&token_id) + .original_result() + } + + pub fn get_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn bridged_tokens_wrapper_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgedTokensWrapperAddress") + .original_result() + } + + pub fn bridge_proxy_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgeProxyContractAddress") + .original_result() + } + + pub fn set_fee_estimator_contract_address< + Arg0: ProxyArg>, + >( + self, + new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setFeeEstimatorContractAddress") + .argument(&new_address) + .original_result() + } + + pub fn set_eth_tx_gas_limit< + Arg0: ProxyArg>, + >( + self, + new_limit: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEthTxGasLimit") + .argument(&new_limit) + .original_result() + } + + /// Default price being used if the aggregator lacks a mapping for this token + /// or the aggregator address is not set + pub fn set_default_price_per_gas_unit< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + default_price_per_gas_unit: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setDefaultPricePerGasUnit") + .argument(&token_id) + .argument(&default_price_per_gas_unit) + .original_result() + } + + /// Token ticker being used when querying the aggregator for GWEI prices + pub fn set_token_ticker< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + ticker: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTokenTicker") + .argument(&token_id) + .argument(&ticker) + .original_result() + } + + /// Returns the fee for the given token ID (the fee amount is in the given token) + pub fn calculate_required_fee< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("calculateRequiredFee") + .argument(&token_id) + .original_result() + } + + pub fn fee_estimator_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeEstimatorContractAddress") + .original_result() + } + + pub fn default_price_per_gas_unit< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getDefaultPricePerGasUnit") + .argument(&token_id) + .original_result() + } + + pub fn eth_tx_gas_limit( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEthTxGasLimit") + .original_result() + } + + /// Distributes the accumulated fees to the given addresses. + /// Expected arguments are pairs of (address, percentage), + /// where percentages must add up to the PERCENTAGE_TOTAL constant + pub fn distribute_fees< + Arg0: ProxyArg>>, + >( + self, + address_percentage_pairs: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributeFees") + .argument(&address_percentage_pairs) + .original_result() + } + + pub fn add_token_to_whitelist< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg>, + Arg7: ProxyArg>>, + >( + self, + token_id: Arg0, + ticker: Arg1, + mint_burn_token: Arg2, + native_token: Arg3, + total_balance: Arg4, + mint_balance: Arg5, + burn_balance: Arg6, + opt_default_price_per_gas_unit: Arg7, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addTokenToWhitelist") + .argument(&token_id) + .argument(&ticker) + .argument(&mint_burn_token) + .argument(&native_token) + .argument(&total_balance) + .argument(&mint_balance) + .argument(&burn_balance) + .argument(&opt_default_price_per_gas_unit) + .original_result() + } + + pub fn remove_token_from_whitelist< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeTokenFromWhitelist") + .argument(&token_id) + .original_result() + } + + pub fn get_tokens< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokens") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("initSupply") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply_mint_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_id: Arg0, + mint_amount: Arg1, + burn_amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("initSupplyMintBurn") + .argument(&token_id) + .argument(&mint_amount) + .argument(&burn_amount) + .original_result() + } + + pub fn set_multi_transfer_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn token_whitelist( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAllKnownTokens") + .original_result() + } + + pub fn native_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isNativeToken") + .argument(&token) + .original_result() + } + + pub fn mint_burn_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isMintBurnToken") + .argument(&token) + .original_result() + } + + pub fn multi_transfer_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferContractAddress") + .original_result() + } + + pub fn accumulated_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAccumulatedTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn total_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalBalances") + .argument(&token_id) + .original_result() + } + + pub fn mint_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMintBalances") + .argument(&token_id) + .original_result() + } + + pub fn burn_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBurnBalances") + .argument(&token_id) + .original_result() + } + + pub fn set_max_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + pub fn set_max_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + pub fn get_current_tx_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentTxBatch") + .original_result() + } + + pub fn get_first_batch_any_status( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchAnyStatus") + .original_result() + } + + pub fn get_batch< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatch") + .argument(&batch_id) + .original_result() + } + + pub fn get_batch_status< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatchStatus") + .argument(&batch_id) + .original_result() + } + + pub fn first_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchId") + .original_result() + } + + pub fn last_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastBatchId") + .original_result() + } + + pub fn set_max_bridged_amount< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxBridgedAmount") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + pub fn max_bridged_amount< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMaxBridgedAmount") + .argument(&token_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, ManagedVecItem, PartialEq)] +pub struct RefundInfo +where + Api: ManagedTypeApi, +{ + pub address: ManagedAddress, + pub initial_batch_id: u64, + pub initial_nonce: u64, +} diff --git a/bridged-tokens-wrapper/src/events.rs b/bridged-tokens-wrapper/src/events.rs new file mode 100644 index 00000000..34893fba --- /dev/null +++ b/bridged-tokens-wrapper/src/events.rs @@ -0,0 +1,8 @@ +#[multiversx_sc::module] +pub trait EventsModule { + #[event("wrap_tokens")] + fn wrap_tokens_event(&self, #[indexed] token_id: TokenIdentifier, #[indexed] amount: BigUint); + + #[event("unwrap_tokens")] + fn unwrap_tokens_event(&self, #[indexed] token_id: &TokenIdentifier, #[indexed] amount: BigUint); +} diff --git a/bridged-tokens-wrapper/src/lib.rs b/bridged-tokens-wrapper/src/lib.rs index c0a0f4bd..15d4fabc 100644 --- a/bridged-tokens-wrapper/src/lib.rs +++ b/bridged-tokens-wrapper/src/lib.rs @@ -1,18 +1,22 @@ #![no_std] mod dfp_big_uint; +mod esdt_safe_proxy; +mod events; use core::ops::Deref; pub use dfp_big_uint::DFPBigUint; use transaction::PaymentsVec; -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use eth_address::*; +use multiversx_sc::imports::*; impl DFPBigUint {} #[multiversx_sc::contract] -pub trait BridgedTokensWrapper: multiversx_sc_modules::pause::PauseModule { +pub trait BridgedTokensWrapper: + multiversx_sc_modules::pause::PauseModule + events::EventsModule +{ #[init] fn init(&self) { self.set_paused(true); @@ -174,14 +178,17 @@ pub trait BridgedTokensWrapper: multiversx_sc_modules::pause::PauseModule { self.send() .esdt_local_mint(&universal_token_id, 0, &converted_amount); new_payments.push(EsdtTokenPayment::new( - universal_token_id, + universal_token_id.clone(), 0, - converted_amount, + converted_amount.clone(), )); + self.wrap_tokens_event(universal_token_id, converted_amount); } - let caller = self.blockchain().get_caller(); - self.send().direct_multi(&caller, &new_payments); + self.tx() + .to(ToCaller) + .multi_esdt(new_payments.clone()) + .transfer(); new_payments } @@ -189,18 +196,27 @@ pub trait BridgedTokensWrapper: multiversx_sc_modules::pause::PauseModule { #[payable("*")] #[endpoint(unwrapToken)] fn unwrap_token(&self, requested_token: TokenIdentifier) { + let converted_amount = self.unwrap_token_common(&requested_token); + self.tx() + .to(ToCaller) + .single_esdt(&requested_token, 0, &converted_amount) + .transfer(); + } + + fn unwrap_token_common(&self, requested_token: &TokenIdentifier) -> BigUint { require!(self.not_paused(), "Contract is paused"); let (payment_token, payment_amount) = self.call_value().single_fungible_esdt(); require!(payment_amount > 0u32, "Must pay more than 0 tokens!"); let universal_bridged_token_ids = self - .chain_specific_to_universal_mapping(&requested_token) + .chain_specific_to_universal_mapping(requested_token) .get(); + require!( payment_token == universal_bridged_token_ids, "Esdt token unavailable" ); - self.require_tokens_have_set_decimals_num(&payment_token, &requested_token); + self.require_tokens_have_set_decimals_num(&payment_token, requested_token); let chain_specific_token_id = &requested_token; let converted_amount = self.get_converted_amount( @@ -221,9 +237,34 @@ pub trait BridgedTokensWrapper: multiversx_sc_modules::pause::PauseModule { self.send() .esdt_local_burn(&universal_bridged_token_ids, 0, &payment_amount); + self.unwrap_tokens_event(chain_specific_token_id, converted_amount.clone()); + converted_amount + } + + #[payable("*")] + #[endpoint(unwrapTokenCreateTransaction)] + fn unwrap_token_create_transaction( + &self, + requested_token: TokenIdentifier, + safe_address: ManagedAddress, + to: EthAddress, + ) { + let converted_amount = self.unwrap_token_common(&requested_token); + let caller = self.blockchain().get_caller(); - self.send() - .direct_esdt(&caller, chain_specific_token_id, 0, &converted_amount); + self.tx() + .to(safe_address) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .create_transaction( + to, + OptionalValue::Some(esdt_safe_proxy::RefundInfo { + address: caller, + initial_batch_id: 0, + initial_nonce: 0, + }), + ) + .single_esdt(&requested_token, 0, &converted_amount) + .sync_call(); } fn get_converted_amount( diff --git a/bridged-tokens-wrapper/tests/bridged_tokens_wrapper_whitebox_test.rs b/bridged-tokens-wrapper/tests/bridged_tokens_wrapper_whitebox_test.rs new file mode 100644 index 00000000..8472a856 --- /dev/null +++ b/bridged-tokens-wrapper/tests/bridged_tokens_wrapper_whitebox_test.rs @@ -0,0 +1,1151 @@ +use bridged_tokens_wrapper::BridgedTokensWrapper; +use eth_address::EthAddress; +use multiversx_sc_modules::pause::PauseModule; +use multiversx_sc_scenario::imports::*; + +const UNIVERSAL_TOKEN_IDENTIFIER: &[u8] = b"UNIV-abc123"; +const CHAIN_TOKEN_IDENTIFIER: &[u8] = b"CHAIN-xyz789"; +const CHAIN_TOKEN_IDENTIFIER2: &[u8] = b"CHAIN-xyz789123"; +const ETH_ADDRESS: &str = "0x2E8e0BBe20Ecd819c721D164fb91F7c33BDFC756"; +const NUM_DECIMALS: u32 = 18; + +const OWNER_ADDRESS_EXPR: &str = "address:owner"; +const BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR: &str = "sc:bridged-tokens-wrapper"; +const BRIDGE_TOKENS_WRAPPER_PATH_EXPR: &str = "mxsc:output/bridged-tokens-wrapper.mxsc.json"; +// const ESDT_SAFE_CONTRACT_ADDRESS_EXPR: &str = "address:esdt_safe"; +// const ESDT_SAFE_CONTRACT_PATH_EXPR: &str = "mxsc:../esdt-safe/output/esdt-safe.mxsc.json"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract( + BRIDGE_TOKENS_WRAPPER_PATH_EXPR, + bridged_tokens_wrapper::ContractBuilder, + ); + + blockchain +} + +#[test] +fn test_get_converted_amount_should_work() { + let mut world = setup(); + + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + let number = 100u64; + world.whitebox_query(&bridged_tokens_wrapper, |sc| { + let result = sc.get_converted_amount( + &managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + &managed_token_id!(CHAIN_TOKEN_IDENTIFIER), + managed_biguint!(number), + ); + assert_eq!(result, managed_biguint!(number)); + }); +} + +#[test] +fn test_require_tokens_have_set_decimals_num_should_fail_case_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error( + "str:Universal token requires updating", + )), + |sc| { + sc.require_tokens_have_set_decimals_num( + &managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + &managed_token_id!(CHAIN_TOKEN_IDENTIFIER), + ); + }, + |r| r.assert_user_error("Universal token requires updating"), + ); +} + +#[test] +fn test_require_tokens_have_set_decimals_num_should_fail_case_2() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.token_decimals_num(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .set(18u32); + }, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error( + "str:Chain-specific token requires updating", + )), + |sc| { + sc.token_decimals_num(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .set(18u32); + sc.require_tokens_have_set_decimals_num( + &managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + &managed_token_id!(CHAIN_TOKEN_IDENTIFIER), + ) + }, + |r| r.assert_user_error("Chain-specific token requires updating"), + ); +} + +#[test] +fn test_require_tokens_have_set_decimals_num_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR).no_expect(), + |sc| { + sc.token_decimals_num(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .set(18u32); + sc.token_decimals_num(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .set(18u32); + sc.require_tokens_have_set_decimals_num( + &managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + &managed_token_id!(CHAIN_TOKEN_IDENTIFIER), + ); + }, + ); +} + +#[test] +fn test_require_mint_and_burn_roles_should_fail() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error("str:Must set local role first")), + |sc| { + sc.require_mint_and_burn_roles(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + }, + |r| r.assert_user_error("Must set local role first"), + ); +} + +#[test] +fn test_require_mint_and_burn_roles_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR).no_expect(), + |sc| { + sc.require_mint_and_burn_roles(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + }, + ); +} + +#[test] +fn test_deposit_liquidity_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(UNIVERSAL_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR).esdt_transfer( + UNIVERSAL_TOKEN_IDENTIFIER, + 0, + 100u32, + ), + |sc| { + sc.set_paused(false); + sc.deposit_liquidity(); + let result = sc + .token_liquidity(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .get(); + assert_ne!(result, 0); + }, + ); +} + +#[test] +fn test_add_wrapped_token_should_fail_case_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error("str:Must set local role first")), + |sc| { + sc.add_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), NUM_DECIMALS); + }, + |r| r.assert_user_error("Must set local role first"), + ); +} + +#[test] +fn test_add_wrapped_token_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.add_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), NUM_DECIMALS); + }, + ); +} + +#[test] +fn test_update_wrapped_token_should_fail_case_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error( + "str:Universal token was not added yet", + )), + |sc| { + sc.update_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), NUM_DECIMALS); + }, + |r| r.assert_user_error("Universal token was not added yet"), + ); +} + +#[test] +fn test_update_wrapped_token_shoud_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.add_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), NUM_DECIMALS); + }, + ); + + world.whitebox_query(&bridged_tokens_wrapper, |sc| { + let result = sc + .universal_bridged_token_ids() + .contains(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + assert!(result); + }); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR).no_expect(), + |sc| { + sc.update_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), 32); + }, + ); + + world.whitebox_query(&bridged_tokens_wrapper, |sc| { + let result = sc + .token_decimals_num(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .get(); + assert_eq!(result, 32); + }); +} + +#[test] +fn test_remove_wrapped_token_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.add_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), NUM_DECIMALS); + sc.chain_specific_token_ids(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .insert(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + sc.chain_specific_token_ids(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .insert(managed_token_id!(CHAIN_TOKEN_IDENTIFIER2)); + sc.remove_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + }, + ); + + world.whitebox_query(&bridged_tokens_wrapper, |sc| { + let result = sc + .universal_bridged_token_ids() + .contains(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + assert!(!result); + }); +} + +#[test] +#[ignore] //Ignore for now; Cannot import esdt-safe code here +fn test_unwrap_token_create_transaction_should_fail_case_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(UNIVERSAL_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(UNIVERSAL_TOKEN_IDENTIFIER, 0, 0u32) + .expect(TxExpect::user_error("str:Contract is paused")), + |sc| { + sc.set_paused(true); + + let address = convert_to_eth_address(ETH_ADDRESS); + sc.unwrap_token_create_transaction( + managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + ManagedAddress::new_from_bytes( + b"0102030405060708090a0b0c0d0e0f10", + ), + address, + ); + }, + |r| r.assert_user_error("Contract is paused"), + ); +} + +#[test] +#[ignore] //Ignore for now; Cannot import esdt-safe code here +fn test_unwrap_token_create_transaction_should_fail_case_2() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(UNIVERSAL_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(UNIVERSAL_TOKEN_IDENTIFIER, 0, 0u32) + .expect(TxExpect::user_error("str:Must pay more than 0 tokens!")), + |sc| { + sc.set_paused(false); + let address = convert_to_eth_address(ETH_ADDRESS); + sc.unwrap_token_create_transaction( + managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + ManagedAddress::new_from_bytes( + b"0102030405060708090a0b0c0d0e0f10", + ), + address, + ); + }, + |r| r.assert_user_error("Must pay more than 0 tokens!"), + ); +} + +#[test] +#[ignore] //Ignore for now; Cannot import esdt-safe code here +fn test_unwrap_token_create_transaction_should_fail_case_3() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(UNIVERSAL_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(UNIVERSAL_TOKEN_IDENTIFIER, 0, 100000u32) + .expect(TxExpect::user_error("str:Esdt token unavailable")), + |sc| { + sc.set_paused(false); + let address = convert_to_eth_address(ETH_ADDRESS); + sc.unwrap_token_create_transaction( + managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + ManagedAddress::zero(), + address, + ); + }, + |r| r.assert_user_error("Esdt token unavailable"), + ); +} + +#[test] +fn test_unwrap_token_create_transaction_should_fail_case_4() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(UNIVERSAL_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR).esdt_transfer( + UNIVERSAL_TOKEN_IDENTIFIER, + 0, + 10000u32, + ), + |sc| { + sc.set_paused(false); + sc.add_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), NUM_DECIMALS); + sc.deposit_liquidity(); + let result = sc + .token_liquidity(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .get(); + sc.chain_specific_to_universal_mapping(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .set(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + assert_ne!(result, 0); + }, + ); + + world.whitebox_query(&bridged_tokens_wrapper, |sc| { + let result = sc + .chain_specific_to_universal_mapping(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .get(); + assert_eq!(result, managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + }); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(UNIVERSAL_TOKEN_IDENTIFIER, 0, 100000u32) + .expect(TxExpect::user_error( + "str:Contract does not have enough funds", + )), + |sc| { + sc.set_paused(false); + let address = convert_to_eth_address(ETH_ADDRESS); + sc.unwrap_token_create_transaction( + managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + ManagedAddress::zero(), + address, + ); + }, + |r| r.assert_user_error("Contract does not have enough funds"), + ); +} + +#[test] +fn test_unwrap_token_create_transaction_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(UNIVERSAL_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(UNIVERSAL_TOKEN_IDENTIFIER, 0, 100u32) + .no_expect(), + |sc| { + sc.set_paused(false); + sc.add_wrapped_token(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), NUM_DECIMALS); + sc.deposit_liquidity(); + sc.chain_specific_to_universal_mapping(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .set(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + }, + ); +} + +#[test] +fn test_whitelist_token_should_fail() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error( + "str:Chain-specific token is already mapped to another universal token", + )), + |sc| { + sc.chain_specific_to_universal_mapping(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER2)) + .set(managed_token_id!(CHAIN_TOKEN_IDENTIFIER2)); + sc.whitelist_token( + managed_token_id!(CHAIN_TOKEN_IDENTIFIER2), + NUM_DECIMALS, + managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + ); + }, + |r| { + r.assert_user_error("Chain-specific token is already mapped to another universal token") + }, + ); +} + +#[test] +fn test_whitelist_token_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.whitelist_token( + managed_token_id!(CHAIN_TOKEN_IDENTIFIER), + NUM_DECIMALS, + managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + ); + }, + ); +} + +#[test] +fn test_update_whitelisted_token_should_fail_case_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error( + "str:Chain-specific token was not whitelisted yet", + )), + |sc| { + sc.update_whitelisted_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER), 18u32); + }, + |r| r.assert_user_error("Chain-specific token was not whitelisted yet"), + ); +} + +#[test] +fn test_update_whitelisted_token_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + let contract_address = AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR); + + world.set_esdt_local_roles( + managed_address!(&contract_address.to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.whitelist_token( + managed_token_id!(CHAIN_TOKEN_IDENTIFIER), + NUM_DECIMALS, + managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER), + ); + sc.update_whitelisted_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER), 12); + }, + ); +} + +#[test] +fn test_blacklist_token_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.chain_specific_to_universal_mapping(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .set(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + sc.blacklist_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + ); + + world.whitebox_query(&bridged_tokens_wrapper, |sc| { + let result = sc + .chain_specific_to_universal_mapping(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .is_empty(); + let token_decimals_result = sc + .token_decimals_num(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .is_empty(); + assert!(result); + assert!(token_decimals_result); + }); +} + +#[test] +fn test_wrap_tokens_should_fail_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 100u32) + .expect(TxExpect::user_error("str:Contract is paused")), + |sc| { + sc.wrap_tokens(); + }, + |r| r.assert_user_error("Contract is paused"), + ); +} + +#[test] +fn test_wrap_tokens_should_work_case_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new().from(OWNER_ADDRESS_EXPR), + |sc| { + sc.set_paused(false); + sc.wrap_tokens(); + }, + ); +} + +#[test] +fn test_wrap_tokens_should_work_case_2() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 100u32), + |sc| { + sc.set_paused(false); + sc.wrap_tokens(); + }, + ); +} + +#[test] +fn test_wrap_tokens_should_work_case_3() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + CHAIN_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 100u32), + |sc| { + sc.token_decimals_num(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .set(NUM_DECIMALS); + sc.token_decimals_num(&managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)) + .set(NUM_DECIMALS); + sc.chain_specific_to_universal_mapping(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .set(managed_token_id!(UNIVERSAL_TOKEN_IDENTIFIER)); + sc.set_paused(false); + sc.wrap_tokens(); + }, + ); +} + +#[test] +fn test_unwrap_token_should_fail_case_1() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .expect(TxExpect::user_error("str:Contract is paused")), + |sc| { + sc.unwrap_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + |r| r.assert_user_error("Contract is paused"), + ); +} + +#[test] +fn test_unwrap_token_should_fail_case_2() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 0u32) + .expect(TxExpect::user_error("str:Must pay more than 0 tokens!")), + |sc| { + sc.set_paused(false); + sc.unwrap_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + |r| r.assert_user_error("Must pay more than 0 tokens!"), + ); +} + +#[test] +fn test_unwrap_token_should_fail_case_3() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + CHAIN_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 100u32) + .expect(TxExpect::user_error("str:Esdt token unavailable")), + |sc| { + sc.set_paused(false); + sc.unwrap_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + |r| r.assert_user_error("Esdt token unavailable"), + ); +} + +#[test] +fn test_unwrap_token_should_fail_case_4() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + CHAIN_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 10000u32) + .no_expect(), + |sc| { + sc.set_paused(false); + sc.add_wrapped_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER), NUM_DECIMALS); + sc.deposit_liquidity(); + sc.chain_specific_to_universal_mapping(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .set(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + ); + + world.whitebox_call_check( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 100000u32) + .expect(TxExpect::user_error( + "str:Contract does not have enough funds", + )), + |sc| { + sc.unwrap_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + |r| r.assert_user_error("Contract does not have enough funds"), + ); +} + +#[test] +fn test_unwrap_token_should_work() { + let mut world = setup(); + let bridged_tokens_wrapper = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + world.set_state_step( + SetStateStep::new().put_account( + OWNER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(100_000_000u64) + .esdt_balance(CHAIN_TOKEN_IDENTIFIER.to_vec(), 100_000_000u64), + ), + ); + + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + CHAIN_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + world.set_esdt_local_roles( + managed_address!(&AddressValue::from(BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR).to_address()), + UNIVERSAL_TOKEN_IDENTIFIER, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 10000u32) + .no_expect(), + |sc| { + sc.set_paused(false); + sc.add_wrapped_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER), NUM_DECIMALS); + sc.deposit_liquidity(); + sc.chain_specific_to_universal_mapping(&managed_token_id!(CHAIN_TOKEN_IDENTIFIER)) + .set(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + ); + + world.whitebox_call( + &bridged_tokens_wrapper, + ScCallStep::new() + .from(OWNER_ADDRESS_EXPR) + .esdt_transfer(CHAIN_TOKEN_IDENTIFIER, 0, 100u32) + .no_expect(), + |sc| { + sc.unwrap_token(managed_token_id!(CHAIN_TOKEN_IDENTIFIER)); + }, + ); +} + +fn setup() -> ScenarioWorld { + let mut world = world(); + let bridged_tokens_wrapper_whitebox = WhiteboxContract::new( + BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR, + bridged_tokens_wrapper::contract_obj, + ); + + let bridged_tokens_wrapper_code = world.code_expression(BRIDGE_TOKENS_WRAPPER_PATH_EXPR); + + let set_state_step = SetStateStep::new() + .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) + .new_address(OWNER_ADDRESS_EXPR, 1, BRIDGE_TOKENS_WRAPPER_ADDRESS_EXPR) + .block_timestamp(100); + + world.set_state_step(set_state_step).whitebox_deploy( + &bridged_tokens_wrapper_whitebox, + ScDeployStep::new() + .from(OWNER_ADDRESS_EXPR) + .code(bridged_tokens_wrapper_code), + |sc| { + sc.init(); + }, + ); + + // let esdt_safe_whitebox = + // WhiteboxContract::new(ESDT_SAFE_CONTRACT_ADDRESS_EXPR, esdt_safe::contract_obj); + // let esdt_safe_code = world.code_expression(ESDT_SAFE_CONTRACT_PATH_EXPR); + + // let state_step = SetStateStep::new() + // .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) + // .new_address(OWNER_ADDRESS_EXPR, 1, ESDT_SAFE_ADDRESS) + // .block_timestamp(100); + + // world + // .tx() + // .from(OWNER_ADDRESS) + // .typed(esdt_safe_proxy::EsdtSafeProxy) + // .init( + // ManagedAddress::zero(), + // ManagedAddress::zero(), + // BigUint::zero(), + // ) + // .code(ESDT_SAFE_CODE_PATH) + // .new_address(ESDT_SAFE_ADDRESS) + // .run(); + + // world.set_state_step(state_step); + + world +} + +fn convert_to_eth_address(address: &str) -> EthAddress { + let address_str = address.trim_start_matches("0x"); + let mut address_bytes = [0u8; 20]; + + for (i, byte) in address_bytes.iter_mut().enumerate() { + let offset = i * 2; + *byte = u8::from_str_radix(&address_str[offset..offset + 2], 16).expect("Parsing error"); + } + + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(&address_bytes), + } +} diff --git a/bridged-tokens-wrapper/tests/dfp_big_uint_test.rs b/bridged-tokens-wrapper/tests/dfp_big_uint_test.rs index 31a2c9b5..1c1c794b 100644 --- a/bridged-tokens-wrapper/tests/dfp_big_uint_test.rs +++ b/bridged-tokens-wrapper/tests/dfp_big_uint_test.rs @@ -1,23 +1,37 @@ -#![feature(associated_type_bounds)] use bridged_tokens_wrapper::DFPBigUint; use multiversx_sc_scenario::DebugApi; #[test] fn test_biguint() { - let _ = DebugApi::dummy(); - let raw = 123456u64; + DebugApi::dummy(); + let raw = 123456789u64; let dfp = DFPBigUint::::from_raw(raw.into(), 6); let converted = dfp.clone().convert(9); assert!(dfp.trunc() == converted.trunc()); - assert!(converted.clone().convert(9).to_raw() == 123456000u64); - assert!(converted.clone().convert(1).to_raw() == 1u64); - assert!(converted.clone().convert(3).to_raw() == 123u64); - assert!(converted.clone().convert(5).to_raw() == 12345u64); + assert!(converted.clone().convert(9).to_raw() == 123456789000u64); + assert!(converted.clone().convert(1).to_raw() == 1234u64); + assert!(converted.clone().convert(3).to_raw() == 123456u64); + assert!(converted.clone().convert(0).to_raw() == 123u64); + assert!(converted.convert(5).to_raw() == 12345678u64); +} + +#[test] +fn test_biguint_zero_dec() { + DebugApi::dummy(); + let raw = 123u64; + let dfp = DFPBigUint::::from_raw(raw.into(), 0); + let converted = dfp.clone().convert(9); + assert!(dfp.trunc() == converted.trunc()); + assert!(converted.clone().convert(9).to_raw() == 123000000000u64); + assert!(converted.clone().convert(1).to_raw() == 1230u64); + assert!(converted.clone().convert(3).to_raw() == 123000u64); + assert!(converted.clone().convert(0).to_raw() == 123u64); + assert!(converted.convert(5).to_raw() == 12300000u64); } #[test] fn test_mandos_scenario_values() { - let _ = DebugApi::dummy(); + DebugApi::dummy(); let raw = 300000000000000u64; let dfp = DFPBigUint::::from_raw(raw.into(), 18); assert!(dfp.convert(6).to_raw() == 300u64); diff --git a/bridged-tokens-wrapper/tests/scenario_go_test.rs b/bridged-tokens-wrapper/tests/scenario_go_test.rs index 4bbc4b02..a3d6e919 100644 --- a/bridged-tokens-wrapper/tests/scenario_go_test.rs +++ b/bridged-tokens-wrapper/tests/scenario_go_test.rs @@ -1,29 +1,40 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + ScenarioWorld::vm_go() +} + #[test] -fn unwrap_token_go() { - multiversx_sc_scenario::run_go("mandos/unwrap_token.scen.json"); +fn add_wrapped_token_go() { + world().run("scenarios/add_wrapped_token.scen.json"); } #[test] -fn wrap_token_go() { - multiversx_sc_scenario::run_go("mandos/wrap_token.scen.json"); +fn blacklist_token_go() { + world().run("scenarios/blacklist_token.scen.json"); } #[test] -fn whitelist_token_go() { - multiversx_sc_scenario::run_go("mandos/whitelist_token.scen.json"); +fn remove_wrapped_token_go() { + world().run("scenarios/remove_wrapped_token.scen.json"); } #[test] -fn blacklist_token_go() { - multiversx_sc_scenario::run_go("mandos/blacklist_token.scen.json"); +fn setup_go() { + world().run("scenarios/setup.scen.json"); } #[test] -fn add_wrapped_token_go() { - multiversx_sc_scenario::run_go("mandos/add_wrapped_token.scen.json"); +fn unwrap_token_go() { + world().run("scenarios/unwrap_token.scen.json"); } #[test] -fn remove_wrapped_token_go() { - multiversx_sc_scenario::run_go("mandos/remove_wrapped_token.scen.json"); +fn whitelist_token_go() { + world().run("scenarios/whitelist_token.scen.json"); +} + +#[test] +fn wrap_token_go() { + world().run("scenarios/wrap_token.scen.json"); } diff --git a/bridged-tokens-wrapper/wasm/Cargo.lock b/bridged-tokens-wrapper/wasm/Cargo.lock index 26ce41ff..9de5b8cd 100644 --- a/bridged-tokens-wrapper/wasm/Cargo.lock +++ b/bridged-tokens-wrapper/wasm/Cargo.lock @@ -2,49 +2,34 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "allocator-api2" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" - [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bridged-tokens-wrapper" version = "0.0.0" dependencies = [ + "eth-address", "multiversx-sc", "multiversx-sc-modules", + "token-module", "transaction", + "tx-batch-module", ] [[package]] @@ -55,12 +40,6 @@ dependencies = [ "multiversx-sc-wasm-adapter", ] -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "endian-type" version = "0.1.2" @@ -75,13 +54,10 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +name = "fee-estimator-module" +version = "0.0.0" dependencies = [ - "ahash", - "allocator-api2", + "multiversx-sc", ] [[package]] @@ -98,33 +74,34 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "multiversx-sc" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2bdb196b3ff2b9f8c744ec2e026c22c8e02bc91e5c6ed09951415c47fef6b8" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" dependencies = [ "bitflags", - "hashbrown", "hex-literal", "multiversx-sc-codec", "multiversx-sc-derive", "num-traits", + "unwrap-infallible", ] [[package]] name = "multiversx-sc-codec" -version = "0.18.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19908153158c03df4582af08f47c0eb39fb52a7dff4736b301a66acbbb9955d3" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" dependencies = [ "arrayvec", "multiversx-sc-codec-derive", + "unwrap-infallible", ] [[package]] name = "multiversx-sc-codec-derive" -version = "0.18.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b03b43f9cad320992f54ed162de2ed63e3ec83ed01361e57ee9c1865fba5a2" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" dependencies = [ "hex", "proc-macro2", @@ -134,9 +111,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e60b5dce707f61376f74d713218f75326121d9f6a5f09a3a63de7aea2a92be9" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" dependencies = [ "hex", "proc-macro2", @@ -147,18 +124,18 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5833f8bc88104357d38a8952d2a16c3e66080e2e512c0e7001c0c003006c475" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4299660d5413d9f120bfddda8105b1f9d28f0345a72f53e5dc90732c4983e45" +checksum = "ed13aaca9cbdbc6911174cd3029e750a7563d85dd3daaa1107b1fd31c7f17245" dependencies = [ "multiversx-sc", ] @@ -174,33 +151,27 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -217,15 +188,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.41" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -233,41 +204,37 @@ dependencies = [ ] [[package]] -name = "transaction" +name = "token-module" version = "0.0.0" dependencies = [ - "eth-address", + "fee-estimator-module", "multiversx-sc", ] [[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +name = "transaction" +version = "0.0.0" +dependencies = [ + "eth-address", + "multiversx-sc", +] [[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +name = "tx-batch-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "transaction", +] [[package]] -name = "zerocopy" -version = "0.7.31" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" -dependencies = [ - "zerocopy-derive", -] +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "zerocopy-derive" -version = "0.7.31" +name = "unwrap-infallible" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" diff --git a/bridged-tokens-wrapper/wasm/Cargo.toml b/bridged-tokens-wrapper/wasm/Cargo.toml index 304c40a8..12b6d648 100644 --- a/bridged-tokens-wrapper/wasm/Cargo.toml +++ b/bridged-tokens-wrapper/wasm/Cargo.toml @@ -21,11 +21,14 @@ debug = false panic = "abort" overflow-checks = false +[profile.dev] +panic = "abort" + [dependencies.bridged-tokens-wrapper] path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.45.2" +version = "=0.52.3" [workspace] members = ["."] diff --git a/bridged-tokens-wrapper/wasm/src/lib.rs b/bridged-tokens-wrapper/wasm/src/lib.rs index 61e709b7..cdad1731 100644 --- a/bridged-tokens-wrapper/wasm/src/lib.rs +++ b/bridged-tokens-wrapper/wasm/src/lib.rs @@ -5,16 +5,13 @@ //////////////////////////////////////////////////// // Init: 1 +// Upgrade: 1 // Endpoints: 17 // Async Callback (empty): 1 -// Total number of exported functions: 19 +// Total number of exported functions: 20 #![no_std] -// Configuration that works with rustc < 1.73.0. -// TODO: Recommended rustc version: 1.73.0 or newer. -#![feature(lang_items)] - multiversx_sc_wasm_adapter::allocator!(); multiversx_sc_wasm_adapter::panic_handler!(); @@ -32,6 +29,7 @@ multiversx_sc_wasm_adapter::endpoints! { depositLiquidity => deposit_liquidity wrapTokens => wrap_tokens unwrapToken => unwrap_token + unwrapTokenCreateTransaction => unwrap_token_create_transaction getUniversalBridgedTokenIds => universal_bridged_token_ids getTokenLiquidity => token_liquidity getChainSpecificToUniversalMapping => chain_specific_to_universal_mapping diff --git a/common/eth-address/Cargo.toml b/common/eth-address/Cargo.toml index e4b8dadc..69e29eb8 100644 --- a/common/eth-address/Cargo.toml +++ b/common/eth-address/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" path = "src/lib.rs" [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" diff --git a/common/eth-address/src/lib.rs b/common/eth-address/src/lib.rs index 0e4e6a53..36249952 100644 --- a/common/eth-address/src/lib.rs +++ b/common/eth-address/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -multiversx_sc::derive_imports!(); +use multiversx_sc::derive_imports::*; use multiversx_sc::{ api::ManagedTypeApi, types::{ManagedBuffer, ManagedByteArray}, @@ -9,7 +9,8 @@ use multiversx_sc::{ pub const ETH_ADDRESS_LEN: usize = 20; /// Wrapper over a 20-byte array -#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, ManagedVecItem)] +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, ManagedVecItem, PartialEq)] pub struct EthAddress { pub raw_addr: ManagedByteArray, } diff --git a/common/fee-estimator-module/Cargo.toml b/common/fee-estimator-module/Cargo.toml index 88663e5d..aed9a0db 100644 --- a/common/fee-estimator-module/Cargo.toml +++ b/common/fee-estimator-module/Cargo.toml @@ -5,7 +5,7 @@ authors = ["dorin-iancu "] edition = "2018" [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/common/fee-estimator-module/src/aggregator_proxy.rs b/common/fee-estimator-module/src/aggregator_proxy.rs deleted file mode 100644 index 123254ae..00000000 --- a/common/fee-estimator-module/src/aggregator_proxy.rs +++ /dev/null @@ -1,38 +0,0 @@ -multiversx_sc::imports!(); - -pub const GWEI_STRING: &[u8] = b"GWEI"; - -pub type AggregatorResultAsMultiValue = - MultiValue5, ManagedBuffer, BigUint, u8>; - -#[multiversx_sc::proxy] -pub trait Aggregator { - #[view(latestPriceFeedOptional)] - fn latest_price_feed_optional( - &self, - from: ManagedBuffer, - to: ManagedBuffer, - ) -> OptionalValue>; -} - -pub struct AggregatorResult { - pub round_id: u32, - pub from_token_name: ManagedBuffer, - pub to_token_name: ManagedBuffer, - pub price: BigUint, - pub decimals: u8, -} - -impl From> for AggregatorResult { - fn from(multi_result: AggregatorResultAsMultiValue) -> Self { - let (round_id, from_token_name, to_token_name, price, decimals) = multi_result.into_tuple(); - - AggregatorResult { - round_id, - from_token_name, - to_token_name, - price, - decimals, - } - } -} diff --git a/common/fee-estimator-module/src/lib.rs b/common/fee-estimator-module/src/lib.rs index 3504543a..e7aa8cb3 100644 --- a/common/fee-estimator-module/src/lib.rs +++ b/common/fee-estimator-module/src/lib.rs @@ -1,9 +1,9 @@ #![no_std] -multiversx_sc::imports!(); +use multiversx_sc::imports::*; +mod price_aggregator_proxy; -mod aggregator_proxy; -pub use aggregator_proxy::*; +pub const GWEI_STRING: &[u8] = b"GWEI"; #[multiversx_sc::module] pub trait FeeEstimatorModule { @@ -67,21 +67,19 @@ pub trait FeeEstimatorModule { let from_ticker = self.token_ticker(from).get(); let to_ticker = self.token_ticker(to).get(); - let result: OptionalValue> = self - .aggregator_proxy(fee_estimator_sc_address) + let result = self + .tx() + .to(fee_estimator_sc_address) + .typed(price_aggregator_proxy::PriceAggregatorProxy) .latest_price_feed_optional(from_ticker, to_ticker) - .execute_on_dest_context(); + .returns(ReturnsResult) + .sync_call(); result .into_option() - .map(|multi_result| AggregatorResult::from(multi_result).price) + .map(|multi_result| multi_result.into_tuple().4) } - // proxies - - #[proxy] - fn aggregator_proxy(&self, sc_address: ManagedAddress) -> aggregator_proxy::Proxy; - // storage #[view(getFeeEstimatorContractAddress)] diff --git a/common/fee-estimator-module/src/price_aggregator_proxy.rs b/common/fee-estimator-module/src/price_aggregator_proxy.rs new file mode 100644 index 00000000..e96244d6 --- /dev/null +++ b/common/fee-estimator-module/src/price_aggregator_proxy.rs @@ -0,0 +1,389 @@ +// 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, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeAmounts") + .argument(&staking_amount) + .argument(&slash_amount) + .original_result() + } + + pub fn add_oracles< + Arg0: ProxyArg>>, + >( + self, + oracles: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("submitBatch") + .argument(&submissions) + .original_result() + } + + pub fn latest_round_data( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("latestRoundData") + .original_result() + } + + pub fn latest_price_feed< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxTypedCall, ManagedBuffer, u64, BigUint, u8>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("latestPriceFeed") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn latest_price_feed_optional< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + from: Arg0, + to: Arg1, + ) -> TxTypedCall, ManagedBuffer, u64, BigUint, u8>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("latestPriceFeedOptional") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn set_submission_count< + Arg0: ProxyArg, + >( + self, + submission_count: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setSubmissionCount") + .argument(&submission_count) + .original_result() + } + + pub fn get_oracles( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getOracles") + .original_result() + } + + pub fn set_pair_decimals< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + >( + self, + from: Arg0, + to: Arg1, + decimals: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPairDecimals") + .argument(&from) + .argument(&to) + .original_result() + } + + pub fn submission_count( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("submission_count") + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } + + pub fn stake( + self, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("stake") + .original_result() + } + + pub fn unstake< + Arg0: ProxyArg>, + >( + self, + unstake_amount: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unstake") + .argument(&unstake_amount) + .original_result() + } + + pub fn vote_slash_member< + Arg0: ProxyArg>, + >( + self, + member_to_slash: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("voteSlashMember") + .argument(&member_to_slash) + .original_result() + } + + pub fn cancel_vote_slash_member< + Arg0: ProxyArg>, + >( + self, + member_to_slash: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("cancelVoteSlashMember") + .argument(&member_to_slash) + .original_result() + } + + pub fn slash_member< + Arg0: ProxyArg>, + >( + self, + member_to_slash: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .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/common/max-bridged-amount-module/Cargo.toml b/common/max-bridged-amount-module/Cargo.toml index 010ce5a2..3492e794 100644 --- a/common/max-bridged-amount-module/Cargo.toml +++ b/common/max-bridged-amount-module/Cargo.toml @@ -5,7 +5,7 @@ authors = ["dorin-iancu "] edition = "2018" [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/common/max-bridged-amount-module/src/lib.rs b/common/max-bridged-amount-module/src/lib.rs index 89ca7afb..d1aa8481 100644 --- a/common/max-bridged-amount-module/src/lib.rs +++ b/common/max-bridged-amount-module/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -multiversx_sc::imports!(); +use multiversx_sc::imports::*; #[multiversx_sc::module] pub trait MaxBridgedAmountModule { diff --git a/common/token-module/Cargo.toml b/common/token-module/Cargo.toml index 207621c7..168b8738 100644 --- a/common/token-module/Cargo.toml +++ b/common/token-module/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" path = "../fee-estimator-module" [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/common/token-module/src/lib.rs b/common/token-module/src/lib.rs index b1b5e3f3..06319302 100644 --- a/common/token-module/src/lib.rs +++ b/common/token-module/src/lib.rs @@ -1,12 +1,13 @@ #![no_std] -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::derive_imports::*; +use multiversx_sc::imports::*; pub const PERCENTAGE_TOTAL: u32 = 10_000; // precision of 2 decimals pub static INVALID_PERCENTAGE_SUM_OVER_ERR_MSG: &[u8] = b"Percentages do not add up to 100%"; -#[derive(NestedEncode, NestedDecode, TypeAbi, ManagedVecItem, Clone)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, ManagedVecItem, Clone)] pub struct AddressPercentagePair { pub address: ManagedAddress, pub percentage: u32, @@ -51,8 +52,10 @@ pub trait TokenModule: fee_estimator_module::FeeEstimatorModule { if amount_to_send > 0 { remaining_fees -= &amount_to_send; - self.send() - .direct_esdt(&pair.address, &token_id, 0, &amount_to_send); + self.tx() + .to(&pair.address) + .single_esdt(&token_id, 0, &amount_to_send) + .transfer(); } } @@ -62,21 +65,55 @@ pub trait TokenModule: fee_estimator_module::FeeEstimatorModule { } #[only_owner] + #[payable("*")] #[endpoint(addTokenToWhitelist)] fn add_token_to_whitelist( &self, - token_id: TokenIdentifier, + token_id: &TokenIdentifier, ticker: ManagedBuffer, + mint_burn_token: bool, + native_token: bool, + total_balance: &BigUint, + mint_balance: &BigUint, + burn_balance: &BigUint, opt_default_price_per_gas_unit: OptionalValue, ) { - self.token_ticker(&token_id).set(&ticker); + self.token_ticker(token_id).set(&ticker); if let OptionalValue::Some(default_price_per_gas_unit) = opt_default_price_per_gas_unit { - self.default_price_per_gas_unit(&token_id) + self.default_price_per_gas_unit(token_id) .set(&default_price_per_gas_unit); } - - let _ = self.token_whitelist().insert(token_id); + self.mint_burn_token(token_id).set(mint_burn_token); + self.native_token(token_id).set(native_token); + let _ = self.token_whitelist().insert(token_id.clone()); + match mint_burn_token { + true => { + require!( + total_balance == &BigUint::zero(), + "Mint-burn tokens must have 0 total balance!" + ); + require!( + self.call_value().all_esdt_transfers().is_empty(), + "No payment required for mint burn tokens!" + ); + self.init_supply_mint_burn(token_id, mint_balance, burn_balance); + } + false => { + require!(native_token, "Only native tokens can be stored!"); + require!( + mint_balance == &BigUint::zero(), + "Stored tokens must have 0 mint balance!" + ); + require!( + burn_balance == &BigUint::zero(), + "Stored tokens must have 0 burn balance!" + ); + if total_balance > &BigUint::zero() { + self.init_supply(token_id, total_balance); + } + } + } } #[only_owner] @@ -85,11 +122,120 @@ pub trait TokenModule: fee_estimator_module::FeeEstimatorModule { self.token_ticker(&token_id).clear(); self.default_price_per_gas_unit(&token_id).clear(); - let _ = self.token_whitelist().swap_remove(&token_id); + self.mint_burn_token(&token_id).clear(); + self.native_token(&token_id).clear(); + self.token_whitelist().swap_remove(&token_id); + } + + #[endpoint(getTokens)] + fn get_tokens(&self, token_id: &TokenIdentifier, amount: &BigUint) -> bool { + let caller = self.blockchain().get_caller(); + require!( + caller == self.multi_transfer_contract_address().get(), + "Only MultiTransfer can get tokens" + ); + + if !self.mint_burn_token(token_id).get() { + let total_balances_mapper = self.total_balances(token_id); + if &total_balances_mapper.get() >= amount { + total_balances_mapper.update(|total| { + *total -= amount; + }); + self.tx() + .to(ToCaller) + .single_esdt(token_id, 0, amount) + .transfer(); + + return true; + } else { + return false; + } + } + + let burn_balances_mapper = self.burn_balances(token_id); + let mint_balances_mapper = self.mint_balances(token_id); + if self.native_token(token_id).get() { + require!( + burn_balances_mapper.get() >= &mint_balances_mapper.get() + amount, + "Not enough burned tokens!" + ); + } + + let mint_executed = self.internal_mint(token_id, amount); + if !mint_executed { + return false; + } + self.tx() + .to(ToCaller) + .single_esdt(token_id, 0, amount) + .transfer(); + + mint_balances_mapper.update(|minted| { + *minted += amount; + }); + + true + } + + #[only_owner] + #[payable("*")] + #[endpoint(initSupply)] + fn init_supply(&self, token_id: &TokenIdentifier, amount: &BigUint) { + let (payment_token, payment_amount) = self.call_value().single_fungible_esdt(); + require!(token_id == &payment_token, "Invalid token ID"); + require!(amount == &payment_amount, "Invalid amount"); + + self.require_token_in_whitelist(token_id); + require!( + !self.mint_burn_token(token_id).get(), + "Cannot init for non mintable/burnable tokens" + ); + require!( + self.native_token(token_id).get(), + "Only native tokens can be stored!" + ); + + self.total_balances(token_id).update(|total| { + *total += amount; + }); + } + + #[only_owner] + #[endpoint(initSupplyMintBurn)] + fn init_supply_mint_burn( + &self, + token_id: &TokenIdentifier, + mint_amount: &BigUint, + burn_amount: &BigUint, + ) { + self.require_token_in_whitelist(token_id); + require!( + self.mint_burn_token(token_id).get(), + "Cannot init for non mintable/burnable tokens" + ); + + self.mint_balances(token_id).set(mint_amount); + self.burn_balances(token_id).set(burn_amount); } // private + fn internal_mint(&self, token_id: &TokenIdentifier, amount: &BigUint) -> bool { + if !self.is_local_role_set(token_id, &EsdtLocalRole::Mint) { + return false; + } + self.send().esdt_local_mint(token_id, 0, amount); + return true; + } + + fn internal_burn(&self, token_id: &TokenIdentifier, amount: &BigUint) -> bool { + if !self.is_local_role_set(token_id, &EsdtLocalRole::Burn) { + return false; + } + self.send().esdt_local_burn(token_id, 0, amount); + return true; + } + fn require_token_in_whitelist(&self, token_id: &TokenIdentifier) { require!( self.token_whitelist().contains(token_id), @@ -110,16 +256,51 @@ pub trait TokenModule: fee_estimator_module::FeeEstimatorModule { roles.has_role(role) } + #[only_owner] + #[endpoint(setMultiTransferContractAddress)] + fn set_multi_transfer_contract_address(&self, opt_new_address: OptionalValue) { + match opt_new_address { + OptionalValue::Some(sc_addr) => { + self.multi_transfer_contract_address().set(&sc_addr); + } + OptionalValue::None => self.multi_transfer_contract_address().clear(), + } + } + // storage #[view(getAllKnownTokens)] #[storage_mapper("tokenWhitelist")] fn token_whitelist(&self) -> UnorderedSetMapper; + #[view(isNativeToken)] + #[storage_mapper("nativeTokens")] + fn native_token(&self, token: &TokenIdentifier) -> SingleValueMapper; + + #[view(isMintBurnToken)] + #[storage_mapper("mintBurnToken")] + fn mint_burn_token(&self, token: &TokenIdentifier) -> SingleValueMapper; + + #[view(getMultiTransferContractAddress)] + #[storage_mapper("multiTransferContractAddress")] + fn multi_transfer_contract_address(&self) -> SingleValueMapper; + #[view(getAccumulatedTransactionFees)] #[storage_mapper("accumulatedTransactionFees")] fn accumulated_transaction_fees( &self, token_id: &TokenIdentifier, ) -> SingleValueMapper; + + #[view(getTotalBalances)] + #[storage_mapper("totalBalances")] + fn total_balances(&self, token_id: &TokenIdentifier) -> SingleValueMapper; + + #[view(getMintBalances)] + #[storage_mapper("mintBalances")] + fn mint_balances(&self, token_id: &TokenIdentifier) -> SingleValueMapper; + + #[view(getBurnBalances)] + #[storage_mapper("burnBalances")] + fn burn_balances(&self, token_id: &TokenIdentifier) -> SingleValueMapper; } diff --git a/common/transaction/Cargo.toml b/common/transaction/Cargo.toml index c1f3d18c..ddde4c76 100644 --- a/common/transaction/Cargo.toml +++ b/common/transaction/Cargo.toml @@ -11,4 +11,4 @@ path = "src/lib.rs" path = "../eth-address" [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" diff --git a/common/transaction/src/lib.rs b/common/transaction/src/lib.rs index c2050a82..56cd8383 100644 --- a/common/transaction/src/lib.rs +++ b/common/transaction/src/lib.rs @@ -1,10 +1,9 @@ #![no_std] -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::derive_imports::*; +use multiversx_sc::imports::*; use eth_address::EthAddress; - pub mod transaction_status; // revert protection @@ -26,19 +25,46 @@ pub type TxAsMultiValue = MultiValue6< pub type PaymentsVec = ManagedVec>; pub type TxBatchSplitInFields = MultiValue2>>; -#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, TypeAbi, ManagedVecItem, Clone)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopDecode, TopEncode, Clone, ManagedVecItem)] +pub struct CallData { + pub endpoint: ManagedBuffer, + pub gas_limit: u64, + pub args: ManagedOption>>, +} + +impl Default for CallData { + fn default() -> Self { + CallData { + endpoint: ManagedBuffer::new(), + gas_limit: 0u64, + args: ManagedOption::none(), + } + } +} + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone, ManagedVecItem)] pub struct EthTransaction { pub from: EthAddress, pub to: ManagedAddress, pub token_id: TokenIdentifier, pub amount: BigUint, pub tx_nonce: TxNonce, + pub call_data: ManagedOption>, } -pub type EthTxAsMultiValue = - MultiValue5, ManagedAddress, TokenIdentifier, BigUint, TxNonce>; +pub type EthTxAsMultiValue = MultiValue6< + EthAddress, + ManagedAddress, + TokenIdentifier, + BigUint, + TxNonce, + ManagedOption>, +>; -#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, TypeAbi, ManagedVecItem, Clone)] +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone)] pub struct Transaction { pub block_nonce: BlockNonce, pub nonce: TxNonce, diff --git a/common/transaction/src/transaction_status.rs b/common/transaction/src/transaction_status.rs index 467477dc..e1933fa9 100644 --- a/common/transaction/src/transaction_status.rs +++ b/common/transaction/src/transaction_status.rs @@ -1,16 +1,8 @@ -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::derive_imports::*; +#[type_abi] #[derive( - TopEncode, - TopDecode, - NestedEncode, - NestedDecode, - TypeAbi, - PartialEq, - Clone, - Copy, - ManagedVecItem, + TopEncode, TopDecode, NestedEncode, NestedDecode, PartialEq, Clone, Copy, ManagedVecItem, )] pub enum TransactionStatus { None, diff --git a/common/tx-batch-module/Cargo.toml b/common/tx-batch-module/Cargo.toml index 3d58cda8..80d4c470 100644 --- a/common/tx-batch-module/Cargo.toml +++ b/common/tx-batch-module/Cargo.toml @@ -5,10 +5,10 @@ authors = ["dorin-iancu "] edition = "2018" [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" [dependencies.transaction] path = "../transaction" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/common/tx-batch-module/src/batch_status.rs b/common/tx-batch-module/src/batch_status.rs index cdf6f902..d8708c01 100644 --- a/common/tx-batch-module/src/batch_status.rs +++ b/common/tx-batch-module/src/batch_status.rs @@ -1,9 +1,10 @@ -multiversx_sc::derive_imports!(); +use multiversx_sc::derive_imports::*; use multiversx_sc::{api::ManagedTypeApi, types::ManagedVec}; use transaction::{BlockNonce, TxNonce}; -#[derive(TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(TopEncode, TopDecode)] pub enum BatchStatus { AlreadyProcessed, Empty, diff --git a/common/tx-batch-module/src/lib.rs b/common/tx-batch-module/src/lib.rs index 545a4cca..c033a911 100644 --- a/common/tx-batch-module/src/lib.rs +++ b/common/tx-batch-module/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::imports::*; pub use batch_status::BatchStatus; use transaction::{Transaction, TxBatchSplitInFields, MIN_BLOCKS_FOR_FINALITY}; @@ -184,7 +183,7 @@ pub trait TxBatchModule { } let max_batch_size = self.max_tx_batch_size().get(); - if tx_batch.len() == max_batch_size { + if tx_batch.len() >= max_batch_size { return true; } diff --git a/docs/setup.md b/docs/setup.md index 01186a22..dd44c29b 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -8,7 +8,7 @@ Additionally, you will have to issue at least two ESDT tokens (suggested paramet IMPORTANT: Ticker should always be chosen so that the aggregator has a mapping for it. "WEGLD" would not work at all, since the aggregator wouldn't know about the token, but "EGLD" works perfectly) -You can find more about how to issue an ESDT token here: https://docs.elrond.com/developers/esdt-tokens/#issuance-of-fungible-esdt-tokens +You can find more about how to issue an ESDT token here: https://docs.multiversx.com/tokens/esdt-tokens/#issuance-of-fungible-esdt-tokens Next, we're going to setup the main "controller" contract, which will be a multisig-style SC. You can find more details about this type of smart contract here: https://github.com/multiversx/mx-sdk-rs/blob/master/contracts/examples/multisig/README.md @@ -35,7 +35,7 @@ The `_code` arguments are the compiled wasm bytecode of the respective contracts `esdt_safe_eth_tx_gas_limit` and `multi_transfer_esdt_eth_tx_gas_limit` are gas limits used for MultiversX -> Ethereum tx, and Ethereum -> MultiversX tx respectively. This is the gas limit used for processing on the Ethereum side (briding over to MultiversX or from MultiversX). This cost is used to calculate the fees taken from the bridged token, to be then used as payment/incentive for the relayers. -`wrapped_egld_token_id` is the token identifier of the previously issued "WrappedEgld" token (Note: identifier format is ticker + '-' + 6 random characters). For WrappedEgld, it might look something like "EGLD-123456". +`wrapped_egld_token_id` is the token identifier of the previously issued "WrappedEgld" token (Note: identifier format is ticker + '-' + 6 random characters). For WrappedEgld, it might look something like "WEGLD-123456". `token_whitelist` is a list of tokens already issued that will be used by the bridge, in our case, that will be only one: The "WrappedEth" token. diff --git a/esdt-safe/.gitignore b/esdt-safe/.gitignore index f00d026a..9494cb14 100644 --- a/esdt-safe/.gitignore +++ b/esdt-safe/.gitignore @@ -3,9 +3,5 @@ /target/ */target/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # The mxpy output output diff --git a/esdt-safe/Cargo.toml b/esdt-safe/Cargo.toml index a7ce3334..2d4b227c 100644 --- a/esdt-safe/Cargo.toml +++ b/esdt-safe/Cargo.toml @@ -26,11 +26,14 @@ path = "../common/tx-batch-module" [dependencies.max-bridged-amount-module] path = "../common/max-bridged-amount-module" +[dependencies.multiversx-price-aggregator-sc] +version = "=0.52.0" + [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" [dependencies.multiversx-sc-modules] -version = "0.45.2" +version = "=0.52.3" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/esdt-safe/interaction/snippets.sh b/esdt-safe/interaction/snippets.sh index 8a46ca3a..ec1c5148 100644 --- a/esdt-safe/interaction/snippets.sh +++ b/esdt-safe/interaction/snippets.sh @@ -1,8 +1,8 @@ -ALICE="/home/elrond/elrond-sdk/mxpy/testnet/wallets/users/alice.pem" -BOB="/home/elrond/elrond-sdk/mxpy/testnet/wallets/users/bob.pem" +ALICE="/home/multiversx/multiversx-sdk/mxpy/testnet/wallets/users/alice.pem" +BOB="/home/multiversx/multiversx-sdk/mxpy/testnet/wallets/users/bob.pem" ADDRESS=$(mxpy data load --key=address-testnet-esdt-safe) DEPLOY_TRANSACTION=$(mxpy data load --key=deployTransaction-testnet) -PROXY=https://testnet-gateway.elrond.com +PROXY=https://testnet-gateway.multiversx.com CHAIN_ID=T BOB_ADDRESS=0x8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8 # 32 bytes diff --git a/esdt-safe/mandos/add_refund_batch.scen.json b/esdt-safe/mandos/add_refund_batch.scen.json deleted file mode 100644 index c88b0013..00000000 --- a/esdt-safe/mandos/add_refund_batch.scen.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "name": "add refund batch", - "steps": [ - { - "step": "externalSteps", - "path": "create_another_tx_ok.scen.json" - }, - { - "step": "setState", - "currentBlockInfo": { - "blockNonce": "5" - } - }, - { - "step": "scCall", - "txId": "add-refund-batch", - "tx": { - "from": "address:owner", - "to": "sc:esdt_safe", - "function": "addRefundBatch", - "arguments": [ - { - "01-block_nonce": "u64:2", - "02-nonce": "u64:1", - "03-from": "u32:20|0x0102030405060708091011121314151617181920", - "04-to": "u32:32|address:user1", - "05-token_identifier": "nested:str:BRIDGE-123456", - "06-amount": "biguint:2,000,000", - "07-is_refund_tx": "u8:1", - "11-block_nonce": "u64:3", - "12-nonce": "u64:2", - "13-from": "u32:20|0x0102030405060708091011121314151617181920", - "14-to": "u32:32|address:user2", - "15-token_identifier": "nested:str:BRIDGE-123456", - "16-amount": "biguint:3,000,000", - "17-is_refund_tx": "u8:1" - } - ], - "gasLimit": "100,000,000", - "gasPrice": "0" - }, - "expect": { - "status": "0", - "out": [ - - ], - "message": "", - "gas": "*", - "refund": "*" - } - }, - { - "step": "checkState", - "accounts": { - "sc:esdt_safe": { - "nonce": "0", - "balance": "0", - "esdt": { - "str:BRIDGE-123456": { - "balance": "3,001,300", - "roles": [ - "ESDTRoleLocalBurn" - ] - } - }, - "storage": { - "str:pendingBatches|u64:1|str:.item|u32:1": { - "1-block_nonce": "u64:0", - "2-nonce": "u64:1", - "3-from": "u32:32|address:user1", - "4-to": "u32:20|0x0102030405060708091011121314151617181920", - "5-token_identifier": "nested:str:BRIDGE-123456", - "6-amount": "biguint:400", - "7-is_refund_tx": "u8:0" - }, - "str:pendingBatches|u64:1|str:.item|u32:2": { - "1-block_nonce": "u64:0", - "2-nonce": "u64:2", - "3-from": "u32:32|address:user2", - "4-to": "u32:20|0x0102030405060708091011121314151617181920", - "5-token_identifier": "nested:str:BRIDGE-123456", - "6-amount": "biguint:900", - "7-is_refund_tx": "u8:0" - }, - "str:pendingBatches|u64:1|str:.item|u32:3": { - "1-block_nonce": "u64:5", - "2-nonce": "u64:3", - "3-from": "u32:32|address:user1", - "4-to": "u32:20|0x0102030405060708091011121314151617181920", - "5-token_identifier": "nested:str:BRIDGE-123456", - "6-amount": "biguint:500,000", - "7-is_refund_tx": "u8:1" - }, - "str:pendingBatches|u64:1|str:.item|u32:4": { - "1-block_nonce": "u64:5", - "2-nonce": "u64:4", - "3-from": "u32:32|address:user2", - "4-to": "u32:20|0x0102030405060708091011121314151617181920", - "5-token_identifier": "nested:str:BRIDGE-123456", - "6-amount": "biguint:1,500,000", - "7-is_refund_tx": "u8:1" - }, - "str:firstBatchId": "1", - "str:lastBatchId": "1", - - "str:accumulatedTransactionFees|nested:str:BRIDGE-123456": "3,000,000", - - "+": "" - }, - "code": "file:../output/esdt-safe.wasm" - }, - "+": {} - } - } - ] -} diff --git a/esdt-safe/meta/Cargo.toml b/esdt-safe/meta/Cargo.toml index 00e7a9e7..8e988868 100644 --- a/esdt-safe/meta/Cargo.toml +++ b/esdt-safe/meta/Cargo.toml @@ -10,6 +10,6 @@ publish = false [dependencies.esdt-safe] path = ".." -[dependencies.multiversx-sc-meta] -version = "0.45.2" +[dependencies.multiversx-sc-meta-lib] +version = "=0.52.3" default-features = false diff --git a/esdt-safe/meta/src/main.rs b/esdt-safe/meta/src/main.rs index 232dc09e..811f0759 100644 --- a/esdt-safe/meta/src/main.rs +++ b/esdt-safe/meta/src/main.rs @@ -1,3 +1,3 @@ fn main() { - multiversx_sc_meta::cli_main::(); + multiversx_sc_meta_lib::cli_main::(); } diff --git a/esdt-safe/sc-config.toml b/esdt-safe/sc-config.toml new file mode 100644 index 00000000..0dc85bf8 --- /dev/null +++ b/esdt-safe/sc-config.toml @@ -0,0 +1,13 @@ +[settings] + +[[proxy]] +path = "../bridge-proxy/src/esdt_safe_proxy.rs" + +[[proxy]] +path = "../bridged-tokens-wrapper/src/esdt_safe_proxy.rs" + +[[proxy]] +path = "../multi-transfer-esdt/src/esdt_safe_proxy.rs" + +[[proxy]] +path = "../multisig/src/esdt_safe_proxy.rs" \ No newline at end of file diff --git a/esdt-safe/scenarios/add_refund_batch.scen.json b/esdt-safe/scenarios/add_refund_batch.scen.json new file mode 100644 index 00000000..e9a7fbe3 --- /dev/null +++ b/esdt-safe/scenarios/add_refund_batch.scen.json @@ -0,0 +1,51 @@ +{ + "name": "add refund batch", + "steps": [ + { + "step": "externalSteps", + "path": "create_another_tx_ok.scen.json" + }, + { + "step": "setState", + "currentBlockInfo": { + "blockNonce": "5" + } + }, + { + "step": "scCall", + "txId": "add-refund-batch", + "tx": { + "from": "address:owner", + "to": "sc:esdt_safe", + "function": "addRefundBatch", + "arguments": [ + { + "01-block_nonce": "u64:2", + "02-nonce": "u64:1", + "03-from": "u32:20|0x0102030405060708091011121314151617181920", + "04-to": "u32:32|address:user1", + "05-token_identifier": "nested:str:BRIDGE-123456", + "06-amount": "biguint:2,000,000", + "07-is_refund_tx": "u8:1", + "11-block_nonce": "u64:3", + "12-nonce": "u64:2", + "13-from": "u32:20|0x0102030405060708091011121314151617181920", + "14-to": "u32:32|address:user2", + "15-token_identifier": "nested:str:BRIDGE-123456", + "16-amount": "biguint:3,000,000", + "17-is_refund_tx": "u8:1" + } + ], + "gasLimit": "100,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "4", + "out": [], + "message": "str:Invalid caller", + "gas": "*", + "refund": "*" + } + } + ] +} diff --git a/esdt-safe/mandos/create_another_tx_ok.scen.json b/esdt-safe/scenarios/create_another_tx_ok.scen.json similarity index 91% rename from esdt-safe/mandos/create_another_tx_ok.scen.json rename to esdt-safe/scenarios/create_another_tx_ok.scen.json index 224c9e7a..653c581b 100644 --- a/esdt-safe/mandos/create_another_tx_ok.scen.json +++ b/esdt-safe/scenarios/create_another_tx_ok.scen.json @@ -11,10 +11,12 @@ "tx": { "from": "address:user2", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:BRIDGE-123456", - "value": "1,500,900" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:BRIDGE-123456", + "value": "1,500,900" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -24,9 +26,7 @@ }, "expect": { "status": "0", - "out": [ - - ], + "out": [], "message": "", "gas": "*", "refund": "*" @@ -71,7 +71,8 @@ "str:BRIDGE-123456": { "balance": "3,001,300", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -105,4 +106,4 @@ } } ] -} +} \ No newline at end of file diff --git a/esdt-safe/mandos/create_another_tx_too_late_for_batch.scen.json b/esdt-safe/scenarios/create_another_tx_too_late_for_batch.scen.json similarity index 94% rename from esdt-safe/mandos/create_another_tx_too_late_for_batch.scen.json rename to esdt-safe/scenarios/create_another_tx_too_late_for_batch.scen.json index c9584de9..811c9c0a 100644 --- a/esdt-safe/mandos/create_another_tx_too_late_for_batch.scen.json +++ b/esdt-safe/scenarios/create_another_tx_too_late_for_batch.scen.json @@ -45,10 +45,12 @@ "tx": { "from": "address:user2", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:BRIDGE-123456", - "value": "1,500,100" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:BRIDGE-123456", + "value": "1,500,100" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -58,9 +60,7 @@ }, "expect": { "status": "0", - "out": [ - - ], + "out": [], "message": "", "gas": "*", "refund": "*" @@ -84,7 +84,8 @@ "str:BRIDGE-123456": { "balance": "4,501,400", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -176,10 +177,12 @@ "tx": { "from": "address:user3", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:BRIDGE-123456", - "value": "1,500,100" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:BRIDGE-123456", + "value": "1,500,100" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -189,9 +192,7 @@ }, "expect": { "status": "0", - "out": [ - - ], + "out": [], "message": "", "gas": "*", "refund": "*" @@ -215,7 +216,8 @@ "str:BRIDGE-123456": { "balance": "6,001,500", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -289,4 +291,4 @@ } } ] -} +} \ No newline at end of file diff --git a/esdt-safe/mandos/create_transaction_ok.scen.json b/esdt-safe/scenarios/create_transaction_ok.scen.json similarity index 91% rename from esdt-safe/mandos/create_transaction_ok.scen.json rename to esdt-safe/scenarios/create_transaction_ok.scen.json index d3e159cb..22bacf7d 100644 --- a/esdt-safe/mandos/create_transaction_ok.scen.json +++ b/esdt-safe/scenarios/create_transaction_ok.scen.json @@ -29,10 +29,12 @@ "tx": { "from": "address:user1", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:BRIDGE-123456", - "value": "1,500,400" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:BRIDGE-123456", + "value": "1,500,400" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -87,7 +89,8 @@ "str:BRIDGE-123456": { "balance": "1,500,400", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -112,4 +115,4 @@ } } ] -} +} \ No newline at end of file diff --git a/esdt-safe/mandos/create_transaction_over_max_amount.scen.json b/esdt-safe/scenarios/create_transaction_over_max_amount.scen.json similarity index 83% rename from esdt-safe/mandos/create_transaction_over_max_amount.scen.json rename to esdt-safe/scenarios/create_transaction_over_max_amount.scen.json index c76faa7f..44418d98 100644 --- a/esdt-safe/mandos/create_transaction_over_max_amount.scen.json +++ b/esdt-safe/scenarios/create_transaction_over_max_amount.scen.json @@ -33,10 +33,12 @@ "tx": { "from": "address:user1", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:BRIDGE-123456", - "value": "1,800,000" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:BRIDGE-123456", + "value": "1,800,000" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -57,10 +59,12 @@ "tx": { "from": "address:user1", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:BRIDGE-123456", - "value": "1,600,000" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:BRIDGE-123456", + "value": "1,600,000" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -70,13 +74,11 @@ }, "expect": { "status": "0", - "out": [ - - ], + "out": [], "message": "", "gas": "*", "refund": "*" } } ] -} +} \ No newline at end of file diff --git a/esdt-safe/mandos/distribute_fees.scen.json b/esdt-safe/scenarios/distribute_fees.scen.json similarity index 92% rename from esdt-safe/mandos/distribute_fees.scen.json rename to esdt-safe/scenarios/distribute_fees.scen.json index 30469112..116bdef3 100644 --- a/esdt-safe/mandos/distribute_fees.scen.json +++ b/esdt-safe/scenarios/distribute_fees.scen.json @@ -43,15 +43,15 @@ "balance": "0", "esdt": { "str:BRIDGE-123456": { - "balance": "0", + "balance": "400", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, "storage": { "str:accumulatedTransactionFees|nested:str:BRIDGE-123456": "0", - "+": "" }, "code": "file:../output/esdt-safe.wasm" diff --git a/esdt-safe/mandos/execute_batch_both_rejected.scen.json b/esdt-safe/scenarios/execute_batch_both_rejected.scen.json similarity index 95% rename from esdt-safe/mandos/execute_batch_both_rejected.scen.json rename to esdt-safe/scenarios/execute_batch_both_rejected.scen.json index 55d42cc2..a80b108e 100644 --- a/esdt-safe/mandos/execute_batch_both_rejected.scen.json +++ b/esdt-safe/scenarios/execute_batch_both_rejected.scen.json @@ -15,7 +15,8 @@ "function": "setTransactionBatchStatus", "arguments": [ "1", - "4", "4" + "4", + "4" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -97,7 +98,8 @@ "str:BRIDGE-123456": { "balance": "3,000,000", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -105,9 +107,7 @@ "str:pendingBatches|u64:1": "", "str:firstBatchId": "2", "str:lastBatchId": "2", - "str:accumulatedTransactionFees|nested:str:BRIDGE-123456": "3,000,000", - "+": "" }, "code": "file:../output/esdt-safe.wasm" diff --git a/esdt-safe/mandos/execute_batch_both_success.scen.json b/esdt-safe/scenarios/execute_batch_both_success.scen.json similarity index 94% rename from esdt-safe/mandos/execute_batch_both_success.scen.json rename to esdt-safe/scenarios/execute_batch_both_success.scen.json index d8d3bdcb..ddbf763b 100644 --- a/esdt-safe/mandos/execute_batch_both_success.scen.json +++ b/esdt-safe/scenarios/execute_batch_both_success.scen.json @@ -15,7 +15,8 @@ "function": "setTransactionBatchStatus", "arguments": [ "1", - "3", "3" + "3", + "3" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -93,9 +94,10 @@ "balance": "0", "esdt": { "str:BRIDGE-123456": { - "balance": "3,000,000", + "balance": "3,001,300", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -103,9 +105,7 @@ "str:pendingBatches|u64:1": "", "str:firstBatchId": "2", "str:lastBatchId": "2", - "str:accumulatedTransactionFees|nested:str:BRIDGE-123456": "3,000,000", - "+": "" }, "code": "file:../output/esdt-safe.wasm" diff --git a/esdt-safe/mandos/execute_batch_one_success_one_rejected.scen.json b/esdt-safe/scenarios/execute_batch_one_success_one_rejected.scen.json similarity index 76% rename from esdt-safe/mandos/execute_batch_one_success_one_rejected.scen.json rename to esdt-safe/scenarios/execute_batch_one_success_one_rejected.scen.json index 757f5141..3a76c22c 100644 --- a/esdt-safe/mandos/execute_batch_one_success_one_rejected.scen.json +++ b/esdt-safe/scenarios/execute_batch_one_success_one_rejected.scen.json @@ -15,7 +15,8 @@ "function": "setTransactionBatchStatus", "arguments": [ "1", - "3", "4" + "3", + "4" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -89,28 +90,6 @@ }, "storage": {} }, - "sc:esdt_safe": { - "nonce": "0", - "balance": "0", - "esdt": { - "str:BRIDGE-123456": { - "balance": "3,000,000", - "roles": [ - "ESDTRoleLocalBurn" - ] - } - }, - "storage": { - "str:pendingBatches|u64:1": "", - "str:firstBatchId": "2", - "str:lastBatchId": "2", - - "str:accumulatedTransactionFees|nested:str:BRIDGE-123456": "3,000,000", - - "+": "" - }, - "code": "file:../output/esdt-safe.wasm" - }, "+": {} } } diff --git a/esdt-safe/mandos/execute_transaction_rejected.scen.json b/esdt-safe/scenarios/execute_transaction_rejected.scen.json similarity index 96% rename from esdt-safe/mandos/execute_transaction_rejected.scen.json rename to esdt-safe/scenarios/execute_transaction_rejected.scen.json index 52a289ac..81345ee9 100644 --- a/esdt-safe/mandos/execute_transaction_rejected.scen.json +++ b/esdt-safe/scenarios/execute_transaction_rejected.scen.json @@ -67,7 +67,8 @@ "str:BRIDGE-123456": { "balance": "1,500,000", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -75,9 +76,7 @@ "str:pendingBatches|u64:1": "", "str:firstBatchId": "2", "str:lastBatchId": "2", - "str:accumulatedTransactionFees|nested:str:BRIDGE-123456": "1,500,000", - "+": "" }, "code": "file:../output/esdt-safe.wasm" diff --git a/esdt-safe/mandos/execute_transaction_success.scen.json b/esdt-safe/scenarios/execute_transaction_success.scen.json similarity index 94% rename from esdt-safe/mandos/execute_transaction_success.scen.json rename to esdt-safe/scenarios/execute_transaction_success.scen.json index 71fbb4c3..1731749b 100644 --- a/esdt-safe/mandos/execute_transaction_success.scen.json +++ b/esdt-safe/scenarios/execute_transaction_success.scen.json @@ -64,9 +64,10 @@ "balance": "0", "esdt": { "str:BRIDGE-123456": { - "balance": "1,500,000", + "balance": "1,500,400", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, diff --git a/esdt-safe/mandos/get_next_pending_tx.scen.json b/esdt-safe/scenarios/get_next_pending_tx.scen.json similarity index 100% rename from esdt-safe/mandos/get_next_pending_tx.scen.json rename to esdt-safe/scenarios/get_next_pending_tx.scen.json diff --git a/esdt-safe/mandos/get_next_tx_batch.scen.json b/esdt-safe/scenarios/get_next_tx_batch.scen.json similarity index 100% rename from esdt-safe/mandos/get_next_tx_batch.scen.json rename to esdt-safe/scenarios/get_next_tx_batch.scen.json diff --git a/esdt-safe/mandos/get_next_tx_batch_too_early.scen.json b/esdt-safe/scenarios/get_next_tx_batch_too_early.scen.json similarity index 100% rename from esdt-safe/mandos/get_next_tx_batch_too_early.scen.json rename to esdt-safe/scenarios/get_next_tx_batch_too_early.scen.json diff --git a/esdt-safe/mandos/setup_accounts.scen.json b/esdt-safe/scenarios/setup_accounts.scen.json similarity index 76% rename from esdt-safe/mandos/setup_accounts.scen.json rename to esdt-safe/scenarios/setup_accounts.scen.json index c6e77b27..b4f5b455 100644 --- a/esdt-safe/mandos/setup_accounts.scen.json +++ b/esdt-safe/scenarios/setup_accounts.scen.json @@ -3,7 +3,7 @@ "steps": [ { "step": "externalSteps", - "path": "../../price-aggregator/mandos/get_latest_price_feed.scen.json" + "path": "../../price-aggregator/scenarios/get_latest_price_feed.scen.json" }, { "step": "setState", @@ -35,6 +35,16 @@ "creatorAddress": "address:owner", "creatorNonce": "0", "newAddress": "sc:esdt_safe" + }, + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:multi_transfer" + }, + { + "creatorAddress": "address:owner", + "creatorNonce": "2", + "newAddress": "sc:bridged_tokens_wrapper" } ] }, @@ -47,6 +57,7 @@ "value": "0", "arguments": [ "sc:price_aggregator", + "sc:multi_transfer", "150,000" ], "gasLimit": "20,000,000", @@ -69,7 +80,33 @@ "function": "addTokenToWhitelist", "arguments": [ "str:BRIDGE-123456", - "str:BRIDGE" + "str:BRIDGE", + "true", + "false", + "0", + "0", + "0" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-bridged-tokens-wrapper-addr", + "tx": { + "from": "address:owner", + "to": "sc:esdt_safe", + "value": "0", + "function": "setBridgedTokensWrapperAddress", + "arguments": [ + "sc:bridged_tokens_wrapper" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -89,6 +126,8 @@ "balance": "0", "storage": { "str:feeEstimatorContractAddress": "sc:price_aggregator", + "str:multiTransferContractAddress": "sc:multi_transfer", + "str:bridgedTokensWrapperAddress": "sc:bridged_tokens_wrapper", "str:maxTxBatchSize": "10", "str:maxTxBatchBlockDuration": "100", "str:firstBatchId": "1", @@ -135,12 +174,15 @@ "str:BRIDGE-123456": { "balance": "0", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, "storage": { "str:feeEstimatorContractAddress": "sc:price_aggregator", + "str:multiTransferContractAddress": "sc:multi_transfer", + "str:bridgedTokensWrapperAddress": "sc:bridged_tokens_wrapper", "str:maxTxBatchSize": "10", "str:maxTxBatchBlockDuration": "100", "str:firstBatchId": "1", diff --git a/esdt-safe/mandos/zero_fees.scen.json b/esdt-safe/scenarios/zero_fees.scen.json similarity index 90% rename from esdt-safe/mandos/zero_fees.scen.json rename to esdt-safe/scenarios/zero_fees.scen.json index f5d6d36d..5e573a8c 100644 --- a/esdt-safe/mandos/zero_fees.scen.json +++ b/esdt-safe/scenarios/zero_fees.scen.json @@ -37,7 +37,8 @@ "str:BRIDGE-123456": { "balance": "0", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -56,10 +57,12 @@ "tx": { "from": "address:user1", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:BRIDGE-123456", - "value": "1,500,400" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:BRIDGE-123456", + "value": "1,500,400" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -93,7 +96,8 @@ "str:BRIDGE-123456": { "balance": "1,500,400", "roles": [ - "ESDTRoleLocalBurn" + "ESDTRoleLocalBurn", + "ESDTRoleLocalMint" ] } }, @@ -118,4 +122,4 @@ } } ] -} +} \ No newline at end of file diff --git a/esdt-safe/src/lib.rs b/esdt-safe/src/lib.rs index 5c946f68..02e76113 100644 --- a/esdt-safe/src/lib.rs +++ b/esdt-safe/src/lib.rs @@ -6,6 +6,7 @@ multiversx_sc::derive_imports!(); use core::convert::TryFrom; +use core::ops::Deref; use eth_address::*; use fee_estimator_module::GWEI_STRING; use transaction::{transaction_status::TransactionStatus, Transaction}; @@ -13,6 +14,16 @@ use transaction::{transaction_status::TransactionStatus, Transaction}; const DEFAULT_MAX_TX_BATCH_SIZE: usize = 10; const DEFAULT_MAX_TX_BATCH_BLOCK_DURATION: u64 = 100; // ~10 minutes +pub type PaymentsVec = ManagedVec>; + +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, ManagedVecItem, PartialEq)] +pub struct RefundInfo { + pub address: ManagedAddress, + pub initial_batch_id: u64, + pub initial_nonce: u64, +} + #[multiversx_sc::contract] pub trait EsdtSafe: fee_estimator_module::FeeEstimatorModule @@ -27,9 +38,17 @@ pub trait EsdtSafe: /// eth_tx_gas_limit - The gas limit that will be used for transactions on the ETH side. /// Will be used to compute the fees for the transfer #[init] - fn init(&self, fee_estimator_contract_address: ManagedAddress, eth_tx_gas_limit: BigUint) { + fn init( + &self, + fee_estimator_contract_address: ManagedAddress, + multi_transfer_contract_address: ManagedAddress, + eth_tx_gas_limit: BigUint, + ) { self.fee_estimator_contract_address() .set(&fee_estimator_contract_address); + self.multi_transfer_contract_address() + .set(&multi_transfer_contract_address); + self.eth_tx_gas_limit().set(ð_tx_gas_limit); self.max_tx_batch_size() @@ -50,7 +69,38 @@ pub trait EsdtSafe: } #[upgrade] - fn upgrade(&self) {} + fn upgrade( + &self, + fee_estimator_contract_address: ManagedAddress, + multi_transfer_contract_address: ManagedAddress, + bridge_proxy_contract_address: ManagedAddress, + eth_tx_gas_limit: BigUint, + ) { + self.fee_estimator_contract_address() + .set(&fee_estimator_contract_address); + self.multi_transfer_contract_address() + .set(&multi_transfer_contract_address); + self.bridge_proxy_contract_address() + .set(&bridge_proxy_contract_address); + + self.eth_tx_gas_limit().set(ð_tx_gas_limit); + + self.max_tx_batch_size() + .set_if_empty(DEFAULT_MAX_TX_BATCH_SIZE); + self.max_tx_batch_block_duration() + .set_if_empty(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); + + // batch ID 0 is considered invalid + self.first_batch_id().set_if_empty(1); + self.last_batch_id().set_if_empty(1); + + // set ticker for "GWEI" + let gwei_token_id = TokenIdentifier::from(GWEI_STRING); + self.token_ticker(&gwei_token_id) + .set(gwei_token_id.as_managed_buffer()); + + self.set_paused(true); + } /// Sets the statuses for the transactions, after they were executed on the Ethereum side. /// @@ -83,16 +133,9 @@ pub trait EsdtSafe: } match tx_status { - TransactionStatus::Executed => { - // local burn role might be removed while tx is executed - // tokens will remain locked forever in that case - // otherwise, the whole batch would fail - if self.is_local_role_set(&tx.token_identifier, &EsdtLocalRole::Burn) { - self.burn_esdt_token(&tx.token_identifier, &tx.amount); - } - } + TransactionStatus::Executed => {} TransactionStatus::Rejected => { - let addr = ManagedAddress::try_from(tx.from).unwrap(); + let addr = ManagedAddress::try_from(tx.from.clone()).unwrap(); self.mark_refund(&addr, &tx.token_identifier, &tx.amount); } _ => { @@ -100,27 +143,54 @@ pub trait EsdtSafe: } } - self.set_status_event(batch_id, tx.nonce, tx_status); + self.set_status_event( + batch_id, + tx.from, + tx.to, + tx.token_identifier, + tx.amount, + tx.nonce, + tx_status, + ); } self.clear_first_batch(&mut tx_batch); } - /// Converts failed Ethereum -> Elrond transactions to Elrond -> Ethereum transaction. + /// Converts failed Ethereum -> MultiversX transactions to MultiversX -> Ethereum transaction. /// This is done every now and then to refund the tokens. /// - /// As with normal Elrond -> Ethereum transactions, a part of the tokens will be + /// As with normal MultiversX -> Ethereum transactions, a part of the tokens will be /// subtracted to pay for the fees - #[only_owner] + #[payable("*")] #[endpoint(addRefundBatch)] fn add_refund_batch(&self, refund_transactions: ManagedVec>) { + let caller = self.blockchain().get_caller(); + let multi_transfer_address = self.multi_transfer_contract_address().get(); + require!(caller == multi_transfer_address, "Invalid caller"); + + let refund_payments = self.call_value().all_esdt_transfers().deref().clone(); + require!( + !refund_payments.is_empty(), + "Cannot refund with no payments" + ); + let block_nonce = self.blockchain().get_block_nonce(); let mut cached_token_ids = ManagedVec::::new(); let mut cached_prices = ManagedVec::::new(); let mut new_transactions = ManagedVec::new(); let mut original_tx_nonces = ManagedVec::::new(); - for refund_tx in &refund_transactions { + for (refund_tx, refund_payment) in refund_transactions.iter().zip(refund_payments.iter()) { + require!( + refund_tx.token_identifier == refund_payment.token_identifier, + "Token identifiers do not match" + ); + require!( + refund_tx.amount == refund_payment.amount, + "Amounts do not match" + ); + let required_fee = match cached_token_ids .iter() .position(|id| *id == refund_tx.token_identifier) @@ -139,21 +209,46 @@ pub trait EsdtSafe: continue; } - let actual_bridged_amount = refund_tx.amount - required_fee; + let actual_bridged_amount = refund_tx.amount - &required_fee; + self.refund_fees_for_ethereum(&refund_tx.token_identifier) + .update(|fees| *fees += required_fee); let tx_nonce = self.get_and_save_next_tx_id(); - // "from" and "to" are inverted, since this was initially an Ethereum -> Elrond tx + // "from" and "to" are inverted, since this was initially an Ethereum -> MultiversX tx let new_tx = Transaction { block_nonce, nonce: tx_nonce, from: refund_tx.to, to: refund_tx.from, - token_identifier: refund_tx.token_identifier, - amount: actual_bridged_amount, + token_identifier: refund_tx.token_identifier.clone(), + amount: actual_bridged_amount.clone(), is_refund_tx: true, }; new_transactions.push(new_tx); original_tx_nonces.push(refund_tx.nonce); + + let refund_token_id = refund_tx.token_identifier; + + if self.mint_burn_token(&refund_token_id).get() { + let burn_balances_mapper = self.burn_balances(&refund_token_id); + let mint_balances_mapper = self.mint_balances(&refund_token_id); + if !self.native_token(&refund_token_id).get() { + require!( + mint_balances_mapper.get() + >= &burn_balances_mapper.get() + &actual_bridged_amount, + "Not enough minted tokens!" + ); + } + let burn_executed = self.internal_burn(&refund_token_id, &actual_bridged_amount); + require!(burn_executed, "Cannot do the burn action!"); + burn_balances_mapper.update(|burned| { + *burned += &actual_bridged_amount; + }); + } else { + self.total_balances(&refund_token_id).update(|total| { + *total += &actual_bridged_amount; + }); + } } let batch_ids = self.add_multiple_tx_to_batch(&new_transactions); @@ -167,7 +262,7 @@ pub trait EsdtSafe: // endpoints - /// Create an Elrond -> Ethereum transaction. Only fungible tokens are accepted. + /// Create an MultiversX -> Ethereum transaction. Only fungible tokens are accepted. /// /// Every transfer will have a part of the tokens subtracted as fees. /// The fee amount depends on the global eth_tx_gas_limit @@ -176,7 +271,11 @@ pub trait EsdtSafe: /// fee_amount = price_per_gas_unit * eth_tx_gas_limit #[payable("*")] #[endpoint(createTransaction)] - fn create_transaction(&self, to: EthAddress) { + fn create_transaction( + &self, + to: EthAddress, + opt_refund_info: OptionalValue>, + ) { require!(self.not_paused(), "Cannot create transaction while paused"); let (payment_token, payment_amount) = self.call_value().single_fungible_esdt(); @@ -190,27 +289,88 @@ pub trait EsdtSafe: self.require_below_max_amount(&payment_token, &payment_amount); + // This addr is used for the refund, if the transaction fails + // This is passed by the BridgeTokenWrapper contract + let mut is_refund_tx = false; + let caller = self.blockchain().get_caller(); + let refund_info = match opt_refund_info { + OptionalValue::Some(refund_info) => { + if caller == self.bridge_proxy_contract_address().get() { + is_refund_tx = true; + refund_info + } else if caller == self.bridged_tokens_wrapper_address().get() { + refund_info + } else { + sc_panic!("Cannot specify a refund address from this caller"); + } + } + OptionalValue::None => RefundInfo { + address: caller, + initial_batch_id: 0, + initial_nonce: 0, + }, + }; + self.accumulated_transaction_fees(&payment_token) .update(|fees| *fees += &required_fee); - let actual_bridged_amount = payment_amount - required_fee; - let caller = self.blockchain().get_caller(); + let actual_bridged_amount = payment_amount - required_fee.clone(); let tx_nonce = self.get_and_save_next_tx_id(); let tx = Transaction { block_nonce: self.blockchain().get_block_nonce(), nonce: tx_nonce, - from: caller.as_managed_buffer().clone(), + from: refund_info.address.as_managed_buffer().clone(), to: to.as_managed_buffer().clone(), - token_identifier: payment_token, - amount: actual_bridged_amount, - is_refund_tx: false, + token_identifier: payment_token.clone(), + amount: actual_bridged_amount.clone(), + is_refund_tx, }; - let batch_id = self.add_to_batch(tx); - self.create_transaction_event(batch_id, tx_nonce); + let batch_id = self.add_to_batch(tx.clone()); + if self.mint_burn_token(&payment_token).get() { + let burn_balances_mapper = self.burn_balances(&payment_token); + let mint_balances_mapper = self.mint_balances(&payment_token); + if !self.native_token(&payment_token).get() { + require!( + mint_balances_mapper.get() + >= &burn_balances_mapper.get() + &actual_bridged_amount, + "Not enough minted tokens!" + ); + } + let burn_executed = self.internal_burn(&payment_token, &actual_bridged_amount); + require!(burn_executed, "Cannot do the burn action!"); + burn_balances_mapper.update(|burned| { + *burned += &actual_bridged_amount; + }); + } else { + self.total_balances(&payment_token).update(|total| { + *total += &actual_bridged_amount; + }); + } + if !is_refund_tx { + self.create_transaction_event( + batch_id, + tx_nonce, + payment_token, + actual_bridged_amount, + required_fee, + refund_info.address.as_managed_buffer().clone(), + tx.to, + ); + } else { + self.create_refund_transaction_event( + batch_id, + tx_nonce, + payment_token, + actual_bridged_amount, + required_fee, + refund_info.initial_batch_id, + refund_info.initial_nonce, + ); + } } - /// Claim funds for failed Elrond -> Ethereum transactions. + /// Claim funds for failed MultiversX -> Ethereum transactions. /// These are not sent automatically to prevent the contract getting stuck. /// For example, if the receiver is a SC, a frozen account, etc. #[endpoint(claimRefund)] @@ -220,12 +380,124 @@ pub trait EsdtSafe: require!(refund_amount > 0, "Nothing to refund"); self.refund_amount(&caller, &token_id).clear(); - self.send() - .direct_esdt(&caller, &token_id, 0, &refund_amount); + self.total_refund_amount(&token_id) + .update(|total| *total -= &refund_amount); + self.rebalance_for_refund(&token_id, &refund_amount); + + self.tx() + .to(ToCaller) + .single_esdt(&token_id, 0, &refund_amount) + .transfer(); + self.claim_refund_transaction_event(&token_id, caller); EsdtTokenPayment::new(token_id, 0, refund_amount) } + #[only_owner] + #[endpoint(setBridgedTokensWrapperAddress)] + fn set_bridged_tokens_wrapper_contract_address( + &self, + opt_address: OptionalValue, + ) { + match opt_address { + OptionalValue::Some(sc_addr) => { + require!( + self.blockchain().is_smart_contract(&sc_addr), + "Invalid bridged tokens wrapper address" + ); + self.bridged_tokens_wrapper_address().set(&sc_addr); + } + OptionalValue::None => self.bridged_tokens_wrapper_address().clear(), + } + } + + #[only_owner] + #[endpoint(setBridgeProxyContractAddress)] + fn set_bridge_proxy_contract_address(&self, opt_new_address: OptionalValue) { + match opt_new_address { + OptionalValue::Some(sc_addr) => { + require!( + self.blockchain().is_smart_contract(&sc_addr), + "Invalid bridge proxy contract address" + ); + + self.bridge_proxy_contract_address().set(&sc_addr); + } + OptionalValue::None => self.bridge_proxy_contract_address().clear(), + } + } + + #[only_owner] + #[endpoint(withdrawRefundFeesForEthereum)] + fn withdraw_refund_fees_for_ethereum( + &self, + token_id: TokenIdentifier, + multisig_owner: ManagedAddress, + ) { + let refund_fees_for_ethereum_mapper = self.refund_fees_for_ethereum(&token_id); + require!( + !refund_fees_for_ethereum_mapper.is_empty(), + "There are no fees to withdraw" + ); + let amount_out = refund_fees_for_ethereum_mapper.get(); + self.tx() + .to(multisig_owner) + .single_esdt(&token_id, 0, &amount_out) + .transfer(); + refund_fees_for_ethereum_mapper.set(BigUint::zero()); + } + + #[only_owner] + #[endpoint(withdrawTransactionFees)] + fn withdraw_transaction_fees(&self, token_id: TokenIdentifier, multisig_owner: ManagedAddress) { + let accumulated_transaction_fees_mapper = self.accumulated_transaction_fees(&token_id); + require!( + !accumulated_transaction_fees_mapper.is_empty(), + "There are no fees to withdraw" + ); + let amount_out = accumulated_transaction_fees_mapper.get(); + self.tx() + .to(multisig_owner) + .single_esdt(&token_id, 0, &amount_out) + .transfer(); + accumulated_transaction_fees_mapper.set(BigUint::zero()); + } + + #[view(computeTotalAmmountsFromIndex)] + fn compute_total_amounts_from_index( + &self, + start_index: u64, + end_index: u64, + ) -> PaymentsVec { + let mut all_payments = PaymentsVec::new(); + for index in start_index..end_index { + let last_batch = self.pending_batches(index); + for tx in last_batch.iter() { + let new_payment = EsdtTokenPayment::new(tx.token_identifier, 0, tx.amount); + let len = all_payments.len(); + + let mut updated = false; + for i in 0..len { + let mut current_payment = all_payments.get(i); + if current_payment.token_identifier != new_payment.token_identifier { + continue; + } + + current_payment.amount += &new_payment.amount; + let _ = all_payments.set(i, ¤t_payment); + + updated = true; + break; + } + if !updated { + all_payments.push(new_payment); + } + } + } + + all_payments + } + /// Query function that lists all refund amounts for a user. /// Useful for knowing which token IDs to pass to the claimRefund endpoint. #[view(getRefundAmounts)] @@ -244,21 +516,90 @@ pub trait EsdtSafe: refund_amounts } + #[view(getTotalRefundAmounts)] + fn get_total_refund_amounts(&self) -> MultiValueEncoded> { + let mut refund_amounts = MultiValueEncoded::new(); + for token_id in self.token_whitelist().iter() { + let amount = self.total_refund_amount(&token_id).get(); + if amount > 0u32 { + refund_amounts.push((token_id, amount).into()); + } + } + + refund_amounts + } + + #[view(getRefundFeesForEthereum)] + fn get_refund_fees_for_ethereum(&self, token_id: TokenIdentifier) -> BigUint { + let refund_fees_for_ethereum_mapper = self.refund_fees_for_ethereum(&token_id); + if refund_fees_for_ethereum_mapper.is_empty() { + BigUint::zero() + } else { + refund_fees_for_ethereum_mapper.get() + } + } + + #[view(getTransactionFees)] + fn get_transaction_fees(&self, token_id: TokenIdentifier) -> BigUint { + let accumulated_transaction_fees_mapper = self.accumulated_transaction_fees(&token_id); + if accumulated_transaction_fees_mapper.is_empty() { + BigUint::zero() + } else { + accumulated_transaction_fees_mapper.get() + } + } // private - fn burn_esdt_token(&self, token_id: &TokenIdentifier, amount: &BigUint) { - self.send().esdt_local_burn(token_id, 0, amount); + fn rebalance_for_refund(&self, token_id: &TokenIdentifier, amount: &BigUint) { + let mintBurnToken = self.mint_burn_token(token_id).get(); + if !mintBurnToken { + let total_balances_mapper = self.total_balances(token_id); + total_balances_mapper.update(|total| { + *total -= amount; + }); + } else { + let mint_balances_mapper = self.mint_balances(token_id); + let mint_executed = self.internal_mint(token_id, amount); + require!(mint_executed, "Cannot do the mint action!"); + + mint_balances_mapper.update(|minted| { + *minted += amount; + }); + } } fn mark_refund(&self, to: &ManagedAddress, token_id: &TokenIdentifier, amount: &BigUint) { self.refund_amount(to, token_id) .update(|refund| *refund += amount); + self.total_refund_amount(token_id) + .update(|total| *total += amount); } // events #[event("createTransactionEvent")] - fn create_transaction_event(&self, #[indexed] batch_id: u64, #[indexed] tx_id: u64); + fn create_transaction_event( + &self, + #[indexed] batch_id: u64, + #[indexed] tx_id: u64, + #[indexed] token_id: TokenIdentifier, + #[indexed] amount: BigUint, + #[indexed] fee: BigUint, + #[indexed] sender: ManagedBuffer, + #[indexed] recipient: ManagedBuffer, + ); + + #[event("createRefundTransactionEvent")] + fn create_refund_transaction_event( + &self, + #[indexed] batch_id: u64, + #[indexed] tx_id: u64, + #[indexed] token_id: TokenIdentifier, + #[indexed] amount: BigUint, + #[indexed] fee: BigUint, + #[indexed] initial_batch_id: u64, + #[indexed] initial_tx_id: u64, + ); #[event("addRefundTransactionEvent")] fn add_refund_transaction_event( @@ -268,20 +609,45 @@ pub trait EsdtSafe: #[indexed] original_tx_id: u64, ); + #[event("claimRefundTransactionEvent")] + fn claim_refund_transaction_event( + &self, + #[indexed] token_id: &TokenIdentifier, + #[indexed] caller: ManagedAddress, + ); + #[event("setStatusEvent")] fn set_status_event( &self, #[indexed] batch_id: u64, + #[indexed] from: ManagedBuffer, + #[indexed] to: ManagedBuffer, + #[indexed] token_id: TokenIdentifier, + #[indexed] amount: BigUint, #[indexed] tx_id: u64, #[indexed] tx_status: TransactionStatus, ); // storage + #[storage_mapper("totalRefundAmount")] + fn total_refund_amount(&self, token_id: &TokenIdentifier) -> SingleValueMapper; + + #[storage_mapper("refundFeesForEthereum")] + fn refund_fees_for_ethereum(&self, token_id: &TokenIdentifier) -> SingleValueMapper; + #[storage_mapper("refundAmount")] fn refund_amount( &self, address: &ManagedAddress, token_id: &TokenIdentifier, ) -> SingleValueMapper; + + #[view(getBridgedTokensWrapperAddress)] + #[storage_mapper("bridgedTokensWrapperAddress")] + fn bridged_tokens_wrapper_address(&self) -> SingleValueMapper; + + #[view(getBridgeProxyContractAddress)] + #[storage_mapper("bridgeProxyContractAddress")] + fn bridge_proxy_contract_address(&self) -> SingleValueMapper; } diff --git a/esdt-safe/tests/esdt_safe_scenario_rs_test.rs b/esdt-safe/tests/esdt_safe_scenario_rs_test.rs new file mode 100644 index 00000000..2e9eb2d5 --- /dev/null +++ b/esdt-safe/tests/esdt_safe_scenario_rs_test.rs @@ -0,0 +1,92 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.register_contract("file:output/esdt-safe.wasm", esdt_safe::ContractBuilder); + blockchain.register_contract( + "file:../price-aggregator/multiversx-price-aggregator-sc.wasm", + multiversx_price_aggregator_sc::ContractBuilder, + ); + + blockchain +} + +#[test] +fn add_refund_batch_rs() { + world().run("scenarios/add_refund_batch.scen.json"); +} + +#[test] +fn create_another_tx_ok_rs() { + world().run("scenarios/create_another_tx_ok.scen.json"); +} + +#[test] +fn create_another_tx_too_late_for_batch_rs() { + world().run("scenarios/create_another_tx_too_late_for_batch.scen.json"); +} + +#[test] +fn create_transaction_ok_rs() { + world().run("scenarios/create_transaction_ok.scen.json"); +} + +#[test] +fn create_transaction_over_max_amount_rs() { + world().run("scenarios/create_transaction_over_max_amount.scen.json"); +} + +#[test] +fn distribute_fees_rs() { + world().run("scenarios/distribute_fees.scen.json"); +} + +#[test] +fn execute_batch_both_rejected_rs() { + world().run("scenarios/execute_batch_both_rejected.scen.json"); +} + +#[test] +fn execute_batch_both_success_rs() { + world().run("scenarios/execute_batch_both_success.scen.json"); +} + +#[test] +fn execute_batch_one_success_one_rejected_rs() { + world().run("scenarios/execute_batch_one_success_one_rejected.scen.json"); +} + +#[test] +fn execute_transaction_rejected_rs() { + world().run("scenarios/execute_transaction_rejected.scen.json"); +} + +#[test] +fn execute_transaction_success_rs() { + world().run("scenarios/execute_transaction_success.scen.json"); +} + +#[test] +fn get_next_pending_tx_rs() { + world().run("scenarios/get_next_pending_tx.scen.json"); +} + +#[test] +fn get_next_tx_batch_rs() { + world().run("scenarios/get_next_tx_batch.scen.json"); +} + +#[test] +fn get_next_tx_batch_too_early_rs() { + world().run("scenarios/get_next_tx_batch_too_early.scen.json"); +} + +#[test] +fn setup_accounts_rs() { + world().run("scenarios/setup_accounts.scen.json"); +} + +#[test] +fn zero_fees_rs() { + world().run("scenarios/zero_fees.scen.json"); +} diff --git a/esdt-safe/tests/scenario_go_test.rs b/esdt-safe/tests/scenario_go_test.rs index 205306a5..7dcd7957 100644 --- a/esdt-safe/tests/scenario_go_test.rs +++ b/esdt-safe/tests/scenario_go_test.rs @@ -1,69 +1,85 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + ScenarioWorld::vm_go() +} + #[test] -fn claim_fees_go() { - multiversx_sc_scenario::run_go("mandos/distribute_fees.scen.json"); +fn add_refund_batch_go() { + world().run("scenarios/add_refund_batch.scen.json"); } #[test] fn create_another_tx_ok_go() { - multiversx_sc_scenario::run_go("mandos/create_another_tx_ok.scen.json"); + world().run("scenarios/create_another_tx_ok.scen.json"); } #[test] fn create_another_tx_too_late_for_batch_go() { - multiversx_sc_scenario::run_go("mandos/create_another_tx_too_late_for_batch.scen.json"); + world().run("scenarios/create_another_tx_too_late_for_batch.scen.json"); } #[test] fn create_transaction_ok_go() { - multiversx_sc_scenario::run_go("mandos/create_transaction_ok.scen.json"); + world().run("scenarios/create_transaction_ok.scen.json"); +} + +#[test] +fn create_transaction_over_max_amount_go() { + world().run("scenarios/create_transaction_over_max_amount.scen.json"); +} + +#[test] +fn distribute_fees_go() { + world().run("scenarios/distribute_fees.scen.json"); } #[test] fn execute_batch_both_rejected_go() { - multiversx_sc_scenario::run_go("mandos/execute_batch_both_rejected.scen.json"); + world().run("scenarios/execute_batch_both_rejected.scen.json"); } #[test] fn execute_batch_both_success_go() { - multiversx_sc_scenario::run_go("mandos/execute_batch_both_success.scen.json"); + world().run("scenarios/execute_batch_both_success.scen.json"); } #[test] fn execute_batch_one_success_one_rejected_go() { - multiversx_sc_scenario::run_go("mandos/execute_batch_one_success_one_rejected.scen.json"); + world().run("scenarios/execute_batch_one_success_one_rejected.scen.json"); } #[test] fn execute_transaction_rejected_go() { - multiversx_sc_scenario::run_go("mandos/execute_transaction_rejected.scen.json"); + world().run("scenarios/execute_transaction_rejected.scen.json"); } #[test] fn execute_transaction_success_go() { - multiversx_sc_scenario::run_go("mandos/execute_transaction_success.scen.json"); + world().run("scenarios/execute_transaction_success.scen.json"); } #[test] fn get_next_pending_tx_go() { - multiversx_sc_scenario::run_go("mandos/get_next_pending_tx.scen.json"); + world().run("scenarios/get_next_pending_tx.scen.json"); } #[test] fn get_next_tx_batch_go() { - multiversx_sc_scenario::run_go("mandos/get_next_tx_batch.scen.json"); + world().run("scenarios/get_next_tx_batch.scen.json"); } #[test] fn get_next_tx_batch_too_early_go() { - multiversx_sc_scenario::run_go("mandos/get_next_tx_batch_too_early.scen.json"); + world().run("scenarios/get_next_tx_batch_too_early.scen.json"); } #[test] fn setup_accounts_go() { - multiversx_sc_scenario::run_go("mandos/setup_accounts.scen.json"); + world().run("scenarios/setup_accounts.scen.json"); } #[test] fn zero_fees_go() { - multiversx_sc_scenario::run_go("mandos/zero_fees.scen.json"); + world().run("scenarios/zero_fees.scen.json"); } diff --git a/esdt-safe/wasm/Cargo.lock b/esdt-safe/wasm/Cargo.lock new file mode 100644 index 00000000..4319c51d --- /dev/null +++ b/esdt-safe/wasm/Cargo.lock @@ -0,0 +1,441 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "esdt-safe" +version = "0.0.0" +dependencies = [ + "eth-address", + "fee-estimator-module", + "max-bridged-amount-module", + "multiversx-price-aggregator-sc", + "multiversx-sc", + "multiversx-sc-modules", + "token-module", + "transaction", + "tx-batch-module", +] + +[[package]] +name = "esdt-safe-wasm" +version = "0.0.0" +dependencies = [ + "esdt-safe", + "multiversx-sc-wasm-adapter", +] + +[[package]] +name = "eth-address" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "fee-estimator-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[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 = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "max-bridged-amount-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-price-aggregator-sc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea572ebab3a6addd937cad829076b13e320851503fb6adf1ad66f544b2bf100" +dependencies = [ + "arrayvec", + "getrandom", + "multiversx-sc", + "multiversx-sc-modules", + "rand", +] + +[[package]] +name = "multiversx-sc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed13aaca9cbdbc6911174cd3029e750a7563d85dd3daaa1107b1fd31c7f17245" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "token-module" +version = "0.0.0" +dependencies = [ + "fee-estimator-module", + "multiversx-sc", +] + +[[package]] +name = "transaction" +version = "0.0.0" +dependencies = [ + "eth-address", + "multiversx-sc", +] + +[[package]] +name = "tx-batch-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "transaction", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/esdt-safe/wasm/Cargo.toml b/esdt-safe/wasm/Cargo.toml index 196a688a..9b79e7d4 100644 --- a/esdt-safe/wasm/Cargo.toml +++ b/esdt-safe/wasm/Cargo.toml @@ -21,11 +21,14 @@ debug = false panic = "abort" overflow-checks = false +[profile.dev] +panic = "abort" + [dependencies.esdt-safe] path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.45.2" +version = "=0.52.3" [workspace] members = ["."] diff --git a/esdt-safe/wasm/src/lib.rs b/esdt-safe/wasm/src/lib.rs index 523d1361..9a67f5f0 100644 --- a/esdt-safe/wasm/src/lib.rs +++ b/esdt-safe/wasm/src/lib.rs @@ -5,16 +5,13 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 32 +// Upgrade: 1 +// Endpoints: 51 // Async Callback (empty): 1 -// Total number of exported functions: 34 +// Total number of exported functions: 54 #![no_std] -// Configuration that works with rustc < 1.73.0. -// TODO: Recommended rustc version: 1.73.0 or newer. -#![feature(lang_items)] - multiversx_sc_wasm_adapter::allocator!(); multiversx_sc_wasm_adapter::panic_handler!(); @@ -27,7 +24,17 @@ multiversx_sc_wasm_adapter::endpoints! { addRefundBatch => add_refund_batch createTransaction => create_transaction claimRefund => claim_refund + setBridgedTokensWrapperAddress => set_bridged_tokens_wrapper_contract_address + setBridgeProxyContractAddress => set_bridge_proxy_contract_address + withdrawRefundFeesForEthereum => withdraw_refund_fees_for_ethereum + withdrawTransactionFees => withdraw_transaction_fees + computeTotalAmmountsFromIndex => compute_total_amounts_from_index getRefundAmounts => get_refund_amounts + getTotalRefundAmounts => get_total_refund_amounts + getRefundFeesForEthereum => get_refund_fees_for_ethereum + getTransactionFees => get_transaction_fees + getBridgedTokensWrapperAddress => bridged_tokens_wrapper_address + getBridgeProxyContractAddress => bridge_proxy_contract_address setFeeEstimatorContractAddress => set_fee_estimator_contract_address setEthTxGasLimit => set_eth_tx_gas_limit setDefaultPricePerGasUnit => set_default_price_per_gas_unit @@ -39,8 +46,18 @@ multiversx_sc_wasm_adapter::endpoints! { distributeFees => distribute_fees addTokenToWhitelist => add_token_to_whitelist removeTokenFromWhitelist => remove_token_from_whitelist + getTokens => get_tokens + initSupply => init_supply + initSupplyMintBurn => init_supply_mint_burn + setMultiTransferContractAddress => set_multi_transfer_contract_address getAllKnownTokens => token_whitelist + isNativeToken => native_token + isMintBurnToken => mint_burn_token + getMultiTransferContractAddress => multi_transfer_contract_address getAccumulatedTransactionFees => accumulated_transaction_fees + getTotalBalances => total_balances + getMintBalances => mint_balances + getBurnBalances => burn_balances setMaxTxBatchSize => set_max_tx_batch_size setMaxTxBatchBlockDuration => set_max_tx_batch_block_duration getCurrentTxBatch => get_current_tx_batch diff --git a/multi-transfer-esdt/Cargo.toml b/multi-transfer-esdt/Cargo.toml index 5d50c179..e26adddc 100644 --- a/multi-transfer-esdt/Cargo.toml +++ b/multi-transfer-esdt/Cargo.toml @@ -14,14 +14,29 @@ path = "../common/transaction" [dependencies.tx-batch-module] path = "../common/tx-batch-module" +[dependencies.eth-address] +path = "../common/eth-address" + [dependencies.max-bridged-amount-module] path = "../common/max-bridged-amount-module" [dependencies.bridged-tokens-wrapper] path = "../bridged-tokens-wrapper" +[dependencies.bridge-proxy] +path = "../bridge-proxy" + +[dependencies.esdt-safe] +path = "../esdt-safe" + +[dependencies.token-module] +path = "../common/token-module" + [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" + +[dependencies.multiversx-sc-modules] +version = "=0.52.3" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/multi-transfer-esdt/README.md b/multi-transfer-esdt/README.md index 821c7653..9a3c4fb6 100644 --- a/multi-transfer-esdt/README.md +++ b/multi-transfer-esdt/README.md @@ -19,11 +19,11 @@ python3 ./interaction/playground.py --pem=./testnet/wallets/users/alice.pem --pr Deploy & interact with contract: ``` -python3 ./interaction/playground.py --pem=my.pem --proxy=https://testnet-gateway.elrond.com +python3 ./interaction/playground.py --pem=my.pem --proxy=https://testnet-gateway.multiversx.com ``` Interact with existing contract: ``` -python3 ./interaction/playground.py --pem=my.pem --proxy=https://testnet-gateway.elrond.com --contract=erd1... +python3 ./interaction/playground.py --pem=my.pem --proxy=https://testnet-gateway.multiversx.com --contract=erd1... ``` diff --git a/multi-transfer-esdt/interaction/snippets.sh b/multi-transfer-esdt/interaction/snippets.sh index 32996d89..d387f47b 100644 --- a/multi-transfer-esdt/interaction/snippets.sh +++ b/multi-transfer-esdt/interaction/snippets.sh @@ -1,8 +1,8 @@ -ALICE="/home/elrond/elrond-sdk/mxpy/testnet/wallets/users/alice.pem" -BOB="/home/elrond/elrond-sdk/mxpy/testnet/wallets/users/bob.pem" +ALICE="/home/multiversx/multiversx-sdk/mxpy/testnet/wallets/users/alice.pem" +BOB="/home/multiversx/multiversx-sdk/mxpy/testnet/wallets/users/bob.pem" ADDRESS=$(mxpy data load --key=address-testnet-multi-transfer-esdt) DEPLOY_TRANSACTION=$(mxpy data load --key=deployTransaction-testnet) -PROXY=https://testnet-gateway.elrond.com +PROXY=https://testnet-gateway.multiversx.com CHAIN_ID=T ALICE_ADDRESS=0x0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1 diff --git a/multi-transfer-esdt/mandos/batch_transfer_with_wrapping.scen.json b/multi-transfer-esdt/mandos/batch_transfer_with_wrapping.scen.json deleted file mode 100644 index 07bb451c..00000000 --- a/multi-transfer-esdt/mandos/batch_transfer_with_wrapping.scen.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "name": "batch transfer both executed", - "steps": [ - { - "step": "externalSteps", - "path": "../../bridged-tokens-wrapper/mandos/whitelist_token.scen.json" - }, - { - "step": "setState", - "accounts": { - "address:owner": { - "nonce": "0", - "balance": "0", - "storage": {} - }, - "address:user1": { - "nonce": "0", - "balance": "0", - "storage": {} - }, - "address:user2": { - "nonce": "0", - "balance": "0", - "storage": {} - } - }, - "newAddresses": [ - { - "creatorAddress": "address:owner", - "creatorNonce": "0", - "newAddress": "sc:multi_transfer_esdt" - } - ] - }, - { - "step": "scDeploy", - "txId": "deploy", - "tx": { - "from": "address:owner", - "contractCode": "file:../output/multi-transfer-esdt.wasm", - "value": "0", - "arguments": [], - "gasLimit": "20,000,000", - "gasPrice": "0" - }, - "expect": { - "status": "0", - "message": "", - "gas": "*", - "refund": "*" - } - }, - { - "step": "setState", - "comment": "setting local mint role", - "accounts": { - "sc:multi_transfer_esdt": { - "nonce": "0", - "balance": "0", - "esdt": { - "str:BRIDGE-123456": { - "balance": "0", - "roles": [ - "ESDTRoleLocalMint" - ] - }, - "str:USDC-aaaaaa": { - "balance": "0", - "roles": [ - "ESDTRoleLocalMint" - ] - }, - "str:USDC-cccccc": { - "balance": "0", - "roles": [ - "ESDTRoleLocalMint" - ] - } - }, - "storage": { - "str:maxTxBatchSize": "10", - "str:maxTxBatchBlockDuration": "3,600", - "str:firstBatchId": "1", - "str:lastBatchId": "1", - "str:wrappingContractAddress": "sc:bridged_tokens_wrapper" - }, - "code": "file:../output/multi-transfer-esdt.wasm", - "owner": "address:owner" - } - } - }, - { - "step": "scCall", - "txId": "batch-transfer-both-executed", - "tx": { - "from": "address:owner", - "to": "sc:multi_transfer_esdt", - "value": "0", - "function": "batchTransferEsdtToken", - "arguments": [ - "1", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1", - "0x0102030405060708091011121314151617181920|address:user2|nested:str:USDC-aaaaaa|biguint:500|u64:2", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:USDC-cccccc|biguint:1000|u64:3" - ], - "gasLimit": "50,000,000", - "gasPrice": "0" - }, - "expect": { - "status": "0", - "message": "", - "out": "*", - "gas": "*", - "refund": "*" - } - }, - { - "step": "checkState", - "accounts": { - "address:user1": { - "nonce": "0", - "balance": "0", - "esdt": { - "str:BRIDGE-123456": "100,200", - "str:WUSDC-abcdef": "1,000" - }, - "storage": {} - }, - "address:user2": { - "nonce": "0", - "balance": "0", - "esdt": { - "str:WUSDC-abcdef": "500" - }, - "storage": {} - }, - "sc:bridged_tokens_wrapper": { - "nonce": "0", - "esdt": { - "str:WUSDC-abcdef": { - "balance": "1", - "roles": [ - "ESDTRoleLocalMint", - "ESDTRoleLocalBurn" - ] - }, - "str:WUSDC-uvwxyz": { - "balance": "1", - "roles": [ - "ESDTRoleLocalMint", - "ESDTRoleLocalBurn" - ] - }, - "str:USDC-aaaaaa": "500", - "str:USDC-cccccc": "1,000" - }, - "storage": "*", - "code": "*" - }, - "+": {} - } - } - ] -} diff --git a/multi-transfer-esdt/mandos/setup_accounts.scen.json b/multi-transfer-esdt/mandos/setup_accounts.scen.json deleted file mode 100644 index 37240de8..00000000 --- a/multi-transfer-esdt/mandos/setup_accounts.scen.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "name": "setup accounts", - "steps": [ - { - "step": "setState", - "accounts": { - "address:owner": { - "nonce": "0", - "balance": "0", - "storage": {} - }, - "address:user1": { - "nonce": "0", - "balance": "0", - "storage": {} - }, - "address:user2": { - "nonce": "0", - "balance": "0", - "storage": {} - } - }, - "newAddresses": [ - { - "creatorAddress": "address:owner", - "creatorNonce": "0", - "newAddress": "sc:multi_transfer_esdt" - } - ] - }, - { - "step": "scDeploy", - "txId": "deploy", - "tx": { - "from": "address:owner", - "contractCode": "file:../output/multi-transfer-esdt.wasm", - "value": "0", - "arguments": [], - "gasLimit": "20,000,000", - "gasPrice": "0" - }, - "expect": { - "status": "0", - "message": "", - "gas": "*", - "refund": "*" - } - }, - { - "step": "setState", - "comment": "setting local mint role", - "accounts": { - "sc:multi_transfer_esdt": { - "nonce": "0", - "balance": "0", - "esdt": { - "str:BRIDGE-123456": { - "balance": "0", - "roles": [ - "ESDTRoleLocalMint" - ] - }, - "str:WRAPPED-123456": { - "balance": "0", - "roles": [ - "ESDTRoleLocalMint" - ] - } - }, - "storage": { - "str:maxTxBatchSize": "10", - "str:maxTxBatchBlockDuration": "3,600", - "str:firstBatchId": "1", - "str:lastBatchId": "1" - }, - "code": "file:../output/multi-transfer-esdt.wasm", - "owner": "address:owner" - } - } - } - ] -} diff --git a/multi-transfer-esdt/meta/Cargo.toml b/multi-transfer-esdt/meta/Cargo.toml index 7582654f..83265f9e 100644 --- a/multi-transfer-esdt/meta/Cargo.toml +++ b/multi-transfer-esdt/meta/Cargo.toml @@ -10,6 +10,6 @@ publish = false [dependencies.multi-transfer-esdt] path = ".." -[dependencies.multiversx-sc-meta] -version = "0.45.2" +[dependencies.multiversx-sc-meta-lib] +version = "=0.52.3" default-features = false diff --git a/multi-transfer-esdt/meta/src/main.rs b/multi-transfer-esdt/meta/src/main.rs index 224a78da..231a4072 100644 --- a/multi-transfer-esdt/meta/src/main.rs +++ b/multi-transfer-esdt/meta/src/main.rs @@ -1,3 +1,3 @@ fn main() { - multiversx_sc_meta::cli_main::(); + multiversx_sc_meta_lib::cli_main::(); } diff --git a/multi-transfer-esdt/sc-config.toml b/multi-transfer-esdt/sc-config.toml new file mode 100644 index 00000000..1a13bc1b --- /dev/null +++ b/multi-transfer-esdt/sc-config.toml @@ -0,0 +1,4 @@ +[settings] + +[[proxy]] +path = "../multisig/src/multi_transfer_esdt_proxy.rs" diff --git a/multi-transfer-esdt/mandos/batch_transfer_both_executed.scen.json b/multi-transfer-esdt/scenarios/batch_transfer_both_executed.scen.json similarity index 62% rename from multi-transfer-esdt/mandos/batch_transfer_both_executed.scen.json rename to multi-transfer-esdt/scenarios/batch_transfer_both_executed.scen.json index e64ad857..231a7622 100644 --- a/multi-transfer-esdt/mandos/batch_transfer_both_executed.scen.json +++ b/multi-transfer-esdt/scenarios/batch_transfer_both_executed.scen.json @@ -15,8 +15,22 @@ "function": "batchTransferEsdtToken", "arguments": [ "1", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1", - "0x0102030405060708091011121314151617181920|address:user2|nested:str:WRAPPED-123456|biguint:500|u64:2" + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user1", + "3-token_id": "nested:str:BRIDGE-123456", + "4-amount": "biguint:100,200", + "5-tx_nonce": "u64:1", + "6-call_data": "nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" + }, + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user2", + "3-token_id": "nested:str:WRAPPED-123456", + "4-amount": "biguint:500", + "5-tx_nonce": "u64:2", + "6-call_data": "nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" + } ], "gasLimit": "50,000,000", "gasPrice": "0" diff --git a/multi-transfer-esdt/mandos/batch_transfer_both_failed.scen.json b/multi-transfer-esdt/scenarios/batch_transfer_both_failed.scen.json similarity index 66% rename from multi-transfer-esdt/mandos/batch_transfer_both_failed.scen.json rename to multi-transfer-esdt/scenarios/batch_transfer_both_failed.scen.json index a9b34ac0..8b6a3681 100644 --- a/multi-transfer-esdt/mandos/batch_transfer_both_failed.scen.json +++ b/multi-transfer-esdt/scenarios/batch_transfer_both_failed.scen.json @@ -15,8 +15,8 @@ "function": "batchTransferEsdtToken", "arguments": [ "1", - "0x0102030405060708091011121314151617181920|sc:multi_transfer_esdt|nested:str:BRIDGE-123456|biguint:100,200|u64:1", - "0x0102030405060708091011121314151617181920|sc:multi_transfer_esdt|nested:str:WRAPPED-123456|biguint:100,500|u64:2" + "0x0102030405060708091011121314151617181920|sc:multi_transfer_esdt|nested:str:BRIDGE-123456|biguint:100,200|u64:1|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5", + "0x0102030405060708091011121314151617181920|sc:multi_transfer_esdt|nested:str:WRAPPED-123456|biguint:100,500|u64:2|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -38,23 +38,7 @@ "arguments": [] }, "expect": { - "out": [ - "1", - - "0", - "1", - "0x0102030405060708091011121314151617181920", - "sc:multi_transfer_esdt", - "str:BRIDGE-123456", - "100,200", - - "0", - "2", - "0x0102030405060708091011121314151617181920", - "sc:multi_transfer_esdt", - "str:WRAPPED-123456", - "100,500" - ] + "out": [] } }, { @@ -64,7 +48,7 @@ "from": "address:owner", "to": "sc:multi_transfer_esdt", "value": "0", - "function": "getAndClearFirstRefundBatch", + "function": "moveRefundBatchToSafe", "arguments": [], "gasLimit": "50,000,000", "gasPrice": "0" @@ -72,23 +56,7 @@ "expect": { "status": "0", "message": "", - "out": [ - "1", - - "0", - "1", - "0x0102030405060708091011121314151617181920", - "sc:multi_transfer_esdt", - "str:BRIDGE-123456", - "100,200", - - "0", - "2", - "0x0102030405060708091011121314151617181920", - "sc:multi_transfer_esdt", - "str:WRAPPED-123456", - "100,500" - ], + "out": [], "gas": "*", "refund": "*" } diff --git a/multi-transfer-esdt/mandos/batch_transfer_one_executed_one_failed.scen.json b/multi-transfer-esdt/scenarios/batch_transfer_one_executed_one_failed.scen.json similarity index 82% rename from multi-transfer-esdt/mandos/batch_transfer_one_executed_one_failed.scen.json rename to multi-transfer-esdt/scenarios/batch_transfer_one_executed_one_failed.scen.json index 7ee4cb31..fd2fc560 100644 --- a/multi-transfer-esdt/mandos/batch_transfer_one_executed_one_failed.scen.json +++ b/multi-transfer-esdt/scenarios/batch_transfer_one_executed_one_failed.scen.json @@ -15,8 +15,8 @@ "function": "batchTransferEsdtToken", "arguments": [ "1", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1", - "0x0102030405060708091011121314151617181920|sc:multi_transfer_esdt|nested:str:WRAPPED-123456|biguint:500|u64:2" + "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5", + "0x0102030405060708091011121314151617181920|sc:multi_transfer_esdt|nested:str:WRAPPED-123456|biguint:500|u64:2|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -52,16 +52,7 @@ "arguments": [] }, "expect": { - "out": [ - "1", - - "0", - "2", - "0x0102030405060708091011121314151617181920", - "sc:multi_transfer_esdt", - "str:WRAPPED-123456", - "500" - ] + "out": [] } } ] diff --git a/multi-transfer-esdt/mandos/batch_transfer_to_frozen_account.scen.json b/multi-transfer-esdt/scenarios/batch_transfer_to_frozen_account.scen.json similarity index 91% rename from multi-transfer-esdt/mandos/batch_transfer_to_frozen_account.scen.json rename to multi-transfer-esdt/scenarios/batch_transfer_to_frozen_account.scen.json index 53ffbc12..7b876d5c 100644 --- a/multi-transfer-esdt/mandos/batch_transfer_to_frozen_account.scen.json +++ b/multi-transfer-esdt/scenarios/batch_transfer_to_frozen_account.scen.json @@ -35,8 +35,8 @@ "function": "batchTransferEsdtToken", "arguments": [ "1", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1", - "0x0102030405060708091011121314151617181920|address:frozen_user|nested:str:BRIDGE-123456|biguint:500|u64:2" + "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5", + "0x0102030405060708091011121314151617181920|address:frozen_user|nested:str:BRIDGE-123456|biguint:500|u64:2|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -84,4 +84,4 @@ } } ] -} \ No newline at end of file +} diff --git a/multi-transfer-esdt/scenarios/batch_transfer_with_wrapping.scen.json b/multi-transfer-esdt/scenarios/batch_transfer_with_wrapping.scen.json new file mode 100644 index 00000000..be25c9fa --- /dev/null +++ b/multi-transfer-esdt/scenarios/batch_transfer_with_wrapping.scen.json @@ -0,0 +1,298 @@ +{ + "name": "batch transfer both executed", + "steps": [ + { + "step": "externalSteps", + "path": "../../bridged-tokens-wrapper/scenarios/whitelist_token.scen.json" + }, + { + "step": "setState", + "accounts": { + "address:owner": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "address:user1": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "address:user2": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "sc:esdt-safe": { + "nonce": "0", + "esdt": { + "str:BRIDGE-123456": { + "balance": "2,000,000", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + }, + "str:USDC-aaaaaa": { + "balance": "2,000,000", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + }, + "str:USDC-cccccc": { + "balance": "2,000,000", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + } + }, + "code": "file:../../esdt-safe/output/esdt-safe.wasm", + "owner": "address:owner" + } + }, + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "0", + "newAddress": "sc:multi_transfer_esdt" + } + ] + }, + { + "step": "scDeploy", + "txId": "deploy", + "tx": { + "from": "address:owner", + "contractCode": "file:../output/multi-transfer-esdt.wasm", + "value": "0", + "arguments": [], + "gasLimit": "20,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "setState", + "comment": "setting local mint role", + "accounts": { + "sc:multi_transfer_esdt": { + "nonce": "0", + "balance": "0", + "storage": { + "str:maxTxBatchSize": "10", + "str:maxTxBatchBlockDuration": "3,600", + "str:firstBatchId": "1", + "str:lastBatchId": "1", + "str:wrappingContractAddress": "sc:bridged_tokens_wrapper", + "str:bridgeProxyContractAddress": "sc:bridge-proxy" + }, + "code": "file:../output/multi-transfer-esdt.wasm", + "owner": "address:owner" + } + } + }, + { + "step": "scCall", + "txId": "add-token-1", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "value": "0", + "function": "addTokenToWhitelist", + "arguments": [ + "str:BRIDGE-123456", + "str:BRIDGE", + "true", + "false", + "0", + "0", + "0", + "2,000,000" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-token-1", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "value": "0", + "function": "addTokenToWhitelist", + "arguments": [ + "str:USDC-aaaaaa", + "str:USDC", + "true", + "false", + "0", + "0", + "0", + "2,000,000" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-token-1", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "value": "0", + "function": "addTokenToWhitelist", + "arguments": [ + "str:USDC-cccccc", + "str:USDC", + "true", + "false", + "0", + "0", + "0", + "2,000,000" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "set-multi-transfer-contract-address", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "value": "0", + "function": "setMultiTransferContractAddress", + "arguments": [ + "sc:multi_transfer_esdt" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-bridge-proxy-to-multi-transfer", + "tx": { + "from": "address:owner", + "to": "sc:multi_transfer_esdt", + "function": "setEsdtSafeContractAddress", + "arguments": [ + "sc:esdt-safe" + ], + "gasLimit": "5,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "batch-transfer-both-executed", + "tx": { + "from": "address:owner", + "to": "sc:multi_transfer_esdt", + "value": "0", + "function": "batchTransferEsdtToken", + "arguments": [ + "1", + "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5", + "0x0102030405060708091011121314151617181920|address:user2|nested:str:USDC-aaaaaa|biguint:500,000,000,000,000|u64:2|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5", + "0x0102030405060708091011121314151617181920|address:user1|nested:str:USDC-cccccc|biguint:1,000,000,000,000,000|u64:3|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "out": "*", + "gas": "*", + "refund": "*" + } + }, + { + "step": "checkState", + "accounts": { + "address:user1": { + "nonce": "0", + "balance": "0", + "esdt": { + "str:BRIDGE-123456": "100,200", + "str:WUSDC-abcdef": "1,000" + }, + "storage": {} + }, + "address:user2": { + "nonce": "0", + "balance": "0", + "esdt": { + "str:WUSDC-abcdef": "500" + }, + "storage": {} + }, + "sc:bridged_tokens_wrapper": { + "nonce": "0", + "esdt": { + "str:WUSDC-abcdef": { + "balance": "1", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + }, + "str:WUSDC-uvwxyz": { + "balance": "1", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + }, + "str:USDC-aaaaaa": "500,000,000,000,000", + "str:USDC-cccccc": "1,000,000,000,000,000" + }, + "storage": "*", + "code": "*" + }, + "+": {} + } + } + ] +} diff --git a/multi-transfer-esdt/scenarios/setup_accounts.scen.json b/multi-transfer-esdt/scenarios/setup_accounts.scen.json new file mode 100644 index 00000000..807472e6 --- /dev/null +++ b/multi-transfer-esdt/scenarios/setup_accounts.scen.json @@ -0,0 +1,331 @@ +{ + "name": "setup accounts", + "steps": [ + { + "step": "setState", + "accounts": { + "address:owner": { + "nonce": "0", + "balance": "0", + "esdt": { + "str:BRIDGE-123456": { + "balance": "10,000,000" + } + }, + "storage": {} + }, + "address:user1": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "address:user2": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "sc:esdt-safe": { + "nonce": "0", + "esdt": { + "str:BRIDGE-123456": { + "balance": "1,000,000", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + }, + "str:WRAPPED-123456": { + "balance": "1,000,000", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + } + }, + "storage": { + "str:feeEstimatorContractAddress": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "code": "file:../../esdt-safe/output/esdt-safe.wasm", + "owner": "address:owner" + } + }, + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "0", + "newAddress": "sc:multi_transfer_esdt" + }, + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:bridge-proxy" + }, + { + "creatorAddress": "address:owner", + "creatorNonce": "2", + "newAddress": "sc:esdt-safe" + } + ] + }, + { + "step": "scDeploy", + "txId": "deploy", + "tx": { + "from": "address:owner", + "contractCode": "file:../output/multi-transfer-esdt.wasm", + "value": "0", + "arguments": [], + "gasLimit": "20,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scDeploy", + "txId": "deploy-bridge-proxy", + "tx": { + "from": "address:owner", + "contractCode": "file:../../bridge-proxy/output/bridge-proxy.wasm", + "value": "0", + "arguments": [ + "sc:multi_transfer_esdt" + ], + "gasLimit": "20,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-bridge-proxy-to-multi-transfer", + "tx": { + "from": "address:owner", + "to": "sc:multi_transfer_esdt", + "function": "setBridgeProxyContractAddress", + "arguments": [ + "sc:bridge-proxy" + ], + "gasLimit": "5,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-token-1", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "value": "0", + "function": "addTokenToWhitelist", + "arguments": [ + "str:BRIDGE-123456", + "str:BRIDGE", + "true", + "false", + "0", + "0", + "0", + "150,000" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-token-1", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "value": "0", + "function": "addTokenToWhitelist", + "arguments": [ + "str:WRAPPED-123456", + "str:WRAPPED", + "true", + "false", + "0", + "0", + "0", + "1,000" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "set-multi-transfer-contract-address", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "value": "0", + "function": "setMultiTransferContractAddress", + "arguments": [ + "sc:multi_transfer_esdt" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-bridge-proxy-to-multi-transfer", + "tx": { + "from": "address:owner", + "to": "sc:multi_transfer_esdt", + "function": "setEsdtSafeContractAddress", + "arguments": [ + "sc:esdt-safe" + ], + "gasLimit": "5,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "checkState", + "accounts": { + "address:owner": { + "nonce": "7", + "balance": "0", + "esdt": { + "str:BRIDGE-123456": { + "balance": "10,000,000" + } + }, + "storage": {} + }, + "address:user1": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "address:user2": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "sc:multi_transfer_esdt": { + "code": "file:../output/multi-transfer-esdt.wasm", + "nonce": "0", + "balance": "0", + "storage": { + "str:firstBatchId": "1", + "str:lastBatchId": "1", + "str:bridgeProxyContractAddress": "sc:bridge-proxy", + "str:maxTxBatchSize": "10", + "str:maxTxBatchBlockDuration": "0xffffffffffffffff", + "str:esdtSafeContractAddress": "sc:esdt-safe" + } + }, + "sc:bridge-proxy": { + "code": "file:../../bridge-proxy/output/bridge-proxy.wasm", + "nonce": "0", + "balance": "0", + "storage": "*" + }, + "sc:esdt-safe": { + "code": "file:../../esdt-safe/output/esdt-safe.wasm", + "nonce": "0", + "balance": "0", + "esdt": { + "str:BRIDGE-123456": { + "balance": "1,000,000", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + }, + "str:WRAPPED-123456": { + "balance": "1,000,000", + "roles": [ + "ESDTRoleLocalMint", + "ESDTRoleLocalBurn" + ] + } + }, + "storage": "*" + } + } + }, + { + "step": "setState", + "comment": "setting local mint role", + "accounts": { + "sc:multi_transfer_esdt": { + "nonce": "0", + "balance": "0", + "storage": { + "str:maxTxBatchSize": "10", + "str:maxTxBatchBlockDuration": "3,600", + "str:firstBatchId": "1", + "str:lastBatchId": "1", + "str:bridgeProxyContractAddress": "sc:bridge-proxy", + "str:esdtSafeContractAddress": "sc:esdt-safe" + }, + "code": "file:../output/multi-transfer-esdt.wasm", + "owner": "address:owner" + } + } + }, + { + "step": "scCall", + "txId": "unpause", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "unpause", + "arguments": [], + "gasLimit": "100,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "out": [], + "message": "", + "gas": "*", + "refund": "*" + } + } + ] +} diff --git a/price-aggregator/mandos/oracle_submit.scen.json b/multi-transfer-esdt/scenarios/transfer_fail_mint_burn_not_allowed.scen.json similarity index 54% rename from price-aggregator/mandos/oracle_submit.scen.json rename to multi-transfer-esdt/scenarios/transfer_fail_mint_burn_not_allowed.scen.json index 02dd2172..107328ff 100644 --- a/price-aggregator/mandos/oracle_submit.scen.json +++ b/multi-transfer-esdt/scenarios/transfer_fail_mint_burn_not_allowed.scen.json @@ -1,24 +1,22 @@ { - "name": "oracle submit", + "name": "transfer ok", "steps": [ { "step": "externalSteps", - "path": "deploy.scen.json" + "path": "setup_accounts.scen.json" }, { "step": "scCall", - "txId": "oracle-submit", + "txId": "remove-token", "tx": { - "from": "address:oracle", - "to": "sc:price_aggregator", + "from": "address:owner", + "to": "sc:esdt-safe", "value": "0", - "function": "submit", + "function": "removeTokenFromWhitelist", "arguments": [ - "str:GWEI", - "str:BRIDGE", - "10" + "str:BRIDGE-123456" ], - "gasLimit": "40,000,000", + "gasLimit": "50,000,000", "gasPrice": "0" }, "expect": { diff --git a/multi-transfer-esdt/mandos/transfer_ok.scen.json b/multi-transfer-esdt/scenarios/transfer_ok.scen.json similarity index 91% rename from multi-transfer-esdt/mandos/transfer_ok.scen.json rename to multi-transfer-esdt/scenarios/transfer_ok.scen.json index 85911b69..d8daf4e7 100644 --- a/multi-transfer-esdt/mandos/transfer_ok.scen.json +++ b/multi-transfer-esdt/scenarios/transfer_ok.scen.json @@ -15,7 +15,7 @@ "function": "batchTransferEsdtToken", "arguments": [ "1", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1" + "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" ], "gasLimit": "50,000,000", "gasPrice": "0" diff --git a/multi-transfer-esdt/mandos/two_transfers_same_token.scen.json b/multi-transfer-esdt/scenarios/two_transfers_same_token.scen.json similarity index 85% rename from multi-transfer-esdt/mandos/two_transfers_same_token.scen.json rename to multi-transfer-esdt/scenarios/two_transfers_same_token.scen.json index 4799f41f..17b9d4ac 100644 --- a/multi-transfer-esdt/mandos/two_transfers_same_token.scen.json +++ b/multi-transfer-esdt/scenarios/two_transfers_same_token.scen.json @@ -15,8 +15,8 @@ "function": "batchTransferEsdtToken", "arguments": [ "1", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1", - "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:2" + "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:1|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5", + "0x0102030405060708091011121314151617181920|address:user1|nested:str:BRIDGE-123456|biguint:100,200|u64:2|nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" ], "gasLimit": "50,000,000", "gasPrice": "0" diff --git a/multi-transfer-esdt/src/bridge_proxy_contract_proxy.rs b/multi-transfer-esdt/src/bridge_proxy_contract_proxy.rs new file mode 100644 index 00000000..3cb21d18 --- /dev/null +++ b/multi-transfer-esdt/src/bridge_proxy_contract_proxy.rs @@ -0,0 +1,239 @@ +// 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 BridgeProxyContractProxy; + +impl TxProxyTrait for BridgeProxyContractProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = BridgeProxyContractProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + BridgeProxyContractProxyMethods { wrapped_tx: tx } + } +} + +pub struct BridgeProxyContractProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + opt_multi_transfer_address: Arg0, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&opt_multi_transfer_address) + .original_result() + } +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn deposit< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + eth_tx: Arg0, + batch_id: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("deposit") + .argument(ð_tx) + .argument(&batch_id) + .original_result() + } + + pub fn execute< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("execute") + .argument(&tx_id) + .original_result() + } + + pub fn get_pending_transaction_by_id< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPendingTransactionById") + .argument(&tx_id) + .original_result() + } + + pub fn get_pending_transactions( + self, + ) -> TxTypedCall>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPendingTransactions") + .original_result() + } + + pub fn set_multi_transfer_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_multi_transfer_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferAddress") + .argument(&opt_multi_transfer_address) + .original_result() + } + + pub fn set_bridged_tokens_wrapper_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgedTokensWrapperAddress") + .argument(&opt_address) + .original_result() + } + + pub fn set_esdt_safe_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEsdtSafeAddress") + .argument(&opt_address) + .original_result() + } + + pub fn multi_transfer_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferAddress") + .original_result() + } + + pub fn bridged_tokens_wrapper_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgedTokensWrapperAddress") + .original_result() + } + + pub fn esdt_safe_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEsdtSafeContractAddress") + .original_result() + } + + pub fn highest_tx_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("highestTxId") + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} diff --git a/multi-transfer-esdt/src/bridged_tokens_wrapper_proxy.rs b/multi-transfer-esdt/src/bridged_tokens_wrapper_proxy.rs new file mode 100644 index 00000000..ac306e11 --- /dev/null +++ b/multi-transfer-esdt/src/bridged_tokens_wrapper_proxy.rs @@ -0,0 +1,298 @@ +// 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 BridgedTokensWrapperProxy; + +impl TxProxyTrait for BridgedTokensWrapperProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = BridgedTokensWrapperProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + BridgedTokensWrapperProxyMethods { wrapped_tx: tx } + } +} + +pub struct BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn add_wrapped_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + universal_bridged_token_ids: Arg0, + num_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addWrappedToken") + .argument(&universal_bridged_token_ids) + .argument(&num_decimals) + .original_result() + } + + pub fn update_wrapped_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + universal_bridged_token_ids: Arg0, + num_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateWrappedToken") + .argument(&universal_bridged_token_ids) + .argument(&num_decimals) + .original_result() + } + + pub fn remove_wrapped_token< + Arg0: ProxyArg>, + >( + self, + universal_bridged_token_ids: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeWrappedToken") + .argument(&universal_bridged_token_ids) + .original_result() + } + + pub fn whitelist_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + chain_specific_token_id: Arg0, + chain_specific_token_decimals: Arg1, + universal_bridged_token_ids: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("whitelistToken") + .argument(&chain_specific_token_id) + .argument(&chain_specific_token_decimals) + .argument(&universal_bridged_token_ids) + .original_result() + } + + pub fn update_whitelisted_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + chain_specific_token_id: Arg0, + chain_specific_token_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateWhitelistedToken") + .argument(&chain_specific_token_id) + .argument(&chain_specific_token_decimals) + .original_result() + } + + pub fn blacklist_token< + Arg0: ProxyArg>, + >( + self, + chain_specific_token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("blacklistToken") + .argument(&chain_specific_token_id) + .original_result() + } + + pub fn deposit_liquidity( + self, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("depositLiquidity") + .original_result() + } + + /// Will wrap what it can, and send back the rest unchanged + pub fn wrap_tokens( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .raw_call("wrapTokens") + .original_result() + } + + pub fn unwrap_token< + Arg0: ProxyArg>, + >( + self, + requested_token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("unwrapToken") + .argument(&requested_token) + .original_result() + } + + pub fn unwrap_token_create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + requested_token: Arg0, + safe_address: Arg1, + to: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("unwrapTokenCreateTransaction") + .argument(&requested_token) + .argument(&safe_address) + .argument(&to) + .original_result() + } + + pub fn universal_bridged_token_ids( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getUniversalBridgedTokenIds") + .original_result() + } + + pub fn token_liquidity< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokenLiquidity") + .argument(&token) + .original_result() + } + + pub fn chain_specific_to_universal_mapping< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getChainSpecificToUniversalMapping") + .argument(&token) + .original_result() + } + + pub fn chain_specific_token_ids< + Arg0: ProxyArg>, + >( + self, + universal_token_id: Arg0, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getchainSpecificTokenIds") + .argument(&universal_token_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} diff --git a/multi-transfer-esdt/src/esdt_safe_proxy.rs b/multi-transfer-esdt/src/esdt_safe_proxy.rs new file mode 100644 index 00000000..3832da69 --- /dev/null +++ b/multi-transfer-esdt/src/esdt_safe_proxy.rs @@ -0,0 +1,810 @@ +// 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 EsdtSafeProxy; + +impl TxProxyTrait for EsdtSafeProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = EsdtSafeProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + EsdtSafeProxyMethods { wrapped_tx: tx } + } +} + +pub struct EsdtSafeProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + /// fee_estimator_contract_address - The address of a Price Aggregator contract, + /// which will get the price of token A in token B + /// + /// eth_tx_gas_limit - The gas limit that will be used for transactions on the ETH side. + /// Will be used to compute the fees for the transfer + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + eth_tx_gas_limit: Arg2, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + bridge_proxy_contract_address: Arg2, + eth_tx_gas_limit: Arg3, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(&bridge_proxy_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Sets the statuses for the transactions, after they were executed on the Ethereum side. + /// + /// Only TransactionStatus::Executed (3) and TransactionStatus::Rejected (4) values are allowed. + /// Number of provided statuses must be equal to number of transactions in the batch. + pub fn set_transaction_batch_status< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + batch_id: Arg0, + tx_statuses: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTransactionBatchStatus") + .argument(&batch_id) + .argument(&tx_statuses) + .original_result() + } + + /// Converts failed Ethereum -> MultiversX transactions to MultiversX -> Ethereum transaction. + /// This is done every now and then to refund the tokens. + /// + /// As with normal MultiversX -> Ethereum transactions, a part of the tokens will be + /// subtracted to pay for the fees + pub fn add_refund_batch< + Arg0: ProxyArg>>, + >( + self, + refund_transactions: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addRefundBatch") + .argument(&refund_transactions) + .original_result() + } + + /// Create an MultiversX -> Ethereum transaction. Only fungible tokens are accepted. + /// + /// Every transfer will have a part of the tokens subtracted as fees. + /// The fee amount depends on the global eth_tx_gas_limit + /// and the current GWEI price, respective to the bridged token + /// + /// fee_amount = price_per_gas_unit * eth_tx_gas_limit + pub fn create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + opt_refund_info: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("createTransaction") + .argument(&to) + .argument(&opt_refund_info) + .original_result() + } + + /// Claim funds for failed MultiversX -> Ethereum transactions. + /// These are not sent automatically to prevent the contract getting stuck. + /// For example, if the receiver is a SC, a frozen account, etc. + pub fn claim_refund< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("claimRefund") + .argument(&token_id) + .original_result() + } + + pub fn set_bridged_tokens_wrapper_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgedTokensWrapperAddress") + .argument(&opt_address) + .original_result() + } + + pub fn set_bridge_proxy_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgeProxyContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn withdraw_refund_fees_for_ethereum< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawRefundFeesForEthereum") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn withdraw_transaction_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawTransactionFees") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn compute_total_amounts_from_index< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + start_index: Arg0, + end_index: Arg1, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("computeTotalAmmountsFromIndex") + .argument(&start_index) + .argument(&end_index) + .original_result() + } + + /// Query function that lists all refund amounts for a user. + /// Useful for knowing which token IDs to pass to the claimRefund endpoint. + pub fn get_refund_amounts< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundAmounts") + .argument(&address) + .original_result() + } + + pub fn get_total_refund_amounts( + self, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalRefundAmounts") + .original_result() + } + + pub fn get_refund_fees_for_ethereum< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundFeesForEthereum") + .argument(&token_id) + .original_result() + } + + pub fn get_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn bridged_tokens_wrapper_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgedTokensWrapperAddress") + .original_result() + } + + pub fn bridge_proxy_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgeProxyContractAddress") + .original_result() + } + + pub fn set_fee_estimator_contract_address< + Arg0: ProxyArg>, + >( + self, + new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setFeeEstimatorContractAddress") + .argument(&new_address) + .original_result() + } + + pub fn set_eth_tx_gas_limit< + Arg0: ProxyArg>, + >( + self, + new_limit: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEthTxGasLimit") + .argument(&new_limit) + .original_result() + } + + /// Default price being used if the aggregator lacks a mapping for this token + /// or the aggregator address is not set + pub fn set_default_price_per_gas_unit< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + default_price_per_gas_unit: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setDefaultPricePerGasUnit") + .argument(&token_id) + .argument(&default_price_per_gas_unit) + .original_result() + } + + /// Token ticker being used when querying the aggregator for GWEI prices + pub fn set_token_ticker< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + ticker: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTokenTicker") + .argument(&token_id) + .argument(&ticker) + .original_result() + } + + /// Returns the fee for the given token ID (the fee amount is in the given token) + pub fn calculate_required_fee< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("calculateRequiredFee") + .argument(&token_id) + .original_result() + } + + pub fn fee_estimator_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeEstimatorContractAddress") + .original_result() + } + + pub fn default_price_per_gas_unit< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getDefaultPricePerGasUnit") + .argument(&token_id) + .original_result() + } + + pub fn eth_tx_gas_limit( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEthTxGasLimit") + .original_result() + } + + /// Distributes the accumulated fees to the given addresses. + /// Expected arguments are pairs of (address, percentage), + /// where percentages must add up to the PERCENTAGE_TOTAL constant + pub fn distribute_fees< + Arg0: ProxyArg>>, + >( + self, + address_percentage_pairs: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributeFees") + .argument(&address_percentage_pairs) + .original_result() + } + + pub fn add_token_to_whitelist< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg>, + Arg7: ProxyArg>>, + >( + self, + token_id: Arg0, + ticker: Arg1, + mint_burn_token: Arg2, + native_token: Arg3, + total_balance: Arg4, + mint_balance: Arg5, + burn_balance: Arg6, + opt_default_price_per_gas_unit: Arg7, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addTokenToWhitelist") + .argument(&token_id) + .argument(&ticker) + .argument(&mint_burn_token) + .argument(&native_token) + .argument(&total_balance) + .argument(&mint_balance) + .argument(&burn_balance) + .argument(&opt_default_price_per_gas_unit) + .original_result() + } + + pub fn remove_token_from_whitelist< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeTokenFromWhitelist") + .argument(&token_id) + .original_result() + } + + pub fn get_tokens< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokens") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("initSupply") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply_mint_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_id: Arg0, + mint_amount: Arg1, + burn_amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("initSupplyMintBurn") + .argument(&token_id) + .argument(&mint_amount) + .argument(&burn_amount) + .original_result() + } + + pub fn set_multi_transfer_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn token_whitelist( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAllKnownTokens") + .original_result() + } + + pub fn native_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isNativeToken") + .argument(&token) + .original_result() + } + + pub fn mint_burn_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isMintBurnToken") + .argument(&token) + .original_result() + } + + pub fn multi_transfer_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferContractAddress") + .original_result() + } + + pub fn accumulated_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAccumulatedTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn total_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalBalances") + .argument(&token_id) + .original_result() + } + + pub fn mint_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMintBalances") + .argument(&token_id) + .original_result() + } + + pub fn burn_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBurnBalances") + .argument(&token_id) + .original_result() + } + + pub fn set_max_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + pub fn set_max_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + pub fn get_current_tx_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentTxBatch") + .original_result() + } + + pub fn get_first_batch_any_status( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchAnyStatus") + .original_result() + } + + pub fn get_batch< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatch") + .argument(&batch_id) + .original_result() + } + + pub fn get_batch_status< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatchStatus") + .argument(&batch_id) + .original_result() + } + + pub fn first_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchId") + .original_result() + } + + pub fn last_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastBatchId") + .original_result() + } + + pub fn set_max_bridged_amount< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxBridgedAmount") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + pub fn max_bridged_amount< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMaxBridgedAmount") + .argument(&token_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, ManagedVecItem, PartialEq)] +pub struct RefundInfo +where + Api: ManagedTypeApi, +{ + pub address: ManagedAddress, + pub initial_batch_id: u64, + pub initial_nonce: u64, +} diff --git a/multi-transfer-esdt/src/lib.rs b/multi-transfer-esdt/src/lib.rs index 43a73246..82d257c0 100644 --- a/multi-transfer-esdt/src/lib.rs +++ b/multi-transfer-esdt/src/lib.rs @@ -1,32 +1,44 @@ #![no_std] -multiversx_sc::imports!(); +use multiversx_sc::{imports::*, storage::StorageKey}; -use transaction::{EthTransaction, PaymentsVec, Transaction, TxBatchSplitInFields}; +use eth_address::EthAddress; +use transaction::{EthTransaction, PaymentsVec, Transaction, TxNonce}; + +pub mod bridge_proxy_contract_proxy; +pub mod bridged_tokens_wrapper_proxy; +pub mod esdt_safe_proxy; +pub mod multi_transfer_proxy; const DEFAULT_MAX_TX_BATCH_SIZE: usize = 10; const DEFAULT_MAX_TX_BATCH_BLOCK_DURATION: u64 = u64::MAX; +const CHAIN_SPECIFIC_TO_UNIVERSAL_TOKEN_MAPPING: &[u8] = b"chainSpecificToUniversalMapping"; #[multiversx_sc::contract] pub trait MultiTransferEsdt: tx_batch_module::TxBatchModule + max_bridged_amount_module::MaxBridgedAmountModule { #[init] - fn init(&self, opt_wrapping_contract_address: OptionalValue) { + fn init(&self) { self.max_tx_batch_size() .set_if_empty(DEFAULT_MAX_TX_BATCH_SIZE); self.max_tx_batch_block_duration() .set_if_empty(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); - - self.set_wrapping_contract_address(opt_wrapping_contract_address); - // batch ID 0 is considered invalid self.first_batch_id().set_if_empty(1); self.last_batch_id().set_if_empty(1); } #[upgrade] - fn upgrade(&self) {} + fn upgrade(&self) { + self.max_tx_batch_size() + .set_if_empty(DEFAULT_MAX_TX_BATCH_SIZE); + self.max_tx_batch_block_duration() + .set_if_empty(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); + // batch ID 0 is considered invalid + self.first_batch_id().set_if_empty(1); + self.last_batch_id().set_if_empty(1); + } #[only_owner] #[endpoint(batchTransferEsdtToken)] @@ -36,24 +48,35 @@ pub trait MultiTransferEsdt: transfers: MultiValueEncoded>, ) { let mut valid_payments_list = ManagedVec::new(); - let mut valid_dest_addresses_list = ManagedVec::new(); + let mut valid_tx_list = ManagedVec::new(); let mut refund_tx_list = ManagedVec::new(); let own_sc_address = self.blockchain().get_sc_address(); let sc_shard = self.blockchain().get_shard_of_address(&own_sc_address); + let safe_address = self.esdt_safe_contract_address().get(); + for eth_tx in transfers { + let is_success: bool = self + .tx() + .to(safe_address.clone()) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .get_tokens(ð_tx.token_id, ð_tx.amount) + .returns(ReturnsResult) + .sync_call(); + + require!(is_success, "Invalid token or amount"); + + let universal_token = self.get_universal_token(eth_tx.clone()); + let mut must_refund = false; - if eth_tx.to.is_zero() || self.blockchain().is_smart_contract(ð_tx.to) { + if eth_tx.to.is_zero() { self.transfer_failed_invalid_destination(batch_id, eth_tx.tx_nonce); must_refund = true; - } else if !self.is_local_role_set(ð_tx.token_id, &EsdtLocalRole::Mint) { - self.transfer_failed_invalid_token(batch_id, eth_tx.tx_nonce); - must_refund = true; } else if self.is_above_max_amount(ð_tx.token_id, ð_tx.amount) { self.transfer_over_max_amount(batch_id, eth_tx.tx_nonce); must_refund = true; - } else if self.is_account_same_shard_frozen(sc_shard, ð_tx.to, ð_tx.token_id) { + } else if self.is_account_same_shard_frozen(sc_shard, ð_tx.to, &universal_token) { self.transfer_failed_frozen_destination_account(batch_id, eth_tx.tx_nonce); must_refund = true; } @@ -65,34 +88,65 @@ pub trait MultiTransferEsdt: continue; } - self.send() - .esdt_local_mint(ð_tx.token_id, 0, ð_tx.amount); - // emit event before the actual transfer so we don't have to save the tx_nonces as well - self.transfer_performed_event(batch_id, eth_tx.tx_nonce); - - valid_dest_addresses_list.push(eth_tx.to); + self.transfer_performed_event( + batch_id, + eth_tx.from.clone(), + eth_tx.to.clone(), + eth_tx.token_id.clone(), + eth_tx.amount.clone(), + eth_tx.tx_nonce, + ); + + valid_tx_list.push(eth_tx.clone()); valid_payments_list.push(EsdtTokenPayment::new(eth_tx.token_id, 0, eth_tx.amount)); } let payments_after_wrapping = self.wrap_tokens(valid_payments_list); - self.distribute_payments(valid_dest_addresses_list, payments_after_wrapping); + self.distribute_payments(valid_tx_list, payments_after_wrapping, batch_id); self.add_multiple_tx_to_batch(&refund_tx_list); } #[only_owner] - #[endpoint(getAndClearFirstRefundBatch)] - fn get_and_clear_first_refund_batch(&self) -> OptionalValue> { + #[endpoint(moveRefundBatchToSafe)] + fn move_refund_batch_to_safe(&self) { let opt_current_batch = self.get_first_batch_any_status(); - if matches!(opt_current_batch, OptionalValue::Some(_)) { - let first_batch_id = self.first_batch_id().get(); - let mut first_batch = self.pending_batches(first_batch_id); - - self.clear_first_batch(&mut first_batch); + match opt_current_batch { + OptionalValue::Some(current_batch) => { + let first_batch_id = self.first_batch_id().get(); + let mut first_batch = self.pending_batches(first_batch_id); + + self.clear_first_batch(&mut first_batch); + let (_batch_id, all_tx_fields) = current_batch.into_tuple(); + let mut refund_batch = ManagedVec::new(); + let mut refund_payments = ManagedVec::new(); + + for tx_fields in all_tx_fields { + let (_, tx_nonce, _, _, token_identifier, amount) = + tx_fields.clone().into_tuple(); + + if self.is_refund_valid(&token_identifier) { + refund_batch.push(Transaction::from(tx_fields)); + refund_payments.push(EsdtTokenPayment::new(token_identifier, 0, amount)); + } else { + self.unprocessed_refund_txs(tx_nonce) + .set(Transaction::from(tx_fields)); + + self.unprocessed_refund_txs_event(tx_nonce); + } + } + + let esdt_safe_addr = self.esdt_safe_contract_address().get(); + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_refund_batch(refund_batch) + .payment(refund_payments) + .sync_call(); + } + OptionalValue::None => {} } - - opt_current_batch } #[only_owner] @@ -111,8 +165,75 @@ pub trait MultiTransferEsdt: } } + #[only_owner] + #[endpoint(setBridgeProxyContractAddress)] + fn set_bridge_proxy_contract_address(&self, opt_new_address: OptionalValue) { + match opt_new_address { + OptionalValue::Some(sc_addr) => { + require!( + self.blockchain().is_smart_contract(&sc_addr), + "Invalid bridge proxy contract address" + ); + + self.bridge_proxy_contract_address().set(&sc_addr); + } + OptionalValue::None => self.bridge_proxy_contract_address().clear(), + } + } + + #[only_owner] + #[endpoint(addUnprocessedRefundTxToBatch)] + fn add_unprocessed_refund_tx_to_batch(&self, tx_id: u64) { + let refund_tx = self.unprocessed_refund_txs(tx_id).get(); + let mut refund_tx_list = ManagedVec::new(); + refund_tx_list.push(refund_tx); + self.add_multiple_tx_to_batch(&refund_tx_list); + + self.unprocessed_refund_txs(tx_id).clear(); + } + + #[only_owner] + #[endpoint(setEsdtSafeContractAddress)] + fn set_esdt_safe_contract_address(&self, opt_new_address: OptionalValue) { + match opt_new_address { + OptionalValue::Some(sc_addr) => { + self.esdt_safe_contract_address().set(&sc_addr); + } + OptionalValue::None => self.esdt_safe_contract_address().clear(), + } + } + // private + fn is_refund_valid(&self, token_id: &TokenIdentifier) -> bool { + let esdt_safe_addr = self.esdt_safe_contract_address().get(); + let own_sc_address = self.blockchain().get_sc_address(); + let sc_shard = self.blockchain().get_shard_of_address(&own_sc_address); + + if self.is_account_same_shard_frozen(sc_shard, &esdt_safe_addr, token_id) { + return false; + } + return true; + } + + fn get_universal_token(&self, eth_tx: EthTransaction) -> TokenIdentifier { + let mut storage_key = StorageKey::new(CHAIN_SPECIFIC_TO_UNIVERSAL_TOKEN_MAPPING); + storage_key.append_item(ð_tx.token_id); + + let chain_specific_to_universal_token_mapper: SingleValueMapper< + TokenIdentifier, + ManagedAddress, + > = SingleValueMapper::<_, _, ManagedAddress>::new_from_address( + self.wrapping_contract_address().get(), + storage_key, + ); + if chain_specific_to_universal_token_mapper.is_empty() { + eth_tx.token_id + } else { + chain_specific_to_universal_token_mapper.get() + } + } + fn convert_to_refund_tx(&self, eth_tx: EthTransaction) -> Transaction { Transaction { block_nonce: self.blockchain().get_block_nonce(), @@ -153,45 +274,68 @@ pub trait MultiTransferEsdt: return payments; } - self.get_wrapping_contract_proxy_instance() + let bridged_tokens_wrapper_addr = self.wrapping_contract_address().get(); + self.tx() + .to(bridged_tokens_wrapper_addr) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) .wrap_tokens() - .with_multi_token_transfer(payments) - .execute_on_dest_context() + .payment(payments) + .returns(ReturnsResult) + .sync_call() } fn distribute_payments( &self, - dest_addresses: ManagedVec, + transfers: ManagedVec>, payments: PaymentsVec, + batch_id: u64, ) { - for (dest, p) in dest_addresses.iter().zip(payments.iter()) { - self.send() - .direct_esdt(&dest, &p.token_identifier, 0, &p.amount); + let bridge_proxy_addr = self.bridge_proxy_contract_address().get(); + for (eth_tx, p) in transfers.iter().zip(payments.iter()) { + if self.blockchain().is_smart_contract(ð_tx.to) { + self.tx() + .to(bridge_proxy_addr.clone()) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .deposit(ð_tx, batch_id) + .single_esdt(&p.token_identifier, 0, &p.amount) + .sync_call(); + } else { + self.tx() + .to(ð_tx.to) + .single_esdt(&p.token_identifier, 0, &p.amount) + .transfer(); + } } } - // proxies - - #[proxy] - fn wrapping_contract_proxy( - &self, - sc_address: ManagedAddress, - ) -> bridged_tokens_wrapper::Proxy; - - fn get_wrapping_contract_proxy_instance(&self) -> bridged_tokens_wrapper::Proxy { - self.wrapping_contract_proxy(self.wrapping_contract_address().get()) - } - // storage - #[view(getWrappingContractAddress)] #[storage_mapper("wrappingContractAddress")] fn wrapping_contract_address(&self) -> SingleValueMapper; + #[view(getBridgeProxyContractAddress)] + #[storage_mapper("bridgeProxyContractAddress")] + fn bridge_proxy_contract_address(&self) -> SingleValueMapper; + + #[view(getEsdtSafeContractAddress)] + #[storage_mapper("esdtSafeContractAddress")] + fn esdt_safe_contract_address(&self) -> SingleValueMapper; + + #[storage_mapper("unprocessedRefundTxs")] + fn unprocessed_refund_txs(&self, tx_id: u64) -> SingleValueMapper>; + // events #[event("transferPerformedEvent")] - fn transfer_performed_event(&self, #[indexed] batch_id: u64, #[indexed] tx_id: u64); + fn transfer_performed_event( + &self, + #[indexed] batch_id: u64, + #[indexed] from: EthAddress, + #[indexed] to: ManagedAddress, + #[indexed] token_id: TokenIdentifier, + #[indexed] amount: BigUint, + #[indexed] tx_id: TxNonce, + ); #[event("transferFailedInvalidDestination")] fn transfer_failed_invalid_destination(&self, #[indexed] batch_id: u64, #[indexed] tx_id: u64); @@ -208,4 +352,7 @@ pub trait MultiTransferEsdt: #[event("transferOverMaxAmount")] fn transfer_over_max_amount(&self, #[indexed] batch_id: u64, #[indexed] tx_id: u64); + + #[event("unprocessedRefundTxs")] + fn unprocessed_refund_txs_event(&self, #[indexed] tx_id: u64); } diff --git a/multi-transfer-esdt/src/multi_transfer_proxy.rs b/multi-transfer-esdt/src/multi_transfer_proxy.rs new file mode 100644 index 00000000..914e46aa --- /dev/null +++ b/multi-transfer-esdt/src/multi_transfer_proxy.rs @@ -0,0 +1,291 @@ +// 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 MultiTransferEsdtProxy; + +impl TxProxyTrait for MultiTransferEsdtProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = MultiTransferEsdtProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + MultiTransferEsdtProxyMethods { wrapped_tx: tx } + } +} + +pub struct MultiTransferEsdtProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl MultiTransferEsdtProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl MultiTransferEsdtProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl MultiTransferEsdtProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn batch_transfer_esdt_token< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + batch_id: Arg0, + transfers: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("batchTransferEsdtToken") + .argument(&batch_id) + .argument(&transfers) + .original_result() + } + + pub fn move_refund_batch_to_safe( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("moveRefundBatchToSafe") + .original_result() + } + + pub fn set_wrapping_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setWrappingContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn set_bridge_proxy_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgeProxyContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn set_esdt_safe_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEsdtSafeContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn wrapping_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getWrappingContractAddress") + .original_result() + } + + pub fn bridge_proxy_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgeProxyContractAddress") + .original_result() + } + + pub fn esdt_safe_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEsdtSafeContractAddress") + .original_result() + } + + pub fn set_max_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + pub fn set_max_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + pub fn get_current_tx_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentTxBatch") + .original_result() + } + + pub fn get_first_batch_any_status( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchAnyStatus") + .original_result() + } + + pub fn get_batch< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatch") + .argument(&batch_id) + .original_result() + } + + pub fn get_batch_status< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatchStatus") + .argument(&batch_id) + .original_result() + } + + pub fn first_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchId") + .original_result() + } + + pub fn last_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastBatchId") + .original_result() + } + + pub fn set_max_bridged_amount< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxBridgedAmount") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + pub fn max_bridged_amount< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMaxBridgedAmount") + .argument(&token_id) + .original_result() + } +} diff --git a/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs b/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs new file mode 100644 index 00000000..804e150c --- /dev/null +++ b/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs @@ -0,0 +1,1062 @@ +#![allow(unused)] + +use bridge_proxy::{ + bridge_proxy_contract_proxy, + config::{self, ProxyTrait as _}, + ProxyTrait as _, +}; +use bridged_tokens_wrapper::ProxyTrait as _; +use esdt_safe::{EsdtSafe, ProxyTrait as _}; +use multi_transfer_esdt::{ + bridged_tokens_wrapper_proxy, esdt_safe_proxy, multi_transfer_proxy, ProxyTrait as _, +}; + +use multiversx_sc::{ + api::{HandleConstraints, ManagedTypeApi}, + codec::{ + multi_types::{MultiValueVec, OptionalValue}, + Empty, TopEncode, + }, + contract_base::ManagedSerializer, + storage::mappers::SingleValue, + types::{ + Address, BigUint, CodeMetadata, EgldOrEsdtTokenIdentifier, EsdtLocalRole, ManagedAddress, + ManagedBuffer, ManagedByteArray, ManagedOption, ManagedVec, MultiValueEncoded, + ReturnsNewManagedAddress, ReturnsResult, TestAddress, TestSCAddress, TestTokenIdentifier, + TokenIdentifier, + }, +}; +use multiversx_sc_modules::pause::ProxyTrait; +use multiversx_sc_scenario::{ + api::{StaticApi, VMHooksApi, VMHooksApiBackend}, + imports::MxscPath, + scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, + scenario_model::*, + ContractInfo, DebugApi, ExpectError, ExpectValue, ScenarioTxRun, ScenarioWorld, +}; + +use eth_address::*; +use token_module::ProxyTrait as _; +use transaction::{CallData, EthTransaction}; + +const UNIVERSAL_TOKEN_IDENTIFIER: TestTokenIdentifier = TestTokenIdentifier::new("UNIV-abc123"); +const BRIDGE_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("BRIDGE-123456"); +const WRAPPED_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("WRAPPED-123456"); +const TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("TOKEN"); + +const USER_ETHEREUM_ADDRESS: &[u8] = b"0x0102030405060708091011121314151617181920"; + +const GAS_LIMIT: u64 = 100_000_000; +const ERROR: u64 = 4; + +const MULTI_TRANSFER_CODE_PATH: MxscPath = MxscPath::new("output/multi-transfer-esdt.mxsc.json"); +const BRIDGE_PROXY_CODE_PATH: MxscPath = + MxscPath::new("../bridge-proxy/output/bridge-proxy.mxsc.json"); +const ESDT_SAFE_CODE_PATH: MxscPath = MxscPath::new("../esdt-safe/output/esdt-safe.mxsc.json"); +const BRIDGED_TOKENS_WRAPPER_CODE_PATH: MxscPath = + MxscPath::new("../bridged-tokens-wrapper/output/bridged-tokens-wrapper.mxsc.json"); +const PRICE_AGGREGATOR_CODE_PATH: MxscPath = + MxscPath::new("../price-aggregator/price-aggregator.mxsc.json"); + +const MULTI_TRANSFER_ADDRESS: TestSCAddress = TestSCAddress::new("multi-transfer"); +const BRIDGE_PROXY_ADDRESS: TestSCAddress = TestSCAddress::new("bridge-proxy"); +const ESDT_SAFE_ADDRESS: TestSCAddress = TestSCAddress::new("esdt-safe"); +const BRIDGED_TOKENS_WRAPPER_ADDRESS: TestSCAddress = TestSCAddress::new("bridged-tokens-wrapper"); +const PRICE_AGGREGATOR_ADDRESS: TestSCAddress = TestSCAddress::new("price-aggregator"); + +const ORACLE_ADDRESS: TestAddress = TestAddress::new("oracle"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const USER1_ADDRESS: TestAddress = TestAddress::new("user1"); +const USER2_ADDRESS: TestAddress = TestAddress::new("user2"); + +const ESDT_SAFE_ETH_TX_GAS_LIMIT: u64 = 150_000; +const MAX_AMOUNT: u64 = 100_000_000_000_000u64; + +const BALANCE: &str = "2,000,000"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract( + MULTI_TRANSFER_CODE_PATH, + multi_transfer_esdt::ContractBuilder, + ); + blockchain.register_contract(BRIDGE_PROXY_CODE_PATH, bridge_proxy::ContractBuilder); + + blockchain.register_contract(ESDT_SAFE_CODE_PATH, esdt_safe::ContractBuilder); + + blockchain.register_contract( + BRIDGED_TOKENS_WRAPPER_CODE_PATH, + bridged_tokens_wrapper::ContractBuilder, + ); + + blockchain +} + +type MultiTransferContract = ContractInfo>; +type BridgeProxyContract = ContractInfo>; +type EsdtSafeContract = ContractInfo>; +type BridgedTokensWrapperContract = ContractInfo>; + +struct MultiTransferTestState { + world: ScenarioWorld, +} + +impl MultiTransferTestState { + fn new() -> Self { + let mut world = world(); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .esdt_balance(BRIDGE_TOKEN_ID, 1001u64) + .esdt_balance(TOKEN_ID, MAX_AMOUNT) + .esdt_balance(WRAPPED_TOKEN_ID, 1001u64) + .esdt_balance(UNIVERSAL_TOKEN_IDENTIFIER, 1001u64) + .account(USER1_ADDRESS) + .nonce(1) + .account(USER2_ADDRESS) + .nonce(1); + + let roles = vec![ + "ESDTRoleLocalMint".to_string(), + "ESDTRoleLocalBurn".to_string(), + ]; + world + .account(ESDT_SAFE_ADDRESS) + .esdt_roles(BRIDGE_TOKEN_ID, roles.clone()) + .esdt_roles(UNIVERSAL_TOKEN_IDENTIFIER, roles.clone()) + .esdt_roles(WRAPPED_TOKEN_ID, roles.clone()) + .code(ESDT_SAFE_CODE_PATH) + .owner(OWNER_ADDRESS); + + Self { world } + } + + fn multi_transfer_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .init() + .code(MULTI_TRANSFER_CODE_PATH) + .new_address(MULTI_TRANSFER_ADDRESS) + .run(); + self + } + + fn bridge_proxy_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .init(OptionalValue::Some(MULTI_TRANSFER_ADDRESS.to_address())) + .code(BRIDGE_PROXY_CODE_PATH) + .new_address(BRIDGE_PROXY_ADDRESS) + .run(); + + self + } + + fn safe_deploy(&mut self, price_aggregator_contract_address: Address) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .upgrade( + ManagedAddress::zero(), + MULTI_TRANSFER_ADDRESS.to_address(), + BRIDGE_PROXY_ADDRESS.to_address(), + ESDT_SAFE_ETH_TX_GAS_LIMIT, + ) + .code(ESDT_SAFE_CODE_PATH) + .run(); + + self + } + + fn bridged_tokens_wrapper_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .init() + .code(BRIDGED_TOKENS_WRAPPER_CODE_PATH) + .new_address(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .run(); + + self + } + + fn config_multi_transfer(&mut self) { + self.world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .set_wrapping_contract_address(OptionalValue::Some( + BRIDGED_TOKENS_WRAPPER_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .set_bridge_proxy_contract_address(OptionalValue::Some( + BRIDGE_PROXY_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .set_esdt_safe_contract_address(OptionalValue::Some(ESDT_SAFE_ADDRESS.to_address())) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .set_multi_transfer_contract_address(OptionalValue::Some( + MULTI_TRANSFER_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + TokenIdentifier::from_esdt_bytes("BRIDGE-123456"), + "BRIDGE", + true, + false, + BigUint::zero(), + BigUint::zero(), + BigUint::zero(), + OptionalValue::Some(BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT)), + ) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + TokenIdentifier::from_esdt_bytes("TOKEN"), + "TOKEN", + false, + true, + BigUint::from(MAX_AMOUNT), + BigUint::zero(), + BigUint::zero(), + OptionalValue::Some(BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT)), + ) + .single_esdt( + &TokenIdentifier::from_esdt_bytes("TOKEN"), + 0, + &BigUint::from(MAX_AMOUNT), + ) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .set_max_bridged_amount(TOKEN_ID, MAX_AMOUNT - 1) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + TokenIdentifier::from_esdt_bytes("WRAPPED-123456"), + "BRIDGE2", + true, + false, + BigUint::zero(), + BigUint::zero(), + BigUint::zero(), + OptionalValue::Some(BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT)), + ) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unpause_endpoint() + .run(); + } + + fn config_bridged_tokens_wrapper(&mut self) { + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .set_bridge_proxy_contract_address(OptionalValue::Some( + BRIDGE_PROXY_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + TokenIdentifier::from_esdt_bytes("UNIV-abc123"), + "BRIDGE1", + true, + false, + BigUint::zero(), + BigUint::zero(), + BigUint::zero(), + OptionalValue::Some(BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT)), + ) + .run(); + self.world.set_esdt_balance( + BRIDGE_PROXY_ADDRESS, + b"UNIV-abc123", + BigUint::from(10_000_000u64), + ); + + self.world.set_esdt_balance( + BRIDGE_PROXY_ADDRESS, + b"WRAPPED-123456", + BigUint::from(10_000_000u64), + ); + + self.world.set_esdt_balance( + BRIDGED_TOKENS_WRAPPER_ADDRESS, + b"WRAPPED-123456", + BigUint::from(10_000_000u64), + ); + + self.world.set_esdt_balance( + BRIDGE_PROXY_ADDRESS, + b"BRIDGE-123456", + BigUint::from(10_000_000u64), + ); + + self.world.set_esdt_local_roles( + BRIDGED_TOKENS_WRAPPER_ADDRESS, + b"UNIV-abc123", + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .set_eth_tx_gas_limit(0u64) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .init_supply_mint_burn( + UNIVERSAL_TOKEN_IDENTIFIER, + BigUint::from(600_000u64), + BigUint::from(0u64), + ) + .run(); + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + TokenIdentifier::from_esdt_bytes("WRAPPED-123456"), + "BRIDGE2", + true, + false, + BigUint::zero(), + BigUint::zero(), + BigUint::zero(), + OptionalValue::Some(BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT)), + ) + .run(); + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .init_supply_mint_burn( + WRAPPED_TOKEN_ID, + BigUint::from(600_000u64), + BigUint::from(0u64), + ) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .set_bridged_tokens_wrapper_contract_address(OptionalValue::Some( + BRIDGED_TOKENS_WRAPPER_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .set_bridged_tokens_wrapper_contract_address(OptionalValue::Some( + BRIDGED_TOKENS_WRAPPER_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .add_wrapped_token(TokenIdentifier::from(UNIVERSAL_TOKEN_IDENTIFIER), 18u32) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .whitelist_token( + TokenIdentifier::from(WRAPPED_TOKEN_ID), + 18u32, + TokenIdentifier::from(UNIVERSAL_TOKEN_IDENTIFIER), + ) + .run(); + } + + fn check_balances_on_safe( + &mut self, + token_id: TestTokenIdentifier, + total_supply: BigUint, + total_minted: BigUint, + total_burned: BigUint, + ) { + let actual_total_supply = self + .world + .query() + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .total_balances(token_id) + .returns(ReturnsResult) + .run(); + + assert_eq!( + actual_total_supply, total_supply, + "Total supply balance is wrong" + ); + let actual_total_burned = self + .world + .query() + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .burn_balances(token_id) + .returns(ReturnsResult) + .run(); + + assert_eq!( + actual_total_burned, total_burned, + "Total burned balance is wrong" + ); + + let actual_total_minted = self + .world + .query() + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .mint_balances(token_id) + .returns(ReturnsResult) + .run(); + + assert_eq!( + actual_total_minted, total_minted, + "Total minted balance is wrong" + ); + } + + fn deploy_contracts(&mut self) { + self.multi_transfer_deploy(); + self.bridge_proxy_deploy(); + self.safe_deploy(Address::zero()); + self.bridged_tokens_wrapper_deploy(); + } +} + +#[test] +fn basic_transfer_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(500u64); + + state.deploy_contracts(); + state.config_multi_transfer(); + + let call_data = ManagedBuffer::from(b"add"); + call_data + .clone() + .concat(ManagedBuffer::from(GAS_LIMIT.to_string())); + call_data.clone().concat(ManagedBuffer::default()); + + let eth_tx = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::default(), + }, + to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID), + amount: token_amount.clone(), + tx_nonce: 1u64, + call_data: ManagedOption::some(call_data), + }; + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .batch_transfer_esdt_token(1u32, transfers) + .run(); + + state + .world + .check_account(USER1_ADDRESS) + .esdt_balance(BRIDGE_TOKEN_ID, token_amount); +} + +#[test] +fn batch_transfer_both_executed_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(500u64); + + state.deploy_contracts(); + state.config_multi_transfer(); + + let mut args = ManagedVec::new(); + args.push(ManagedBuffer::from(&[5u8])); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from("add"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + + let call_data: ManagedBuffer = + ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx1 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(USER2_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID), + amount: token_amount.clone(), + tx_nonce: 1u64, + call_data: ManagedOption::some(call_data.clone()), + }; + + let eth_tx2 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(WRAPPED_TOKEN_ID), + amount: token_amount.clone(), + tx_nonce: 2u64, + call_data: ManagedOption::some(call_data), + }; + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx1); + transfers.push(eth_tx2); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .batch_transfer_esdt_token(1u32, transfers) + .run(); + + state + .world + .check_account(USER1_ADDRESS) + .esdt_balance(WRAPPED_TOKEN_ID, token_amount.clone()); + + state + .world + .check_account(USER2_ADDRESS) + .esdt_balance(BRIDGE_TOKEN_ID, token_amount); +} + +#[test] +fn batch_two_transfers_same_token_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(500u64); + + state.deploy_contracts(); + state.config_multi_transfer(); + + let mut args = ManagedVec::new(); + args.push(ManagedBuffer::from(&[5u8])); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from("add"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + + let call_data: ManagedBuffer = + ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx1 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(USER2_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID), + amount: token_amount.clone(), + tx_nonce: 1u64, + call_data: ManagedOption::some(call_data.clone()), + }; + + let eth_tx2 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID), + amount: token_amount.clone(), + tx_nonce: 2u64, + call_data: ManagedOption::some(call_data), + }; + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx1); + transfers.push(eth_tx2); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .batch_transfer_esdt_token(1u32, transfers) + .run(); + + state + .world + .check_account(USER1_ADDRESS) + .esdt_balance(BRIDGE_TOKEN_ID, token_amount.clone()); + + state + .world + .check_account(USER2_ADDRESS) + .esdt_balance(BRIDGE_TOKEN_ID, token_amount); +} + +#[test] +fn batch_transfer_both_failed_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(500u64); + + state.deploy_contracts(); + state.config_multi_transfer(); + + let mut args = ManagedVec::new(); + args.push(ManagedBuffer::from(&[5u8])); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from("add"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + + let call_data: ManagedBuffer = + ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx1 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(BRIDGE_PROXY_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID), + amount: token_amount.clone(), + tx_nonce: 1u64, + call_data: ManagedOption::some(call_data.clone()), + }; + + let eth_tx2 = EthTransaction { + from: EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + to: ManagedAddress::from(BRIDGE_PROXY_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(BRIDGE_TOKEN_ID), + amount: token_amount.clone(), + tx_nonce: 2u64, + call_data: ManagedOption::some(call_data), + }; + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx1); + transfers.push(eth_tx2); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .batch_transfer_esdt_token(1u32, transfers) + .run(); + + let first_batch = state + .world + .query() + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .get_first_batch_any_status() + .returns(ReturnsResult) + .run(); + + assert!(first_batch.is_none()); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .move_refund_batch_to_safe() + .run(); + + let first_batch = state + .world + .query() + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .get_first_batch_any_status() + .returns(ReturnsResult) + .run(); + + assert!(first_batch.is_none()); +} + +#[test] +fn test_unwrap_token_create_transaction_paused() { + let mut state = MultiTransferTestState::new(); + + state.deploy_contracts(); + + state.config_bridged_tokens_wrapper(); + + state + .world + .tx() + .from(BRIDGE_PROXY_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unwrap_token_create_transaction( + TokenIdentifier::from(UNIVERSAL_TOKEN_IDENTIFIER), + ESDT_SAFE_ADDRESS.to_address(), + EthAddress::zero(), + ) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), + 0u64, + &BigUint::from(10u64), + ) + .returns(ExpectError(ERROR, "Contract is paused")) + .run(); +} + +#[test] +fn test_unwrap_token_create_transaction_insufficient_liquidity() { + let mut state = MultiTransferTestState::new(); + state.deploy_contracts(); + state.config_multi_transfer(); + state.config_bridged_tokens_wrapper(); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unpause_endpoint() + .run(); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .deposit_liquidity() + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(WRAPPED_TOKEN_ID), + 0u64, + &BigUint::from(1_000u64), + ) + .run(); + + state + .world + .set_esdt_balance(USER1_ADDRESS, b"UNIV-abc123", BigUint::from(5_000u64)); + + state + .world + .tx() + .from(USER1_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unwrap_token_create_transaction(WRAPPED_TOKEN_ID, ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero()) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), + 0u64, + &BigUint::from(2_000u64), + ) + .returns(ExpectError(ERROR, "Contract does not have enough funds")) + .run(); +} + +#[test] +fn test_unwrap_token_create_transaction_should_work() { + let mut state = MultiTransferTestState::new(); + + state.deploy_contracts(); + + state.config_multi_transfer(); + state.config_bridged_tokens_wrapper(); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .deposit_liquidity() + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(WRAPPED_TOKEN_ID), + 0u64, + &BigUint::from(1_000u64), + ) + .run(); + + state + .world + .set_esdt_balance(USER1_ADDRESS, b"UNIV-abc123", BigUint::from(5_000u64)); + + state.check_balances_on_safe( + WRAPPED_TOKEN_ID, + BigUint::zero(), + BigUint::from(600000u64), + BigUint::zero(), + ); + + state + .world + .query() + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .token_liquidity(WRAPPED_TOKEN_ID) + .returns(ExpectValue(BigUint::from(1000u64))) + .run(); + + state + .world + .tx() + .from(USER1_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unwrap_token_create_transaction(WRAPPED_TOKEN_ID, ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero()) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), + 0u64, + &BigUint::from(900u64), + ) + .run(); + + state + .world + .query() + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .token_liquidity(WRAPPED_TOKEN_ID) + .returns(ExpectValue(BigUint::from(100u64))) + .run(); + + state.check_balances_on_safe( + WRAPPED_TOKEN_ID, + BigUint::zero(), + BigUint::from(600000u64), + BigUint::from(900u64), + ); +} + +#[test] +fn test_unwrap_token_create_transaction_should_fail() { + let mut state = MultiTransferTestState::new(); + + state.deploy_contracts(); + + state.config_multi_transfer(); + state.config_bridged_tokens_wrapper(); + + state + .world + .set_esdt_balance(USER1_ADDRESS, b"TOKEN", BigUint::from(5_000u64)); + + state + .world + .tx() + .from(USER1_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unwrap_token_create_transaction(WRAPPED_TOKEN_ID, ESDT_SAFE_ADDRESS.to_address(), EthAddress::zero()) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(TOKEN_ID), + 0u64, + &BigUint::from(1_000u64), + ) + .returns(ExpectError(ERROR, "Esdt token unavailable")) + .run(); +} + +#[test] +fn test_unwrap_token_create_transaction_amount_zero() { + let mut state = MultiTransferTestState::new(); + + state.deploy_contracts(); + + state.config_multi_transfer(); + state.config_bridged_tokens_wrapper(); + state + .world + .tx() + .from(BRIDGE_PROXY_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unwrap_token_create_transaction( + TokenIdentifier::from(WRAPPED_TOKEN_ID), + ESDT_SAFE_ADDRESS.to_address(), + EthAddress::zero(), + ) + .egld_or_single_esdt( + &EgldOrEsdtTokenIdentifier::esdt(UNIVERSAL_TOKEN_IDENTIFIER), + 0u64, + &BigUint::from(0u64), + ) + .returns(ExpectError(ERROR, "Must pay more than 0 tokens!")) + .run(); +} + +#[test] +fn add_refund_batch_test() { + let mut state = MultiTransferTestState::new(); + + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.safe_deploy(Address::zero()); + state.bridged_tokens_wrapper_deploy(); + state.config_multi_transfer(); + + let eth_tx = EthTransaction { + from: EthAddress::zero(), + to: ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + token_id: TokenIdentifier::from(TOKEN_ID), + amount: BigUint::from(MAX_AMOUNT), + tx_nonce: 1u64, + call_data: ManagedOption::none(), + }; + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx.clone()); + + let fee = state + .world + .query() + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .calculate_required_fee(TOKEN_ID) + .returns(ReturnsResult) + .run(); + + state.check_balances_on_safe( + TOKEN_ID, + BigUint::from(MAX_AMOUNT), + BigUint::zero(), + BigUint::zero(), + ); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .batch_transfer_esdt_token(1u32, transfers) + .run(); + state.check_balances_on_safe(TOKEN_ID, BigUint::zero(), BigUint::zero(), BigUint::zero()); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .move_refund_batch_to_safe() + .run(); + + state.check_balances_on_safe( + TOKEN_ID, + BigUint::from(MAX_AMOUNT) - fee, + BigUint::zero(), + BigUint::zero(), + ); +} diff --git a/multi-transfer-esdt/tests/multi_transfer_esdt_scenario_rs_test.rs b/multi-transfer-esdt/tests/multi_transfer_esdt_scenario_rs_test.rs new file mode 100644 index 00000000..84f27346 --- /dev/null +++ b/multi-transfer-esdt/tests/multi_transfer_esdt_scenario_rs_test.rs @@ -0,0 +1,76 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract( + "file:output/multi-transfer-esdt.wasm", + multi_transfer_esdt::ContractBuilder, + ); + blockchain.register_contract( + "file:../esdt-safe/output/esdt-safe.wasm", + esdt_safe::ContractBuilder, + ); + blockchain.register_contract( + "file:../bridge-proxy/output/bridge-proxy.wasm", + bridge_proxy::ContractBuilder, + ); + blockchain.register_contract( + "file:../bridged-tokens-wrapper/output/bridged-tokens-wrapper.wasm", + bridged_tokens_wrapper::ContractBuilder, + ); + + blockchain +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn batch_transfer_both_executed_rs() { + world().run("scenarios/batch_transfer_both_executed.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn batch_transfer_both_failed_rs() { + world().run("scenarios/batch_transfer_both_failed.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn batch_transfer_one_executed_one_failed_rs() { + world().run("scenarios/batch_transfer_one_executed_one_failed.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn batch_transfer_to_frozen_account_rs() { + world().run("scenarios/batch_transfer_to_frozen_account.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn batch_transfer_with_wrapping_rs() { + world().run("scenarios/batch_transfer_with_wrapping.scen.json"); +} + +#[test] +fn setup_accounts_rs() { + world().run("scenarios/setup_accounts.scen.json"); +} + +#[test] +fn transfer_fail_mint_burn_not_allowed_rs() { + world().run("scenarios/transfer_fail_mint_burn_not_allowed.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn transfer_ok_rs() { + world().run("scenarios/transfer_ok.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn two_transfers_same_token_rs() { + world().run("scenarios/two_transfers_same_token.scen.json"); +} diff --git a/multi-transfer-esdt/tests/scenario_go_test.rs b/multi-transfer-esdt/tests/scenario_go_test.rs index cdda9c2b..0f043e4a 100644 --- a/multi-transfer-esdt/tests/scenario_go_test.rs +++ b/multi-transfer-esdt/tests/scenario_go_test.rs @@ -1,34 +1,57 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + ScenarioWorld::vm_go() +} + #[test] +#[ignore] //Ignore for now fn batch_transfer_both_executed_go() { - multiversx_sc_scenario::run_go("mandos/batch_transfer_both_executed.scen.json"); + world().run("scenarios/batch_transfer_both_executed.scen.json"); } #[test] +#[ignore] //Ignore for now fn batch_transfer_both_failed_go() { - multiversx_sc_scenario::run_go("mandos/batch_transfer_both_failed.scen.json"); + world().run("scenarios/batch_transfer_both_failed.scen.json"); } #[test] +#[ignore] //Ignore for now fn batch_transfer_one_executed_one_failed_go() { - multiversx_sc_scenario::run_go("mandos/batch_transfer_one_executed_one_failed.scen.json"); + world().run("scenarios/batch_transfer_one_executed_one_failed.scen.json"); } #[test] +#[ignore] //Ignore for now fn batch_transfer_to_frozen_account_go() { - multiversx_sc_scenario::run_go("mandos/batch_transfer_to_frozen_account.scen.json"); + world().run("scenarios/batch_transfer_to_frozen_account.scen.json"); +} + +#[test] +#[ignore] //Ignore for now +fn batch_transfer_with_wrapping_go() { + world().run("scenarios/batch_transfer_with_wrapping.scen.json"); } #[test] fn setup_accounts_go() { - multiversx_sc_scenario::run_go("mandos/setup_accounts.scen.json"); + world().run("scenarios/setup_accounts.scen.json"); +} + +#[test] +fn transfer_fail_mint_burn_not_allowed_go() { + world().run("scenarios/transfer_fail_mint_burn_not_allowed.scen.json"); } #[test] +#[ignore] //Ignore for now fn transfer_ok_go() { - multiversx_sc_scenario::run_go("mandos/transfer_ok.scen.json"); + world().run("scenarios/transfer_ok.scen.json"); } #[test] +#[ignore] //Ignore for now fn two_transfers_same_token_go() { - multiversx_sc_scenario::run_go("mandos/two_transfers_same_token.scen.json"); + world().run("scenarios/two_transfers_same_token.scen.json"); } diff --git a/multi-transfer-esdt/wasm/Cargo.lock b/multi-transfer-esdt/wasm/Cargo.lock index a6f561a9..663a9880 100644 --- a/multi-transfer-esdt/wasm/Cargo.lock +++ b/multi-transfer-esdt/wasm/Cargo.lock @@ -2,24 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "allocator-api2" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" - [[package]] name = "arrayvec" version = "0.7.4" @@ -28,37 +10,90 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bridge-proxy" +version = "0.0.0" +dependencies = [ + "bridged-tokens-wrapper", + "crowdfunding-esdt", + "esdt-safe", + "eth-address", + "multiversx-sc", + "multiversx-sc-modules", + "token-module", + "transaction", + "tx-batch-module", +] [[package]] name = "bridged-tokens-wrapper" version = "0.0.0" dependencies = [ + "eth-address", "multiversx-sc", "multiversx-sc-modules", + "token-module", "transaction", + "tx-batch-module", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "crowdfunding-esdt" +version = "0.0.0" +source = "git+https://github.com/multiversx/mx-contracts-rs?rev=d91bbff#d91bbff295295c2f7e2baf1cd569dd5693ddfb56" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "endian-type" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "esdt-safe" +version = "0.0.0" +dependencies = [ + "eth-address", + "fee-estimator-module", + "max-bridged-amount-module", + "multiversx-price-aggregator-sc", + "multiversx-sc", + "multiversx-sc-modules", + "token-module", + "transaction", + "tx-batch-module", +] + [[package]] name = "eth-address" version = "0.0.0" @@ -67,13 +102,23 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.14.3" +name = "fee-estimator-module" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "getrandom" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "ahash", - "allocator-api2", + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", ] [[package]] @@ -88,6 +133,27 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "max-bridged-amount-module" version = "0.0.0" @@ -99,9 +165,14 @@ dependencies = [ name = "multi-transfer-esdt" version = "0.0.0" dependencies = [ + "bridge-proxy", "bridged-tokens-wrapper", + "esdt-safe", + "eth-address", "max-bridged-amount-module", "multiversx-sc", + "multiversx-sc-modules", + "token-module", "transaction", "tx-batch-module", ] @@ -114,35 +185,49 @@ dependencies = [ "multiversx-sc-wasm-adapter", ] +[[package]] +name = "multiversx-price-aggregator-sc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea572ebab3a6addd937cad829076b13e320851503fb6adf1ad66f544b2bf100" +dependencies = [ + "arrayvec", + "getrandom", + "multiversx-sc", + "multiversx-sc-modules", + "rand", +] + [[package]] name = "multiversx-sc" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2bdb196b3ff2b9f8c744ec2e026c22c8e02bc91e5c6ed09951415c47fef6b8" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" dependencies = [ "bitflags", - "hashbrown", "hex-literal", "multiversx-sc-codec", "multiversx-sc-derive", "num-traits", + "unwrap-infallible", ] [[package]] name = "multiversx-sc-codec" -version = "0.18.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19908153158c03df4582af08f47c0eb39fb52a7dff4736b301a66acbbb9955d3" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" dependencies = [ "arrayvec", "multiversx-sc-codec-derive", + "unwrap-infallible", ] [[package]] name = "multiversx-sc-codec-derive" -version = "0.18.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b03b43f9cad320992f54ed162de2ed63e3ec83ed01361e57ee9c1865fba5a2" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" dependencies = [ "hex", "proc-macro2", @@ -152,9 +237,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e60b5dce707f61376f74d713218f75326121d9f6a5f09a3a63de7aea2a92be9" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" dependencies = [ "hex", "proc-macro2", @@ -165,18 +250,18 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5833f8bc88104357d38a8952d2a16c3e66080e2e512c0e7001c0c003006c475" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4299660d5413d9f120bfddda8105b1f9d28f0345a72f53e5dc90732c4983e45" +checksum = "ed13aaca9cbdbc6911174cd3029e750a7563d85dd3daaa1107b1fd31c7f17245" dependencies = [ "multiversx-sc", ] @@ -192,33 +277,42 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -233,23 +327,61 @@ dependencies = [ "nibble_vec", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.41" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "token-module" +version = "0.0.0" +dependencies = [ + "fee-estimator-module", + "multiversx-sc", +] + [[package]] name = "transaction" version = "0.0.0" @@ -268,30 +400,91 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] [[package]] -name = "version_check" -version = "0.9.4" +name = "wasm-bindgen-shared" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "zerocopy" -version = "0.7.31" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.31" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/multi-transfer-esdt/wasm/Cargo.toml b/multi-transfer-esdt/wasm/Cargo.toml index 69f59530..78436b15 100644 --- a/multi-transfer-esdt/wasm/Cargo.toml +++ b/multi-transfer-esdt/wasm/Cargo.toml @@ -21,11 +21,14 @@ debug = false panic = "abort" overflow-checks = false +[profile.dev] +panic = "abort" + [dependencies.multi-transfer-esdt] path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.45.2" +version = "=0.52.3" [workspace] members = ["."] diff --git a/multi-transfer-esdt/wasm/src/lib.rs b/multi-transfer-esdt/wasm/src/lib.rs index 85514113..13c00129 100644 --- a/multi-transfer-esdt/wasm/src/lib.rs +++ b/multi-transfer-esdt/wasm/src/lib.rs @@ -5,16 +5,13 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 15 +// Upgrade: 1 +// Endpoints: 19 // Async Callback (empty): 1 -// Total number of exported functions: 17 +// Total number of exported functions: 22 #![no_std] -// Configuration that works with rustc < 1.73.0. -// TODO: Recommended rustc version: 1.73.0 or newer. -#![feature(lang_items)] - multiversx_sc_wasm_adapter::allocator!(); multiversx_sc_wasm_adapter::panic_handler!(); @@ -24,9 +21,14 @@ multiversx_sc_wasm_adapter::endpoints! { init => init upgrade => upgrade batchTransferEsdtToken => batch_transfer_esdt_token - getAndClearFirstRefundBatch => get_and_clear_first_refund_batch + moveRefundBatchToSafe => move_refund_batch_to_safe setWrappingContractAddress => set_wrapping_contract_address + setBridgeProxyContractAddress => set_bridge_proxy_contract_address + addUnprocessedRefundTxToBatch => add_unprocessed_refund_tx_to_batch + setEsdtSafeContractAddress => set_esdt_safe_contract_address getWrappingContractAddress => wrapping_contract_address + getBridgeProxyContractAddress => bridge_proxy_contract_address + getEsdtSafeContractAddress => esdt_safe_contract_address setMaxTxBatchSize => set_max_tx_batch_size setMaxTxBatchBlockDuration => set_max_tx_batch_block_duration getCurrentTxBatch => get_current_tx_batch diff --git a/multisig/Cargo.toml b/multisig/Cargo.toml index d6f77141..c24b49eb 100644 --- a/multisig/Cargo.toml +++ b/multisig/Cargo.toml @@ -32,11 +32,20 @@ path = "../esdt-safe" [dependencies.multi-transfer-esdt] path = "../multi-transfer-esdt" +[dependencies.bridged-tokens-wrapper] +path = "../bridged-tokens-wrapper" + +[dependencies.bridge-proxy] +path = "../bridge-proxy" + [dependencies.multiversx-sc] -version = "0.45.2" +version = "=0.52.3" + +[dependencies.multiversx-price-aggregator-sc] +version = "=0.52.0" [dependencies.multiversx-sc-modules] -version = "0.45.2" +version = "=0.52.3" [dev-dependencies.multiversx-sc-scenario] -version = "0.45.2" +version = "=0.52.3" diff --git a/multisig/README.md b/multisig/README.md index 8f0b223f..afb02fb7 100644 --- a/multisig/README.md +++ b/multisig/README.md @@ -27,14 +27,14 @@ The required guidelines are: * **No libraries.** Extending the last guideline, our contract has no upstream dependencies other than itself. This minimizes the chance of us misunderstanding or misusing some piece of library code. It also forces us to stay simple and eases auditing and eventually formal verification. -* **Minimal internal state.** Complex applications can be built inside Elrond smart contracts. Storing minimal internal state allows our contract’s code to be simpler, and to be written in a more functional style, which is easier to test and reason about. +* **Minimal internal state.** Complex applications can be built inside MultiversX smart contracts. Storing minimal internal state allows our contract’s code to be simpler, and to be written in a more functional style, which is easier to test and reason about. * **Uses cold-storage.** The proposer which creates an action or spends from the contract has no special rights or access to the MSC. Authorization is handled by directly signing messages by the board members’ wallets that can be hardware wallets (Trezor; Ledger, etc.) or software wallets. * **Complete end-to-end testing.** The contract itself is exhaustively unit tested, audited and formally verified. ## Roles -* **Deployer** - This is the address that deploys the MSC. By default, this address is also the owner of the SC, but the owner can be changed later if required, as this is by default supported by the Elrond protocol itself. This is the address that initially set up the configuration of the SC: board members, quorum, etc. It is important to mention that at deployment a very important configuration parameter is the option to allow the SC to be upgradeable or not. It is recommended for most use cases the SC to be non-upgradeable. Leaving the SC upgradable will give the owner of the SC the possibility to upgrade the SC and bypass the board, defeating the purpose of a MSC. If keeping the SC upgradeable is desired, a possible approach would be to make the owner another MSC, and both SCs could maintain the same board, so an upgrade action would need the approval of the board. +* **Deployer** - This is the address that deploys the MSC. By default, this address is also the owner of the SC, but the owner can be changed later if required, as this is by default supported by the MultiversX protocol itself. This is the address that initially set up the configuration of the SC: board members, quorum, etc. It is important to mention that at deployment a very important configuration parameter is the option to allow the SC to be upgradeable or not. It is recommended for most use cases the SC to be non-upgradeable. Leaving the SC upgradable will give the owner of the SC the possibility to upgrade the SC and bypass the board, defeating the purpose of a MSC. If keeping the SC upgradeable is desired, a possible approach would be to make the owner another MSC, and both SCs could maintain the same board, so an upgrade action would need the approval of the board. * **Owner** - The deployer is initially the owner of the MSC, but if desired can be changed later by the current owner to a different owner. If the SC is upgradeable, the owner can also upgrade the SC. @@ -79,4 +79,4 @@ MSC is a deployable SC written in Rust and compiled in WASM. ## Conclusion -Multisig accounts are a critical safety feature for all users of the Elrond ecosystem. Decentralised applications will rely heavily upon multisig security. +Multisig accounts are a critical safety feature for all users of the MultiversX ecosystem. Decentralised applications will rely heavily upon multisig security. diff --git a/multisig/interaction/config/aggregator-snippets.sh b/multisig/interaction/config/aggregator-snippets.sh index 3c12fa92..c5c910ef 100644 --- a/multisig/interaction/config/aggregator-snippets.sh +++ b/multisig/interaction/config/aggregator-snippets.sh @@ -1,8 +1,10 @@ deployAggregator() { - CHECK_VARIABLES AGGREGATOR_WASM CHAIN_SPECIFIC_TOKEN ALICE_ADDRESS + CHECK_VARIABLES AGGREGATOR_WASM CHAIN_SPECIFIC_TOKEN ORACLE_ADDR_0 ORACLE_ADDR_1 ORACLE_ADDR_2 - mxpy --verbose contract deploy --bytecode=${AGGREGATOR_WASM} --recall-nonce --pem=${ALICE} \ - --gas-limit=100000000 --arguments 1 0 ${ALICE_ADDRESS} \ + STAKE=$(echo "$ORACLE_REQUIRED_STAKE*10^18" | bc) + mxpy contract deploy --bytecode=${AGGREGATOR_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=100000000 --arguments str:EGLD ${STAKE} 1 2 3 \ + ${ORACLE_ADDR_0} ${ORACLE_ADDR_1} ${ORACLE_ADDR_2} \ --send --outfile=deploy-price-agregator-testnet.interaction.json --proxy=${PROXY} --chain=${CHAIN_ID} || return TRANSACTION=$(mxpy data parse --file="./deploy-price-agregator-testnet.interaction.json" --expression="data['emittedTransactionHash']") @@ -13,6 +15,28 @@ deployAggregator() { echo "" echo "Price agregator: ${ADDRESS}" + update-config AGGREGATOR ${ADDRESS} +} + +stakeOracles() { + CHECK_VARIABLES AGGREGATOR + + STAKE=$(echo "$ORACLE_REQUIRED_STAKE*10^18" | bc) + echo "---------------------------------------------------------" + mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ORACLE_WALLET0} \ + --gas-limit=35000000 --function="stake" --value=${STAKE} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} + echo "---------------------------------------------------------" + echo "---------------------------------------------------------" + mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ORACLE_WALLET1} \ + --gas-limit=35000000 --function="stake" --value=${STAKE} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} + echo "---------------------------------------------------------" + echo "---------------------------------------------------------" + mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ORACLE_WALLET2} \ + --gas-limit=35000000 --function="stake" --value=${STAKE} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} + echo "---------------------------------------------------------" } submitAggregatorBatch() { @@ -20,16 +44,46 @@ submitAggregatorBatch() { FEE=$(echo "scale=0; $FEE_AMOUNT*10^$NR_DECIMALS_CHAIN_SPECIFIC/1" | bc) - mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ALICE} \ + CURRENT_TIME=$(date +%s) + mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ORACLE_WALLET0} \ --gas-limit=15000000 --function="submitBatch" \ - --arguments str:GWEI str:${CHAIN_SPECIFIC_TOKEN_TICKER} ${FEE} \ + --arguments str:GWEI str:${CHAIN_SPECIFIC_TOKEN_TICKER} ${CURRENT_TIME} ${FEE} 0 \ --send --proxy=${PROXY} --chain=${CHAIN_ID} || return + + CURRENT_TIME=$(date +%s) + mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ORACLE_WALLET1} \ + --gas-limit=15000000 --function="submitBatch" \ + --arguments str:GWEI str:${CHAIN_SPECIFIC_TOKEN_TICKER} ${CURRENT_TIME} ${FEE} 0 \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} || return + + CURRENT_TIME=$(date +%s) + mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ORACLE_WALLET2} \ + --gas-limit=15000000 --function="submitBatch" \ + --arguments str:GWEI str:${CHAIN_SPECIFIC_TOKEN_TICKER} ${CURRENT_TIME} ${FEE} 0 \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} || return +} + +setPairDecimals() { + CHECK_VARIABLES AGGREGATOR + + mxpy contract call ${AGGREGATOR} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=15000000 --function="setPairDecimals" \ + --arguments str:GWEI str:${CHAIN_SPECIFIC_TOKEN_TICKER} 0 \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} || return } pauseAggregator() { CHECK_VARIABLES AGGREGATOR - mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${AGGREGATOR} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=5000000 --function="pause" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} || return +} + +pauseAggregatorV2() { + CHECK_VARIABLES AGGREGATOR_v2 + + mxpy contract call ${AGGREGATOR_v2} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=5000000 --function="pause" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} || return } @@ -37,7 +91,15 @@ pauseAggregator() { unpauseAggregator() { CHECK_VARIABLES AGGREGATOR - mxpy --verbose contract call ${AGGREGATOR} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${AGGREGATOR} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=5000000 --function="unpause" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} || return } + +aggregator-upgrade() { + CHECK_VARIABLES AGGREGATOR AGGREGATOR_WASM + + mxpy contract upgrade ${AGGREGATOR} --bytecode=${AGGREGATOR_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=100000000 --send \ + --outfile="upgrade-aggregator.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return +} diff --git a/multisig/interaction/config/configs.cfg b/multisig/interaction/config/configs.cfg index 9b58c555..df5ba4cf 100644 --- a/multisig/interaction/config/configs.cfg +++ b/multisig/interaction/config/configs.cfg @@ -10,13 +10,22 @@ CHAIN_ID=T ALICE="./wallets/erd1zsha9cvx7gwraytgp740dcjzwy9v5xwnmas77d33uve6sk0rs0vqel4ln5.pem" ALICE_ADDRESS=erd1zsha9cvx7gwraytgp740dcjzwy9v5xwnmas77d33uve6sk0rs0vqel4ln5 +MXPY_SIGN=() +#use this for signing transactions with a pem file +#MXPY_SIGN+=(--pem=${ALICE}) +#use this to sign with ledger +MXPY_SIGN+=(--ledger) + #============WASM FILES============== -AGGREGATOR_WASM="./price-aggregator.wasm" +AGGREGATOR_WASM="./multiversx-price-aggregator-sc.wasm" SAFE_WASM="./esdt-safe.wasm" BRIDGED_TOKENS_WRAPPER_WASM="./bridged-tokens-wrapper.wasm" MULTI_TRANSFER_WASM="./multi-transfer-esdt.wasm" MULTISIG_WASM="./multisig.wasm" +PROXY_WASM="./bridge-proxy.wasm" +FAUCET_WASM="./faucet.wasm" +TEST_CALLER_WASM="./test-caller.wasm" #============CONTRACT ADDRESSES============== @@ -25,6 +34,14 @@ SAFE=erd1qqqqqqqqqqqqqpgqkhx64czgpc84eftg6q25lrfyv95ndwtcs0vqwusfuh BRIDGED_TOKENS_WRAPPER=erd1qqqqqqqqqqqqqpgqlgjwk8mpfycxpdf9q2sgzcndtdhdxr5ss0vqgygjmn MULTI_TRANSFER=erd1qqqqqqqqqqqqqpgqjsh8kss3w67xks7ths5d795q3nz8y52as0vqu0ujzg MULTISIG=erd1qqqqqqqqqqqqqpgqdcat402y6c62hv07gt04rynjg4668z9fs0vq3qxepp +BRIDGE_PROXY=erd1qqqqqqqqqqqqqpgqk09rka2dslnf9ns5eze2s5xw2hfjxm0jzlsqzyjh28 +FAUCET=erd1qqqqqqqqqqqqqpgqhhlx9mpdc92l0psszy3cf9lxhg9vzhs8zlsqjeeqqn +TEST_CALLER=erd1qqqqqqqqqqqqqpgq398fy44g59se3pkmjz8tya39pz5q4tuvpqqqgwffes + +#============v2 CONTRACT ADDRESSES============== +MULTISIG_v2=erd1qqqqqqqqqqqqqpgqu5asufdaxnzxhxgjheuee2mzm28y205rzcqq25xvky +AGGREGATOR_v2=erd1qqqqqqqqqqqqqpgqxgpczmmcjr64ladk2hz05gm6j73usrugzcqqmhhzd0 +BRIDGED_TOKENS_WRAPPER_v2=erd1qqqqqqqqqqqqqpgqgvx0y4c9ael8ha29cvn0c3r6ay5c9heezcqq2nejur #============TOKENS SETTINGS============== NR_DECIMALS_CHAIN_SPECIFIC=6 @@ -35,13 +52,18 @@ UNIVERSAL_TOKEN_DISPLAY_NAME=WrappedUSDC CHAIN_SPECIFIC_TOKEN_TICKER=ETHUSDC CHAIN_SPECIFIC_TOKEN_DISPLAY_NAME=EthereumWrappedUSDC -UNIVERSAL_TOKENS_ALREADY_MINTED=0 +UNIVERSAL_TOKENS_ALREADY_MINTED=0 # do not add the decimals on this value #============TOKENS TO BE WHITELISTED============== -UNIVERSAL_TOKEN=USDT-92ae4e -CHAIN_SPECIFIC_TOKEN=ETHUSDT-41b065 -ERC20_TOKEN=0xbe388e5276035575e672ce795a87d16976ecaacb - +UNIVERSAL_TOKEN= +CHAIN_SPECIFIC_TOKEN=MEX-a659d0 +ERC20_TOKEN=0x2E8e0BBe20Ecd819c721D164fb91F7c33BDFC756 +MINTBURN_WHITELIST=true +NATIVE_TOKEN=true + +TOTAL_BALANCE=0 +MINT_BALANCE=0 +BURN_BALANCE=0 #============BRIDGE SETTINGS============== FEE_AMOUNT=50 # value without decimals @@ -50,21 +72,22 @@ MAX_AMOUNT=100000 # value without decimals RELAYER_REQUIRED_STAKE=0 #1000eGLD SLASH_AMOUNT=0 QUORUM=3 +ORACLE_REQUIRED_STAKE=1 #1EGLD MAX_TX_PER_BATCH=70 MAX_TX_BLOCK_DURATION_PER_BATCH=100 #10minutes #============RELAYERS ADDRESSES============== -RELAYER_ADDR_0=erd1l9hpewk3dd6mz5j0yytjnzqtydukslmsms2d0fn0pg8pc42chqgqk8pm5u -RELAYER_ADDR_1=erd1tfj6fpr5hd5fw8h6efycw42mk3c4wynausntvg6x98kcyn5npkkqmq7t9g -RELAYER_ADDR_2=erd1689ky73s93aptw8ek0wrrzujtus365ygrqgj0hgj4cn09n5k3kuqyhr0j7 -RELAYER_ADDR_3=erd1uae36y2qvrslexcv3mwjqy9lwrlspvkdyjsar2xcj5ctrq7th26q8twvyc -RELAYER_ADDR_4=erd1pkwhtl85ze02ckaf0t6qgycgx863kxyefxyqxumcth0nwtu3a9yqzg2yn2 -RELAYER_ADDR_5=erd197rmyux8ttzuwssh9thsewlzsc766tvpnussqkpew5vm9x63k0kqw56hr7 -RELAYER_ADDR_6=erd1yhqfhsf237uyz4uzzg0duy9hhg8t3j4wtt020c5cy59w2v2jvkgq6nxf0c -RELAYER_ADDR_7=erd1pgvt06tyhlwegkdkzknyhcxfl3wz69wseqeqashm3d83mxjaewzqnug90w -RELAYER_ADDR_8=erd1ujfl0yxff6ey008ef89au4dn486dj549kpjuuu4xxtn9q550x3gqcu6wed -RELAYER_ADDR_9=erd1zsha9cvx7gwraytgp740dcjzwy9v5xwnmas77d33uve6sk0rs0vqel4ln5 +RELAYER_ADDR_0=erd1l9hpewk3dd6mz5j0yytjnzqtydukslmsms2d0fn0pg8pc42chqgqk8pm5u +RELAYER_ADDR_1=erd1tfj6fpr5hd5fw8h6efycw42mk3c4wynausntvg6x98kcyn5npkkqmq7t9g +RELAYER_ADDR_2=erd1689ky73s93aptw8ek0wrrzujtus365ygrqgj0hgj4cn09n5k3kuqyhr0j7 +RELAYER_ADDR_3=erd1uae36y2qvrslexcv3mwjqy9lwrlspvkdyjsar2xcj5ctrq7th26q8twvyc +RELAYER_ADDR_4=erd1pkwhtl85ze02ckaf0t6qgycgx863kxyefxyqxumcth0nwtu3a9yqzg2yn2 +RELAYER_ADDR_5=erd197rmyux8ttzuwssh9thsewlzsc766tvpnussqkpew5vm9x63k0kqw56hr7 +RELAYER_ADDR_6=erd1yhqfhsf237uyz4uzzg0duy9hhg8t3j4wtt020c5cy59w2v2jvkgq6nxf0c +RELAYER_ADDR_7=erd1pgvt06tyhlwegkdkzknyhcxfl3wz69wseqeqashm3d83mxjaewzqnug90w +RELAYER_ADDR_8=erd1ujfl0yxff6ey008ef89au4dn486dj549kpjuuu4xxtn9q550x3gqcu6wed +RELAYER_ADDR_9=erd1zsha9cvx7gwraytgp740dcjzwy9v5xwnmas77d33uve6sk0rs0vqel4ln5 RELAYER_WALLET0="./walletsRelay/${RELAYER_ADDR_0}.pem" RELAYER_WALLET1="./walletsRelay/${RELAYER_ADDR_1}.pem" @@ -77,3 +100,11 @@ RELAYER_WALLET7="./walletsRelay/${RELAYER_ADDR_7}.pem" RELAYER_WALLET8="./walletsRelay/${RELAYER_ADDR_8}.pem" RELAYER_WALLET9="./walletsRelay/${RELAYER_ADDR_9}.pem" +#============ORACLE ADDRESSES============== +ORACLE_ADDR_0=erd1ek7r87m623y94n8htdjhmhwud6vwhxanwl2xzdfl3kccejhefuqqhwjmv2 +ORACLE_ADDR_1=erd1vpz5mpsttd9q5puuaqr7kxfjhwsv2zqqu9jdhyrvkpyfhpnsf5qqhtkkca +ORACLE_ADDR_2=erd10f8xflx9svsje0v2ujggp76jkzyxwpj0rxzgmvx5kle5vqk4f5qqg57m7t + +ORACLE_WALLET0="./walletsOracle/${ORACLE_ADDR_0}.pem" +ORACLE_WALLET1="./walletsOracle/${ORACLE_ADDR_1}.pem" +ORACLE_WALLET2="./walletsOracle/${ORACLE_ADDR_2}.pem" diff --git a/multisig/interaction/config/helper.cfg b/multisig/interaction/config/helper.cfg index 0d8d105e..97a8dc7e 100644 --- a/multisig/interaction/config/helper.cfg +++ b/multisig/interaction/config/helper.cfg @@ -55,6 +55,37 @@ function manual-update-config-file { source $SCRIPTPATH/config/configs.cfg } +function confirmation-multiple { + DISPLAY_STR="" + for var in "$@" + do + DISPLAY_STR="${DISPLAY_STR} & ${var}" + done + + echo -e + read -p "Do you want to go on with ${GREEN}${DISPLAY_STR}${NC} (Default No) ? (Yy/Nn)" yn + echo -e + + case $yn in + [Yy]* ) + + echo -e "${GREEN}Proceeding with ${DISPLAY_STR}!${NC}" + for var in "$@" + do + confirmation ${var} + done + + ;; + [Nn]* ) + echo -e "${GREEN}Exiting...${NC}" + ;; + + * ) + echo -e "${GREEN}I'll take that as a no then... ${NC}" + ;; + esac +} + function update-config { TARGET_KEY=$1 REPLACEMENT_VALUE=$2 diff --git a/multisig/interaction/config/issue-tokens-snippets.sh b/multisig/interaction/config/issue-tokens-snippets.sh index b800bcde..17886593 100644 --- a/multisig/interaction/config/issue-tokens-snippets.sh +++ b/multisig/interaction/config/issue-tokens-snippets.sh @@ -4,7 +4,7 @@ issueUniversalToken() { CHECK_VARIABLES ESDT_SYSTEM_SC_ADDRESS ESDT_ISSUE_COST UNIVERSAL_TOKEN_DISPLAY_NAME \ UNIVERSAL_TOKEN_TICKER NR_DECIMALS_UNIVERSAL - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --value=${ESDT_ISSUE_COST} --function="issue" \ --arguments str:${UNIVERSAL_TOKEN_DISPLAY_NAME} str:${UNIVERSAL_TOKEN_TICKER} \ 0 ${NR_DECIMALS_UNIVERSAL} str:canAddSpecialRoles str:true \ @@ -17,7 +17,7 @@ issueChainSpecificToken() { VALUE_TO_MINT=$(echo "scale=0; $UNIVERSAL_TOKENS_ALREADY_MINTED*10^$NR_DECIMALS_CHAIN_SPECIFIC/1" | bc) - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --value=${ESDT_ISSUE_COST} --function="issue" \ --arguments str:${CHAIN_SPECIFIC_TOKEN_DISPLAY_NAME} str:${CHAIN_SPECIFIC_TOKEN_TICKER} \ ${VALUE_TO_MINT} ${NR_DECIMALS_CHAIN_SPECIFIC} str:canAddSpecialRoles str:true \ @@ -29,21 +29,21 @@ transferToSC() { VALUE_TO_MINT=$(echo "scale=0; $UNIVERSAL_TOKENS_ALREADY_MINTED*10^$NR_DECIMALS_CHAIN_SPECIFIC/1" | bc) - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=5000000 --function="ESDTTransfer" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${VALUE_TO_MINT} str:depositLiquidity \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } setMintRole() { - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="setSpecialRole" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${ALICE_ADDRESS} str:ESDTRoleLocalMint \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } unSetMintRole() { - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="unSetSpecialRole" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${ALICE_ADDRESS} str:ESDTRoleLocalMint \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -53,7 +53,7 @@ mint() { CHECK_VARIABLES NR_DECIMALS_CHAIN_SPECIFIC ALICE_ADDRESS CHAIN_SPECIFIC_TOKEN read -p "Amount to mint(without decimals): " AMOUNT_TO_MINT VALUE_TO_MINT=$(echo "scale=0; $AMOUNT_TO_MINT*10^$NR_DECIMALS_CHAIN_SPECIFIC/1" | bc) - mxpy --verbose contract call ${ALICE_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ALICE_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=300000 --function="ESDTLocalMint" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${VALUE_TO_MINT} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} diff --git a/multisig/interaction/config/mainnet-release-v3.sh b/multisig/interaction/config/mainnet-release-v3.sh new file mode 100644 index 00000000..28479238 --- /dev/null +++ b/multisig/interaction/config/mainnet-release-v3.sh @@ -0,0 +1,25 @@ +deployMultisigMainnetV3() { + CHECK_VARIABLES RELAYER_ADDR_0 RELAYER_ADDR_1 RELAYER_ADDR_2 RELAYER_ADDR_3 \ + RELAYER_ADDR_4 RELAYER_ADDR_5 RELAYER_ADDR_6 RELAYER_ADDR_7 RELAYER_ADDR_8 \ + RELAYER_ADDR_9 SAFE MULTI_TRANSFER BRIDGE_PROXY RELAYER_REQUIRED_STAKE SLASH_AMOUNT QUORUM MULTISIG_WASM + + MIN_STAKE=$(echo "$RELAYER_REQUIRED_STAKE*10^18" | bc) + mxpy contract deploy --bytecode=${MULTISIG_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=200000000 \ + --arguments ${SAFE} ${MULTI_TRANSFER} ${BRIDGE_PROXY} \ + ${MIN_STAKE} ${SLASH_AMOUNT} ${QUORUM} \ + ${RELAYER_ADDR_0} ${RELAYER_ADDR_1} ${RELAYER_ADDR_2} ${RELAYER_ADDR_3} \ + ${RELAYER_ADDR_4} ${RELAYER_ADDR_5} ${RELAYER_ADDR_6} ${RELAYER_ADDR_7} \ + ${RELAYER_ADDR_8} ${RELAYER_ADDR_9} \ + --send --outfile="deploy-testnet.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./deploy-testnet.interaction.json" --expression="data['emitted_tx']['hash']") + ADDRESS=$(mxpy data parse --file="./deploy-testnet.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-testnet-multisig --value=${ADDRESS} + mxpy data store --key=deployTransaction-testnet --value=${TRANSACTION} + + echo "" + echo "Multisig contract address: ${ADDRESS}" + update-config MULTISIG ${ADDRESS} +} \ No newline at end of file diff --git a/multisig/interaction/config/menu_functions.cfg b/multisig/interaction/config/menu_functions.cfg index e7585ccf..844dd030 100644 --- a/multisig/interaction/config/menu_functions.cfg +++ b/multisig/interaction/config/menu_functions.cfg @@ -5,30 +5,13 @@ source $SCRIPTPATH/config/aggregator-snippets.sh source $SCRIPTPATH/config/issue-tokens-snippets.sh source $SCRIPTPATH/config/multisig-snippets.sh source $SCRIPTPATH/config/multitransfer-snippets.sh +source $SCRIPTPATH/config/proxy-snippets.sh source $SCRIPTPATH/config/relayers-snippets.sh -source $SCRIPTPATH/config/upgrade-snippets.sh source $SCRIPTPATH/config/wrapped-snippets.sh source $SCRIPTPATH/config/safe-snippets.sh +source $SCRIPTPATH/config/testing.sh CHECK_VARIABLES ALICE PROXY CHAIN_ID -function deploy-aggregator { - deployAggregator - update-config AGGREGATOR ${ADDRESS} - confirmation-with-skip unpauseAggregator - - echo -e - echo "Aggregator deployed!" - echo -e -} - -function deploy-wrapper { - deployBridgedTokensWrapper - update-config BRIDGED_TOKENS_WRAPPER ${ADDRESS} -} - -function upgrade-wrapper { - wrapper-upgrade -} function upgrade-wrapper-universal-token { wrapper-updateWrappedToken @@ -38,15 +21,43 @@ function upgrade-wrapper-chain-specific-token { wrapper-updateWhitelistedToken } +function init-supply-mint-burn { + initSupplyMintBurn +} + function deploy-bridge-contracts { - deploySafe - update-config SAFE ${ADDRESS} + confirmation-with-skip deployAggregator + confirmation-with-skip manual-update-config-file + confirmation-with-skip stakeOracles + + confirmation-with-skip deployBridgedTokensWrapper + manual-update-config-file confirmation-with-skip deployMultiTransfer - update-config MULTI_TRANSFER ${ADDRESS} + manual-update-config-file + confirmation-with-skip deploySafe + manual-update-config-file + confirmation-with-skip deployBridgeProxy + manual-update-config-file confirmation-with-skip deployMultisig - update-config MULTISIG ${ADDRESS} + manual-update-config-file + + confirmation-with-skip setBridgeProxyContractAddressOnMultiTransfer + confirmation-with-skip setBridgedTokensWrapperOnMultiTransfer + + confirmation-with-skip setBridgedTokensWrapperOnSCProxy + confirmation-with-skip setMultiTransferOnSCProxy + confirmation-with-skip setEsdtSafeOnSCProxy + + confirmation-with-skip setBridgedTokensWrapperOnEsdtSafe + confirmation-with-skip setSCProxyOnEsdtSafe + confirmation-with-skip changeChildContractsOwnershipSafe confirmation-with-skip changeChildContractsOwnershipMultiTransfer + confirmation-with-skip changeChildContractsOwnershipProxy + + confirmation-with-skip setEsdtSafeOnMultiTransferThroughMultisig + + confirmation-with-skip stakeRelayers } function remove-whitelist-token { @@ -84,7 +95,6 @@ function whitelist-token { confirmation-with-skip addWrappedToken confirmation-with-skip wrapper-whitelistToken confirmation-with-skip setLocalRolesEsdtSafe - confirmation-with-skip setLocalRolesMultiTransferEsdt confirmation-with-skip addMapping confirmation-with-skip addTokenToWhitelist echo -e @@ -92,6 +102,23 @@ function whitelist-token { echo -e confirmation-with-skip manual-update-config-file + confirmation-with-skip setPairDecimals + confirmation-with-skip submitAggregatorBatch + + confirmation-with-skip esdtSafeSetMaxBridgedAmountForToken + confirmation-with-skip multiTransferEsdtSetMaxBridgedAmountForToken +} + +function whitelist-native-token { + confirmation-with-skip setLocalRolesEsdtSafe + confirmation-with-skip addMapping + confirmation-with-skip addTokenToWhitelist + echo -e + echo "Update FEE_AMOUNT and MAX_AMOUNT in BRIDGE SETTINGS section in configs.cfg" + echo -e + confirmation-with-skip manual-update-config-file + + confirmation-with-skip setPairDecimals confirmation-with-skip submitAggregatorBatch confirmation-with-skip esdtSafeSetMaxBridgedAmountForToken @@ -121,6 +148,7 @@ function pause-contracts { confirmation-with-skip pauseEsdtSafe confirmation-with-skip pauseAggregator confirmation-with-skip wrapper-pause + confirmation-with-skip pauseProxy } function unpause-contracts { @@ -128,6 +156,7 @@ function unpause-contracts { confirmation-with-skip unpauseEsdtSafe confirmation-with-skip unpauseAggregator confirmation-with-skip wrapper-unpause + confirmation-with-skip unpauseProxy } function set-fee { @@ -140,4 +169,54 @@ function mint-chain-specific { update-config UNIVERSAL_TOKENS_ALREADY_MINTED ${AMOUNT_TO_MINT} confirmation-with-skip transferToSC confirmation-with-skip unSetMintRole -} \ No newline at end of file +} + +function upgrade-aggregator { + aggregator-upgrade +} + +function upgrade-wrapper { + wrapper-upgrade +} + +function upgrade-safe { + confirmation-with-skip deploySafeForUpgrade + confirmation-with-skip upgradeSafeContract +} + +function upgrade-multi-transfer { + confirmation-with-skip deployMultiTransferForUpgrade + confirmation-with-skip upgradeMultiTransferContract +} + +function upgrade-proxy { + confirmation-with-skip deployBridgeProxyForUpgrade + confirmation-with-skip upgradeBridgeProxyContract +} + +function upgrade-multisig { + confirmation-with-skip upgradeMultisig +} + +function faucet-deposit { + confirmation-with-skip deployFaucet + echo -e + echo "Update UNIVERSAL_TOKEN and NR_DECIMALS_UNIVERSAL in BRIDGE SETTINGS section in configs.cfg" + echo -e + confirmation-with-skip manual-update-config-file + + confirmation-with-skip setMintRoleForUniversalToken + confirmation-with-skip mintAndDeposit + confirmation-with-skip unSetMintRoleForUniversalToken +} + +function deploy-test-caller { + confirmation-with-skip deployTestCaller +} + +function pause-v2-contracts { + confirmation-with-skip pauseV2 + confirmation-with-skip pauseEsdtSafeV2 + confirmation-with-skip pauseAggregatorV2 + confirmation-with-skip wrapper-pauseV2 +} diff --git a/multisig/interaction/config/multisig-snippets.sh b/multisig/interaction/config/multisig-snippets.sh index 2037bfc1..8485a624 100644 --- a/multisig/interaction/config/multisig-snippets.sh +++ b/multisig/interaction/config/multisig-snippets.sh @@ -1,12 +1,12 @@ deployMultisig() { CHECK_VARIABLES RELAYER_ADDR_0 RELAYER_ADDR_1 RELAYER_ADDR_2 RELAYER_ADDR_3 \ RELAYER_ADDR_4 RELAYER_ADDR_5 RELAYER_ADDR_6 RELAYER_ADDR_7 RELAYER_ADDR_8 \ - RELAYER_ADDR_9 SAFE MULTI_TRANSFER RELAYER_REQUIRED_STAKE SLASH_AMOUNT QUORUM MULTISIG_WASM + RELAYER_ADDR_9 SAFE MULTI_TRANSFER BRIDGE_PROXY RELAYER_REQUIRED_STAKE SLASH_AMOUNT QUORUM MULTISIG_WASM MIN_STAKE=$(echo "$RELAYER_REQUIRED_STAKE*10^18" | bc) - mxpy --verbose contract deploy --bytecode=${MULTISIG_WASM} --recall-nonce --pem=${ALICE} \ + mxpy contract deploy --bytecode=${MULTISIG_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=200000000 \ - --arguments ${SAFE} ${MULTI_TRANSFER} \ + --arguments ${SAFE} ${MULTI_TRANSFER} ${BRIDGE_PROXY} \ ${MIN_STAKE} ${SLASH_AMOUNT} ${QUORUM} \ ${RELAYER_ADDR_0} ${RELAYER_ADDR_1} ${RELAYER_ADDR_2} ${RELAYER_ADDR_3} \ --send --outfile="deploy-testnet.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return @@ -19,12 +19,22 @@ deployMultisig() { echo "" echo "Multisig contract address: ${ADDRESS}" + update-config MULTISIG ${ADDRESS} } changeChildContractsOwnershipSafe() { CHECK_VARIABLES SAFE MULTISIG - mxpy --verbose contract call ${SAFE} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${SAFE} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=10000000 --function="ChangeOwnerAddress" \ + --arguments ${MULTISIG} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +changeChildContractsOwnershipProxy() { + CHECK_VARIABLES BRIDGE_PROXY MULTISIG + + mxpy contract call ${BRIDGE_PROXY} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=10000000 --function="ChangeOwnerAddress" \ --arguments ${MULTISIG} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -33,7 +43,7 @@ changeChildContractsOwnershipSafe() { changeChildContractsOwnershipMultiTransfer() { CHECK_VARIABLES MULTI_TRANSFER MULTISIG - mxpy --verbose contract call ${MULTI_TRANSFER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTI_TRANSFER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=10000000 --function="ChangeOwnerAddress" \ --arguments ${MULTISIG} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -42,7 +52,7 @@ changeChildContractsOwnershipMultiTransfer() { clearMapping() { CHECK_VARIABLES ERC20_TOKEN CHAIN_SPECIFIC_TOKEN MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="clearMapping" \ --arguments ${ERC20_TOKEN} str:${CHAIN_SPECIFIC_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -51,25 +61,29 @@ clearMapping() { addMapping() { CHECK_VARIABLES ERC20_TOKEN CHAIN_SPECIFIC_TOKEN MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="addMapping" \ --arguments ${ERC20_TOKEN} str:${CHAIN_SPECIFIC_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } addTokenToWhitelist() { - CHECK_VARIABLES CHAIN_SPECIFIC_TOKEN CHAIN_SPECIFIC_TOKEN_TICKER MULTISIG + CHECK_VARIABLES CHAIN_SPECIFIC_TOKEN CHAIN_SPECIFIC_TOKEN_TICKER MULTISIG MINTBURN_WHITELIST NATIVE_TOKEN - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + BALANCE=$(echo "$TOTAL_BALANCE*10^$NR_DECIMALS_CHAIN_SPECIFIC" | bc) + MINT=$(echo "$MINT_BALANCE*10^$NR_DECIMALS_CHAIN_SPECIFIC" | bc) + BURN=$(echo "$BURN_BALANCE*10^$NR_DECIMALS_CHAIN_SPECIFIC" | bc) + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="esdtSafeAddTokenToWhitelist" \ - --arguments str:${CHAIN_SPECIFIC_TOKEN} str:${CHAIN_SPECIFIC_TOKEN_TICKER} \ - --send --proxy=${PROXY} --chain=${CHAIN_ID} + --arguments str:${CHAIN_SPECIFIC_TOKEN} str:${CHAIN_SPECIFIC_TOKEN_TICKER} ${MINTBURN_WHITELIST} ${NATIVE_TOKEN} \ + ${BALANCE} ${MINT} ${BURN} --send --proxy=${PROXY} --chain=${CHAIN_ID} } removeTokenFromWhitelist() { CHECK_VARIABLES CHAIN_SPECIFIC_TOKEN CHAIN_SPECIFIC_TOKEN_TICKER MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="esdtSafeRemoveTokenFromWhitelist" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -78,7 +92,7 @@ removeTokenFromWhitelist() { esdtSafeSetMaxTxBatchSize() { CHECK_VARIABLES MAX_TX_PER_BATCH MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=30000000 --function="esdtSafeSetMaxTxBatchSize" \ --arguments ${MAX_TX_PER_BATCH} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -87,7 +101,7 @@ esdtSafeSetMaxTxBatchSize() { esdtSafeSetMaxTxBatchBlockDuration() { CHECK_VARIABLES MAX_TX_BLOCK_DURATION_PER_BATCH MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=30000000 --function="esdtSafeSetMaxTxBatchBlockDuration" \ --arguments ${MAX_TX_BLOCK_DURATION_PER_BATCH} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -96,7 +110,7 @@ esdtSafeSetMaxTxBatchBlockDuration() { clearMapping() { CHECK_VARIABLES ERC20_TOKEN CHAIN_SPECIFIC_TOKEN MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="clearMapping" \ --arguments ${ERC20_TOKEN} str:${CHAIN_SPECIFIC_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -105,7 +119,7 @@ clearMapping() { changeQuorum() { CHECK_VARIABLES QUORUM MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="changeQuorum" \ --arguments ${QUORUM} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -114,7 +128,15 @@ changeQuorum() { pause() { CHECK_VARIABLES MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=40000000 --function="pause" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +pauseV2() { + CHECK_VARIABLES MULTISIG_v2 + + mxpy contract call ${MULTISIG_v2} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="pause" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } @@ -122,15 +144,31 @@ pause() { pauseEsdtSafe() { CHECK_VARIABLES MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="pauseEsdtSafe" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } +pauseEsdtSafeV2() { + CHECK_VARIABLES MULTISIG_v2 + + mxpy contract call ${MULTISIG_v2} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=40000000 --function="pauseEsdtSafe" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +pauseProxy() { + CHECK_VARIABLES MULTISIG + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=40000000 --function="pauseProxy" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + unpause() { CHECK_VARIABLES MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="unpause" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } @@ -138,16 +176,24 @@ unpause() { unpauseEsdtSafe() { CHECK_VARIABLES MULTISIG - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="unpauseEsdtSafe" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } +unpauseProxy() { + CHECK_VARIABLES MULTISIG + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=40000000 --function="unpauseProxy" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + esdtSafeSetMaxBridgedAmountForToken() { CHECK_VARIABLES MAX_AMOUNT NR_DECIMALS_CHAIN_SPECIFIC CHAIN_SPECIFIC_TOKEN MULTISIG MAX=$(echo "scale=0; $MAX_AMOUNT*10^$NR_DECIMALS_CHAIN_SPECIFIC/1" | bc) - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="esdtSafeSetMaxBridgedAmountForToken" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${MAX} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -157,8 +203,62 @@ multiTransferEsdtSetMaxBridgedAmountForToken() { CHECK_VARIABLES MAX_AMOUNT NR_DECIMALS_CHAIN_SPECIFIC CHAIN_SPECIFIC_TOKEN MULTISIG MAX=$(echo "scale=0; $MAX_AMOUNT*10^$NR_DECIMALS_CHAIN_SPECIFIC/1" | bc) - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=40000000 --function="multiTransferEsdtSetMaxBridgedAmountForToken" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${MAX} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } + + +setMultiTransferOnEsdtSafeThroughMultisig() { + CHECK_VARIABLES MULTISIG + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setMultiTransferOnEsdtSafe" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +setEsdtSafeOnMultiTransferThroughMultisig() { + CHECK_VARIABLES MULTISIG + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setEsdtSafeOnMultiTransfer" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +initSupplyMintBurn() { + CHECK_VARIABLES MULTISIG + + echo -e + echo "PREREQUIREMENTS: The MINT_BALANCE & BURN_BALANCE values should be defined in configs.cfg file" + echo "The script automatically apply denomination factors based on the number of the decimals the token has" + echo -e + + confirmation-with-skip manual-update-config-file + + MINT=$(echo "$MINT_BALANCE*10^$NR_DECIMALS_CHAIN_SPECIFIC" | bc) + BURN=$(echo "$BURN_BALANCE*10^$NR_DECIMALS_CHAIN_SPECIFIC" | bc) + + MINT=$(echo ${MINT%.*}) # trim decimals, if existing + BURN=$(echo ${BURN%.*}) # trim decimals, if existing + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="initSupplyMintBurnEsdtSafe" \ + --arguments str:${CHAIN_SPECIFIC_TOKEN} ${MINT} ${BURN} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +upgradeMultisig() { + CHECK_VARIABLES SAFE MULTI_TRANSFER BRIDGE_PROXY MULTISIG_WASM + + mxpy contract upgrade ${MULTISIG} --bytecode=${MULTISIG_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=100000000 --send \ + --arguments ${SAFE} ${MULTI_TRANSFER} ${BRIDGE_PROXY} \ + --outfile="upgrade-multisig-child-sc.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./upgrade-multisig-child-sc.json" --expression="data['emitted_tx']['hash']") + ADDRESS=$(mxpy data parse --file="./upgrade-multisig-child-sc.json" --expression="data['contractAddress']") + + echo "" + echo "Multisig contract updated: ${ADDRESS}" +} diff --git a/multisig/interaction/config/multitransfer-snippets.sh b/multisig/interaction/config/multitransfer-snippets.sh index 38304735..4dcff5b9 100644 --- a/multisig/interaction/config/multitransfer-snippets.sh +++ b/multisig/interaction/config/multitransfer-snippets.sh @@ -1,9 +1,8 @@ deployMultiTransfer() { - CHECK_VARIABLES MULTI_TRANSFER_WASM BRIDGED_TOKENS_WRAPPER + CHECK_VARIABLES MULTI_TRANSFER_WASM - mxpy --verbose contract deploy --bytecode=${MULTI_TRANSFER_WASM} --recall-nonce --pem=${ALICE} \ - --gas-limit=100000000 \ - --arguments ${BRIDGED_TOKENS_WRAPPER} --metadata-payable \ + mxpy contract deploy --bytecode=${MULTI_TRANSFER_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=100000000 --metadata-payable \ --send --outfile="deploy-multitransfer-testnet.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return ADDRESS=$(mxpy data parse --file="./deploy-multitransfer-testnet.interaction.json" --expression="data['contractAddress']") @@ -11,22 +10,46 @@ deployMultiTransfer() { echo "" echo "Multi transfer contract address: ${ADDRESS}" + update-config MULTI_TRANSFER ${ADDRESS} } -setLocalRolesMultiTransferEsdt() { - CHECK_VARIABLES ESDT_SYSTEM_SC_ADDRESS CHAIN_SPECIFIC_TOKEN MULTI_TRANSFER +setBridgeProxyContractAddressOnMultiTransfer() { + CHECK_VARIABLES MULTI_TRANSFER BRIDGE_PROXY - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ - --gas-limit=60000000 --function="setSpecialRole" \ - --arguments str:${CHAIN_SPECIFIC_TOKEN} ${MULTI_TRANSFER} str:ESDTRoleLocalMint \ + mxpy contract call ${MULTI_TRANSFER} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setBridgeProxyContractAddress" \ + --arguments ${BRIDGE_PROXY} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } -unsetLocalRolesMultiTransferEsdt() { - CHECK_VARIABLES ESDT_SYSTEM_SC_ADDRESS CHAIN_SPECIFIC_TOKEN MULTI_TRANSFER +setBridgedTokensWrapperOnMultiTransfer() { + CHECK_VARIABLES MULTI_TRANSFER BRIDGED_TOKENS_WRAPPER - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ - --gas-limit=60000000 --function="unSetSpecialRole" \ - --arguments str:${CHAIN_SPECIFIC_TOKEN} ${MULTI_TRANSFER} str:ESDTRoleLocalMint \ + mxpy contract call ${MULTI_TRANSFER} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setWrappingContractAddress" \ + --arguments ${BRIDGED_TOKENS_WRAPPER} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} -} \ No newline at end of file +} + +deployMultiTransferForUpgrade() { + CHECK_VARIABLES MULTI_TRANSFER_WASM + + mxpy contract deploy --bytecode=${MULTI_TRANSFER_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=100000000 --metadata-payable \ + --send --outfile="deploy-multitransfer-upgrade.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./deploy-multitransfer-upgrade.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="./deploy-multitransfer-upgrade.interaction.json" --expression="data['contractAddress']") + + echo "" + echo "New multi transfer contract address: ${ADDRESS}" +} + +upgradeMultiTransferContract() { + local NEW_MULTI_TRANSFER_ADDR=$(mxpy data parse --file="./deploy-multitransfer-upgrade.interaction.json" --expression="data['contractAddress']") + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=400000000 --function="upgradeChildContractFromSource" \ + --arguments ${MULTI_TRANSFER} ${NEW_MULTI_TRANSFER_ADDR} 0x00 \ + --send --outfile="upgrade-multitransfer-child-sc.json" --proxy=${PROXY} --chain=${CHAIN_ID} +} diff --git a/multisig/interaction/config/proxy-snippets.sh b/multisig/interaction/config/proxy-snippets.sh new file mode 100644 index 00000000..2db7d8d4 --- /dev/null +++ b/multisig/interaction/config/proxy-snippets.sh @@ -0,0 +1,69 @@ +deployBridgeProxy() { + CHECK_VARIABLES PROXY_WASM MULTI_TRANSFER + + mxpy contract deploy --bytecode=${PROXY_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=200000000 \ + --arguments ${MULTI_TRANSFER} \ + --send --outfile="deploy-proxy-testnet.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./deploy-proxy-testnet.interaction.json" --expression="data['emitted_tx']['hash']") + ADDRESS=$(mxpy data parse --file="./deploy-proxy-testnet.interaction.json" --expression="data['contractAddress']") + + # mxpy data store --key=address-testnet-proxy --value=${ADDRESS} + # mxpy data store --key=deployTransaction-testnet --value=${TRANSACTION} + + echo "" + echo "Proxy contract address: ${ADDRESS}" + update-config BRIDGE_PROXY ${ADDRESS} +} + +setBridgedTokensWrapperOnSCProxy() { + CHECK_VARIABLES BRIDGE_PROXY BRIDGED_TOKENS_WRAPPER + + mxpy contract call ${BRIDGE_PROXY} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setBridgedTokensWrapperAddress" \ + --arguments ${BRIDGED_TOKENS_WRAPPER} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +setMultiTransferOnSCProxy() { + CHECK_VARIABLES BRIDGE_PROXY MULTI_TRANSFER + + mxpy contract call ${BRIDGE_PROXY} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setMultiTransferAddress" \ + --arguments ${MULTI_TRANSFER} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +setEsdtSafeOnSCProxy() { + CHECK_VARIABLES BRIDGE_PROXY SAFE + + mxpy contract call ${BRIDGE_PROXY} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setEsdtSafeAddress" \ + --arguments ${SAFE} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +deployBridgeProxyForUpgrade() { + CHECK_VARIABLES PROXY_WASM MULTI_TRANSFER + + mxpy contract deploy --bytecode=${PROXY_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=200000000 \ + --arguments ${MULTI_TRANSFER} \ + --send --outfile="deploy-proxy-upgrade.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./deploy-proxy-upgrade.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="./deploy-proxy-upgrade.interaction.json" --expression="data['contractAddress']") + + echo "" + echo "New proxy contract address: ${ADDRESS}" +} + +upgradeBridgeProxyContract() { + local NEW_BRIDGE_PROXY_ADDR=$(mxpy data parse --file="./deploy-proxy-upgrade.interaction.json" --expression="data['contractAddress']") + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=400000000 --function="upgradeChildContractFromSource" \ + --arguments ${BRIDGE_PROXY} ${NEW_BRIDGE_PROXY_ADDR} 0x00 \ + --send --outfile="upgrade-proxy-child-sc.json" --proxy=${PROXY} --chain=${CHAIN_ID} +} diff --git a/multisig/interaction/config/relayers-snippets.sh b/multisig/interaction/config/relayers-snippets.sh index 3528a641..5a416943 100644 --- a/multisig/interaction/config/relayers-snippets.sh +++ b/multisig/interaction/config/relayers-snippets.sh @@ -2,7 +2,7 @@ addBoardMember() { CHECK_VARIABLES MULTISIG read -p "Relayer address: " RELAYER_ADDR - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=35000000 --function="addBoardMember" --arguments ${RELAYER_ADDR} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } @@ -11,7 +11,7 @@ removeBoardMember() { CHECK_VARIABLES MULTISIG read -p "Relayer address: " RELAYER_ADDR - mxpy --verbose contract call ${MULTISIG} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=35000000 --function="removeUser" --arguments ${RELAYER_ADDR} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } @@ -27,7 +27,7 @@ unstake() { --send --proxy=${PROXY} --chain=${CHAIN_ID} } -stake() { +stakeRelayers() { CHECK_VARIABLES MULTISIG RELAYER_REQUIRED_STAKE \ RELAYER_WALLET0 RELAYER_WALLET1 RELAYER_WALLET2 RELAYER_WALLET3 RELAYER_WALLET4 \ RELAYER_WALLET5 RELAYER_WALLET6 RELAYER_WALLET7 RELAYER_WALLET8 RELAYER_WALLET9 diff --git a/multisig/interaction/config/safe-snippets.sh b/multisig/interaction/config/safe-snippets.sh index 636c5cbc..506939a5 100644 --- a/multisig/interaction/config/safe-snippets.sh +++ b/multisig/interaction/config/safe-snippets.sh @@ -1,9 +1,9 @@ deploySafe() { - CHECK_VARIABLES SAFE_WASM AGGREGATOR + CHECK_VARIABLES SAFE_WASM MULTI_TRANSFER AGGREGATOR - mxpy --verbose contract deploy --bytecode=${SAFE_WASM} --recall-nonce --pem=${ALICE} \ + mxpy contract deploy --bytecode=${SAFE_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=150000000 \ - --arguments ${AGGREGATOR} 1 \ + --arguments ${AGGREGATOR} ${MULTI_TRANSFER} 1 \ --send --outfile="deploy-safe-testnet.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return TRANSACTION=$(mxpy data parse --file="./deploy-safe-testnet.interaction.json" --expression="data['emittedTransactionHash']") @@ -14,22 +14,66 @@ deploySafe() { echo "" echo "Safe contract address: ${ADDRESS}" + update-config SAFE ${ADDRESS} } setLocalRolesEsdtSafe() { CHECK_VARIABLES ESDT_SYSTEM_SC_ADDRESS CHAIN_SPECIFIC_TOKEN SAFE - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="setSpecialRole" \ - --arguments str:${CHAIN_SPECIFIC_TOKEN} ${SAFE} str:ESDTRoleLocalBurn \ + --arguments str:${CHAIN_SPECIFIC_TOKEN} ${SAFE} str:ESDTRoleLocalBurn str:ESDTRoleLocalMint \ --send --proxy=${PROXY} --chain=${CHAIN_ID} } unsetLocalRolesEsdtSafe() { CHECK_VARIABLES ESDT_SYSTEM_SC_ADDRESS CHAIN_SPECIFIC_TOKEN SAFE - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="unSetSpecialRole" \ - --arguments str:${CHAIN_SPECIFIC_TOKEN} ${SAFE} str:ESDTRoleLocalBurn \ + --arguments str:${CHAIN_SPECIFIC_TOKEN} ${SAFE} str:ESDTRoleLocalBurn str:ESDTRoleLocalMint \ --send --proxy=${PROXY} --chain=${CHAIN_ID} -} \ No newline at end of file +} + +setBridgedTokensWrapperOnEsdtSafe() { + CHECK_VARIABLES SAFE BRIDGED_TOKENS_WRAPPER + + mxpy contract call ${SAFE} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setBridgedTokensWrapperAddress" \ + --arguments ${BRIDGED_TOKENS_WRAPPER} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +setSCProxyOnEsdtSafe() { + CHECK_VARIABLES SAFE BRIDGE_PROXY + + mxpy contract call ${SAFE} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setBridgeProxyContractAddress" \ + --arguments ${BRIDGE_PROXY} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +deploySafeForUpgrade() { + CHECK_VARIABLES SAFE_WASM MULTI_TRANSFER AGGREGATOR BRIDGE_PROXY + + mxpy contract deploy --bytecode=${SAFE_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=150000000 \ + --arguments ${AGGREGATOR} ${MULTI_TRANSFER} 1 \ + --send --outfile="deploy-safe-upgrade.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./deploy-safe-upgrade.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="./deploy-safe-upgrade.interaction.json" --expression="data['contractAddress']") + + echo "" + echo "New safe contract address: ${ADDRESS}" +} + +upgradeSafeContract() { + local NEW_SAFE_ADDR=$(mxpy data parse --file="./deploy-safe-upgrade.interaction.json" --expression="data['contractAddress']") + + mxpy contract call ${MULTISIG} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=400000000 --function="upgradeChildContractFromSource" \ + --arguments ${SAFE} ${NEW_SAFE_ADDR} 0x00 \ + ${AGGREGATOR} ${MULTI_TRANSFER} ${BRIDGE_PROXY} 1 \ + --send --outfile="upgrade-safe-child-sc.json" --proxy=${PROXY} --chain=${CHAIN_ID} +} diff --git a/multisig/interaction/config/testing.sh b/multisig/interaction/config/testing.sh new file mode 100644 index 00000000..d7426120 --- /dev/null +++ b/multisig/interaction/config/testing.sh @@ -0,0 +1,71 @@ +deployFaucet() { + CHECK_VARIABLES FAUCET_WASM ALICE + + mxpy contract deploy --bytecode=${FAUCET_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=20000000 \ + --send --outfile=deploy-faucet-testnet.interaction.json --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./deploy-faucet-testnet.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="./deploy-faucet-testnet.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-testnet-faucet --value=${ADDRESS} + mxpy data store --key=deployTransaction-testnet --value=${TRANSACTION} + + echo "" + echo "Faucet: ${ADDRESS}" + update-config FAUCET ${ADDRESS} +} + +setMintRoleForUniversalToken() { + CHECK_VARIABLES ALICE ALICE_ADDRESS + + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="setSpecialRole" \ + --arguments str:${UNIVERSAL_TOKEN} ${ALICE_ADDRESS} str:ESDTRoleLocalMint \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +mintAndDeposit() { + CHECK_VARIABLES ALICE ALICE_ADDRESS FAUCET + + read -p "Amount to mint (without decimals): " AMOUNT_TO_MINT + VALUE_TO_MINT=$(echo "scale=0; $AMOUNT_TO_MINT*10^$NR_DECIMALS_UNIVERSAL/1" | bc) + mxpy contract call ${ALICE_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=300000 --function="ESDTLocalMint" \ + --arguments str:${UNIVERSAL_TOKEN} ${VALUE_TO_MINT} \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} + + sleep 6 + + mxpy contract call ${FAUCET} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=5000000 --function="ESDTTransfer" \ + --arguments str:${UNIVERSAL_TOKEN} ${VALUE_TO_MINT} str:deposit 100 \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +unSetMintRoleForUniversalToken() { + CHECK_VARIABLES ALICE ALICE_ADDRESS ESDT_SYSTEM_SC_ADDRESS + + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 --function="unSetSpecialRole" \ + --arguments str:${UNIVERSAL_TOKEN} ${ALICE_ADDRESS} str:ESDTRoleLocalMint \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} +} + +deployTestCaller() { + CHECK_VARIABLES TEST_CALLER_WASM ALICE + + mxpy contract deploy --bytecode=${TEST_CALLER_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=20000000 \ + --send --outfile=deploy-test-caller.interaction.json --proxy=${PROXY} --chain=${CHAIN_ID} || return + + TRANSACTION=$(mxpy data parse --file="./deploy-test-caller.interaction.json" --expression="data['emittedTransactionHash']") + ADDRESS=$(mxpy data parse --file="./deploy-test-caller.interaction.json" --expression="data['contractAddress']") + + mxpy data store --key=address-test-caller --value=${ADDRESS} + mxpy data store --key=deployTransaction-testnet --value=${TRANSACTION} + + echo "" + echo "Test caller: ${ADDRESS}" + update-config TEST_CALLER ${ADDRESS} +} diff --git a/multisig/interaction/config/upgrade-snippets.sh b/multisig/interaction/config/upgrade-snippets.sh deleted file mode 100644 index 5eeb077f..00000000 --- a/multisig/interaction/config/upgrade-snippets.sh +++ /dev/null @@ -1,53 +0,0 @@ -#TODO: check & updates upgrade snippets -deploySafeForUpgrade() { - getAggregatorAddressHex - - local ESDT_SAFE_ETH_TX_GAS_LIMIT=20000 # gives us 200$ for elrond->eth - - mxpy --verbose contract deploy --project=${PROJECT_SAFE} --recall-nonce --pem=${ALICE} \ - --gas-limit=150000000 \ - --arguments 0x${AGGREGATOR_ADDRESS_HEX} ${ESDT_SAFE_ETH_TX_GAS_LIMIT} \ - --send --outfile="deploy-safe-upgrade.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return - - ADDRESS=$(mxpy data parse --file="./deploy-safe-upgrade.interaction.json" --expression="data['contractAddress']") - - echo "" - echo "Safe contract address: ${ADDRESS}" -} - - -upgradeSafeContract() { - getEsdtSafeAddressHex - getAggregatorAddressHex - local ESDT_SAFE_ETH_TX_GAS_LIMIT=20000 - - local NEW_SAFE_BECH=$(mxpy data parse --file="./deploy-safe-upgrade.interaction.json" --expression="data['contractAddress']") - local NEW_SAFE_ADDR=$(mxpy wallet bech32 --decode $NEW_SAFE_BECH) - - - - mxpy --verbose contract call ${ADDRESS} --recall-nonce --pem=${ALICE} \ - --gas-limit=400000000 --function="upgradeChildContractFromSource" \ - --arguments 0x${ESDT_SAFE_ADDRESS_HEX} 0x${NEW_SAFE_ADDR} 0x00 \ - 0x${AGGREGATOR_ADDRESS_HEX} ${ESDT_SAFE_ETH_TX_GAS_LIMIT} \ - --send --outfile="upgradesafe-child-sc-spam.json" --proxy=${PROXY} --chain=${CHAIN_ID} -} - -upgrade() { - mxpy --verbose contract upgrade ${ADDRESS} --project=${PROJECT} --recall-nonce --pem=${ALICE} \ - --gas-limit=100000000 --send --outfile="upgrade.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return -} - -upgradeMultisig() { - getMultiTransferEsdtAddressHex - getEsdtSafeAddressHex - getMultiTransferEsdtAddressHex - - local SLASH_AMOUNT=0x00 # 0 - MIN_STAKE=$(echo "$RELAYER_REQUIRED_STAKE*10^18" | bc) - mxpy --verbose contract upgrade ${ADDRESS} --bytecode=../output/multisig.wasm --recall-nonce --pem=${ALICE} \ - --arguments 0x${ESDT_SAFE_ADDRESS_HEX} 0x${MULTI_TRANSFER_ESDT_ADDRESS_HEX} \ - ${local} ${SLASH_AMOUNT} 0x07 \ - --gas-limit=200000000 --send --outfile="upgrade-multisig.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return - -} \ No newline at end of file diff --git a/multisig/interaction/config/wrapped-snippets.sh b/multisig/interaction/config/wrapped-snippets.sh index 4985d888..1bcc3e73 100644 --- a/multisig/interaction/config/wrapped-snippets.sh +++ b/multisig/interaction/config/wrapped-snippets.sh @@ -8,8 +8,8 @@ deployBridgedTokensWrapper() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER_WASM - mxpy --verbose contract deploy --bytecode=${BRIDGED_TOKENS_WRAPPER_WASM} --recall-nonce --pem=${ALICE} \ - --gas-limit=30000000 \ + mxpy contract deploy --bytecode=${BRIDGED_TOKENS_WRAPPER_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=60000000 \ --send --outfile="deploy-bridged-tokens-wrapper-testnet.interaction.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return TRANSACTION=$(mxpy data parse --file="./deploy-bridged-tokens-wrapper-testnet.interaction.json" --expression="data['emittedTransactionHash']") @@ -20,12 +20,13 @@ deployBridgedTokensWrapper() { echo "" echo "Bridged tokens wrapper SC: ${ADDRESS}" + update-config BRIDGED_TOKENS_WRAPPER ${ADDRESS} } setLocalRolesBridgedTokensWrapper() { CHECK_VARIABLES ESDT_SYSTEM_SC_ADDRESS UNIVERSAL_TOKEN BRIDGED_TOKENS_WRAPPER - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="setSpecialRole" \ --arguments str:${UNIVERSAL_TOKEN} ${BRIDGED_TOKENS_WRAPPER} str:ESDTRoleLocalMint str:ESDTRoleLocalBurn\ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -34,7 +35,7 @@ setLocalRolesBridgedTokensWrapper() { unsetLocalRolesBridgedTokensWrapper() { CHECK_VARIABLES ESDT_SYSTEM_SC_ADDRESS UNIVERSAL_TOKEN BRIDGED_TOKENS_WRAPPER - mxpy --verbose contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${ESDT_SYSTEM_SC_ADDRESS} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=60000000 --function="unSetSpecialRole" \ --arguments str:${UNIVERSAL_TOKEN} ${BRIDGED_TOKENS_WRAPPER} str:ESDTRoleLocalMint str:ESDTRoleLocalBurn\ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -43,7 +44,7 @@ unsetLocalRolesBridgedTokensWrapper() { addWrappedToken() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER UNIVERSAL_TOKEN NR_DECIMALS_UNIVERSAL - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=6000000 --function="addWrappedToken" \ --arguments str:${UNIVERSAL_TOKEN} ${NR_DECIMALS_UNIVERSAL} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -52,7 +53,7 @@ addWrappedToken() { removeWrappedToken() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER UNIVERSAL_TOKEN - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=6000000 --function="removeWrappedToken" \ --arguments str:${UNIVERSAL_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -61,7 +62,7 @@ removeWrappedToken() { removeWrappedToken() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER UNIVERSAL_TOKEN - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=6000000 --function="removeWrappedToken" \ --arguments str:${UNIVERSAL_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -70,7 +71,7 @@ removeWrappedToken() { wrapper-whitelistToken() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER CHAIN_SPECIFIC_TOKEN NR_DECIMALS_CHAIN_SPECIFIC UNIVERSAL_TOKEN - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=6000000 --function="whitelistToken" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${NR_DECIMALS_CHAIN_SPECIFIC} str:${UNIVERSAL_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -79,7 +80,7 @@ wrapper-whitelistToken() { wrapper-blacklistToken() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER CHAIN_SPECIFIC_TOKEN UNIVERSAL_TOKEN - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=6000000 --function="blacklistToken" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -88,7 +89,7 @@ wrapper-blacklistToken() { wrapper-updateWrappedToken() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER UNIVERSAL_TOKEN NR_DECIMALS_UNIVERSAL - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=6000000 --function="updateWrappedToken" \ --arguments str:${UNIVERSAL_TOKEN} ${NR_DECIMALS_UNIVERSAL} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -97,7 +98,7 @@ wrapper-updateWrappedToken() { wrapper-updateWhitelistedToken() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER CHAIN_SPECIFIC_TOKEN NR_DECIMALS_CHAIN_SPECIFIC - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=6000000 --function="updateWhitelistedToken" \ --arguments str:${CHAIN_SPECIFIC_TOKEN} ${NR_DECIMALS_CHAIN_SPECIFIC} \ --send --proxy=${PROXY} --chain=${CHAIN_ID} @@ -107,7 +108,7 @@ wrapper-updateWhitelistedToken() { wrapper-unpause() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=5000000 --function="unpause" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} || return } @@ -115,7 +116,15 @@ wrapper-unpause() { wrapper-pause() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER - mxpy --verbose contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce --pem=${ALICE} \ + mxpy contract call ${BRIDGED_TOKENS_WRAPPER} --recall-nonce "${MXPY_SIGN[@]}" \ + --gas-limit=5000000 --function="pause" \ + --send --proxy=${PROXY} --chain=${CHAIN_ID} || return +} + +wrapper-pauseV2() { + CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER_v2 + + mxpy contract call ${BRIDGED_TOKENS_WRAPPER_v2} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=5000000 --function="pause" \ --send --proxy=${PROXY} --chain=${CHAIN_ID} || return } @@ -123,7 +132,7 @@ wrapper-pause() { wrapper-upgrade() { CHECK_VARIABLES BRIDGED_TOKENS_WRAPPER BRIDGED_TOKENS_WRAPPER_WASM - mxpy --verbose contract upgrade ${BRIDGED_TOKENS_WRAPPER} --bytecode=${BRIDGED_TOKENS_WRAPPER_WASM} --recall-nonce --pem=${ALICE} \ + mxpy contract upgrade ${BRIDGED_TOKENS_WRAPPER} --bytecode=${BRIDGED_TOKENS_WRAPPER_WASM} --recall-nonce "${MXPY_SIGN[@]}" \ --gas-limit=50000000 --send \ --outfile="upgrade-bridged-tokens-wrapper.json" --proxy=${PROXY} --chain=${CHAIN_ID} || return -} \ No newline at end of file +} diff --git a/multisig/interaction/release-v3/config-setter.cfg b/multisig/interaction/release-v3/config-setter.cfg new file mode 100644 index 00000000..f3c4c863 --- /dev/null +++ b/multisig/interaction/release-v3/config-setter.cfg @@ -0,0 +1,285 @@ +#### Ethereum + +function set-eth-contracts-settings() { + update-config RELAYER_ADDR_0 erd1utcjaku9mpat3mqmref29ppklvk0rfamxtwa6vszpn538e5gxc7qxn60fv + update-config RELAYER_ADDR_1 erd13cgug7jgk0rfjypgxxe78g08cuetcd59nwygdtvtxf757mp0kuxq0ptlmz + update-config RELAYER_ADDR_2 erd176k35a4x6edcp3zf3s78ht73nw0fdw3sa0rzdctfrdr97pf2sxvqhrqcgz + update-config RELAYER_ADDR_3 erd1e7rkf4zsehn3ny3wz9ryp8zfr0emu49jx2vz7szsugwftavctskquff643 + update-config RELAYER_ADDR_4 erd1h4zv5y3xaxz523p0pluc2dz88lvqt8p9w28ftzz86vnsc6yx8vxqqc8sr9 + update-config RELAYER_ADDR_5 erd1c744ej6prx3yjydmr68jyrsg7hz5hj58gmcr02j6he782yh2qqyqlpamdj + update-config RELAYER_ADDR_6 erd1cdjeyqcxxeqc8jx0r463rywrew6x26kxq6h42duuxaffm0gjvszq5y8ynv + update-config RELAYER_ADDR_7 erd175tjdcmxq47rk0qd3n8fr74n9uaxyfjv5xvel5mp9emvxqk2tdzqdhyrqk + update-config RELAYER_ADDR_8 erd17t7kr6u4kzm4r0ftjzpzher38yw9z4hzu96p3hhkz9q944xv43wq8fc6rz + update-config RELAYER_ADDR_9 erd1ack50m42nta2x0my4kadfl0ylzu60prxgzuhjhdw6jlujjgmk5yq2wvxcr + update-config QUORUM 7 + + manual-update-config-file +} + +function set-eth-USDC-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 6 + update-config NR_DECIMALS_UNIVERSAL 6 + update-config UNIVERSAL_TOKEN USDC-c76f1f + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHUSDC + update-config CHAIN_SPECIFIC_TOKEN ETHUSDC-220753 + update-config ERC20_TOKEN 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 20 + update-config MAX_AMOUNT 50000 + + manual-update-config-file +} + +function set-eth-UTK-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN UTK-2f80e9 + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHUTK + update-config CHAIN_SPECIFIC_TOKEN ETHUTK-8cdf7a + update-config ERC20_TOKEN 0xdc9ac3c20d1ed0b540df9b1fedc10039df13f99c + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 660 + update-config MAX_AMOUNT 676600 + + manual-update-config-file +} + +function set-eth-USDT-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 6 + update-config NR_DECIMALS_UNIVERSAL 6 + update-config UNIVERSAL_TOKEN USDT-f8c08c + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHUSDT + update-config CHAIN_SPECIFIC_TOKEN ETHUSDT-9c73c6 + update-config ERC20_TOKEN 0xdac17f958d2ee523a2206206994597c13d831ec7 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 20 + update-config MAX_AMOUNT 50000 + + manual-update-config-file +} + +#function set-eth-BUSD-token-settings { +# update-config NR_DECIMALS_CHAIN_SPECIFIC 18 +# update-config NR_DECIMALS_UNIVERSAL 18 +# update-config UNIVERSAL_TOKEN BUSD-40b57e +# update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHBUSD +# update-config CHAIN_SPECIFIC_TOKEN ETHBUSD-450923 +# update-config ERC20_TOKEN 0x4fabb145d64652a948d72533023f6e7a623c7c53 +# update-config MINTBURN_WHITELIST true +# update-config NATIVE_TOKEN false +# update-config FEE_AMOUNT 25 +# update-config MAX_AMOUNT 50000 +# +# manual-update-config-file +#} + +function set-eth-HMT-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN HMT-fc75d2 + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHHMT + update-config CHAIN_SPECIFIC_TOKEN ETHHMT-18538a + update-config ERC20_TOKEN 0xd1ba9bac957322d6e8c07a160a3a8da11a0d2867 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 870 + update-config MAX_AMOUNT 872750 + + manual-update-config-file +} + +function set-eth-CGG-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN CGG-8b4838 + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHCGG + update-config CHAIN_SPECIFIC_TOKEN ETHCGG-ee4e0c + update-config ERC20_TOKEN 0x1fe24f25b1cf609b9c4e7e12d802e3640dfa5e43 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 1853 + update-config MAX_AMOUNT 635000 + + manual-update-config-file +} + +function set-eth-INFRA-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN INFRA-43985c + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHINFRA + update-config CHAIN_SPECIFIC_TOKEN ETHINFRA-60a3bf + update-config ERC20_TOKEN 0x013062189dc3dcc99e9cee714c513033b8d99e3c + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 150 + update-config MAX_AMOUNT 100000 + + manual-update-config-file +} + +function set-eth-WBTC-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 8 + update-config NR_DECIMALS_UNIVERSAL 8 + update-config UNIVERSAL_TOKEN WBTC-5349b3 + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHWBTC + update-config CHAIN_SPECIFIC_TOKEN ETHWBTC-74e282 + update-config ERC20_TOKEN 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 0.00032055 + update-config MAX_AMOUNT 2 + + manual-update-config-file +} + +function set-eth-WETH-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN WETH-b4ca29 + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHWETH + update-config CHAIN_SPECIFIC_TOKEN ETHWETH-e1c126 + update-config ERC20_TOKEN 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 0.00711 + update-config MAX_AMOUNT 28.5 + + manual-update-config-file +} + +function set-eth-WSDAI-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN WSDAI-277fee + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHWSDAI + update-config CHAIN_SPECIFIC_TOKEN ETHWSDAI-572803 + update-config ERC20_TOKEN 0x83f20f44975d03b1b09e64809b757c47f942beea + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 17 + update-config MAX_AMOUNT 50000 + + manual-update-config-file +} + +function set-eth-WDAI-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN WDAI-9eeb54 + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHWDAI + update-config CHAIN_SPECIFIC_TOKEN ETHWDAI-bd65f9 + update-config ERC20_TOKEN 0x6b175474e89094c44da98b954eedeac495271d0f + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 20 + update-config MAX_AMOUNT 50000 + + manual-update-config-file +} + +function set-eth-UMB-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN UMB-e2b3d8 + update-config CHAIN_SPECIFIC_TOKEN_TICKER ETHUMB + update-config CHAIN_SPECIFIC_TOKEN ETHUMB-291202 + update-config ERC20_TOKEN 0x6fc13eace26590b80cccab1ba5d51890577d83b2 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 2640 + update-config MAX_AMOUNT 2500000 + + manual-update-config-file +} + +### BSC + +function set-bsc-contracts-settings() { + update-config RELAYER_ADDR_0 erd18ymp4ppzxjkexvceedxt2lwllgqf9r30tf53af5jx8tufqa70rvq8f48fc + update-config RELAYER_ADDR_1 erd12l4hyrxp76fdjae42vqr7tfcs38d83qe4d5kh8gykvqkkr3a0ejqzsl568 + update-config RELAYER_ADDR_2 erd1nrf9f39slwaj6qmv6vkchqydl9ap2tw28xxllg08weqw4vul8pvqheh84x + update-config RELAYER_ADDR_3 erd1e9h0g5sjc26dpskuyxsn3hkqcw229zgcdkpjghc94nmcsht47nzqpefjwa + update-config RELAYER_ADDR_4 erd1wzr5se3xwn5d2aurl9jzjcmchuv3gljk8f4dl0uxdashmn3ygysq54renf + update-config RELAYER_ADDR_5 erd1f5zvn3snuruvs4vuzhs0mqx4q8r4gtt4ze2zmsdcu7tl6cgkvxyqtrftk6 + update-config RELAYER_ADDR_6 erd10adh0mnzv7s7g4hmr0aj4mpwp3mgr3ykq8lgwg2tkd84jukxyyzqh5tf23 + update-config RELAYER_ADDR_7 erd1lzssh9anhmxg480jmt0rdxt4v43vjnx9wpjg4psq5c68qthc4gzqs2lcqx + update-config RELAYER_ADDR_8 erd1yv639w0lkrvdh5vmyjy8n8e23zh9a55upzx2gr8h4ez0vgw09psqr40w8g + update-config RELAYER_ADDR_9 erd1sy2ymmvk2l5z6dkfl5gtzrvvwc9g9jwaaq63t3jfeenagne2fdcqqwm3jq + update-config QUORUM 7 + + manual-update-config-file +} + +function set-bsc-USDC-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 6 + update-config UNIVERSAL_TOKEN USDC-c76f1f + update-config CHAIN_SPECIFIC_TOKEN_TICKER BSCUSDC + update-config CHAIN_SPECIFIC_TOKEN BSCUSDC-887875 + update-config ERC20_TOKEN 0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 1 + update-config MAX_AMOUNT 50000 + + manual-update-config-file +} + +function set-bsc-USDT-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 6 + update-config UNIVERSAL_TOKEN USDT-f8c08c + update-config CHAIN_SPECIFIC_TOKEN_TICKER BSCUSDT + update-config CHAIN_SPECIFIC_TOKEN BSCUSDT-059796 + update-config ERC20_TOKEN 0x55d398326f99059ff775485246999027b3197955 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 1 + update-config MAX_AMOUNT 50000 + + manual-update-config-file +} + +# function set-bsc-BUSD-token-settings { +# update-config NR_DECIMALS_CHAIN_SPECIFIC 18 +# update-config NR_DECIMALS_UNIVERSAL 18 +# update-config UNIVERSAL_TOKEN BUSD-40b57e +# update-config CHAIN_SPECIFIC_TOKEN_TICKER BSCBUSD +# update-config CHAIN_SPECIFIC_TOKEN BSCBUSD-69b1d9 +# update-config ERC20_TOKEN 0xe9e7cea3dedca5984780bafc599bd69add087d56 +# update-config MINTBURN_WHITELIST true +# update-config NATIVE_TOKEN false +# update-config FEE_AMOUNT 5 +# update-config MAX_AMOUNT 50000 +# +# manual-update-config-file +# } + +function set-bsc-TADA-token-settings { + update-config NR_DECIMALS_CHAIN_SPECIFIC 18 + update-config NR_DECIMALS_UNIVERSAL 18 + update-config UNIVERSAL_TOKEN TADA-5c032c + update-config CHAIN_SPECIFIC_TOKEN_TICKER BSCTADA + update-config CHAIN_SPECIFIC_TOKEN BSCTADA-f64757 + update-config ERC20_TOKEN 0x9b26e318bc6a2c8b45f5daea2cc14697e0e0f8b5 + update-config MINTBURN_WHITELIST true + update-config NATIVE_TOKEN false + update-config FEE_AMOUNT 45 + update-config MAX_AMOUNT 1000000 + + manual-update-config-file +} + +### common + +function set-oracle-addresses { + update-config ORACLE_ADDR_0 erd1eq3yemt04efrsafedena3h8qcxlypvhxq5t69nuvaaxgj25uytxq7hc5ga + update-config ORACLE_ADDR_1 erd1hkfnfsajglf4dk44fe4v67nhz3kxfp2qqejj5uazmu5hv6xye42qyywr53 + update-config ORACLE_ADDR_2 erd12806lwvndt7r37l95dmv5p35nsqv59judlds9qxacgtksv8h9pjqa5hnw9 + + manual-update-config-file +} diff --git a/multisig/interaction/release-v3/menu_functions.cfg b/multisig/interaction/release-v3/menu_functions.cfg new file mode 100644 index 00000000..a838bd3c --- /dev/null +++ b/multisig/interaction/release-v3/menu_functions.cfg @@ -0,0 +1,187 @@ +#!/bin/bash +set -e + +source $SCRIPTPATH/config/aggregator-snippets.sh +source $SCRIPTPATH/config/issue-tokens-snippets.sh +source $SCRIPTPATH/config/multisig-snippets.sh +source $SCRIPTPATH/config/multitransfer-snippets.sh +source $SCRIPTPATH/config/proxy-snippets.sh +source $SCRIPTPATH/config/relayers-snippets.sh +source $SCRIPTPATH/config/wrapped-snippets.sh +source $SCRIPTPATH/config/safe-snippets.sh +source $SCRIPTPATH/config/testing.sh +source $SCRIPTPATH/config/mainnet-release-v3.sh +source $SCRIPTPATH/release-v3/config-setter.cfg + +CHECK_VARIABLES ALICE PROXY CHAIN_ID + +function deploy-bridge-contracts-eth-v3 { + echo -e + echo "PREREQUIREMENTS: The BRIDGED_TOKENS_WRAPPER address should be defined in configs.cfg file" + echo -e + + set-eth-contracts-settings + set-oracle-addresses + + confirmation-with-skip deployAggregator + confirmation-with-skip manual-update-config-file + + deploy-chain-only-contract +} + +function deploy-bridge-contracts-bsc-v3 { + echo -e + echo "PREREQUIREMENTS: The BRIDGED_TOKENS_WRAPPER address should be defined in configs.cfg file" + echo -e + + set-bsc-contracts-settings + + deploy-chain-only-contract +} + +function deploy-chain-only-contract { + confirmation-with-skip deployMultiTransfer + manual-update-config-file + confirmation-with-skip deploySafe + manual-update-config-file + confirmation-with-skip deployBridgeProxy + manual-update-config-file + confirmation-with-skip deployMultisigMainnetV3 + manual-update-config-file + + confirmation-with-skip setBridgeProxyContractAddressOnMultiTransfer + confirmation-with-skip setBridgedTokensWrapperOnMultiTransfer + + confirmation-with-skip setBridgedTokensWrapperOnSCProxy + confirmation-with-skip setMultiTransferOnSCProxy + confirmation-with-skip setEsdtSafeOnSCProxy + + confirmation-with-skip setBridgedTokensWrapperOnEsdtSafe + confirmation-with-skip setSCProxyOnEsdtSafe + + confirmation-with-skip changeChildContractsOwnershipSafe + confirmation-with-skip changeChildContractsOwnershipMultiTransfer + confirmation-with-skip changeChildContractsOwnershipProxy + + confirmation-with-skip setEsdtSafeOnMultiTransferThroughMultisig +} + +function unpause-contracts-eth-v3 { + confirmation-with-skip unpauseAggregator + confirmation-with-skip unpause + confirmation-with-skip unpauseEsdtSafe + confirmation-with-skip unpauseProxy +} + +function unpause-contracts-bsc-v3 { + confirmation-with-skip unpause + confirmation-with-skip unpauseEsdtSafe + confirmation-with-skip unpauseProxy +} + +function set-tokens-on-eth { + confirmation-multiple set-eth-USDC-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-UTK-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-USDT-token-settings addMapping addTokenToWhitelist setPairDecimals + #confirmation-multiple set-eth-BUSD-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-HMT-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-CGG-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-INFRA-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-WBTC-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-WETH-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-WSDAI-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-WDAI-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-eth-UMB-token-settings addMapping addTokenToWhitelist setPairDecimals +} + +function set-tokens-on-bsc { + confirmation-multiple set-bsc-USDC-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-bsc-USDT-token-settings addMapping addTokenToWhitelist setPairDecimals + #confirmation-multiple set-bsc-BUSD-token-settings addMapping addTokenToWhitelist setPairDecimals + confirmation-multiple set-bsc-TADA-token-settings addMapping addTokenToWhitelist setPairDecimals +} + +function stake-oracles { + echo -e + echo "PREREQUIREMENTS: The AGGREGATOR address should be defined in configs.cfg file" + echo -e + + confirmation-with-skip manual-update-config-file + set-oracle-addresses + + confirmation stakeOracles +} + +function submit-aggregation-batches-eth { + echo -e + echo "PREREQUIREMENTS: The AGGREGATOR address should be defined in configs.cfg file" + echo -e + + confirmation-with-skip manual-update-config-file + set-oracle-addresses + + confirmation-multiple set-eth-USDC-token-settings submitAggregatorBatch + confirmation-multiple set-eth-UTK-token-settings submitAggregatorBatch + confirmation-multiple set-eth-USDT-token-settings submitAggregatorBatch + #confirmation-multiple set-eth-BUSD-token-settings submitAggregatorBatch + confirmation-multiple set-eth-HMT-token-settings submitAggregatorBatch + confirmation-multiple set-eth-CGG-token-settings submitAggregatorBatch + confirmation-multiple set-eth-INFRA-token-settings submitAggregatorBatch + confirmation-multiple set-eth-WBTC-token-settings submitAggregatorBatch + confirmation-multiple set-eth-WETH-token-settings submitAggregatorBatch + confirmation-multiple set-eth-WSDAI-token-settings submitAggregatorBatch + confirmation-multiple set-eth-WDAI-token-settings submitAggregatorBatch + confirmation-multiple set-eth-UMB-token-settings submitAggregatorBatch +} + +function submit-aggregation-batches-bsc { + echo -e + echo "PREREQUIREMENTS: The AGGREGATOR address should be defined in configs.cfg file" + echo -e + + confirmation-with-skip manual-update-config-file + set-oracle-addresses + + confirmation-multiple set-bsc-USDC-token-settings submitAggregatorBatch + confirmation-multiple set-bsc-USDT-token-settings submitAggregatorBatch + #confirmation-multiple set-bsc-BUSD-token-settings submitAggregatorBatch + confirmation-multiple set-bsc-TADA-token-settings submitAggregatorBatch +} + +function stake-relayers-eth { + set-eth-contracts-settings + + confirmation-with-skip stakeRelayers +} + +function stake-relayers-bsc { + set-bsc-contracts-settings + + confirmation-with-skip stakeRelayers +} + +function set-roles-on-esdt-safe-eth { + confirmation-multiple set-eth-USDC-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-UTK-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-USDT-token-settings setLocalRolesEsdtSafe + #confirmation-multiple set-eth-BUSD-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-HMT-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-CGG-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-INFRA-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-WBTC-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-WETH-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-WSDAI-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-WDAI-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-eth-UMB-token-settings setLocalRolesEsdtSafe +} + +function set-roles-on-esdt-safe-bsc { + confirmation-multiple set-bsc-USDC-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-bsc-USDT-token-settings setLocalRolesEsdtSafe + #confirmation-multiple set-bsc-BUSD-token-settings setLocalRolesEsdtSafe + confirmation-multiple set-bsc-TADA-token-settings setLocalRolesEsdtSafe +} + +function unpause-wrapper { + confirmation-with-skip wrapper-unpause +} \ No newline at end of file diff --git a/multisig/interaction/script-v3-release.sh b/multisig/interaction/script-v3-release.sh new file mode 100755 index 00000000..008d2708 --- /dev/null +++ b/multisig/interaction/script-v3-release.sh @@ -0,0 +1,111 @@ +#!/bin/bash +set -e + +#Make script aware of its location +SCRIPTPATH="$( cd "$(dirname -- "$0")" ; pwd -P )" + +source $SCRIPTPATH/config/configs.cfg +source $SCRIPTPATH/config/helper.cfg +source $SCRIPTPATH/config/menu_functions.cfg +source $SCRIPTPATH/release-v3/menu_functions.cfg + +case "$1" in + +### PART 1 + +'deploy-bridge-contracts-eth-v3') + confirmation deploy-bridge-contracts-eth-v3 + ;; + +'unpause-contracts-eth-v3') + confirmation unpause-contracts-eth-v3 + ;; + +'set-tokens-on-eth') + confirmation set-tokens-on-eth + ;; + +'stake-oracles') + confirmation stake-oracles + ;; + +'submit-aggregation-batches-eth') + confirmation submit-aggregation-batches-eth + ;; + +'stake-relayers-eth') + confirmation stake-relayers-eth + ;; + +'set-roles-on-esdt-safe-eth') + confirmation set-roles-on-esdt-safe-eth + ;; + +### PART 2 + +'deploy-bridge-contracts-bsc-v3') + confirmation deploy-bridge-contracts-bsc-v3 + ;; + +'unpause-contracts-bsc-v3') + confirmation unpause-contracts-bsc-v3 + ;; + +'set-tokens-on-bsc') + confirmation set-tokens-on-bsc + ;; + +'submit-aggregation-batches-bsc') + confirmation submit-aggregation-batches-bsc + ;; + +'stake-relayers-bsc') + confirmation stake-relayers-bsc + ;; + +'set-roles-on-esdt-safe-bsc') + confirmation set-roles-on-esdt-safe-bsc + ;; + +### PART 3 + +'upgrade-wrapper') + confirmation upgrade-wrapper + ;; + +'unpause-wrapper') + confirmation unpause-wrapper + ;; + +*) + echo "Usage: Invalid choice: '"$1"'" + echo -e + echo "Choose from:" + echo "PART 1 - Ethereum:" + echo " 1.1 deploy-bridge-contracts-eth-v3" + echo " 1.2 unpause-contracts-eth-v3" + echo " 1.3 set-tokens-on-eth" + echo " -----------" + echo " 1.4 stake-oracles" + echo " 1.5 submit-aggregation-batches-eth" + echo " 1.6 stake-relayers-eth" + echo " -----------" + echo " 1.7 set-roles-on-esdt-safe-eth" + echo -e + echo "PART 2 - BSC:" + echo " 2.1 deploy-bridge-contracts-bsc-v3" + echo " 2.2 unpause-contracts-bsc-v3" + echo " 2.3 set-tokens-on-bsc" + echo " -----------" + echo " 2.4 submit-aggregation-batches-bsc" + echo " 2.5 stake-relayers-bsc" + echo " -----------" + echo " 2.6 set-roles-on-esdt-safe-bsc" + echo -e + echo "PART 3 - Upgrade wrapper:" + echo " 3.1 upgrade-wrapper" + echo " 3.2 unpause-wrapper" + echo -e + ;; + +esac \ No newline at end of file diff --git a/multisig/interaction/script.sh b/multisig/interaction/script.sh index ed684a2a..b4e3f493 100755 --- a/multisig/interaction/script.sh +++ b/multisig/interaction/script.sh @@ -9,22 +9,7 @@ source $SCRIPTPATH/config/helper.cfg source $SCRIPTPATH/config/menu_functions.cfg case "$1" in -'deploy-aggregator') - confirmation deploy-aggregator - ;; - -'deploy-wrapper') - confirmation deploy-wrapper - ;; - -'upgrade-wrapper') - confirmation upgrade-wrapper - ;; - 'deploy-bridge-contracts') - echo -e - echo "PREREQUIREMENTS: AGGREGATOR & BRIDGED_TOKENS_WRAPPER deployed" - echo -e confirmation deploy-bridge-contracts ;; @@ -45,6 +30,14 @@ case "$1" in confirmation whitelist-token ;; +'whitelist-native-token') + echo -e + echo "Check and update TOKENS SETTINGS section in configs.cfg" + source $SCRIPTPATH/config/configs.cfg + echo -e + confirmation whitelist-native-token + ;; + 'remove-whitelist-token') echo -e echo "PREREQUIREMENTS: BRIDGED_TOKENS_WRAPPER needs to have MINT+BURN role for the UNIVERSAL TOKEN" @@ -90,13 +83,62 @@ case "$1" in confirmation upgrade-wrapper-chain-specific-token ;; +'init-supply-mint-burn') + confirmation init-supply-mint-burn + ;; + +'upgrade-aggregator') + confirmation upgrade-aggregator + ;; + +'upgrade-wrapper') + confirmation upgrade-wrapper + ;; + +'upgrade-safe') + confirmation upgrade-safe + ;; + +'upgrade-multi-transfer') + confirmation upgrade-multi-transfer + ;; + +'upgrade-proxy') + confirmation upgrade-proxy + ;; + +'upgrade-multisig') + confirmation upgrade-multisig + ;; + +'whitelist-native-token') + confirmation whitelist-native-token + ;; + +'faucet-deposit') + confirmation faucet-deposit + ;; + +'deploy-test-caller') + confirmation deploy-test-caller + ;; + +'pause-v2-contracts') + confirmation pause-v2-contracts + ;; + *) echo "Usage: Invalid choice: '"$1"'" echo -e echo "Choose from:" - echo " { \"deploy-aggregator\", \"deploy-wrapper\", \"upgrade-wrapper\", \"deploy-bridge-contracts\", \"add-relayer\", \"remove-relayer\", \"whitelist-token\", " - echo " \"remove-whitelist-token\", \"set-safe-max-tx\", \"set-safe-batch-block-duration\", \"change-quorum\", \"pause-contracts\", \"unpause-contracts\", " - echo " \"set-swap-fee\", \"mint-chain-specific\", \"upgrade-wrapper-universal-token\", \"upgrade-wrapper-chain-specific-token\" }" + echo " { \"deploy-bridge-contracts\", " + echo " \"upgrade-aggregator\", \"upgrade-wrapper\", \"upgrade-safe\", \"upgrade-multi-transfer\", \"upgrade-proxy\", \"upgrade-multisig\" " + echo " \"pause-contracts\", \"unpause-contracts\", \"add-relayer\", \"remove-relayer\", \"pause-v2-contracts\", " + echo " \"set-safe-max-tx\", \"set-safe-batch-block-duration\", \"change-quorum\", \"set-swap-fee\", " + echo " \"whitelist-token\", \"whitelist-native-token\", \"remove-whitelist-token\", \"upgrade-wrapper-universal-token\", \"upgrade-wrapper-chain-specific-token\", " + echo " \"mint-chain-specific\", \"init-supply-mint-burn\", " + echo " \"faucet-deposit\", \"deploy-test-caller\"" + echo " } " ;; esac \ No newline at end of file diff --git a/multisig/meta/Cargo.toml b/multisig/meta/Cargo.toml index ec3e8100..983daa8d 100644 --- a/multisig/meta/Cargo.toml +++ b/multisig/meta/Cargo.toml @@ -8,6 +8,6 @@ publish = false [dependencies.multisig] path = ".." -[dependencies.multiversx-sc-meta] -version = "0.45.2" +[dependencies.multiversx-sc-meta-lib] +version = "=0.52.3" default-features = false diff --git a/multisig/meta/src/main.rs b/multisig/meta/src/main.rs index 69a0a648..8719674b 100644 --- a/multisig/meta/src/main.rs +++ b/multisig/meta/src/main.rs @@ -1,3 +1,3 @@ fn main() { - multiversx_sc_meta::cli_main::(); + multiversx_sc_meta_lib::cli_main::(); } diff --git a/multisig/sc-config.toml b/multisig/sc-config.toml new file mode 100644 index 00000000..f357ac11 --- /dev/null +++ b/multisig/sc-config.toml @@ -0,0 +1,4 @@ +[settings] + +[[proxy]] +path = "../multisig/src/multisig_proxy.rs" diff --git a/multisig/mandos/change_token_config.scen.json b/multisig/scenarios/change_token_config.scen.json similarity index 97% rename from multisig/mandos/change_token_config.scen.json rename to multisig/scenarios/change_token_config.scen.json index 8a9d0c73..75610ded 100644 --- a/multisig/mandos/change_token_config.scen.json +++ b/multisig/scenarios/change_token_config.scen.json @@ -154,7 +154,7 @@ "function": "addMapping", "arguments": [ "0x0102030405060708091011121314151617181999", - "str:EGLD-123456" + "str:WEGLD-123456" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -177,7 +177,7 @@ "function": "addMapping", "arguments": [ "0x0000030405060708091011121314151617181999", - "str:EGLD-123456" + "str:WEGLD-123456" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -202,7 +202,7 @@ }, "expect": { "out": [ - "str:EGLD-123456" + "str:WEGLD-123456" ] } }, @@ -213,7 +213,7 @@ "to": "sc:multisig", "function": "getErc20AddressForTokenId", "arguments": [ - "str:EGLD-123456" + "str:WEGLD-123456" ] }, "expect": { @@ -232,7 +232,7 @@ "function": "clearMapping", "arguments": [ "0x0102030405060708091011121314151617181920", - "str:EGLD-123456" + "str:WEGLD-123456" ], "gasLimit": "50,000,000", "gasPrice": "0" diff --git a/multisig/mandos/create_elrond_to_ethereum_tx_batch.scen.json b/multisig/scenarios/create_multiversx_to_ethereum_tx_batch.scen.json similarity index 76% rename from multisig/mandos/create_elrond_to_ethereum_tx_batch.scen.json rename to multisig/scenarios/create_multiversx_to_ethereum_tx_batch.scen.json index 1cd5744f..5dd942d7 100644 --- a/multisig/mandos/create_elrond_to_ethereum_tx_batch.scen.json +++ b/multisig/scenarios/create_multiversx_to_ethereum_tx_batch.scen.json @@ -1,5 +1,5 @@ { - "name": "batch tx from Elrond to Ethereum", + "name": "batch tx from MultiversX to Ethereum", "steps": [ { "step": "externalSteps", @@ -11,10 +11,13 @@ "tx": { "from": "address:user", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:EGLD-123456", - "value": "1,500,400" - }, + "value": "0", + "esdtValue": [ + { + "tokenIdentifier": "str:WEGLD-123456", + "value": "85,000,000,000" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -37,8 +40,8 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": "499,600", - "str:ETH-123456": "1,000,000" + "str:WEGLD-123456": "15,000,000,000", + "str:ETH-123456": "200,000,000,000" }, "storage": {} }, @@ -46,15 +49,17 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { - "balance": "1,500,400", + "str:WEGLD-123456": { + "balance": "1,500,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { "balance": "0", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } @@ -65,13 +70,13 @@ "2-nonce": "u64:1", "3-from": "u32:32|address:user", "4-to": "u32:20|0x0102030405060708091011121314151617181920", - "5-token_identifier": "nested:str:EGLD-123456", - "6-amount": "biguint:400", + "5-token_identifier": "nested:str:WEGLD-123456", + "6-amount": "biguint:84,998,500,000", "7-is_refund_tx": "u8:0" }, "str:firstBatchId": "1", "str:lastBatchId": "1", - "str:accumulatedTransactionFees|nested:str:EGLD-123456": "1,500,000", + "str:accumulatedTransactionFees|nested:str:WEGLD-123456": "1,500,000", "+": "" }, "code": "*" @@ -85,10 +90,12 @@ "tx": { "from": "address:user", "to": "sc:esdt_safe", - "esdt": { - "tokenIdentifier": "str:ETH-123456", - "value": "500,000" - }, + "esdtValue": [ + { + "tokenIdentifier": "str:ETH-123456", + "value": "95,000,000,000" + } + ], "function": "createTransaction", "arguments": [ "0x0102030405060708091011121314151617181920" @@ -111,8 +118,8 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": "499,600", - "str:ETH-123456": "500,000" + "str:WEGLD-123456": "15,000,000,000", + "str:ETH-123456": "105,000,000,000" }, "storage": {} }, @@ -120,15 +127,17 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { - "balance": "1,500,400", + "str:WEGLD-123456": { + "balance": "1,500,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { - "balance": "500,000", + "balance": "1,500,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } @@ -139,8 +148,8 @@ "2-nonce": "u64:1", "3-from": "u32:32|address:user", "4-to": "u32:20|0x0102030405060708091011121314151617181920", - "5-token_identifier": "nested:str:EGLD-123456", - "6-amount": "biguint:400", + "5-token_identifier": "nested:str:WEGLD-123456", + "6-amount": "biguint:84,998,500,000", "7-is_refund_tx": "u8:0" }, "str:pendingBatches|u64:1|str:.item|u32:2": { @@ -149,13 +158,13 @@ "3-from": "u32:32|address:user", "4-to": "u32:20|0x0102030405060708091011121314151617181920", "5-token_identifier": "nested:str:ETH-123456", - "6-amount": "biguint:350,000", + "6-amount": "biguint:94,998,500,000", "7-is_refund_tx": "u8:0" }, "str:firstBatchId": "1", "str:lastBatchId": "1", - "str:accumulatedTransactionFees|nested:str:EGLD-123456": "1,500,000", - "str:accumulatedTransactionFees|nested:str:ETH-123456": "150,000", + "str:accumulatedTransactionFees|nested:str:WEGLD-123456": "1,500,000", + "str:accumulatedTransactionFees|nested:str:ETH-123456": "1,500,000", "+": "" }, "code": "*" @@ -184,16 +193,16 @@ "1", "address:user", "0x0102030405060708091011121314151617181920", - "str:EGLD-123456", - "400", + "str:WEGLD-123456", + "84,998,500,000", "0", "2", "address:user", "0x0102030405060708091011121314151617181920", "str:ETH-123456", - "350,000" + "94,998,500,000" ] } } ] -} +} \ No newline at end of file diff --git a/multisig/scenarios/ethereum_to_multiversx_relayer_call_data_several_tx_test.scen.json b/multisig/scenarios/ethereum_to_multiversx_relayer_call_data_several_tx_test.scen.json new file mode 100644 index 00000000..fbb56f5e --- /dev/null +++ b/multisig/scenarios/ethereum_to_multiversx_relayer_call_data_several_tx_test.scen.json @@ -0,0 +1,432 @@ +{ + "steps": [ + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:multisig" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:output/multisig.mxsc.json", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x03e8", + "0x01f4", + "0x02", + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "upgrade", + "arguments": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "sc:multisig", + "creatorNonce": "0", + "newAddress": "sc:multi-transfer" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "sc:multisig", + "contractCode": "mxsc:../multi-transfer-esdt/output/multi-transfer-esdt.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "3", + "newAddress": "sc:bridge-proxy" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridge-proxy/output/bridge-proxy.mxsc.json", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "4", + "newAddress": "sc:bridged-tokens-wrapper" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridged-tokens-wrapper/output/bridged-tokens-wrapper.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setWrappingContractAddress", + "arguments": [ + "0x00000000000000000500627269646765642d746f6b656e732d77726170706572" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setBridgeProxyContractAddress", + "arguments": [ + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setEsdtSafeContractAddress", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "setMultiTransferContractAddress", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x5745474c442d313233343536", + "0x5745474c44", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x4554482d313233343536", + "0x455448", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:multisig", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "getAllStakedRelayers", + "arguments": [] + }, + "expect": { + "out": [ + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "proposeMultiTransferEsdtBatch", + "arguments": [ + "0x01", + "0x3564393539653938656137336333353737386666", + "0x65726431647977376179736e306e776d75616876786e68326530706d306b676a", + "0x455448555344432d616661363839", + "0x1388", + "0x01", + "0x", + "0x3564393539653938656137336333353737386666", + "0x65726431647977376179736e306e776d75616876786e68326530706d306b676a", + "0x455448555344432d616661363839", + "0x1388", + "0x02", + "0x", + "0x3564393539653938656137336333353737386666", + "0x65726431647977376179736e306e776d75616876786e68326530706d306b676a", + "0x455448555344432d616661363839", + "0x1388", + "0x03", + "0x01000000110000000466756e640000000005f5e10000", + "0x3564393539653938656137336333353737386666", + "0x65726431647977376179736e306e776d75616876786e68326530706d306b676a", + "0x455448555344432d616661363839", + "0x1388", + "0x04", + "0x010000001a0000000466756e640000000005f5e10001000000010000000135" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "function": "sign", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "performAction", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "status": "4", + "message": "str:Invalid token or amount" + } + } + ] +} diff --git a/multisig/scenarios/ethereum_to_multiversx_relayer_query2_test.scen.json b/multisig/scenarios/ethereum_to_multiversx_relayer_query2_test.scen.json new file mode 100644 index 00000000..78291d1c --- /dev/null +++ b/multisig/scenarios/ethereum_to_multiversx_relayer_query2_test.scen.json @@ -0,0 +1,460 @@ +{ + "steps": [ + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:multisig" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:output/multisig.mxsc.json", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x03e8", + "0x01f4", + "0x02", + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "upgrade", + "arguments": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "sc:multisig", + "creatorNonce": "0", + "newAddress": "sc:multi-transfer" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "sc:multisig", + "contractCode": "mxsc:../multi-transfer-esdt/output/multi-transfer-esdt.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "3", + "newAddress": "sc:bridge-proxy" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridge-proxy/output/bridge-proxy.mxsc.json", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "4", + "newAddress": "sc:bridged-tokens-wrapper" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridged-tokens-wrapper/output/bridged-tokens-wrapper.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setWrappingContractAddress", + "arguments": [ + "0x00000000000000000500627269646765642d746f6b656e732d77726170706572" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setBridgeProxyContractAddress", + "arguments": [ + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setEsdtSafeContractAddress", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "setMultiTransferContractAddress", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x5745474c442d313233343536", + "0x5745474c44", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x4554482d313233343536", + "0x455448", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:multisig", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "getAllStakedRelayers", + "arguments": [] + }, + "expect": { + "out": [ + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "proposeMultiTransferEsdtBatch", + "arguments": [ + "0x01", + "0x3564393539653938656137336333353737386666", + "0x691dee92137cddbe76ec34eeacbc3b7d91264148da5a69205133c395aa7662cf", + "0x455448555344432d616661363839", + "0x1388", + "0x01", + "0x" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "wasTransferActionProposed", + "arguments": [ + "0x01", + "0x3564393539653938656137336333353737386666", + "0x691dee92137cddbe76ec34eeacbc3b7d91264148da5a69205133c395aa7662cf", + "0x455448555344432d616661363839", + "0x1388", + "0x01", + "0x" + ] + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "getActionIdForTransferBatch", + "arguments": [ + "0x01", + "0x3564393539653938656137336333353737386666", + "0x691dee92137cddbe76ec34eeacbc3b7d91264148da5a69205133c395aa7662cf", + "0x455448555344432d616661363839", + "0x1388", + "0x01", + "0x" + ] + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "function": "sign", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "performAction", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "status": "4", + "message": "str:Invalid token or amount" + } + } + ] +} diff --git a/multisig/scenarios/ethereum_to_multiversx_relayer_query_test.scen.json b/multisig/scenarios/ethereum_to_multiversx_relayer_query_test.scen.json new file mode 100644 index 00000000..b00b780f --- /dev/null +++ b/multisig/scenarios/ethereum_to_multiversx_relayer_query_test.scen.json @@ -0,0 +1,474 @@ +{ + "steps": [ + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:multisig" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:output/multisig.mxsc.json", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x03e8", + "0x01f4", + "0x02", + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "upgrade", + "arguments": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "sc:multisig", + "creatorNonce": "0", + "newAddress": "sc:multi-transfer" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "sc:multisig", + "contractCode": "mxsc:../multi-transfer-esdt/output/multi-transfer-esdt.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "3", + "newAddress": "sc:bridge-proxy" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridge-proxy/output/bridge-proxy.mxsc.json", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "4", + "newAddress": "sc:bridged-tokens-wrapper" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridged-tokens-wrapper/output/bridged-tokens-wrapper.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setWrappingContractAddress", + "arguments": [ + "0x00000000000000000500627269646765642d746f6b656e732d77726170706572" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setBridgeProxyContractAddress", + "arguments": [ + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setEsdtSafeContractAddress", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "setMultiTransferContractAddress", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x5745474c442d313233343536", + "0x5745474c44", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x4554482d313233343536", + "0x455448", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:multisig", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "getAllStakedRelayers", + "arguments": [] + }, + "expect": { + "out": [ + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "proposeMultiTransferEsdtBatch", + "arguments": [ + "0x01", + "0x3031303230333034303530363037303830393130", + "0x75736572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x5745474c442d313233343536", + "0x11b1f3f800", + "0x01", + "0x" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "wasTransferActionProposed", + "arguments": [ + "0x01", + "0x3031303230333034303530363037303830393130", + "0x75736572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x5745474c442d313233343536", + "0x11b1f3f800", + "0x01", + "0x" + ] + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "getActionIdForTransferBatch", + "arguments": [ + "0x01", + "0x3031303230333034303530363037303830393130", + "0x75736572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x5745474c442d313233343536", + "0x11b1f3f800", + "0x01", + "0x" + ] + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "function": "sign", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "performAction", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "checkState", + "accounts": { + "address:user1": { + "esdt": { + "str:WEGLD-123456": "76000000000", + "+": "" + }, + "storage": "*", + "code": "*", + "owner": "*" + } + } + } + ] +} diff --git a/multisig/mandos/ethereum_to_elrond_tx_batch_ok.scen.json b/multisig/scenarios/ethereum_to_multiversx_tx_batch_ok.scen.json similarity index 68% rename from multisig/mandos/ethereum_to_elrond_tx_batch_ok.scen.json rename to multisig/scenarios/ethereum_to_multiversx_tx_batch_ok.scen.json index 86fe3a03..d6681d28 100644 --- a/multisig/mandos/ethereum_to_elrond_tx_batch_ok.scen.json +++ b/multisig/scenarios/ethereum_to_multiversx_tx_batch_ok.scen.json @@ -1,5 +1,5 @@ { - "name": "create ethereum to elrond tx batch", + "name": "create ethereum to MultiversX tx batch", "steps": [ { "step": "externalSteps", @@ -14,9 +14,23 @@ "value": "0", "function": "proposeMultiTransferEsdtBatch", "arguments": [ - "1", - "0x0102030405060708091011121314151617181920", "address:user", "str:EGLD-123456", "500,000", "1", - "0x0102030405060708091011121314151617181920", "address:user", "str:ETH-123456", "500,000", "2" + "u64:1", + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user", + "3-token_id": "nested:str:WEGLD-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:1", + "6-call_data": "0x000000036164640000000000989680000000010000000105" + }, + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user", + "3-token_id": "nested:str:ETH-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:2", + "6-call_data": "0x000000036164640000000000989680000000010000000105" + } ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -46,16 +60,18 @@ { "1-from": "0x0102030405060708091011121314151617181920", "2-to": "address:user", - "3-token_id": "nested:str:EGLD-123456", - "4-amount": "biguint:500,000", - "5-tx_nonce": "u64:1" + "3-token_id": "nested:str:WEGLD-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:1", + "6-call_data": "nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" }, { "1-from": "0x0102030405060708091011121314151617181920", "2-to": "address:user", "3-token_id": "nested:str:ETH-123456", - "4-amount": "biguint:500,000", - "5-tx_nonce": "u64:2" + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:2", + "6-call_endpoint": "nested:str:add|u64:10,000,000|u32:0x1|nested:u8:5" } ] }, @@ -117,8 +133,8 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": "2,500,000", - "str:ETH-123456": "1,500,000" + "str:WEGLD-123456": "176,000,000,000", + "str:ETH-123456": "276,000,000,000" }, "storage": {} }, diff --git a/multisig/scenarios/ethereum_to_multiversx_tx_batch_ok_call_data_encoded.scen.json b/multisig/scenarios/ethereum_to_multiversx_tx_batch_ok_call_data_encoded.scen.json new file mode 100644 index 00000000..84ec33e6 --- /dev/null +++ b/multisig/scenarios/ethereum_to_multiversx_tx_batch_ok_call_data_encoded.scen.json @@ -0,0 +1,434 @@ +{ + "steps": [ + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "1", + "newAddress": "sc:multisig" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:output/multisig.mxsc.json", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x03e8", + "0x01f4", + "0x02", + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "upgrade", + "arguments": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f", + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "sc:multisig", + "creatorNonce": "0", + "newAddress": "sc:multi-transfer" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "sc:multisig", + "contractCode": "mxsc:../multi-transfer-esdt/output/multi-transfer-esdt.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "3", + "newAddress": "sc:bridge-proxy" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridge-proxy/output/bridge-proxy.mxsc.json", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "setState", + "newAddresses": [ + { + "creatorAddress": "address:owner", + "creatorNonce": "4", + "newAddress": "sc:bridged-tokens-wrapper" + } + ] + }, + { + "step": "scDeploy", + "id": "", + "tx": { + "from": "address:owner", + "contractCode": "mxsc:../bridged-tokens-wrapper/output/bridged-tokens-wrapper.mxsc.json", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setWrappingContractAddress", + "arguments": [ + "0x00000000000000000500627269646765642d746f6b656e732d77726170706572" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setBridgeProxyContractAddress", + "arguments": [ + "0x000000000000000005006272696467652d70726f78795f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "sc:multisig", + "to": "sc:multi-transfer", + "function": "setEsdtSafeContractAddress", + "arguments": [ + "0x00000000000000000500657364742d736166655f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "setMultiTransferContractAddress", + "arguments": [ + "0x000000000000000005006d756c74692d7472616e736665725f5f5f5f5f5f5f5f" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x5745474c442d313233343536", + "0x5745474c44", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "addTokenToWhitelist", + "arguments": [ + "0x4554482d313233343536", + "0x455448", + "0x01", + "0x", + "0x", + "0x", + "0x", + "0x0249f0" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:multisig", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridged-tokens-wrapper", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:bridge-proxy", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:owner", + "to": "sc:esdt-safe", + "function": "unpause", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "egldValue": "1000", + "function": "stake", + "arguments": [], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scQuery", + "id": "", + "tx": { + "to": "sc:multisig", + "function": "getAllStakedRelayers", + "arguments": [] + }, + "expect": { + "out": [ + "0x72656c61796572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x72656c61796572325f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "proposeMultiTransferEsdtBatch", + "arguments": [ + "0x01", + "0x3031303230333034303530363037303830393130", + "0x75736572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x5745474c442d313233343536", + "0x11b1f3f800", + "0x01", + "0x010000002a000000036164640000000005f5e100010000000300000002050600000003070809000000050708090a0b", + "0x3031303230333034303530363037303830393130", + "0x75736572315f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f", + "0x4554482d313233343536", + "0x11b1f3f800", + "0x02", + "0x010000002a000000036164640000000005f5e100010000000300000002050600000003070809000000050708090a0b" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [ + "0x01" + ], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer2", + "to": "sc:multisig", + "function": "sign", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "scCall", + "id": "", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "function": "performAction", + "arguments": [ + "0x01" + ], + "gasLimit": "5,000,000" + }, + "expect": { + "out": [], + "status": "0" + } + }, + { + "step": "checkState", + "accounts": { + "address:user1": { + "esdt": { + "str:WEGLD-123456": "76000000000", + "+": "" + }, + "storage": "*", + "code": "*", + "owner": "*" + } + } + } + ] +} diff --git a/multisig/mandos/ethereum_to_elrond_tx_batch_rejected.scen.json b/multisig/scenarios/ethereum_to_multiversx_tx_batch_rejected.scen.json similarity index 68% rename from multisig/mandos/ethereum_to_elrond_tx_batch_rejected.scen.json rename to multisig/scenarios/ethereum_to_multiversx_tx_batch_rejected.scen.json index f3d8f739..d2575ae0 100644 --- a/multisig/mandos/ethereum_to_elrond_tx_batch_rejected.scen.json +++ b/multisig/scenarios/ethereum_to_multiversx_tx_batch_rejected.scen.json @@ -1,5 +1,5 @@ { - "name": "create ethereum to elrond tx batch - rejected", + "name": "create ethereum to MultiversX tx batch - rejected", "steps": [ { "step": "externalSteps", @@ -17,14 +17,16 @@ "2", "0x0102030405060708091011121314151617181920", "sc:egld_esdt_swap", - "str:EGLD-123456", - "2,000,000", - "u64:1", + "str:WEGLD-123456", + "76,000,000,000", + "str:data", + "0x01|nested:str:data|u64:50,000,000|u32:0", "0x0102030405060708091011121314151617181920", "sc:egld_esdt_swap", "str:ETH-123456", - "2,000,000", - "u64:2" + "76,000,000,000", + "u64:2", + "0x01|nested:str:data|u64:50,000,000|u32:0" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -47,16 +49,26 @@ "function": "proposeMultiTransferEsdtBatch", "arguments": [ "1", - "0x0102030405060708091011121314151617181920", - "sc:egld_esdt_swap", - "str:EGLD-123456", - "2,000,000", - "u64:2", - "0x0102030405060708091011121314151617181920", - "sc:egld_esdt_swap", - "str:ETH-123456", - "2,000,000", - "u64:3" + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "sc:egld_esdt_swap", + "3-token_id": "nested:str:WEGLD-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:2", + "6-call_endpoint": "nested:str:data", + "7-call_gas_limit": "u64:50,000,000", + "8-call_args": "u32:0" + }, + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "sc:egld_esdt_swap", + "3-token_id": "nested:str:ETH-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:3", + "6-call_endpoint": "nested:str:data", + "7-call_gas_limit": "u64:50,000,000", + "8-call_args": "u32:0" + } ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -79,16 +91,26 @@ "function": "proposeMultiTransferEsdtBatch", "arguments": [ "1", - "0x0102030405060708091011121314151617181920", - "sc:egld_esdt_swap", - "str:EGLD-123456", - "2,000,000", - "u64:1", - "0x0102030405060708091011121314151617181920", - "sc:egld_esdt_swap", - "str:ETH-123456", - "2,000,000", - "u64:2" + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "sc:egld_esdt_swap", + "3-token_id": "nested:str:WEGLD-123456", + "4-amount": "biguint:101,000,000,000", + "5-tx_nonce": "u64:1", + "6-call_endpoint": "nested:str:data", + "7-call_gas_limit": "u64:50,000,000", + "8-call_args": "0x" + }, + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "sc:egld_esdt_swap", + "3-token_id": "nested:str:ETH-123456", + "4-amount": "biguint:101,000,000,000", + "5-tx_nonce": "u64:2", + "6-call_endpoint": "nested:str:data", + "7-call_gas_limit": "u64:50,000,000", + "8-call_args": "0x" + } ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -118,16 +140,22 @@ { "1-from": "0x0102030405060708091011121314151617181920", "2-to": "sc:egld_esdt_swap", - "3-token_id": "nested:str:EGLD-123456", - "4-amount": "biguint:2,000,000", - "5-tx_id": "u64:1" + "3-token_id": "nested:str:WEGLD-123456", + "4-amount": "biguint:101,000,000,000", + "5-tx_nonce": "u64:1", + "6-call_endpoint": "nested:str:data", + "7-call_gas_limit": "u64:50,000,000", + "8-call_args": "u32:0" }, { "1-from": "0x0102030405060708091011121314151617181920", "2-to": "sc:egld_esdt_swap", "3-token_id": "nested:str:ETH-123456", - "4-amount": "biguint:2,000,000", - "5-tx_id": "u64:2" + "4-amount": "biguint:101,000,000,000", + "5-tx_nonce": "u64:2", + "6-call_endpoint": "nested:str:data", + "7-call_gas_limit": "u64:50,000,000", + "8-call_args": "u32:0" } ] }, @@ -198,14 +226,14 @@ "1", "0x0102030405060708091011121314151617181920", "sc:egld_esdt_swap", - "str:EGLD-123456", - "2,000,000", + "str:WEGLD-123456", + "101,000,000,000", "0", "2", "0x0102030405060708091011121314151617181920", "sc:egld_esdt_swap", "str:ETH-123456", - "2,000,000" + "101,000,000,000" ] } }, @@ -216,7 +244,7 @@ "from": "address:owner", "to": "sc:multisig", "value": "0", - "function": "moveRefundBatchToSafe", + "function": "moveRefundBatchToSafeFromChildContract", "arguments": [], "gasLimit": "200,000,000", "gasPrice": "0" @@ -248,15 +276,17 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { - "balance": "0", + "str:WEGLD-123456": { + "balance": "101,000,000,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { - "balance": "0", + "balance": "101,000,000,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } @@ -267,8 +297,8 @@ "2-nonce": "u64:1", "3-from": "u32:32|sc:egld_esdt_swap", "4-to": "u32:20|0x0102030405060708091011121314151617181920", - "5-token_identifier": "nested:str:EGLD-123456", - "6-amount": "biguint:500,000", + "5-token_identifier": "nested:str:WEGLD-123456", + "6-amount": "biguint:100,998,500,000", "7-is_refund_tx": "u8:1" }, "str:pendingBatches|u64:1|str:.item|u32:2": { @@ -277,12 +307,12 @@ "3-from": "u32:32|sc:egld_esdt_swap", "4-to": "u32:20|0x0102030405060708091011121314151617181920", "5-token_identifier": "nested:str:ETH-123456", - "6-amount": "biguint:1,850,000", + "6-amount": "biguint:100,998,500,000", "7-is_refund_tx": "u8:1" }, "str:firstBatchId": "1", "str:lastBatchId": "1", - "str:accumulatedTransactionFees|nested:str:EGLD-123456": "0", + "str:accumulatedTransactionFees|nested:str:WEGLD-123456": "0", "str:accumulatedTransactionFees|nested:str:ETH-123456": "0", "+": "" }, diff --git a/multisig/scenarios/ethereum_to_multiversx_tx_batch_without_data.scen.json b/multisig/scenarios/ethereum_to_multiversx_tx_batch_without_data.scen.json new file mode 100644 index 00000000..34a1cc00 --- /dev/null +++ b/multisig/scenarios/ethereum_to_multiversx_tx_batch_without_data.scen.json @@ -0,0 +1,77 @@ +{ + "name": "create ethereum to MultiversX tx batch", + "steps": [ + { + "step": "externalSteps", + "path": "setup.scen.json" + }, + { + "step": "scCall", + "txId": "propose-transfer-ok", + "tx": { + "from": "address:relayer1", + "to": "sc:multisig", + "value": "0", + "function": "proposeMultiTransferEsdtBatch", + "arguments": [ + "1", + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user", + "3-token_id": "nested:str:WEGLD-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:1" + }, + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user", + "3-token_id": "nested:str:ETH-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:2" + } + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "out": [ + "1" + ], + "gas": "*", + "refund": "*" + } + }, + { + "step": "scQuery", + "txId": "get-current-tx-batch", + "tx": { + "to": "sc:multisig", + "function": "wasTransferActionProposed", + "arguments": [ + "1", + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user", + "3-token_id": "nested:str:WEGLD-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:1" + }, + { + "1-from": "0x0102030405060708091011121314151617181920", + "2-to": "address:user", + "3-token_id": "nested:str:ETH-123456", + "4-amount": "biguint:76,000,000,000", + "5-tx_nonce": "u64:2" + } + ] + }, + "expect": { + "out": [ + "1" + ] + } + } + ] +} diff --git a/multisig/mandos/execute_elrond_to_ethereum_tx_batch.scen.json b/multisig/scenarios/execute_multiversx_to_ethereum_tx_batch.scen.json similarity index 91% rename from multisig/mandos/execute_elrond_to_ethereum_tx_batch.scen.json rename to multisig/scenarios/execute_multiversx_to_ethereum_tx_batch.scen.json index 77368000..c965c992 100644 --- a/multisig/mandos/execute_elrond_to_ethereum_tx_batch.scen.json +++ b/multisig/scenarios/execute_multiversx_to_ethereum_tx_batch.scen.json @@ -3,7 +3,7 @@ "steps": [ { "step": "externalSteps", - "path": "create_elrond_to_ethereum_tx_batch.scen.json" + "path": "create_multiversx_to_ethereum_tx_batch.scen.json" }, { "step": "scCall", @@ -51,6 +51,7 @@ "+": {} } }, + { "step": "scCall", "txId": "second-relayer-sign", @@ -103,7 +104,7 @@ "value": "0", "function": "claimRefund", "arguments": [ - "str:EGLD-123456" + "str:WEGLD-123456" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -144,15 +145,17 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "1,500,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { - "balance": "150,000", + "balance": "1,500,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } @@ -162,8 +165,8 @@ "str:transactionsByNonce|address:user|str:.item|u32:1": "", "str:transactionStatus|address:user|u32:2": "", "str:transactionsByNonce|address:user|str:.item|u32:2": "", - "str:accumulatedTransactionFees|nested:str:EGLD-123456": "1,500,000", - "str:accumulatedTransactionFees|nested:str:ETH-123456": "150,000", + "str:accumulatedTransactionFees|nested:str:WEGLD-123456": "1,500,000", + "str:accumulatedTransactionFees|nested:str:ETH-123456": "1,500,000", "+": "" }, "code": "*" @@ -202,11 +205,11 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "600,000" }, "str:ETH-123456": { - "balance": "60,000" + "balance": "600,000" } }, "storage": {} @@ -215,11 +218,11 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "900,000" }, "str:ETH-123456": { - "balance": "90,000" + "balance": "900,000" } }, "storage": {} @@ -228,21 +231,23 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "0", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { "balance": "0", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } }, "storage": { - "str:accumulatedTransactionFees|nested:str:EGLD-123456": "0", + "str:accumulatedTransactionFees|nested:str:WEGLD-123456": "0", "str:accumulatedTransactionFees|nested:str:ETH-123456": "0", "+": "" }, diff --git a/multisig/mandos/get_empty_batch.scen.json b/multisig/scenarios/get_empty_batch.scen.json similarity index 100% rename from multisig/mandos/get_empty_batch.scen.json rename to multisig/scenarios/get_empty_batch.scen.json diff --git a/multisig/mandos/reject_elrond_to_ethereum_tx_batch.scen.json b/multisig/scenarios/reject_multiversx_to_ethereum_tx_batch.scen.json similarity index 89% rename from multisig/mandos/reject_elrond_to_ethereum_tx_batch.scen.json rename to multisig/scenarios/reject_multiversx_to_ethereum_tx_batch.scen.json index 1150e544..122fabab 100644 --- a/multisig/mandos/reject_elrond_to_ethereum_tx_batch.scen.json +++ b/multisig/scenarios/reject_multiversx_to_ethereum_tx_batch.scen.json @@ -3,7 +3,7 @@ "steps": [ { "step": "externalSteps", - "path": "create_elrond_to_ethereum_tx_batch.scen.json" + "path": "create_multiversx_to_ethereum_tx_batch.scen.json" }, { "step": "scCall", @@ -106,10 +106,10 @@ }, "expect": { "out": [ - "str:EGLD-123456", - "400", + "str:WEGLD-123456", + "84,998,500,000", "str:ETH-123456", - "350,000" + "94,998,500,000" ] } }, @@ -122,7 +122,7 @@ "value": "0", "function": "claimRefund", "arguments": [ - "str:EGLD-123456" + "str:WEGLD-123456" ], "gasLimit": "50,000,000", "gasPrice": "0" @@ -165,8 +165,8 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": "500,000", - "str:ETH-123456": "850,000" + "str:WEGLD-123456": "99,998,500,000", + "str:ETH-123456": "199,998,500,000" }, "storage": {} }, @@ -174,15 +174,17 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "1,500,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { - "balance": "150,000", + "balance": "1,500,000", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } @@ -192,8 +194,8 @@ "str:transactionsByNonce|address:user|str:.item|u32:1": "", "str:transactionStatus|address:user|u32:2": "", "str:transactionsByNonce|address:user|str:.item|u32:2": "", - "str:accumulatedTransactionFees|nested:str:EGLD-123456": "1,500,000", - "str:accumulatedTransactionFees|nested:str:ETH-123456": "150,000", + "str:accumulatedTransactionFees|nested:str:WEGLD-123456": "1,500,000", + "str:accumulatedTransactionFees|nested:str:ETH-123456": "1,500,000", "+": "" }, "code": "*" @@ -232,11 +234,11 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "600,000" }, "str:ETH-123456": { - "balance": "60,000" + "balance": "600,000" } }, "storage": {} @@ -245,11 +247,11 @@ "nonce": "*", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "900,000" }, "str:ETH-123456": { - "balance": "90,000" + "balance": "900,000" } }, "storage": {} @@ -258,21 +260,23 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "0", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { "balance": "0", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } }, "storage": { - "str:accumulatedTransactionFees|nested:str:EGLD-123456": "0", + "str:accumulatedTransactionFees|nested:str:WEGLD-123456": "0", "str:accumulatedTransactionFees|nested:str:ETH-123456": "0", "+": "" }, diff --git a/multisig/mandos/setup.scen.json b/multisig/scenarios/setup.scen.json similarity index 72% rename from multisig/mandos/setup.scen.json rename to multisig/scenarios/setup.scen.json index 9739684e..9572e774 100644 --- a/multisig/mandos/setup.scen.json +++ b/multisig/scenarios/setup.scen.json @@ -3,17 +3,25 @@ "steps": [ { "step": "externalSteps", - "path": "../../price-aggregator/mandos/oracle_gwei_in_eth_and_egld_submit.scen.json" + "path": "../../price-aggregator/scenarios/oracle_gwei_in_eth_and_egld_submit.scen.json" }, { "step": "setState", "comment": "simulate child contracts deploy + setting local roles + change ownership. Changing ownership will be done after the multisig deploy in the real setup, but this is way less verbose in mandos.", "accounts": { + "sc:bridge_proxy": { + "code": "file:../../bridge-proxy/output/bridge-proxy.wasm", + "nonce": "0", + "balance": "0", + "storage": { + "str:multiTransferAddress": "sc:multi_transfer" + } + }, "sc:multi_transfer": { "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "0", "roles": [ "ESDTRoleLocalMint" @@ -27,9 +35,12 @@ } }, "storage": { + "str:esdtSafeContractAddress": "sc:esdt_safe", + "str:bridgeProxyContractAddress": "sc:bridge_proxy", "str:maxTxBatchSize": "10", "str:maxTxBatchBlockDuration": "3,600", - + "str:maxBridgedAmount|nested:str:WEGLD-123456": "100,000,000,000", + "str:maxBridgedAmount|nested:str:ETH-123456": "100,000,000,000", "str:firstBatchId": "1", "str:lastBatchId": "1" }, @@ -40,37 +51,40 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": { + "str:WEGLD-123456": { "balance": "0", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] }, "str:ETH-123456": { "balance": "0", "roles": [ + "ESDTRoleLocalMint", "ESDTRoleLocalBurn" ] } }, "storage": { + "str:multiTransferContractAddress": "sc:multi_transfer", "str:feeEstimatorContractAddress": "sc:price_aggregator", + "str:bridgedTokensWrapperAddress": "sc:bridged_tokens_wrapper", "str:maxTxBatchSize": "10", "str:maxTxBatchBlockDuration": "100", "str:ethTxGasLimit": "150,000", - "str:firstBatchId": "1", "str:lastBatchId": "1", - "str:tokenTicker|nested:str:GWEI": "str:GWEI", - "str:tokenTicker|nested:str:EGLD-123456": "str:EGLD", + "str:tokenTicker|nested:str:WEGLD-123456": "str:WEGLD", "str:tokenTicker|nested:str:ETH-123456": "str:ETH", - - "str:tokenWhitelist.index|nested:str:EGLD-123456": "1", - "str:tokenWhitelist.item|u32:1": "str:EGLD-123456", + "str:tokenWhitelist.index|nested:str:WEGLD-123456": "1", + "str:tokenWhitelist.item|u32:1": "str:WEGLD-123456", "str:tokenWhitelist.index|nested:str:ETH-123456": "2", "str:tokenWhitelist.item|u32:2": "str:ETH-123456", - "str:tokenWhitelist.len": "2" + "str:tokenWhitelist.len": "2", + "str:mintBalances|nested:str:WEGLD-123456": "500,000,000,000", + "str:mintBalances|nested:str:ETH-123456": "500,000,000,000" }, "owner": "sc:multisig", "code": "file:../../esdt-safe/output/esdt-safe.wasm" @@ -99,10 +113,15 @@ "nonce": "0", "balance": "0", "esdt": { - "str:EGLD-123456": "2,000,000", - "str:ETH-123456": "1,000,000" + "str:WEGLD-123456": "100,000,000,000", + "str:ETH-123456": "200,000,000,000" }, "storage": {} + }, + "sc:egld_esdt_swap": { + "nonce": "0", + "balance": "0", + "code": "sc:egld_esdt_swap" } }, "newAddresses": [ @@ -123,6 +142,7 @@ "arguments": [ "sc:esdt_safe", "sc:multi_transfer", + "sc:bridge_proxy", "1000", "500", "2", @@ -148,20 +168,18 @@ "storage": { "str:esdtSafeAddress": "sc:esdt_safe", "str:multiTransferEsdtAddress": "sc:multi_transfer", - + "str:proxyAddress": "sc:bridge_proxy", "str:num_board_members": "2", "str:quorum": "2", "str:requiredStakeAmount": "1000", "str:slashAmount": "500", "str:user_role|u32:1": "1", "str:user_role|u32:2": "1", - "str:user_address_to_id|address:relayer1": "1", "str:user_address_to_id|address:relayer2": "2", "str:user_count": "2", "str:user_id_to_address|u32:1": "address:relayer1", "str:user_id_to_address|u32:2": "address:relayer2", - "str:pause_module:paused": "true" }, "code": "file:../output/multisig.wasm" @@ -277,7 +295,7 @@ }, "expect": { "out": [ - "str:EGLD-123456", + "str:WEGLD-123456", "str:ETH-123456" ] } @@ -300,6 +318,62 @@ "gas": "*", "refund": "*" } + }, + { + "step": "scCall", + "txId": "add-token-1", + "tx": { + "from": "sc:multisig", + "to": "sc:esdt_safe", + "value": "0", + "function": "addTokenToWhitelist", + "arguments": [ + "str:WEGLD-123456", + "str:WEGLD", + "true", + "false", + "0", + "1000000000000", + "0", + "500,000" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "add-token-1", + "tx": { + "from": "sc:multisig", + "to": "sc:esdt_safe", + "value": "0", + "function": "addTokenToWhitelist", + "arguments": [ + "str:ETH-123456", + "str:ETH", + "true", + "false", + "0", + "1000000000000", + "0", + "500,000" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } } ] -} +} \ No newline at end of file diff --git a/multisig/mandos/unstake.scen.json b/multisig/scenarios/unstake.scen.json similarity index 99% rename from multisig/mandos/unstake.scen.json rename to multisig/scenarios/unstake.scen.json index 4ba80b64..ab177b2a 100644 --- a/multisig/mandos/unstake.scen.json +++ b/multisig/scenarios/unstake.scen.json @@ -193,4 +193,4 @@ } } ] -} +} \ No newline at end of file diff --git a/multisig/src/action.rs b/multisig/src/action.rs index d2bf8850..ec83eadb 100644 --- a/multisig/src/action.rs +++ b/multisig/src/action.rs @@ -3,9 +3,10 @@ use multiversx_sc::types::ManagedVec; use transaction::transaction_status::TransactionStatus; use transaction::EthTransaction; -multiversx_sc::derive_imports!(); +use multiversx_sc::derive_imports::*; -#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] pub enum Action { Nothing, SetCurrentTransactionBatchStatus { diff --git a/multisig/src/bridge_proxy_contract_proxy.rs b/multisig/src/bridge_proxy_contract_proxy.rs new file mode 100644 index 00000000..3cb21d18 --- /dev/null +++ b/multisig/src/bridge_proxy_contract_proxy.rs @@ -0,0 +1,239 @@ +// 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 BridgeProxyContractProxy; + +impl TxProxyTrait for BridgeProxyContractProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = BridgeProxyContractProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + BridgeProxyContractProxyMethods { wrapped_tx: tx } + } +} + +pub struct BridgeProxyContractProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init< + Arg0: ProxyArg>>, + >( + self, + opt_multi_transfer_address: Arg0, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&opt_multi_transfer_address) + .original_result() + } +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgeProxyContractProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn deposit< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + eth_tx: Arg0, + batch_id: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("deposit") + .argument(ð_tx) + .argument(&batch_id) + .original_result() + } + + pub fn execute< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("execute") + .argument(&tx_id) + .original_result() + } + + pub fn get_pending_transaction_by_id< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPendingTransactionById") + .argument(&tx_id) + .original_result() + } + + pub fn get_pending_transactions( + self, + ) -> TxTypedCall>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getPendingTransactions") + .original_result() + } + + pub fn set_multi_transfer_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_multi_transfer_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferAddress") + .argument(&opt_multi_transfer_address) + .original_result() + } + + pub fn set_bridged_tokens_wrapper_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgedTokensWrapperAddress") + .argument(&opt_address) + .original_result() + } + + pub fn set_esdt_safe_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEsdtSafeAddress") + .argument(&opt_address) + .original_result() + } + + pub fn multi_transfer_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferAddress") + .original_result() + } + + pub fn bridged_tokens_wrapper_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgedTokensWrapperAddress") + .original_result() + } + + pub fn esdt_safe_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEsdtSafeContractAddress") + .original_result() + } + + pub fn highest_tx_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("highestTxId") + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} diff --git a/multisig/src/bridged_tokens_wrapper_proxy.rs b/multisig/src/bridged_tokens_wrapper_proxy.rs new file mode 100644 index 00000000..ac306e11 --- /dev/null +++ b/multisig/src/bridged_tokens_wrapper_proxy.rs @@ -0,0 +1,298 @@ +// 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 BridgedTokensWrapperProxy; + +impl TxProxyTrait for BridgedTokensWrapperProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = BridgedTokensWrapperProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + BridgedTokensWrapperProxyMethods { wrapped_tx: tx } + } +} + +pub struct BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl BridgedTokensWrapperProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn add_wrapped_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + universal_bridged_token_ids: Arg0, + num_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addWrappedToken") + .argument(&universal_bridged_token_ids) + .argument(&num_decimals) + .original_result() + } + + pub fn update_wrapped_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + universal_bridged_token_ids: Arg0, + num_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateWrappedToken") + .argument(&universal_bridged_token_ids) + .argument(&num_decimals) + .original_result() + } + + pub fn remove_wrapped_token< + Arg0: ProxyArg>, + >( + self, + universal_bridged_token_ids: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeWrappedToken") + .argument(&universal_bridged_token_ids) + .original_result() + } + + pub fn whitelist_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + Arg2: ProxyArg>, + >( + self, + chain_specific_token_id: Arg0, + chain_specific_token_decimals: Arg1, + universal_bridged_token_ids: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("whitelistToken") + .argument(&chain_specific_token_id) + .argument(&chain_specific_token_decimals) + .argument(&universal_bridged_token_ids) + .original_result() + } + + pub fn update_whitelisted_token< + Arg0: ProxyArg>, + Arg1: ProxyArg, + >( + self, + chain_specific_token_id: Arg0, + chain_specific_token_decimals: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateWhitelistedToken") + .argument(&chain_specific_token_id) + .argument(&chain_specific_token_decimals) + .original_result() + } + + pub fn blacklist_token< + Arg0: ProxyArg>, + >( + self, + chain_specific_token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("blacklistToken") + .argument(&chain_specific_token_id) + .original_result() + } + + pub fn deposit_liquidity( + self, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("depositLiquidity") + .original_result() + } + + /// Will wrap what it can, and send back the rest unchanged + pub fn wrap_tokens( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .raw_call("wrapTokens") + .original_result() + } + + pub fn unwrap_token< + Arg0: ProxyArg>, + >( + self, + requested_token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("unwrapToken") + .argument(&requested_token) + .original_result() + } + + pub fn unwrap_token_create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + requested_token: Arg0, + safe_address: Arg1, + to: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("unwrapTokenCreateTransaction") + .argument(&requested_token) + .argument(&safe_address) + .argument(&to) + .original_result() + } + + pub fn universal_bridged_token_ids( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getUniversalBridgedTokenIds") + .original_result() + } + + pub fn token_liquidity< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokenLiquidity") + .argument(&token) + .original_result() + } + + pub fn chain_specific_to_universal_mapping< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getChainSpecificToUniversalMapping") + .argument(&token) + .original_result() + } + + pub fn chain_specific_token_ids< + Arg0: ProxyArg>, + >( + self, + universal_token_id: Arg0, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getchainSpecificTokenIds") + .argument(&universal_token_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} diff --git a/multisig/src/esdt_safe_proxy.rs b/multisig/src/esdt_safe_proxy.rs new file mode 100644 index 00000000..3832da69 --- /dev/null +++ b/multisig/src/esdt_safe_proxy.rs @@ -0,0 +1,810 @@ +// 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 EsdtSafeProxy; + +impl TxProxyTrait for EsdtSafeProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = EsdtSafeProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + EsdtSafeProxyMethods { wrapped_tx: tx } + } +} + +pub struct EsdtSafeProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + /// fee_estimator_contract_address - The address of a Price Aggregator contract, + /// which will get the price of token A in token B + /// + /// eth_tx_gas_limit - The gas limit that will be used for transactions on the ETH side. + /// Will be used to compute the fees for the transfer + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + eth_tx_gas_limit: Arg2, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + >( + self, + fee_estimator_contract_address: Arg0, + multi_transfer_contract_address: Arg1, + bridge_proxy_contract_address: Arg2, + eth_tx_gas_limit: Arg3, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .argument(&fee_estimator_contract_address) + .argument(&multi_transfer_contract_address) + .argument(&bridge_proxy_contract_address) + .argument(ð_tx_gas_limit) + .original_result() + } +} + +#[rustfmt::skip] +impl EsdtSafeProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Sets the statuses for the transactions, after they were executed on the Ethereum side. + /// + /// Only TransactionStatus::Executed (3) and TransactionStatus::Rejected (4) values are allowed. + /// Number of provided statuses must be equal to number of transactions in the batch. + pub fn set_transaction_batch_status< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + batch_id: Arg0, + tx_statuses: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTransactionBatchStatus") + .argument(&batch_id) + .argument(&tx_statuses) + .original_result() + } + + /// Converts failed Ethereum -> MultiversX transactions to MultiversX -> Ethereum transaction. + /// This is done every now and then to refund the tokens. + /// + /// As with normal MultiversX -> Ethereum transactions, a part of the tokens will be + /// subtracted to pay for the fees + pub fn add_refund_batch< + Arg0: ProxyArg>>, + >( + self, + refund_transactions: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addRefundBatch") + .argument(&refund_transactions) + .original_result() + } + + /// Create an MultiversX -> Ethereum transaction. Only fungible tokens are accepted. + /// + /// Every transfer will have a part of the tokens subtracted as fees. + /// The fee amount depends on the global eth_tx_gas_limit + /// and the current GWEI price, respective to the bridged token + /// + /// fee_amount = price_per_gas_unit * eth_tx_gas_limit + pub fn create_transaction< + Arg0: ProxyArg>, + Arg1: ProxyArg>>, + >( + self, + to: Arg0, + opt_refund_info: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("createTransaction") + .argument(&to) + .argument(&opt_refund_info) + .original_result() + } + + /// Claim funds for failed MultiversX -> Ethereum transactions. + /// These are not sent automatically to prevent the contract getting stuck. + /// For example, if the receiver is a SC, a frozen account, etc. + pub fn claim_refund< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("claimRefund") + .argument(&token_id) + .original_result() + } + + pub fn set_bridged_tokens_wrapper_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgedTokensWrapperAddress") + .argument(&opt_address) + .original_result() + } + + pub fn set_bridge_proxy_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgeProxyContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn withdraw_refund_fees_for_ethereum< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawRefundFeesForEthereum") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn withdraw_transaction_fees< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + multisig_owner: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawTransactionFees") + .argument(&token_id) + .argument(&multisig_owner) + .original_result() + } + + pub fn compute_total_amounts_from_index< + Arg0: ProxyArg, + Arg1: ProxyArg, + >( + self, + start_index: Arg0, + end_index: Arg1, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("computeTotalAmmountsFromIndex") + .argument(&start_index) + .argument(&end_index) + .original_result() + } + + /// Query function that lists all refund amounts for a user. + /// Useful for knowing which token IDs to pass to the claimRefund endpoint. + pub fn get_refund_amounts< + Arg0: ProxyArg>, + >( + self, + address: Arg0, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundAmounts") + .argument(&address) + .original_result() + } + + pub fn get_total_refund_amounts( + self, + ) -> TxTypedCall, BigUint>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalRefundAmounts") + .original_result() + } + + pub fn get_refund_fees_for_ethereum< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRefundFeesForEthereum") + .argument(&token_id) + .original_result() + } + + pub fn get_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn bridged_tokens_wrapper_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgedTokensWrapperAddress") + .original_result() + } + + pub fn bridge_proxy_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgeProxyContractAddress") + .original_result() + } + + pub fn set_fee_estimator_contract_address< + Arg0: ProxyArg>, + >( + self, + new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setFeeEstimatorContractAddress") + .argument(&new_address) + .original_result() + } + + pub fn set_eth_tx_gas_limit< + Arg0: ProxyArg>, + >( + self, + new_limit: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEthTxGasLimit") + .argument(&new_limit) + .original_result() + } + + /// Default price being used if the aggregator lacks a mapping for this token + /// or the aggregator address is not set + pub fn set_default_price_per_gas_unit< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + default_price_per_gas_unit: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setDefaultPricePerGasUnit") + .argument(&token_id) + .argument(&default_price_per_gas_unit) + .original_result() + } + + /// Token ticker being used when querying the aggregator for GWEI prices + pub fn set_token_ticker< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + ticker: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setTokenTicker") + .argument(&token_id) + .argument(&ticker) + .original_result() + } + + /// Returns the fee for the given token ID (the fee amount is in the given token) + pub fn calculate_required_fee< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("calculateRequiredFee") + .argument(&token_id) + .original_result() + } + + pub fn fee_estimator_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFeeEstimatorContractAddress") + .original_result() + } + + pub fn default_price_per_gas_unit< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getDefaultPricePerGasUnit") + .argument(&token_id) + .original_result() + } + + pub fn eth_tx_gas_limit( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEthTxGasLimit") + .original_result() + } + + /// Distributes the accumulated fees to the given addresses. + /// Expected arguments are pairs of (address, percentage), + /// where percentages must add up to the PERCENTAGE_TOTAL constant + pub fn distribute_fees< + Arg0: ProxyArg>>, + >( + self, + address_percentage_pairs: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributeFees") + .argument(&address_percentage_pairs) + .original_result() + } + + pub fn add_token_to_whitelist< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg>, + Arg7: ProxyArg>>, + >( + self, + token_id: Arg0, + ticker: Arg1, + mint_burn_token: Arg2, + native_token: Arg3, + total_balance: Arg4, + mint_balance: Arg5, + burn_balance: Arg6, + opt_default_price_per_gas_unit: Arg7, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("addTokenToWhitelist") + .argument(&token_id) + .argument(&ticker) + .argument(&mint_burn_token) + .argument(&native_token) + .argument(&total_balance) + .argument(&mint_balance) + .argument(&burn_balance) + .argument(&opt_default_price_per_gas_unit) + .original_result() + } + + pub fn remove_token_from_whitelist< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeTokenFromWhitelist") + .argument(&token_id) + .original_result() + } + + pub fn get_tokens< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokens") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("initSupply") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply_mint_burn< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_id: Arg0, + mint_amount: Arg1, + burn_amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("initSupplyMintBurn") + .argument(&token_id) + .argument(&mint_amount) + .argument(&burn_amount) + .original_result() + } + + pub fn set_multi_transfer_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn token_whitelist( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAllKnownTokens") + .original_result() + } + + pub fn native_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isNativeToken") + .argument(&token) + .original_result() + } + + pub fn mint_burn_token< + Arg0: ProxyArg>, + >( + self, + token: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isMintBurnToken") + .argument(&token) + .original_result() + } + + pub fn multi_transfer_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferContractAddress") + .original_result() + } + + pub fn accumulated_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAccumulatedTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn total_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTotalBalances") + .argument(&token_id) + .original_result() + } + + pub fn mint_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMintBalances") + .argument(&token_id) + .original_result() + } + + pub fn burn_balances< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBurnBalances") + .argument(&token_id) + .original_result() + } + + pub fn set_max_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + pub fn set_max_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + pub fn get_current_tx_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentTxBatch") + .original_result() + } + + pub fn get_first_batch_any_status( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchAnyStatus") + .original_result() + } + + pub fn get_batch< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatch") + .argument(&batch_id) + .original_result() + } + + pub fn get_batch_status< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatchStatus") + .argument(&batch_id) + .original_result() + } + + pub fn first_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchId") + .original_result() + } + + pub fn last_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastBatchId") + .original_result() + } + + pub fn set_max_bridged_amount< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxBridgedAmount") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + pub fn max_bridged_amount< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMaxBridgedAmount") + .argument(&token_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, ManagedVecItem, PartialEq)] +pub struct RefundInfo +where + Api: ManagedTypeApi, +{ + pub address: ManagedAddress, + pub initial_batch_id: u64, + pub initial_nonce: u64, +} diff --git a/multisig/src/events.rs b/multisig/src/events.rs new file mode 100644 index 00000000..a1526a3d --- /dev/null +++ b/multisig/src/events.rs @@ -0,0 +1,30 @@ +use eth_address::EthAddress; + +#[multiversx_sc::module] +pub trait EventsModule { + #[event("addMapping")] + fn add_mapping_event( + &self, + #[indexed] erc20_address: EthAddress, + #[indexed] token_id: TokenIdentifier, + ); + + #[event("clearMapping")] + fn clear_mapping_event( + &self, + #[indexed] erc20_address: EthAddress, + #[indexed] token_id: TokenIdentifier, + ); + + #[event("moveRefundBatchToSafeEvent")] + fn move_refund_batch_to_safe_event(&self); + + #[event("addUnprocessedRefundTxToBatchEvent")] + fn add_unprocessed_refund_tx_to_batch_event(&self, #[indexed] tx_id: u64); + + #[event("pauseBridgeProxyEvent")] + fn pause_bridge_proxy_event(&self); + + #[event("unpauseBridgeProxyEvent")] + fn unpause_bridge_proxy_event(&self); +} diff --git a/multisig/src/lib.rs b/multisig/src/lib.rs index 39c658ea..cb2bef3a 100644 --- a/multisig/src/lib.rs +++ b/multisig/src/lib.rs @@ -2,6 +2,7 @@ #![allow(clippy::too_many_arguments)] mod action; +mod events; mod multisig_general; mod queries; mod setup; @@ -9,6 +10,11 @@ mod storage; mod user_role; mod util; +pub mod bridge_proxy_contract_proxy; +pub mod esdt_safe_proxy; +pub mod multi_transfer_esdt_proxy; +pub mod multisig_proxy; + use action::Action; use token_module::{AddressPercentagePair, INVALID_PERCENTAGE_SUM_OVER_ERR_MSG, PERCENTAGE_TOTAL}; use transaction::transaction_status::TransactionStatus; @@ -16,18 +22,14 @@ use transaction::TxBatchSplitInFields; use transaction::*; use user_role::UserRole; -use esdt_safe::ProxyTrait as _; -use multi_transfer_esdt::ProxyTrait as _; -use token_module::ProxyTrait as _; -use tx_batch_module::ProxyTrait as _; - -multiversx_sc::imports!(); +use multiversx_sc::imports::*; /// Multi-signature smart contract implementation. /// Acts like a wallet that needs multiple signers for any action performed. #[multiversx_sc::contract] pub trait Multisig: multisig_general::MultisigGeneralModule + + events::EventsModule + setup::SetupModule + storage::StorageModule + util::UtilModule @@ -41,6 +43,7 @@ pub trait Multisig: &self, esdt_safe_sc_address: ManagedAddress, multi_transfer_sc_address: ManagedAddress, + proxy_sc_address: ManagedAddress, required_stake: BigUint, slash_amount: BigUint, quorum: usize, @@ -82,11 +85,44 @@ pub trait Multisig: self.multi_transfer_esdt_address() .set(&multi_transfer_sc_address); + require!( + self.blockchain().is_smart_contract(&proxy_sc_address), + "Proxy address is not a Smart Contract address" + ); + self.proxy_address().set(&proxy_sc_address); + self.set_paused(true); } #[upgrade] - fn upgrade(&self) {} + fn upgrade( + &self, + esdt_safe_sc_address: ManagedAddress, + multi_transfer_sc_address: ManagedAddress, + proxy_sc_address: ManagedAddress, + ) { + require!( + self.blockchain().is_smart_contract(&esdt_safe_sc_address), + "Esdt Safe address is not a Smart Contract address" + ); + self.esdt_safe_address().set(&esdt_safe_sc_address); + + require!( + self.blockchain() + .is_smart_contract(&multi_transfer_sc_address), + "Multi Transfer address is not a Smart Contract address" + ); + self.multi_transfer_esdt_address() + .set(&multi_transfer_sc_address); + + require!( + self.blockchain().is_smart_contract(&proxy_sc_address), + "Proxy address is not a Smart Contract address" + ); + self.proxy_address().set(&proxy_sc_address); + + self.set_paused(true); + } /// Distributes the accumulated fees to the given addresses. /// Expected arguments are pairs of (address, percentage), @@ -119,11 +155,12 @@ pub trait Multisig: total_percentage == PERCENTAGE_TOTAL as u64, INVALID_PERCENTAGE_SUM_OVER_ERR_MSG ); - - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .distribute_fees(args) - .execute_on_dest_context(); + .sync_call(); } /// Board members have to stake a certain amount of EGLD @@ -161,7 +198,7 @@ pub trait Multisig: } self.amount_staked(&caller).set(&remaining_stake); - self.send().direct_egld(&caller, &amount); + self.tx().to(ToCaller).egld(&amount).transfer(); } // ESDT Safe SC calls @@ -177,10 +214,15 @@ pub trait Multisig: esdt_safe_batch_id: u64, tx_batch_status: MultiValueEncoded, ) -> usize { + let esdt_safe_addr = self.esdt_safe_address().get(); let call_result: OptionalValue> = self - .get_esdt_safe_proxy_instance() + .tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .get_current_tx_batch() - .execute_on_dest_context(); + .returns(ReturnsResult) + .sync_call(); + let (current_batch_id, current_batch_transactions) = match call_result { OptionalValue::Some(batch) => batch.into_tuple(), OptionalValue::None => sc_panic!("Current batch is empty"), @@ -218,7 +260,7 @@ pub trait Multisig: // Multi-transfer ESDT SC calls - /// Proposes a batch of Ethereum -> Elrond transfers. + /// Proposes a batch of Ethereum -> MultiversX transfers. /// Transactions have to be separated by fields, in the following order: /// Sender Address, Destination Address, Token ID, Amount, Tx Nonce #[endpoint(proposeMultiTransferEsdtBatch)] @@ -255,33 +297,86 @@ pub trait Multisig: action_id } - /// Failed Ethereum -> Elrond transactions are saved in the MultiTransfer SC + /// Failed Ethereum -> MultiversX transactions are saved in the MultiTransfer SC /// as "refund transactions", and stored in batches, using the same mechanism as EsdtSafe. /// /// This function moves the first refund batch into the EsdtSafe SC, - /// converting the transactions into Elrond -> Ethereum transactions + /// converting the transactions into MultiversX -> Ethereum transactions /// and adding them into EsdtSafe batches #[only_owner] - #[endpoint(moveRefundBatchToSafe)] - fn move_refund_batch_to_safe(&self) { - let opt_refund_batch_fields: OptionalValue> = self - .get_multi_transfer_esdt_proxy_instance() - .get_and_clear_first_refund_batch() - .execute_on_dest_context(); - - if let OptionalValue::Some(refund_batch_fields) = opt_refund_batch_fields { - let (_batch_id, all_tx_fields) = refund_batch_fields.into_tuple(); - let mut refund_batch = ManagedVec::new(); - - for tx_fields in all_tx_fields { - refund_batch.push(Transaction::from(tx_fields)); - } + #[endpoint(moveRefundBatchToSafeFromChildContract)] + fn move_refund_batch_to_safe_from_child_contract(&self) { + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) + .move_refund_batch_to_safe() + .sync_call(); + + self.move_refund_batch_to_safe_event(); + } - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() - .add_refund_batch(refund_batch) - .execute_on_dest_context(); - } + #[only_owner] + #[payable("*")] + #[endpoint(initSupplyFromChildContract)] + fn init_supply_from_child_contract(&self, token_id: TokenIdentifier, amount: BigUint) { + let (payment_token, payment_amount) = self.call_value().single_fungible_esdt(); + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .init_supply(token_id, amount) + .payment((payment_token, 0, payment_amount)) + .sync_call(); + } + + #[only_owner] + #[endpoint(addUnprocessedRefundTxToBatch)] + fn add_unprocessed_refund_tx_to_batch(&self, tx_id: u64) { + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) + .add_unprocessed_refund_tx_to_batch(tx_id) + .sync_call(); + + self.add_unprocessed_refund_tx_to_batch_event(tx_id); + } + + #[only_owner] + #[endpoint(withdrawRefundFeesForEthereum)] + fn withdraw_refund_fees_for_ethereum(&self, token_id: TokenIdentifier) { + let esdt_safe_addr = self.esdt_safe_address().get(); + let multisig_owner = self.blockchain().get_owner_address(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .withdraw_refund_fees_for_ethereum(token_id, multisig_owner) + .sync_call(); + } + + #[only_owner] + #[endpoint(withdrawTransactionFees)] + fn withdraw_transaction_fees(&self, token_id: TokenIdentifier) { + let esdt_safe_addr = self.esdt_safe_address().get(); + let multisig_owner = self.blockchain().get_owner_address(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .withdraw_transaction_fees(token_id, multisig_owner) + .sync_call(); + } + + #[only_owner] + #[endpoint(withdrawSlashedAmount)] + fn withdraw_slashed_amount(&self) { + let slashed_tokens_amount_mapper = self.slashed_tokens_amount(); + let slashed_amount = slashed_tokens_amount_mapper.get(); + self.tx().to(ToCaller).egld(&slashed_amount).transfer(); + slashed_tokens_amount_mapper.clear(); } /// Proposers and board members use this to launch signed actions. @@ -331,14 +426,15 @@ pub trait Multisig: } action_ids_mapper.clear(); - - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_transaction_batch_status( esdt_safe_batch_id, MultiValueEncoded::from(tx_batch_status), ) - .execute_on_dest_context(); + .sync_call(); } Action::BatchTransferEsdtToken { eth_batch_id, @@ -361,12 +457,15 @@ pub trait Multisig: let last_tx = transfers.get(last_tx_index); self.last_executed_eth_tx_id().set(last_tx.tx_nonce); + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); let transfers_multi: MultiValueEncoded> = transfers.into(); - let _: IgnoreValue = self - .get_multi_transfer_esdt_proxy_instance() + + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) .batch_transfer_esdt_token(eth_batch_id, transfers_multi) - .execute_on_dest_context(); + .sync_call(); } } } diff --git a/multisig/src/multi_transfer_esdt_proxy.rs b/multisig/src/multi_transfer_esdt_proxy.rs new file mode 100644 index 00000000..68871989 --- /dev/null +++ b/multisig/src/multi_transfer_esdt_proxy.rs @@ -0,0 +1,304 @@ +// 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 MultiTransferEsdtProxy; + +impl TxProxyTrait for MultiTransferEsdtProxy +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + type TxProxyMethods = MultiTransferEsdtProxyMethods; + + fn proxy_methods(self, tx: Tx) -> Self::TxProxyMethods { + MultiTransferEsdtProxyMethods { wrapped_tx: tx } + } +} + +pub struct MultiTransferEsdtProxyMethods +where + Env: TxEnv, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + wrapped_tx: Tx, +} + +#[rustfmt::skip] +impl MultiTransferEsdtProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + Gas: TxGas, +{ + pub fn init( + self, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .original_result() + } +} + +#[rustfmt::skip] +impl MultiTransferEsdtProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn upgrade( + self, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .original_result() + } +} + +#[rustfmt::skip] +impl MultiTransferEsdtProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + pub fn batch_transfer_esdt_token< + Arg0: ProxyArg, + Arg1: ProxyArg>>, + >( + self, + batch_id: Arg0, + transfers: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("batchTransferEsdtToken") + .argument(&batch_id) + .argument(&transfers) + .original_result() + } + + pub fn move_refund_batch_to_safe( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("moveRefundBatchToSafe") + .original_result() + } + + pub fn set_wrapping_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setWrappingContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn set_bridge_proxy_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setBridgeProxyContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn add_unprocessed_refund_tx_to_batch< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addUnprocessedRefundTxToBatch") + .argument(&tx_id) + .original_result() + } + + pub fn set_esdt_safe_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEsdtSafeContractAddress") + .argument(&opt_new_address) + .original_result() + } + + pub fn wrapping_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getWrappingContractAddress") + .original_result() + } + + pub fn bridge_proxy_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBridgeProxyContractAddress") + .original_result() + } + + pub fn esdt_safe_contract_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEsdtSafeContractAddress") + .original_result() + } + + pub fn set_max_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + pub fn set_max_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + pub fn get_current_tx_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentTxBatch") + .original_result() + } + + pub fn get_first_batch_any_status( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchAnyStatus") + .original_result() + } + + pub fn get_batch< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatch") + .argument(&batch_id) + .original_result() + } + + pub fn get_batch_status< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatchStatus") + .argument(&batch_id) + .original_result() + } + + pub fn first_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getFirstBatchId") + .original_result() + } + + pub fn last_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastBatchId") + .original_result() + } + + pub fn set_max_bridged_amount< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMaxBridgedAmount") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + pub fn max_bridged_amount< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMaxBridgedAmount") + .argument(&token_id) + .original_result() + } +} diff --git a/multisig/src/multisig_general.rs b/multisig/src/multisig_general.rs index c044e663..91f54be0 100644 --- a/multisig/src/multisig_general.rs +++ b/multisig/src/multisig_general.rs @@ -1,4 +1,4 @@ -multiversx_sc::imports!(); +use multiversx_sc::imports::*; use crate::action::Action; use crate::user_role::UserRole; diff --git a/multisig/src/multisig_proxy.rs b/multisig/src/multisig_proxy.rs new file mode 100644 index 00000000..a652c8ba --- /dev/null +++ b/multisig/src/multisig_proxy.rs @@ -0,0 +1,1185 @@ +// 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, +{ + /// EsdtSafe and MultiTransferEsdt are expected to be deployed and configured separately, + /// and then having their ownership changed to this Multisig SC. + pub fn init< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + Arg3: ProxyArg>, + Arg4: ProxyArg>, + Arg5: ProxyArg, + Arg6: ProxyArg>>, + >( + self, + esdt_safe_sc_address: Arg0, + multi_transfer_sc_address: Arg1, + proxy_sc_address: Arg2, + required_stake: Arg3, + slash_amount: Arg4, + quorum: Arg5, + board: Arg6, + ) -> TxTypedDeploy { + self.wrapped_tx + .payment(NotPayable) + .raw_deploy() + .argument(&esdt_safe_sc_address) + .argument(&multi_transfer_sc_address) + .argument(&proxy_sc_address) + .argument(&required_stake) + .argument(&slash_amount) + .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>, + Arg2: ProxyArg>, + >( + self, + esdt_safe_sc_address: Arg0, + multi_transfer_sc_address: Arg1, + proxy_sc_address: Arg2, + ) -> TxTypedUpgrade { + self.wrapped_tx + .payment(NotPayable) + .raw_upgrade() + .argument(&esdt_safe_sc_address) + .argument(&multi_transfer_sc_address) + .argument(&proxy_sc_address) + .original_result() + } +} + +#[rustfmt::skip] +impl MultisigProxyMethods +where + Env: TxEnv, + Env::Api: VMApi, + From: TxFrom, + To: TxTo, + Gas: TxGas, +{ + /// Distributes the accumulated fees to the given addresses. + /// Expected arguments are pairs of (address, percentage), + /// where percentages must add up to the PERCENTAGE_TOTAL constant + pub fn distribute_fees_from_child_contracts< + Arg0: ProxyArg, u32>>>, + >( + self, + dest_address_percentage_pairs: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("distributeFeesFromChildContracts") + .argument(&dest_address_percentage_pairs) + .original_result() + } + + /// Board members have to stake a certain amount of EGLD + /// before being allowed to sign actions + pub fn stake( + self, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("stake") + .original_result() + } + + pub fn unstake< + Arg0: ProxyArg>, + >( + self, + amount: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unstake") + .argument(&amount) + .original_result() + } + + /// After a batch is processed on the Ethereum side, + /// the EsdtSafe expects a list of statuses of said transactions (success or failure). + /// + /// This endpoint proposes an action to set the statuses to a certain list of values. + /// Nothing is changed in the EsdtSafe contract until the action is signed and executed. + pub fn propose_esdt_safe_set_current_transaction_batch_status< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + esdt_safe_batch_id: Arg0, + tx_batch_status: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("proposeEsdtSafeSetCurrentTransactionBatchStatus") + .argument(&esdt_safe_batch_id) + .argument(&tx_batch_status) + .original_result() + } + + /// Proposes a batch of Ethereum -> MultiversX transfers. + /// Transactions have to be separated by fields, in the following order: + /// Sender Address, Destination Address, Token ID, Amount, Tx Nonce + pub fn propose_multi_transfer_esdt_batch< + Arg0: ProxyArg, + Arg1: ProxyArg, ManagedAddress, TokenIdentifier, BigUint, u64, ManagedOption>>>>, + >( + self, + eth_batch_id: Arg0, + transfers: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("proposeMultiTransferEsdtBatch") + .argument(ð_batch_id) + .argument(&transfers) + .original_result() + } + + /// Failed Ethereum -> MultiversX transactions are saved in the MultiTransfer SC + /// as "refund transactions", and stored in batches, using the same mechanism as EsdtSafe. + /// + /// This function moves the first refund batch into the EsdtSafe SC, + /// converting the transactions into MultiversX -> Ethereum transactions + /// and adding them into EsdtSafe batches + pub fn move_refund_batch_to_safe_from_child_contract( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("moveRefundBatchToSafeFromChildContract") + .original_result() + } + + pub fn init_supply_from_child_contract< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("initSupplyFromChildContract") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn add_unprocessed_refund_tx_to_batch< + Arg0: ProxyArg, + >( + self, + tx_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addUnprocessedRefundTxToBatch") + .argument(&tx_id) + .original_result() + } + + pub fn withdraw_refund_fees_for_ethereum< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawRefundFeesForEthereum") + .argument(&token_id) + .original_result() + } + + pub fn withdraw_transaction_fees< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawTransactionFees") + .argument(&token_id) + .original_result() + } + + pub fn withdraw_slashed_amount( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("withdrawSlashedAmount") + .original_result() + } + + /// Proposers and board members use this to launch signed actions. + pub fn perform_action_endpoint< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("performAction") + .argument(&action_id) + .original_result() + } + + /// Used by board members to sign actions. + pub fn sign< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("sign") + .argument(&action_id) + .original_result() + } + + pub fn upgrade_child_contract_from_source< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg>>, + >( + self, + child_sc_address: Arg0, + source_address: Arg1, + is_payable: Arg2, + init_args: Arg3, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("upgradeChildContractFromSource") + .argument(&child_sc_address) + .argument(&source_address) + .argument(&is_payable) + .argument(&init_args) + .original_result() + } + + pub fn add_board_member_endpoint< + Arg0: ProxyArg>, + >( + self, + board_member: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addBoardMember") + .argument(&board_member) + .original_result() + } + + pub fn remove_user< + Arg0: ProxyArg>, + >( + self, + board_member: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("removeUser") + .argument(&board_member) + .original_result() + } + + /// Cuts a fixed amount from a board member's stake. + /// This should be used only in cases where the board member + /// is being actively malicious. + /// + /// After stake is cut, the board member would have to stake again + /// to be able to sign actions. + pub fn slash_board_member< + Arg0: ProxyArg>, + >( + self, + board_member: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("slashBoardMember") + .argument(&board_member) + .original_result() + } + + pub fn change_quorum< + Arg0: ProxyArg, + >( + self, + new_quorum: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeQuorum") + .argument(&new_quorum) + .original_result() + } + + /// Maps an ESDT token to an ERC20 address. Used by relayers. + pub fn add_mapping< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + erc20_address: Arg0, + token_id: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("addMapping") + .argument(&erc20_address) + .argument(&token_id) + .original_result() + } + + pub fn clear_mapping< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + erc20_address: Arg0, + token_id: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("clearMapping") + .argument(&erc20_address) + .argument(&token_id) + .original_result() + } + + pub fn pause_esdt_safe( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pauseEsdtSafe") + .original_result() + } + + pub fn unpause_esdt_safe( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpauseEsdtSafe") + .original_result() + } + + pub fn init_supply_esdt_safe< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .raw_call("initSupplyEsdtSafe") + .argument(&token_id) + .argument(&amount) + .original_result() + } + + pub fn init_supply_mint_burn_esdt_safe< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg>, + >( + self, + token_id: Arg0, + mint_amount: Arg1, + burn_amount: Arg2, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("initSupplyMintBurnEsdtSafe") + .argument(&token_id) + .argument(&mint_amount) + .argument(&burn_amount) + .original_result() + } + + pub fn pause_proxy( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pauseProxy") + .original_result() + } + + pub fn unpause_proxy( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpauseProxy") + .original_result() + } + + pub fn change_fee_estimator_contract_address< + Arg0: ProxyArg>, + >( + self, + new_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeFeeEstimatorContractAddress") + .argument(&new_address) + .original_result() + } + + /// Sets the gas limit being used for Ethereum transactions + /// This is used in the EsdtSafe contract to determine the fee amount + /// + /// fee_amount = eth_gas_limit * price_per_gas_unit + /// + /// where price_per_gas_unit is queried from the aggregator (fee estimator SC) + pub fn change_multiversx_to_eth_gas_limit< + Arg0: ProxyArg>, + >( + self, + new_gas_limit: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeMultiversXToEthGasLimit") + .argument(&new_gas_limit) + .original_result() + } + + /// Default price being used if the aggregator lacks a mapping for this token + /// or the aggregator address is not set + pub fn change_default_price_per_gas_unit< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + new_value: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeDefaultPricePerGasUnit") + .argument(&token_id) + .argument(&new_value) + .original_result() + } + + /// Token ticker being used when querying the aggregator for GWEI prices + pub fn change_token_ticker< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + new_ticker: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeTokenTicker") + .argument(&token_id) + .argument(&new_ticker) + .original_result() + } + + pub fn esdt_safe_add_token_to_whitelist< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + Arg2: ProxyArg, + Arg3: ProxyArg, + Arg4: ProxyArg>, + Arg5: ProxyArg>, + Arg6: ProxyArg>, + Arg7: ProxyArg>>, + >( + self, + token_id: Arg0, + ticker: Arg1, + mint_burn_allowed: Arg2, + is_native_token: Arg3, + total_balance: Arg4, + mint_balance: Arg5, + burn_balance: Arg6, + opt_default_price_per_gas_unit: Arg7, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("esdtSafeAddTokenToWhitelist") + .argument(&token_id) + .argument(&ticker) + .argument(&mint_burn_allowed) + .argument(&is_native_token) + .argument(&total_balance) + .argument(&mint_balance) + .argument(&burn_balance) + .argument(&opt_default_price_per_gas_unit) + .original_result() + } + + pub fn set_multi_transfer_on_esdt_safe( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setMultiTransferOnEsdtSafe") + .original_result() + } + + pub fn set_esdt_safe_on_multi_transfer( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("setEsdtSafeOnMultiTransfer") + .original_result() + } + + pub fn esdt_safe_remove_token_from_whitelist< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("esdtSafeRemoveTokenFromWhitelist") + .argument(&token_id) + .original_result() + } + + /// Sets maximum batch size for the EsdtSafe SC. + /// If a batch reaches this amount of transactions, it is considered full, + /// and a new incoming transaction will be put into a new batch. + pub fn esdt_safe_set_max_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("esdtSafeSetMaxTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + /// Sets the maximum block duration in which an EsdtSafe batch accepts transactions + /// For a batch to be considered "full", it has to either reach `maxTxBatchSize` transactions, + /// or have txBatchBlockDuration blocks pass since the first tx was added in the batch + pub fn esdt_safe_set_max_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("esdtSafeSetMaxTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + /// Sets the maximum bridged amount for the token for the MultiversX -> Ethereum direction. + /// Any attempt to transfer over this amount will be rejected. + pub fn esdt_safe_set_max_bridged_amount_for_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("esdtSafeSetMaxBridgedAmountForToken") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + /// Same as the function above, but for Ethereum -> MultiversX transactions. + pub fn multi_transfer_esdt_set_max_bridged_amount_for_token< + Arg0: ProxyArg>, + Arg1: ProxyArg>, + >( + self, + token_id: Arg0, + max_amount: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("multiTransferEsdtSetMaxBridgedAmountForToken") + .argument(&token_id) + .argument(&max_amount) + .original_result() + } + + /// Any failed Ethereum -> MultiversX transactions are added into so-called "refund batches\ + /// This configures the size of a batch. + pub fn multi_transfer_esdt_set_max_refund_tx_batch_size< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_size: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("multiTransferEsdtSetMaxRefundTxBatchSize") + .argument(&new_max_tx_batch_size) + .original_result() + } + + /// Max block duration for refund batches. Default is "infinite" (u64::MAX) + /// and only max batch size matters + pub fn multi_transfer_esdt_set_max_refund_tx_batch_block_duration< + Arg0: ProxyArg, + >( + self, + new_max_tx_batch_block_duration: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("multiTransferEsdtSetMaxRefundTxBatchBlockDuration") + .argument(&new_max_tx_batch_block_duration) + .original_result() + } + + /// Sets the wrapping contract address. + /// This contract is used to map multiple tokens to a universal one. + /// Useful in cases where a single token (USDC for example) + /// is being transferred from multiple chains. + /// + /// They will all have different token IDs, but can be swapped 1:1 in the wrapping SC. + /// The wrapping is done automatically, so the user only receives the universal token. + pub fn multi_transfer_esdt_set_wrapping_contract_address< + Arg0: ProxyArg>>, + >( + self, + opt_wrapping_contract_address: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("multiTransferEsdtSetWrappingContractAddress") + .argument(&opt_wrapping_contract_address) + .original_result() + } + + /// Minimum number of signatures needed to perform any action. + pub fn quorum( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getNumBoardMembers") + .original_result() + } + + /// The required amount to stake for accepting relayer position + pub fn required_stake_amount( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getRequiredStakeAmount") + .original_result() + } + + /// Staked amount by each board member. + pub fn amount_staked< + Arg0: ProxyArg>, + >( + self, + board_member_address: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAmountStaked") + .argument(&board_member_address) + .original_result() + } + + /// Amount of stake slashed if a relayer is misbehaving + pub fn slash_amount( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getSlashAmount") + .original_result() + } + + /// Total slashed tokens accumulated + pub fn slashed_tokens_amount( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getSlashedTokensAmount") + .original_result() + } + + pub fn last_executed_eth_batch_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastExecutedEthBatchId") + .original_result() + } + + pub fn last_executed_eth_tx_id( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getLastExecutedEthTxId") + .original_result() + } + + /// Mapping between ERC20 Ethereum address and MultiversX ESDT Token Identifiers + pub fn erc20_address_for_token_id< + Arg0: ProxyArg>, + >( + self, + token_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getErc20AddressForTokenId") + .argument(&token_id) + .original_result() + } + + pub fn token_id_for_erc20_address< + Arg0: ProxyArg>, + >( + self, + erc20_address: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getTokenIdForErc20Address") + .argument(&erc20_address) + .original_result() + } + + pub fn esdt_safe_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getEsdtSafeAddress") + .original_result() + } + + pub fn multi_transfer_esdt_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getMultiTransferEsdtAddress") + .original_result() + } + + pub fn proxy_address( + self, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getProxyAddress") + .original_result() + } + + /// Returns the current EsdtSafe batch. + /// + /// First result is the batch ID, then pairs of 6 results, representing transactions + /// split by fields: + /// + /// Block Nonce, Tx Nonce, Sender Address, Receiver Address, Token ID, Amount + pub fn get_current_tx_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentTxBatch") + .original_result() + } + + /// Returns the EsdtSafe batch that has the provided batch_id. + /// + /// First result is the batch ID, then pairs of 6 results, representing transactions + /// split by fields: + /// + /// Block Nonce, Tx Nonce, Sender Address, Receiver Address, Token ID, Amount + pub fn get_batch< + Arg0: ProxyArg, + >( + self, + batch_id: Arg0, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getBatch") + .argument(&batch_id) + .original_result() + } + + /// Returns a batch of failed Ethereum -> MultiversX transactions. + /// The result format is the same as getCurrentTxBatch + pub fn get_current_refund_batch( + self, + ) -> TxTypedCall, ManagedBuffer, TokenIdentifier, BigUint>>>>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getCurrentRefundBatch") + .original_result() + } + + /// Actions are cleared after execution, so an empty entry means the action was executed already + /// Returns "false" if the action ID is invalid + pub fn was_action_executed< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("wasActionExecuted") + .argument(&action_id) + .original_result() + } + + /// Used for Ethereum -> MultiversX batches. + /// If the mapping was made, it means that the transfer action was proposed in the past. + /// To check if it was executed as well, use the wasActionExecuted view + pub fn was_transfer_action_proposed< + Arg0: ProxyArg, + Arg1: ProxyArg, ManagedAddress, TokenIdentifier, BigUint, u64, ManagedOption>>>>, + >( + self, + eth_batch_id: Arg0, + transfers: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("wasTransferActionProposed") + .argument(ð_batch_id) + .argument(&transfers) + .original_result() + } + + /// Used for Ethereum -> MultiversX batches. + /// If `wasActionExecuted` returns true, then this can be used to get the action ID. + /// Will return 0 if the transfers were not proposed + pub fn get_action_id_for_transfer_batch< + Arg0: ProxyArg, + Arg1: ProxyArg, ManagedAddress, TokenIdentifier, BigUint, u64, ManagedOption>>>>, + >( + self, + eth_batch_id: Arg0, + transfers: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getActionIdForTransferBatch") + .argument(ð_batch_id) + .argument(&transfers) + .original_result() + } + + /// Used for MultiversX -> Ethereum batches. + /// Returns "true" if an action was already proposed for the given batch, + /// with these exact transaction statuses, in this exact order + pub fn was_set_current_transaction_batch_status_action_proposed< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + esdt_safe_batch_id: Arg0, + expected_tx_batch_status: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("wasSetCurrentTransactionBatchStatusActionProposed") + .argument(&esdt_safe_batch_id) + .argument(&expected_tx_batch_status) + .original_result() + } + + /// If `wasSetCurrentTransactionBatchStatusActionProposed` return true, + /// this can be used to get the action ID. + /// Will return 0 if the set status action was not proposed + pub fn get_action_id_for_set_current_transaction_batch_status< + Arg0: ProxyArg, + Arg1: ProxyArg>, + >( + self, + esdt_safe_batch_id: Arg0, + expected_tx_batch_status: Arg1, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getActionIdForSetCurrentTransactionBatchStatus") + .argument(&esdt_safe_batch_id) + .argument(&expected_tx_batch_status) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("signed") + .argument(&user) + .argument(&action_id) + .original_result() + } + + /// Indicates user rights. + /// `0` = no rights, + /// `1` = can propose. Can also sign if they have enough stake. + pub fn user_role< + Arg0: ProxyArg>, + >( + self, + user: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("userRole") + .argument(&user) + .original_result() + } + + /// Lists all board members + pub fn get_all_board_members( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAllBoardMembers") + .original_result() + } + + /// Lists all board members that staked the correct amount. + /// A board member with not enough stake can propose, but cannot sign. + pub fn get_all_staked_relayers( + self, + ) -> TxTypedCall>> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getAllStakedRelayers") + .original_result() + } + + /// Gets the number of signatures for the action with the given ID + pub fn get_action_signer_count< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getActionValidSignerCount") + .argument(&action_id) + .original_result() + } + + /// Returns `true` (`1`) if `getActionValidSignerCount >= getQuorum`. + pub fn quorum_reached< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("quorumReached") + .argument(&action_id) + .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, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getActionLastIndex") + .original_result() + } + + /// Serialized action data of an action with index. + pub fn get_action_data< + Arg0: ProxyArg, + >( + self, + action_id: Arg0, + ) -> TxTypedCall> { + self.wrapped_tx + .payment(NotPayable) + .raw_call("getActionData") + .argument(&action_id) + .original_result() + } + + pub fn pause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("pause") + .original_result() + } + + pub fn unpause_endpoint( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("unpause") + .original_result() + } + + pub fn paused_status( + self, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("isPaused") + .original_result() + } +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq)] +pub enum UserRole { + None, + BoardMember, +} + +#[rustfmt::skip] +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode)] +pub enum Action +where + Api: ManagedTypeApi, +{ + Nothing, + SetCurrentTransactionBatchStatus { + esdt_safe_batch_id: u64, + tx_batch_status: ManagedVec, + }, + BatchTransferEsdtToken { + eth_batch_id: u64, + transfers: ManagedVec>, + }, +} diff --git a/multisig/src/queries.rs b/multisig/src/queries.rs index dc5c15ad..4bb93210 100644 --- a/multisig/src/queries.rs +++ b/multisig/src/queries.rs @@ -1,10 +1,8 @@ -multiversx_sc::imports!(); +use multiversx_sc::imports::*; -use crate::{action::Action, user_role::UserRole}; +use crate::{action::Action, esdt_safe_proxy, multi_transfer_esdt_proxy, user_role::UserRole}; use transaction::{transaction_status::TransactionStatus, EthTxAsMultiValue, TxBatchSplitInFields}; -use tx_batch_module::ProxyTrait as _; - /// Note: Additional queries can be found in the Storage module #[multiversx_sc::module] pub trait QueriesModule: crate::storage::StorageModule + crate::util::UtilModule { @@ -16,18 +14,45 @@ pub trait QueriesModule: crate::storage::StorageModule + crate::util::UtilModule /// Block Nonce, Tx Nonce, Sender Address, Receiver Address, Token ID, Amount #[view(getCurrentTxBatch)] fn get_current_tx_batch(&self) -> OptionalValue> { - self.get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .get_current_tx_batch() - .execute_on_dest_context() + .returns(ReturnsResult) + .sync_call() + } + + /// Returns the EsdtSafe batch that has the provided batch_id. + /// + /// First result is the batch ID, then pairs of 6 results, representing transactions + /// split by fields: + /// + /// Block Nonce, Tx Nonce, Sender Address, Receiver Address, Token ID, Amount + #[view(getBatch)] + fn get_batch(&self, batch_id: u64) -> OptionalValue> { + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .get_batch(batch_id) + .returns(ReturnsResult) + .sync_call() } - /// Returns a batch of failed Ethereum -> Elrond transactions. + /// Returns a batch of failed Ethereum -> MultiversX transactions. /// The result format is the same as getCurrentTxBatch #[view(getCurrentRefundBatch)] fn get_current_refund_batch(&self) -> OptionalValue> { - self.get_multi_transfer_esdt_proxy_instance() + let multi_transfer_addr = self.multi_transfer_esdt_address().get(); + self.tx() + .to(multi_transfer_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) .get_first_batch_any_status() - .execute_on_dest_context() + .returns(ReturnsResult) + .sync_call() } /// Actions are cleared after execution, so an empty entry means the action was executed already @@ -41,7 +66,7 @@ pub trait QueriesModule: crate::storage::StorageModule + crate::util::UtilModule } } - /// Used for Ethereum -> Elrond batches. + /// Used for Ethereum -> MultiversX batches. /// If the mapping was made, it means that the transfer action was proposed in the past. /// To check if it was executed as well, use the wasActionExecuted view #[view(wasTransferActionProposed)] @@ -55,7 +80,7 @@ pub trait QueriesModule: crate::storage::StorageModule + crate::util::UtilModule self.is_valid_action_id(action_id) } - /// Used for Ethereum -> Elrond batches. + /// Used for Ethereum -> MultiversX batches. /// If `wasActionExecuted` returns true, then this can be used to get the action ID. /// Will return 0 if the transfers were not proposed #[view(getActionIdForTransferBatch)] @@ -72,7 +97,7 @@ pub trait QueriesModule: crate::storage::StorageModule + crate::util::UtilModule .unwrap_or(0) } - /// Used for Elrond -> Ethereum batches. + /// Used for MultiversX -> Ethereum batches. /// Returns "true" if an action was already proposed for the given batch, /// with these exact transaction statuses, in this exact order #[view(wasSetCurrentTransactionBatchStatusActionProposed)] diff --git a/multisig/src/setup.rs b/multisig/src/setup.rs index 624b1c98..c1e4706a 100644 --- a/multisig/src/setup.rs +++ b/multisig/src/setup.rs @@ -1,20 +1,15 @@ -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::imports::*; use eth_address::EthAddress; -use fee_estimator_module::ProxyTrait as _; -use max_bridged_amount_module::ProxyTrait as _; -use multi_transfer_esdt::ProxyTrait as _; -use multiversx_sc_modules::pause::ProxyTrait as _; -use token_module::ProxyTrait as _; -use tx_batch_module::ProxyTrait as _; +use crate::{bridge_proxy_contract_proxy, esdt_safe_proxy, multi_transfer_esdt_proxy}; #[multiversx_sc::module] pub trait SetupModule: crate::multisig_general::MultisigGeneralModule + crate::storage::StorageModule + crate::util::UtilModule + + crate::events::EventsModule + multiversx_sc_modules::pause::PauseModule { #[only_owner] @@ -70,8 +65,6 @@ pub trait SetupModule: #[only_owner] #[endpoint(slashBoardMember)] fn slash_board_member(&self, board_member: ManagedAddress) { - self.remove_user(board_member.clone()); - let slash_amount = self.slash_amount().get(); // remove slashed amount from user stake amountself @@ -110,6 +103,7 @@ pub trait SetupModule: .set(&erc20_address); self.token_id_for_erc20_address(&erc20_address) .set(&token_id); + self.add_mapping_event(erc20_address, token_id); } #[only_owner] @@ -134,33 +128,106 @@ pub trait SetupModule: self.erc20_address_for_token_id(&token_id).clear(); self.token_id_for_erc20_address(&erc20_address).clear(); + self.clear_mapping_event(erc20_address, token_id); } #[only_owner] #[endpoint(pauseEsdtSafe)] fn pause_esdt_safe(&self) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .pause_endpoint() - .execute_on_dest_context(); + .sync_call(); + + self.pause_bridge_proxy_event(); } #[only_owner] #[endpoint(unpauseEsdtSafe)] fn unpause_esdt_safe(&self) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .unpause_endpoint() + .sync_call(); + self.unpause_bridge_proxy_event(); + } + + #[only_owner] + #[payable("*")] + #[endpoint(initSupplyEsdtSafe)] + fn init_supply_esdt_safe(&self, token_id: TokenIdentifier, amount: BigUint) { + let esdt_safe_addr = self.esdt_safe_address().get(); + let (payment_token, payment_amount) = self.call_value().single_fungible_esdt(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .init_supply(token_id, amount) + .single_esdt(&payment_token, 0, &payment_amount) // enforce only single FT transfer + .sync_call(); + } + + #[only_owner] + #[endpoint(initSupplyMintBurnEsdtSafe)] + fn init_supply_mint_burn_esdt_safe( + &self, + token_id: TokenIdentifier, + mint_amount: BigUint, + burn_amount: BigUint, + ) { + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .init_supply_mint_burn(token_id, mint_amount, burn_amount) + .sync_call(); + } + + #[only_owner] + #[endpoint(pauseProxy)] + fn pause_proxy(&self) { + let proxy_addr = self.proxy_address().get(); + + self.tx() + .to(proxy_addr) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .pause_endpoint() + .sync_call(); + + self.pause_bridge_proxy_event(); + } + + #[only_owner] + #[endpoint(unpauseProxy)] + fn unpause_proxy(&self) { + let proxy_addr = self.proxy_address().get(); + + self.tx() + .to(proxy_addr) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) .unpause_endpoint() - .execute_on_dest_context(); + .sync_call(); + + self.unpause_bridge_proxy_event(); } #[only_owner] #[endpoint(changeFeeEstimatorContractAddress)] fn change_fee_estimator_contract_address(&self, new_address: ManagedAddress) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_fee_estimator_contract_address(new_address) - .execute_on_dest_context(); + .sync_call(); } /// Sets the gas limit being used for Ethereum transactions @@ -170,12 +237,15 @@ pub trait SetupModule: /// /// where price_per_gas_unit is queried from the aggregator (fee estimator SC) #[only_owner] - #[endpoint(changeElrondToEthGasLimit)] - fn change_elrond_to_eth_gas_limit(&self, new_gas_limit: BigUint) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + #[endpoint(changeMultiversXToEthGasLimit)] + fn change_multiversx_to_eth_gas_limit(&self, new_gas_limit: BigUint) { + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_eth_tx_gas_limit(new_gas_limit) - .execute_on_dest_context(); + .sync_call(); } /// Default price being used if the aggregator lacks a mapping for this token @@ -183,43 +253,92 @@ pub trait SetupModule: #[only_owner] #[endpoint(changeDefaultPricePerGasUnit)] fn change_default_price_per_gas_unit(&self, token_id: TokenIdentifier, new_value: BigUint) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_default_price_per_gas_unit(token_id, new_value) - .execute_on_dest_context(); + .sync_call(); } /// Token ticker being used when querying the aggregator for GWEI prices #[only_owner] #[endpoint(changeTokenTicker)] fn change_token_ticker(&self, token_id: TokenIdentifier, new_ticker: ManagedBuffer) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_token_ticker(token_id, new_ticker) - .execute_on_dest_context(); + .sync_call(); } #[only_owner] #[endpoint(esdtSafeAddTokenToWhitelist)] fn esdt_safe_add_token_to_whitelist( &self, - token_id: TokenIdentifier, + token_id: &TokenIdentifier, ticker: ManagedBuffer, + mint_burn_allowed: bool, + is_native_token: bool, + total_balance: &BigUint, + mint_balance: &BigUint, + burn_balance: &BigUint, opt_default_price_per_gas_unit: OptionalValue, ) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() - .add_token_to_whitelist(token_id, ticker, opt_default_price_per_gas_unit) - .execute_on_dest_context(); + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + token_id, + ticker, + mint_burn_allowed, + is_native_token, + total_balance, + mint_balance, + burn_balance, + opt_default_price_per_gas_unit, + ) + .sync_call(); + } + + #[only_owner] + #[endpoint(setMultiTransferOnEsdtSafe)] + fn set_multi_transfer_on_esdt_safe(&self) { + let multi_transfer_esdt_address = self.multi_transfer_esdt_address().get(); + let esdt_safe_addr = self.esdt_safe_address().get(); + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .set_multi_transfer_contract_address(OptionalValue::Some(multi_transfer_esdt_address)) + .sync_call(); + } + + #[only_owner] + #[endpoint(setEsdtSafeOnMultiTransfer)] + fn set_esdt_safe_on_multi_transfer(&self) { + let esdt_safe_address = self.esdt_safe_address().get(); + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) + .set_esdt_safe_contract_address(OptionalValue::Some(esdt_safe_address)) + .sync_call(); } #[only_owner] #[endpoint(esdtSafeRemoveTokenFromWhitelist)] fn esdt_safe_remove_token_from_whitelist(&self, token_id: TokenIdentifier) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .remove_token_from_whitelist(token_id) - .execute_on_dest_context(); + .sync_call(); } /// Sets maximum batch size for the EsdtSafe SC. @@ -228,10 +347,12 @@ pub trait SetupModule: #[only_owner] #[endpoint(esdtSafeSetMaxTxBatchSize)] fn esdt_safe_set_max_tx_batch_size(&self, new_max_tx_batch_size: usize) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_max_tx_batch_size(new_max_tx_batch_size) - .execute_on_dest_context(); + .sync_call(); } /// Sets the maximum block duration in which an EsdtSafe batch accepts transactions @@ -240,13 +361,16 @@ pub trait SetupModule: #[only_owner] #[endpoint(esdtSafeSetMaxTxBatchBlockDuration)] fn esdt_safe_set_max_tx_batch_block_duration(&self, new_max_tx_batch_block_duration: u64) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_max_tx_batch_block_duration(new_max_tx_batch_block_duration) - .execute_on_dest_context(); + .sync_call(); } - /// Sets the maximum bridged amount for the token for the Elrond -> Ethereum direction. + /// Sets the maximum bridged amount for the token for the MultiversX -> Ethereum direction. /// Any attempt to transfer over this amount will be rejected. #[only_owner] #[endpoint(esdtSafeSetMaxBridgedAmountForToken)] @@ -255,13 +379,16 @@ pub trait SetupModule: token_id: TokenIdentifier, max_amount: BigUint, ) { - let _: IgnoreValue = self - .get_esdt_safe_proxy_instance() + let esdt_safe_addr = self.esdt_safe_address().get(); + + self.tx() + .to(esdt_safe_addr) + .typed(esdt_safe_proxy::EsdtSafeProxy) .set_max_bridged_amount(token_id, max_amount) - .execute_on_dest_context(); + .sync_call(); } - /// Same as the function above, but for Ethereum -> Elrond transactions. + /// Same as the function above, but for Ethereum -> MultiversX transactions. #[only_owner] #[endpoint(multiTransferEsdtSetMaxBridgedAmountForToken)] fn multi_transfer_esdt_set_max_bridged_amount_for_token( @@ -269,21 +396,26 @@ pub trait SetupModule: token_id: TokenIdentifier, max_amount: BigUint, ) { - let _: IgnoreValue = self - .get_multi_transfer_esdt_proxy_instance() + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) .set_max_bridged_amount(token_id, max_amount) - .execute_on_dest_context(); + .sync_call(); } - /// Any failed Ethereum -> Elrond transactions are added into so-called "refund batches" + /// Any failed Ethereum -> MultiversX transactions are added into so-called "refund batches" /// This configures the size of a batch. #[only_owner] #[endpoint(multiTransferEsdtSetMaxRefundTxBatchSize)] fn multi_transfer_esdt_set_max_refund_tx_batch_size(&self, new_max_tx_batch_size: usize) { - let _: IgnoreValue = self - .get_multi_transfer_esdt_proxy_instance() + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); + + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) .set_max_tx_batch_size(new_max_tx_batch_size) - .execute_on_dest_context(); + .sync_call(); } /// Max block duration for refund batches. Default is "infinite" (u64::MAX) @@ -294,10 +426,13 @@ pub trait SetupModule: &self, new_max_tx_batch_block_duration: u64, ) { - let _: IgnoreValue = self - .get_multi_transfer_esdt_proxy_instance() + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); + + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) .set_max_tx_batch_block_duration(new_max_tx_batch_block_duration) - .execute_on_dest_context(); + .sync_call(); } /// Sets the wrapping contract address. @@ -313,9 +448,12 @@ pub trait SetupModule: &self, opt_wrapping_contract_address: OptionalValue, ) { - let _: IgnoreValue = self - .get_multi_transfer_esdt_proxy_instance() + let multi_transfer_esdt_addr = self.multi_transfer_esdt_address().get(); + + self.tx() + .to(multi_transfer_esdt_addr) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) .set_wrapping_contract_address(opt_wrapping_contract_address) - .execute_on_dest_context(); + .sync_call(); } } diff --git a/multisig/src/storage.rs b/multisig/src/storage.rs index bbc353c2..e130c3c4 100644 --- a/multisig/src/storage.rs +++ b/multisig/src/storage.rs @@ -1,5 +1,4 @@ -multiversx_sc::imports!(); -multiversx_sc::derive_imports!(); +use multiversx_sc::imports::*; use eth_address::EthAddress; use transaction::transaction_status::TransactionStatus; @@ -74,7 +73,7 @@ pub trait StorageModule { esdt_safe_batch_id: u64, ) -> MapMapper, usize>; - /// Mapping between ERC20 Ethereum address and Elrond ESDT Token Identifiers + /// Mapping between ERC20 Ethereum address and MultiversX ESDT Token Identifiers #[view(getErc20AddressForTokenId)] #[storage_mapper("erc20AddressForTokenId")] @@ -99,4 +98,8 @@ pub trait StorageModule { #[view(getMultiTransferEsdtAddress)] #[storage_mapper("multiTransferEsdtAddress")] fn multi_transfer_esdt_address(&self) -> SingleValueMapper; + + #[view(getProxyAddress)] + #[storage_mapper("proxyAddress")] + fn proxy_address(&self) -> SingleValueMapper; } diff --git a/multisig/src/user_role.rs b/multisig/src/user_role.rs index 813974a6..5e2a83f8 100644 --- a/multisig/src/user_role.rs +++ b/multisig/src/user_role.rs @@ -1,6 +1,7 @@ -multiversx_sc::derive_imports!(); +use multiversx_sc::derive_imports::*; -#[derive(TopEncode, TopDecode, TypeAbi, Clone, Copy, PartialEq)] +#[type_abi] +#[derive(TopEncode, TopDecode, Clone, Copy, PartialEq)] pub enum UserRole { None, BoardMember, diff --git a/multisig/src/util.rs b/multisig/src/util.rs index 96fc007b..ee41bd53 100644 --- a/multisig/src/util.rs +++ b/multisig/src/util.rs @@ -1,4 +1,4 @@ -multiversx_sc::imports!(); +use multiversx_sc::imports::*; use transaction::{EthTransaction, EthTxAsMultiValue}; @@ -49,7 +49,7 @@ pub trait UtilModule: crate::storage::StorageModule { ) -> ManagedVec> { let mut transfers_as_eth_tx = ManagedVec::new(); for transfer in transfers { - let (from, to, token_id, amount, tx_nonce) = transfer.into_tuple(); + let (from, to, token_id, amount, tx_nonce, call_data) = transfer.into_tuple(); transfers_as_eth_tx.push(EthTransaction { from, @@ -57,6 +57,7 @@ pub trait UtilModule: crate::storage::StorageModule { token_id, amount, tx_nonce, + call_data, }); } @@ -84,23 +85,4 @@ pub trait UtilModule: crate::storage::StorageModule { self.crypto().keccak256(&serialized) } - - // proxies - - #[proxy] - fn esdt_safe_proxy(&self, sc_address: ManagedAddress) -> esdt_safe::Proxy; - - #[proxy] - fn multi_transfer_esdt_proxy( - &self, - sc_address: ManagedAddress, - ) -> multi_transfer_esdt::Proxy; - - fn get_esdt_safe_proxy_instance(&self) -> esdt_safe::Proxy { - self.esdt_safe_proxy(self.esdt_safe_address().get()) - } - - fn get_multi_transfer_esdt_proxy_instance(&self) -> multi_transfer_esdt::Proxy { - self.multi_transfer_esdt_proxy(self.multi_transfer_esdt_address().get()) - } } diff --git a/multisig/tests/multisig_blackbox_test.rs b/multisig/tests/multisig_blackbox_test.rs new file mode 100644 index 00000000..fba5a36c --- /dev/null +++ b/multisig/tests/multisig_blackbox_test.rs @@ -0,0 +1,910 @@ +#![allow(unused)] + +use std::ops::Add; + +use bridge_proxy::{bridge_proxy_contract_proxy, config::ProxyTrait as _, ProxyTrait as _}; +use esdt_safe::{EsdtSafe, ProxyTrait as _}; +use multi_transfer_esdt::{bridged_tokens_wrapper_proxy, multi_transfer_proxy, ProxyTrait as _}; + +use multisig::{ + __endpoints_5__::multi_transfer_esdt_address, esdt_safe_proxy, multi_transfer_esdt_proxy, + multisig_proxy, +}; +use multiversx_sc::{ + api::{HandleConstraints, ManagedTypeApi}, + codec::{ + multi_types::{MultiValueVec, OptionalValue}, + Empty, + }, + contract_base::ManagedSerializer, + hex_literal::hex, + storage::mappers::SingleValue, + types::{ + Address, BigUint, CodeMetadata, ManagedAddress, ManagedBuffer, ManagedByteArray, + ManagedOption, ManagedType, ManagedVec, MultiValueEncoded, ReturnsNewManagedAddress, + ReturnsResult, TestAddress, TestSCAddress, TestTokenIdentifier, TokenIdentifier, + }, +}; +use multiversx_sc_modules::pause::ProxyTrait; +use multiversx_sc_scenario::{ + api::{StaticApi, VMHooksApi, VMHooksApiBackend}, + imports::MxscPath, + scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, + scenario_model::*, + ContractInfo, DebugApi, ExpectError, ExpectValue, ScenarioTxRun, ScenarioWorld, +}; + +use eth_address::*; +use token_module::ProxyTrait as _; +use transaction::{CallData, EthTransaction, EthTxAsMultiValue, TxBatchSplitInFields}; + +const WEGLD_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("WEGLD-123456"); +const ETH_TOKEN_ID: TestTokenIdentifier = TestTokenIdentifier::new("ETH-123456"); + +const USER_ETHEREUM_ADDRESS: &[u8] = b"0x0102030405060708091011121314151617181920"; + +const GAS_LIMIT: u64 = 100_000_000; + +const MULTISIG_CODE_PATH: MxscPath = MxscPath::new("output/multisig.mxsc.json"); +const MULTI_TRANSFER_CODE_PATH: MxscPath = + MxscPath::new("../multi-transfer-esdt/output/multi-transfer-esdt.mxsc.json"); +const BRIDGE_PROXY_CODE_PATH: MxscPath = + MxscPath::new("../bridge-proxy/output/bridge-proxy.mxsc.json"); +const ESDT_SAFE_CODE_PATH: MxscPath = MxscPath::new("../esdt-safe/output/esdt-safe.mxsc.json"); +const BRIDGED_TOKENS_WRAPPER_CODE_PATH: MxscPath = + MxscPath::new("../bridged-tokens-wrapper/output/bridged-tokens-wrapper.mxsc.json"); +const PRICE_AGGREGATOR_CODE_PATH: MxscPath = + MxscPath::new("../price-aggregator/price-aggregator.mxsc.json"); + +const MULTISIG_ADDRESS: TestSCAddress = TestSCAddress::new("multisig"); +const MULTI_TRANSFER_ADDRESS: TestSCAddress = TestSCAddress::new("multi-transfer"); +const BRIDGE_PROXY_ADDRESS: TestSCAddress = TestSCAddress::new("bridge-proxy"); +const ESDT_SAFE_ADDRESS: TestSCAddress = TestSCAddress::new("esdt-safe"); +const BRIDGED_TOKENS_WRAPPER_ADDRESS: TestSCAddress = TestSCAddress::new("bridged-tokens-wrapper"); +const PRICE_AGGREGATOR_ADDRESS: TestSCAddress = TestSCAddress::new("price-aggregator"); + +const ORACLE_ADDRESS: TestAddress = TestAddress::new("oracle"); +const OWNER_ADDRESS: TestAddress = TestAddress::new("owner"); +const USER1_ADDRESS: TestAddress = TestAddress::new("user1"); +const USER2_ADDRESS: TestAddress = TestAddress::new("user2"); +const RELAYER1_ADDRESS: TestAddress = TestAddress::new("relayer1"); +const RELAYER2_ADDRESS: TestAddress = TestAddress::new("relayer2"); + +const RANDOM_SC_ADDRESS: TestSCAddress = TestSCAddress::new("random-sc"); + +const ESDT_SAFE_ETH_TX_GAS_LIMIT: u64 = 150_000; + +const BALANCE: &str = "2,000,000"; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract(MULTISIG_CODE_PATH, multisig::ContractBuilder); + blockchain.register_contract( + MULTI_TRANSFER_CODE_PATH, + multi_transfer_esdt::ContractBuilder, + ); + blockchain.register_contract(BRIDGE_PROXY_CODE_PATH, bridge_proxy::ContractBuilder); + blockchain.register_contract(ESDT_SAFE_CODE_PATH, esdt_safe::ContractBuilder); + blockchain.register_contract( + BRIDGED_TOKENS_WRAPPER_CODE_PATH, + bridged_tokens_wrapper::ContractBuilder, + ); + + blockchain +} + +type MultiTransferContract = ContractInfo>; +type BridgeProxyContract = ContractInfo>; +type EsdtSafeContract = ContractInfo>; +type BridgedTokensWrapperContract = ContractInfo>; + +struct MultiTransferTestState { + world: ScenarioWorld, +} + +impl MultiTransferTestState { + fn new() -> Self { + let mut world = world(); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .esdt_balance(WEGLD_TOKEN_ID, 1001u64) + .esdt_balance(ETH_TOKEN_ID, 1001u64) + .account(USER1_ADDRESS) + .nonce(1) + .account(RELAYER1_ADDRESS) + .nonce(1) + .balance(1_000u64) + .account(RELAYER2_ADDRESS) + .nonce(1) + .balance(1_000u64); + + let roles = vec![ + "ESDTRoleLocalMint".to_string(), + "ESDTRoleLocalBurn".to_string(), + ]; + world + .account(ESDT_SAFE_ADDRESS) + .esdt_roles(WEGLD_TOKEN_ID, roles.clone()) + .esdt_roles(ETH_TOKEN_ID, roles) + .code(ESDT_SAFE_CODE_PATH) + .owner(OWNER_ADDRESS); + + Self { world } + } + + fn multisig_deploy(&mut self) -> &mut Self { + let mut board: MultiValueEncoded> = + MultiValueEncoded::new(); + board.push(ManagedAddress::from(RELAYER1_ADDRESS.eval_to_array())); + board.push(ManagedAddress::from(RELAYER2_ADDRESS.eval_to_array())); + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .init( + ESDT_SAFE_ADDRESS, + MULTI_TRANSFER_ADDRESS, + BRIDGE_PROXY_ADDRESS, + 1_000u64, + 500u64, + 2usize, + board, + ) + .code(MULTISIG_CODE_PATH) + .new_address(MULTISIG_ADDRESS) + .run(); + self + } + + fn multi_transfer_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(MULTISIG_ADDRESS) + .typed(multi_transfer_esdt_proxy::MultiTransferEsdtProxy) + .init() + .code(MULTI_TRANSFER_CODE_PATH) + .new_address(MULTI_TRANSFER_ADDRESS) + .run(); + + self + } + + fn bridged_tokens_wrapper_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .init() + .code(BRIDGED_TOKENS_WRAPPER_CODE_PATH) + .new_address(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .run(); + + self + } + + fn bridge_proxy_deploy(&mut self) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .typed(bridge_proxy_contract_proxy::BridgeProxyContractProxy) + .init(OptionalValue::Some(MULTI_TRANSFER_ADDRESS.to_address())) + .code(BRIDGE_PROXY_CODE_PATH) + .new_address(BRIDGE_PROXY_ADDRESS) + .run(); + + self + } + + fn safe_deploy(&mut self, price_aggregator_contract_address: Address) -> &mut Self { + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .upgrade( + ManagedAddress::zero(), + MULTI_TRANSFER_ADDRESS.to_address(), + BRIDGE_PROXY_ADDRESS.to_address(), + ESDT_SAFE_ETH_TX_GAS_LIMIT, + ) + .code(ESDT_SAFE_CODE_PATH) + .run(); + + self + } + + fn config_multisig(&mut self) { + self.world + .tx() + .from(MULTISIG_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .set_wrapping_contract_address(OptionalValue::Some( + BRIDGED_TOKENS_WRAPPER_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(MULTISIG_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .set_bridge_proxy_contract_address(OptionalValue::Some( + BRIDGE_PROXY_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(MULTISIG_ADDRESS) + .to(MULTI_TRANSFER_ADDRESS) + .typed(multi_transfer_proxy::MultiTransferEsdtProxy) + .set_esdt_safe_contract_address(OptionalValue::Some(ESDT_SAFE_ADDRESS.to_address())) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .set_multi_transfer_contract_address(OptionalValue::Some( + MULTI_TRANSFER_ADDRESS.to_address(), + )) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + TokenIdentifier::from_esdt_bytes("WEGLD-123456"), + "WEGLD", + true, + false, + BigUint::zero(), + BigUint::zero(), + BigUint::zero(), + OptionalValue::Some(BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT)), + ) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .add_token_to_whitelist( + TokenIdentifier::from_esdt_bytes("ETH-123456"), + "ETH", + true, + false, + BigUint::zero(), + BigUint::zero(), + BigUint::zero(), + OptionalValue::Some(BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT)), + ) + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGED_TOKENS_WRAPPER_ADDRESS) + .typed(bridged_tokens_wrapper_proxy::BridgedTokensWrapperProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(BRIDGE_PROXY_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(OWNER_ADDRESS) + .to(ESDT_SAFE_ADDRESS) + .typed(esdt_safe_proxy::EsdtSafeProxy) + .unpause_endpoint() + .run(); + + self.world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .stake() + .egld(1_000) + .run(); + + self.world + .tx() + .from(RELAYER2_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .stake() + .egld(1_000) + .run(); + + let staked_relayers = self + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .get_all_staked_relayers() + .returns(ReturnsResult) + .run(); + + assert!(staked_relayers + .to_vec() + .contains(&RELAYER1_ADDRESS.to_managed_address())); + assert!(staked_relayers + .to_vec() + .contains(&RELAYER2_ADDRESS.to_managed_address())); + } +} + +#[test] +fn config_test() { + let mut state = MultiTransferTestState::new(); + + state.multisig_deploy(); + state.safe_deploy(Address::zero()); + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.bridged_tokens_wrapper_deploy(); + state.config_multisig(); +} + +#[test] +fn ethereum_to_multiversx_call_data_empty_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(76_000_000_000u64); + + state.multisig_deploy(); + state.safe_deploy(Address::zero()); + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.bridged_tokens_wrapper_deploy(); + state.config_multisig(); + + let eth_tx = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + TokenIdentifier::from(WEGLD_TOKEN_ID), + token_amount.clone(), + 1u64, + ManagedOption::none(), + )); + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_multi_transfer_esdt_batch(1u32, transfers) + .run(); + + state + .world + .tx() + .from(RELAYER2_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(1usize) + .run(); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(1usize) + .run(); + + state + .world + .check_account(USER1_ADDRESS) + .esdt_balance(WEGLD_TOKEN_ID, token_amount.clone()); +} + +#[test] +fn ethereum_to_multiversx_relayer_call_data_several_tx_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(5_000u64); + + state.world.start_trace(); + + state.multisig_deploy(); + state.safe_deploy(Address::zero()); + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.bridged_tokens_wrapper_deploy(); + state.config_multisig(); + + let addr = + Address::from_slice(b"erd1dyw7aysn0nwmuahvxnh2e0pm0kgjvs2gmfdxjgz3x0pet2nkvt8s7tkyrj"); + let eth_tx = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"5d959e98ea73c35778ff"), + }, + ManagedAddress::from(addr.clone()), + TokenIdentifier::from("ETHUSDC-afa689"), + token_amount.clone(), + 1u64, + ManagedOption::none(), + )); + + let eth_tx2 = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"5d959e98ea73c35778ff"), + }, + ManagedAddress::from(addr.clone()), + TokenIdentifier::from("ETHUSDC-afa689"), + token_amount.clone(), + 2u64, + ManagedOption::none(), + )); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from(b"fund"), + gas_limit: GAS_LIMIT, + args: ManagedOption::none(), + }; + let call_data = ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx3 = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"5d959e98ea73c35778ff"), + }, + ManagedAddress::from(addr.clone()), + TokenIdentifier::from("ETHUSDC-afa689"), + token_amount.clone(), + 3u64, + ManagedOption::some(call_data), + )); + + let args = ManagedVec::from_single_item(ManagedBuffer::from(b"5")); + let call_data2: CallData = CallData { + endpoint: ManagedBuffer::from(b"fund"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + let call_data2 = ManagedSerializer::new().top_encode_to_managed_buffer(&call_data2); + + let eth_tx4 = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"5d959e98ea73c35778ff"), + }, + ManagedAddress::from(addr.clone()), + TokenIdentifier::from("ETHUSDC-afa689"), + token_amount.clone(), + 4u64, + ManagedOption::some(call_data2), + )); + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx); + transfers.push(eth_tx2); + transfers.push(eth_tx3); + transfers.push(eth_tx4); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_multi_transfer_esdt_batch(1u32, transfers) + .run(); + + state + .world + .tx() + .from(RELAYER2_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(1usize) + .run(); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(1usize) + .returns(ExpectError(4, "Invalid token or amount")) + .run(); + + state.world.write_scenario_trace( + "scenarios/ethereum_to_multiversx_relayer_call_data_several_tx_test.scen.json", + ); +} + +#[test] +fn ethereum_to_multiversx_relayer_query_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(76_000_000_000u64); + state.world.start_trace(); + + state.multisig_deploy(); + state.safe_deploy(Address::zero()); + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.bridged_tokens_wrapper_deploy(); + state.config_multisig(); + + let eth_tx = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + TokenIdentifier::from(WEGLD_TOKEN_ID), + token_amount.clone(), + 1u64, + ManagedOption::none(), + )); + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_multi_transfer_esdt_batch(1u32, transfers.clone()) + .run(); + + let was_transfer = state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .was_transfer_action_proposed(1u64, transfers.clone()) + .returns(ReturnsResult) + .run(); + + assert!(was_transfer); + + let get_action_id = state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .get_action_id_for_transfer_batch(1u64, transfers) + .returns(ReturnsResult) + .run(); + + assert!(get_action_id == 1usize); + + state + .world + .tx() + .from(RELAYER2_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(1usize) + .run(); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(1usize) + .run(); + + state + .world + .check_account(USER1_ADDRESS) + .esdt_balance(WEGLD_TOKEN_ID, token_amount.clone()); + + state + .world + .write_scenario_trace("scenarios/ethereum_to_multiversx_relayer_query_test.scen.json"); +} + +#[test] +fn ethereum_to_multiversx_relayer_query2_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(5_000u64); + state.world.start_trace(); + + state.multisig_deploy(); + state.safe_deploy(Address::zero()); + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.bridged_tokens_wrapper_deploy(); + state.config_multisig(); + + let addr = + Address::from_slice(b"erd1dyw7aysn0nwmuahvxnh2e0pm0kgjvs2gmfdxjgz3x0pet2nkvt8s7tkyrj"); + + const ADDR: [u8; 32] = hex!("691dee92137cddbe76ec34eeacbc3b7d91264148da5a69205133c395aa7662cf"); + + let eth_tx = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"5d959e98ea73c35778ff"), + }, + ManagedAddress::from(ADDR), + TokenIdentifier::from("ETHUSDC-afa689"), + token_amount.clone(), + 1u64, + ManagedOption::none(), + )); + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_multi_transfer_esdt_batch(1u32, transfers.clone()) + .run(); + + let was_transfer = state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .was_transfer_action_proposed(1u64, transfers.clone()) + .returns(ReturnsResult) + .run(); + + assert!(was_transfer); + + let get_action_id = state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .get_action_id_for_transfer_batch(1u64, transfers) + .returns(ReturnsResult) + .run(); + + assert!(get_action_id == 1usize); + + state + .world + .tx() + .from(RELAYER2_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(1usize) + .run(); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(1usize) + .returns(ExpectError(4, "Invalid token or amount")) + .run(); + + state + .world + .write_scenario_trace("scenarios/ethereum_to_multiversx_relayer_query2_test.scen.json"); +} + +#[test] +fn ethereum_to_multiversx_tx_batch_ok_test() { + let mut state = MultiTransferTestState::new(); + let token_amount = BigUint::from(76_000_000_000u64); + state.world.start_trace(); + + state.multisig_deploy(); + state.safe_deploy(Address::zero()); + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.bridged_tokens_wrapper_deploy(); + state.config_multisig(); + + let mut args = ManagedVec::new(); + args.push(ManagedBuffer::from(&[5u8, 6u8])); + args.push(ManagedBuffer::from(&[7u8, 8u8, 9u8])); + args.push(ManagedBuffer::from(&[7u8, 8u8, 9u8, 10u8, 11u8])); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from("add"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + + let call_data: ManagedBuffer = + ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx1 = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + TokenIdentifier::from(WEGLD_TOKEN_ID), + token_amount.clone(), + 1u64, + ManagedOption::some(call_data.clone()), + )); + + let eth_tx2 = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + ManagedAddress::from(USER1_ADDRESS.eval_to_array()), + TokenIdentifier::from(ETH_TOKEN_ID), + token_amount.clone(), + 2u64, + ManagedOption::some(call_data.clone()), + )); + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx1); + transfers.push(eth_tx2); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_multi_transfer_esdt_batch(1u32, transfers) + .run(); + + state + .world + .tx() + .from(RELAYER2_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(1usize) + .run(); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(1usize) + .run(); + + state + .world + .check_account(USER1_ADDRESS) + .esdt_balance(WEGLD_TOKEN_ID, token_amount.clone()) + .esdt_balance(ETH_TOKEN_ID, token_amount.clone()); + + state.world.write_scenario_trace( + "scenarios/ethereum_to_multiversx_tx_batch_ok_call_data_encoded.scen.json", + ); +} + +#[test] +fn ethereum_to_multiversx_tx_batch_rejected_test() { + let mut state = MultiTransferTestState::new(); + let over_the_limit_token_amount = BigUint::from(101_000_000_000u64); + + state.multisig_deploy(); + state.safe_deploy(Address::zero()); + state.multi_transfer_deploy(); + state.bridge_proxy_deploy(); + state.bridged_tokens_wrapper_deploy(); + state.config_multisig(); + + let mut args = ManagedVec::new(); + args.push(ManagedBuffer::from(&[5u8])); + + let call_data: CallData = CallData { + endpoint: ManagedBuffer::from("add"), + gas_limit: GAS_LIMIT, + args: ManagedOption::some(args), + }; + + let call_data: ManagedBuffer = + ManagedSerializer::new().top_encode_to_managed_buffer(&call_data); + + let eth_tx1 = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + ManagedAddress::from(BRIDGE_PROXY_ADDRESS.eval_to_array()), + TokenIdentifier::from(WEGLD_TOKEN_ID), + over_the_limit_token_amount.clone(), + 1u64, + ManagedOption::some(call_data.clone()), + )); + + let eth_tx2 = EthTxAsMultiValue::::from(( + EthAddress { + raw_addr: ManagedByteArray::new_from_bytes(b"01020304050607080910"), + }, + ManagedAddress::from(BRIDGE_PROXY_ADDRESS.eval_to_array()), + TokenIdentifier::from(ETH_TOKEN_ID), + over_the_limit_token_amount.clone(), + 2u64, + ManagedOption::some(call_data.clone()), + )); + + let mut transfers: MultiValueEncoded> = + MultiValueEncoded::new(); + transfers.push(eth_tx1); + transfers.push(eth_tx2); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .propose_multi_transfer_esdt_batch(1u32, transfers) + .run(); + + state + .world + .tx() + .from(RELAYER2_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .sign(1usize) + .run(); + + state + .world + .tx() + .from(RELAYER1_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .perform_action_endpoint(1usize) + .run(); + + let refund_tx = state + .world + .query() + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .get_current_refund_batch() + .returns(ReturnsResult) + .run(); + + assert!(refund_tx.is_none()); + + state + .world + .tx() + .from(OWNER_ADDRESS) + .to(MULTISIG_ADDRESS) + .typed(multisig_proxy::MultisigProxy) + .move_refund_batch_to_safe_from_child_contract() + .run(); +} diff --git a/multisig/tests/multisig_scenario_rs_test.rs b/multisig/tests/multisig_scenario_rs_test.rs new file mode 100644 index 00000000..6f0f2030 --- /dev/null +++ b/multisig/tests/multisig_scenario_rs_test.rs @@ -0,0 +1,77 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + + blockchain.register_contract("file:output/multisig.wasm", multisig::ContractBuilder); + blockchain.register_contract( + "file:../multi-transfer-esdt/output/multi-transfer-esdt.wasm", + multi_transfer_esdt::ContractBuilder, + ); + blockchain.register_contract( + "file:../esdt-safe/output/esdt-safe.wasm", + esdt_safe::ContractBuilder, + ); + blockchain.register_contract( + "file:../price-aggregator/multiversx-price-aggregator-sc.wasm", + multiversx_price_aggregator_sc::ContractBuilder, + ); + blockchain.register_contract( + "file:../bridge-proxy/output/bridge-proxy.wasm", + bridge_proxy::ContractBuilder, + ); + blockchain +} + +#[test] +fn change_token_config_rs() { + world().run("scenarios/change_token_config.scen.json"); +} + +#[test] +fn create_multiversx_to_ethereum_tx_batch_rs() { + world().run("scenarios/create_multiversx_to_ethereum_tx_batch.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn ethereum_to_multiversx_tx_batch_ok_rs() { + world().run("scenarios/ethereum_to_multiversx_tx_batch_ok.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn ethereum_to_multiversx_tx_batch_rejected_rs() { + world().run("scenarios/ethereum_to_multiversx_tx_batch_rejected.scen.json"); +} + +#[test] +#[ignore] //There is an equivalent blackbox test +fn ethereum_to_multiversx_tx_batch_without_data_rs() { + world().run("scenarios/ethereum_to_multiversx_tx_batch_without_data.scen.json"); +} + +#[test] +fn execute_multiversx_to_ethereum_tx_batch_rs() { + world().run("scenarios/execute_multiversx_to_ethereum_tx_batch.scen.json"); +} + +#[test] +fn get_empty_batch_rs() { + world().run("scenarios/get_empty_batch.scen.json"); +} + +#[test] +fn reject_multiversx_to_ethereum_tx_batch_rs() { + world().run("scenarios/reject_multiversx_to_ethereum_tx_batch.scen.json"); +} + +#[test] +fn setup_rs() { + world().run("scenarios/setup.scen.json"); +} + +#[test] +fn unstake_rs() { + world().run("scenarios/unstake.scen.json"); +} diff --git a/multisig/tests/scenario_go_test.rs b/multisig/tests/scenario_go_test.rs index 9605e9d4..a14f3b24 100644 --- a/multisig/tests/scenario_go_test.rs +++ b/multisig/tests/scenario_go_test.rs @@ -1,46 +1,52 @@ +use multiversx_sc_scenario::*; + +fn world() -> ScenarioWorld { + ScenarioWorld::vm_go() +} #[test] -fn create_elrond_to_ethereum_tx_batch_go() { - multiversx_sc_scenario::run_go("mandos/create_elrond_to_ethereum_tx_batch.scen.json"); +fn change_token_config_go() { + world().run("scenarios/change_token_config.scen.json"); } #[test] -fn ethereum_to_elrond_tx_batch_ok_go() { - multiversx_sc_scenario::run_go("mandos/ethereum_to_elrond_tx_batch_ok.scen.json"); +fn create_multiversx_to_ethereum_tx_batch_go() { + world().run("scenarios/create_multiversx_to_ethereum_tx_batch.scen.json"); } #[test] -fn ethereum_to_elrond_tx_batch_rejected_go() { - multiversx_sc_scenario::run_go("mandos/ethereum_to_elrond_tx_batch_rejected.scen.json"); +#[ignore] //Ignore for now +fn ethereum_to_multiversx_tx_batch_ok_go() { + world().run("scenarios/ethereum_to_multiversx_tx_batch_ok.scen.json"); } #[test] -fn execute_elrond_to_ethereum_tx_batch_go() { - multiversx_sc_scenario::run_go("mandos/execute_elrond_to_ethereum_tx_batch.scen.json"); +#[ignore] //Ignore for now +fn ethereum_to_multiversx_tx_batch_rejected_go() { + world().run("scenarios/ethereum_to_multiversx_tx_batch_rejected.scen.json"); } #[test] -fn get_empty_batch_go() { - multiversx_sc_scenario::run_go("mandos/get_empty_batch.scen.json"); +#[ignore] //Ignore for now +fn execute_multiversx_to_ethereum_tx_batch_go() { + world().run("scenarios/execute_multiversx_to_ethereum_tx_batch.scen.json"); } #[test] -fn reject_elrond_to_ethereum_tx_batch_go() { - multiversx_sc_scenario::run_go("mandos/reject_elrond_to_ethereum_tx_batch.scen.json"); +fn get_empty_batch_go() { + world().run("scenarios/get_empty_batch.scen.json"); } #[test] -fn setup_go() { - multiversx_sc_scenario::run_go("mandos/setup.scen.json"); +fn reject_multiversx_to_ethereum_tx_batch_go() { + world().run("scenarios/reject_multiversx_to_ethereum_tx_batch.scen.json"); } #[test] -fn unstake_go() { - multiversx_sc_scenario::run_go("mandos/unstake.scen.json"); +fn setup_go() { + world().run("scenarios/setup.scen.json"); } -/* #[test] -fn upgrade_child_sc_go() { - multiversx_sc_scenario::run_go("mandos/upgrade_child_sc.scen.json"); +fn unstake_go() { + world().run("scenarios/unstake.scen.json"); } -*/ diff --git a/multisig/wasm/Cargo.lock b/multisig/wasm/Cargo.lock index b114b035..7c894f12 100644 --- a/multisig/wasm/Cargo.lock +++ b/multisig/wasm/Cargo.lock @@ -2,24 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "allocator-api2" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" - [[package]] name = "arrayvec" version = "0.7.4" @@ -28,31 +10,69 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bridge-proxy" +version = "0.0.0" +dependencies = [ + "bridged-tokens-wrapper", + "crowdfunding-esdt", + "esdt-safe", + "eth-address", + "multiversx-sc", + "multiversx-sc-modules", + "token-module", + "transaction", + "tx-batch-module", +] [[package]] name = "bridged-tokens-wrapper" version = "0.0.0" dependencies = [ + "eth-address", "multiversx-sc", "multiversx-sc-modules", + "token-module", "transaction", + "tx-batch-module", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "crowdfunding-esdt" +version = "0.0.0" +source = "git+https://github.com/multiversx/mx-contracts-rs?rev=d91bbff#d91bbff295295c2f7e2baf1cd569dd5693ddfb56" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "endian-type" version = "0.1.2" @@ -66,6 +86,7 @@ dependencies = [ "eth-address", "fee-estimator-module", "max-bridged-amount-module", + "multiversx-price-aggregator-sc", "multiversx-sc", "multiversx-sc-modules", "token-module", @@ -88,13 +109,16 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.14.3" +name = "getrandom" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "ahash", - "allocator-api2", + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", ] [[package]] @@ -109,6 +133,27 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "max-bridged-amount-module" version = "0.0.0" @@ -120,9 +165,14 @@ dependencies = [ name = "multi-transfer-esdt" version = "0.0.0" dependencies = [ + "bridge-proxy", "bridged-tokens-wrapper", + "esdt-safe", + "eth-address", "max-bridged-amount-module", "multiversx-sc", + "multiversx-sc-modules", + "token-module", "transaction", "tx-batch-module", ] @@ -131,11 +181,14 @@ dependencies = [ name = "multisig" version = "0.0.0" dependencies = [ + "bridge-proxy", + "bridged-tokens-wrapper", "esdt-safe", "eth-address", "fee-estimator-module", "max-bridged-amount-module", "multi-transfer-esdt", + "multiversx-price-aggregator-sc", "multiversx-sc", "multiversx-sc-modules", "token-module", @@ -151,35 +204,49 @@ dependencies = [ "multiversx-sc-wasm-adapter", ] +[[package]] +name = "multiversx-price-aggregator-sc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea572ebab3a6addd937cad829076b13e320851503fb6adf1ad66f544b2bf100" +dependencies = [ + "arrayvec", + "getrandom", + "multiversx-sc", + "multiversx-sc-modules", + "rand", +] + [[package]] name = "multiversx-sc" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2bdb196b3ff2b9f8c744ec2e026c22c8e02bc91e5c6ed09951415c47fef6b8" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" dependencies = [ "bitflags", - "hashbrown", "hex-literal", "multiversx-sc-codec", "multiversx-sc-derive", "num-traits", + "unwrap-infallible", ] [[package]] name = "multiversx-sc-codec" -version = "0.18.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19908153158c03df4582af08f47c0eb39fb52a7dff4736b301a66acbbb9955d3" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" dependencies = [ "arrayvec", "multiversx-sc-codec-derive", + "unwrap-infallible", ] [[package]] name = "multiversx-sc-codec-derive" -version = "0.18.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b03b43f9cad320992f54ed162de2ed63e3ec83ed01361e57ee9c1865fba5a2" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" dependencies = [ "hex", "proc-macro2", @@ -189,9 +256,9 @@ dependencies = [ [[package]] name = "multiversx-sc-derive" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e60b5dce707f61376f74d713218f75326121d9f6a5f09a3a63de7aea2a92be9" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" dependencies = [ "hex", "proc-macro2", @@ -202,18 +269,18 @@ dependencies = [ [[package]] name = "multiversx-sc-modules" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5833f8bc88104357d38a8952d2a16c3e66080e2e512c0e7001c0c003006c475" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" dependencies = [ "multiversx-sc", ] [[package]] name = "multiversx-sc-wasm-adapter" -version = "0.45.2" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4299660d5413d9f120bfddda8105b1f9d28f0345a72f53e5dc90732c4983e45" +checksum = "ed13aaca9cbdbc6911174cd3029e750a7563d85dd3daaa1107b1fd31c7f17245" dependencies = [ "multiversx-sc", ] @@ -229,33 +296,42 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -270,17 +346,47 @@ dependencies = [ "nibble_vec", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.41" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -313,30 +419,91 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] [[package]] -name = "version_check" -version = "0.9.4" +name = "wasm-bindgen-shared" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "zerocopy" -version = "0.7.31" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.31" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/multisig/wasm/Cargo.toml b/multisig/wasm/Cargo.toml index b6d0ab00..8d164a22 100644 --- a/multisig/wasm/Cargo.toml +++ b/multisig/wasm/Cargo.toml @@ -21,11 +21,14 @@ debug = false panic = "abort" overflow-checks = false +[profile.dev] +panic = "abort" + [dependencies.multisig] path = ".." [dependencies.multiversx-sc-wasm-adapter] -version = "0.45.2" +version = "=0.52.3" [workspace] members = ["."] diff --git a/multisig/wasm/src/lib.rs b/multisig/wasm/src/lib.rs index 9d0cd26b..d7138aaa 100644 --- a/multisig/wasm/src/lib.rs +++ b/multisig/wasm/src/lib.rs @@ -5,16 +5,13 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 62 +// Upgrade: 1 +// Endpoints: 74 // Async Callback (empty): 1 -// Total number of exported functions: 64 +// Total number of exported functions: 77 #![no_std] -// Configuration that works with rustc < 1.73.0. -// TODO: Recommended rustc version: 1.73.0 or newer. -#![feature(lang_items)] - multiversx_sc_wasm_adapter::allocator!(); multiversx_sc_wasm_adapter::panic_handler!(); @@ -28,7 +25,12 @@ multiversx_sc_wasm_adapter::endpoints! { unstake => unstake proposeEsdtSafeSetCurrentTransactionBatchStatus => propose_esdt_safe_set_current_transaction_batch_status proposeMultiTransferEsdtBatch => propose_multi_transfer_esdt_batch - moveRefundBatchToSafe => move_refund_batch_to_safe + moveRefundBatchToSafeFromChildContract => move_refund_batch_to_safe_from_child_contract + initSupplyFromChildContract => init_supply_from_child_contract + addUnprocessedRefundTxToBatch => add_unprocessed_refund_tx_to_batch + withdrawRefundFeesForEthereum => withdraw_refund_fees_for_ethereum + withdrawTransactionFees => withdraw_transaction_fees + withdrawSlashedAmount => withdraw_slashed_amount performAction => perform_action_endpoint sign => sign upgradeChildContractFromSource => upgrade_child_contract_from_source @@ -40,11 +42,17 @@ multiversx_sc_wasm_adapter::endpoints! { clearMapping => clear_mapping pauseEsdtSafe => pause_esdt_safe unpauseEsdtSafe => unpause_esdt_safe + initSupplyEsdtSafe => init_supply_esdt_safe + initSupplyMintBurnEsdtSafe => init_supply_mint_burn_esdt_safe + pauseProxy => pause_proxy + unpauseProxy => unpause_proxy changeFeeEstimatorContractAddress => change_fee_estimator_contract_address - changeElrondToEthGasLimit => change_elrond_to_eth_gas_limit + changeMultiversXToEthGasLimit => change_multiversx_to_eth_gas_limit changeDefaultPricePerGasUnit => change_default_price_per_gas_unit changeTokenTicker => change_token_ticker esdtSafeAddTokenToWhitelist => esdt_safe_add_token_to_whitelist + setMultiTransferOnEsdtSafe => set_multi_transfer_on_esdt_safe + setEsdtSafeOnMultiTransfer => set_esdt_safe_on_multi_transfer esdtSafeRemoveTokenFromWhitelist => esdt_safe_remove_token_from_whitelist esdtSafeSetMaxTxBatchSize => esdt_safe_set_max_tx_batch_size esdtSafeSetMaxTxBatchBlockDuration => esdt_safe_set_max_tx_batch_block_duration @@ -65,7 +73,9 @@ multiversx_sc_wasm_adapter::endpoints! { getTokenIdForErc20Address => token_id_for_erc20_address getEsdtSafeAddress => esdt_safe_address getMultiTransferEsdtAddress => multi_transfer_esdt_address + getProxyAddress => proxy_address getCurrentTxBatch => get_current_tx_batch + getBatch => get_batch getCurrentRefundBatch => get_current_refund_batch wasActionExecuted => was_action_executed wasTransferActionProposed => was_transfer_action_proposed diff --git a/price-aggregator/mandos/deploy.scen.json b/price-aggregator/mandos/deploy.scen.json deleted file mode 100644 index c7474748..00000000 --- a/price-aggregator/mandos/deploy.scen.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "name": "deploy", - "steps": [ - { - "step": "setState", - "accounts": { - "address:aggregator-owner": { - "nonce": "0", - "balance": "0", - "storage": {} - }, - "address:oracle": { - "nonce": "0", - "balance": "0", - "storage": {} - } - }, - "newAddresses": [ - { - "creatorAddress": "address:aggregator-owner", - "creatorNonce": "0", - "newAddress": "sc:price_aggregator" - } - ] - }, - { - "step": "scDeploy", - "txId": "deploy", - "tx": { - "from": "address:aggregator-owner", - "contractCode": "file:../price-aggregator.wasm", - "value": "0", - "arguments": [ - "1", - "0", - "address:oracle" - ], - "gasLimit": "20,000,000", - "gasPrice": "0" - }, - "expect": { - "status": "0", - "message": "", - "gas": "*", - "refund": "*" - } - }, - { - "step": "scCall", - "txId": "unpause", - "tx": { - "from": "address:aggregator-owner", - "to": "sc:price_aggregator", - "value": "0", - "function": "unpause", - "arguments": [], - "gasLimit": "100,000,000", - "gasPrice": "0" - }, - "expect": { - "status": "0", - "message": "", - "out": [], - "gas": "*", - "refund": "*" - } - }, - { - "step": "checkState", - "accounts": { - "address:aggregator-owner": { - "nonce": "2", - "balance": "0", - "storage": {} - }, - "sc:price_aggregator": { - "nonce": "0", - "balance": "0", - "storage": { - "str:submission_count": "1", - "str:decimals": "0", - "str:oracle_status.mapped|address:oracle": { - "0-total_submissions": "u64:0", - "1-accepted_submissions": "u64:0" - }, - "+": "" - }, - "code": "file:../price-aggregator.wasm" - }, - "+": {} - } - } - ] -} diff --git a/price-aggregator/multiversx-price-aggregator-sc.abi.json b/price-aggregator/multiversx-price-aggregator-sc.abi.json new file mode 100644 index 00000000..67d5f029 --- /dev/null +++ b/price-aggregator/multiversx-price-aggregator-sc.abi.json @@ -0,0 +1,439 @@ +{ + "buildInfo": { + "rustc": { + "version": "1.79.0", + "commitHash": "129f3b9964af4d4a709d1383930ade12dfe7c081", + "commitDate": "2024-06-10", + "channel": "Stable", + "short": "rustc 1.79.0 (129f3b996 2024-06-10)" + }, + "contractCrate": { + "name": "multiversx-price-aggregator-sc", + "version": "0.52.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.52.0" + } + }, + "name": "PriceAggregator", + "constructor": { + "inputs": [ + { + "name": "staking_token", + "type": "EgldOrEsdtTokenIdentifier" + }, + { + "name": "staking_amount", + "type": "BigUint" + }, + { + "name": "slash_amount", + "type": "BigUint" + }, + { + "name": "slash_quorum", + "type": "u32" + }, + { + "name": "submission_count", + "type": "u32" + }, + { + "name": "oracles", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + "endpoints": [ + { + "name": "changeAmounts", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "staking_amount", + "type": "BigUint" + }, + { + "name": "slash_amount", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "addOracles", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "oracles", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "docs": [ + "Also receives submission count,", + "so the owner does not have to update it manually with setSubmissionCount before this call" + ], + "name": "removeOracles", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "submission_count", + "type": "u32" + }, + { + "name": "oracles", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "submit", + "mutability": "mutable", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + }, + { + "name": "submission_timestamp", + "type": "u64" + }, + { + "name": "price", + "type": "BigUint" + }, + { + "name": "decimals", + "type": "u8" + } + ], + "outputs": [] + }, + { + "name": "submitBatch", + "mutability": "mutable", + "inputs": [ + { + "name": "submissions", + "type": "variadic>", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "latestRoundData", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "latestPriceFeed", + "mutability": "readonly", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "u32" + }, + { + "type": "bytes" + }, + { + "type": "bytes" + }, + { + "type": "u64" + }, + { + "type": "BigUint" + }, + { + "type": "u8" + } + ] + }, + { + "name": "latestPriceFeedOptional", + "mutability": "readonly", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "optional>", + "multi_result": true + } + ] + }, + { + "name": "setSubmissionCount", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "submission_count", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "getOracles", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic
", + "multi_result": true + } + ] + }, + { + "name": "setPairDecimals", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + }, + { + "name": "decimals", + "type": "u8" + } + ], + "outputs": [] + }, + { + "name": "getPairDecimals", + "mutability": "readonly", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "u8" + } + ] + }, + { + "name": "submission_count", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "pause", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "unpause", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "isPaused", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "stake", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [], + "outputs": [] + }, + { + "name": "unstake", + "mutability": "mutable", + "inputs": [ + { + "name": "unstake_amount", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "voteSlashMember", + "mutability": "mutable", + "inputs": [ + { + "name": "member_to_slash", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "cancelVoteSlashMember", + "mutability": "mutable", + "inputs": [ + { + "name": "member_to_slash", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "slashMember", + "mutability": "mutable", + "inputs": [ + { + "name": "member_to_slash", + "type": "Address" + } + ], + "outputs": [] + } + ], + "events": [ + { + "identifier": "new_round", + "inputs": [ + { + "name": "from", + "type": "bytes", + "indexed": true + }, + { + "name": "to", + "type": "bytes", + "indexed": true + }, + { + "name": "epoch", + "type": "u64", + "indexed": true + }, + { + "name": "new_round_event", + "type": "NewRoundEvent" + } + ] + } + ], + "esdtAttributes": [], + "hasCallback": false, + "types": { + "NewRoundEvent": { + "type": "struct", + "fields": [ + { + "name": "price", + "type": "BigUint" + }, + { + "name": "timestamp", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + }, + { + "name": "block", + "type": "u64" + }, + { + "name": "epoch", + "type": "u64" + } + ] + }, + "PriceFeed": { + "type": "struct", + "fields": [ + { + "name": "round_id", + "type": "u32" + }, + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + }, + { + "name": "timestamp", + "type": "u64" + }, + { + "name": "price", + "type": "BigUint" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + } +} diff --git a/price-aggregator/multiversx-price-aggregator-sc.mxsc.json b/price-aggregator/multiversx-price-aggregator-sc.mxsc.json new file mode 100644 index 00000000..9748b33b --- /dev/null +++ b/price-aggregator/multiversx-price-aggregator-sc.mxsc.json @@ -0,0 +1,496 @@ +{ + "buildInfo": { + "rustc": { + "version": "1.79.0", + "commitHash": "129f3b9964af4d4a709d1383930ade12dfe7c081", + "commitDate": "2024-06-10", + "channel": "Stable", + "short": "rustc 1.79.0 (129f3b996 2024-06-10)" + }, + "contractCrate": { + "name": "multiversx-price-aggregator-sc", + "version": "0.52.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.52.0" + } + }, + "abi": { + "name": "PriceAggregator", + "constructor": { + "inputs": [ + { + "name": "staking_token", + "type": "EgldOrEsdtTokenIdentifier" + }, + { + "name": "staking_amount", + "type": "BigUint" + }, + { + "name": "slash_amount", + "type": "BigUint" + }, + { + "name": "slash_quorum", + "type": "u32" + }, + { + "name": "submission_count", + "type": "u32" + }, + { + "name": "oracles", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + "endpoints": [ + { + "name": "changeAmounts", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "staking_amount", + "type": "BigUint" + }, + { + "name": "slash_amount", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "addOracles", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "oracles", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "docs": [ + "Also receives submission count,", + "so the owner does not have to update it manually with setSubmissionCount before this call" + ], + "name": "removeOracles", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "submission_count", + "type": "u32" + }, + { + "name": "oracles", + "type": "variadic
", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "submit", + "mutability": "mutable", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + }, + { + "name": "submission_timestamp", + "type": "u64" + }, + { + "name": "price", + "type": "BigUint" + }, + { + "name": "decimals", + "type": "u8" + } + ], + "outputs": [] + }, + { + "name": "submitBatch", + "mutability": "mutable", + "inputs": [ + { + "name": "submissions", + "type": "variadic>", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "latestRoundData", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic", + "multi_result": true + } + ] + }, + { + "name": "latestPriceFeed", + "mutability": "readonly", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "u32" + }, + { + "type": "bytes" + }, + { + "type": "bytes" + }, + { + "type": "u64" + }, + { + "type": "BigUint" + }, + { + "type": "u8" + } + ] + }, + { + "name": "latestPriceFeedOptional", + "mutability": "readonly", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "optional>", + "multi_result": true + } + ] + }, + { + "name": "setSubmissionCount", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "submission_count", + "type": "u32" + } + ], + "outputs": [] + }, + { + "name": "getOracles", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "variadic
", + "multi_result": true + } + ] + }, + { + "name": "setPairDecimals", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + }, + { + "name": "decimals", + "type": "u8" + } + ], + "outputs": [] + }, + { + "name": "getPairDecimals", + "mutability": "readonly", + "inputs": [ + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + } + ], + "outputs": [ + { + "type": "u8" + } + ] + }, + { + "name": "submission_count", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "u32" + } + ] + }, + { + "name": "pause", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "unpause", + "onlyOwner": true, + "mutability": "mutable", + "inputs": [], + "outputs": [] + }, + { + "name": "isPaused", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "bool" + } + ] + }, + { + "name": "stake", + "mutability": "mutable", + "payableInTokens": [ + "*" + ], + "inputs": [], + "outputs": [] + }, + { + "name": "unstake", + "mutability": "mutable", + "inputs": [ + { + "name": "unstake_amount", + "type": "BigUint" + } + ], + "outputs": [] + }, + { + "name": "voteSlashMember", + "mutability": "mutable", + "inputs": [ + { + "name": "member_to_slash", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "cancelVoteSlashMember", + "mutability": "mutable", + "inputs": [ + { + "name": "member_to_slash", + "type": "Address" + } + ], + "outputs": [] + }, + { + "name": "slashMember", + "mutability": "mutable", + "inputs": [ + { + "name": "member_to_slash", + "type": "Address" + } + ], + "outputs": [] + } + ], + "events": [ + { + "identifier": "new_round", + "inputs": [ + { + "name": "from", + "type": "bytes", + "indexed": true + }, + { + "name": "to", + "type": "bytes", + "indexed": true + }, + { + "name": "epoch", + "type": "u64", + "indexed": true + }, + { + "name": "new_round_event", + "type": "NewRoundEvent" + } + ] + } + ], + "esdtAttributes": [], + "hasCallback": false, + "types": { + "NewRoundEvent": { + "type": "struct", + "fields": [ + { + "name": "price", + "type": "BigUint" + }, + { + "name": "timestamp", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + }, + { + "name": "block", + "type": "u64" + }, + { + "name": "epoch", + "type": "u64" + } + ] + }, + "PriceFeed": { + "type": "struct", + "fields": [ + { + "name": "round_id", + "type": "u32" + }, + { + "name": "from", + "type": "bytes" + }, + { + "name": "to", + "type": "bytes" + }, + { + "name": "timestamp", + "type": "u64" + }, + { + "name": "price", + "type": "BigUint" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + } + }, + "code": "0061736d010000000182011660027f7f0060000060027f7f017f60017f017f60017f0060037f7f7f006000017f60047f7f7f7f0060037f7f7f017f60047f7f7f7f017f60057f7f7f7f7f006000017e60027f7e0060017f017e60017e0060057f7f7e7f7f017f60027f7f017e60057f7f7f7e7e0060027e7f0060047f7e7f7f0060057f7f7e7f7f0060027e7e0002ac072703656e760e626967496e74536574496e743634000c03656e7609626967496e74416464000503656e760b7369676e616c4572726f72000003656e760a6d4275666665724e6577000603656e760d6d427566666572417070656e64000203656e76096d4275666665724571000203656e76136d42756666657253746f7261676553746f7265000203656e76106d4275666665724765744c656e677468000303656e760d6d616e6167656443616c6c6572000403656e76136d616e616765644f776e657241646472657373000403656e76126d427566666572476574417267756d656e74000203656e76126d427566666572417070656e644279746573000803656e76126d616e616765645369676e616c4572726f72000403656e761b736d616c6c496e74476574556e7369676e6564417267756d656e74000d03656e7619626967496e74476574556e7369676e6564417267756d656e74000003656e760f6765744e756d417267756d656e7473000603656e7609626967496e74537562000503656e76146d427566666572436f707942797465536c696365000903656e760f6d4275666665725365744279746573000803656e7609626967496e74436d70000203656e76196d42756666657246726f6d426967496e74556e7369676e6564000203656e76176d427566666572546f426967496e74556e7369676e6564000203656e76126d42756666657253746f726167654c6f6164000203656e7616736d616c6c496e7446696e697368556e7369676e6564000e03656e760d6d42756666657246696e697368000303656e7614626967496e7446696e697368556e7369676e6564000403656e7611676574426c6f636b54696d657374616d70000b03656e760a626967496e7454446976000503656e760d676574426c6f636b45706f6368000b03656e760d676574426c6f636b4e6f6e6365000b03656e760f6d616e6167656457726974654c6f67000003656e760e636865636b4e6f5061796d656e74000103656e7614736d616c6c496e7446696e6973685369676e6564000e03656e761c6d616e616765644765744d756c74694553445443616c6c56616c7565000403656e7612626967496e7447657443616c6c56616c7565000403656e761b6d616e616765645472616e7366657256616c756545786563757465000f03656e76226d616e616765644d756c74695472616e73666572455344544e465445786563757465000f03656e760a626967496e745369676e000303656e76136d42756666657247657442797465536c696365000903b601b40103060a0105030200020005020003000300000006010307020306000303060803040404010503020205050909000200030405000600000004110702120505100702030002070800070903080c00020305030002030000000a000a0003031000020202050002000400030400000407000d130200060406010306030402040405020a1404030315060a040205010403020207010507050501060606000301010101010101010101010101010101010101010101010505030100030616037f01418080080b7f0041d9dc080b7f0041e0dc080b0790031a066d656d6f7279020004696e697400c3010d6368616e6765416d6f756e747300c4010a6164644f7261636c657300c5010d72656d6f76654f7261636c657300c601067375626d697400c7010b7375626d6974426174636800c8010f6c6174657374526f756e644461746100c9010f6c617465737450726963654665656400ca01176c61746573745072696365466565644f7074696f6e616c00cb01127365745375626d697373696f6e436f756e7400cc010a6765744f7261636c657300cd010f73657450616972446563696d616c7300ce010f67657450616972446563696d616c7300cf01107375626d697373696f6e5f636f756e7400d00105706175736500d10107756e706175736500d20108697350617573656400d301057374616b6500d40107756e7374616b6500d5010f766f7465536c6173684d656d62657200d6011563616e63656c566f7465536c6173684d656d62657200d7010b736c6173684d656d62657200d8010863616c6c4261636b00d9010a5f5f646174615f656e6403010b5f5f686561705f6261736503020a807bb4011601017f1028220142001000200120012000100120010b1901017f41b48e0841b48e0828020041016b220036020020000b31000240200120024d0440200220044d0d01102a000b102a000b2000200220016b3602042000200320014102746a3602000b060010b801000b18002001102c210120002002102c360204200020013602000b0f01017f10032201200010041a20010b0b0020002001100541004a0b4101017f2001280204220220012802084b047f4100052001200241016a36020420012802002802002002102f210141010b210220002001360204200020023602000b0a00200020011079107a0b5b01037f230041106b2203240020012802042202047f200341086a20012802002204280200200210312001200328020c360204200428020020021032210241010541000b21012000200236020420002001360200200341106a24000b800101027f230041206b220324002003410c6a22042001419e8208410b2002106f2201103520042001104e21022003410c6a2001104e21042003280210200328020c46044020032d001c044041c8dc08410036020041ccdc0841003a00000b2000200436020420002002360200200341206a24000f0b200141808008410e104f000b1000200041a9820841062001106f107a0b0b0020012000103410061a0b0f01017f10282201200010141a20010b3101017f20011036220210072101200041003a00102000200136020c2000200236020820002001360204200041003602000b0d0020001028220010161a20000b0a0020001034200110380b4f01027f230041106b22022400200220001007220341187420034180fe03714108747220034108764180fe03712003411876727236020c20012002410c6a41041050200120001053200241106a24000b0900200020011002000b0c01017f10282200100820000b1d01017f1028220010092000103a102d04400f0b41e08d0841241002000b0d00200010282200100a1a20000b2e01017f41d480084117103e220420002001100b1a200441eb80084103100b1a200420022003100b1a2004100c000b1101017f102822022000200110121a20020b3b01037f1040210220002802002101034041d0dc0828020020014a04402000200141016a220336020020022001103c1041200321010c010b0b20020b1101017f102822004101410010121a20000b4601017f230041106b220224002002200141187420014180fe03714108747220014108764180fe03712001411876727236020c20002002410c6a4104100b1a200241106a24000b2301017e2000100d22014280025a044041898908410841808008410e103d000b2001a70b4c01017f230041106b220124002000100741044604402001410036020c200041002001410c6a410410521a41feffffff072000200128020c41c58eb1a204461b21000b200141106a240020000b2301017f4100103c22001007412047044041d18608410f41e182084110103d000b20000b2401017e2000100d22034280808080105a04402001200241808008410e103d000b2003a70b0c00200010282200100e20000b1900200041d0dc082802004e04400f0b41ff800841121002000b1400100f20004604400f0b4191810841191002000b1900200041d0dc082802004c04400f0b41ee800841111002000b0b0041d0dc08100f3602000b1f0020002001200210102000104c41ff017104400f0b41aa810841301002000b1500410241012000102522001b4100200041004e1b0b3e01037f20002001104e21022000280200210310032104200028020820032002200410110440200141da8108410f104f000b2000200220036a36020020040b5101017f230041106b220224002002410036020c20002002410c6a41042001109401200228020c2100200241106a2400200041187420004180fe03714108747220004108764180fe0371200041187672720b2c01017f41c28208411b103e2203200010041a200341eb80084103100b1a200320012002100b1a2003100c000b0b00200020012002100b1a0b0c00200020012002200310520b0f00200020012003200210264100470b09002000200110041a0b1500417f200020011013220041004720004100481b0b0a0020002000200110010b0d0020001028220010151a20000b0a0020004101410010580b0d00200020012002103e10061a0b4001017f2001280200220204402002105a2202105b20012802042002105b20012802082002105b200128020c2002105b20002002105c0f0b20004101410010580b080041014100103e0b4501017f230041106b220224002002200041187420004180fe03714108747220004108764180fe03712000411876727236020c20012002410c6a41041050200241106a24000b09002000200110061a0b080020002001105c0b1200416c4101410010121a2000416c10061a0b3b01027f20002001280200220520012802082200200210602000200210612003105a220010622004200010622000105c20052001280204200210630b4902017f017e230041106b220424002000200120031067047e200420022003106420042903002105200020042903083703102000200537030842010542000b370300200441106a24000b19002000102c2200418a82084107100b1a20002001105320000b7701017f230041106b220224002002200042388620004280fe0383422886842000428080fc0783421886200042808080f80f834208868484200042088842808080f80f832000421888428080fc07838420004228884280fe038320004238888484843703082001200241086a41081050200241106a24000ba90101047f230041206b22032400200020021067450440200341106a2001106d2003200328021c41016a220436021c024020032802102206450440200320043602140c010b200341086a20012003280218220510312001200520032802082004106e0b2001200420054100106e20032004360218200141a9820841062004106f2002105d2003200641016a3602102001200341106a107320002002106a2004ad10720b200341206a24000b7c02027f027e230041206b220324002003410c6a22042001200210612201103520042001106521052003410c6a2001106521062003280210200328020c46044020032d001c044041c8dc08410036020041ccdc0841003a00000b2000200637030820002005370300200341206a24000f0b200141808008410e104f000b850102017e017f230041106b22032400200342003703082000200341086a4108200110940120032903082102200341106a2400200242388620024280fe0383422886842002428080fc0783421886200242808080f80f834208868484200242088842808080f80f832002421888428080fc07838420024228884280fe038320024238888484840b2a00200120031067047f2002200310611068210341010541000b210120002003360204200020013602000b0b002000200110744100470b08002000103610560b0a0020002001106a10570b19002000102c2200419182084108100b1a20002001105320000bbd0101057f230041206b22042400200020022003106c450440200441106a2001106d2004200428021c41016a220536021c024020042802102207450440200420053602140c010b200441086a20012004280218220610312001200620042802082005106e0b2001200520064100106e20042005360218200141a9820841062005106f2002105a220610382003200610382006105c2004200741016a36021020011070200441106a105920002002200310712005ad10720b200441206a24000b0f00200020012002107110754100470bb20101057f230041206b22022400200110702201416710161a02400240416710074504400c010b2002410c6a22032001103520032001104e21062002410c6a2001104e21032002410c6a2001104e21042002410c6a2001104e21052002280210200228020c470d0120022d001c450d0041c8dc08410036020041ccdc0841003a00000b2000200536020c200020043602082000200336020420002006360200200241206a24000f0b200141808008410e104f000b20002000419e8208410b2001106f2002105a2200105b20032000105b2000105c0b17002000102c220020012002100b1a20032000105b20000b13002000102c220041af82084105100b1a20000b1b002000102c2200419182084108100b1a200120022000107620000b3701017f230041106b2202240020024200370308200220014100200241086a1097012000200228020020022802041058200241106a24000b0a0020001070200110590b0a0020002001106a10750b2501017e2000200010840122014280808080105a0440200041808008410e104f000b2001a70b0e002000200210382001200210380b1f01017f230041106b2201240020012000106d2001280200200141106a24000b090020002001ad10720b19002000102c2200419982084105100b1a20012000105b20000b1f01017f20001036220110074120470440200041e182084110104f000b20010b10002000419e8208410b2001106f10570b1000200041a9820841062001106f10570b2e01017f230041106b2202240020022001280200106d2000200228020436020420002001360200200241106a24000b6602027f017e230041106b220524002000200120032004106c047f2002102c220141b482084108100b1a20032004200110762001102c2102200541086a2001107f200529030821072000200236020c2000200737020441010541000b360200200541106a24000b1801017f2001102c210220002001360204200020023602000b4d01017f2000200120032004106c047f2002102c220141b482084108100b1a20032004200110762001102c220241dd82084104100b1a200020023602082000200136020441010541000b3602000b08002001200010330b08002000103610430b3301017e027f0240200020001084012201420158044041002001a741016b0d021a0c010b2000418683084112104f000b41010b0ba30102017e027f230041106b22032400200342003703082000103622041007220041094f0440200141808008410e104f000b20044100200320006b41106a200010521a20032903082102200341106a2400200242388620024280fe0383422886842002428080fc0783421886200242808080f80f834208868484200242088842808080f80f832002421888428080fc07838420024228884280fe038320024238888484840b0b0020002001108601105e0b19002000102c220041bc82084106100b1a20002001105320000ba40101067f0240200028020822052001108801220204400240200220002802042204107522034d044020022003460d01200410752003490d03200028020022072003102f2106200410752002490d032007200210792006105d0c010b0c020b200410752003490d01200028020020031079105e2004200341016b1078200220034704402005200620021089010b200520011085010b20024100470f0b41848e0841121002000b0b002000200110860110750b0e00200020011086012002ad10720b4201037f200028020822032001108b0145044020002802042202107521042000280200200441016a220010792001105d20022000107820032001200210751089010b0b0c00200020011088014100470b0d0010401a20002001102c10410bf60101037f230041d0006b22012400200141286a200041046a2202107d200120012903283702400340200141206a200141406b103020012802200440200028020820012802241061105e0c0105200141186a2002107d2001200129031837024003400240200141106a200141406b1030200128021004402000280200200128021410690c0205200141306a2002280200106d2001280234210003402000450d02200141086a200228020020001031200128020c20022802002000107b20022802002000107c21000c000b000b000b0b200141c8006a4200370300200142003703402002280200200141406b1073200141d0006a24000b0b0b8a0101047f230041106b220324002001280204220241046a220420012802084b047f41000520012802002003410036020c28020020022003410c6a410410511a200328020c210220012004360204200241187420024180fe03714108747220024108764180fe037120024118767272210241010b21012000200236020420002001360200200341106a24000b7d01037f230041106b22012400200028020821032001410036020c200028020020034102742001410c6a41041051450440200128020c21022000200341016a360208200241187420024180fe03714108747220024108764180fe037120024118767272102c200141106a24000f0b41f18208410841ee80084111103d000b980101047f230041206b2201240020012000280204107536021c20014101360218200120003602140340200141086a200141146a102e200128020804402000280208200128020c1085010c01052000280204107521034101210203402004200220034b72450440200028020020021079105e200220034f2104200220022003496a21020c010b0b200028020441001078200141206a24000b0b0b4801017f0240200128020820012802044f04400c010b410121022001108f01102c220110074120460d0041f18208410841e182084110103d000b20002001360204200020023602000b2e01027f2001102c21022001102c220341dd82084104100b1a2000200336020420002001360200200020023602080b2e0020003502081017200028020c10181a200028021010181a2000290300101720002802141019200031001810170bef0301077f2000280200210702400240024002400240024020002d001045044020002802082204100722054190ce004b0d0141ccdc082d00000d0141c8dc08200536020041ccdc0841013a00002004410041b88e08200510511a200041013a00100b200220076a220841c8dc082802004d0d010c050b200041003a0010200420072001200210510d04200220076a21080c010b200720084b0d0120084190ce004b0d02200741b88e086a210320012104200241104f04402004410020046b41037122016a210620010440200321050340200420052d00003a0000200541016a2105200441016a22042006490d000b0b2006200220016b220a417c7122096a21040240200120036a22014103710440200941004c0d012001410374220241187121072001417c71220541046a2103410020026b4118712102200528020021050340200620052007762003280200220520027472360200200341046a2103200641046a22062004490d000b0c010b200941004c0d0020012103034020062003280200360200200341046a2103200641046a22062004490d000b0b200120096a2103200a41037121020b20020440200220046a21010340200420032d00003a0000200341016a2103200441016a22042001490d000b0b0b200020083602000f0b102a000b102a000b200341da8108410f104f000b2601017f230041106b22022400200220003a000f20012002410f6a41011050200241106a24000ba30102017e027f230041106b220224002002420037030820001007220341094f044041f18208410841808008410e103d000b20004100200220036b41106a200310521a20022903082101200241106a2400200142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc07838420014228884280fe038320014238888484840baa0202047f027e2003200142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc07838420014238882208200142288822094280fe0383848484370000200041084100200142005322072002716b41ff017122042008a746220520042001423088a741ff01714671220620056a2006410020042009a741ff0171461b22056a2005410020042001422088a741ff0171461b22056a2005410020042001a72205411876461b22066a200641002004200541107641ff0171461b22066a200641002004200541087641ff0171461b22046a200441002001501b6a22042007200320044107716a2c0000410048732004410047712002716b22026b3602042000200220036a3602000b2e01017f230041106b22022400200241003a000f20002002410f6a4101200110940120022d000f200241106a24000b2601017f230041106b22022400200220013a000f20002002410f6a41011050200241106a24000b0b00109c011083014101730b3901027f230041106b22012400109c012001420037030820012000ad4101200141086a109701200128020020012802041058200141106a24000b0a0041bc8a084113103e0b1200109a0145044041ae830841121039000b0b4401047f230041106b22012400109f0110682103200010a00110682104200141046a10a101200128020c2000108b0104402004200310a20121020b200141106a240020020b0a0041f68b084122103e0b1401017f41838b08411b103e22012000105320010b0f00200041b98b08411c103e1092010b0f0020002001105441ff01714102490ba60101037f230041406a22012400200141106a10a40120001007210220014100360224200120024102763602202001200036021c2001280210210202400340200141086a2001411c6a1091012001280208450d012002200128020c220010670d00200141286a2203200141106a2000102c42004200105f200310a10120032000108a01200310a101200128022c107541e500490d000b41d2830841161039000b200141406b24000b0d002000410d41bd8c0810da010b20002000200110a60141ff0171200241ff017147044041bb870841181039000b0bbf0101027f230041206b220224002002410c6a2000200110b001220310350240024002402002280210200228020c460440410021010c010b410021010240024002402002410c6a200310980141ff01710e020201000b200341f98208410d104f000b410121012002410c6a200310980121000b2002280210200228020c470d010b20022d001c044041c8dc08410036020041ccdc0841003a00000b2001450d01200241206a240020000f0b200341808008410e104f000b41828808411c1039000bc00102037f017e230041206b2205240002400240200410752207450d00200410752007490d002005410c6a22062003200710792203103520062003104d1056210420062003106521082006200310980121062005280210200528020c470d0120052d001c044041c8dc08410036020041ccdc0841003a00000b200020023602102000200136020c20002007360208200020063a00182000200436021420002008370300200541206a24000f0b41848e0841121002000b200341808008410e104f000bd60a02067f027e230041f0026b220524002005200136024c20052000360248200541e0026a10a901200541406b20002001102b20052802e00222062005280240220720052802442208106c450440200541386a20072008102b200620052802e4022005280238200528023c106b0b200541f8006a2209200620052802e80220072008107e02402005280278450d00200541d8006a20054184016a2802003602002005200529027c370350200541c8006a220710aa012106200710ab012107101a210b20092005280254106d027e0240027e200528027822080440200620061084010c010b2002200b10ac012006200b1072200b0b220c42880e7c200b5a0440103a2106420020052802502006106720084100472002200c5471720d021a0c010b2002200b10ac01200541d0006a108d012006200b10722007200b1072103a210642002005280250200610670d011a0b200541306a2005280250200541d8006a2208280200200610662003200828020020061061103320052802502005280254200610632007200b1072200541e8006a2008280200360200200520052903503703602005200136027420052000360270024020052802641077220310ad011075490d000240024002402003413349044041002106200541003602c002200541286a200541e0006a2203410472107d200520052903283702e002200520033602e802200541f8006a21030340200541206a200541e0026a1030024020052802204101460440200520052802e8022207280200200741086a2802002005280224106620052802000d010c090b027f200645044041012107410021064100210341040c010b41002103200541f8006a2006200541e0026a410041202006676b10ae0141012107200641017621080240024020064101714504402006200841016b22074d0440200541bf89083602cc024101210341002107411521060c030b200541f8006a220920074102746a280200102722062006200841027420096a28020010271001417242021000200620064172101b410121070c010b200541f8006a20084102746a280200102721060b200541013602cc020b41080b200541c8026a6a2006360200200520033602c80220052802d00221062007450d0320052802cc02450d04101a2102200541e0006a108d01200541f0006a220310aa01105e200310ab01105e200541d4026a10af01200541186a20002001102b20052802d402220320052802182207200528021c2208106c450440200541106a20072008102b200320052802d80220052802102005280214106b0b200541e0026a2209200320052802dc022007200810800120052802e002450d0820052802e40220052802e8022207107541016a22081079105a21032006103420031038200220031062200320041099012003105c20072008ad1072101c210b2000102c21002001102c210320061027101d210c1040220141908d084109103e104120012000108c0120012003108c0110402100200542003703e002200541086a200b4100200910970120002005280208200528020c10121a2001200010411040102c2200103720022000106220042000109501200c20001062200b2000106220012000101e0c060b20064132460d04200320052802043602002005200641016a22063602c002200341046a21030c000b000b41d3870841211039000b20052802cc0220061039000b41f48708410e1039000b10bd01000b42010b2102200541e0026a220110a401103a210020052802e0022203200010670440200541f8006a2204200320052802e802200010602005290378500d01200529038801210b200529038001210c200420012000102c2002200c7c200b42017c105f0b200541f0026a24000f0b10b801000b0d002000410b4198890810da010b1e01017f41f08c08411a103e2101200028020020002802042001107620010b1e01017f41d78c084119103e2101200028020020002802042001107620010b1600200120007d421f5a044041d9880841181039000b0b0a0041a389084110103e0bfa1201127f230041d0026b22072400410121144101210f02400340200121082000210b024003400240200841154f044020040d01200841017641016b210503402005417f46044020082105034020054102490d08200b20084100200541016b220510b701200741086a41002005200b200810292007280208200728020c410010bc010c000b0005200b2008200510bc01200541016b21050c010b000b000b200841014d0d04200b2008410110bb010c040b200f450440200841017641feffffff0771210c417f2105417f200841016b6776210920082106034020054102470440200b20082005200c6a2006410d74200673220641117620067322064105742006732206200971220a200841002008200a4d1b6b10b701200541016a21050c010b0b200441016b21040b20072008410276220636023c2007200641017422053602402007200641036c220c36024420074100360248200720083602d8012007200b3602d401200720023602d0012007200741c8006a3602dc01200841314b04402007200641016b36024c2007200641016a360250200741d0016a2206200741cc006a22092007413c6a200741d0006a220a10ba012007200541016b36024c2007200541017236025020062009200741406b200a10ba012007200c41016b36024c2007200c41016a36025020062009200741c4006a200a10ba010b200741d0016a2007413c6a200741406b200741c4006a10ba0102400240200f027f20072802482206410c4f0440200741306a410020084101762205200b200510292007280234210920072802302106200741286a41002005200b20084102746a2005410274220c6b20051029200541016b21052007280228200c6a41046b210a200728022c210c024003402005417f460d012009450d042005200c4904402006280200210d2006200a280200360200200a200d360200200941016b2109200641046a2106200a41046b210a200541016b21050c010b0b10b801000b20082007280240417f736a210c41010c010b2007280240210c2006450b20147171450d01200b41046b2112410121054100210d200841324921130340200d4105460d0220052008200520084b1b210a200d41016a210d201220054102746a21060340024002402005200a460440200a21050c010b200641046a2209280200200628020010b601450d010b2013200520084672450440200b2008200541016b2206200510b70120054102490d03200741206a41002005200b2008102920072802202007280224200610bb01200741186a41002005200b2008102920072802182109200728021c2106230041106b220a24000240200641014b0440200a41086a41002006200920061029200a28020c210e200a2802082209280204200928020010b601450d01200941046a21062009280200211020092009280204360200200e41026b21112009200e4102746a41046b210e034002402011047f200641046a2209280200201010b6010d01200605200e0b20103602000c030b20062009280200360200201141016b2111200921060c000b000b10b801000b200a41106a24000c030b20052008460d080c040b200541016a2105200921060c000b000b000b10b801000b2003450440200121080c020b2008200c4d044010b801000b2003280200200b200c4102746a28020010b6010440200b21000c020b41002105200b20084100200c10b701200b41046a210d200841016b210a200b280200210c0340200a20052005200a491b2109200d20054102746a21060240034020052009460d01200c200628020010b601450440200641046a2106200541016a21050c010b0b200521090b200b200a4102746a2105024003402009200a41016b220a4f0d0120052802002106200541046b2105200c200610b6010d000b200d20094102746a220628020021112006200541046a220628020036020020062011360200200941016a21050c010b0b200b200c360200200941016a220620084d0440200820066b2108200b20064102746a210b0c010b0b102a000b4100210f200020084100200c10b701200841016b210120002802002110200041046a220c210503400240024002402001200f4604402001210f0c010b2005280200201010b6010d010b200020084102746a41046b2105200121060340200f2006220b4f2214450440200641016b21062005280200200541046b2105201010b601450d010b0b200741106a200f200b200c200110292007280210221120072802144102746a210b41800121014100210e41002105410021094100210d41800121122011210c03400240200b200c6b220a418408492215450d00200a41027621062009200d4b22132005200e49722216044020064180016b220a200120131b21012012200a200620161b20131b21120c010b2006200a41037622126b21010b02402009200d470d0041002106200c210a200741d0006a220d2109034020062012460d01200920063a0000200641016a21062009200a280200201010b6014101736a2109200a41046a210a0c000b000b02402005200e470d00200b41046b210a41002106200741d0016a2205210e034020012006460d01200e20063a0000200641016a2106200a280200201010b601200e6a210e200a41046b210a0c000b000b2009200d6b2206200e20056b220a2006200a491b220a0440200d41016a2106200a41016b210a200c200d2d00004102746a220d2802002113037f200d200b20052d0000417f734102746a220d280200360200200a047f200d200c20062d00004102746a220d280200360200200641016a2106200a41016b210a200541016a21050c0105200d20133602002006210d200541016a0b0b21050b200b410020016b41002005200e461b4102746a210b200c201241002009200d461b4102746a210c2015450d000b02402009200d4d04402005200e4f0d0103402005200e4f0d02200c2802002101200c200b200e41016b220e2d0000417f734102746a220628020036020020062001360200200c41046a210c0c000b000b03402009200d4b0440200c200941016b22092d00004102746a220128020021062001200b41046b220b280200360200200b20063602000c010b0b200b210c0b20002010360200200020084100200c20116b410276200f6a220110b7012001200846200120084b720d0120084103762001200820016b220520012005491b4d210f200020014102746a220641046a2108200541016b220520014d04402008200520022006200410ae010c040b2000200120022003200410ae012006210320052101200821000c030b200541046a2105200f41016a210f0c010b0b0b10bd01000b200741d0026a24000b0d0020004106418a8d0810da010b2201017f41ca8c08410d103e210220002802002002103820012802002002103820020b930101027f230041306b220324000240109a010440200341106a220410af01200341046a20032802102003280218200120021080012003280204450d012004200120022003280208200328020c10a701200020032d00283a0018200020032903203703102000200329031837030820002003290310370300200341306a24000f0b41ae830841121039000b419e880841141039000b3f01027f230041106b22002400103a2101200041046a10a401024020002802042001106704402001109e010d010b41c5880841141039000b200041106a24000b4201017f230041106b220124000240200041024d0d00200141046a10a40120012802081077200049200041324b720d00200141106a24000f0b41f1880841181039000b0d002000104c41ff017141014b0b0f0020002001105441ff01714101470b100020002001105441ff017141ff01460b44000240200120024b0440200120034b0d0110b801000b10b801000b200020024102746a220128020021022001200020034102746a2200280200360200200020023602000b060010bd01000b4f01037f20002802042203200228020022044102746a2802002003200128020022054102746a28020010b60104402002200536020020012004360200200028020c2200200028020041016a3602000b0b1d0020002001200210b90120002002200310b90120002001200210b9010bd40101077f230041106b2205240002402001200241016b4b0440034020012002460d02200541086a4100200241016a220220002001102920052802082207200528020c22084102746a220341046b2204280200200341086b220928020010b601450d002004280200210620042009280200360200200841026b21042003410c6b2103034002402004047f2006200328020010b6010d01200341046a0520070b20063602000c020b200341046a2003280200360200200441016b2104200341046b21030c000b000b000b10b801000b200541106a24000b900101027f024002400340024020024101742204410172220320014f0d002001200441026a22044b0440200020034102746a280200200020044102746a28020010b60120036a21030b200120024d0d02200120034d0d03200020024102746a280200200020034102746a28020010b601450d00200020012002200310b701200321020c010b0b0f0b10b801000b10b801000b0b0041a68e08410e1002000b0a0041cf8a08411a103e0b0a0041e98a08411a103e0b0a00419e8b08411b103e0b1901017f41988c084125103e220220011053200020021092010b09002000108f01102c0bc904010b7f230041206b22012400101f104a410510494100103c10432106410110462102410210462103410341b38908410c10452104410441a3890841101045210720014105360214200141146a103f2100200128021410472001200036020c1040210520012000100736021c2001410036021820012001410c6a3602140240034002402001200141146a108e012001280200450d002001280204102c102c220010074120470d022001200041187420004180fe03714108747220004108764180fe0371200041187672723602102005200141106a4104100b1a0c010b0b200510072109410021000240024002400240024003402009200041046a220a4904400240200141146a10a101200128021810752200450d00200041e5004f0d03200020044d0d04200441024d0d05200210b401450d06200310b401450d062003200210b501450d0710c00121000240200641feffffff074704402000200610061a0c010b200041868208410410580b2002109f011033200310be01103310bf0120041078200128020c10a301200710b30110ad01200710784101109b01200141206a24000f0b052001410036021420052000200141146a2208410410521a20012802142100200810a1012008200041187420004180fe03714108747220004108764180fe037120004118767272108a01200a21000c010b0b418f840841101039000b41d2830841161039000b419f8408412f1039000b41ce840841301039000b41fe840841241039000b41a2850841311039000b419980084119103e220041e182084110100b1a2000100c000bda0101057f230041206b22002400101f103b4102104841001046210241011046210302400240200210b401450d00200310b401450d002003200210b5010440200041086a220110a10110bf01107521042000200028020c107536021c20004101360218200020013602144100210103402000200041146a102e2000280200450d032002200028020410a001106810b60120016a220120044d0d000b0c020b41a2850841311039000b41fe840841241039000b200120044b0440109f01200210810110be012003108101200041206a24000f0b41fc8608413f1039000b3601027f230041106b22002400101f103b104a410010492000410036020c2000410c6a103f200028020c104710a301200041106a24000b880401097f23004180016b22002400101f103b104a41011049410041a3890841101045210620004101360258200041d8006a103f210120002802581047200041406b10a40120011007210320004100360254200020034102763602502000200136024c200028024821072000280244210120002802402108024003400240200041386a200041cc006a1091012000280238450d002008200028023c2203107422040440200041306a2001200410312000280234210220002802302105200041d8006a2001106d024020050440200041286a2001200510312001200520002802282002106e0c010b2000200236025c0b024020020440200041206a2001200210312001200220052000280224106e0c010b200020053602600b20012004107b2001200410321a20012004107c2000200028025841016b3602582001200041d8006a1073200820031069200041106a200720031064200720031061105e0b200041e8006a220410a10110bf011075210220042003108701200028026c107520024d0d02450d012000200028026c107536027c20004101360278200020043602740340200041086a200041f4006a102e20002802080440200041d8006a2202200028020c10c101200220031087011a0c0105200041d8006a2202200310c10120021090010c030b000b000b0b200610b30110ad012006107820004180016a24000f0b41d3850841c7001039000b7b02057f017e230041106b22002400101f410510484100103c21014101103c21024102100d21054103104621044104104221032000200236020c20002001360208109d0110b201101a200554044041e08608411c1039000b200041086a2000410c6a200310a5012001200220052004200310a801200041106a24000b8c0202057f037e230041206b22002400101f104a410010492000410036020c2000410c6a103f2103200028020c1047109d0110b201101a2106200310072101200041003602142000200141027622013602102000200336020c024002400340200120024b04402000410c6a220110c20121022000410c6a10c20121032001108f0110960121052000410c6a108f01105621012000410c6a108f0110960122074280025a0d02200020023602182000200336021c20052006560d03200041186a2000411c6a2007a7220410a5012002200320052001200410a80120002802102101200028021421020c010b0b200041206a24000f0b41f18208410841808008410e103d000b41e08608411c1039000ba70301097f230041406a22002400101f41001048109d01200041146a220110af01200041206a22032000280218106d024002402000280220044010402104200110af01200320002802182205106d20002802242101200028021c210720002802142108034020010440200041086a200520011031200028020c200041206a2202200541a9820841062001106f2201103520022001104d2102200041206a2001104d210620002802242000280220470d0320002d0030044041c8dc08410036020041ccdc0841003a00000b200041206a220120082007200220061080012000280220450d042001200220062000280224200028022810a7011040102c210120002802282001105b200028022c2001103820002802302001103820002903202001106220002802342001103720002d0038200110950120042001104121010c010b0b20002004360210200020041007360228200041003602242000200041106a36022003402000200041206a108e0120002802000440200028020410181a0c010b0b200041406b24000f0b41b2880841131039000b200141808008410e104f000b418e8008410b1039000b2c01017f230041206b22002400101f4102104820004100103c4101103c10b1012000109301200041206a24000b3801027f230041306b22002400101f41021048200041106a22014100103c4101103c10b101200042003703082001109301200041306a24000b2201017f101f103b41011048410041a3890841101045220010b30110ad01200010780ba70101037f230041306b22002400101f4100104810402101200041246a10a401200041106a200041286a107d2000200029031037021c0340200041086a2000411c6a103020002802080440200028020c210210401a20012002102c10410c010b0b2000200136021820002001100736022c200041003602282000200041186a36022403402000200041246a108e0120002802000440200028020410181a0c010b0b200041306a24000bd80101067f230041406a22002400101f103b410310484100103c21014101103c21024102104221042000200236020820002001360204109c011083010440200041046a200041086a10b001105a22034101109901200320041099012003105c200020023602102000200136020c200041246a10a901200041146a2000280224200028022c20012002107e20002802140440200041386a200041206a28020036020020002000290218370330200041306a108d010b2000410c6a220110aa01105e200110ab01105e200041406b24000f0b4198830841161039000b4801037f230041106b22002400101f410210484100103c21014101103c2102200020013602082000200236020c200041086a2000410c6a10a601ad42ff01831017200041106a24000b1000101f4100104810ad011075ad10170b0f00101f103b410010484101109b010b0f00101f103b410010484100109b010b1100101f41001048109c01108301ad10200ba20301047f230041106b2202240041001048416b2100024041d8dc082d000022010440416b41ffffffff0720011b21000c010b41d8dc0841013a0000416b10210b0240024002400240027f024002400240200010074104760e020102000b41b2800841221002000b41752101024041d4dc082d000022000440417541ffffffff0720001b21010c010b41d4dc0841013a0000417510220b20011027210141feffffff070c010b200241086a420037030020024200370300200041002002411010520d01200229020450450d02200228020c220141187420014180fe03714108747220014108764180fe03712001411876727221012002280200220041187420004180fe03714108747220004108764180fe0371200041187672720b220010c0011082012203470440200041feffffff0746200341feffffff0746720d0320002003102d450d030b103a2100200210a10120022802082000108b01450d03200010a0012200106822032001105520002003108101200241106a24000f0b41e98108411d1002000b41c48d08411c1002000b419a860841151039000b41af860841221039000ba50201077f230041106b22022400101f41011048410010462201103a220510a00122041068220310b50104401028220020032001104b109f0110682103200210a10102400240024020022802082005108b0104402000200310a201450d010b20002004103310c00110820121001040210410402103200041feffffff07470d012005200142002004200310231a0c020b41968e0841101039000b104021062000102c2100200110272101200242003702042002200041187420004180fe03714108747220004108764180fe0371200041187672723602002002200141187420014180fe03714108747220014108764180fe03712001411876727236020c200620024110100b1a2005200642002004200310241a0b200241106a24000f0b41968e0841101039000b5701047f230041106b22002400101f41011048024010442201109e010440103a2202109e01450d01200041046a2203200110c10120032002108a01200041106a24000f0b41e8830841271039000b41968e0841101039000b3601047f230041106b22002400101f4101104810442101103a2102200041046a2203200110c101200320021087011a200041106a24000b850101047f230041106b22012400101f410110481044210010bf0110752102200141046a200010c10120012802081075200249044041c0830841121039000b10be0110682102200010a00122031068220020002002104b2003200010810141d58b084121103e2200106822032002105520002003108101200141046a109001200141106a24000b02000b3a01037f230041106b2203240020022001103e2204102c2105200341086a2004107f2000200329030837020020002005360208200341106a24000b0bc80e0200418080080bb40e696e70757420746f6f206c6f6e676d697373696e67206b657973657269616c697a6572206465636f6465206572726f723a20696e636f7272656374206e756d626572206f662045534454207472616e7366657273617267756d656e74206465636f6465206572726f722028293a20746f6f2066657720617267756d656e7473746f6f206d616e7920617267756d656e747377726f6e67206e756d626572206f6620617267756d656e747363616e6e6f74207375627472616374206265636175736520726573756c7420776f756c64206265206e65676174697665696e70757420746f6f2073686f72744d616e6167656456656320696e646578206f7574206f662072616e676545474c442e6d61707065642e6e6f64655f69642e6974656d2e6e6f64655f6c696e6b732e76616c75652e696e666f2e73746f726167652e696e64657873746f72616765206465636f6465206572726f7220286b65793a202e6c656e626164206172726179206c656e6774687661722061726773696e76616c69642076616c7565696e707574206f7574206f662072616e6765436f6e7472616374206973206e6f7420706175736564436f6e74726163742069732070617573656451756f72756d206e6f742072656163686564546f6f206d616e7920626f617264206d656d62657273566f7465642075736572206973206e6f742061207374616b656420626f617264206d656d6265724e6f20626f617264206d656d6265727351756f72756d20686967686572207468616e20746f74616c20706f737369626c6520626f617264206d656d6265727351756f72756d206d696e696d756d20626f617264206d656d6265727320726571756972656d656e74206e6f74206d65745374616b696e6720616e6420736c61736820616d6f756e742063616e6e6f742062652030536c61736820616d6f756e742063616e6e6f7420626520686967686572207468616e207265717569726564207374616b6572656d61696e696e67206e756d626572206f6620626f617264206d656d62657273206d7573742062652067726561746572207468616e2074686520736c6173682071756f72756d496e76616c6964207061796d656e7420746f6b656e4f6e6c792077686974656c6973746564206d656d626572732063616e207374616b656d656d6265725f746f5f736c61736854696d657374616d702069732066726f6d20746865206675747572654e6577207374616b696e6720616d6f756e7420697320746f6f2062696720636f6d706172656420746f206d656d62657273207374616b656420616d6f756e7477726f6e67206e756d626572206f6620646563696d616c737375626d697373696f6e206c6973742063617061636974792065786365656465646e6f207375626d697373696f6e737061697220646563696d616c73206e6f7420636f6e66696775726564746f6b656e2070616972206e6f7420666f756e646e6f20636f6d706c6574656420726f756e64736f6e6c79206f7261636c657320616c6c6f7765644669727374207375626d697373696f6e20746f6f206f6c64496e76616c6964207375626d697373696f6e20636f756e74646563696d616c736f7261636c65737375626d697373696f6e737375626d697373696f6e5f636f756e74736c6173685f71756f72756d6d656469616e3120696e76616c696420696e646578617373657274696f6e206661696c65643a206f666673657420213d2030202626206f6666736574203c3d206c656e617373657274696f6e206661696c65643a206f666673657420213d2030202626206f6666736574203c3d206c656e202626206c656e203e3d203270617573655f6d6f64756c653a7061757365647374616b696e675f6d6f64756c653a736c617368416d6f756e747374616b696e675f6d6f64756c653a736c61736851756f72756d7374616b696e675f6d6f64756c653a7374616b6564416d6f756e747374616b696e675f6d6f64756c653a7374616b696e67546f6b656e7374616b696e675f6d6f64756c653a7573657257686974656c6973747374616b696e675f6d6f64756c653a746f74616c536c6173686564416d6f756e747374616b696e675f6d6f64756c653a72657175697265645374616b65416d6f756e747374616b696e675f6d6f64756c653a736c617368696e6750726f706f73616c566f746572736f7261636c655f737461747573706169725f646563696d616c736c6173745f7375626d697373696f6e5f74696d657374616d7066697273745f7375626d697373696f6e5f74696d657374616d70726f756e64736e65775f726f756e6463616c6c656420604f7074696f6e3a3a756e77726170282960206f6e206120604e6f6e65602076616c756566756e6769626c65204553445420746f6b656e206578706563746564456e64706f696e742063616e206f6e6c792062652063616c6c6564206279206f776e6572696e646578206f7574206f662072616e67654e6f7420656e6f756768207374616b6570616e6963206f636375727265640041b48e080b0438ffffff", + "report": { + "imports": [ + "bigIntAdd", + "bigIntCmp", + "bigIntFinishUnsigned", + "bigIntGetCallValue", + "bigIntGetUnsignedArgument", + "bigIntSetInt64", + "bigIntSign", + "bigIntSub", + "bigIntTDiv", + "checkNoPayment", + "getBlockEpoch", + "getBlockNonce", + "getBlockTimestamp", + "getNumArguments", + "mBufferAppend", + "mBufferAppendBytes", + "mBufferCopyByteSlice", + "mBufferEq", + "mBufferFinish", + "mBufferFromBigIntUnsigned", + "mBufferGetArgument", + "mBufferGetByteSlice", + "mBufferGetLength", + "mBufferNew", + "mBufferSetBytes", + "mBufferStorageLoad", + "mBufferStorageStore", + "mBufferToBigIntUnsigned", + "managedCaller", + "managedGetMultiESDTCallValue", + "managedMultiTransferESDTNFTExecute", + "managedOwnerAddress", + "managedSignalError", + "managedTransferValueExecute", + "managedWriteLog", + "signalError", + "smallIntFinishSigned", + "smallIntFinishUnsigned", + "smallIntGetUnsignedArgument" + ], + "isMemGrow": false, + "eiCheck": { + "eiVersion": "1.3", + "ok": true + }, + "codeReport": { + "path": "../output/multiversx-price-aggregator-sc.wasm", + "size": 19315, + "hasAllocator": false, + "hasPanic": "without message" + } + } +} diff --git a/price-aggregator/multiversx-price-aggregator-sc.wasm b/price-aggregator/multiversx-price-aggregator-sc.wasm new file mode 100755 index 00000000..38c04596 Binary files /dev/null and b/price-aggregator/multiversx-price-aggregator-sc.wasm differ diff --git a/price-aggregator/price-aggregator.abi.json b/price-aggregator/price-aggregator-deprecated.abi.json similarity index 100% rename from price-aggregator/price-aggregator.abi.json rename to price-aggregator/price-aggregator-deprecated.abi.json diff --git a/price-aggregator/price-aggregator.wasm b/price-aggregator/price-aggregator-deprecated.wasm similarity index 100% rename from price-aggregator/price-aggregator.wasm rename to price-aggregator/price-aggregator-deprecated.wasm diff --git a/price-aggregator/scenarios/deploy.scen.json b/price-aggregator/scenarios/deploy.scen.json new file mode 100644 index 00000000..d069ba8a --- /dev/null +++ b/price-aggregator/scenarios/deploy.scen.json @@ -0,0 +1,190 @@ +{ + "name": "deploy", + "steps": [ + { + "step": "setState", + "accounts": { + "address:aggregator-owner": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "address:oracle": { + "nonce": "0", + "balance": "100", + "storage": {} + }, + "address:oracle2": { + "nonce": "0", + "balance": "100", + "storage": {} + }, + "address:oracle3": { + "nonce": "0", + "balance": "100", + "storage": {} + }, + "address:oracle4": { + "nonce": "0", + "balance": "0", + "storage": {} + }, + "address:oracle5": { + "nonce": "0", + "balance": "0", + "storage": {} + } + }, + "newAddresses": [ + { + "creatorAddress": "address:aggregator-owner", + "creatorNonce": "0", + "newAddress": "sc:price_aggregator" + } + ] + }, + { + "step": "scDeploy", + "txId": "deploy", + "tx": { + "from": "address:aggregator-owner", + "contractCode": "file:../multiversx-price-aggregator-sc.wasm", + "value": "0", + "arguments": [ + "str:EGLD", + "20", + "10", + "3", + "3", + "address:oracle", + "address:oracle2", + "address:oracle3", + "address:oracle4", + "address:oracle5" + ], + "gasLimit": "20,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-set-pair", + "tx": { + "from": "address:aggregator-owner", + "to": "sc:price_aggregator", + "value": "0", + "function": "setPairDecimals", + "arguments": [ + "str:GWEI", + "str:BRIDGE", + "u8:6" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-set-pair", + "tx": { + "from": "address:aggregator-owner", + "to": "sc:price_aggregator", + "value": "0", + "function": "setPairDecimals", + "arguments": [ + "str:GWEI", + "str:WEGLD", + "u8:9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-set-pair", + "tx": { + "from": "address:aggregator-owner", + "to": "sc:price_aggregator", + "value": "0", + "function": "setPairDecimals", + "arguments": [ + "str:GWEI", + "str:ETH", + "u8:9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "unpause", + "tx": { + "from": "address:aggregator-owner", + "to": "sc:price_aggregator", + "value": "0", + "function": "unpause", + "arguments": [], + "gasLimit": "100,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "out": [], + "gas": "*", + "refund": "*" + } + }, + { + "step": "checkState", + "accounts": { + "address:aggregator-owner": { + "nonce": "5", + "balance": "0", + "storage": {} + }, + "sc:price_aggregator": { + "nonce": "0", + "balance": "0", + "storage": { + "str:submission_count": "3", + "str:decimals": "0", + "str:oracle_status.mapped|address:oracle": { + "0-total_submissions": "u64:0", + "1-accepted_submissions": "u64:0" + }, + "+": "" + }, + "code": "file:../multiversx-price-aggregator-sc.wasm" + }, + "+": {} + } + } + ] +} diff --git a/price-aggregator/mandos/get_latest_price_feed.scen.json b/price-aggregator/scenarios/get_latest_price_feed.scen.json similarity index 90% rename from price-aggregator/mandos/get_latest_price_feed.scen.json rename to price-aggregator/scenarios/get_latest_price_feed.scen.json index 27ccdaa8..1bf5063b 100644 --- a/price-aggregator/mandos/get_latest_price_feed.scen.json +++ b/price-aggregator/scenarios/get_latest_price_feed.scen.json @@ -22,8 +22,9 @@ "1", "str:GWEI", "str:BRIDGE", + "0", "10", - "0" + "6" ] } }, @@ -47,8 +48,9 @@ "1", "str:GWEI", "str:BRIDGE", + "0", "10", - "0" + "6" ], "status": "0", "message": "", @@ -66,17 +68,14 @@ "function": "latestPriceFeedOptional", "arguments": [ "str:RAND-TOKEN", - "str:EGLD" + "str:WEGLD-123456" ], "gasLimit": "40,000,000", "gasPrice": "0" }, "expect": { - "out": [], - "status": "0", - "message": "", - "gas": "*", - "refund": "*" + "status": "4", + "message": "str:token pair not found" } } ] diff --git a/price-aggregator/mandos/oracle_gwei_in_eth_and_egld_submit.scen.json b/price-aggregator/scenarios/oracle_gwei_in_eth_and_egld_submit.scen.json similarity index 86% rename from price-aggregator/mandos/oracle_gwei_in_eth_and_egld_submit.scen.json rename to price-aggregator/scenarios/oracle_gwei_in_eth_and_egld_submit.scen.json index b8bf80d3..f5dc37e0 100644 --- a/price-aggregator/mandos/oracle_gwei_in_eth_and_egld_submit.scen.json +++ b/price-aggregator/scenarios/oracle_gwei_in_eth_and_egld_submit.scen.json @@ -15,8 +15,10 @@ "function": "submit", "arguments": [ "str:GWEI", - "str:ETH", - "1" + "str:BRIDGE", + "u64:0", + "1", + "6" ], "gasLimit": "40,000,000", "gasPrice": "0" @@ -38,8 +40,10 @@ "function": "submit", "arguments": [ "str:GWEI", - "str:EGLD", - "10" + "str:WEGLD", + "u64:0", + "10", + "9" ], "gasLimit": "40,000,000", "gasPrice": "0" diff --git a/price-aggregator/scenarios/oracle_stake.scen.json b/price-aggregator/scenarios/oracle_stake.scen.json new file mode 100644 index 00000000..93c442b1 --- /dev/null +++ b/price-aggregator/scenarios/oracle_stake.scen.json @@ -0,0 +1,66 @@ +{ + "name": "oracle stake", + "steps": [ + { + "step": "externalSteps", + "path": "deploy.scen.json" + }, + { + "step": "scCall", + "txId": "oracle-stake", + "tx": { + "from": "address:oracle", + "to": "sc:price_aggregator", + "value": "100", + "function": "stake", + "arguments": [], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-stake", + "tx": { + "from": "address:oracle2", + "to": "sc:price_aggregator", + "value": "100", + "function": "stake", + "arguments": [], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-stake", + "tx": { + "from": "address:oracle3", + "to": "sc:price_aggregator", + "value": "100", + "function": "stake", + "arguments": [], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + } + ] +} diff --git a/price-aggregator/scenarios/oracle_submit.scen.json b/price-aggregator/scenarios/oracle_submit.scen.json new file mode 100644 index 00000000..ff2604f3 --- /dev/null +++ b/price-aggregator/scenarios/oracle_submit.scen.json @@ -0,0 +1,234 @@ +{ + "name": "oracle submit", + "steps": [ + { + "step": "externalSteps", + "path": "oracle_stake.scen.json" + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:BRIDGE", + "u64:0", + "10", + "6" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle2", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:BRIDGE", + "u64:0", + "10", + "6" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle3", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:BRIDGE", + "u64:0", + "10", + "6" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:WEGLD", + "u64:0", + "10", + "9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle2", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:WEGLD", + "u64:0", + "10", + "9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle3", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:WEGLD", + "u64:0", + "10", + "9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:ETH", + "u64:0", + "10", + "9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle2", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:ETH", + "u64:0", + "10", + "9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + }, + { + "step": "scCall", + "txId": "oracle-submit", + "tx": { + "from": "address:oracle3", + "to": "sc:price_aggregator", + "value": "0", + "function": "submit", + "arguments": [ + "str:GWEI", + "str:ETH", + "u64:0", + "10", + "9" + ], + "gasLimit": "40,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0", + "message": "", + "gas": "*", + "refund": "*" + } + } + ] +} diff --git a/test-caller/.gitignore b/test-caller/.gitignore new file mode 100644 index 00000000..2c76bc98 --- /dev/null +++ b/test-caller/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The mxpy output +/output*/ diff --git a/test-caller/Cargo.toml b/test-caller/Cargo.toml new file mode 100644 index 00000000..8487b40e --- /dev/null +++ b/test-caller/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "test-caller" +version = "0.0.0" +authors = ["Iulian Pascalau "] +edition = "2018" +publish = false + +[lib] +path = "src/test-caller.rs" + +[dependencies.multiversx-sc] +version = "=0.52.3" + +[dependencies.multiversx-sc-modules] +version = "0.52.3" + +[dev-dependencies] +num-bigint = "0.4.2" + +[dev-dependencies.multiversx-sc-scenario] +version = "=0.52.3" diff --git a/test-caller/meta/Cargo.toml b/test-caller/meta/Cargo.toml new file mode 100644 index 00000000..bf04cf16 --- /dev/null +++ b/test-caller/meta/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "test-caller-meta" +version = "0.0.0" +edition = "2018" +publish = false +authors = ["you"] + +[dev-dependencies] + +[dependencies.test-caller] +path = ".." + +[dependencies.multiversx-sc-meta-lib] +version = "=0.52.3" diff --git a/test-caller/meta/src/main.rs b/test-caller/meta/src/main.rs new file mode 100644 index 00000000..4c7e0bff --- /dev/null +++ b/test-caller/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta_lib::cli_main::(); +} diff --git a/test-caller/multiversx.json b/test-caller/multiversx.json new file mode 100644 index 00000000..73655396 --- /dev/null +++ b/test-caller/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/test-caller/src/test-caller.rs b/test-caller/src/test-caller.rs new file mode 100644 index 00000000..2c7fcf17 --- /dev/null +++ b/test-caller/src/test-caller.rs @@ -0,0 +1,68 @@ +#![no_std] + +use multiversx_sc::api::ManagedTypeApi; +use multiversx_sc::derive_imports::*; +use multiversx_sc::imports::*; + +#[type_abi] +#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, Clone, ManagedVecItem)] +pub struct CalledData { + pub size: u64, + pub address: ManagedAddress, + pub token_identifier: TokenIdentifier, +} + +#[multiversx_sc::contract] +pub trait TestCallerContract { + #[init] + fn init(&self) {} + + #[upgrade] + fn upgrade(&self) {} + + #[payable("*")] + #[endpoint(callPayable)] + fn call_payable(&self) {} + + #[endpoint(callNonPayable)] + fn call_non_payable(&self) {} + + #[payable("*")] + #[view(callPayableWithParams)] + fn call_payable_with_params( + &self, + size: u64, + address: ManagedAddress, + ) { + let payment = self.call_value().single_esdt(); + let token_identifier = payment.token_identifier; + + let data = CalledData{ + size, + address, + token_identifier, + }; + + _ = self.called_data_params().push(&data); + } + + #[view(getCalledDataParams)] + fn get_called_data_params( + &self, + ) -> MultiValueEncoded> { + let mut values = MultiValueEncoded::new(); + let len = self.called_data_params().len(); + + for i in 1..=len { + if self.called_data_params().item_is_empty(i) { + continue; + } + let value = self.called_data_params().get_unchecked(i); + values.push(value); + } + values + } + + #[storage_mapper("calledDataParams")] + fn called_data_params(&self) -> VecMapper>; +} diff --git a/test-caller/wasm/Cargo.lock b/test-caller/wasm/Cargo.lock new file mode 100644 index 00000000..708839a7 --- /dev/null +++ b/test-caller/wasm/Cargo.lock @@ -0,0 +1,198 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "multiversx-sc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "526760b1d6236c011285b264a70a0a9dd3b3dbc53c3b5f76932f4bcfd3a8910c" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4f318427761faecf26c1f3115a3beeb5f61858845a60547d9763aa981ddd2d" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476501462b0c2654b64f9dec6f2c480e24b4e9b7133ec10b7167e64acda35d04" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3557f2f12640a8a07fa6af66cc2a13b188c5b61bed72db22fe631fb3a60c3e96" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f5c29c6044f3dc9e866858feee625d7fae5604a68ac7bd66dec683eee97563" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed13aaca9cbdbc6911174cd3029e750a7563d85dd3daaa1107b1fd31c7f17245" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "test-caller" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + +[[package]] +name = "test-caller-wasm" +version = "0.0.0" +dependencies = [ + "multiversx-sc-wasm-adapter", + "test-caller", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" diff --git a/test-caller/wasm/Cargo.toml b/test-caller/wasm/Cargo.toml new file mode 100644 index 00000000..f97bbae6 --- /dev/null +++ b/test-caller/wasm/Cargo.toml @@ -0,0 +1,34 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "test-caller-wasm" +version = "0.0.0" +edition = "2018" +publish = false + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" +overflow-checks = false + +[profile.dev] +panic = "abort" + +[dependencies.test-caller] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "=0.52.3" + +[workspace] +members = ["."] diff --git a/test-caller/wasm/src/lib.rs b/test-caller/wasm/src/lib.rs new file mode 100644 index 00000000..43f3fc05 --- /dev/null +++ b/test-caller/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: 4 +// Async Callback (empty): 1 +// Total number of exported functions: 7 + +#![no_std] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + test_caller + ( + init => init + upgrade => upgrade + callPayable => call_payable + callNonPayable => call_non_payable + callPayableWithParams => call_payable_with_params + getCalledDataParams => get_called_data_params + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {}