diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 723b143..0badafa 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -14,9 +14,9 @@ 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@v2.3.5 with: - rust-toolchain: nightly-2023-04-24 + rust-toolchain: nightly-2023-05-27 vmtools-version: v1.4.60 secrets: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f4d16ca..8d25526 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ permissions: jobs: build: - uses: multiversx/mx-sc-actions/.github/workflows/reproducible-build.yml@v2.3.1 + uses: multiversx/mx-sc-actions/.github/workflows/reproducible-build.yml@v2.3.5 with: - image_tag: v5.1.0 + image_tag: v5.5.0 attach_to_existing_release: true diff --git a/.gitignore b/.gitignore index e1b8e97..9173cd8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ # 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 diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..32dc38e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1464 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "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 = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "bstr" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", + "once_cell", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "common-path" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +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.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +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 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "globset" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +dependencies = [ + "aho-corasick 0.7.20", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[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.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "launchpad" +version = "0.0.0" +dependencies = [ + "launchpad-common", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "launchpad-common" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + +[[package]] +name = "launchpad-guaranteed-tickets" +version = "0.0.0" +dependencies = [ + "launchpad-common", + "multiversx-sc", + "multiversx-sc-meta", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "launchpad-guaranteed-tickets-meta" +version = "0.0.0" +dependencies = [ + "launchpad-guaranteed-tickets", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "launchpad-locked-tokens" +version = "0.0.0" +dependencies = [ + "launchpad-common", + "multiversx-sc", + "multiversx-sc-meta", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "launchpad-locked-tokens-and-guaranteed-tickets" +version = "0.0.0" +dependencies = [ + "launchpad-common", + "launchpad-guaranteed-tickets", + "launchpad-locked-tokens", + "multiversx-sc", + "multiversx-sc-meta", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "launchpad-locked-tokens-and-guaranteed-tickets-meta" +version = "0.0.0" +dependencies = [ + "launchpad-locked-tokens-and-guaranteed-tickets", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "launchpad-locked-tokens-meta" +version = "0.0.0" +dependencies = [ + "launchpad-locked-tokens", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "launchpad-meta" +version = "0.0.0" +dependencies = [ + "launchpad", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "launchpad-migration-guaranteed-tickets" +version = "0.0.0" +dependencies = [ + "launchpad-common", + "multiversx-sc", + "multiversx-sc-meta", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "launchpad-migration-guaranteed-tickets-meta" +version = "0.0.0" +dependencies = [ + "launchpad-migration-guaranteed-tickets", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "launchpad-nft-and-guaranteed-tickets" +version = "0.0.0" +dependencies = [ + "hex", + "launchpad-common", + "launchpad-guaranteed-tickets", + "launchpad-with-nft", + "multiversx-sc", + "multiversx-sc-meta", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "num-bigint", + "num-traits", +] + +[[package]] +name = "launchpad-nft-and-guaranteed-tickets-meta" +version = "0.0.0" +dependencies = [ + "launchpad-nft-and-guaranteed-tickets", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "launchpad-with-nft" +version = "0.0.0" +dependencies = [ + "hex", + "launchpad-common", + "multiversx-sc", + "multiversx-sc-meta", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "num-bigint", + "num-traits", +] + +[[package]] +name = "launchpad-with-nft-meta" +version = "0.0.0" +dependencies = [ + "launchpad-with-nft", + "multiversx-sc", + "multiversx-sc-meta", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "log" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "multiversx-chain-scenario-format" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d2592a441608937c5aebec6732c38e6097f58de1dc9a64d7dbe98e0ab97a3c0" +dependencies = [ + "bech32", + "hex", + "num-bigint", + "num-traits", + "serde", + "serde_json", + "sha3 0.9.1", +] + +[[package]] +name = "multiversx-chain-vm" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c3cbb5b2609eda4d5c5070e8c08441b668440c88763fb41bcf9dfa4fb630cb1" +dependencies = [ + "bech32", + "ed25519-dalek", + "hex", + "itertools", + "multiversx-chain-scenario-format", + "multiversx-sc", + "multiversx-sc-meta", + "num-bigint", + "num-traits", + "rand 0.8.5", + "rand_seeder", + "serde", + "serde_json", + "sha2 0.10.6", + "sha3 0.10.8", +] + +[[package]] +name = "multiversx-sc" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "842795458f7aa56ca04191993628980987baa8558357f708a93514c1b2e9948a" +dependencies = [ + "bitflags", + "hashbrown 0.13.2", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7638cb46a0e99c636fd55443ac534ff0a5fad0bd772e1037fbac9a75e04c3c9" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "num-bigint", + "wee_alloc", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e976002d51367f16140929c10ee695f95dd8d34c150a45db60d3fcd1328a267a" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn 1.0.86", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99390a0cc0406e86993772bdf16c6be4e990117f939df94a6a6e2f89d18c4983" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn 1.0.86", +] + +[[package]] +name = "multiversx-sc-meta" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca81ea694896b732a379dea9457153d04e5e783a1f7e788842c34e4e1560b5ae" +dependencies = [ + "clap", + "colored", + "common-path", + "convert_case", + "hex", + "lazy_static", + "multiversx-sc", + "pathdiff", + "ruplacer", + "rustc_version", + "serde", + "serde_json", + "toml", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2f13e0d94bd5e2d1b0c1b1f31ffe7ef223d396a4b939d46a66c3519557d0a3" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-scenario" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cd84767e9e06589412cbfb572bee7dbead1eb9be6d1a0204619503f5f7d3dd0" +dependencies = [ + "colored", + "hex", + "itertools", + "multiversx-chain-vm", + "num-traits", + "pathdiff", + "serde", + "serde_json", + "sha2 0.10.6", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +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.3", +] + +[[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.3", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.5", +] + +[[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.3", +] + +[[package]] +name = "regex" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +dependencies = [ + "aho-corasick 1.0.1", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "ruplacer" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1001b63b19333d7a462006c7d281a43ce5c1b3c44cd2a9696ab54b8e9aa7e388" +dependencies = [ + "Inflector", + "anyhow", + "atty", + "clap", + "colored", + "ignore", + "regex", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.86", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa", + "ryu", + "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 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[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.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.86", + "unicode-xid", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "indexmap", + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[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.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[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.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.86", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index ebc4f27..62813d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ members = [ "launchpad-with-nft/meta", "launchpad-guaranteed-tickets", "launchpad-guaranteed-tickets/meta", + "launchpad-migration-guaranteed-tickets", + "launchpad-migration-guaranteed-tickets/meta", "launchpad-nft-and-guaranteed-tickets", "launchpad-nft-and-guaranteed-tickets/meta" ] diff --git a/launchpad-guaranteed-tickets/src/lib.rs b/launchpad-guaranteed-tickets/src/lib.rs index 3a0f4a4..323ec0a 100644 --- a/launchpad-guaranteed-tickets/src/lib.rs +++ b/launchpad-guaranteed-tickets/src/lib.rs @@ -3,12 +3,13 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); -use launchpad_common::launch_stage::Flags; +use launchpad_common::{launch_stage::Flags, tickets::WINNING_TICKET}; use crate::guranteed_ticket_winners::GuaranteedTicketsSelectionOperation; pub mod guaranteed_tickets_init; pub mod guranteed_ticket_winners; +pub mod token_release; pub type UserTicketsStatus = MultiValue5; @@ -27,6 +28,7 @@ pub trait LaunchpadGuaranteedTickets: + launchpad_common::user_interactions::UserInteractionsModule + guaranteed_tickets_init::GuaranteedTicketsInitModule + guranteed_ticket_winners::GuaranteedTicketWinnersModule + + token_release::TokenReleaseModule { #[allow(clippy::too_many_arguments)] #[init] @@ -149,7 +151,62 @@ pub trait LaunchpadGuaranteedTickets: #[endpoint(claimLaunchpadTokens)] fn claim_launchpad_tokens_endpoint(&self) { - self.claim_launchpad_tokens(Self::default_send_launchpad_tokens_fn); + let caller = self.blockchain().get_caller(); + let user_results_processed = self.claim_list().contains(&caller); + if !user_results_processed { + self.compute_launchpad_results(&caller); + }; + + let claimable_tokens = self.compute_claimable_tokens(&caller); + if claimable_tokens > 0 { + let launchpad_token_id = self.launchpad_token_id().get(); + self.send() + .direct_esdt(&caller, &launchpad_token_id, 0, &claimable_tokens); + self.user_claimed_balance(&caller) + .update(|balance| *balance += claimable_tokens); + } + } + + fn compute_launchpad_results(&self, caller: &ManagedAddress) { + self.require_claim_period(); + + let ticket_range = self.try_get_ticket_range(caller); + let nr_confirmed_tickets = self.nr_confirmed_tickets(caller).get(); + let mut nr_redeemable_tickets = 0; + + for ticket_id in ticket_range.first_id..=ticket_range.last_id { + let ticket_status = self.ticket_status(ticket_id).get(); + if ticket_status == WINNING_TICKET { + self.ticket_status(ticket_id).clear(); + + nr_redeemable_tickets += 1; + } + + self.ticket_pos_to_id(ticket_id).clear(); + } + + self.nr_confirmed_tickets(caller).clear(); + self.ticket_range_for_address(caller).clear(); + self.ticket_batch(ticket_range.first_id).clear(); + + if nr_redeemable_tickets > 0 { + self.nr_winning_tickets() + .update(|nr_winning_tickets| *nr_winning_tickets -= nr_redeemable_tickets); + } + + self.claim_list().add(caller); + + let nr_tickets_to_refund = nr_confirmed_tickets - nr_redeemable_tickets; + self.refund_ticket_payment(caller, nr_tickets_to_refund); + + if nr_redeemable_tickets > 0 { + let tokens_per_winning_ticket = self.launchpad_tokens_per_winning_ticket().get(); + let launchpad_tokens_amount_won = + BigUint::from(nr_redeemable_tickets as u32) * tokens_per_winning_ticket; + + self.user_total_claimable_balance(caller) + .set(launchpad_tokens_amount_won); + } } #[only_owner] diff --git a/launchpad-guaranteed-tickets/src/token_release.rs b/launchpad-guaranteed-tickets/src/token_release.rs new file mode 100644 index 0000000..2685a42 --- /dev/null +++ b/launchpad-guaranteed-tickets/src/token_release.rs @@ -0,0 +1,129 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use launchpad_common::config; + +pub const MAX_PERCENTAGE: u64 = 10_000; + +#[derive(TopEncode, TopDecode, TypeAbi)] +pub struct UnlockSchedule { + claim_start_round: u64, + initial_release_percentage: u64, + vesting_release_times: u64, + vesting_release_percentage: u64, + vesting_release_period: u64, +} + +impl UnlockSchedule { + pub fn new( + claim_start_round: u64, + initial_release_percentage: u64, + vesting_release_times: u64, + vesting_release_percentage: u64, + vesting_release_period: u64, + ) -> Self { + UnlockSchedule { + claim_start_round, + initial_release_percentage, + vesting_release_times, + vesting_release_percentage, + vesting_release_period, + } + } +} + +#[multiversx_sc::module] +pub trait TokenReleaseModule: config::ConfigModule { + #[only_owner] + #[endpoint(setUnlockSchedule)] + fn set_unlock_schedule( + &self, + claim_start_round: u64, + initial_release_percentage: u64, + vesting_release_times: u64, + vesting_release_percentage: u64, + vesting_release_period: u64, + ) { + let configuration = self.configuration(); + require!( + !configuration.is_empty(), + "Timeline configuration is not set" + ); + let confirmation_period_start_block = configuration.get().confirmation_period_start_block; + + let current_block = self.blockchain().get_block_nonce(); + let current_round = self.blockchain().get_block_round(); + require!( + current_block < confirmation_period_start_block || self.unlock_schedule().is_empty(), + "Can't change the unlock schedule" + ); + require!( + claim_start_round >= current_round, + "Wrong claim start round" + ); + require!( + vesting_release_period > 0, + "Wrong vesting release recurrency" + ); + + let unlock_percentage = + initial_release_percentage + vesting_release_times * vesting_release_percentage; + + require!( + unlock_percentage == MAX_PERCENTAGE, + "Unlock percentage is not 100%" + ); + + let unlock_schedule = UnlockSchedule::new( + claim_start_round, + initial_release_percentage, + vesting_release_times, + vesting_release_percentage, + vesting_release_period, + ); + + self.unlock_schedule().set(unlock_schedule); + } + + #[view(getClaimableTokens)] + fn compute_claimable_tokens(&self, address: &ManagedAddress) -> BigUint { + let user_total_claimable_balance = self.user_total_claimable_balance(address).get(); + let user_claimed_balance = self.user_claimed_balance(address).get(); + if user_total_claimable_balance == user_claimed_balance { + return BigUint::zero(); + } + let unlock_schedule_mapper = self.unlock_schedule(); + if unlock_schedule_mapper.is_empty() { + return BigUint::zero(); + } + let unlock_schedule = unlock_schedule_mapper.get(); + let current_round = self.blockchain().get_block_round(); + if unlock_schedule.claim_start_round > current_round { + return BigUint::zero(); + } + + let rounds_passed = current_round - unlock_schedule.claim_start_round; + let mut claimable_periods = rounds_passed / unlock_schedule.vesting_release_period; + if claimable_periods > unlock_schedule.vesting_release_times { + claimable_periods = unlock_schedule.vesting_release_times; + } + let claimable_percentage = unlock_schedule.initial_release_percentage + + unlock_schedule.vesting_release_percentage * claimable_periods; + let current_claimable_tokens = + &user_total_claimable_balance * claimable_percentage / MAX_PERCENTAGE; + + current_claimable_tokens - user_claimed_balance + } + + #[view(getUserTotalClaimableBalance)] + #[storage_mapper("userTotalClaimableBalance")] + fn user_total_claimable_balance(&self, address: &ManagedAddress) -> SingleValueMapper; + + #[view(getUserClaimedBalance)] + #[storage_mapper("userClaimedBalance")] + fn user_claimed_balance(&self, address: &ManagedAddress) -> SingleValueMapper; + + #[view(getUnlockSchedule)] + #[storage_mapper("unlockSchedule")] + fn unlock_schedule(&self) -> SingleValueMapper; +} diff --git a/launchpad-guaranteed-tickets/wasm/src/lib.rs b/launchpad-guaranteed-tickets/wasm/src/lib.rs index b43e809..d7ae6da 100644 --- a/launchpad-guaranteed-tickets/wasm/src/lib.rs +++ b/launchpad-guaranteed-tickets/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 32 +// Endpoints: 38 // Async Callback (empty): 1 -// Total number of exported functions: 34 +// Total number of exported functions: 40 #![no_std] #![feature(lang_items)] @@ -21,6 +21,7 @@ multiversx_sc_wasm_adapter::endpoints! { addTickets depositLaunchpadTokens addUsersToBlacklist + removeGuaranteedUsersFromBlacklist distributeGuaranteedTickets claimLaunchpadTokens claimTicketPayment @@ -50,6 +51,11 @@ multiversx_sc_wasm_adapter::endpoints! { isUserBlacklisted confirmTickets hasUserClaimedTokens + setUnlockSchedule + getClaimableTokens + getUserTotalClaimableBalance + getUserClaimedBalance + getUnlockSchedule ) } diff --git a/launchpad-migration-guaranteed-tickets/.gitignore b/launchpad-migration-guaranteed-tickets/.gitignore new file mode 100644 index 0000000..eaf5915 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The erdpy output +output diff --git a/launchpad-migration-guaranteed-tickets/Cargo.toml b/launchpad-migration-guaranteed-tickets/Cargo.toml new file mode 100644 index 0000000..2b31188 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "launchpad-migration-guaranteed-tickets" +version = "0.0.0" +authors = ["Dorin Marian Iancu "] +edition = "2021" +publish = false + +[lib] +path = "src/lib.rs" + +[dependencies.launchpad-common] +path = "../launchpad-common" + +[dependencies.multiversx-sc] +version = "0.41.1" + +[dev-dependencies.multiversx-sc-meta] +version = "0.41.1" + +[dev-dependencies] +num-bigint = "0.4.2" + +[dev-dependencies.multiversx-sc-scenario] +version = "0.41.1" diff --git a/launchpad-migration-guaranteed-tickets/meta/Cargo.toml b/launchpad-migration-guaranteed-tickets/meta/Cargo.toml new file mode 100644 index 0000000..d99e49d --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/meta/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "launchpad-migration-guaranteed-tickets-meta" +version = "0.0.0" +authors = ["Dorin Marian Iancu "] +edition = "2021" +publish = false + +[dependencies.launchpad-migration-guaranteed-tickets] +path = ".." + +[dependencies.multiversx-sc] +version = "0.41.1" + +[dependencies.multiversx-sc-meta] +version = "0.41.1" diff --git a/launchpad-migration-guaranteed-tickets/meta/src/main.rs b/launchpad-migration-guaranteed-tickets/meta/src/main.rs new file mode 100644 index 0000000..24f9ce5 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta::cli_main::(); +} diff --git a/launchpad-migration-guaranteed-tickets/multiversx.json b/launchpad-migration-guaranteed-tickets/multiversx.json new file mode 100644 index 0000000..7365539 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/launchpad-migration-guaranteed-tickets/src/guaranteed_tickets_init.rs b/launchpad-migration-guaranteed-tickets/src/guaranteed_tickets_init.rs new file mode 100644 index 0000000..5f93ed0 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/src/guaranteed_tickets_init.rs @@ -0,0 +1,154 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +pub const STAKING_GUARANTEED_TICKETS_NO: usize = 1; +pub const MIGRATION_GUARANTEED_TICKETS_NO: usize = 1; + +#[derive(TopEncode, TopDecode)] +pub struct UserTicketsStatus { + pub staking_tickets_allowance: usize, + pub energy_tickets_allowance: usize, + pub staking_guaranteed_tickets: usize, + pub migration_guaranteed_tickets: usize, +} + +impl UserTicketsStatus { + fn new(staking_tickets_allowance: usize, energy_tickets_allowance: usize) -> Self { + Self { + staking_tickets_allowance, + energy_tickets_allowance, + staking_guaranteed_tickets: 0usize, + migration_guaranteed_tickets: 0usize, + } + } +} + +#[multiversx_sc::module] +pub trait GuaranteedTicketsInitModule: + launchpad_common::launch_stage::LaunchStageModule + + launchpad_common::config::ConfigModule + + launchpad_common::ongoing_operation::OngoingOperationModule + + launchpad_common::tickets::TicketsModule +{ + fn add_tickets_with_guaranteed_winners( + &self, + address_number_pairs: MultiValueEncoded>, + ) { + self.require_add_tickets_period(); + + let min_confirmed_for_guaranteed_ticket = self.min_confirmed_for_guaranteed_ticket().get(); + let mut guranteed_ticket_whitelist = self.users_with_guaranteed_ticket(); + let mut total_winning_tickets = self.nr_winning_tickets().get(); + let mut total_guaranteed_tickets = self.total_guaranteed_tickets().get(); + + for multi_arg in address_number_pairs { + let (buyer, nr_staking_tickets, nr_energy_tickets, has_migrated_tokens) = + multi_arg.into_tuple(); + self.try_create_tickets(buyer.clone(), nr_staking_tickets + nr_energy_tickets); + + let mut user_ticket_status = + UserTicketsStatus::new(nr_staking_tickets, nr_energy_tickets); + + if nr_staking_tickets >= min_confirmed_for_guaranteed_ticket { + require!( + total_winning_tickets > 0, + "Too many users with guaranteed ticket" + ); + let _ = guranteed_ticket_whitelist.insert(buyer.clone()); + total_winning_tickets -= STAKING_GUARANTEED_TICKETS_NO; + total_guaranteed_tickets += STAKING_GUARANTEED_TICKETS_NO; + user_ticket_status.staking_guaranteed_tickets = STAKING_GUARANTEED_TICKETS_NO; + } + + if has_migrated_tokens { + require!( + total_winning_tickets > 0, + "Too many users with guaranteed ticket" + ); + let _ = guranteed_ticket_whitelist.insert(buyer.clone()); + total_winning_tickets -= MIGRATION_GUARANTEED_TICKETS_NO; + total_guaranteed_tickets += MIGRATION_GUARANTEED_TICKETS_NO; + user_ticket_status.migration_guaranteed_tickets = MIGRATION_GUARANTEED_TICKETS_NO; + } + + self.user_ticket_status(&buyer).set(user_ticket_status); + } + + self.total_guaranteed_tickets() + .set(total_guaranteed_tickets); + self.nr_winning_tickets().set(total_winning_tickets); + } + + fn clear_users_with_guaranteed_ticket_after_blacklist( + &self, + users: &ManagedVec, + ) { + let mut whitelist = self.users_with_guaranteed_ticket(); + let mut nr_winning_tickets_removed = 0; + let mut total_guaranteed_tickets = self.total_guaranteed_tickets().get(); + for user in users { + let was_whitelisted = whitelist.swap_remove(&user); + if was_whitelisted { + let user_ticket_status = self.user_ticket_status(&user).take(); + nr_winning_tickets_removed += user_ticket_status.staking_guaranteed_tickets; + nr_winning_tickets_removed += user_ticket_status.migration_guaranteed_tickets; + total_guaranteed_tickets -= user_ticket_status.staking_guaranteed_tickets; + total_guaranteed_tickets -= user_ticket_status.migration_guaranteed_tickets; + self.blacklist_user_ticket_status(&user) + .set(user_ticket_status); + } + } + + if nr_winning_tickets_removed > 0 { + self.nr_winning_tickets() + .update(|nr_winning| *nr_winning += nr_winning_tickets_removed); + } + self.total_guaranteed_tickets() + .set(total_guaranteed_tickets); + } + + fn remove_guaranteed_tickets_from_blacklist(&self, users: &ManagedVec) { + let mut nr_winning_tickets = self.nr_winning_tickets().get(); + let mut total_guaranteed_tickets = self.total_guaranteed_tickets().get(); + let mut whitelist = self.users_with_guaranteed_ticket(); + for user in users { + let user_ticket_status_mapper = self.user_ticket_status(&user); + if !user_ticket_status_mapper.is_empty() + || self.ticket_range_for_address(&user).is_empty() + { + continue; + } + + if whitelist.insert(user.clone()) { + let user_ticket_status = self.blacklist_user_ticket_status(&user).take(); + nr_winning_tickets -= user_ticket_status.staking_guaranteed_tickets; + nr_winning_tickets -= user_ticket_status.migration_guaranteed_tickets; + total_guaranteed_tickets += user_ticket_status.staking_guaranteed_tickets; + total_guaranteed_tickets += user_ticket_status.migration_guaranteed_tickets; + user_ticket_status_mapper.set(user_ticket_status); + } + } + + self.nr_winning_tickets().set(nr_winning_tickets); + self.total_guaranteed_tickets() + .set(total_guaranteed_tickets); + } + + #[storage_mapper("minConfirmedForGuaranteedTicket")] + fn min_confirmed_for_guaranteed_ticket(&self) -> SingleValueMapper; + + #[storage_mapper("usersWithGuaranteedTicket")] + fn users_with_guaranteed_ticket(&self) -> UnorderedSetMapper; + + #[storage_mapper("totalGuaranteedTickets")] + fn total_guaranteed_tickets(&self) -> SingleValueMapper; + + #[storage_mapper("userTicketStatus")] + fn user_ticket_status(&self, user: &ManagedAddress) -> SingleValueMapper; + + #[storage_mapper("blacklistUserTicketStatus")] + fn blacklist_user_ticket_status( + &self, + user: &ManagedAddress, + ) -> SingleValueMapper; +} diff --git a/launchpad-migration-guaranteed-tickets/src/guranteed_ticket_winners.rs b/launchpad-migration-guaranteed-tickets/src/guranteed_ticket_winners.rs new file mode 100644 index 0000000..b98ada6 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/src/guranteed_ticket_winners.rs @@ -0,0 +1,202 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use launchpad_common::{ + ongoing_operation::{CONTINUE_OP, STOP_OP}, + random::Random, + tickets::{TicketRange, WINNING_TICKET}, +}; + +const VEC_MAPPER_START_INDEX: usize = 1; + +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode)] +pub struct GuaranteedTicketsSelectionOperation { + pub rng: Random, + pub leftover_tickets: usize, + pub leftover_ticket_pos_offset: usize, + pub total_additional_winning_tickets: usize, +} + +impl Default for GuaranteedTicketsSelectionOperation { + fn default() -> Self { + Self { + rng: Random::default(), + leftover_tickets: 0, + leftover_ticket_pos_offset: 1, + total_additional_winning_tickets: 0, + } + } +} + +pub enum AdditionalSelectionTryResult { + Ok, + CurrentAlreadyWinning, + NewlySelectedAlreadyWinning, +} + +#[multiversx_sc::module] +pub trait GuaranteedTicketWinnersModule: + launchpad_common::launch_stage::LaunchStageModule + + launchpad_common::config::ConfigModule + + launchpad_common::ongoing_operation::OngoingOperationModule + + launchpad_common::tickets::TicketsModule + + crate::guaranteed_tickets_init::GuaranteedTicketsInitModule +{ + fn select_guaranteed_tickets( + &self, + op: &mut GuaranteedTicketsSelectionOperation, + ) -> OperationCompletionStatus { + let min_confirmed_for_staking_guaranteed_ticket = + self.min_confirmed_for_guaranteed_ticket().get(); + let mut users_whitelist = self.users_with_guaranteed_ticket(); + let mut users_left = users_whitelist.len(); + + self.run_while_it_has_gas(|| { + if users_left == 0 { + return STOP_OP; + } + + let current_user = users_whitelist.get_by_index(VEC_MAPPER_START_INDEX); + let _ = users_whitelist.swap_remove(¤t_user); + users_left -= 1; + + let user_ticket_status_mapper = self.user_ticket_status(¤t_user); + if user_ticket_status_mapper.is_empty() { + return CONTINUE_OP; + } + let user_confirmed_tickets = self.nr_confirmed_tickets(¤t_user).get(); + let user_ticket_status = user_ticket_status_mapper.get(); + let user_total_tickets_allowance = user_ticket_status.staking_tickets_allowance + + user_ticket_status.energy_tickets_allowance; + + let mut user_guaranteed_tickets_no = 0; + // Tickets guaranteed by token migration + if user_confirmed_tickets >= user_ticket_status.energy_tickets_allowance { + user_guaranteed_tickets_no += user_ticket_status.migration_guaranteed_tickets; + } else { + op.leftover_tickets += user_ticket_status.migration_guaranteed_tickets; + } + + // Tickets guaranteed by EGLD staking + if (user_guaranteed_tickets_no > 0 + && user_confirmed_tickets >= user_total_tickets_allowance) + || (user_guaranteed_tickets_no == 0 + && user_confirmed_tickets >= min_confirmed_for_staking_guaranteed_ticket) + { + user_guaranteed_tickets_no += user_ticket_status.staking_guaranteed_tickets; + } else { + op.leftover_tickets += user_ticket_status.staking_guaranteed_tickets; + } + + if user_guaranteed_tickets_no > 0 { + let ticket_range_mapper = self.ticket_range_for_address(¤t_user); + if ticket_range_mapper.is_empty() { + op.leftover_tickets += user_guaranteed_tickets_no; + return CONTINUE_OP; + } + + let ticket_range: TicketRange = ticket_range_mapper.get(); + let user_winning_tickets_no = self.winning_tickets_in_range(&ticket_range); + + if user_guaranteed_tickets_no <= user_winning_tickets_no { + op.leftover_tickets += user_guaranteed_tickets_no; + return CONTINUE_OP; + } + + let mut remaining_tickets_to_be_won = + user_guaranteed_tickets_no - user_winning_tickets_no; + + op.leftover_tickets += user_guaranteed_tickets_no - remaining_tickets_to_be_won; + + let mut current_ticket = ticket_range.first_id; + while remaining_tickets_to_be_won > 0 { + let is_winning_ticket = self.ticket_status(current_ticket).get(); + if !is_winning_ticket { + self.ticket_status(current_ticket).set(WINNING_TICKET); + op.total_additional_winning_tickets += 1; + remaining_tickets_to_be_won -= 1; + } + current_ticket += 1; + } + } + CONTINUE_OP + }) + } + + fn distribute_leftover_tickets( + &self, + op: &mut GuaranteedTicketsSelectionOperation, + ) -> OperationCompletionStatus { + let nr_original_winning_tickets = self.nr_winning_tickets().get(); + let last_ticket_pos = self.get_total_tickets(); + + self.run_while_it_has_gas(|| { + if nr_original_winning_tickets + op.total_additional_winning_tickets >= last_ticket_pos + { + op.leftover_tickets = 0; + } + + if op.leftover_tickets == 0 { + return STOP_OP; + } + + let current_ticket_pos = nr_original_winning_tickets + op.leftover_ticket_pos_offset; + + let selection_result = + self.try_select_winning_ticket(&mut op.rng, current_ticket_pos, last_ticket_pos); + match selection_result { + AdditionalSelectionTryResult::Ok => { + op.leftover_tickets -= 1; + op.total_additional_winning_tickets += 1; + op.leftover_ticket_pos_offset += 1; + } + AdditionalSelectionTryResult::CurrentAlreadyWinning => { + op.leftover_ticket_pos_offset += 1; + } + AdditionalSelectionTryResult::NewlySelectedAlreadyWinning => {} + } + + CONTINUE_OP + }) + } + + fn winning_tickets_in_range(&self, ticket_range: &TicketRange) -> usize { + let mut winning_tickets_no = 0; + for ticket_id in ticket_range.first_id..=ticket_range.last_id { + let ticket_status = self.ticket_status(ticket_id).get(); + if ticket_status == WINNING_TICKET { + winning_tickets_no += 1; + } + } + + winning_tickets_no + } + + fn try_select_winning_ticket( + &self, + rng: &mut Random, + current_ticket_position: usize, + last_ticket_position: usize, + ) -> AdditionalSelectionTryResult { + let current_ticket_id = self.get_ticket_id_from_pos(current_ticket_position); + if self.is_already_winning_ticket(current_ticket_id) { + return AdditionalSelectionTryResult::CurrentAlreadyWinning; + } + + let rand_pos = rng.next_usize_in_range(current_ticket_position, last_ticket_position + 1); + let winning_ticket_id = self.get_ticket_id_from_pos(rand_pos); + if self.is_already_winning_ticket(winning_ticket_id) { + return AdditionalSelectionTryResult::NewlySelectedAlreadyWinning; + } + + self.ticket_pos_to_id(rand_pos).set(current_ticket_id); + self.ticket_status(winning_ticket_id).set(WINNING_TICKET); + + AdditionalSelectionTryResult::Ok + } + + #[inline] + fn is_already_winning_ticket(&self, ticket_id: usize) -> bool { + self.ticket_status(ticket_id).get() == WINNING_TICKET + } +} diff --git a/launchpad-migration-guaranteed-tickets/src/lib.rs b/launchpad-migration-guaranteed-tickets/src/lib.rs new file mode 100644 index 0000000..edd01b9 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/src/lib.rs @@ -0,0 +1,177 @@ +#![no_std] + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +use launchpad_common::launch_stage::Flags; + +use crate::guranteed_ticket_winners::GuaranteedTicketsSelectionOperation; + +pub mod guaranteed_tickets_init; +pub mod guranteed_ticket_winners; + +pub type UserTicketsStatus = MultiValue5; + +#[multiversx_sc::contract] +pub trait LaunchpadMigrationGuaranteedTickets: + launchpad_common::LaunchpadMain + + launchpad_common::launch_stage::LaunchStageModule + + launchpad_common::config::ConfigModule + + launchpad_common::setup::SetupModule + + launchpad_common::tickets::TicketsModule + + launchpad_common::winner_selection::WinnerSelectionModule + + launchpad_common::ongoing_operation::OngoingOperationModule + + launchpad_common::permissions::PermissionsModule + + launchpad_common::blacklist::BlacklistModule + + launchpad_common::token_send::TokenSendModule + + launchpad_common::user_interactions::UserInteractionsModule + + guaranteed_tickets_init::GuaranteedTicketsInitModule + + guranteed_ticket_winners::GuaranteedTicketWinnersModule +{ + #[allow(clippy::too_many_arguments)] + #[init] + fn init( + &self, + launchpad_token_id: TokenIdentifier, + launchpad_tokens_per_winning_ticket: BigUint, + ticket_payment_token: EgldOrEsdtTokenIdentifier, + ticket_price: BigUint, + nr_winning_tickets: usize, + confirmation_period_start_block: u64, + winner_selection_start_block: u64, + claim_start_block: u64, + min_confirmed_for_guaranteed_ticket: usize, + ) { + self.init_base( + launchpad_token_id, + launchpad_tokens_per_winning_ticket, + ticket_payment_token, + ticket_price, + nr_winning_tickets, + confirmation_period_start_block, + winner_selection_start_block, + claim_start_block, + Flags::default(), + ); + + require!( + min_confirmed_for_guaranteed_ticket > 0, + "Invalid minimum tickets confirmed for guaranteed winning ticket" + ); + self.min_confirmed_for_guaranteed_ticket() + .set(min_confirmed_for_guaranteed_ticket); + } + + #[only_owner] + #[endpoint(addTickets)] + fn add_tickets_endpoint( + &self, + address_number_pairs: MultiValueEncoded>, + ) { + self.add_tickets_with_guaranteed_winners(address_number_pairs); + } + + #[only_owner] + #[payable("*")] + #[endpoint(depositLaunchpadTokens)] + fn deposit_launchpad_tokens_endpoint(&self) { + let base_selection_winning_tickets = self.nr_winning_tickets().get(); + let reserved_tickets = self.total_guaranteed_tickets().get(); + let total_tickets = base_selection_winning_tickets + reserved_tickets; + + self.deposit_launchpad_tokens(total_tickets); + } + + #[endpoint(addUsersToBlacklist)] + fn add_users_to_blacklist_endpoint(&self, users_list: MultiValueEncoded) { + let users_vec = users_list.to_vec(); + self.add_users_to_blacklist(&users_vec); + self.clear_users_with_guaranteed_ticket_after_blacklist(&users_vec); + } + + #[endpoint(removeGuaranteedUsersFromBlacklist)] + fn remove_guaranteed_users_from_blacklist_endpoint( + &self, + users_list: MultiValueEncoded, + ) { + let users_vec = users_list.to_vec(); + self.remove_users_from_blacklist(users_list); + self.remove_guaranteed_tickets_from_blacklist(&users_vec); + } + + #[endpoint(distributeGuaranteedTickets)] + fn distribute_guaranteed_tickets_endpoint(&self) -> OperationCompletionStatus { + self.require_winner_selection_period(); + + let flags_mapper = self.flags(); + let mut flags = flags_mapper.get(); + require!( + flags.were_winners_selected, + "Must select winners for base launchpad first" + ); + require!( + !flags.was_additional_step_completed, + "Already distributed tickets" + ); + + let mut current_operation: GuaranteedTicketsSelectionOperation = + self.load_additional_selection_operation(); + let first_op_run_result = self.select_guaranteed_tickets(&mut current_operation); + if first_op_run_result == OperationCompletionStatus::InterruptedBeforeOutOfGas { + self.save_additional_selection_progress(¤t_operation); + + return first_op_run_result; + } + + let second_op_run_result = self.distribute_leftover_tickets(&mut current_operation); + match second_op_run_result { + OperationCompletionStatus::InterruptedBeforeOutOfGas => { + self.save_additional_selection_progress(¤t_operation); + } + OperationCompletionStatus::Completed => { + flags.was_additional_step_completed = true; + flags_mapper.set(&flags); + + let ticket_price = self.ticket_price().get(); + let claimable_ticket_payment = ticket_price.amount + * (current_operation.total_additional_winning_tickets as u32); + self.claimable_ticket_payment() + .update(|claim_amt| *claim_amt += claimable_ticket_payment); + + self.nr_winning_tickets().update(|nr_winning| { + *nr_winning += current_operation.total_additional_winning_tickets + }); + } + }; + + second_op_run_result + } + + #[endpoint(claimLaunchpadTokens)] + fn claim_launchpad_tokens_endpoint(&self) { + self.claim_launchpad_tokens(Self::default_send_launchpad_tokens_fn); + } + + #[only_owner] + #[endpoint(claimTicketPayment)] + fn claim_ticket_payment_endpoint(&self) { + self.claim_ticket_payment(); + } + + #[view(getUserTicketsStatus)] + fn user_tickets_status(&self, address: ManagedAddress) -> UserTicketsStatus { + let user_ticket_status_mapper = self.user_ticket_status(&address); + require!(!user_ticket_status_mapper.is_empty(), "User not found"); + let user_ticket_status = user_ticket_status_mapper.get(); + let user_confirmed_tickets_no = self.nr_confirmed_tickets(&address).get(); + + ( + user_ticket_status.staking_tickets_allowance, + user_ticket_status.energy_tickets_allowance, + user_confirmed_tickets_no, + user_ticket_status.staking_guaranteed_tickets, + user_ticket_status.migration_guaranteed_tickets, + ) + .into() + } +} diff --git a/launchpad-migration-guaranteed-tickets/testnet.toml b/launchpad-migration-guaranteed-tickets/testnet.toml new file mode 100644 index 0000000..e69de29 diff --git a/launchpad-migration-guaranteed-tickets/tests/migration_guaranteed_tickets_setup/mod.rs b/launchpad-migration-guaranteed-tickets/tests/migration_guaranteed_tickets_setup/mod.rs new file mode 100644 index 0000000..9fa2563 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/tests/migration_guaranteed_tickets_setup/mod.rs @@ -0,0 +1,208 @@ +use multiversx_sc::types::{ + Address, EgldOrEsdtTokenIdentifier, MultiValueEncoded, OperationCompletionStatus, +}; + +use launchpad_common::{ + config::ConfigModule, + launch_stage::{Flags, LaunchStageModule}, + tickets::{TicketsModule, WINNING_TICKET}, + user_interactions::UserInteractionsModule, + winner_selection::WinnerSelectionModule, +}; +use launchpad_migration_guaranteed_tickets::{ + guaranteed_tickets_init::GuaranteedTicketsInitModule, LaunchpadMigrationGuaranteedTickets, +}; +use multiversx_sc_scenario::{ + managed_address, managed_biguint, managed_token_id, rust_biguint, + testing_framework::{BlockchainStateWrapper, ContractObjWrapper, TxResult}, + DebugApi, +}; + +pub static LAUNCHPAD_TOKEN_ID: &[u8] = b"LAUNCH-123456"; +pub const LAUNCHPAD_TOKENS_PER_TICKET: u64 = 100; +pub const CONFIRM_START_BLOCK: u64 = 5; +pub const WINNER_SELECTION_START_BLOCK: u64 = 10; +pub const CLAIM_START_BLOCK: u64 = 15; + +pub const NR_LAUNCHPAD_PARTICIPANTS: usize = 3; +pub const NR_WINNING_TICKETS: usize = 3; +pub const MAX_TIER_TICKETS: usize = 3; +pub const TICKET_COST: u64 = 10; + +pub struct LaunchpadSetup +where + LaunchpadBuilder: 'static + Copy + Fn() -> launchpad_migration_guaranteed_tickets::ContractObj, +{ + pub b_mock: BlockchainStateWrapper, + pub owner_address: Address, + pub participants: Vec
, + pub lp_wrapper: + ContractObjWrapper, LaunchpadBuilder>, +} + +impl LaunchpadSetup +where + LaunchpadBuilder: 'static + Copy + Fn() -> launchpad_migration_guaranteed_tickets::ContractObj, +{ + pub fn new(nr_winning_tickets: usize, lp_builder: LaunchpadBuilder) -> Self { + let rust_zero = rust_biguint!(0u64); + let user_balance = rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64); + let total_launchpad_tokens = + rust_biguint!(LAUNCHPAD_TOKENS_PER_TICKET * nr_winning_tickets as u64); + + let mut b_mock = BlockchainStateWrapper::new(); + let owner_address = b_mock.create_user_account(&rust_zero); + let mut participants = Vec::new(); + + for _ in 0..NR_LAUNCHPAD_PARTICIPANTS { + let addr = b_mock.create_user_account(&user_balance); + participants.push(addr); + } + + b_mock.set_esdt_balance(&owner_address, LAUNCHPAD_TOKEN_ID, &total_launchpad_tokens); + + let lp_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(&owner_address), + lp_builder, + "buy tickets = win.wasm", + ); + + // init launchpad + b_mock + .execute_tx(&owner_address, &lp_wrapper, &rust_zero, |sc| { + sc.init( + managed_token_id!(LAUNCHPAD_TOKEN_ID), + managed_biguint!(LAUNCHPAD_TOKENS_PER_TICKET), + EgldOrEsdtTokenIdentifier::egld(), + managed_biguint!(TICKET_COST), + nr_winning_tickets, + CONFIRM_START_BLOCK, + WINNER_SELECTION_START_BLOCK, + CLAIM_START_BLOCK, + MAX_TIER_TICKETS, + ); + }) + .assert_ok(); + + // add tickets + // first user - 1 ticket, secnond user - 2 tickets, 3rd user - 3 tickets + b_mock + .execute_tx(&owner_address, &lp_wrapper, &rust_zero, |sc| { + let mut args = MultiValueEncoded::new(); + for (i, p) in participants.iter().enumerate() { + args.push((managed_address!(p), i + 1, 0, false).into()); + } + + sc.add_tickets_endpoint(args); + + // 1 ticket for the max tier gets removed + assert_eq!(sc.nr_winning_tickets().get(), nr_winning_tickets - 1); + assert_eq!(sc.users_with_guaranteed_ticket().len(), 1); + assert!(sc + .users_with_guaranteed_ticket() + .contains(&managed_address!(participants.last().unwrap()))); + }) + .assert_ok(); + + // deposit launchpad tokens + b_mock + .execute_esdt_transfer( + &owner_address, + &lp_wrapper, + LAUNCHPAD_TOKEN_ID, + 0, + &total_launchpad_tokens, + |sc| { + sc.deposit_launchpad_tokens_endpoint(); + }, + ) + .assert_ok(); + + b_mock.set_block_nonce(CONFIRM_START_BLOCK); + + Self { + b_mock, + owner_address, + participants, + lp_wrapper, + } + } + + pub fn confirm(&mut self, caller: &Address, nr_tickets: usize) -> TxResult { + self.b_mock.execute_tx( + caller, + &self.lp_wrapper, + &rust_biguint!(TICKET_COST * nr_tickets as u64), + |sc| { + sc.confirm_tickets(nr_tickets); + }, + ) + } + + pub fn filter_tickets(&mut self) -> TxResult { + self.b_mock.execute_tx( + &self.owner_address, + &self.lp_wrapper, + &rust_biguint!(0), + |sc| { + let result = sc.filter_tickets(); + assert_eq!(result, OperationCompletionStatus::Completed); + }, + ) + } + + pub fn select_base_winners_mock(&mut self, nr_whales: usize) -> TxResult { + self.b_mock.execute_tx( + &self.owner_address, + &self.lp_wrapper, + &rust_biguint!(0), + |sc| { + let base_winning = NR_WINNING_TICKETS - nr_whales; + for ticket_id in 1..=base_winning { + sc.ticket_status(ticket_id).set(WINNING_TICKET); + } + + sc.claimable_ticket_payment() + .set(&managed_biguint!(TICKET_COST * (base_winning as u64))); + + sc.flags().set(&Flags { + were_tickets_filtered: true, + has_winner_selection_process_started: true, + were_winners_selected: true, + was_additional_step_completed: false, + }) + }, + ) + } + + pub fn distribute_tickets(&mut self) -> TxResult { + self.b_mock.execute_tx( + &self.owner_address, + &self.lp_wrapper, + &rust_biguint!(0), + |sc| { + let result = sc.distribute_guaranteed_tickets_endpoint(); + assert_eq!(result, OperationCompletionStatus::Completed); + }, + ) + } + + pub fn claim_user(&mut self, user: &Address) -> TxResult { + self.b_mock + .execute_tx(user, &self.lp_wrapper, &rust_biguint!(0), |sc| { + sc.claim_launchpad_tokens_endpoint(); + }) + } + + pub fn claim_owner(&mut self) -> TxResult { + self.b_mock.execute_tx( + &self.owner_address, + &self.lp_wrapper, + &rust_biguint!(0), + |sc| { + sc.claim_ticket_payment(); + }, + ) + } +} diff --git a/launchpad-migration-guaranteed-tickets/tests/migration_guaranteed_tickets_test.rs b/launchpad-migration-guaranteed-tickets/tests/migration_guaranteed_tickets_test.rs new file mode 100644 index 0000000..9aa4366 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/tests/migration_guaranteed_tickets_test.rs @@ -0,0 +1,1177 @@ +#![allow(clippy::bool_assert_comparison)] + +mod migration_guaranteed_tickets_setup; + +use migration_guaranteed_tickets_setup::{ + LaunchpadSetup, CLAIM_START_BLOCK, CONFIRM_START_BLOCK, LAUNCHPAD_TOKENS_PER_TICKET, + LAUNCHPAD_TOKEN_ID, MAX_TIER_TICKETS, TICKET_COST, WINNER_SELECTION_START_BLOCK, +}; +use launchpad_common::{ + config::ConfigModule, + setup::SetupModule, + tickets::{TicketsModule, WINNING_TICKET}, + winner_selection::WinnerSelectionModule, +}; +use launchpad_migration_guaranteed_tickets::{ + guaranteed_tickets_init::GuaranteedTicketsInitModule, + guranteed_ticket_winners::{ + GuaranteedTicketWinnersModule, GuaranteedTicketsSelectionOperation, + }, + LaunchpadMigrationGuaranteedTickets, +}; +use multiversx_sc::types::{EgldOrEsdtTokenIdentifier, MultiValueEncoded}; +use multiversx_sc_scenario::{managed_address, managed_biguint, rust_biguint}; + +use crate::migration_guaranteed_tickets_setup::NR_WINNING_TICKETS; + +#[test] +fn init_test() { + let _ = LaunchpadSetup::new( + NR_WINNING_TICKETS, + launchpad_migration_guaranteed_tickets::contract_obj, + ); +} + +#[test] +fn confirm_all_test() { + let mut lp_setup = LaunchpadSetup::new( + NR_WINNING_TICKETS, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let participants = lp_setup.participants.clone(); + + for (i, p) in participants.iter().enumerate() { + lp_setup.confirm(p, i + 1).assert_ok(); + } + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + lp_setup.filter_tickets().assert_ok(); + lp_setup.select_base_winners_mock(1).assert_ok(); + + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), false); + assert_eq!(sc.ticket_status(5).get(), false); + assert_eq!(sc.ticket_status(6).get(), false); + + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[0])), + 1 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[1])), + 1 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[2])), + 0 + ); + + assert_eq!(sc.nr_winning_tickets().get(), NR_WINNING_TICKETS - 1); + }) + .assert_ok(); + + lp_setup.distribute_tickets().assert_ok(); + + // third user now has ticket with ID 4 as winning + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(5).get(), false); + assert_eq!(sc.ticket_status(6).get(), false); + + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[0])), + 1 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[1])), + 1 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[2])), + 1 + ); + + assert_eq!(sc.nr_winning_tickets().get(), NR_WINNING_TICKETS); + }) + .assert_ok(); + + lp_setup.b_mock.set_block_nonce(CLAIM_START_BLOCK); + + // check balances before + let base_user_balance = rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64); + for (i, p) in participants.iter().enumerate() { + let ticket_payment = (i as u64 + 1) * TICKET_COST; + let remaining_balance = &base_user_balance - ticket_payment; + + lp_setup.b_mock.check_egld_balance(p, &remaining_balance); + lp_setup + .b_mock + .check_esdt_balance(p, LAUNCHPAD_TOKEN_ID, &rust_biguint!(0)); + } + lp_setup + .b_mock + .check_egld_balance(&lp_setup.owner_address, &rust_biguint!(0)); + + // claim + for p in participants.iter() { + lp_setup.claim_user(p).assert_ok(); + } + lp_setup.claim_owner().assert_ok(); + + // check balances after + // each user won 1 ticket + for p in participants.iter() { + let remaining_balance = &base_user_balance - TICKET_COST; + + lp_setup.b_mock.check_egld_balance(p, &remaining_balance); + lp_setup.b_mock.check_esdt_balance( + p, + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(LAUNCHPAD_TOKENS_PER_TICKET), + ); + } + lp_setup + .b_mock + .check_egld_balance(&lp_setup.owner_address, &rust_biguint!(TICKET_COST * 3)); +} + +#[test] +fn redistribute_test() { + let mut lp_setup = LaunchpadSetup::new( + NR_WINNING_TICKETS, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let participants = lp_setup.participants.clone(); + + lp_setup.confirm(&participants[0], 1).assert_ok(); + lp_setup.confirm(&participants[1], 2).assert_ok(); + lp_setup.confirm(&participants[2], 2).assert_ok(); + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + lp_setup.filter_tickets().assert_ok(); + lp_setup.select_base_winners_mock(1).assert_ok(); + + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), false); + assert_eq!(sc.ticket_status(5).get(), false); + + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[0])), + 1 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[1])), + 1 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[2])), + 0 + ); + + assert_eq!(sc.nr_winning_tickets().get(), NR_WINNING_TICKETS - 1); + assert_eq!(sc.users_with_guaranteed_ticket().len(), 1); + }) + .assert_ok(); + + lp_setup.distribute_tickets().assert_ok(); + + // distribute leftover selected ticket ID 3 as winning + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(3).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(4).get(), false); + assert_eq!(sc.ticket_status(5).get(), false); + + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[0])), + 1 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[1])), + 2 + ); + assert_eq!( + sc.get_number_of_winning_tickets_for_address(managed_address!(&participants[2])), + 0 + ); + + assert_eq!(sc.nr_winning_tickets().get(), NR_WINNING_TICKETS); + assert_eq!(sc.users_with_guaranteed_ticket().len(), 0); + }) + .assert_ok(); +} + +#[test] +fn combined_scenario_test() { + let mut lp_setup = LaunchpadSetup::new( + NR_WINNING_TICKETS, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let mut participants = lp_setup.participants.clone(); + + let new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64)); + participants.push(new_participant.clone()); + + let second_new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST)); + participants.push(second_new_participant.clone()); + + // add another "whale" + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK - 1); + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push( + ( + managed_address!(&new_participant), + MAX_TIER_TICKETS, + 0, + false, + ) + .into(), + ); + args.push((managed_address!(&second_new_participant), 1, 0, false).into()); + + sc.add_tickets_endpoint(args); + }, + ) + .assert_ok(); + + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK); + + // user[0] and user[1] will not confirm, so they get filtered + lp_setup.confirm(&participants[2], 3).assert_ok(); + lp_setup.confirm(&participants[3], 3).assert_ok(); + lp_setup.confirm(&participants[4], 1).assert_ok(); + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + lp_setup.filter_tickets().assert_ok(); + lp_setup.select_base_winners_mock(2).assert_ok(); + + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), false); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), false); + assert_eq!(sc.ticket_status(5).get(), false); + assert_eq!(sc.ticket_status(6).get(), false); + assert_eq!(sc.ticket_status(7).get(), false); + + assert_eq!(sc.nr_winning_tickets().get(), NR_WINNING_TICKETS - 2); + assert_eq!(sc.users_with_guaranteed_ticket().len(), 2); + }) + .assert_ok(); + + // distribute by steps, to isolate each step's effect + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut op = GuaranteedTicketsSelectionOperation::default(); + + // first step + sc.select_guaranteed_tickets(&mut op); + + // user[3]'s first ticket was selected + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), false); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(5).get(), false); + assert_eq!(sc.ticket_status(6).get(), false); + assert_eq!(sc.ticket_status(7).get(), false); + + assert_eq!(op.leftover_tickets, 1); + assert_eq!(op.total_additional_winning_tickets, 1); + assert_eq!(op.leftover_ticket_pos_offset, 1); + + // second step + sc.distribute_leftover_tickets(&mut op); + + // ticket ID 2 was selected as winner + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(5).get(), false); + assert_eq!(sc.ticket_status(6).get(), false); + assert_eq!(sc.ticket_status(7).get(), false); + + assert_eq!(op.leftover_tickets, 0); + assert_eq!(op.total_additional_winning_tickets, 2); + assert_eq!(op.leftover_ticket_pos_offset, 2); + + assert_eq!(sc.users_with_guaranteed_ticket().len(), 0); + }, + ) + .assert_ok(); +} + +#[test] +fn add_migration_guaranteed_tickets_distribution_isolated_steps_scenario_test() { + let nr_random_tickets = 1; + let nr_staking_guaranteed_tickets = 2; + let nr_migration_guaranteed_tickets = 2; + let nr_winning_tickets = + nr_random_tickets + nr_staking_guaranteed_tickets + nr_migration_guaranteed_tickets; + let mut lp_setup = LaunchpadSetup::new( + nr_winning_tickets, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let mut participants = lp_setup.participants.clone(); + + let new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64)); + participants.push(new_participant.clone()); + + let second_new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64 * 2)); + participants.push(second_new_participant.clone()); + + // add 2 new users with migration guaranteed tickets + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK - 1); + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push((managed_address!(&new_participant), 1, 1, true).into()); + args.push( + ( + managed_address!(&second_new_participant), + MAX_TIER_TICKETS, + MAX_TIER_TICKETS, + true, + ) + .into(), + ); + + sc.add_tickets_endpoint(args); + }, + ) + .assert_ok(); + + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK); + + // user[0] and user[1] will not confirm, so they get filtered + // user[3] confirms only 1 from maximum of 2 allowed tickets - should win by migration guaranteed + lp_setup.confirm(&participants[2], 3).assert_ok(); + lp_setup.confirm(&participants[3], 1).assert_ok(); + lp_setup.confirm(&participants[4], 6).assert_ok(); + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + lp_setup.filter_tickets().assert_ok(); + + lp_setup.select_base_winners_mock(2).assert_ok(); + + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), false); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), false); + assert_eq!(sc.ticket_status(5).get(), false); + assert_eq!(sc.ticket_status(6).get(), false); + assert_eq!(sc.ticket_status(7).get(), false); + assert_eq!(sc.ticket_status(8).get(), false); + assert_eq!(sc.ticket_status(9).get(), false); + assert_eq!(sc.ticket_status(10).get(), false); + + assert_eq!( + sc.nr_winning_tickets().get(), + nr_winning_tickets + - nr_staking_guaranteed_tickets + - nr_migration_guaranteed_tickets + ); + // 1 user with 1 staking guaranteed ticket + // 1 user with 2 guaranteed tickets (1 staking + 1 migration) + // 1 user with 1 migration guaranteed ticket + assert_eq!(sc.users_with_guaranteed_ticket().len(), 3); + }) + .assert_ok(); + + // distribute by steps, to isolate each step's effect + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut op = GuaranteedTicketsSelectionOperation::default(); + + // first step + sc.select_guaranteed_tickets(&mut op); + + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); // randomly selected -> leftover_ticket + assert_eq!(sc.ticket_status(2).get(), false); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), WINNING_TICKET); // migration guaranteed ticket -> additional_winning_tickets + assert_eq!(sc.ticket_status(5).get(), WINNING_TICKET); // staking guaranteed ticket -> additional_winning_tickets + assert_eq!(sc.ticket_status(6).get(), WINNING_TICKET); // migration guaranteed ticket -> additional_winning_tickets + assert_eq!(sc.ticket_status(7).get(), false); + assert_eq!(sc.ticket_status(8).get(), false); + assert_eq!(sc.ticket_status(9).get(), false); + assert_eq!(sc.ticket_status(10).get(), false); + + assert_eq!(op.leftover_tickets, 1); + assert_eq!(op.total_additional_winning_tickets, 3); + assert_eq!(op.leftover_ticket_pos_offset, 1); + + // second step + sc.distribute_leftover_tickets(&mut op); + + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), false); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(5).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(6).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(7).get(), false); + assert_eq!(sc.ticket_status(8).get(), WINNING_TICKET); // randomly selected in distribute_leftover_tickets + assert_eq!(sc.ticket_status(9).get(), false); + assert_eq!(sc.ticket_status(10).get(), false); + + assert_eq!(op.leftover_tickets, 0); + assert_eq!(op.total_additional_winning_tickets, 4); + assert_eq!(op.leftover_ticket_pos_offset, 2); + + assert_eq!(sc.users_with_guaranteed_ticket().len(), 0); + }, + ) + .assert_ok(); + + lp_setup.distribute_tickets().assert_ok(); + + lp_setup.b_mock.set_block_nonce(CLAIM_START_BLOCK); + + // Check user balance after winning 2 of 3 tickets + lp_setup.claim_user(&participants[2]).assert_ok(); + + // 2 tickets were refunded + lp_setup + .b_mock + .check_egld_balance(&participants[2], &rust_biguint!(2 * TICKET_COST)); + + // 1 ticket was won + lp_setup.b_mock.check_esdt_balance( + &participants[2], + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(LAUNCHPAD_TOKENS_PER_TICKET), + ); +} + +#[test] +fn add_migration_guaranteed_tickets_distribution_and_claim_scenario_test() { + let nr_random_tickets = 1; + let nr_staking_guaranteed_tickets = 2; + let nr_migration_guaranteed_tickets = 2; + let nr_winning_tickets = + nr_random_tickets + nr_staking_guaranteed_tickets + nr_migration_guaranteed_tickets; + let mut lp_setup = LaunchpadSetup::new( + nr_winning_tickets, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let mut participants = lp_setup.participants.clone(); + + let new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64)); + participants.push(new_participant.clone()); + + let second_new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64 * 2)); + participants.push(second_new_participant.clone()); + + // add 2 new users with migration guaranteed tickets + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK - 1); + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push((managed_address!(&new_participant), 1, 1, true).into()); + args.push( + ( + managed_address!(&second_new_participant), + MAX_TIER_TICKETS, + MAX_TIER_TICKETS, + true, + ) + .into(), + ); + + sc.add_tickets_endpoint(args); + }, + ) + .assert_ok(); + + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK); + + // user[0] and user[1] will not confirm, so they get filtered + // user[3] confirms only 1 from maximum of 2 allowed tickets - should win by migration guaranteed + lp_setup.confirm(&participants[2], 3).assert_ok(); + lp_setup.confirm(&participants[3], 1).assert_ok(); + lp_setup.confirm(&participants[4], 6).assert_ok(); + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + lp_setup.filter_tickets().assert_ok(); + + lp_setup.select_base_winners_mock(2).assert_ok(); + + // distribute guaranteed tickets + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + sc.distribute_guaranteed_tickets_endpoint(); + } + ) + .assert_ok(); + + lp_setup.b_mock.set_block_nonce(CLAIM_START_BLOCK); + + // check EGLD balances of participants before they claim + let base_user_balance = rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64); + lp_setup.b_mock.check_egld_balance(&participants[0], &base_user_balance); + lp_setup.b_mock.check_egld_balance(&participants[1], &base_user_balance); + lp_setup.b_mock.check_egld_balance(&participants[2], &(&base_user_balance - TICKET_COST * 3)); + lp_setup.b_mock.check_egld_balance(&participants[3], &(&base_user_balance - TICKET_COST)); + lp_setup.b_mock.check_egld_balance(&participants[4], &(&base_user_balance * 2_u64 - TICKET_COST * 6)); + + // check launchpad tokens balances of participants before they claim + for p in participants.iter() { + lp_setup + .b_mock + .check_esdt_balance(p, LAUNCHPAD_TOKEN_ID, &rust_biguint!(0)); + } + + // check EGLD and launchpad token balance for the owner before users claim + lp_setup + .b_mock + .check_egld_balance(&lp_setup.owner_address, &rust_biguint!(0)); + lp_setup + .b_mock + .check_esdt_balance( + &lp_setup.owner_address, + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(0) + ); + + // 1st and 2nd participants have not confirmed anything. So they should not be able to claim anything. + + lp_setup + .claim_user(&participants[0]) + .assert_error(4, "You have no tickets"); + + lp_setup + .claim_user(&participants[1]) + .assert_error(4, "You have no tickets"); + + // 3rd participant claims. + lp_setup.claim_user(&participants[2]).assert_ok(); + + // Out of 3 confirmed tickets, 1 was won, and 2 were refunded. + lp_setup + .b_mock + .check_egld_balance(&participants[2], &rust_biguint!(2 * TICKET_COST)); + + lp_setup.b_mock.check_esdt_balance( + &participants[2], + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(LAUNCHPAD_TOKENS_PER_TICKET), + ); + + // 4th participant claims + lp_setup.claim_user(&participants[3]).assert_ok(); + + // Out of 1 confirmed ticket, 1 was won. + lp_setup + .b_mock + .check_egld_balance(&participants[3], &rust_biguint!(2 * TICKET_COST)); + + lp_setup.b_mock.check_esdt_balance( + &participants[3], + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(LAUNCHPAD_TOKENS_PER_TICKET), + ); + + //5th participant claims + lp_setup.claim_user(&participants[4]).assert_ok(); + + // Out of 6 confirmed tickets, 3 are winning, 3 are refunded. + lp_setup + .b_mock + .check_egld_balance(&participants[4], &rust_biguint!(3 * TICKET_COST)); + + lp_setup.b_mock.check_esdt_balance( + &participants[4], + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(3 * LAUNCHPAD_TOKENS_PER_TICKET), + ); + + // Owner claims. All nr_winning_tickets are sold for EGLD. No launchpad tokens refunded. + lp_setup.claim_owner().assert_ok(); + + lp_setup.b_mock.check_egld_balance( + &lp_setup.owner_address, + &rust_biguint!(TICKET_COST * nr_winning_tickets as u64), + ); + + lp_setup.b_mock.check_esdt_balance( + &lp_setup.owner_address, + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(0), + ); +} + +#[test] +fn condition_checks_test() { + let nr_random_tickets = 1; + let nr_staking_guaranteed_tickets = 1; + let nr_migration_guaranteed_tickets = 1; + let nr_winning_tickets = + nr_random_tickets + nr_staking_guaranteed_tickets + nr_migration_guaranteed_tickets; + let mut lp_setup = LaunchpadSetup::new( + nr_winning_tickets, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let mut participants = lp_setup.participants.clone(); + + let new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64)); + participants.push(new_participant.clone()); + + // Check error - add tickets for user twice + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK - 1); + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push((managed_address!(&new_participant), 1, 1, true).into()); + sc.add_tickets_endpoint(args); + }, + ) + .assert_ok(); + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push((managed_address!(&new_participant), 1, 1, true).into()); + sc.add_tickets_endpoint(args); + }, + ) + .assert_error(4, "Duplicate entry for user"); + + // Check error - add tickets after allowed period + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK + 1); // -> Confirm phase + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push((managed_address!(&new_participant), 1, 1, true).into()); + + sc.add_tickets_endpoint(args); + }, + ) + .assert_error(4, "Add tickets period has passed"); + + // Check error - update launchpad parameters after add ticket phase + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + sc.set_ticket_price( + EgldOrEsdtTokenIdentifier::egld(), + managed_biguint!(TICKET_COST), + ); + }, + ) + .assert_error(4, "Add tickets period has passed"); + + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK); + + // User 0 confirms with 0 tickets - the flow should still work + lp_setup.confirm(&participants[0], 0).assert_ok(); + + lp_setup.confirm(&participants[2], 3).assert_ok(); + lp_setup.confirm(&participants[3], 1).assert_ok(); + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + lp_setup.filter_tickets().assert_ok(); + + lp_setup + .claim_user(&participants[3]) + .assert_error(4, "Not in claim period"); + + lp_setup.select_base_winners_mock(2).assert_ok(); + + lp_setup.distribute_tickets().assert_ok(); + + // Check error - user claim twice + lp_setup.b_mock.set_block_nonce(CLAIM_START_BLOCK); + lp_setup.claim_user(&participants[3]).assert_ok(); + + lp_setup + .claim_user(&participants[3]) + .assert_error(4, "Already claimed"); + + // Check user balance after winning 2 of 3 tickets + lp_setup.claim_user(&participants[2]).assert_ok(); + + // 1 ticket was refunded + lp_setup + .b_mock + .check_egld_balance(&participants[2], &rust_biguint!(TICKET_COST)); + + // 2 tickets were won + lp_setup.b_mock.check_esdt_balance( + &participants[2], + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(2 * LAUNCHPAD_TOKENS_PER_TICKET), + ); + + // Check owner claim and balance (before and after) + lp_setup + .b_mock + .check_egld_balance(&lp_setup.owner_address, &rust_biguint!(0)); + + lp_setup.claim_owner().assert_ok(); + + lp_setup.b_mock.check_egld_balance( + &lp_setup.owner_address, + &rust_biguint!(TICKET_COST * nr_winning_tickets as u64), + ); +} + +#[test] +fn blacklist_scenario_test() { + let nr_random_tickets = 1; + let nr_staking_guaranteed_tickets = 1; + let nr_migration_guaranteed_tickets = 2; + let nr_winning_tickets = + nr_random_tickets + nr_staking_guaranteed_tickets + nr_migration_guaranteed_tickets; + let mut lp_setup = LaunchpadSetup::new( + nr_winning_tickets, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let mut participants = lp_setup.participants.clone(); + + let new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64)); + participants.push(new_participant.clone()); + + let second_new_participant_tickets = 2; + let second_new_participant_egld_balance = TICKET_COST * second_new_participant_tickets; + let second_new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(second_new_participant_egld_balance)); + participants.push(second_new_participant.clone()); + + // add 2 new users with migration guaranteed tickets + // second_new_participant will be blacklisted + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK - 1); + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push((managed_address!(&new_participant), 1, 1, true).into()); + args.push((managed_address!(&second_new_participant), 1, 1, true).into()); + + sc.add_tickets_endpoint(args); + }, + ) + .assert_ok(); + + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK); + + lp_setup.confirm(&participants[2], 3).assert_ok(); + lp_setup.confirm(&participants[3], 1).assert_ok(); + + lp_setup.b_mock.check_egld_balance( + &second_new_participant, + &rust_biguint!(second_new_participant_egld_balance), + ); + lp_setup + .confirm( + &second_new_participant, + second_new_participant_tickets as usize, + ) + .assert_ok(); + lp_setup.b_mock.check_egld_balance( + &second_new_participant, + &rust_biguint!( + second_new_participant_egld_balance - second_new_participant_tickets * TICKET_COST + ), + ); + + // Check error - unauthorized endpoint call + lp_setup + .b_mock + .execute_tx( + &new_participant, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut blacklist = MultiValueEncoded::new(); + blacklist.push(managed_address!(&participants[4])); + sc.add_users_to_blacklist_endpoint(blacklist); + }, + ) + .assert_error(4, "Permission denied"); + + // Before blacklist + let no_users_with_guaranteed_tickets = 3; + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!( + sc.nr_winning_tickets().get(), + nr_winning_tickets + - nr_staking_guaranteed_tickets + - nr_migration_guaranteed_tickets + ); + assert_eq!( + sc.total_guaranteed_tickets().get(), + nr_staking_guaranteed_tickets + nr_migration_guaranteed_tickets + ); + assert_eq!( + sc.users_with_guaranteed_ticket().len(), + no_users_with_guaranteed_tickets + ); + }) + .assert_ok(); + + // Blacklist second_new_participant + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut blacklist = MultiValueEncoded::new(); + blacklist.push(managed_address!(&second_new_participant)); + sc.add_users_to_blacklist_endpoint(blacklist); + }, + ) + .assert_ok(); + + // User gets his payment tokens back + lp_setup.b_mock.check_egld_balance( + &second_new_participant, + &rust_biguint!(second_new_participant_egld_balance), + ); + + // After blacklist + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + let blacklisted_user_guaranteed_tickets = 1; + assert_eq!( + sc.nr_winning_tickets().get(), + nr_winning_tickets + - nr_staking_guaranteed_tickets + - nr_migration_guaranteed_tickets + + blacklisted_user_guaranteed_tickets + ); + assert_eq!( + sc.total_guaranteed_tickets().get(), + nr_staking_guaranteed_tickets + nr_migration_guaranteed_tickets + - blacklisted_user_guaranteed_tickets + ); + assert_eq!( + sc.users_with_guaranteed_ticket().len(), + no_users_with_guaranteed_tickets - blacklisted_user_guaranteed_tickets + ); + }) + .assert_ok(); + + // Check error - Blacklist user tries to confirm his tickets again, while being blacklisted + lp_setup.confirm(&second_new_participant, 2).assert_error( + 4, + "You have been put into the blacklist and may not confirm tickets", + ); + + // Check error - unauthorized endpoint call + lp_setup + .b_mock + .execute_tx( + &new_participant, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut blacklist = MultiValueEncoded::new(); + blacklist.push(managed_address!(&second_new_participant)); + sc.remove_guaranteed_users_from_blacklist_endpoint(blacklist); + }, + ) + .assert_error(4, "Permission denied"); + + // Remove second_new_participant from blacklist + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut blacklist = MultiValueEncoded::new(); + blacklist.push(managed_address!(&second_new_participant)); + sc.remove_guaranteed_users_from_blacklist_endpoint(blacklist); + }, + ) + .assert_ok(); + + // User tries to confirm his tickets after he is removed from blacklist + lp_setup.confirm(&second_new_participant, 2).assert_ok(); + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + // Check error - try to blacklist user again, in the winner selection phase + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut blacklist = MultiValueEncoded::new(); + blacklist.push(managed_address!(&second_new_participant)); + sc.add_users_to_blacklist_endpoint(blacklist); + }, + ) + .assert_error(4, "May only modify blacklist before winner selection"); + + lp_setup.filter_tickets().assert_ok(); + lp_setup.select_base_winners_mock(2).assert_ok(); + + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), false); + assert_eq!(sc.ticket_status(3).get(), false); + assert_eq!(sc.ticket_status(4).get(), false); + assert_eq!(sc.ticket_status(5).get(), false); + assert_eq!(sc.ticket_status(6).get(), false); + assert_eq!(sc.ticket_status(7).get(), false); + + assert_eq!(sc.users_with_guaranteed_ticket().len(), 3); + }) + .assert_ok(); + + lp_setup.distribute_tickets().assert_ok(); + + lp_setup + .b_mock + .execute_query(&lp_setup.lp_wrapper, |sc| { + assert_eq!(sc.ticket_status(1).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(2).get(), false); + assert_eq!(sc.ticket_status(3).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(4).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(5).get(), WINNING_TICKET); + assert_eq!(sc.ticket_status(6).get(), false); + + assert_eq!(sc.users_with_guaranteed_ticket().len(), 0); + }) + .assert_ok(); + + // Check user balance after he wins only 1 ticket + lp_setup.b_mock.set_block_nonce(CLAIM_START_BLOCK); + lp_setup.claim_user(&second_new_participant).assert_ok(); + + lp_setup.b_mock.check_egld_balance( + &second_new_participant, + &rust_biguint!(second_new_participant_egld_balance - TICKET_COST), + ); + lp_setup.b_mock.check_esdt_balance( + &second_new_participant, + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(LAUNCHPAD_TOKENS_PER_TICKET), + ); +} + +#[test] +fn confirm_less_tickets_than_total_available_scenario_test() { + let nr_random_tickets = 1; + let nr_staking_guaranteed_tickets = 1; + let nr_migration_guaranteed_tickets = 1; + let nr_winning_tickets = + nr_random_tickets + nr_staking_guaranteed_tickets + nr_migration_guaranteed_tickets; + let mut lp_setup = LaunchpadSetup::new( + nr_winning_tickets, + launchpad_migration_guaranteed_tickets::contract_obj, + ); + let mut participants = lp_setup.participants.clone(); + + let new_participant = lp_setup + .b_mock + .create_user_account(&rust_biguint!(TICKET_COST * MAX_TIER_TICKETS as u64)); + participants.push(new_participant.clone()); + + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK - 1); + lp_setup + .b_mock + .execute_tx( + &lp_setup.owner_address, + &lp_setup.lp_wrapper, + &rust_biguint!(0), + |sc| { + let mut args = MultiValueEncoded::new(); + args.push((managed_address!(&new_participant), 1, 1, true).into()); + sc.add_tickets_endpoint(args); + }, + ) + .assert_ok(); + + lp_setup.b_mock.set_block_nonce(CONFIRM_START_BLOCK); + + lp_setup.confirm(&participants[3], 1).assert_ok(); + + lp_setup + .b_mock + .set_block_nonce(WINNER_SELECTION_START_BLOCK); + + lp_setup.filter_tickets().assert_ok(); + + lp_setup.select_base_winners_mock(2).assert_ok(); + + lp_setup.distribute_tickets().assert_ok(); + + lp_setup.b_mock.set_block_nonce(CLAIM_START_BLOCK); + + // Check user balance after winning 1 ticket + lp_setup.claim_user(&participants[3]).assert_ok(); + + // 1 ticket was won + lp_setup.b_mock.check_esdt_balance( + &participants[3], + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(LAUNCHPAD_TOKENS_PER_TICKET), + ); + + // Check owner claim and balance (before and after) + // only 1 ticket was confirmed and won + let actual_winning_tickets = 1; + lp_setup + .b_mock + .check_egld_balance(&lp_setup.owner_address, &rust_biguint!(0)); + + lp_setup.b_mock.check_esdt_balance( + &lp_setup.owner_address, + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(0), + ); + + lp_setup.claim_owner().assert_ok(); + + lp_setup.b_mock.check_egld_balance( + &lp_setup.owner_address, + &rust_biguint!(TICKET_COST * actual_winning_tickets as u64), + ); + + lp_setup.b_mock.check_esdt_balance( + &lp_setup.owner_address, + LAUNCHPAD_TOKEN_ID, + &rust_biguint!( + (nr_winning_tickets - actual_winning_tickets) as u64 * LAUNCHPAD_TOKENS_PER_TICKET + ), + ); + + // Check if SC funds are 0 after all tokens were claimed + lp_setup + .b_mock + .check_egld_balance(lp_setup.lp_wrapper.address_ref(), &rust_biguint!(0)); + + lp_setup.b_mock.check_esdt_balance( + lp_setup.lp_wrapper.address_ref(), + LAUNCHPAD_TOKEN_ID, + &rust_biguint!(0), + ); +} diff --git a/launchpad-migration-guaranteed-tickets/wasm/Cargo.lock b/launchpad-migration-guaranteed-tickets/wasm/Cargo.lock new file mode 100644 index 0000000..440c2ab --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/wasm/Cargo.lock @@ -0,0 +1,290 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[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 = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[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.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "launchpad-common" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + +[[package]] +name = "launchpad-migration-guaranteed-tickets" +version = "0.0.0" +dependencies = [ + "launchpad-common", + "multiversx-sc", +] + +[[package]] +name = "launchpad-migration-guaranteed-tickets-wasm" +version = "0.0.0" +dependencies = [ + "launchpad-migration-guaranteed-tickets", + "multiversx-sc-wasm-adapter", +] + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "multiversx-sc" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "842795458f7aa56ca04191993628980987baa8558357f708a93514c1b2e9948a" +dependencies = [ + "bitflags", + "hashbrown", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7638cb46a0e99c636fd55443ac534ff0a5fad0bd772e1037fbac9a75e04c3c9" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "wee_alloc", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e976002d51367f16140929c10ee695f95dd8d34c150a45db60d3fcd1328a267a" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99390a0cc0406e86993772bdf16c6be4e990117f939df94a6a6e2f89d18c4983" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2f13e0d94bd5e2d1b0c1b1f31ffe7ef223d396a4b939d46a66c3519557d0a3" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70852439508cfbbc1d92f11210f76c8c1ca2a8869fe8cbd316c2a82518c58249" +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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" + +[[package]] +name = "proc-macro2" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +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.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/launchpad-migration-guaranteed-tickets/wasm/Cargo.toml b/launchpad-migration-guaranteed-tickets/wasm/Cargo.toml new file mode 100644 index 0000000..a2555b6 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/wasm/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "launchpad-migration-guaranteed-tickets-wasm" +version = "0.0.0" +authors = ["Dorin Marian Iancu "] +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" + +[dependencies.launchpad-migration-guaranteed-tickets] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.41.1" + +[workspace] +members = ["."] diff --git a/launchpad-migration-guaranteed-tickets/wasm/src/lib.rs b/launchpad-migration-guaranteed-tickets/wasm/src/lib.rs new file mode 100644 index 0000000..1494cc0 --- /dev/null +++ b/launchpad-migration-guaranteed-tickets/wasm/src/lib.rs @@ -0,0 +1,57 @@ +// Code generated by the multiversx-sc multi-contract system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Endpoints: 33 +// Async Callback (empty): 1 +// Total number of exported functions: 35 + +#![no_std] +#![feature(lang_items)] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + launchpad_migration_guaranteed_tickets + ( + addTickets + depositLaunchpadTokens + addUsersToBlacklist + removeGuaranteedUsersFromBlacklist + distributeGuaranteedTickets + claimLaunchpadTokens + claimTicketPayment + getUserTicketsStatus + getLaunchStageFlags + getConfiguration + getLaunchpadTokenId + getLaunchpadTokensPerWinningTicket + getTicketPrice + getNumberOfWinningTickets + setTicketPrice + setLaunchpadTokensPerWinningTicket + setConfirmationPeriodStartBlock + setWinnerSelectionStartBlock + setClaimStartBlock + getTicketRangeForAddress + getTotalNumberOfTicketsForAddress + getTotalNumberOfTickets + getNumberOfConfirmedTicketsForAddress + filterTickets + selectWinners + getNumberOfWinningTicketsForAddress + getWinningTicketIdsForAddress + setSupportAddress + getSupportAddress + removeUsersFromBlacklist + isUserBlacklisted + confirmTickets + hasUserClaimedTokens + ) +} + +multiversx_sc_wasm_adapter::empty_callback! {}