diff --git a/Cargo.lock b/Cargo.lock index 23b66e533..a63fd7ef6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -411,6 +411,7 @@ name = "asset-manager" version = "0.1.0" dependencies = [ "bit-country-primitives", + "core-primitives", "frame-support", "frame-system", "hex", @@ -4346,6 +4347,19 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "insta" +version = "1.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d64600be34b2fcfc267740a243fa7744441bb4947a619ac4e5bb6507f35fbfc" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "similar", + "yaml-rust", +] + [[package]] name = "instant" version = "0.1.12" @@ -5771,6 +5785,15 @@ dependencies = [ "auction-manager", "bit-country-primitives", "core-primitives", + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-session-benchmarking", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", "currencies", "fp-evm", "fp-rpc", @@ -5790,6 +5813,7 @@ dependencies = [ "orml-currencies", "orml-nft", "orml-oracle", + "orml-rewards", "orml-tokens", "orml-traits", "pallet-auction", @@ -5822,6 +5846,7 @@ dependencies = [ "pallet-reward", "pallet-scheduler", "pallet-session", + "pallet-spp", "pallet-sudo", "pallet-timestamp", "pallet-transaction-payment", @@ -5829,6 +5854,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "parachain-info", "parity-scale-codec", "polkadot-primitives", "scale-info", @@ -6636,6 +6662,23 @@ dependencies = [ "sp-std", ] +[[package]] +name = "orml-rewards" +version = "0.4.1-dev" +source = "git+https://github.com/bit-country/open-runtime-module-library?branch=v-9.38#5861b6707c69031e8d70515b0aea6d222f5a5053" +dependencies = [ + "frame-support", + "frame-system", + "orml-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "orml-tokens" version = "0.4.1-dev" @@ -8020,6 +8063,33 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-spp" +version = "2.0.0-rc6" +dependencies = [ + "asset-manager", + "auction-manager", + "bit-country-primitives", + "core-primitives", + "currencies", + "frame-benchmarking", + "frame-support", + "frame-system", + "orml-rewards", + "orml-tokens", + "orml-traits", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-version", + "substrate-fixed", +] + [[package]] name = "pallet-staking" version = "4.0.0-dev" @@ -8277,6 +8347,35 @@ dependencies = [ "xcm-executor", ] +[[package]] +name = "pallet-xcm-interface" +version = "2.0.0-rc6" +dependencies = [ + "asset-manager", + "bit-country-primitives", + "core-primitives", + "cumulus-primitives-core", + "currencies", + "frame-benchmarking", + "frame-support", + "frame-system", + "insta", + "log", + "orml-tokens", + "orml-traits", + "pallet-balances", + "pallet-xcm", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "parachain-info" version = "0.1.0" @@ -15575,6 +15674,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yamux" version = "0.10.2" diff --git a/Cargo.toml b/Cargo.toml index 41220719b..3f959a986 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ url = "2.3.1" tracing-core = "0.1.28" impl-trait-for-tuples = "0.2.2" num_enum = { version = "0.5.3", default-features = false } -getrandom = { version = "0.2.7", features = ["js"]} +getrandom = { version = "0.2.7", features = ["js"] } blake2-rfc = { version = "0.2.18", default-features = false } hex = { version = "0.4", default-features = false } funty = { version = "=1.1.0", default-features = false } @@ -38,13 +38,13 @@ similar-asserts = { version = "1.1.0" } # General (ethereum) ethabi = { version = "18.0.0", default-features = false } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "51b8c2ce3104265e1fd5bb0fe5cdfd2e0938239c", default-features = false, features = [ "with-codec" ] } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "51b8c2ce3104265e1fd5bb0fe5cdfd2e0938239c", default-features = false, features = ["with-codec"] } # General (precompile macro) proc-macro2 = "1.0" quote = "1.0" sha3 = "0.8" -syn = { version = "1.0", features = [ "extra-traits", "fold", "full", "visit" ] } +syn = { version = "1.0", features = ["extra-traits", "fold", "full", "visit"] } # General (node only) parking_lot = "0.12.1" @@ -60,7 +60,7 @@ frame-executive = { git = 'https://github.com/paritytech/substrate', branch = 'p frame-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } frame-support = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } frame-system = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -frame-system-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false} +frame-system-benchmarking = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } frame-system-rpc-runtime-api = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } frame-try-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38", default-features = false } @@ -85,7 +85,7 @@ sc-consensus-epochs = { git = "https://github.com/paritytech/substrate", branch sc-consensus-slots = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sc-consensus-manual-seal = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } -sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38"} +sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sc-finality-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } @@ -101,22 +101,22 @@ sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "polkad # Substrate Primitive Dependencies (general) sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } sp-block-builder = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-session = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } -sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } sp-api = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } sp-core = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-consensus-aura = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-inherents = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-io = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-std = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-version = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } -sp-application-crypto = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -sp-arithmetic = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-consensus-aura = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-inherents = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-io = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-runtime = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-std = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-version = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } +sp-application-crypto = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } +sp-arithmetic = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } # Substrate Utilities -node-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38"} +node-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } try-runtime-cli = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.38" } substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } @@ -128,13 +128,13 @@ sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "polkad sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } -pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38"} +pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38" } # Substrate Pallets pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } pallet-balances = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } -pallet-collective = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false} +pallet-collective = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } pallet-democracy = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } pallet-randomness-collective-flip = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } pallet-sudo = { git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.38', default-features = false } @@ -186,38 +186,39 @@ pallet-collator-selection = { git = 'https://github.com/paritytech/cumulus', bra # Polkadot polkadot-cli = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" } polkadot-service = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" } -polkadot-parachain = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" , default-features = false } -polkadot-runtime-parachains = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" , default-features = false } -polkadot-primitives = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" , default-features = false } -xcm = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" , default-features = false } -xcm-builder = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" , default-features = false } -xcm-executor = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" , default-features = false } -pallet-xcm = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38" , default-features = false } +polkadot-parachain = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } +polkadot-runtime-parachains = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } +polkadot-primitives = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } +xcm = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } +xcm-builder = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } +xcm-executor = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } +pallet-xcm = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } polkadot-runtime-common = { git = 'https://github.com/paritytech/polkadot', branch = "release-v0.9.38", default-features = false } kusama-runtime = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.38", default-features = false } # ORML -orml-currencies = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-tokens = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-traits = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-nft = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-unknown-tokens = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-xtokens = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-xcm = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-xcm-support = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } -orml-oracle = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-currencies = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-tokens = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-traits = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-nft = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-unknown-tokens = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-xtokens = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-xcm = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-xcm-support = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-oracle = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } orml-benchmarking = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } +orml-rewards = { git = "https://github.com/bit-country/open-runtime-module-library", branch = "v-9.38", default-features = false } # EVM pallet-dynamic-fee = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } -fp-consensus = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} -fp-storage = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} -fc-cli = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} -fc-rpc = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} -fc-rpc-core = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} -fc-consensus = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} -fc-mapping-sync = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} -fc-db = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38"} +fp-consensus = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } +fp-storage = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } +fc-cli = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } +fc-rpc = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } +fc-rpc-core = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } +fc-consensus = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } +fc-mapping-sync = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } +fc-db = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38" } fp-self-contained = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38", default-features = false } fp-rpc = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38", default-features = false } fp-evm = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38", default-features = false } @@ -231,7 +232,7 @@ pallet-evm-precompile-ed25519 = { git = "https://github.com/justinphamnz/frontie pallet-evm-precompile-modexp = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38", default-features = false } pallet-evm-precompile-sha3fips = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38", default-features = false } pallet-evm-precompile-simple = { git = "https://github.com/justinphamnz/frontier", branch = "polkadot-v0.9.38", default-features = false } -libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"]} +libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"] } # ink! pallet-contracts = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.38", default-features = false } diff --git a/Makefile b/Makefile index 60b69f451..fe5d92fd9 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,11 @@ build-docker-pioneer: .PHONY: run-dev run-dev: ./target/release/metaverse-node purge-chain --dev - ./target/release/metaverse-node --dev --tmp --alice -lruntime=debug + ./target/release/metaverse-node --dev --tmp --alice --node-key 0000000000000000000000000000000000000000000000000000000000000001 -lruntime=debug + +.PHONY: run-bob-dev +run-bob-dev: + ./target/release/metaverse-node --dev --tmp --bob --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp -lruntime=debug .PHONY: run-chopsticks-pioneer run-chopsticks-pioneer: diff --git a/README.md b/README.md index 36c712e74..0b3612156 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,7 @@ -

- -

- -

- -

-
-

[Bit.Country] Metaverse.Network

+

MNET (Metaverse.Network) by BitCountry team

-## Start your own metaverse. An Ethereum-compatible Network for Metaverses & Games +## An Ethereum-compatible Blockchain Network Built using Substrate [![Substrate version](https://img.shields.io/badge/Substrate-3.0.0-brightgreen?logo=Parity%20Substrate)](https://substrate.dev/) [![Twitter URL](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Ftwitter.com%2Fbitdotcountry)](https://twitter.com/bitdotcountry) @@ -30,10 +22,7 @@ Development Note: It is still a WIP. # 1. Introduction -Metaverse Network is an EVM-enabled blockchain network for user-created metaverses and games. - -Everyone can start their own metaverse for their people with the 3D world, NFTs, play-to-earn & build communities to -earn, and takes community engagement to a new dimension on web3.0. +MNET (Metaverse.Network), featuring a seamlessly integrated enriched social layer, stands as an interesting blockchain ecosystem that extends support for both EVM (Ethereum Virtual Machine) and WASM (WebAssembly) smart contracts. This framework empowers developers to harness the network's capabilities in crafting decentralized applications (dApps) with unparalleled versatility and functionality. # 2. Build @@ -105,3 +94,8 @@ cargo run -- \ --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' \ --validator ``` + +

+ +

+ diff --git a/modules/bridge/src/lib.rs b/modules/bridge/src/lib.rs index e8c26764e..5390eda15 100644 --- a/modules/bridge/src/lib.rs +++ b/modules/bridge/src/lib.rs @@ -11,7 +11,7 @@ use sp_core::{H160, U256}; use sp_std::prelude::*; pub use pallet::*; -use primitives::{Balance, FungibleTokenId}; +use primitives::FungibleTokenId; pub type ResourceId = H160; pub type ChainId = u8; @@ -29,12 +29,12 @@ pub mod pallet { use frame_support::traits::{Currency, ExistenceRequirement, LockableCurrency, ReservableCurrency}; use frame_support::PalletId; use orml_traits::MultiCurrency; - use sp_arithmetic::traits::{CheckedMul, Saturating, Zero}; - use sp_runtime::traits::{AccountIdConversion, CheckedDiv}; - use sp_runtime::{ArithmeticError, ModuleError}; + use sp_arithmetic::traits::{Saturating, Zero}; + use sp_runtime::traits::AccountIdConversion; + use sp_runtime::ModuleError; use core_primitives::NFTTrait; - use primitives::evm::CurrencyIdType::FungibleToken; + use primitives::{Attributes, ClassId, NftMetadata, TokenId}; use super::*; @@ -300,7 +300,11 @@ pub mod pallet { Ok(()) } Err(err) => match err { - DispatchError::Module(ModuleError { index, error, message }) => { + DispatchError::Module(ModuleError { + index: _, + error: _, + message, + }) => { if message == Some("AssetInfoNotFound") { if let Ok(_mint_succeeded) = T::NFTHandler::mint_token_with_id(&to, class_id, token_id, metadata, Attributes::new()) @@ -335,7 +339,7 @@ pub mod pallet { let bridge_id = T::PalletId::get().into_account_truncating(); ensure!(BridgeFee::::contains_key(&chain_id), Error::::FeeOptionsMissing); - let (min_fee, fee_scale) = Self::bridge_fee(chain_id); + let (min_fee, _fee_scale) = Self::bridge_fee(chain_id); T::Currency::transfer(&source, &bridge_id, min_fee.into(), ExistenceRequirement::AllowDeath)?; diff --git a/modules/bridge/src/mock.rs b/modules/bridge/src/mock.rs index 1fbfa7bd9..32894d6bf 100644 --- a/modules/bridge/src/mock.rs +++ b/modules/bridge/src/mock.rs @@ -3,22 +3,18 @@ use std::collections::BTreeMap; use std::vec; -use frame_support::traits::{EqualPrivilegeOnly, Nothing}; +use frame_support::traits::Nothing; use frame_support::{construct_runtime, ord_parameter_types, pallet_prelude::Hooks, parameter_types, PalletId}; -use frame_system::{EnsureRoot, EnsureSignedBy}; +use frame_system::EnsureRoot; use orml_traits::parameter_type_with_key; use sp_core::H256; use sp_runtime::traits::AccountIdConversion; use sp_runtime::{testing::Header, traits::IdentityLookup, ModuleError, Perbill}; -use auction_manager::{Auction, AuctionInfo, AuctionItem, AuctionType, CheckAuctionItemHandler, ListingLevel}; -use core_primitives::{ - Attributes, CollectionType, MetaverseInfo, MetaverseMetadata, MetaverseTrait, NFTTrait, NftAssetData, NftClassData, - NftMetadata, TokenType, -}; +use core_primitives::{Attributes, CollectionType, NFTTrait, NftClassData, NftMetadata, TokenType}; use primitives::{ - continuum::MapTrait, estate::Estate, Amount, AuctionId, ClassId, EstateId, FungibleTokenId, GroupCollectionId, - ItemId, MapSpotId, NftOffer, TokenId, UndeployedLandBlockId, + continuum::MapTrait, Amount, ClassId, EstateId, FungibleTokenId, GroupCollectionId, MapSpotId, TokenId, + UndeployedLandBlockId, }; use crate as bridge; @@ -283,7 +279,7 @@ impl NFTTrait for MockNFTHandler { { return Ok(true); } - if (nft_value.1 == 5) { + if nft_value.1 == 5 { return Err(DispatchError::Module(ModuleError { index: 5, error: [0, 0, 0, 0], @@ -293,7 +289,7 @@ impl NFTTrait for MockNFTHandler { Ok(false) } - fn is_stackable(asset_id: (Self::ClassId, Self::TokenId)) -> Result { + fn is_stackable(_asset_id: (Self::ClassId, Self::TokenId)) -> Result { Ok(false) } @@ -306,19 +302,19 @@ impl NFTTrait for MockNFTHandler { } Ok(false) } - fn get_nft_group_collection(nft_collection: &Self::ClassId) -> Result { + fn get_nft_group_collection(_nft_collection: &Self::ClassId) -> Result { Ok(ASSET_COLLECTION_ID) } fn create_token_class( sender: &AccountId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, collection_id: GroupCollectionId, - token_type: TokenType, - collection_type: CollectionType, - royalty_fee: Perbill, - mint_limit: Option, + _token_type: TokenType, + _collection_type: CollectionType, + _royalty_fee: Perbill, + _mint_limit: Option, ) -> Result { match *sender { ALICE => { @@ -339,8 +335,8 @@ impl NFTTrait for MockNFTHandler { fn mint_token( sender: &AccountId, class_id: ClassId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -364,26 +360,26 @@ impl NFTTrait for MockNFTHandler { } } - fn transfer_nft(from: &AccountId, to: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn transfer_nft(_from: &AccountId, _to: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn check_item_on_listing(class_id: Self::ClassId, token_id: Self::TokenId) -> Result { + fn check_item_on_listing(_class_id: Self::ClassId, _token_id: Self::TokenId) -> Result { Ok(true) } - fn burn_nft(account: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn burn_nft(_account: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn is_transferable(nft: &(Self::ClassId, Self::TokenId)) -> Result { + fn is_transferable(_nft: &(Self::ClassId, Self::TokenId)) -> Result { Ok(true) } - fn get_class_fund(class_id: &Self::ClassId) -> AccountId { + fn get_class_fund(_class_id: &Self::ClassId) -> AccountId { CLASS_FUND_ID } - fn get_nft_detail(asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { + fn get_nft_detail(_asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { let new_data = NftClassData { deposit: 0, attributes: test_attributes(1), @@ -397,11 +393,11 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn set_lock_collection(class_id: Self::ClassId, is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_collection(_class_id: Self::ClassId, _is_locked: bool) -> sp_runtime::DispatchResult { todo!() } - fn set_lock_nft(token_id: (Self::ClassId, Self::TokenId), is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_nft(_token_id: (Self::ClassId, Self::TokenId), _is_locked: bool) -> sp_runtime::DispatchResult { todo!() } @@ -419,20 +415,20 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn get_total_issuance(class_id: Self::ClassId) -> Result { + fn get_total_issuance(_class_id: Self::ClassId) -> Result { Ok(10u64) } - fn get_asset_owner(asset_id: &(Self::ClassId, Self::TokenId)) -> Result { + fn get_asset_owner(_asset_id: &(Self::ClassId, Self::TokenId)) -> Result { Ok(ALICE) } fn mint_token_with_id( sender: &AccountId, class_id: Self::ClassId, - token_id: Self::TokenId, - metadata: NftMetadata, - attributes: Attributes, + _token_id: Self::TokenId, + _metadata: NftMetadata, + _attributes: Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -456,31 +452,31 @@ impl NFTTrait for MockNFTHandler { } } - fn get_free_stackable_nft_balance(who: &AccountId, asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { + fn get_free_stackable_nft_balance(_who: &AccountId, _asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { 1000 } fn reserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> DispatchResult { Ok(()) } fn unreserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } fn transfer_stackable_nft( - sender: &AccountId, - to: &AccountId, - nft: &(Self::ClassId, Self::TokenId), - amount: Balance, + _sender: &AccountId, + _to: &AccountId, + _nft: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } diff --git a/modules/bridge/src/tests.rs b/modules/bridge/src/tests.rs index c3e5f13a4..0308dcb72 100644 --- a/modules/bridge/src/tests.rs +++ b/modules/bridge/src/tests.rs @@ -1,16 +1,13 @@ #![cfg(test)] -use std::str::{from_utf8, FromStr}; +use std::str::FromStr; -use frame_support::{assert_noop, assert_ok}; +use frame_support::assert_ok; use sp_core::H160; -use mock::{Balances, BridgeModule, ExtBuilder, One, Runtime, RuntimeEvent, RuntimeOrigin, System, Tokens}; -use primitives::evm::{CurrencyIdType, EvmAddress, H160_POSITION_CURRENCY_ID_TYPE, H160_POSITION_TOKEN}; -use primitives::FungibleTokenId::FungibleToken; -use primitives::{TokenId, TokenSymbol}; +use mock::{Balances, BridgeModule, ExtBuilder, RuntimeOrigin}; -use crate::mock::{BridgeSovereignPalletId, ALICE, BOB}; +use crate::mock::{ALICE, BOB}; use super::*; diff --git a/node/src/chain_spec/metaverse.rs b/node/src/chain_spec/metaverse.rs index 64d0d0010..1c88f618a 100644 --- a/node/src/chain_spec/metaverse.rs +++ b/node/src/chain_spec/metaverse.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::str::FromStr; use hex_literal::hex; @@ -8,16 +7,13 @@ use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::crypto::UncheckedInto; use sp_core::{sr25519, Pair, Public, H160, U256}; use sp_finality_grandpa::AuthorityId as GrandpaId; -use sp_runtime::{ - traits::{IdentifyAccount, Verify}, - Perbill, -}; +use sp_runtime::traits::{IdentifyAccount, Verify}; use metaverse_runtime::{ constants::currency::*, opaque::SessionKeys, wasm_binary_unwrap, AccountId, AuraConfig, BalancesConfig, BaseFeeConfig, CollatorSelectionConfig, DemocracyConfig, EVMConfig, EstateConfig, EthereumConfig, GenesisAccount, - GenesisConfig, GrandpaConfig, MintingRange, MintingRateInfo, OracleMembershipConfig, SessionConfig, Signature, - SudoConfig, SystemConfig, + GenesisConfig, GrandpaConfig, MintingRateInfo, OracleMembershipConfig, SessionConfig, Signature, SudoConfig, + SystemConfig, }; use primitives::Balance; diff --git a/node/src/cli.rs b/node/src/cli.rs index 53d21dab7..10454a8e5 100644 --- a/node/src/cli.rs +++ b/node/src/cli.rs @@ -5,7 +5,6 @@ use cumulus_client_cli; use url::Url; use crate::chain_spec; -use crate::chain_spec::Extensions; fn validate_relay_chain_url(arg: &str) -> Result<(), String> { let url = Url::parse(arg).map_err(|e| e.to_string())?; diff --git a/node/src/command.rs b/node/src/command.rs index 41a6fc8a6..c2be223b2 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{io::Write, net::SocketAddr, sync::Arc}; +use std::{io::Write, net::SocketAddr}; use codec::Encode; use cumulus_client_cli::generate_genesis_block; @@ -23,13 +23,14 @@ use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; use log::info; use sc_cli::{ - ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, Result, Role, + ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, }; use sc_service::config::{BasePath, PrometheusConfig}; use sc_service::PartialComponents; use sp_core::hexdisplay::HexDisplay; -use sp_runtime::traits::{AccountIdConversion, Block as BlockT}; +use sp_runtime::traits::AccountIdConversion; +use sp_runtime::traits::Block as BlockT; #[cfg(feature = "with-continuum-runtime")] use continuum_runtime::RuntimeApi; @@ -41,12 +42,11 @@ use pioneer_runtime::RuntimeApi; use crate::service::{continuum_partial, ContinuumParachainRuntimeExecutor}; #[cfg(feature = "with-pioneer-runtime")] use crate::service::{pioneer_partial, ParachainRuntimeExecutor}; -use crate::service::{CONTINUUM_RUNTIME_NOT_AVAILABLE, METAVERSE_RUNTIME_NOT_AVAILABLE, PIONEER_RUNTIME_NOT_AVAILABLE}; +use crate::service::{CONTINUUM_RUNTIME_NOT_AVAILABLE, PIONEER_RUNTIME_NOT_AVAILABLE}; use crate::{ chain_spec, cli::{Cli, RelayChainCli, Subcommand}, service, - service::ExecutorDispatch, }; fn load_spec(id: &str) -> std::result::Result, String> { diff --git a/node/src/rpc/rpc_metaverse.rs b/node/src/rpc/rpc_metaverse.rs index f46faed58..b4113a02e 100644 --- a/node/src/rpc/rpc_metaverse.rs +++ b/node/src/rpc/rpc_metaverse.rs @@ -6,12 +6,12 @@ use fc_rpc::{ EthBlockDataCacheTask, OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override, SchemaV2Override, SchemaV3Override, StorageOverride, }; -use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool}; +use fc_rpc_core::types::{FeeHistoryCache, FilterPool}; use fp_storage::EthereumStorageSchema; -use jsonrpc_pubsub::manager::SubscriptionManager; + use jsonrpsee::RpcModule; use pallet_transaction_payment_rpc; -use sc_cli::SubstrateCli; + // Substrate use sc_client_api::{ backend::{AuxStore, Backend, StateBackend, StorageProvider}, @@ -23,7 +23,7 @@ use sc_transaction_pool::{ChainApi, Pool}; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; -use sp_blockchain::{Backend as BlockchainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_runtime::traits::BlakeTwo256; use substrate_frame_rpc_system::{System, SystemApiServer}; @@ -138,8 +138,8 @@ where A: ChainApi + 'static, { use fc_rpc::{ - Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub, EthPubSubApiServer, EthSigner, Net, - NetApiServer, Web3, Web3ApiServer, + Eth, EthApiServer, EthFilter, EthFilterApiServer, EthPubSub, EthPubSubApiServer, Net, NetApiServer, Web3, + Web3ApiServer, }; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use substrate_frame_rpc_system::SystemApiServer; diff --git a/node/src/service/metaverse.rs b/node/src/service/metaverse.rs index 2dacd366b..1c4c478d1 100644 --- a/node/src/service/metaverse.rs +++ b/node/src/service/metaverse.rs @@ -14,7 +14,7 @@ use fc_consensus::FrontierBlockImport; use fc_rpc::EthTask; use fc_rpc_core::types::{FeeHistoryCache, FilterPool}; use futures::StreamExt; -use sc_client_api::{BlockBackend, BlockchainEvents, ExecutorProvider}; +use sc_client_api::{BlockBackend, BlockchainEvents}; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; use sc_executor::NativeElseWasmExecutor; use sc_finality_grandpa::SharedVoterState; diff --git a/pallets/asset-manager/Cargo.toml b/pallets/asset-manager/Cargo.toml index ca6303094..61d84ad3b 100644 --- a/pallets/asset-manager/Cargo.toml +++ b/pallets/asset-manager/Cargo.toml @@ -12,12 +12,13 @@ version = '0.1.0' log = { workspace = true } serde = { workspace = true, optional = true } scale-info = { workspace = true } -codec = { package = "parity-scale-codec", version ="3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } sp-runtime = { workspace = true } sp-std = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } primitives = { package = "bit-country-primitives", path = "../../primitives/metaverse", default-features = false } +core-primitives = { path = "../../traits/core-primitives", default-features = false } xcm = { workspace = true } [dev-dependencies] @@ -42,5 +43,6 @@ std = [ "frame-support/std", "frame-system/std", "primitives/std", + "core-primitives/std", "xcm/std", ] \ No newline at end of file diff --git a/pallets/asset-manager/src/lib.rs b/pallets/asset-manager/src/lib.rs index c8c33008d..7a793cb42 100644 --- a/pallets/asset-manager/src/lib.rs +++ b/pallets/asset-manager/src/lib.rs @@ -23,7 +23,6 @@ #![allow(clippy::unused_unit)] use frame_support::{ - assert_ok, dispatch::DispatchResult, ensure, pallet_prelude::*, @@ -31,16 +30,14 @@ use frame_support::{ transactional, }; use frame_system::pallet_prelude::*; -use scale_info::prelude::format; use sp_runtime::{traits::One, ArithmeticError, FixedPointNumber, FixedU128}; -use sp_std::{boxed::Box, vec::Vec}; +use sp_std::boxed::Box; use xcm::v3::MultiLocation; use xcm::VersionedMultiLocation; +use core_primitives::CurrencyIdManagement; pub use pallet::*; -use primitives::{ - AssetIds, AssetMetadata, BuyWeightRate, CurrencyId, ForeignAssetIdMapping, FungibleTokenId, Ratio, TokenId, -}; +use primitives::{AssetIds, AssetMetadata, BuyWeightRate, ForeignAssetIdMapping, FungibleTokenId, Ratio, TokenId}; mod mock; mod tests; @@ -346,3 +343,23 @@ where None } } + +impl CurrencyIdManagement for ForeignAssetMapping { + fn check_token_exist(_token_id: FungibleTokenId) -> bool { + return true; + } + + fn convert_to_rcurrency(currency_id: FungibleTokenId) -> Result { + match currency_id { + FungibleTokenId::NativeToken(token_id) => Ok(FungibleTokenId::FungibleToken(token_id)), + _ => Err(()), + } + } + + fn convert_to_currency(currency_id: FungibleTokenId) -> Result { + match currency_id { + FungibleTokenId::FungibleToken(token_id) => Ok(FungibleTokenId::NativeToken(token_id)), + _ => Err(()), + } + } +} diff --git a/pallets/auction/src/lib.rs b/pallets/auction/src/lib.rs index 8afd48829..e338a1cf7 100644 --- a/pallets/auction/src/lib.rs +++ b/pallets/auction/src/lib.rs @@ -31,7 +31,7 @@ use frame_system::{self as system, ensure_signed}; use sp_core::sp_std::convert::TryInto; use sp_runtime::SaturatedConversion; use sp_runtime::{ - traits::{CheckedDiv, One, Saturating, Zero}, + traits::{One, Saturating, Zero}, DispatchError, DispatchResult, Perbill, }; use sp_std::vec::Vec; @@ -58,17 +58,12 @@ pub mod weights; pub struct AuctionLogicHandler; pub mod migration_v2 { - use codec::FullCodec; use codec::{Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; - use sp_runtime::{traits::AtLeast32BitUnsigned, DispatchError, RuntimeDebug}; - use sp_std::{ - cmp::{Eq, PartialEq}, - fmt::Debug, - vec::Vec, - }; + use sp_runtime::RuntimeDebug; + use sp_std::cmp::{Eq, PartialEq}; use auction_manager::{AuctionType, ListingLevel}; use primitives::{AssetId, EstateId, FungibleTokenId, MetaverseId}; @@ -104,20 +99,17 @@ pub mod migration_v2 { #[frame_support::pallet] pub mod pallet { + use frame_support::dispatch::DispatchResultWithPostInfo; use frame_support::log; use frame_support::sp_runtime::traits::CheckedSub; - use frame_support::{dispatch::DispatchResultWithPostInfo, traits::tokens::currency}; - use frame_system::ensure_root; use frame_system::pallet_prelude::OriginFor; use orml_traits::{MultiCurrency, MultiReservableCurrency}; use sp_runtime::traits::CheckedAdd; use sp_runtime::ArithmeticError; - use auction_manager::{AuctionItemV1, CheckAuctionItemHandler, ListingLevel}; + use auction_manager::{CheckAuctionItemHandler, ListingLevel}; use core_primitives::{MetaverseTrait, NFTTrait}; - use primitives::{AssetId, Balance, ClassId, FungibleTokenId, MetaverseId, TokenId}; - - use crate::migration_v2::V1ItemId; + use primitives::{Balance, ClassId, FungibleTokenId, MetaverseId, TokenId}; use super::*; @@ -1191,7 +1183,7 @@ pub mod pallet { /// Internal auction bid handler fn auction_bid_handler(from: T::AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult { - let mut auction_item: AuctionItem> = + let auction_item: AuctionItem> = Self::get_auction_item(id.clone()).ok_or(Error::::AuctionDoesNotExist)?; ensure!( auction_item.auction_type == AuctionType::Auction, @@ -1426,7 +1418,7 @@ pub mod pallet { ::Currency::unreserve(&auction_item.recipient, T::NetworkFeeReserve::get()); // Transfer balance from buy it now user to asset owner - let mut currency_transfer; + let currency_transfer; if auction_item.currency_id == FungibleTokenId::NativeToken(0) { currency_transfer = ::Currency::transfer( &from, @@ -1618,7 +1610,7 @@ pub mod pallet { } // Handle balance transfer - let mut currency_transfer; + let currency_transfer; if auction_item.currency_id == FungibleTokenId::NativeToken(0) { currency_transfer = ::Currency::transfer( &high_bidder, diff --git a/pallets/auction/src/mock.rs b/pallets/auction/src/mock.rs index e91e72bac..0352d86ce 100644 --- a/pallets/auction/src/mock.rs +++ b/pallets/auction/src/mock.rs @@ -4,14 +4,15 @@ use frame_support::traits::{EqualPrivilegeOnly, Nothing}; use frame_support::{construct_runtime, pallet_prelude::Hooks, parameter_types, PalletId}; use frame_system::EnsureRoot; use orml_traits::parameter_type_with_key; +use sp_core::crypto::AccountId32; use sp_core::H256; -use sp_runtime::traits::AccountIdConversion; -use sp_runtime::{testing::Header, traits::IdentityLookup, Perbill}; +use sp_runtime::traits::{AccountIdConversion, IdentifyAccount, Verify}; +use sp_runtime::{testing::Header, traits::IdentityLookup, MultiSignature, Perbill}; use auction_manager::{CheckAuctionItemHandler, ListingLevel}; use core_primitives::{MetaverseInfo, MetaverseMetadata, MetaverseTrait, NftAssetData, NftClassData}; use primitives::{ - continuum::MapTrait, estate::Estate, Amount, AuctionId, ClassId, EstateId, FungibleTokenId, MapSpotId, NftOffer, + continuum::MapTrait, estate::Estate, Amount, AuctionId, ClassId, EstateId, FungibleTokenId, MapSpotId, UndeployedLandBlockId, }; @@ -23,14 +24,13 @@ parameter_types! { pub const BlockHashCount: u32 = 256; } -pub type AccountId = u128; +pub type AccountId = ::AccountId; pub type Balance = u128; pub type BlockNumber = u64; pub type MetaverseId = u64; +type Signature = MultiSignature; +type AccountPublic = ::Signer; -pub const ALICE: AccountId = 1; -pub const BOB: AccountId = 2; -pub const NO_METAVERSE_OWNER: AccountId = 3; pub const CLASS_ID: u32 = 0; pub const COLLECTION_ID: u64 = 0; pub const ALICE_METAVERSE_ID: MetaverseId = 1; @@ -43,8 +43,6 @@ pub const LAND_UNIT_EXIST: (i32, i32) = (0, 0); pub const LAND_UNIT_EXIST_1: (i32, i32) = (1, 1); pub const LAND_UNIT_NOT_EXIST: (i32, i32) = (99, 99); -pub const GENERAL_METAVERSE_FUND: AccountId = 102; - pub const UNDEPLOYED_LAND_BLOCK_ID_EXIST: UndeployedLandBlockId = 4; pub const UNDEPLOYED_LAND_BLOCK_ID_NOT_EXIST: UndeployedLandBlockId = 5; @@ -93,7 +91,7 @@ impl pallet_balances::Config for Runtime { pub struct Continuumm; -impl MapTrait for Continuumm { +impl MapTrait for Continuumm { fn transfer_spot( _spot_id: MapSpotId, _from: AccountId, @@ -105,7 +103,7 @@ impl MapTrait for Continuumm { pub struct EstateHandler; -impl Estate for EstateHandler { +impl Estate for EstateHandler { fn transfer_estate(_estate_id: EstateId, _from: &AccountId, _to: &AccountId) -> Result { Ok(1) } @@ -119,9 +117,9 @@ impl Estate for EstateHandler { } fn transfer_undeployed_land_block( - who: &AccountId, - to: &AccountId, - undeployed_land_block_id: UndeployedLandBlockId, + _who: &AccountId, + _to: &AccountId, + _undeployed_land_block_id: UndeployedLandBlockId, ) -> Result { Ok(2) } @@ -143,7 +141,7 @@ impl Estate for EstateHandler { } fn check_undeployed_land_block( - owner: &AccountId, + _owner: &AccountId, undeployed_land_block_id: UndeployedLandBlockId, ) -> Result { match undeployed_land_block_id { @@ -153,7 +151,7 @@ impl Estate for EstateHandler { } } - fn get_total_land_units(estate_id: Option) -> u64 { + fn get_total_land_units(_estate_id: Option) -> u64 { 100 } @@ -161,15 +159,15 @@ impl Estate for EstateHandler { 100 } - fn check_estate_ownership(owner: AccountId, estate_id: EstateId) -> Result { + fn check_estate_ownership(_owner: AccountId, _estate_id: EstateId) -> Result { Ok(false) } - fn is_estate_leasor(leasor: AccountId, estate_id: EstateId) -> Result { + fn is_estate_leasor(_leasor: AccountId, _estate_id: EstateId) -> Result { Ok(false) } - fn is_estate_leased(estate_id: EstateId) -> Result { + fn is_estate_leased(_estate_id: EstateId) -> Result { Ok(false) } } @@ -183,8 +181,8 @@ impl AuctionHandler for Handler { new_bid: (AccountId, Balance), _last_bid: Option<(AccountId, Balance)>, ) -> OnNewBidResult { - // Test with Alice bid - if new_bid.0 == ALICE || new_bid.0 == BOB { + // Test with [1,32].into() bid + if new_bid.0 == [1; 32].into() || new_bid.0 == [2; 32].into() { OnNewBidResult { accept_bid: true, auction_end_change: Change::NoChange, @@ -243,19 +241,21 @@ parameter_types! { pub struct MetaverseInfoSource {} impl MetaverseTrait for MetaverseInfoSource { - fn create_metaverse(who: &AccountId, metadata: MetaverseMetadata) -> MetaverseId { + fn create_metaverse(_who: &AccountId, _metadata: MetaverseMetadata) -> MetaverseId { 1u64 } fn check_ownership(who: &AccountId, metaverse_id: &MetaverseId) -> bool { - match *who { - ALICE => *metaverse_id == ALICE_METAVERSE_ID, - BOB => *metaverse_id == BOB_METAVERSE_ID, - _ => false, + if who == &AccountId32::new([1; 32]) { + *metaverse_id == ALICE_METAVERSE_ID + } else if who == &AccountId32::new([2; 32]) { + *metaverse_id == BOB_METAVERSE_ID + } else { + false } } - fn get_metaverse(_metaverse_id: u64) -> Option> { + fn get_metaverse(_metaverse_id: u64) -> Option> { None } @@ -267,28 +267,28 @@ impl MetaverseTrait for MetaverseInfoSource { Ok(()) } - fn get_metaverse_land_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_land_class(_metaverse_id: MetaverseId) -> Result { Ok(15u32) } - fn get_metaverse_estate_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_estate_class(_metaverse_id: MetaverseId) -> Result { Ok(16u32) } - fn get_metaverse_marketplace_listing_fee(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_marketplace_listing_fee(_metaverse_id: MetaverseId) -> Result { Ok(Perbill::from_percent(1u32)) } - fn get_metaverse_treasury(metaverse_id: MetaverseId) -> AccountId { - GENERAL_METAVERSE_FUND + fn get_metaverse_treasury(_metaverse_id: MetaverseId) -> AccountId { + [102; 32].into() } fn get_network_treasury() -> AccountId { - GENERAL_METAVERSE_FUND + [102; 32].into() } fn check_if_metaverse_estate( - metaverse_id: primitives::MetaverseId, + _metaverse_id: primitives::MetaverseId, class_id: &ClassId, ) -> Result { if class_id == &15u32 || class_id == &16u32 { @@ -302,7 +302,7 @@ impl MetaverseTrait for MetaverseInfoSource { } fn is_metaverse_owner(who: &AccountId) -> bool { - who != &NO_METAVERSE_OWNER + who != &[3; 32].into() } } @@ -384,6 +384,8 @@ impl pallet_nft::Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = AccountPublic; } parameter_types! { @@ -442,15 +444,15 @@ impl ExtBuilder { .unwrap(); pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, 100000), (BOB, 500), (NO_METAVERSE_OWNER, 500)], + balances: vec![([1; 32].into(), 100000), ([2; 32].into(), 500), ([3; 32].into(), 500)], } .assimilate_storage(&mut t) .unwrap(); orml_tokens::GenesisConfig:: { balances: vec![ - (ALICE, FungibleTokenId::MiningResource(0), 10000), - (BOB, FungibleTokenId::MiningResource(0), 5000), + ([1; 32].into(), FungibleTokenId::MiningResource(0), 10000), + ([2; 32].into(), FungibleTokenId::MiningResource(0), 5000), ], } .assimilate_storage(&mut t) @@ -484,24 +486,24 @@ pub struct MockAuctionManager; impl Auction for MockAuctionManager { type Balance = Balance; - fn auction_info(_id: u64) -> Option> { + fn auction_info(_id: u64) -> Option> { None } - fn auction_item(id: AuctionId) -> Option> { + fn auction_item(_id: AuctionId) -> Option> { None } - fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { + fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { Ok(()) } - fn update_auction_item(id: AuctionId, item_id: ItemId) -> frame_support::dispatch::DispatchResult { + fn update_auction_item(_id: AuctionId, _item_id: ItemId) -> frame_support::dispatch::DispatchResult { Ok(()) } fn new_auction( - _recipient: u128, + _recipient: AccountId, _initial_amount: Self::Balance, _start: u64, _end: Option, @@ -513,7 +515,7 @@ impl Auction for MockAuctionManager { _auction_type: AuctionType, _item_id: ItemId, _end: Option, - _recipient: u128, + _recipient: AccountId, _initial_amount: Self::Balance, _start: u64, _listing_level: ListingLevel, @@ -526,17 +528,17 @@ impl Auction for MockAuctionManager { fn remove_auction(_id: u64, _item_id: ItemId) {} fn auction_bid_handler( - from: AccountId, - id: AuctionId, - value: Self::Balance, + _from: AccountId, + _id: AuctionId, + _value: Self::Balance, ) -> frame_support::dispatch::DispatchResult { Ok(()) } fn buy_now_handler( - from: AccountId, - auction_id: AuctionId, - value: Self::Balance, + _from: AccountId, + _auction_id: AuctionId, + _value: Self::Balance, ) -> frame_support::dispatch::DispatchResult { Ok(()) } @@ -544,8 +546,8 @@ impl Auction for MockAuctionManager { fn local_auction_bid_handler( _now: u64, _id: u64, - _new_bid: (u128, Self::Balance), - _last_bid: Option<(u128, Self::Balance)>, + _new_bid: (AccountId, Self::Balance), + _last_bid: Option<(AccountId, Self::Balance)>, _social_currency_id: FungibleTokenId, ) -> DispatchResult { Ok(()) @@ -553,7 +555,7 @@ impl Auction for MockAuctionManager { fn collect_royalty_fee( _high_bid_price: &Self::Balance, - _high_bidder: &u128, + _high_bidder: &AccountId, _asset_id: &(u32, u64), _social_currency_id: FungibleTokenId, ) -> DispatchResult { diff --git a/pallets/auction/src/tests.rs b/pallets/auction/src/tests.rs index ab4a5b657..9a0616e6d 100644 --- a/pallets/auction/src/tests.rs +++ b/pallets/auction/src/tests.rs @@ -1,16 +1,22 @@ #![cfg(test)] use frame_support::{assert_noop, assert_ok}; +use sp_core::crypto::AccountId32; use sp_std::collections::btree_map::BTreeMap; use auction_manager::ListingLevel; use core_primitives::{Attributes, CollectionType, NFTTrait, TokenType}; use mock::{RuntimeEvent, *}; -use primitives::ItemId::NFT; -use primitives::{ClassId, FungibleTokenId}; + +use primitives::FungibleTokenId; use super::*; +pub const ALICE: AccountId = AccountId32::new([1; 32]); +pub const BOB: AccountId = AccountId32::new([2; 32]); +pub const NO_METAVERSE_OWNER: AccountId = AccountId32::new([3; 32]); +pub const GENERAL_METAVERSE_FUND: AccountId = AccountId32::new([102; 32]); + fn init_test_nft(owner: RuntimeOrigin) { //Create group collection before class assert_ok!(NFTModule::::create_group( @@ -785,7 +791,7 @@ fn bid_works() { assert_eq!( AuctionModule::auctions(0), Some(AuctionInfo { - bid: Some((1, 200)), + bid: Some((ALICE, 200)), start: 1, end: Some(101), }) @@ -825,7 +831,7 @@ fn bid_anti_snipe_duration_works() { assert_eq!( AuctionModule::auctions(0), Some(AuctionInfo { - bid: Some((1, 200)), + bid: Some((ALICE, 200)), start: 1, end: Some(106), }) @@ -848,7 +854,7 @@ fn bid_anti_snipe_duration_works() { // Verify if auction finalized with new end time. assert_eq!( last_event(), - RuntimeEvent::AuctionModule(crate::Event::AuctionFinalized(0, 1, 201)) + RuntimeEvent::AuctionModule(crate::Event::AuctionFinalized(0, ALICE, 201)) ); }); } @@ -1046,7 +1052,7 @@ fn asset_transfers_after_auction() { // Verify asset transfers to alice after end of auction assert_eq!( last_event(), - RuntimeEvent::AuctionModule(crate::Event::AuctionFinalized(0, 1, 200)) + RuntimeEvent::AuctionModule(crate::Event::AuctionFinalized(0, ALICE, 200)) ); // Verify transfer of fund (minus gas) @@ -1100,7 +1106,7 @@ fn asset_transfers_after_multicurrency_auction() { // Verify asset transfers to alice after end of auction assert_eq!( last_event(), - RuntimeEvent::AuctionModule(crate::Event::AuctionFinalized(0, 1, 200)) + RuntimeEvent::AuctionModule(crate::Event::AuctionFinalized(0, ALICE, 200)) ); // Verify transfer of fund @@ -1685,7 +1691,7 @@ fn auction_bundle_should_update_new_price_according_new_bid() { assert_eq!(Balances::free_balance(ALICE), 99991); let tokens_after_bid = vec![(0, 0, 150), (0, 1, 150)]; - let item_updated_after_bid = AuctionModule::items_in_auction(ItemId::Bundle(tokens.clone())); + let _item_updated_after_bid = AuctionModule::items_in_auction(ItemId::Bundle(tokens.clone())); let auction_item = AuctionModule::get_auction_item(0).unwrap(); assert_eq!(auction_item.item_id, ItemId::Bundle(tokens_after_bid)); @@ -2106,7 +2112,7 @@ fn withdraw_offer_should_work() { fn finalize_auction_should_fail() { ExtBuilder::default().build().execute_with(|| { let owner = RuntimeOrigin::signed(BOB); - let bidder = RuntimeOrigin::signed(ALICE); + let _bidder = RuntimeOrigin::signed(ALICE); init_test_nft(owner.clone()); init_test_nft(owner.clone()); assert_ok!(AuctionModule::create_auction( @@ -2146,7 +2152,7 @@ fn finalize_auction_should_fail() { fn cancel_listing_should_work() { ExtBuilder::default().build().execute_with(|| { let owner = RuntimeOrigin::signed(BOB); - let bidder = RuntimeOrigin::signed(ALICE); + let _bidder = RuntimeOrigin::signed(ALICE); init_test_nft(owner.clone()); assert_ok!(AuctionModule::create_auction( AuctionType::Auction, @@ -2186,7 +2192,7 @@ fn cancel_listing_should_work() { fn cancel_listing_should_fail() { ExtBuilder::default().build().execute_with(|| { let owner = RuntimeOrigin::signed(BOB); - let bidder = RuntimeOrigin::signed(ALICE); + let _bidder = RuntimeOrigin::signed(ALICE); init_test_nft(owner.clone()); init_test_nft(owner.clone()); assert_ok!(AuctionModule::create_auction( diff --git a/pallets/continuum/src/lib.rs b/pallets/continuum/src/lib.rs index e73c0aca7..52649c14f 100644 --- a/pallets/continuum/src/lib.rs +++ b/pallets/continuum/src/lib.rs @@ -47,18 +47,15 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::DispatchResult, - ensure, log, + ensure, traits::ExistenceRequirement, traits::{Currency, Get, LockableCurrency, ReservableCurrency}, transactional, PalletId, }; use frame_system::{ensure_root, ensure_signed}; use scale_info::TypeInfo; -use sp_runtime::traits::CheckedAdd; -use sp_runtime::{ - traits::{AccountIdConversion, One, Zero}, - DispatchError, Perbill, RuntimeDebug, -}; + +use sp_runtime::{traits::AccountIdConversion, DispatchError, Perbill, RuntimeDebug}; use sp_std::vec; use sp_std::vec::Vec; @@ -112,7 +109,6 @@ pub struct AuctionSlot { pub mod pallet { use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; use frame_system::pallet_prelude::OriginFor; - use sp_arithmetic::traits::UniqueSaturatedInto; use core_primitives::TokenType; use primitives::{AuctionId, MapSpotId}; diff --git a/pallets/continuum/src/mock.rs b/pallets/continuum/src/mock.rs index a49353f1f..a57a3abf0 100644 --- a/pallets/continuum/src/mock.rs +++ b/pallets/continuum/src/mock.rs @@ -25,7 +25,7 @@ use sp_runtime::{testing::Header, traits::IdentityLookup, Perbill}; use auction_manager::{Auction, AuctionInfo, AuctionItem, CheckAuctionItemHandler, ListingLevel}; use core_primitives::{MetaverseInfo, MetaverseMetadata, MetaverseTrait}; -use primitives::FungibleTokenId::FungibleToken; + use primitives::{AuctionId, ClassId, FungibleTokenId}; use crate as continuum; @@ -147,11 +147,11 @@ impl Auction for MockAuctionManager { return None; } - fn update_auction(id: AuctionId, _info: AuctionInfo) -> DispatchResult { + fn update_auction(_id: AuctionId, _info: AuctionInfo) -> DispatchResult { Ok(()) } - fn update_auction_item(id: AuctionId, item_id: ItemId) -> DispatchResult { + fn update_auction_item(_id: AuctionId, _item_id: ItemId) -> DispatchResult { Ok(()) } @@ -180,11 +180,11 @@ impl Auction for MockAuctionManager { fn remove_auction(_id: u64, _item_id: ItemId) {} - fn auction_bid_handler(from: AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult { + fn auction_bid_handler(_from: AccountId, _id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } - fn buy_now_handler(from: AccountId, auction_id: AuctionId, value: Self::Balance) -> DispatchResult { + fn buy_now_handler(_from: AccountId, _auction_id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } @@ -228,7 +228,7 @@ parameter_types! { pub struct MetaverseInfoSource {} impl MetaverseTrait for MetaverseInfoSource { - fn create_metaverse(who: &AccountId, metadata: MetaverseMetadata) -> MetaverseId { + fn create_metaverse(_who: &AccountId, _metadata: MetaverseMetadata) -> MetaverseId { 1u64 } @@ -253,15 +253,15 @@ impl MetaverseTrait for MetaverseInfoSource { Ok(()) } - fn get_metaverse_land_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_land_class(_metaverse_id: MetaverseId) -> Result { Ok(15u32) } - fn get_metaverse_estate_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_estate_class(_metaverse_id: MetaverseId) -> Result { Ok(16u32) } - fn get_metaverse_marketplace_listing_fee(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_marketplace_listing_fee(_metaverse_id: MetaverseId) -> Result { Ok(Perbill::from_percent(1u32)) } @@ -278,7 +278,7 @@ impl MetaverseTrait for MetaverseInfoSource { } fn check_if_metaverse_estate( - metaverse_id: primitives::MetaverseId, + _metaverse_id: primitives::MetaverseId, class_id: &ClassId, ) -> Result { if class_id == &15u32 || class_id == &16u32 { @@ -295,7 +295,7 @@ impl MetaverseTrait for MetaverseInfoSource { } } - fn is_metaverse_owner(who: &AccountId) -> bool { + fn is_metaverse_owner(_who: &AccountId) -> bool { true } } diff --git a/pallets/continuum/src/tests.rs b/pallets/continuum/src/tests.rs index db3b7c10c..048f61345 100644 --- a/pallets/continuum/src/tests.rs +++ b/pallets/continuum/src/tests.rs @@ -21,8 +21,8 @@ use frame_support::{assert_noop, assert_ok}; use sp_runtime::traits::BadOrigin; use core_primitives::TokenType; -use mock::BlockNumber as MBlockNumber; -use mock::{RuntimeEvent, *}; + +use mock::*; use super::*; diff --git a/pallets/crowdloan/src/lib.rs b/pallets/crowdloan/src/lib.rs index ebe710e1e..ed189b346 100644 --- a/pallets/crowdloan/src/lib.rs +++ b/pallets/crowdloan/src/lib.rs @@ -18,26 +18,17 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::pallet_prelude::*; -use frame_support::traits::{Currency, ExistenceRequirement, VestingSchedule}; -use frame_support::{dispatch::DispatchResult, ensure, traits::Get, PalletId}; +use frame_support::traits::{Currency, VestingSchedule}; +use frame_support::{dispatch::DispatchResult, ensure, traits::Get}; use frame_system::pallet_prelude::*; use frame_system::{ensure_root, ensure_signed}; use pallet_vesting::{Pallet as VestingModule, VestingInfo}; -use scale_info::TypeInfo; -use sp_runtime::traits::Convert; -use sp_runtime::{ - traits::{AccountIdConversion, One, Saturating, Zero}, - DispatchError, -}; + +use sp_runtime::traits::Saturating; use sp_std::{convert::TryInto, vec::Vec}; -use auction_manager::{Auction, CheckAuctionItemHandler}; -use core_primitives::*; pub use pallet::*; -use primitives::{ - estate::Estate, Balance, EstateId, ItemId, MetaverseId, UndeployedLandBlock, UndeployedLandBlockId, - UndeployedLandBlockType, -}; + pub use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] @@ -53,11 +44,9 @@ pub mod weights; #[frame_support::pallet] pub mod pallet { - use frame_support::traits::{Currency, ExistenceRequirement, Imbalance, ReservableCurrency, VestingSchedule}; + use frame_support::traits::{Currency, ExistenceRequirement, VestingSchedule}; use pallet_vesting::VestingInfo; - use sp_runtime::traits::{CheckedAdd, CheckedSub, Convert, ConvertInto, StaticLookup, Zero}; - - use primitives::UndeployedLandBlockId; + use sp_runtime::traits::{Convert, StaticLookup}; use super::*; diff --git a/pallets/crowdloan/src/mock.rs b/pallets/crowdloan/src/mock.rs index d13741bbb..d7366fa24 100644 --- a/pallets/crowdloan/src/mock.rs +++ b/pallets/crowdloan/src/mock.rs @@ -1,14 +1,11 @@ #![cfg(test)] use frame_support::traits::WithdrawReasons; -use frame_support::{construct_runtime, ord_parameter_types, parameter_types, PalletId}; -use frame_system::EnsureSignedBy; -use sp_core::H256; -use sp_runtime::traits::{ConvertInto, Identity}; -use sp_runtime::{testing::Header, traits::IdentityLookup, DispatchError, Perbill}; +use frame_support::{construct_runtime, ord_parameter_types, parameter_types}; -use auction_manager::{Auction, AuctionInfo, AuctionType, CheckAuctionItemHandler, ListingLevel}; -use primitives::FungibleTokenId; +use sp_core::H256; +use sp_runtime::traits::ConvertInto; +use sp_runtime::{testing::Header, traits::IdentityLookup, Perbill}; use crate as crowdloan; @@ -124,29 +121,29 @@ impl VestingSchedule for VestingScheduleTrait { type Moment = (); type Currency = Balances; - fn vesting_balance(who: &AccountId) -> Option { + fn vesting_balance(_who: &AccountId) -> Option { None } fn add_vesting_schedule( - who: &AccountId, - locked: Balance, - per_block: Balance, - starting_block: Self::Moment, + _who: &AccountId, + _locked: Balance, + _per_block: Balance, + _starting_block: Self::Moment, ) -> DispatchResult { Ok(()) } fn can_add_vesting_schedule( - who: &AccountId, - locked: Balance, - per_block: Balance, - starting_block: Self::Moment, + _who: &AccountId, + _locked: Balance, + _per_block: Balance, + _starting_block: Self::Moment, ) -> DispatchResult { Ok(()) } - fn remove_vesting_schedule(who: &AccountId, schedule_index: u32) -> DispatchResult { + fn remove_vesting_schedule(_who: &AccountId, _schedule_index: u32) -> DispatchResult { Ok(()) } } diff --git a/pallets/crowdloan/src/tests.rs b/pallets/crowdloan/src/tests.rs index e64629b57..79d295b2d 100644 --- a/pallets/crowdloan/src/tests.rs +++ b/pallets/crowdloan/src/tests.rs @@ -17,7 +17,7 @@ #![cfg(test)] -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok}; use sp_runtime::traits::BadOrigin; use mock::{RuntimeEvent, *}; diff --git a/pallets/economy/src/lib.rs b/pallets/economy/src/lib.rs index be695632a..124e7997a 100644 --- a/pallets/economy/src/lib.rs +++ b/pallets/economy/src/lib.rs @@ -17,16 +17,15 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, HasCompact}; -use frame_support::traits::{LockIdentifier, WithdrawReasons}; +use codec::Encode; use frame_support::{ - ensure, log, + ensure, pallet_prelude::*, - traits::{Currency, ExistenceRequirement, LockableCurrency, ReservableCurrency}, + traits::{Currency, LockableCurrency, ReservableCurrency}, transactional, PalletId, }; use frame_system::{ensure_signed, pallet_prelude::*}; -use orml_traits::{DataFeeder, DataProvider, MultiCurrency, MultiReservableCurrency}; +use orml_traits::{DataProvider, MultiCurrency, MultiReservableCurrency}; use sp_runtime::traits::{BlockNumberProvider, CheckedAdd, CheckedMul, Saturating}; use sp_runtime::{ traits::{AccountIdConversion, One, Zero}, @@ -38,7 +37,7 @@ use core_primitives::NFTTrait; use core_primitives::*; pub use pallet::*; use primitives::{estate::Estate, EstateId}; -use primitives::{AssetId, Balance, ClassId, DomainId, FungibleTokenId, MetaverseId, NftId, PowerAmount, RoundIndex}; +use primitives::{Balance, ClassId, DomainId, FungibleTokenId, PowerAmount, RoundIndex}; pub use weights::WeightInfo; //#[cfg(feature = "runtime-benchmarks")] @@ -54,12 +53,11 @@ pub mod weights; #[frame_support::pallet] pub mod pallet { - use orml_traits::MultiCurrencyExtended; use sp_runtime::traits::{CheckedAdd, CheckedSub, Saturating}; use sp_runtime::ArithmeticError; - use primitives::staking::{Bond, RoundInfo}; - use primitives::{ClassId, GroupCollectionId, NftId}; + use primitives::staking::Bond; + use primitives::{ClassId, NftId}; use super::*; @@ -338,7 +336,7 @@ pub mod pallet { Error::::ExitQueueAlreadyScheduled ); - let mut staked_balance = StakingInfo::::get(&who); + let staked_balance = StakingInfo::::get(&who); let total = staked_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; ensure!(total >= T::MinimumStake::get(), Error::::StakeBelowMinimum); @@ -440,7 +438,7 @@ pub mod pallet { match estate { None => { - let mut staked_balance = StakingInfo::::get(&who); + let staked_balance = StakingInfo::::get(&who); ensure!(amount <= staked_balance, Error::::UnstakeAmountExceedStakedAmount); let remaining = staked_balance.checked_sub(&amount).ok_or(ArithmeticError::Underflow)?; @@ -672,7 +670,7 @@ pub mod pallet { match estate { None => { - let mut staked_balance = StakingInfo::::get(&who); + let staked_balance = StakingInfo::::get(&who); ensure!(amount <= staked_balance, Error::::UnstakeAmountExceedStakedAmount); let remaining = staked_balance.checked_sub(&amount).ok_or(ArithmeticError::Underflow)?; @@ -771,7 +769,7 @@ pub mod pallet { ensure!(!amount.is_zero(), Error::::UnstakeAmountIsZero); // Update staking info - let mut staked_reserved_balance = T::Currency::reserved_balance(&who); + let staked_reserved_balance = T::Currency::reserved_balance(&who); ensure!( amount <= staked_reserved_balance, Error::::UnstakeAmountExceedStakedAmount @@ -795,7 +793,7 @@ impl Pallet { pub fn convert_power_to_bit(power_amount: Balance, commission: Perbill) -> (Balance, Balance) { let rate = Self::get_bit_power_exchange_rate(); - let mut bit_required = power_amount + let bit_required = power_amount .checked_mul(rate) .ok_or(ArithmeticError::Overflow) .unwrap_or(Zero::zero()); diff --git a/pallets/economy/src/mock.rs b/pallets/economy/src/mock.rs index f6da3a3ca..6969f2bf4 100644 --- a/pallets/economy/src/mock.rs +++ b/pallets/economy/src/mock.rs @@ -3,10 +3,12 @@ use frame_support::traits::Nothing; use frame_support::{construct_runtime, ord_parameter_types, parameter_types, PalletId}; use frame_system::EnsureSignedBy; -use orml_traits::currency::MutationHooks; + use orml_traits::parameter_type_with_key; +use sp_core::crypto::AccountId32; use sp_core::H256; -use sp_runtime::{testing::Header, traits::IdentityLookup, Perbill}; +use sp_runtime::traits::{IdentifyAccount, Verify}; +use sp_runtime::{testing::Header, traits::IdentityLookup, MultiSignature, Perbill}; use auction_manager::*; use core_primitives::NftAssetData; @@ -18,13 +20,15 @@ use crate as economy; use super::*; -pub type AccountId = u128; +pub type AccountId = ::AccountId; pub type Balance = u128; pub type BlockNumber = u64; +type Signature = MultiSignature; +type AccountPublic = ::Signer; -pub const ALICE: AccountId = 1; -pub const BOB: AccountId = 2; -pub const FREEDY: AccountId = 3; +pub const ALICE: AccountId = AccountId32::new([1; 32]); +pub const BOB: AccountId = AccountId32::new([2; 32]); +pub const FREEDY: AccountId = AccountId32::new([3; 32]); pub const DISTRIBUTOR_COLLECTION_ID: u64 = 0; pub const DISTRIBUTOR_CLASS_ID: ClassId = 0; @@ -121,23 +125,23 @@ impl pallet_balances::Config for Runtime { pub struct EstateHandler; -impl Estate for EstateHandler { - fn transfer_estate(estate_id: EstateId, _from: &u128, _to: &u128) -> Result { +impl Estate for EstateHandler { + fn transfer_estate(estate_id: EstateId, _from: &AccountId, _to: &AccountId) -> Result { Ok(estate_id) } fn transfer_landunit( coordinate: (i32, i32), - _from: &u128, - _to: &(u128, primitives::MetaverseId), + _from: &AccountId, + _to: &(AccountId, primitives::MetaverseId), ) -> Result<(i32, i32), DispatchError> { Ok(coordinate) } fn transfer_undeployed_land_block( - who: &AccountId, - to: &AccountId, - undeployed_land_block_id: UndeployedLandBlockId, + _who: &AccountId, + _to: &AccountId, + _undeployed_land_block_id: UndeployedLandBlockId, ) -> Result { Ok(2) } @@ -156,18 +160,18 @@ impl Estate for EstateHandler { Ok(false) } - fn check_landunit(_metaverse_id: primitives::MetaverseId, coordinate: (i32, i32)) -> Result { + fn check_landunit(_metaverse_id: primitives::MetaverseId, _coordinate: (i32, i32)) -> Result { Ok(true) } fn check_undeployed_land_block( - owner: &AccountId, - undeployed_land_block_id: UndeployedLandBlockId, + _owner: &AccountId, + _undeployed_land_block_id: UndeployedLandBlockId, ) -> Result { Ok(true) } - fn get_total_land_units(estate_id: Option) -> u64 { + fn get_total_land_units(_estate_id: Option) -> u64 { 10 } @@ -175,11 +179,11 @@ impl Estate for EstateHandler { 10 } - fn is_estate_leasor(leasor: AccountId, estate_id: EstateId) -> Result { + fn is_estate_leasor(_leasor: AccountId, _estate_id: EstateId) -> Result { Ok(false) } - fn is_estate_leased(estate_id: EstateId) -> Result { + fn is_estate_leased(_estate_id: EstateId) -> Result { Ok(false) } } @@ -187,7 +191,7 @@ impl Estate for EstateHandler { pub struct MetaverseStakingHandler; impl MetaverseStakingTrait for MetaverseStakingHandler { - fn update_staking_reward(round: RoundIndex, total_reward: u128) -> sp_runtime::DispatchResult { + fn update_staking_reward(_round: RoundIndex, _total_reward: u128) -> sp_runtime::DispatchResult { Ok(()) } } @@ -213,8 +217,8 @@ impl pallet_mining::Config for Runtime { } ord_parameter_types! { - pub const One: AccountId = 1; - pub const Two: AccountId = 2; + pub const One: AccountId = AccountId32::new([1;32]); + pub const Two: AccountId = AccountId32::new([2;32]); pub const PowerAmountPerBlock: u32 = 10; } impl Config for Runtime { @@ -276,24 +280,24 @@ pub struct MockAuctionManager; impl Auction for MockAuctionManager { type Balance = Balance; - fn auction_info(_id: u64) -> Option> { + fn auction_info(_id: u64) -> Option> { None } - fn auction_item(id: AuctionId) -> Option> { + fn auction_item(_id: AuctionId) -> Option> { None } - fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { + fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { Ok(()) } - fn update_auction_item(id: AuctionId, item_id: ItemId) -> DispatchResult { + fn update_auction_item(_id: AuctionId, _item_id: ItemId) -> DispatchResult { Ok(()) } fn new_auction( - _recipient: u128, + _recipient: AccountId, _initial_amount: Self::Balance, _start: u64, _end: Option, @@ -305,7 +309,7 @@ impl Auction for MockAuctionManager { _auction_type: AuctionType, _item_id: ItemId, _end: Option, - _recipient: u128, + _recipient: AccountId, _initial_amount: Self::Balance, _start: u64, _listing_level: ListingLevel, @@ -317,19 +321,19 @@ impl Auction for MockAuctionManager { fn remove_auction(_id: u64, _item_id: ItemId) {} - fn auction_bid_handler(from: AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult { + fn auction_bid_handler(_from: AccountId, _id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } - fn buy_now_handler(from: AccountId, auction_id: AuctionId, value: Self::Balance) -> DispatchResult { + fn buy_now_handler(_from: AccountId, _auction_id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } fn local_auction_bid_handler( _now: u64, _id: u64, - _new_bid: (u128, Self::Balance), - _last_bid: Option<(u128, Self::Balance)>, + _new_bid: (AccountId, Self::Balance), + _last_bid: Option<(AccountId, Self::Balance)>, _social_currency_id: FungibleTokenId, ) -> DispatchResult { Ok(()) @@ -337,7 +341,7 @@ impl Auction for MockAuctionManager { fn collect_royalty_fee( _high_bid_price: &Self::Balance, - _high_bidder: &u128, + _high_bidder: &AccountId, _asset_id: &(u32, u64), _social_currency_id: FungibleTokenId, ) -> DispatchResult { @@ -376,6 +380,8 @@ impl pallet_nft::Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = AccountPublic; } parameter_types! { diff --git a/pallets/economy/src/tests.rs b/pallets/economy/src/tests.rs index a67f3e08b..64e848a46 100644 --- a/pallets/economy/src/tests.rs +++ b/pallets/economy/src/tests.rs @@ -17,12 +17,11 @@ #![cfg(test)] -use frame_support::{assert_err, assert_noop, assert_ok}; -use orml_nft::Tokens; +use frame_support::{assert_noop, assert_ok}; + use sp_runtime::traits::BadOrigin; use sp_std::default::Default; -use auction_manager::ListingLevel; use core_primitives::{Attributes, CollectionType, TokenType}; use mock::{RuntimeEvent, *}; use primitives::staking::Bond; @@ -30,6 +29,12 @@ use primitives::GroupCollectionId; use super::*; +type AccountIdOf = ::AccountId; + +fn account(id: u8) -> AccountIdOf { + [id; 32].into() +} + fn init_test_nft(owner: RuntimeOrigin, collection_id: GroupCollectionId, class_id: ClassId) { //Create group collection before class assert_ok!(NFTModule::create_group(RuntimeOrigin::root(), vec![1], vec![1])); @@ -66,7 +71,7 @@ fn get_mining_currency() -> FungibleTokenId { fn set_bit_power_exchange_rate_should_fail_bad_origin() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - EconomyModule::set_bit_power_exchange_rate(RuntimeOrigin::signed(BOB), EXCHANGE_RATE), + EconomyModule::set_bit_power_exchange_rate(RuntimeOrigin::signed(account(2)), EXCHANGE_RATE), BadOrigin ); }); @@ -88,7 +93,7 @@ fn set_bit_power_exchange_rate_should_work() { fn stake_should_fail_insufficient_balance() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_EXCESS_BALANCE, None), + EconomyModule::stake(RuntimeOrigin::signed(account(1)), STAKE_EXCESS_BALANCE, None), Error::::InsufficientBalanceForStaking ); }); @@ -98,10 +103,10 @@ fn stake_should_fail_insufficient_balance() { fn stake_should_fail_exit_queue_scheduled() { ExtBuilder::default().build().execute_with(|| { // Add account entry to ExitQueue - ExitQueue::::insert(ALICE, CURRENT_ROUND, STAKE_BALANCE); + ExitQueue::::insert(account(1), CURRENT_ROUND, STAKE_BALANCE); assert_noop!( - EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BELOW_MINIMUM_BALANCE, None), + EconomyModule::stake(RuntimeOrigin::signed(account(1)), STAKE_BELOW_MINIMUM_BALANCE, None), Error::::ExitQueueAlreadyScheduled ); }); @@ -111,7 +116,7 @@ fn stake_should_fail_exit_queue_scheduled() { fn stake_should_fail_below_minimum() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BELOW_MINIMUM_BALANCE, None), + EconomyModule::stake(RuntimeOrigin::signed(account(1)), STAKE_BELOW_MINIMUM_BALANCE, None), Error::::StakeBelowMinimum ); }); @@ -121,7 +126,7 @@ fn stake_should_fail_below_minimum() { fn stake_should_fail_for_non_existing_estate() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, Some(8u32.into())), + EconomyModule::stake(RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(8u32.into())), Error::::StakeEstateDoesNotExist ); }); @@ -131,7 +136,11 @@ fn stake_should_fail_for_non_existing_estate() { fn stake_should_fail_for_estate_not_owned_by_staker() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, Some(EXISTING_ESTATE_ID)), + EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + Some(EXISTING_ESTATE_ID) + ), Error::::StakerNotEstateOwner ); }); @@ -140,14 +149,14 @@ fn stake_should_fail_for_estate_not_owned_by_staker() { fn stake_should_fail_for_estate_owned_by_staker_but_having_previously_staked_bond() { ExtBuilder::default().build().execute_with(|| { let prepopulated_bond = Bond { - staker: BOB, + staker: account(2), amount: STAKE_BALANCE, }; EstateStakingInfo::::insert(&OWNED_ESTATE_ID, prepopulated_bond); assert_noop!( - EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, Some(OWNED_ESTATE_ID)), + EconomyModule::stake(RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(OWNED_ESTATE_ID)), Error::::PreviousOwnerStillStakesAtEstate ); }); @@ -156,16 +165,20 @@ fn stake_should_fail_for_estate_owned_by_staker_but_having_previously_staked_bon #[test] fn stake_should_work() { ExtBuilder::default().build().execute_with(|| { - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, None)); + assert_ok!(EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + None + )); assert_eq!( last_event(), - RuntimeEvent::Economy(crate::Event::SelfStakedToEconomy101(ALICE, STAKE_BALANCE)) + RuntimeEvent::Economy(crate::Event::SelfStakedToEconomy101(account(1), STAKE_BALANCE)) ); - assert_eq!(Balances::reserved_balance(ALICE), STAKE_BALANCE); + assert_eq!(Balances::reserved_balance(account(1)), STAKE_BALANCE); - assert_eq!(EconomyModule::get_staking_info(ALICE), STAKE_BALANCE); + assert_eq!(EconomyModule::get_staking_info(account(1)), STAKE_BALANCE); assert_eq!(EconomyModule::total_stake(), STAKE_BALANCE); }); @@ -175,7 +188,7 @@ fn stake_should_work() { fn stake_should_work_for_estate() { ExtBuilder::default().build().execute_with(|| { assert_ok!(EconomyModule::stake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(OWNED_ESTATE_ID) )); @@ -183,16 +196,16 @@ fn stake_should_work_for_estate() { assert_eq!( last_event(), RuntimeEvent::Economy(crate::Event::EstateStakedToEconomy101( - ALICE, + account(1), OWNED_ESTATE_ID, STAKE_BALANCE )) ); - assert_eq!(Balances::reserved_balance(ALICE), STAKE_BALANCE); + assert_eq!(Balances::reserved_balance(account(1)), STAKE_BALANCE); assert_eq!( EconomyModule::get_estate_staking_info(OWNED_ESTATE_ID).unwrap().staker, - ALICE + account(1) ); assert_eq!( EconomyModule::get_estate_staking_info(OWNED_ESTATE_ID).unwrap().amount, @@ -206,15 +219,19 @@ fn stake_should_work_for_estate() { #[test] fn stake_should_work_with_more_operations() { ExtBuilder::default().build().execute_with(|| { - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, None)); + assert_ok!(EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + None + )); - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), 100, None)); + assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(account(1)), 100, None)); let total_staked_balance = STAKE_BALANCE + 100u128; - assert_eq!(Balances::reserved_balance(ALICE), total_staked_balance); + assert_eq!(Balances::reserved_balance(account(1)), total_staked_balance); - assert_eq!(EconomyModule::get_staking_info(ALICE), total_staked_balance); + assert_eq!(EconomyModule::get_staking_info(account(1)), total_staked_balance); assert_eq!(EconomyModule::total_stake(), total_staked_balance); }); @@ -224,7 +241,7 @@ fn stake_should_work_with_more_operations() { fn unstake_should_fail_exceeds_staked_amount() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - EconomyModule::unstake(RuntimeOrigin::signed(ALICE), UNSTAKE_AMOUNT, None), + EconomyModule::unstake(RuntimeOrigin::signed(account(1)), UNSTAKE_AMOUNT, None), Error::::UnstakeAmountExceedStakedAmount ); }); @@ -233,10 +250,14 @@ fn unstake_should_fail_exceeds_staked_amount() { #[test] fn unstake_should_fail_unstake_zero() { ExtBuilder::default().build().execute_with(|| { - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, None)); + assert_ok!(EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + None + )); assert_noop!( - EconomyModule::unstake(RuntimeOrigin::signed(ALICE), 0u128, None), + EconomyModule::unstake(RuntimeOrigin::signed(account(1)), 0u128, None), Error::::UnstakeAmountIsZero ); }); @@ -246,7 +267,7 @@ fn unstake_should_fail_unstake_zero() { fn unstake_should_fail_for_non_existing_estate() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - EconomyModule::unstake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, Some(8u32.into())), + EconomyModule::unstake(RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(8u32.into())), Error::::StakeEstateDoesNotExist ); }); @@ -256,14 +277,14 @@ fn unstake_should_fail_for_non_existing_estate() { fn unstake_should_fail_for_estate_the_account_has_not_staked_in() { ExtBuilder::default().build().execute_with(|| { let prepopulated_bond = Bond { - staker: BOB, + staker: account(2), amount: STAKE_BALANCE, }; EstateStakingInfo::::insert(&OWNED_ESTATE_ID, prepopulated_bond); assert_noop!( - EconomyModule::unstake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, Some(OWNED_ESTATE_ID)), + EconomyModule::unstake(RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(OWNED_ESTATE_ID)), Error::::NoFundsStakedAtEstate ); }); @@ -272,26 +293,33 @@ fn unstake_should_fail_for_estate_the_account_has_not_staked_in() { #[test] fn unstake_should_work() { ExtBuilder::default().build().execute_with(|| { - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, None)); + assert_ok!(EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + None + )); assert_ok!(EconomyModule::unstake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), UNSTAKE_AMOUNT, None )); assert_eq!( last_event(), - RuntimeEvent::Economy(crate::Event::SelfStakingRemovedFromEconomy101(ALICE, UNSTAKE_AMOUNT)) + RuntimeEvent::Economy(crate::Event::SelfStakingRemovedFromEconomy101( + account(1), + UNSTAKE_AMOUNT + )) ); let total_staked_balance = STAKE_BALANCE - UNSTAKE_AMOUNT; - assert_eq!(EconomyModule::get_staking_info(ALICE), total_staked_balance); + assert_eq!(EconomyModule::get_staking_info(account(1)), total_staked_balance); assert_eq!(EconomyModule::total_stake(), total_staked_balance); let next_round: RoundIndex = CURRENT_ROUND.saturating_add(1); assert_eq!( - EconomyModule::staking_exit_queue(ALICE, next_round), + EconomyModule::staking_exit_queue(account(1), next_round), Some(UNSTAKE_AMOUNT) ); }); @@ -301,18 +329,18 @@ fn unstake_should_work() { fn unstake_should_work_for_estate() { ExtBuilder::default().build().execute_with(|| { assert_ok!(EconomyModule::stake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(OWNED_ESTATE_ID) )); assert_noop!( - EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, Some(OWNED_ESTATE_ID)), + EconomyModule::stake(RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(OWNED_ESTATE_ID)), Error::::StakeAmountExceedMaximumAmount ); assert_ok!(EconomyModule::unstake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), UNSTAKE_AMOUNT, Some(OWNED_ESTATE_ID) )); @@ -320,7 +348,7 @@ fn unstake_should_work_for_estate() { assert_eq!( last_event(), RuntimeEvent::Economy(crate::Event::EstateStakingRemovedFromEconomy101( - ALICE, + account(1), OWNED_ESTATE_ID, UNSTAKE_AMOUNT )) @@ -329,7 +357,7 @@ fn unstake_should_work_for_estate() { let total_staked_balance = STAKE_BALANCE - UNSTAKE_AMOUNT; assert_eq!( EconomyModule::get_estate_staking_info(OWNED_ESTATE_ID).unwrap().staker, - ALICE + account(1) ); assert_eq!( EconomyModule::get_estate_staking_info(OWNED_ESTATE_ID).unwrap().amount, @@ -339,7 +367,7 @@ fn unstake_should_work_for_estate() { let next_round: RoundIndex = CURRENT_ROUND.saturating_add(1); assert_eq!( - EconomyModule::estate_staking_exit_queue((ALICE, next_round, OWNED_ESTATE_ID)), + EconomyModule::estate_staking_exit_queue((account(1), next_round, OWNED_ESTATE_ID)), Some(UNSTAKE_AMOUNT) ); }); @@ -348,56 +376,67 @@ fn unstake_should_work_for_estate() { #[test] fn withdraw_unstake_should_work() { ExtBuilder::default().build().execute_with(|| { - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, None)); + assert_ok!(EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + None + )); assert_ok!(EconomyModule::unstake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), UNSTAKE_AMOUNT, None )); assert_eq!( last_event(), - RuntimeEvent::Economy(crate::Event::SelfStakingRemovedFromEconomy101(ALICE, UNSTAKE_AMOUNT)) + RuntimeEvent::Economy(crate::Event::SelfStakingRemovedFromEconomy101( + account(1), + UNSTAKE_AMOUNT + )) ); let total_staked_balance = STAKE_BALANCE - UNSTAKE_AMOUNT; - assert_eq!(EconomyModule::get_staking_info(ALICE), total_staked_balance); + assert_eq!(EconomyModule::get_staking_info(account(1)), total_staked_balance); assert_eq!(EconomyModule::total_stake(), total_staked_balance); let next_round: RoundIndex = CURRENT_ROUND.saturating_add(1); assert_eq!( - EconomyModule::staking_exit_queue(ALICE, next_round), + EconomyModule::staking_exit_queue(account(1), next_round), Some(UNSTAKE_AMOUNT) ); // Default round length is 20 blocks so moving 25 blocks will move to the next round run_to_block(25); assert_ok!(EconomyModule::withdraw_unreserved( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), next_round )); - // ALICE balance free_balance was 9000 and added 9010 after withdraw unreserved - assert_eq!(Balances::free_balance(ALICE), FREE_BALANCE); + // account(1) balance free_balance was 9000 and added 9010 after withdraw unreserved + assert_eq!(Balances::free_balance(account(1)), FREE_BALANCE); }); } #[test] fn unstake_should_work_with_single_round() { ExtBuilder::default().build().execute_with(|| { - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, None)); + assert_ok!(EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + None + )); assert_ok!(EconomyModule::unstake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), UNSTAKE_AMOUNT, None )); - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(BOB), 200, None)); + assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(account(2)), 200, None)); let alice_staked_balance = STAKE_BALANCE - UNSTAKE_AMOUNT; - assert_eq!(EconomyModule::get_staking_info(ALICE), alice_staked_balance); + assert_eq!(EconomyModule::get_staking_info(account(1)), alice_staked_balance); let total_staked_balance = alice_staked_balance + 200; assert_eq!(EconomyModule::total_stake(), total_staked_balance); @@ -407,25 +446,29 @@ fn unstake_should_work_with_single_round() { #[test] fn unstake_should_fail_with_existing_queue() { ExtBuilder::default().build().execute_with(|| { - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, None)); + assert_ok!(EconomyModule::stake( + RuntimeOrigin::signed(account(1)), + STAKE_BALANCE, + None + )); assert_ok!(EconomyModule::unstake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), UNSTAKE_AMOUNT, None )); - assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(BOB), 200, None)); + assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(account(2)), 200, None)); let alice_staked_balance = STAKE_BALANCE - UNSTAKE_AMOUNT; - assert_eq!(EconomyModule::get_staking_info(ALICE), alice_staked_balance); + assert_eq!(EconomyModule::get_staking_info(account(1)), alice_staked_balance); let total_staked_balance = alice_staked_balance + 200; assert_eq!(EconomyModule::total_stake(), total_staked_balance); assert_noop!( - EconomyModule::unstake(RuntimeOrigin::signed(ALICE), UNSTAKE_AMOUNT, None), + EconomyModule::unstake(RuntimeOrigin::signed(account(1)), UNSTAKE_AMOUNT, None), Error::::ExitQueueAlreadyScheduled ); }); @@ -434,10 +477,10 @@ fn unstake_should_fail_with_existing_queue() { #[test] fn unstake_new_estate_owner_should_fail_if_estate_does_not_exist() { ExtBuilder::default().build().execute_with(|| { - //assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(ALICE), STAKE_BALANCE, + //assert_ok!(EconomyModule::stake(RuntimeOrigin::signed(account(1)), STAKE_BALANCE, // Some(OWNED_ESTATE_ID))); assert_noop!( - EconomyModule::unstake_new_estate_owner(RuntimeOrigin::signed(ALICE), 1000u64), + EconomyModule::unstake_new_estate_owner(RuntimeOrigin::signed(account(1)), 1000u64), Error::::StakeEstateDoesNotExist ); }); @@ -447,12 +490,12 @@ fn unstake_new_estate_owner_should_fail_if_estate_does_not_exist() { fn unstake_new_estate_owner_should_fail_if_not_estate_owner() { ExtBuilder::default().build().execute_with(|| { assert_ok!(EconomyModule::stake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(OWNED_ESTATE_ID) )); assert_noop!( - EconomyModule::unstake_new_estate_owner(RuntimeOrigin::signed(BOB), OWNED_ESTATE_ID), + EconomyModule::unstake_new_estate_owner(RuntimeOrigin::signed(account(2)), OWNED_ESTATE_ID), Error::::StakerNotEstateOwner ); }); @@ -462,12 +505,12 @@ fn unstake_new_estate_owner_should_fail_if_not_estate_owner() { fn unstake_new_estate_owner_should_fail_if_no_previous_owner_has_staked_balance_left() { ExtBuilder::default().build().execute_with(|| { assert_ok!(EconomyModule::stake( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), STAKE_BALANCE, Some(OWNED_ESTATE_ID) )); assert_noop!( - EconomyModule::unstake_new_estate_owner(RuntimeOrigin::signed(ALICE), OWNED_ESTATE_ID), + EconomyModule::unstake_new_estate_owner(RuntimeOrigin::signed(account(1)), OWNED_ESTATE_ID), Error::::StakerNotPreviousOwner ); }); @@ -477,19 +520,19 @@ fn unstake_new_estate_owner_should_fail_if_no_previous_owner_has_staked_balance_ fn unstake_new_estate_owner_should_work() { ExtBuilder::default().build().execute_with(|| { let prepopulated_bond = Bond { - staker: BOB, + staker: account(2), amount: STAKE_BALANCE, }; EstateStakingInfo::::insert(&OWNED_ESTATE_ID, prepopulated_bond); assert_ok!(EconomyModule::unstake_new_estate_owner( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(account(1)), OWNED_ESTATE_ID )); assert_eq!( last_event(), RuntimeEvent::Economy(crate::Event::EstateStakingRemovedFromEconomy101( - ALICE, + account(1), OWNED_ESTATE_ID, STAKE_BALANCE )) diff --git a/pallets/estate/src/lib.rs b/pallets/estate/src/lib.rs index 3c124e779..b7a31ca30 100644 --- a/pallets/estate/src/lib.rs +++ b/pallets/estate/src/lib.rs @@ -26,11 +26,10 @@ use frame_support::{ }; use frame_system::pallet_prelude::*; use frame_system::{ensure_root, ensure_signed}; -use scale_info::TypeInfo; use sp_runtime::{ - traits::{AccountIdConversion, Convert, One, Saturating, Zero}, - ArithmeticError, DispatchError, Perbill, SaturatedConversion, + traits::{AccountIdConversion, Convert, One, Saturating}, + DispatchError, Perbill, SaturatedConversion, }; use sp_std::vec::Vec; @@ -40,7 +39,7 @@ pub use pallet::*; use primitives::estate::EstateInfo; use primitives::{ estate::{Estate, LandUnitStatus, LeaseContract, OwnerId}, - Attributes, ClassId, EstateId, FungibleTokenId, ItemId, MetaverseId, NftMetadata, TokenId, UndeployedLandBlock, + Attributes, ClassId, EstateId, ItemId, MetaverseId, NftMetadata, TokenId, UndeployedLandBlock, UndeployedLandBlockId, UndeployedLandBlockType, }; pub use rate::{MintingRateInfo, Range}; @@ -61,11 +60,11 @@ pub mod weights; #[frame_support::pallet] pub mod pallet { use frame_support::traits::{Currency, Imbalance, ReservableCurrency}; - use sp_runtime::traits::{CheckedAdd, CheckedSub, Zero}; + use sp_runtime::traits::{CheckedSub, Zero}; use primitives::estate::EstateInfo; - use primitives::staking::{Bond, RoundInfo, StakeSnapshot}; - use primitives::{Balance, RoundIndex, UndeployedLandBlockId}; + use primitives::staking::RoundInfo; + use primitives::{RoundIndex, UndeployedLandBlockId}; use crate::rate::{round_issuance_range, MintingRateInfo}; @@ -1047,7 +1046,7 @@ pub mod pallet { T::NFTTokenizationSource::burn_nft(&who, &(class_id, token_id)); *estate_owner = None; } - OwnerId::Account(ref a) => { + OwnerId::Account(ref _a) => { *estate_owner = None; } } @@ -1063,7 +1062,7 @@ pub mod pallet { AllEstatesCount::::put(new_total_estates_count); // Mint new land tokens to replace the lands in the dissolved estate - let estate_account_id: T::AccountId = + let _estate_account_id: T::AccountId = T::LandTreasury::get().into_sub_account_truncating(estate_id); let storage_fee: BalanceOf = Perbill::from_percent(100u32.saturating_mul(estate_info.land_units.len() as u32)) @@ -1207,11 +1206,12 @@ pub mod pallet { Error::::NoPermission ); let estate_info: EstateInfo = Estates::::get(estate_id).ok_or(Error::::EstateDoesNotExist)?; - let estate_account_id: T::AccountId = T::LandTreasury::get().into_sub_account_truncating(estate_id); + let _estate_account_id: T::AccountId = + T::LandTreasury::get().into_sub_account_truncating(estate_id); // Mutate estates Estates::::try_mutate_exists(&estate_id, |maybe_estate_info| { - let mut mut_estate_info = maybe_estate_info.as_mut().ok_or(Error::::EstateDoesNotExist)?; + let mut_estate_info = maybe_estate_info.as_mut().ok_or(Error::::EstateDoesNotExist)?; let storage_fee: BalanceOf = Perbill::from_percent(100u32.saturating_mul(land_units.len() as u32)) @@ -1549,7 +1549,7 @@ pub mod pallet { ); let current_block = >::block_number(); EstateLeases::::try_mutate_exists(&estate_id, |estate_lease_value| { - let mut lease = estate_lease_value.as_mut().ok_or(Error::::LeaseDoesNotExist)?; + let lease = estate_lease_value.as_mut().ok_or(Error::::LeaseDoesNotExist)?; ensure!(lease.end_block > current_block, Error::::LeaseIsExpired); @@ -1615,7 +1615,7 @@ impl Pallet { Error::::NoPermission ); - if let OwnerId::Token(owner_class_id, owner_token_id) = token_owner { + if let OwnerId::Token(owner_class_id, _owner_token_id) = token_owner { ensure!(owner_class_id != class_id, Error::::LandUnitAlreadyInEstate) } @@ -1881,11 +1881,11 @@ impl Pallet { from: &T::AccountId, to: &T::AccountId, ) -> Result { - EstateOwner::::try_mutate_exists(&estate_id, |estate_owner| -> Result { + EstateOwner::::try_mutate_exists(&estate_id, |_estate_owner| -> Result { //ensure there is record of the estate owner with estate id and account id ensure!(from != to, Error::::AlreadyOwnTheEstate); let estate_owner_value = Self::get_estate_owner(&estate_id).ok_or(Error::::NoPermission)?; - let estate_info = Estates::::get(estate_id).ok_or(Error::::EstateDoesNotExist)?; + let _estate_info = Estates::::get(estate_id).ok_or(Error::::EstateDoesNotExist)?; ensure!( !EstateLeases::::contains_key(estate_id), Error::::EstateIsAlreadyLeased @@ -2081,8 +2081,8 @@ impl Pallet { } fn verify_land_unit_in_bound(block_coordinate: &(i32, i32), land_unit_coordinates: &Vec<(i32, i32)>) -> bool { - let mut vec_axis = land_unit_coordinates.iter().map(|lu| lu.0).collect::>(); - let mut vec_yaxis = land_unit_coordinates.iter().map(|lu| lu.1).collect::>(); + let vec_axis = land_unit_coordinates.iter().map(|lu| lu.0).collect::>(); + let vec_yaxis = land_unit_coordinates.iter().map(|lu| lu.1).collect::>(); let max_axis = vec_axis.iter().max().unwrap_or(&i32::MAX); let max_yaxis = vec_yaxis.iter().max().unwrap_or(&i32::MAX); diff --git a/pallets/estate/src/mock.rs b/pallets/estate/src/mock.rs index 3856a489b..c20c8137d 100644 --- a/pallets/estate/src/mock.rs +++ b/pallets/estate/src/mock.rs @@ -14,9 +14,7 @@ use sp_std::vec::Vec; use auction_manager::{Auction, AuctionInfo, AuctionItem, AuctionType, CheckAuctionItemHandler, ListingLevel}; use core_primitives::{CollectionType, NftClassData, TokenType}; -use primitives::{ - AssetId, Attributes, AuctionId, ClassId, FungibleTokenId, GroupCollectionId, NftMetadata, TokenId, LAND_CLASS_ID, -}; +use primitives::{Attributes, AuctionId, ClassId, FungibleTokenId, GroupCollectionId, NftMetadata, TokenId}; use crate as estate; @@ -144,7 +142,7 @@ parameter_types! { pub struct MetaverseInfoSource {} impl MetaverseTrait for MetaverseInfoSource { - fn create_metaverse(who: &AccountId, metadata: MetaverseMetadata) -> MetaverseId { + fn create_metaverse(_who: &AccountId, _metadata: MetaverseMetadata) -> MetaverseId { 1u64 } @@ -168,19 +166,19 @@ impl MetaverseTrait for MetaverseInfoSource { Ok(()) } - fn get_metaverse_land_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_land_class(_metaverse_id: MetaverseId) -> Result { Ok(METAVERSE_LAND_CLASS) } - fn get_metaverse_estate_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_estate_class(_metaverse_id: MetaverseId) -> Result { Ok(METAVERSE_ESTATE_CLASS) } - fn get_metaverse_marketplace_listing_fee(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_marketplace_listing_fee(_metaverse_id: MetaverseId) -> Result { Ok(Perbill::from_percent(1u32)) } - fn get_metaverse_treasury(metaverse_id: MetaverseId) -> AccountId { + fn get_metaverse_treasury(_metaverse_id: MetaverseId) -> AccountId { GENERAL_METAVERSE_FUND } @@ -189,7 +187,7 @@ impl MetaverseTrait for MetaverseInfoSource { } fn check_if_metaverse_estate( - metaverse_id: primitives::MetaverseId, + _metaverse_id: primitives::MetaverseId, class_id: &ClassId, ) -> Result { if class_id == &METAVERSE_LAND_CLASS || class_id == &METAVERSE_ESTATE_CLASS { @@ -202,7 +200,7 @@ impl MetaverseTrait for MetaverseInfoSource { Ok(true) } - fn is_metaverse_owner(who: &AccountId) -> bool { + fn is_metaverse_owner(_who: &AccountId) -> bool { true } } @@ -216,7 +214,7 @@ impl Auction for MockAuctionManager { None } - fn auction_item(id: AuctionId) -> Option> { + fn auction_item(_id: AuctionId) -> Option> { None } @@ -224,7 +222,7 @@ impl Auction for MockAuctionManager { Ok(()) } - fn update_auction_item(id: AuctionId, item_id: ItemId) -> DispatchResult { + fn update_auction_item(_id: AuctionId, _item_id: ItemId) -> DispatchResult { Ok(()) } @@ -253,11 +251,11 @@ impl Auction for MockAuctionManager { fn remove_auction(_id: u64, _item_id: ItemId) {} - fn auction_bid_handler(from: AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult { + fn auction_bid_handler(_from: AccountId, _id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } - fn buy_now_handler(from: AccountId, auction_id: AuctionId, value: Self::Balance) -> DispatchResult { + fn buy_now_handler(_from: AccountId, _auction_id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } @@ -335,23 +333,23 @@ impl NFTTrait for MockNFTHandler { } Ok(false) } - fn get_nft_group_collection(nft_collection: &Self::ClassId) -> Result { + fn get_nft_group_collection(_nft_collection: &Self::ClassId) -> Result { Ok(ASSET_COLLECTION_ID) } - fn is_stackable(asset_id: (Self::ClassId, Self::TokenId)) -> Result { + fn is_stackable(_asset_id: (Self::ClassId, Self::TokenId)) -> Result { Ok(false) } fn create_token_class( sender: &AccountId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, collection_id: GroupCollectionId, - token_type: TokenType, - collection_type: CollectionType, - royalty_fee: Perbill, - mint_limit: Option, + _token_type: TokenType, + _collection_type: CollectionType, + _royalty_fee: Perbill, + _mint_limit: Option, ) -> Result { match *sender { ALICE => { @@ -372,8 +370,8 @@ impl NFTTrait for MockNFTHandler { fn mint_token( sender: &AccountId, class_id: ClassId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -406,26 +404,26 @@ impl NFTTrait for MockNFTHandler { } } - fn transfer_nft(from: &AccountId, to: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn transfer_nft(_from: &AccountId, _to: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn check_item_on_listing(class_id: Self::ClassId, token_id: Self::TokenId) -> Result { + fn check_item_on_listing(_class_id: Self::ClassId, _token_id: Self::TokenId) -> Result { Ok(true) } - fn burn_nft(account: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn burn_nft(_account: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn is_transferable(nft: &(Self::ClassId, Self::TokenId)) -> Result { + fn is_transferable(_nft: &(Self::ClassId, Self::TokenId)) -> Result { Ok(true) } - fn get_class_fund(class_id: &Self::ClassId) -> AccountId { + fn get_class_fund(_class_id: &Self::ClassId) -> AccountId { CLASS_FUND_ID } - fn get_nft_detail(asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { + fn get_nft_detail(_asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { let new_data = NftClassData { deposit: 0, attributes: test_attributes(1), @@ -439,11 +437,11 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn set_lock_collection(class_id: Self::ClassId, is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_collection(_class_id: Self::ClassId, _is_locked: bool) -> sp_runtime::DispatchResult { Ok(()) } - fn set_lock_nft(token_id: (Self::ClassId, Self::TokenId), is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_nft(_token_id: (Self::ClassId, Self::TokenId), _is_locked: bool) -> sp_runtime::DispatchResult { Ok(()) } @@ -461,20 +459,20 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn get_total_issuance(class_id: Self::ClassId) -> Result { + fn get_total_issuance(_class_id: Self::ClassId) -> Result { Ok(10u64) } - fn get_asset_owner(asset_id: &(Self::ClassId, Self::TokenId)) -> Result { + fn get_asset_owner(_asset_id: &(Self::ClassId, Self::TokenId)) -> Result { Ok(ALICE) } fn mint_token_with_id( sender: &AccountId, class_id: Self::ClassId, - token_id: Self::TokenId, - metadata: core_primitives::NftMetadata, - attributes: core_primitives::Attributes, + _token_id: Self::TokenId, + _metadata: core_primitives::NftMetadata, + _attributes: core_primitives::Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -507,31 +505,31 @@ impl NFTTrait for MockNFTHandler { } } - fn get_free_stackable_nft_balance(who: &AccountId, asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { + fn get_free_stackable_nft_balance(_who: &AccountId, _asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { 1000 } fn reserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> DispatchResult { Ok(()) } fn unreserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } fn transfer_stackable_nft( - sender: &AccountId, - to: &AccountId, - nft: &(Self::ClassId, Self::TokenId), - amount: Balance, + _sender: &AccountId, + _to: &AccountId, + _nft: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } diff --git a/pallets/governance/src/lib.rs b/pallets/governance/src/lib.rs index 0f748ebf7..a1dfa13bd 100644 --- a/pallets/governance/src/lib.rs +++ b/pallets/governance/src/lib.rs @@ -459,7 +459,7 @@ pub mod pallet { let mut metaverse_has_referendum_running: bool = false; for (_, referendum_info) in ReferendumInfoOf::::iter_prefix(metaverse_id) { match referendum_info { - ReferendumInfo::Ongoing(status) => { + ReferendumInfo::Ongoing(_status) => { metaverse_has_referendum_running = true; break; } @@ -514,7 +514,7 @@ pub mod pallet { metaverse_id: MetaverseId, ) -> DispatchResultWithPostInfo { ensure_root(origin)?; - let proposal_info = Self::proposals(metaverse_id, proposal).ok_or(Error::::ProposalDoesNotExist)?; + let _proposal_info = Self::proposals(metaverse_id, proposal).ok_or(Error::::ProposalDoesNotExist)?; if let Some((depositors, deposit)) = >::take(proposal) { >::remove(metaverse_id, proposal); Self::update_proposals_per_metaverse_number(metaverse_id, false); // slash depositors @@ -670,7 +670,7 @@ pub mod pallet { ReferendumInfoOf::::insert(&metaverse, &referendum, ReferendumInfo::Ongoing(status)); Self::deposit_event(Event::VoteRemoved(from, referendum)); } - Some(ReferendumInfo::Finished { end, passed, title }) => { + Some(ReferendumInfo::Finished { end, passed, title: _ }) => { let prior = &mut voting_record.prior; if let Some((lock_periods, balance)) = vote.locked_if(passed) { let mut lock_value: T::BlockNumber = @@ -893,7 +893,7 @@ impl Pallet { } /// Table the waiting public proposal with the highest backing for a vote. - fn launch_public(now: T::BlockNumber, metaverse_id: MetaverseId) -> DispatchResult { + fn launch_public(_now: T::BlockNumber, metaverse_id: MetaverseId) -> DispatchResult { let launch_block = Self::get_proposal_launch_block(metaverse_id)?; if let Some((_, proposal)) = Proposals::::iter_prefix(metaverse_id).enumerate().max_by_key( // defensive only: All current public proposals have an amount locked @@ -1059,7 +1059,7 @@ impl Pallet { } else { let preimage = >::take(&metaverse_id, &referendum_status.proposal_hash); if let Some(PreimageStatus::Available { - data, + data: _, provider, deposit, .. @@ -1075,7 +1075,7 @@ impl Pallet { /// Internal enacting of successfully passed proposal fn do_enact_proposal( - proposal_id: ProposalId, + _proposal_id: ProposalId, metaverse_id: MetaverseId, referendum_id: ReferendumId, proposal_hash: T::Hash, diff --git a/pallets/governance/src/mock.rs b/pallets/governance/src/mock.rs index 85d0294b0..6e9f212f8 100644 --- a/pallets/governance/src/mock.rs +++ b/pallets/governance/src/mock.rs @@ -136,7 +136,7 @@ impl pallet_scheduler::Config for Runtime { pub struct MetaverseInfo {} impl MetaverseTrait for MetaverseInfo { - fn create_metaverse(who: &AccountId, metadata: MetaverseMetadata) -> MetaverseId { + fn create_metaverse(_who: &AccountId, _metadata: MetaverseMetadata) -> MetaverseId { 1u64 } @@ -160,19 +160,19 @@ impl MetaverseTrait for MetaverseInfo { Ok(()) } - fn get_metaverse_land_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_land_class(_metaverse_id: MetaverseId) -> Result { Ok(15u32) } - fn get_metaverse_estate_class(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_estate_class(_metaverse_id: MetaverseId) -> Result { Ok(16u32) } - fn get_metaverse_marketplace_listing_fee(metaverse_id: MetaverseId) -> Result { + fn get_metaverse_marketplace_listing_fee(_metaverse_id: MetaverseId) -> Result { Ok(Perbill::from_percent(1u32)) } - fn get_metaverse_treasury(metaverse_id: MetaverseId) -> AccountId { + fn get_metaverse_treasury(_metaverse_id: MetaverseId) -> AccountId { GENERAL_METAVERSE_FUND } @@ -181,7 +181,7 @@ impl MetaverseTrait for MetaverseInfo { } fn check_if_metaverse_estate( - metaverse_id: primitives::MetaverseId, + _metaverse_id: primitives::MetaverseId, class_id: &ClassId, ) -> Result { if class_id == &15u32 || class_id == &16u32 { @@ -194,7 +194,7 @@ impl MetaverseTrait for MetaverseInfo { Ok(true) } - fn is_metaverse_owner(who: &AccountId) -> bool { + fn is_metaverse_owner(_who: &AccountId) -> bool { true } } @@ -213,7 +213,7 @@ impl MetaverseLandTrait for MetaverseLandInfo { _ => false, } } - fn check_landunit(metaverse_id: MetaverseId, coordinate: (i32, i32)) -> Result { + fn check_landunit(_metaverse_id: MetaverseId, _coordinate: (i32, i32)) -> Result { Ok(false) } } @@ -258,7 +258,7 @@ impl NFTTrait for MockNFTHandler { Ok(false) } - fn is_stackable(asset_id: (Self::ClassId, Self::TokenId)) -> Result { + fn is_stackable(_asset_id: (Self::ClassId, Self::TokenId)) -> Result { Ok(false) } @@ -271,19 +271,19 @@ impl NFTTrait for MockNFTHandler { } Ok(false) } - fn get_nft_group_collection(nft_collection: &Self::ClassId) -> Result { + fn get_nft_group_collection(_nft_collection: &Self::ClassId) -> Result { Ok(ASSET_COLLECTION_ID) } fn create_token_class( sender: &AccountId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, collection_id: GroupCollectionId, - token_type: TokenType, - collection_type: CollectionType, - royalty_fee: Perbill, - mint_limit: Option, + _token_type: TokenType, + _collection_type: CollectionType, + _royalty_fee: Perbill, + _mint_limit: Option, ) -> Result { match *sender { ALICE => { @@ -304,8 +304,8 @@ impl NFTTrait for MockNFTHandler { fn mint_token( sender: &AccountId, class_id: ClassId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -329,26 +329,26 @@ impl NFTTrait for MockNFTHandler { } } - fn transfer_nft(from: &AccountId, to: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn transfer_nft(_from: &AccountId, _to: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn check_item_on_listing(class_id: Self::ClassId, token_id: Self::TokenId) -> Result { + fn check_item_on_listing(_class_id: Self::ClassId, _token_id: Self::TokenId) -> Result { Ok(true) } - fn burn_nft(account: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn burn_nft(_account: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn is_transferable(nft: &(Self::ClassId, Self::TokenId)) -> Result { + fn is_transferable(_nft: &(Self::ClassId, Self::TokenId)) -> Result { Ok(true) } - fn get_class_fund(class_id: &Self::ClassId) -> AccountId { + fn get_class_fund(_class_id: &Self::ClassId) -> AccountId { CLASS_FUND_ID } - fn get_nft_detail(asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { + fn get_nft_detail(_asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { let new_data = NftClassData { deposit: 0, attributes: test_attributes(1), @@ -362,11 +362,11 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn set_lock_collection(class_id: Self::ClassId, is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_collection(_class_id: Self::ClassId, _is_locked: bool) -> sp_runtime::DispatchResult { todo!() } - fn set_lock_nft(token_id: (Self::ClassId, Self::TokenId), is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_nft(_token_id: (Self::ClassId, Self::TokenId), _is_locked: bool) -> sp_runtime::DispatchResult { todo!() } @@ -384,20 +384,20 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn get_total_issuance(class_id: Self::ClassId) -> Result { + fn get_total_issuance(_class_id: Self::ClassId) -> Result { Ok(10u64) } - fn get_asset_owner(asset_id: &(Self::ClassId, Self::TokenId)) -> Result { + fn get_asset_owner(_asset_id: &(Self::ClassId, Self::TokenId)) -> Result { Ok(ALICE) } fn mint_token_with_id( sender: &AccountId, class_id: Self::ClassId, - token_id: Self::TokenId, - metadata: NftMetadata, - attributes: Attributes, + _token_id: Self::TokenId, + _metadata: NftMetadata, + _attributes: Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -420,31 +420,31 @@ impl NFTTrait for MockNFTHandler { } } } - fn get_free_stackable_nft_balance(who: &AccountId, asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { + fn get_free_stackable_nft_balance(_who: &AccountId, _asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { 1000 } fn reserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> DispatchResult { Ok(()) } fn unreserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } fn transfer_stackable_nft( - sender: &AccountId, - to: &AccountId, - nft: &(Self::ClassId, Self::TokenId), - amount: Balance, + _sender: &AccountId, + _to: &AccountId, + _nft: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } diff --git a/pallets/governance/src/tests.rs b/pallets/governance/src/tests.rs index 6433a6905..886638493 100644 --- a/pallets/governance/src/tests.rs +++ b/pallets/governance/src/tests.rs @@ -382,7 +382,7 @@ fn vote_work() { #[test] fn vote_when_not_country_member_does_not_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(BOB); + let _origin = RuntimeOrigin::signed(BOB); let hash = set_freeze_metaverse_proposal_hash(1); add_freeze_metaverse_preimage_alice(hash); assert_ok!(GovernanceModule::propose( diff --git a/pallets/metaverse/src/lib.rs b/pallets/metaverse/src/lib.rs index 68bca1bce..a0621c741 100644 --- a/pallets/metaverse/src/lib.rs +++ b/pallets/metaverse/src/lib.rs @@ -80,7 +80,7 @@ pub struct MetaverseStakingPoints { #[frame_support::pallet] pub mod pallet { use orml_traits::MultiCurrencyExtended; - use sp_runtime::traits::{CheckedAdd, Saturating}; + use sp_runtime::ArithmeticError; use primitives::staking::RoundInfo; @@ -545,7 +545,7 @@ impl Pallet { } /// Minting of a land class for the metaverse - fn mint_metaverse_land_class(sender: &T::AccountId, metaverse_id: MetaverseId) -> Result { + fn mint_metaverse_land_class(_sender: &T::AccountId, metaverse_id: MetaverseId) -> Result { // Pre-mint class for lands let mut land_class_attributes = Attributes::new(); land_class_attributes.insert("MetaverseId:".as_bytes().to_vec(), "MetaverseId:".as_bytes().to_vec()); @@ -565,7 +565,10 @@ impl Pallet { } /// Minting of an estate class for the metaverse - fn mint_metaverse_estate_class(sender: &T::AccountId, metaverse_id: MetaverseId) -> Result { + fn mint_metaverse_estate_class( + _sender: &T::AccountId, + metaverse_id: MetaverseId, + ) -> Result { // Pre-mint class for estates let mut estate_class_attributes = Attributes::new(); estate_class_attributes.insert("MetaverseId:".as_bytes().to_vec(), metaverse_id.to_be_bytes().to_vec()); @@ -611,7 +614,7 @@ impl Pallet { let default_land_class_id = TryInto::::try_into(0u32).unwrap_or_default(); let default_estate_class_id = TryInto::::try_into(1u32).unwrap_or_default(); - Metaverses::::translate(|k, metaverse_info_v1: MetaverseInfoV1| { + Metaverses::::translate(|_k, metaverse_info_v1: MetaverseInfoV1| { upgraded_metaverse_items += 1; let v2: MetaverseInfo = MetaverseInfo { diff --git a/pallets/metaverse/src/mock.rs b/pallets/metaverse/src/mock.rs index 5b12d9bf5..a238459de 100644 --- a/pallets/metaverse/src/mock.rs +++ b/pallets/metaverse/src/mock.rs @@ -7,7 +7,6 @@ use orml_traits::parameter_type_with_key; use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, Perbill}; -use primitives::staking::RoundInfo; use primitives::{Amount, ClassId, GroupCollectionId, TokenId}; use crate as metaverse; @@ -128,22 +127,22 @@ impl NFTTrait for MockNFTHandler { } Ok(false) } - fn get_nft_group_collection(nft_collection: &Self::ClassId) -> Result { + fn get_nft_group_collection(_nft_collection: &Self::ClassId) -> Result { Ok(ASSET_COLLECTION_ID) } - fn is_stackable(asset_id: (Self::ClassId, Self::TokenId)) -> Result { + fn is_stackable(_asset_id: (Self::ClassId, Self::TokenId)) -> Result { Ok(false) } fn create_token_class( sender: &AccountId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, collection_id: GroupCollectionId, - token_type: TokenType, - collection_type: CollectionType, - royalty_fee: Perbill, - mint_limit: Option, + _token_type: TokenType, + _collection_type: CollectionType, + _royalty_fee: Perbill, + _mint_limit: Option, ) -> Result { match *sender { ALICE => Ok(100), @@ -164,8 +163,8 @@ impl NFTTrait for MockNFTHandler { fn mint_token( sender: &AccountId, class_id: ClassId, - metadata: NftMetadata, - attributes: Attributes, + _metadata: NftMetadata, + _attributes: Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -189,26 +188,26 @@ impl NFTTrait for MockNFTHandler { } } - fn transfer_nft(from: &AccountId, to: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn transfer_nft(_from: &AccountId, _to: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn check_item_on_listing(class_id: Self::ClassId, token_id: Self::TokenId) -> Result { + fn check_item_on_listing(_class_id: Self::ClassId, _token_id: Self::TokenId) -> Result { Ok(true) } - fn burn_nft(account: &AccountId, nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { + fn burn_nft(_account: &AccountId, _nft: &(Self::ClassId, Self::TokenId)) -> DispatchResult { Ok(()) } - fn is_transferable(nft: &(Self::ClassId, Self::TokenId)) -> Result { + fn is_transferable(_nft: &(Self::ClassId, Self::TokenId)) -> Result { Ok(true) } - fn get_class_fund(class_id: &Self::ClassId) -> AccountId { + fn get_class_fund(_class_id: &Self::ClassId) -> AccountId { CLASS_FUND_ID } - fn get_nft_detail(asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { + fn get_nft_detail(_asset_id: (Self::ClassId, Self::TokenId)) -> Result, DispatchError> { let new_data = NftClassData { deposit: 0, attributes: test_attributes(1), @@ -222,11 +221,11 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn set_lock_collection(class_id: Self::ClassId, is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_collection(_class_id: Self::ClassId, _is_locked: bool) -> sp_runtime::DispatchResult { todo!() } - fn set_lock_nft(token_id: (Self::ClassId, Self::TokenId), is_locked: bool) -> sp_runtime::DispatchResult { + fn set_lock_nft(_token_id: (Self::ClassId, Self::TokenId), _is_locked: bool) -> sp_runtime::DispatchResult { todo!() } @@ -244,20 +243,20 @@ impl NFTTrait for MockNFTHandler { Ok(new_data) } - fn get_total_issuance(class_id: Self::ClassId) -> Result { + fn get_total_issuance(_class_id: Self::ClassId) -> Result { Ok(10u64) } - fn get_asset_owner(asset_id: &(Self::ClassId, Self::TokenId)) -> Result { + fn get_asset_owner(_asset_id: &(Self::ClassId, Self::TokenId)) -> Result { Ok(ALICE) } fn mint_token_with_id( sender: &AccountId, class_id: Self::ClassId, - token_id: Self::TokenId, - metadata: NftMetadata, - attributes: Attributes, + _token_id: Self::TokenId, + _metadata: NftMetadata, + _attributes: Attributes, ) -> Result { match *sender { ALICE => Ok(1), @@ -281,31 +280,31 @@ impl NFTTrait for MockNFTHandler { } } - fn get_free_stackable_nft_balance(who: &AccountId, asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { + fn get_free_stackable_nft_balance(_who: &AccountId, _asset_id: &(Self::ClassId, Self::TokenId)) -> Balance { 1000 } fn reserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> DispatchResult { Ok(()) } fn unreserve_stackable_nft_balance( - who: &AccountId, - asset_id: &(Self::ClassId, Self::TokenId), - amount: Balance, + _who: &AccountId, + _asset_id: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } fn transfer_stackable_nft( - sender: &AccountId, - to: &AccountId, - nft: &(Self::ClassId, Self::TokenId), - amount: Balance, + _sender: &AccountId, + _to: &AccountId, + _nft: &(Self::ClassId, Self::TokenId), + _amount: Balance, ) -> sp_runtime::DispatchResult { Ok(()) } diff --git a/pallets/metaverse/src/tests.rs b/pallets/metaverse/src/tests.rs index 39ba4822c..f75e1203d 100644 --- a/pallets/metaverse/src/tests.rs +++ b/pallets/metaverse/src/tests.rs @@ -17,12 +17,11 @@ #![cfg(test)] -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_noop, assert_ok}; use sp_runtime::traits::BadOrigin; use sp_runtime::Perbill; use mock::{RuntimeEvent, *}; -use primitives::staking::RoundInfo; #[cfg(test)] use super::*; diff --git a/pallets/mining/src/lib.rs b/pallets/mining/src/lib.rs index 1d1b34f55..bdb6ce7f4 100644 --- a/pallets/mining/src/lib.rs +++ b/pallets/mining/src/lib.rs @@ -19,34 +19,28 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; -use frame_support::traits::{Currency, Get, WithdrawReasons}; +use frame_support::traits::{Currency, Get}; use frame_support::PalletId; use frame_support::{ dispatch::{DispatchResult, DispatchResultWithPostInfo}, ensure, pallet_prelude::*, traits::ExistenceRequirement, - transactional, Parameter, }; use frame_system::pallet_prelude::*; use frame_system::{self as system, ensure_signed}; -use orml_traits::{ - arithmetic::{Signed, SimpleArithmetic}, - BalanceStatus, BasicCurrency, BasicCurrencyExtended, BasicLockableCurrency, BasicReservableCurrency, - LockIdentifier, MultiCurrency, MultiCurrencyExtended, MultiLockableCurrency, MultiReservableCurrency, -}; +use orml_traits::{BasicCurrency, LockIdentifier, MultiCurrency, MultiCurrencyExtended}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{AccountIdConversion, AtLeast32Bit, One, StaticLookup, Zero}, - DispatchError, Perbill, + traits::{AccountIdConversion, Zero}, + DispatchError, }; use sp_std::vec::Vec; -use auction_manager::SwapManager; use core_primitives::*; pub use pallet::*; use primitives::staking::RoundInfo; -use primitives::{Balance, CurrencyId, FungibleTokenId, MetaverseId}; +use primitives::{Balance, FungibleTokenId}; pub use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] @@ -80,16 +74,15 @@ pub mod weights; #[frame_support::pallet] pub mod pallet { - use frame_support::sp_runtime::traits::Saturating; - use frame_support::sp_runtime::{FixedPointNumber, SaturatedConversion}; - use frame_support::traits::OnUnbalanced; - use pallet_balances::NegativeImbalance; + + use frame_support::sp_runtime::SaturatedConversion; + use sp_runtime::Perbill; use sp_std::convert::TryInto; use primitives::estate::Estate; use primitives::staking::{MetaverseStakingTrait, RoundInfo}; - use primitives::{FungibleTokenId, RoundIndex, TokenId, VestingSchedule}; + use primitives::{FungibleTokenId, RoundIndex, VestingSchedule}; use crate::mining::round_issuance_range; diff --git a/pallets/mining/src/mining.rs b/pallets/mining/src/mining.rs index 750e698bf..a35a4a0ff 100644 --- a/pallets/mining/src/mining.rs +++ b/pallets/mining/src/mining.rs @@ -15,17 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use codec::{Decode, Encode}; -use orml_traits::arithmetic::{CheckedDiv, CheckedMul}; use orml_traits::MultiCurrency; -use scale_info::TypeInfo; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; -use sp_runtime::traits::{Saturating, Zero}; -use sp_runtime::{ArithmeticError, Perbill, RuntimeDebug}; + +use sp_runtime::Perbill; use core_primitives::{MiningRange, MiningResourceRateInfo}; -use primitives::{estate::Estate, Balance, FungibleTokenId}; +use primitives::{Balance, FungibleTokenId}; // Helper methods to compute the issuance rate for undeployed land. use crate::pallet::{Config, Pallet}; diff --git a/pallets/mining/src/mock.rs b/pallets/mining/src/mock.rs index cac0f11ba..007245e98 100644 --- a/pallets/mining/src/mock.rs +++ b/pallets/mining/src/mock.rs @@ -1,8 +1,8 @@ -use frame_support::pallet_prelude::{GenesisBuild, Hooks, MaybeSerializeDeserialize}; -use frame_support::sp_runtime::traits::AtLeast32Bit; +use frame_support::pallet_prelude::GenesisBuild; + use frame_support::traits::Nothing; -use frame_support::{construct_runtime, ord_parameter_types, parameter_types, traits::EnsureOrigin, weights::Weight}; -use frame_system::{EnsureRoot, EnsureSignedBy}; +use frame_support::{construct_runtime, ord_parameter_types, parameter_types}; +use frame_system::EnsureSignedBy; use orml_traits::parameter_type_with_key; use sp_core::H256; use sp_runtime::{ @@ -13,11 +13,11 @@ use sp_runtime::{ use primitives::estate::Estate; use primitives::staking::MetaverseStakingTrait; -use primitives::FungibleTokenId::FungibleToken; + use primitives::{Amount, CurrencyId, EstateId, FungibleTokenId, RoundIndex, UndeployedLandBlockId}; use crate as mining; -use crate::{Config, Module}; +use crate::Config; use super::*; @@ -137,22 +137,22 @@ parameter_types! { pub struct EstateHandler; impl Estate for EstateHandler { - fn transfer_estate(estate_id: EstateId, from: &u128, to: &u128) -> Result { + fn transfer_estate(estate_id: EstateId, _from: &u128, _to: &u128) -> Result { Ok(estate_id) } fn transfer_landunit( coordinate: (i32, i32), - from: &u128, - to: &(u128, primitives::MetaverseId), + _from: &u128, + _to: &(u128, primitives::MetaverseId), ) -> Result<(i32, i32), DispatchError> { Ok(coordinate) } fn transfer_undeployed_land_block( - who: &AccountId, - to: &AccountId, - undeployed_land_block_id: UndeployedLandBlockId, + _who: &AccountId, + _to: &AccountId, + _undeployed_land_block_id: UndeployedLandBlockId, ) -> Result { Ok(2) } @@ -161,18 +161,18 @@ impl Estate for EstateHandler { Ok(true) } - fn check_landunit(_metaverse_id: primitives::MetaverseId, coordinate: (i32, i32)) -> Result { + fn check_landunit(_metaverse_id: primitives::MetaverseId, _coordinate: (i32, i32)) -> Result { Ok(true) } fn check_undeployed_land_block( - owner: &AccountId, - undeployed_land_block_id: UndeployedLandBlockId, + _owner: &AccountId, + _undeployed_land_block_id: UndeployedLandBlockId, ) -> Result { Ok(true) } - fn get_total_land_units(estate_id: Option) -> u64 { + fn get_total_land_units(_estate_id: Option) -> u64 { 10 } @@ -180,15 +180,15 @@ impl Estate for EstateHandler { 10 } - fn check_estate_ownership(owner: AccountId, estate_id: EstateId) -> Result { + fn check_estate_ownership(_owner: AccountId, _estate_id: EstateId) -> Result { Ok(false) } - fn is_estate_leasor(leasor: AccountId, estate_id: EstateId) -> Result { + fn is_estate_leasor(_leasor: AccountId, _estate_id: EstateId) -> Result { Ok(false) } - fn is_estate_leased(estate_id: EstateId) -> Result { + fn is_estate_leased(_estate_id: EstateId) -> Result { Ok(false) } } @@ -196,7 +196,7 @@ impl Estate for EstateHandler { pub struct MetaverseStakingHandler; impl MetaverseStakingTrait for MetaverseStakingHandler { - fn update_staking_reward(round: RoundIndex, total_reward: u128) -> sp_runtime::DispatchResult { + fn update_staking_reward(_round: RoundIndex, _total_reward: u128) -> sp_runtime::DispatchResult { Ok(()) } } diff --git a/pallets/mining/src/tests.rs b/pallets/mining/src/tests.rs index 52586b8ef..3b6198186 100644 --- a/pallets/mining/src/tests.rs +++ b/pallets/mining/src/tests.rs @@ -1,10 +1,8 @@ use frame_support::{assert_noop, assert_ok}; -use sp_core::blake2_256; -use sp_runtime::traits::BadOrigin; -use sp_runtime::{AccountId32, Perbill}; -use sp_std::vec::Vec; -use mock::{RuntimeEvent, *}; +use sp_runtime::Perbill; + +use mock::*; use primitives::Balance; // Unit testing for metaverse currency, metaverse treasury @@ -55,7 +53,7 @@ fn burn_mining_resource_should_work() { assert_eq!(get_mining_balance(), 1000); - let event = mock::RuntimeEvent::MiningModule(crate::Event::MiningResourceMintedTo(BOB, 1000)); + let _event = mock::RuntimeEvent::MiningModule(crate::Event::MiningResourceMintedTo(BOB, 1000)); assert_ok!(MiningModule::burn(origin, BOB, 300)); assert_eq!(get_mining_balance(), 700); diff --git a/pallets/nft/src/benchmarking.rs b/pallets/nft/src/benchmarking.rs index 5f0659965..17350517a 100644 --- a/pallets/nft/src/benchmarking.rs +++ b/pallets/nft/src/benchmarking.rs @@ -19,23 +19,30 @@ //! Benchmarks for the nft module. #![cfg(feature = "runtime-benchmarks")] -use crate::Call; -#[allow(unused)] -use crate::Pallet as NftModule; -pub use crate::*; + use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; use frame_support::traits::Get; use frame_system::RawOrigin; use orml_traits::BasicCurrencyExtended; -use primitive_traits::CollectionType; -use primitives::{AssetId, Balance, ClassId}; //use core_primitives::NFTTrait; use scale_info::Type; -use sp_runtime::traits::{AccountIdConversion, StaticLookup, UniqueSaturatedInto}; +use sp_io::crypto::{sr25519_generate, sr25519_sign}; use sp_runtime::Perbill; +use sp_runtime::{ + traits::{AccountIdConversion, ConvertInto, IdentifyAccount, StaticLookup, UniqueSaturatedInto}, + AccountId32, MultiSignature, MultiSigner, +}; use sp_std::prelude::*; use sp_std::vec; +use primitive_traits::CollectionType; +use primitives::{AssetId, Balance, ClassId}; + +use crate::Call; +#[allow(unused)] +use crate::Pallet as NftModule; +pub use crate::*; + pub struct Pallet(crate::Pallet); const SEED: u32 = 0; @@ -64,6 +71,11 @@ fn test_attributes(x: u8) -> Attributes { } benchmarks! { + where_clause { + where + T::OffchainSignature: From, + T::AccountId: From, + } // create NFT group create_group{ @@ -158,6 +170,31 @@ benchmarks! { crate::Pallet::::create_group(RawOrigin::Root.into(), vec![1], vec![1]); crate::Pallet::::create_class(RawOrigin::Signed(caller.clone()).into(), vec![1], test_attributes(1), 0u32.into(), TokenType::Transferable, CollectionType::Collectable, Perbill::from_percent(0u32), None); }: _(RawOrigin::Root, 0u32.into(), 0u32.into(), 1u32.into()) + mint_pre_signed{ + let caller_public = sr25519_generate(0.into(), None); + let caller = MultiSigner::Sr25519(caller_public).into_account().into(); + let initial_balance = dollar(1000); + + ::Currency::make_free_balance_be(&caller, initial_balance.unique_saturated_into()); + + crate::Pallet::::create_group(RawOrigin::Root.into(), vec![1], vec![1]); + crate::Pallet::::create_class(RawOrigin::Signed(caller.clone()).into(), vec![1], test_attributes(1), 0u32.into(), TokenType::Transferable, CollectionType::Collectable, Perbill::from_percent(0u32),None); + + let mint_data = PreSignedMint { + class_id: 0u32.into(), + token_id: None, + attributes: test_attributes(1), + metadata: vec![1], + only_account: None, + mint_price: None, + }; + + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &caller_public, &message).unwrap()); + + let target = funded_account::("target", 1); + + }: _(RawOrigin::Signed(target), Box::new(mint_data), signature.into(), caller) } impl_benchmark_test_suite!(Pallet, crate::benchmarking::tests::new_test_ext(), crate::mock::Test); diff --git a/pallets/nft/src/lib.rs b/pallets/nft/src/lib.rs index b01dbae01..fc1b14d09 100644 --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -26,8 +26,6 @@ #![allow(clippy::upper_case_acronyms)] #![cfg_attr(not(feature = "std"), no_std)] -use core::result; - use codec::Encode; use frame_support::traits::Len; use frame_support::{ @@ -39,7 +37,6 @@ use frame_support::{ }; use frame_system::pallet_prelude::*; use orml_nft::{ClassInfo, ClassInfoOf, Classes, Pallet as NftModule, TokenInfo, TokenInfoOf, TokenMetadataOf, Tokens}; -use scale_info::TypeInfo; use sp_runtime::traits::Saturating; use sp_runtime::Perbill; use sp_runtime::{ @@ -52,8 +49,8 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use auction_manager::{Auction, CheckAuctionItemHandler}; pub use pallet::*; pub use primitive_traits::{Attributes, NFTTrait, NftClassData, NftGroupCollectionData, NftMetadata, TokenType}; -use primitive_traits::{CollectionType, NftAssetData, NftAssetDataV1, NftClassDataV1}; -use primitives::{AssetId, BlockNumber, ClassId, GroupCollectionId, Hash, ItemId, TokenId}; +use primitive_traits::{CollectionType, NftAssetData, NftClassDataV1, PreSignedMint}; +use primitives::{AssetId, ClassId, GroupCollectionId, ItemId, TokenId}; pub use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] @@ -62,6 +59,7 @@ pub mod benchmarking; mod mock; #[cfg(test)] mod tests; +mod utils; pub mod weights; @@ -76,10 +74,12 @@ pub enum StorageVersion { #[frame_support::pallet] pub mod pallet { use orml_traits::{MultiCurrency, MultiCurrencyExtended}; - use sp_runtime::traits::CheckedSub; + use sp_runtime::traits::{CheckedSub, IdentifyAccount, Verify}; use sp_runtime::ArithmeticError; - use primitive_traits::{CollectionType, NftAssetData, NftGroupCollectionData, NftMetadata, TokenType}; + use primitive_traits::{ + CollectionType, NftAssetData, NftGroupCollectionData, NftMetadata, PreSignedMint, TokenType, + }; use primitives::FungibleTokenId; use super::*; @@ -135,12 +135,30 @@ pub mod pallet { /// The fee will be unreserved after the storage is freed. #[pallet::constant] type StorageDepositFee: Get>; + + /// Off-Chain signature type. + /// + /// Can verify whether an `Self::OffchainPublic` created a signature. + type OffchainSignature: Verify + Parameter; + + /// Off-Chain public key. + /// + /// Must identify as an on-chain `Self::AccountId`. + type OffchainPublic: IdentifyAccount; } pub type ClassIdOf = ::ClassId; pub type TokenIdOf = ::TokenId; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; + /// A type alias for the pre-signed minting configuration for a specified collection. + pub(super) type PreSignedMintOf = PreSignedMint< + ::ClassId, + ::TokenId, + ::AccountId, + BlockNumberFor, + BalanceOf, + >; #[pallet::storage] #[pallet::getter(fn get_group_collection)] @@ -383,8 +401,11 @@ pub mod pallet { /// Invalid stackable NFT amount InvalidStackableNftAmount, /// Invalid current total issuance - /// Invalid current total issuance InvalidCurrentTotalIssuance, + /// Wrong signature + WrongSignature, + /// Signature expired + SignatureExpired, } #[pallet::call] @@ -452,7 +473,7 @@ pub mod pallet { mint_limit: Option, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let class_id = Self::do_create_class( + let _class_id = Self::do_create_class( &sender, metadata, attributes, @@ -534,7 +555,7 @@ pub mod pallet { let result = NftModule::::mint_stackable_nft(&sender, class_id, metadata, new_stackable_nft_data, amount); match result { - Ok((token_id, balance)) => { + Ok((token_id, _balance)) => { Self::deposit_event(Event::::NewStackableNftMinted(sender, class_id, token_id, amount)); Ok(().into()) } @@ -947,6 +968,27 @@ pub mod pallet { Ok(()) }) } + + /// Mint an item by providing the pre-signed approval. + /// + /// Origin must be Signed. + /// + /// - `mint_data`: The pre-signed approval that consists of the information about the item, + /// its metadata, attributes, who can mint it (`None` for anyone) and until what block + /// number. + /// - `signature`: The signature of the `data` object. + /// - `signer`: The `data` object's signer. Should be an Issuer of the collection. + #[pallet::weight(T::WeightInfo::mint_pre_signed())] + pub fn mint_pre_signed( + origin: OriginFor, + mint_data: Box>, + signature: T::OffchainSignature, + signer: T::AccountId, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::validate_signature(&Encode::encode(&mint_data), &signature, &signer)?; + Self::do_mint_pre_signed(origin, *mint_data, signer) + } } #[pallet::hooks] @@ -1123,6 +1165,107 @@ impl Pallet { Ok((new_asset_ids, last_token_id)) } + // Mint with pre-signed approval from collection owner + pub(crate) fn do_mint_pre_signed( + mint_to: T::AccountId, + mint_data: PreSignedMintOf, + signer: T::AccountId, + ) -> DispatchResult { + let PreSignedMint { + class_id, + token_id, + attributes, + metadata, + only_account, + expired, + mint_price, + } = mint_data; + + // Make sure collection is not locked + ensure!(!Self::is_collection_locked(&class_id), Error::::CollectionIsLocked); + + // Check metadata length + ensure!( + attributes.len() <= T::MaxMetadata::get() as usize, + Error::::ExceedMaximumMetadataLength + ); + + // If specific account recipient specified, this will make sure requirement pass + if let Some(account) = only_account { + ensure!(account == mint_to, Error::::NoPermission); + } + + let now = frame_system::Pallet::::block_number(); + ensure!(expired >= now, Error::::SignatureExpired); + + // Get class info of the collection + let class_info = NftModule::::classes(class_id).ok_or(Error::::ClassIdNotFound)?; + + // Ensure signer is owner of collection + ensure!(signer == class_info.owner, Error::::NoPermission); + + // If minting price is specified, this will transfer token to collection owner. + if let Some(price) = mint_price { + ::Currency::transfer( + &mint_to, + &class_info.owner, + price, + ExistenceRequirement::KeepAlive, + )?; + } + + // Update class total issuance + Self::update_class_total_issuance(&signer, &class_id, One::one())?; + + let class_fund: T::AccountId = T::Treasury::get().into_account_truncating(); + let deposit = T::AssetMintingFee::get().saturating_mul(Into::>::into(1 as u32)); + ::Currency::transfer(&mint_to, &class_fund, deposit, ExistenceRequirement::KeepAlive)?; + + let new_nft_data = NftAssetData { + deposit, + attributes: attributes, + is_locked: false, + }; + + let mut new_token_id: TokenIdOf = Default::default(); + + // Mint specific token id + if let Some(provided_token_id) = token_id { + NftModule::::mint_with_token_id( + &mint_to, + class_id, + provided_token_id, + metadata.clone(), + new_nft_data.clone(), + )?; + new_token_id = provided_token_id + } else { + new_token_id = NftModule::::mint(&mint_to, class_id, metadata.clone(), new_nft_data.clone())?; + } + + // Emit New Nft minted event + Self::deposit_event(Event::::NewNftMinted( + (class_id, new_token_id), + (class_id, new_token_id), + mint_to.clone(), + class_id, + One::one(), + new_token_id, + )); + + Ok(()) + } + + /// A helper method to construct metadata. + /// + /// # Errors + /// + /// This function returns an [`IncorrectMetadata`](crate::Error::IncorrectMetadata) dispatch + /// error if the provided metadata is too long. + pub fn construct_metadata(metadata: Vec) -> Result, DispatchError> { + Ok(BoundedVec::try_from(metadata).map_err(|_| Error::::ExceedMaximumMetadataLength)?) + } + /// Internal NFT class creation fn do_create_class( sender: &T::AccountId, @@ -1230,8 +1373,8 @@ impl Pallet { log::info!("Start upgrading nft class data v2"); log::info!("Start upgrading nft token data v2"); let mut num_nft_classes = 0; - let mut num_nft_tokens = 0; - let mut asset_by_owner_updates = 0; + let _num_nft_tokens = 0; + let _asset_by_owner_updates = 0; Classes::::translate( |k, diff --git a/pallets/nft/src/migration.rs b/pallets/nft/src/migration.rs deleted file mode 100644 index 8b1378917..000000000 --- a/pallets/nft/src/migration.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pallets/nft/src/mock.rs b/pallets/nft/src/mock.rs index d98b5bb3f..ab7304ee9 100644 --- a/pallets/nft/src/mock.rs +++ b/pallets/nft/src/mock.rs @@ -5,10 +5,11 @@ use frame_support::traits::{EqualPrivilegeOnly, Nothing}; use frame_support::{construct_runtime, parameter_types}; use frame_system::EnsureRoot; use orml_traits::parameter_type_with_key; +use sp_core::crypto::AccountId32; use sp_core::H256; use sp_runtime::testing::Header; -use sp_runtime::traits::IdentityLookup; -use sp_runtime::Perbill; +use sp_runtime::traits::{IdentifyAccount, IdentityLookup, Verify}; +use sp_runtime::{MultiSignature, Perbill}; use auction_manager::{Auction, AuctionInfo, AuctionItem, AuctionType, ListingLevel}; pub use primitive_traits::{CollectionType, NftAssetData, NftClassData}; @@ -22,12 +23,12 @@ parameter_types! { pub const BlockHashCount: u32 = 256; } -pub type AccountId = u128; +pub type AccountId = ::AccountId; pub type Balance = u128; pub type BlockNumber = u64; +pub type Signature = MultiSignature; +pub type AccountPublic = ::Signer; -pub const ALICE: AccountId = 1; -pub const BOB: AccountId = 2; pub const CLASS_ID: ::ClassId = 0; pub const CLASS_ID_1: ::ClassId = 1; pub const NON_EXISTING_CLASS_ID: ::ClassId = 1000; @@ -94,24 +95,24 @@ pub struct MockAuctionManager; impl Auction for MockAuctionManager { type Balance = Balance; - fn auction_info(_id: u64) -> Option> { + fn auction_info(_id: u64) -> Option> { None } - fn auction_item(id: AuctionId) -> Option> { + fn auction_item(_id: AuctionId) -> Option> { None } - fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { + fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { Ok(()) } - fn update_auction_item(id: AuctionId, item_id: ItemId) -> DispatchResult { + fn update_auction_item(_id: AuctionId, _item_id: ItemId) -> DispatchResult { Ok(()) } fn new_auction( - _recipient: u128, + _recipient: AccountId32, _initial_amount: Self::Balance, _start: u64, _end: Option, @@ -123,7 +124,7 @@ impl Auction for MockAuctionManager { _auction_type: AuctionType, _item_id: ItemId, _end: Option, - _recipient: u128, + _recipient: AccountId32, _initial_amount: Self::Balance, _start: u64, _listing_level: ListingLevel, @@ -135,11 +136,11 @@ impl Auction for MockAuctionManager { fn remove_auction(_id: u64, _item_id: ItemId) {} - fn auction_bid_handler(from: AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult { + fn auction_bid_handler(_from: AccountId, _id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } - fn buy_now_handler(from: AccountId, auction_id: AuctionId, value: Self::Balance) -> DispatchResult { + fn buy_now_handler(_from: AccountId, _auction_id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } @@ -161,7 +162,7 @@ impl Auction for MockAuctionManager { fn collect_royalty_fee( _high_bid_price: &Self::Balance, - _high_bidder: &u128, + _high_bidder: &AccountId32, _asset_id: &(u32, u64), _social_currency_id: FungibleTokenId, ) -> DispatchResult { @@ -252,6 +253,8 @@ impl Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = AccountPublic; } parameter_types! { @@ -303,7 +306,7 @@ impl ExtBuilder { .unwrap(); pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, 100000), (BOB, 1000)], + balances: vec![([0; 32].into(), 100), ([1; 32].into(), 100000), ([2; 32].into(), 1000)], } .assimilate_storage(&mut t) .unwrap(); diff --git a/pallets/nft/src/tests.rs b/pallets/nft/src/tests.rs index d91e41ad5..d2cd87bda 100644 --- a/pallets/nft/src/tests.rs +++ b/pallets/nft/src/tests.rs @@ -1,7 +1,9 @@ use frame_support::{assert_noop, assert_ok}; use orml_nft::Pallet as NftModule; use orml_traits::MultiCurrency; -use sp_runtime::traits::BadOrigin; +use sp_core::Pair; +use sp_runtime::traits::{BadOrigin, IdentifyAccount}; +use sp_runtime::{MultiSignature, MultiSigner}; use sp_std::default::Default; use mock::*; @@ -10,6 +12,11 @@ use primitives::{Balance, FungibleTokenId}; #[cfg(test)] use super::*; +type AccountIdOf = ::AccountId; +fn account(id: u8) -> AccountIdOf { + [id; 32].into() +} + fn free_bit_balance(who: &AccountId) -> Balance { ::MultiCurrency::free_balance(mining_resource_id(), &who) } @@ -131,7 +138,7 @@ fn create_group_should_work() { #[test] fn create_group_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_noop!(Nft::create_group(origin, vec![1], vec![1]), BadOrigin); }); @@ -140,7 +147,7 @@ fn create_group_should_fail() { #[test] fn create_class_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( @@ -170,21 +177,21 @@ fn create_class_should_work() { } ); - let event = mock::RuntimeEvent::Nft(crate::Event::NewNftClassCreated(ALICE, CLASS_ID)); + let event = mock::RuntimeEvent::Nft(crate::Event::NewNftClassCreated(account(1), CLASS_ID)); assert_eq!(last_event(), event); assert_eq!( free_native_balance(class_id_account()), class_deposit + ::StorageDepositFee::get() ); - assert_eq!(Balances::free_balance(ALICE), 99997); + assert_eq!(Balances::free_balance(account(1)), 99997); }); } #[test] fn create_class_with_royalty_fee_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( @@ -214,82 +221,87 @@ fn create_class_with_royalty_fee_should_work() { } ); - let event = mock::RuntimeEvent::Nft(crate::Event::NewNftClassCreated(ALICE, CLASS_ID)); + let event = mock::RuntimeEvent::Nft(crate::Event::NewNftClassCreated(account(1), CLASS_ID)); assert_eq!(last_event(), event); assert_eq!( free_native_balance(class_id_account()), class_deposit + ::StorageDepositFee::get() ); - assert_eq!(Balances::free_balance(ALICE), 99997); + assert_eq!(Balances::free_balance(account(1)), 99997); }); } #[test] fn mint_asset_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::enable_promotion(RuntimeOrigin::root(), true)); init_test_nft(origin.clone()); assert_eq!(free_native_balance(class_id_account()), 4); - assert_eq!(OrmlNft::tokens_by_owner((ALICE, 0, 0)), ()); + assert_eq!(OrmlNft::tokens_by_owner((account(1), 0, 0)), ()); - let event = mock::RuntimeEvent::Nft(crate::Event::NewNftMinted((0, 0), (0, 0), ALICE, CLASS_ID, 1, 0)); + let event = mock::RuntimeEvent::Nft(crate::Event::NewNftMinted((0, 0), (0, 0), account(1), CLASS_ID, 1, 0)); assert_eq!(last_event(), event); // mint two assets assert_ok!(Nft::mint(origin.clone(), CLASS_ID, vec![1], test_attributes(1), 2)); // bit balance should be 0 (minted 2 NFT) - assert_eq!(free_bit_balance(&ALICE), 0); + assert_eq!(free_bit_balance(&account(1)), 0); - assert_eq!(OrmlNft::tokens_by_owner((ALICE, 0, 0)), ()); - assert_eq!(OrmlNft::tokens_by_owner((ALICE, 0, 1)), ()); - assert_eq!(OrmlNft::tokens_by_owner((ALICE, 0, 2)), ()); + assert_eq!(OrmlNft::tokens_by_owner((account(1), 0, 0)), ()); + assert_eq!(OrmlNft::tokens_by_owner((account(1), 0, 1)), ()); + assert_eq!(OrmlNft::tokens_by_owner((account(1), 0, 2)), ()); }) } #[test] fn mint_asset_with_promotion_enabled_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::enable_promotion(RuntimeOrigin::root(), true)); init_test_nft(origin.clone()); // bit balance should be 0 (minted 1 NFT) - assert_eq!(free_bit_balance(&ALICE), 0); + assert_eq!(free_bit_balance(&account(1)), 0); }) } #[test] fn mint_asset_with_promotion_disabled_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::enable_promotion(RuntimeOrigin::root(), false)); init_test_nft(origin.clone()); // bit balance should be 1 (minted 1 NFT) - assert_eq!(free_bit_balance(&ALICE), 0); + assert_eq!(free_bit_balance(&account(1)), 0); }) } #[test] fn mint_stackable_asset_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::enable_promotion(RuntimeOrigin::root(), true)); init_test_stackable_nft(origin.clone()); assert_eq!(free_native_balance(class_id_account()), 4); - assert_eq!(OrmlNft::tokens_by_owner((ALICE, 0, 0)), ()); + assert_eq!(OrmlNft::tokens_by_owner((account(1), 0, 0)), ()); assert_eq!( - OrmlNft::get_stackable_collections_balances((0, 0, ALICE)), + OrmlNft::get_stackable_collections_balances((0, 0, account(1))), 100u32.into() ); - let event = mock::RuntimeEvent::Nft(crate::Event::NewStackableNftMinted(ALICE, CLASS_ID, 0, 100u32.into())); + let event = mock::RuntimeEvent::Nft(crate::Event::NewStackableNftMinted( + account(1), + CLASS_ID, + 0, + 100u32.into(), + )); assert_eq!(last_event(), event); }) } @@ -297,8 +309,8 @@ fn mint_stackable_asset_should_work() { #[test] fn mint_asset_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); - let invalid_owner = RuntimeOrigin::signed(BOB); + let origin = RuntimeOrigin::signed(account(1)); + let invalid_owner = RuntimeOrigin::signed(account(2)); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -328,7 +340,7 @@ fn mint_asset_should_fail() { #[test] fn mint_exceed_max_minting_limit_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -355,8 +367,8 @@ fn mint_exceed_max_minting_limit_should_fail() { #[test] fn mint_stackable_asset_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); - let invalid_owner = RuntimeOrigin::signed(BOB); + let origin = RuntimeOrigin::signed(account(1)); + let invalid_owner = RuntimeOrigin::signed(account(2)); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -392,7 +404,7 @@ fn mint_stackable_asset_should_fail() { #[test] fn mint_exceed_max_batch_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1])); assert_ok!(Nft::create_class( origin.clone(), @@ -414,10 +426,10 @@ fn mint_exceed_max_batch_should_fail() { #[test] fn transfer_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_nft(origin.clone()); - assert_ok!(Nft::transfer(origin, BOB, (0, 0))); - let event = mock::RuntimeEvent::Nft(crate::Event::TransferedNft(ALICE, BOB, 0, (0, 0))); + assert_ok!(Nft::transfer(origin, account(2), (0, 0))); + let event = mock::RuntimeEvent::Nft(crate::Event::TransferedNft(account(1), account(2), 0, (0, 0))); assert_eq!(last_event(), event); }) } @@ -425,18 +437,29 @@ fn transfer_should_work() { #[test] fn transfer_stackable_nft_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_stackable_nft(origin.clone()); assert_eq!( - OrmlNft::get_stackable_collections_balances((0, 0, ALICE)), + OrmlNft::get_stackable_collections_balances((0, 0, account(1))), 100u32.into() ); - assert_ok!(Nft::transfer_stackable_nft(origin, BOB, (0, 0), 50u32.into())); - assert_eq!(OrmlNft::get_stackable_collections_balances((0, 0, BOB)), 50u32.into()); - assert_eq!(OrmlNft::get_stackable_collections_balances((0, 0, ALICE)), 50u32.into()); + assert_ok!(Nft::transfer_stackable_nft(origin, account(2), (0, 0), 50u32.into())); + assert_eq!( + OrmlNft::get_stackable_collections_balances((0, 0, account(2))), + 50u32.into() + ); + assert_eq!( + OrmlNft::get_stackable_collections_balances((0, 0, account(1))), + 50u32.into() + ); - let event = mock::RuntimeEvent::Nft(crate::Event::TransferedStackableNft(ALICE, BOB, (0, 0), 50u32.into())); + let event = mock::RuntimeEvent::Nft(crate::Event::TransferedStackableNft( + account(1), + account(2), + (0, 0), + 50u32.into(), + )); assert_eq!(last_event(), event); }) } @@ -444,48 +467,48 @@ fn transfer_stackable_nft_should_work() { #[test] fn transfer_stackable_nft_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); - let failing_origin = RuntimeOrigin::signed(BOB); + let origin = RuntimeOrigin::signed(account(1)); + let failing_origin = RuntimeOrigin::signed(account(2)); init_test_stackable_nft(origin.clone()); init_test_nft(origin.clone()); assert_noop!( - Nft::transfer_stackable_nft(origin.clone(), BOB, (0, 1), 0u32.into()), + Nft::transfer_stackable_nft(origin.clone(), account(2), (0, 1), 0u32.into()), Error::::InvalidStackableNftTransfer ); assert_noop!( - Nft::transfer_stackable_nft(origin.clone(), BOB, (0, 1), 10u32.into()), + Nft::transfer_stackable_nft(origin.clone(), account(2), (0, 1), 10u32.into()), Error::::InvalidStackableNftTransfer ); assert_noop!( - Nft::transfer_stackable_nft(origin.clone(), BOB, (0, 0), 101u32.into()), + Nft::transfer_stackable_nft(origin.clone(), account(2), (0, 0), 101u32.into()), Error::::InvalidStackableNftTransfer ); - ReservedStackableNftBalance::::insert(ALICE, (0, 0), 70); + ReservedStackableNftBalance::::insert(account(1), (0, 0), 70); assert_noop!( - Nft::transfer_stackable_nft(origin.clone(), BOB, (0, 0), 71u128), + Nft::transfer_stackable_nft(origin.clone(), account(2), (0, 0), 71u128), Error::::InvalidStackableNftTransfer ); assert_noop!( - Nft::transfer_stackable_nft(failing_origin, ALICE, (0, 0), 10u32.into()), + Nft::transfer_stackable_nft(failing_origin, account(1), (0, 0), 10u32.into()), Error::::InvalidStackableNftTransfer ); - ReservedStackableNftBalance::::insert(ALICE, (0, 0), 0); + ReservedStackableNftBalance::::insert(account(1), (0, 0), 0); - assert_ok!(Nft::transfer_stackable_nft(origin, BOB, (0, 0), 71u32.into())); + assert_ok!(Nft::transfer_stackable_nft(origin, account(2), (0, 0), 71u32.into())); }) } #[test] fn burn_nft_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_nft(origin.clone()); assert_ok!(Nft::mint(origin.clone(), CLASS_ID, vec![1], test_attributes(1), 1)); assert_ok!(Nft::burn(origin, (0, 1))); @@ -497,13 +520,18 @@ fn burn_nft_should_work() { #[test] fn burn_nft_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_stackable_nft(origin.clone()); assert_noop!(Nft::burn(origin.clone(), (0, 0)), Error::::InvalidAssetType); - assert_ok!(Nft::transfer_stackable_nft(origin.clone(), BOB, (0, 0), 100u32.into())); + assert_ok!(Nft::transfer_stackable_nft( + origin.clone(), + account(2), + (0, 0), + 100u32.into() + )); assert_noop!(Nft::burn(origin.clone(), (0, 0)), Error::::InvalidAssetType); }) @@ -512,7 +540,7 @@ fn burn_nft_should_fail() { #[test] fn transfer_batch_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_nft(origin.clone()); assert_ok!(Nft::create_class( origin.clone(), @@ -525,8 +553,11 @@ fn transfer_batch_should_work() { None )); assert_ok!(Nft::mint(origin.clone(), 1, vec![1], test_attributes(1), 4)); - assert_ok!(Nft::transfer_batch(origin, vec![(BOB, (1, 0)), (BOB, (1, 1))])); - let event = mock::RuntimeEvent::Nft(crate::Event::TransferedNft(ALICE, BOB, 1, (1, 1))); + assert_ok!(Nft::transfer_batch( + origin, + vec![(account(2), (1, 0)), (account(2), (1, 1))] + )); + let event = mock::RuntimeEvent::Nft(crate::Event::TransferedNft(account(1), account(2), 1, (1, 1))); assert_eq!(last_event(), event); }) } @@ -534,7 +565,7 @@ fn transfer_batch_should_work() { #[test] fn transfer_batch_exceed_length_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_nft(origin.clone()); assert_ok!(Nft::create_class( origin.clone(), @@ -548,7 +579,15 @@ fn transfer_batch_exceed_length_should_fail() { )); assert_ok!(Nft::mint(origin.clone(), 1, vec![1], test_attributes(1), 4)); assert_noop!( - Nft::transfer_batch(origin, vec![(BOB, (0, 0)), (BOB, (0, 1)), (BOB, (0, 2)), (BOB, (0, 3))]), + Nft::transfer_batch( + origin, + vec![ + (account(2), (0, 0)), + (account(2), (0, 1)), + (account(2), (0, 2)), + (account(2), (0, 3)) + ] + ), Error::::ExceedMaximumBatchTransfer ); }) @@ -557,7 +596,7 @@ fn transfer_batch_exceed_length_should_fail() { #[test] fn transfer_batch_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_stackable_nft(origin.clone()); init_test_nft(origin.clone()); assert_ok!(Nft::create_class( @@ -572,11 +611,11 @@ fn transfer_batch_should_fail() { )); assert_ok!(Nft::mint(origin.clone(), 1, vec![1], test_attributes(1), 1)); assert_noop!( - Nft::transfer_batch(origin.clone(), vec![(BOB, (0, 0)), (BOB, (0, 1))]), + Nft::transfer_batch(origin.clone(), vec![(account(2), (0, 0)), (account(2), (0, 1))]), Error::::InvalidAssetType ); assert_noop!( - Nft::transfer_batch(origin.clone(), vec![(BOB, (0, 3)), (BOB, (0, 6))]), + Nft::transfer_batch(origin.clone(), vec![(account(2), (0, 3)), (account(2), (0, 6))]), Error::::AssetInfoNotFound ); }) @@ -596,13 +635,19 @@ fn do_create_group_collection_should_work() { #[test] fn do_transfer_should_fail() { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); ExtBuilder::default().build().execute_with(|| { - assert_noop!(Nft::do_transfer(ALICE, BOB, (0, 0)), Error::::ClassIdNotFound); + assert_noop!( + Nft::do_transfer(account(1), account(2), (0, 0)), + Error::::ClassIdNotFound + ); init_test_nft(origin.clone()); - assert_noop!(Nft::do_transfer(BOB, ALICE, (0, 0)), Error::::NoPermission); + assert_noop!( + Nft::do_transfer(account(2), account(1), (0, 0)), + Error::::NoPermission + ); assert_ok!(Nft::create_class( origin.clone(), @@ -617,46 +662,63 @@ fn do_transfer_should_fail() { assert_ok!(Nft::mint(origin.clone(), 1, vec![1], test_attributes(1), 1)); assert_noop!( - Nft::do_transfer(ALICE, BOB, (0, 1)), + Nft::do_transfer(account(1), account(2), (0, 1)), Error::::AssetInfoNotFound ); init_test_stackable_nft(origin.clone()); - assert_noop!(Nft::do_transfer(ALICE, BOB, (0, 1)), Error::::InvalidAssetType); + assert_noop!( + Nft::do_transfer(account(1), account(2), (0, 1)), + Error::::InvalidAssetType + ); - assert_ok!(Nft::transfer_stackable_nft(origin.clone(), BOB, (0, 1), 100u32.into())); + assert_ok!(Nft::transfer_stackable_nft( + origin.clone(), + account(2), + (0, 1), + 100u32.into() + )); - assert_noop!(Nft::do_transfer(ALICE, BOB, (0, 1)), Error::::InvalidAssetType); + assert_noop!( + Nft::do_transfer(account(1), account(2), (0, 1)), + Error::::InvalidAssetType + ); }) } #[test] fn do_transfer_should_fail_if_bound_to_address() { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); ExtBuilder::default().build().execute_with(|| { - assert_noop!(Nft::do_transfer(ALICE, BOB, (0, 0)), Error::::ClassIdNotFound); + assert_noop!( + Nft::do_transfer(account(1), account(2), (0, 0)), + Error::::ClassIdNotFound + ); init_bound_to_address_nft(origin.clone()); // Owner allowed to transfer - assert_ok!(Nft::transfer(origin.clone(), BOB, (0, 0))); + assert_ok!(Nft::transfer(origin.clone(), account(2), (0, 0))); - let event = mock::RuntimeEvent::Nft(crate::Event::TransferedNft(ALICE, BOB, 0, (0, 0))); + let event = mock::RuntimeEvent::Nft(crate::Event::TransferedNft(account(1), account(2), 0, (0, 0))); assert_eq!(last_event(), event); - // Reject ownership if BOB tries to transfer - assert_noop!(Nft::do_transfer(BOB, ALICE, (0, 0)), Error::::NonTransferable); + // Reject ownership if account(2) tries to transfer + assert_noop!( + Nft::do_transfer(account(2), account(1), (0, 0)), + Error::::NonTransferable + ); }) } #[test] fn do_check_nft_ownership_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_nft(origin.clone()); - assert_ok!(Nft::check_nft_ownership(&ALICE, &(CLASS_ID, TOKEN_ID)), true); - assert_ok!(Nft::check_nft_ownership(&BOB, &(CLASS_ID, TOKEN_ID)), false); + assert_ok!(Nft::check_nft_ownership(&account(1), &(CLASS_ID, TOKEN_ID)), true); + assert_ok!(Nft::check_nft_ownership(&account(2), &(CLASS_ID, TOKEN_ID)), false); }) } @@ -664,7 +726,7 @@ fn do_check_nft_ownership_should_work() { fn do_check_nft_ownership_should_fail() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - Nft::check_nft_ownership(&ALICE, &(CLASS_ID, TOKEN_ID)), + Nft::check_nft_ownership(&account(1), &(CLASS_ID, TOKEN_ID)), Error::::AssetInfoNotFound ); }) @@ -673,7 +735,7 @@ fn do_check_nft_ownership_should_fail() { #[test] fn do_withdraw_funds_from_class_fund_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); assert_noop!( Nft::withdraw_funds_from_class_fund(origin.clone(), NON_EXISTING_CLASS_ID), Error::::ClassIdNotFound @@ -689,7 +751,7 @@ fn do_withdraw_funds_from_class_fund_should_fail() { Perbill::from_percent(0u32), None )); - let non_class_owner_origin = RuntimeOrigin::signed(BOB); + let non_class_owner_origin = RuntimeOrigin::signed(account(2)); assert_noop!( Nft::withdraw_funds_from_class_fund(non_class_owner_origin, CLASS_ID), Error::::NoPermission @@ -700,14 +762,18 @@ fn do_withdraw_funds_from_class_fund_should_fail() { #[test] fn do_withdraw_funds_from_class_fund_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); init_test_nft(origin.clone()); let class_fund: AccountId = ::PalletId::get().into_sub_account_truncating(CLASS_ID); - assert_ok!(::Currency::transfer(origin.clone(), class_fund, 100)); - assert_eq!(free_native_balance(ALICE), 99896); - assert_eq!(free_native_balance(class_fund), 100); + assert_ok!(::Currency::transfer( + origin.clone(), + class_fund.clone(), + 100 + )); + assert_eq!(free_native_balance(account(1)), 99896); + assert_eq!(free_native_balance(class_fund.clone()), 100); assert_ok!(Nft::withdraw_funds_from_class_fund(origin.clone(), CLASS_ID)); - assert_eq!(free_native_balance(ALICE), 99995); + assert_eq!(free_native_balance(account(1)), 99995); assert_eq!(free_native_balance(class_fund), 1); }) } @@ -715,8 +781,8 @@ fn do_withdraw_funds_from_class_fund_should_work() { #[test] fn setting_hard_limit_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); - let failing_origin = RuntimeOrigin::signed(BOB); + let origin = RuntimeOrigin::signed(account(1)); + let failing_origin = RuntimeOrigin::signed(account(2)); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -761,7 +827,7 @@ fn setting_hard_limit_should_fail() { #[test] fn setting_hard_limit_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); + let origin = RuntimeOrigin::signed(account(1)); let class_deposit = ::ClassMintingFee::get(); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( @@ -796,8 +862,8 @@ fn setting_hard_limit_should_work() { #[test] fn force_updating_total_issuance_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); - let class_deposit = ::ClassMintingFee::get(); + let origin = RuntimeOrigin::signed(account(1)); + let _class_deposit = ::ClassMintingFee::get(); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -827,8 +893,8 @@ fn force_updating_total_issuance_should_work() { #[test] fn force_updating_total_issuance_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); - let class_deposit = ::ClassMintingFee::get(); + let origin = RuntimeOrigin::signed(account(1)); + let _class_deposit = ::ClassMintingFee::get(); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -855,8 +921,8 @@ fn force_updating_total_issuance_should_fail() { #[test] fn force_updating_new_royal_fee_should_work() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(ALICE); - let class_deposit = ::ClassMintingFee::get(); + let origin = RuntimeOrigin::signed(account(1)); + let _class_deposit = ::ClassMintingFee::get(); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -889,8 +955,8 @@ fn force_updating_new_royal_fee_should_work() { #[test] fn force_updating_new_royal_fee_should_fail() { ExtBuilder::default().build().execute_with(|| { - let origin = RuntimeOrigin::signed(BOB); - let class_deposit = ::ClassMintingFee::get(); + let origin = RuntimeOrigin::signed(account(2)); + let _class_deposit = ::ClassMintingFee::get(); assert_ok!(Nft::create_group(RuntimeOrigin::root(), vec![1], vec![1],)); assert_ok!(Nft::create_class( origin.clone(), @@ -904,7 +970,7 @@ fn force_updating_new_royal_fee_should_fail() { )); // Non-root signer is not allowed assert_noop!( - Nft::force_update_royalty_fee(RuntimeOrigin::signed(ALICE), CLASS_ID, Perbill::from_percent(0u32)), + Nft::force_update_royalty_fee(RuntimeOrigin::signed(account(1)), CLASS_ID, Perbill::from_percent(0u32)), BadOrigin ); @@ -915,3 +981,152 @@ fn force_updating_new_royal_fee_should_fail() { ); }) } + +#[test] +fn validate_signature() { + ExtBuilder::default().build().execute_with(|| { + let alice_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let alice_signer = MultiSigner::Sr25519(alice_pair.public()); + let alice = alice_signer.clone().into_account(); + let mint_data: PreSignedMint = PreSignedMint { + class_id: 0, + attributes: test_attributes(1), + metadata: vec![], + only_account: None, + mint_price: None, + token_id: None, + }; + let encoded_data = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(alice_pair.sign(&encoded_data)); + assert_ok!(Nft::validate_signature(&encoded_data, &signature, &alice)); + + let mut wrapped_data: Vec = Vec::new(); + wrapped_data.extend(b""); + wrapped_data.extend(&encoded_data); + wrapped_data.extend(b""); + + let signature = MultiSignature::Sr25519(alice_pair.sign(&wrapped_data)); + assert_ok!(Nft::validate_signature(&encoded_data, &signature, &alice)); + }) +} + +#[test] +fn pre_signed_mints_should_work() { + ExtBuilder::default().build().execute_with(|| { + let alice = account(1); + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let mint_data: PreSignedMint = PreSignedMint { + class_id: 0, + attributes: test_attributes(1), + metadata: vec![], + only_account: None, + mint_price: None, + token_id: None, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(alice.clone()), + user_1.clone(), + 100 + )); + + init_test_nft(RuntimeOrigin::signed(user_1.clone())); + + // User id already signed message so Alice should able to mint nft from pre-signed message + assert_ok!(Nft::mint_pre_signed( + RuntimeOrigin::signed(alice.clone()), + Box::new(mint_data.clone()), + signature.clone(), + user_1.clone(), + )); + assert_eq!(OrmlNft::tokens_by_owner((alice, 0, 0)), ()); + }) +} + +#[test] +fn pre_signed_mint_should_work_with_only_account() { + ExtBuilder::default().build().execute_with(|| { + let alice = account(1); + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let mint_data: PreSignedMint = PreSignedMint { + class_id: 0, + attributes: test_attributes(1), + metadata: vec![], + only_account: Some(account(2)), + mint_price: None, + token_id: None, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(alice.clone()), + user_1.clone(), + 100 + )); + + init_test_nft(RuntimeOrigin::signed(user_1.clone())); + + assert_noop!( + Nft::mint_pre_signed( + RuntimeOrigin::signed(alice.clone()), + Box::new(mint_data.clone()), + signature.clone(), + user_1.clone(), + ), + Error::::NoPermission + ); + + assert_ok!(Nft::mint_pre_signed( + RuntimeOrigin::signed(account(2)), + Box::new(mint_data.clone()), + signature.clone(), + user_1.clone(), + )); + assert_eq!(OrmlNft::tokens_by_owner((account(2), 0, 0)), ()); + }) +} + +#[test] +fn pre_signed_mint_should_collect_fee_with_mint_price() { + ExtBuilder::default().build().execute_with(|| { + let alice = account(1); + let user_1_pair = sp_core::sr25519::Pair::from_string("//Alice", None).unwrap(); + let user_1_signer = MultiSigner::Sr25519(user_1_pair.public()); + let user_1 = user_1_signer.clone().into_account(); + let mint_data: PreSignedMint = PreSignedMint { + class_id: 0, + attributes: test_attributes(1), + metadata: vec![], + only_account: None, + mint_price: Some(50), + token_id: None, + }; + let message = Encode::encode(&mint_data); + let signature = MultiSignature::Sr25519(user_1_pair.sign(&message)); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(alice.clone()), + user_1.clone(), + 100 + )); + assert_eq!(Balances::free_balance(user_1.clone()), 100); + assert_eq!(Balances::free_balance(alice.clone()), 99900); + + init_test_nft(RuntimeOrigin::signed(user_1.clone())); + assert_eq!(Balances::free_balance(user_1.clone()), 96); // Deduct fee + + assert_ok!(Nft::mint_pre_signed( + RuntimeOrigin::signed(alice.clone()), + Box::new(mint_data.clone()), + signature.clone(), + user_1.clone(), + )); + assert_eq!(Balances::free_balance(user_1.clone()), 146); // Get 50 mint fees from NFT + assert_eq!(Balances::free_balance(alice.clone()), 99849); // Pay 1 mint fee for protocol and 50 mint price = 99900 - 51 + assert_eq!(OrmlNft::tokens_by_owner((account(2), 0, 0)), ()); + }) +} diff --git a/pallets/nft/src/utils.rs b/pallets/nft/src/utils.rs new file mode 100644 index 000000000..68c01e8bd --- /dev/null +++ b/pallets/nft/src/utils.rs @@ -0,0 +1,50 @@ +// This file is part of Metaverse.Network & Bit.Country. + +// Copyright (C) 2020-2022 Metaverse.Network & Bit.Country . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_support::pallet_prelude::*; +use sp_runtime::traits::Verify; + +use crate::*; + +impl Pallet { + /// Validates the signature of the given data with the provided signer's account ID. + /// + /// # Errors + /// + /// This function returns a [`WrongSignature`](crate::Error::WrongSignature) error if the + /// signature is invalid or the verification process fails. + pub fn validate_signature( + data: &Vec, + signature: &T::OffchainSignature, + signer: &T::AccountId, + ) -> DispatchResult { + if signature.verify(&**data, &signer) { + return Ok(()); + } + + let prefix = b""; + let suffix = b""; + let mut wrapped: Vec = Vec::with_capacity(data.len() + prefix.len() + suffix.len()); + wrapped.extend(prefix); + wrapped.extend(data); + wrapped.extend(suffix); + + ensure!(signature.verify(&*wrapped, &signer), Error::::WrongSignature); + + Ok(()) + } +} diff --git a/pallets/nft/src/weights.rs b/pallets/nft/src/weights.rs index 1111bfbde..568a8dfe1 100644 --- a/pallets/nft/src/weights.rs +++ b/pallets/nft/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for nft //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-16, STEPS: `20`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-26, STEPS: `20`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: @@ -27,6 +27,7 @@ // pallet // --execution=wasm // --wasm-execution=compiled +// --template=./template/weight-template.hbs // --pallet // nft // --extrinsic @@ -35,37 +36,36 @@ // 20 // --repeat // 10 -// --template=./template/weight-template.hbs // --output -// ./pallets/nft/src/weights.rs +// pallets/nft/src/weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{constants::RocksDbWeight, Weight}}; use sp_std::marker::PhantomData; /// Weight functions needed for nft. -pub trait WeightInfo { fn create_group() -> Weight; fn create_class() -> Weight; fn mint() -> Weight; fn mint_stackable_nft() -> Weight; fn transfer() -> Weight; fn transfer_stackable_nft() -> Weight; fn transfer_batch() -> Weight; fn sign_asset() -> Weight; fn set_hard_limit() -> Weight; fn withdraw_funds_from_class_fund() -> Weight; fn force_update_total_issuance() -> Weight;} +pub trait WeightInfo { fn create_group() -> Weight; fn create_class() -> Weight; fn mint() -> Weight; fn mint_stackable_nft() -> Weight; fn transfer() -> Weight; fn transfer_stackable_nft() -> Weight; fn transfer_batch() -> Weight; fn sign_asset() -> Weight; fn set_hard_limit() -> Weight; fn withdraw_funds_from_class_fund() -> Weight; fn force_update_total_issuance() -> Weight; fn mint_pre_signed() -> Weight;} /// Weights for nft using the for collator node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Nft NextGroupCollectionId (r:1 w:1) - // Proof Skipped: Nft NextGroupCollectionId (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Nft AllNftGroupCollection (r:1 w:1) - // Proof Skipped: Nft AllNftGroupCollection (max_values: Some(1), max_size: None, mode: Measured) - // Storage: Nft GroupCollections (r:0 w:1) - // Proof Skipped: Nft GroupCollections (max_values: None, max_size: None, mode: Measured) - fn create_group() -> Weight { - // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `1317` - // Minimum execution time: 11_475 nanoseconds. - Weight::from_parts(12_117_000, 1317) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - } +// Proof Skipped: Nft NextGroupCollectionId (max_values: Some(1), max_size: None, mode: Measured) +// Storage: Nft AllNftGroupCollection (r:1 w:1) +// Proof Skipped: Nft AllNftGroupCollection (max_values: Some(1), max_size: None, mode: Measured) +// Storage: Nft GroupCollections (r:0 w:1) +// Proof Skipped: Nft GroupCollections (max_values: None, max_size: None, mode: Measured) +fn create_group() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `1317` + // Minimum execution time: 15_000 nanoseconds. + Weight::from_parts(16_000_000, 1317) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) +} // Storage: OrmlNFT NextClassId (r:1 w:1) // Proof Skipped: OrmlNFT NextClassId (max_values: Some(1), max_size: None, mode: Measured) // Storage: Nft GroupCollections (r:1 w:0) @@ -80,8 +80,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `461` // Estimated: `7417` - // Minimum execution time: 35_571 nanoseconds. - Weight::from_parts(37_465_000, 7417) + // Minimum execution time: 43_000 nanoseconds. + Weight::from_parts(45_000_000, 7417) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -101,8 +101,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `784` // Estimated: `23976` - // Minimum execution time: 63_219 nanoseconds. - Weight::from_parts(69_706_000, 23976) + // Minimum execution time: 65_000 nanoseconds. + Weight::from_parts(66_000_000, 23976) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(10)) } @@ -124,11 +124,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `550` // Estimated: `15931` - // Minimum execution time: 46_695 nanoseconds. - Weight::from_parts(111_946_000, 15931) + // Minimum execution time: 48_000 nanoseconds. + Weight::from_parts(49_000_000, 15931) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(8)) - } + } // Storage: Auction ItemsInAuction (r:1 w:0) // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) // Storage: Nft LockedCollection (r:1 w:0) @@ -145,8 +145,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `802` // Estimated: `17187` - // Minimum execution time: 31_317 nanoseconds. - Weight::from_parts(33_226_000, 17187) + // Minimum execution time: 36_000 nanoseconds. + Weight::from_parts(37_000_000, 17187) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -160,8 +160,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `630` // Estimated: `11790` - // Minimum execution time: 27_633 nanoseconds. - Weight::from_parts(28_946_000, 11790) + // Minimum execution time: 33_000 nanoseconds. + Weight::from_parts(33_000_000, 11790) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -181,8 +181,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `980` // Estimated: `25680` - // Minimum execution time: 54_804 nanoseconds. - Weight::from_parts(63_183_000, 25680) + // Minimum execution time: 63_000 nanoseconds. + Weight::from_parts(64_000_000, 25680) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -196,8 +196,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `1002` // Estimated: `14763` - // Minimum execution time: 79_688 nanoseconds. - Weight::from_parts(115_994_000, 14763) + // Minimum execution time: 57_000 nanoseconds. + Weight::from_parts(58_000_000, 14763) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -207,8 +207,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `282` // Estimated: `2757` - // Minimum execution time: 12_053 nanoseconds. - Weight::from_parts(23_425_000, 2757) + // Minimum execution time: 15_000 nanoseconds. + Weight::from_parts(16_000_000, 2757) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -220,8 +220,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `587` // Estimated: `8268` - // Minimum execution time: 56_702 nanoseconds. - Weight::from_parts(61_491_000, 8268) + // Minimum execution time: 31_000 nanoseconds. + Weight::from_parts(31_000_000, 8268) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -231,67 +231,94 @@ impl WeightInfo for SubstrateWeight { // Storage: Nf // Proof Size summary in bytes: // Measured: `282` // Estimated: `2757` - // Minimum execution time: 10_855 nanoseconds. - Weight::from_parts(27_207_000, 2757) + // Minimum execution time: 13_000 nanoseconds. + Weight::from_parts(14_000_000, 2757) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:1) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:2 w:2) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:1) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn mint_pre_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `786` + // Estimated: `19036` + // Minimum execution time: 87_000 nanoseconds. + Weight::from_parts(91_000_000, 19036) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } } + // For backwards compatibility and tests impl WeightInfo for () { fn create_group() -> Weight { - Weight::from_parts(12_117_000, 1317) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(3)) - } + Weight::from_parts(16_000_000, 1317) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(3)) +} fn create_class() -> Weight { - Weight::from_parts(37_465_000, 7417) + Weight::from_parts(45_000_000, 7417) .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(4)) } fn mint() -> Weight { - Weight::from_parts(69_706_000, 23976) + Weight::from_parts(66_000_000, 23976) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(10)) } fn mint_stackable_nft() -> Weight { - Weight::from_parts(111_946_000, 15931) + Weight::from_parts(49_000_000, 15931) .saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().writes(8)) } fn transfer() -> Weight { - Weight::from_parts(33_226_000, 17187) + Weight::from_parts(37_000_000, 17187) .saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().writes(3)) } fn transfer_stackable_nft() -> Weight { - Weight::from_parts(28_946_000, 11790) + Weight::from_parts(33_000_000, 11790) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(2)) } fn transfer_batch() -> Weight { - Weight::from_parts(63_183_000, 25680) + Weight::from_parts(64_000_000, 25680) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(6)) } fn sign_asset() -> Weight { - Weight::from_parts(115_994_000, 14763) + Weight::from_parts(58_000_000, 14763) .saturating_add(RocksDbWeight::get().reads(5)) .saturating_add(RocksDbWeight::get().writes(4)) } fn set_hard_limit() -> Weight { - Weight::from_parts(23_425_000, 2757) + Weight::from_parts(16_000_000, 2757) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } fn withdraw_funds_from_class_fund() -> Weight { - Weight::from_parts(61_491_000, 8268) + Weight::from_parts(31_000_000, 8268) .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(2)) } fn force_update_total_issuance() -> Weight { - Weight::from_parts(27_207_000, 2757) + Weight::from_parts(14_000_000, 2757) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } + fn mint_pre_signed() -> Weight { + Weight::from_parts(91_000_000, 19036) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(6)) + } } diff --git a/pallets/reward/src/lib.rs b/pallets/reward/src/lib.rs index 28681399c..ac4a96a4c 100644 --- a/pallets/reward/src/lib.rs +++ b/pallets/reward/src/lib.rs @@ -17,9 +17,9 @@ #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, HasCompact}; +use codec::Encode; use frame_support::storage::{child, ChildTriePrefixIterator}; -use frame_support::traits::{LockIdentifier, WithdrawReasons}; + use frame_support::{ ensure, log, pallet_prelude::*, @@ -27,23 +27,21 @@ use frame_support::{ transactional, PalletId, }; use frame_system::{ensure_signed, pallet_prelude::*}; -use orml_traits::{DataFeeder, DataProvider, MultiCurrency, MultiReservableCurrency}; +use orml_traits::{DataProvider, MultiCurrency, MultiReservableCurrency}; use sp_core::Encode as SPEncode; use sp_io::hashing::keccak_256; -use sp_runtime::traits::{BlockNumberProvider, CheckedAdd, CheckedMul, Hash as Hasher, Saturating}; +use sp_runtime::traits::{Hash as Hasher, Saturating}; use sp_runtime::{ - traits::{AccountIdConversion, One, Zero}, - ArithmeticError, DispatchError, Perbill, SaturatedConversion, + traits::{AccountIdConversion, Zero}, + DispatchError, Perbill, SaturatedConversion, }; -use sp_std::{collections::btree_map::BTreeMap, prelude::*, vec::Vec}; +use sp_std::{prelude::*, vec::Vec}; use core_primitives::NFTTrait; use core_primitives::*; pub use pallet::*; -use primitives::{ - estate::Estate, CampaignId, CampaignInfo, CampaignInfoV1, CampaignInfoV2, EstateId, Hash, RewardType, TrieIndex, -}; -use primitives::{Balance, ClassId, FungibleTokenId, NftId}; +use primitives::{Balance, ClassId, FungibleTokenId}; +use primitives::{CampaignId, CampaignInfo, CampaignInfoV2, Hash, RewardType, TrieIndex}; pub use weights::WeightInfo; //#[cfg(feature = "runtime-benchmarks")] @@ -59,13 +57,12 @@ pub mod weights; #[frame_support::pallet] pub mod pallet { - use frame_support::traits::tokens::currency; + use frame_support::traits::ExistenceRequirement::AllowDeath; - use orml_traits::{rewards, MultiCurrencyExtended}; - use sp_runtime::traits::{CheckedAdd, CheckedSub, Saturating}; + + use sp_runtime::traits::{CheckedAdd, Saturating}; use sp_runtime::ArithmeticError; - use primitives::staking::RoundInfo; use primitives::{CampaignId, CampaignInfo, ClassId, NftId}; use super::*; @@ -379,7 +376,7 @@ pub mod pallet { /// - `properties`: information relevant for the campaign. /// /// Emits `NewRewardCampaignCreated` if successful. - #[pallet::weight(T::WeightInfo::create_campaign().saturating_mul((1u64.saturating_add(reward.len() as u64))))] + #[pallet::weight(T::WeightInfo::create_campaign().saturating_mul(1u64.saturating_add(reward.len() as u64)))] #[transactional] pub fn create_nft_campaign( origin: OriginFor, @@ -518,7 +515,7 @@ pub mod pallet { /// - `leaf_nodes`: list of the merkle tree nodes required for merkle-proof calculation. /// /// Emits `RewardClaimed` if successful. - #[pallet::weight(T::WeightInfo::claim_reward_root().saturating_mul((1u64.saturating_add(leaf_nodes.len() as u64))))] + #[pallet::weight(T::WeightInfo::claim_reward_root().saturating_mul(1u64.saturating_add(leaf_nodes.len() as u64)))] #[transactional] pub fn claim_reward_root( origin: OriginFor, @@ -582,7 +579,7 @@ pub mod pallet { /// - `amount`: the amount of NFTs that the account is going to claim /// /// Emits `RewardClaimed` if successful. - #[pallet::weight(T::WeightInfo::claim_nft_reward().saturating_mul((1u64.saturating_add(*amount))))] + #[pallet::weight(T::WeightInfo::claim_nft_reward().saturating_mul(1u64.saturating_add(*amount)))] #[transactional] pub fn claim_nft_reward(origin: OriginFor, id: CampaignId, amount: u64) -> DispatchResult { let who = ensure_signed(origin)?; @@ -641,7 +638,7 @@ pub mod pallet { /// - `leaf_nodes`: list of the merkle tree nodes required for merkle-proof calculation. /// /// Emits `RewardClaimed` if successful. - #[pallet::weight(T::WeightInfo::claim_nft_reward_root().saturating_mul((1u64.saturating_add(reward_tokens.len() as u64))))] + #[pallet::weight(T::WeightInfo::claim_nft_reward_root().saturating_mul(1u64.saturating_add(reward_tokens.len() as u64)))] #[transactional] pub fn claim_nft_reward_root( origin: OriginFor, @@ -855,7 +852,7 @@ pub mod pallet { let mut new_cap = cap.clone(); let mut rewards_list: Vec<(T::AccountId, Vec<(ClassId, NftId)>)> = Vec::new(); let mut tokens: Vec<(ClassId, TokenId)> = Vec::new(); - let mut total_amount_left: u64 = total_nfts_amount; + let total_amount_left: u64 = total_nfts_amount; for (to, amount) in rewards { let (t, _) = Self::reward_get_nft(campaign.trie_index, &to); ensure!(t.is_empty(), Error::::AccountAlreadyRewarded); @@ -866,7 +863,7 @@ pub mod pallet { ); total_amount_left.saturating_sub(amount); - for l in 0..amount { + for _l in 0..amount { let token = new_cap.pop().ok_or(Error::::RewardExceedCap)?; tokens.push(token); } @@ -945,13 +942,13 @@ pub mod pallet { /// - `merkle_roots_quanity`: the amount of merkle roots that were used for setting rewards. /// /// Emits `RewardCampaignClosed` and/or `RewardCampaignRootClosed` if successful. - #[pallet::weight(T::WeightInfo::close_campaign().saturating_mul((1u64.saturating_add(*merkle_roots_quantity))))] + #[pallet::weight(T::WeightInfo::close_campaign().saturating_mul(1u64.saturating_add(*merkle_roots_quantity)))] #[transactional] pub fn close_campaign(origin: OriginFor, id: CampaignId, merkle_roots_quantity: u64) -> DispatchResult { let who = ensure_signed(origin)?; let now = frame_system::Pallet::::block_number(); - let mut campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; + let campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; ensure!(who == campaign.creator, Error::::NotCampaignCreator); @@ -1012,7 +1009,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let now = frame_system::Pallet::::block_number(); - let mut campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; + let campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; ensure!(who == campaign.creator, Error::::NotCampaignCreator); @@ -1069,7 +1066,7 @@ pub mod pallet { T::AdminOrigin::ensure_origin(origin)?; let now = frame_system::Pallet::::block_number(); - let mut campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; + let campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; ensure!(campaign.end > now, Error::::CampaignEnded); @@ -1100,7 +1097,7 @@ pub mod pallet { T::AdminOrigin::ensure_origin(origin)?; let now = frame_system::Pallet::::block_number(); - let mut campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; + let campaign = Self::campaigns(id).ok_or(Error::::CampaignIsNotFound)?; ensure!(campaign.end > now, Error::::CampaignEnded); @@ -1179,7 +1176,7 @@ pub mod pallet { impl Hooks for Pallet { /// Hook that is called every time a new block is finalized. fn on_finalize(block_number: T::BlockNumber) { - for (id, info) in Campaigns::::iter() + for (id, _info) in Campaigns::::iter() .filter(|(_, campaign_info)| campaign_info.end == block_number) .collect::>() { @@ -1394,7 +1391,7 @@ impl Pallet { let mut upgraded_campaign_items = 0; Campaigns::::translate( - |k, campaign_info_v2: CampaignInfoV2, T::BlockNumber>| { + |_k, campaign_info_v2: CampaignInfoV2, T::BlockNumber>| { upgraded_campaign_items += 1; let v3_reward = RewardType::FungibleTokens(FungibleTokenId::NativeToken(0), campaign_info_v2.reward); diff --git a/pallets/reward/src/mock.rs b/pallets/reward/src/mock.rs index ac67ad3c5..2fa488767 100644 --- a/pallets/reward/src/mock.rs +++ b/pallets/reward/src/mock.rs @@ -4,29 +4,32 @@ use frame_support::traits::Nothing; use frame_support::{construct_runtime, ord_parameter_types, parameter_types, PalletId}; use frame_system::EnsureSignedBy; use orml_traits::parameter_type_with_key; +use sp_core::crypto::AccountId32; use sp_core::H256; -use sp_runtime::{testing::Header, traits::IdentityLookup, Perbill}; +use sp_runtime::traits::{IdentifyAccount, Verify}; +use sp_runtime::{testing::Header, traits::IdentityLookup, MultiSignature, Perbill}; use auction_manager::*; use core_primitives::NftAssetData; -use primitives::estate::Estate; -use primitives::staking::MetaverseStakingTrait; -use primitives::{Amount, AuctionId, EstateId, FungibleTokenId, ItemId, UndeployedLandBlockId}; + +use primitives::{Amount, AuctionId, FungibleTokenId, ItemId}; use crate as reward; use super::*; -pub type AccountId = u128; +pub type AccountId = ::AccountId; pub type Balance = u128; pub type BlockNumber = u64; pub type Hash = H256; +type Signature = MultiSignature; +type AccountPublic = ::Signer; -pub const ALICE: AccountId = 1; -pub const BOB: AccountId = 2; -pub const CHARLIE: AccountId = 3; -pub const DONNA: AccountId = 4; -pub const EVA: AccountId = 5; +pub const ALICE: AccountId = AccountId32::new([1; 32]); +pub const BOB: AccountId = AccountId32::new([2; 32]); +pub const CHARLIE: AccountId = AccountId32::new([3; 32]); +pub const DONNA: AccountId = AccountId32::new([4; 32]); +pub const EVA: AccountId = AccountId32::new([5; 32]); pub const COLLECTION_ID: u64 = 0; pub const CLASS_ID: u32 = 0; @@ -162,24 +165,24 @@ pub struct MockAuctionManager; impl Auction for MockAuctionManager { type Balance = Balance; - fn auction_info(_id: u64) -> Option> { + fn auction_info(_id: u64) -> Option> { None } - fn auction_item(id: AuctionId) -> Option> { + fn auction_item(_id: AuctionId) -> Option> { None } - fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { + fn update_auction(_id: u64, _info: AuctionInfo) -> DispatchResult { Ok(()) } - fn update_auction_item(id: AuctionId, item_id: ItemId) -> DispatchResult { + fn update_auction_item(_id: AuctionId, _item_id: ItemId) -> DispatchResult { Ok(()) } fn new_auction( - _recipient: u128, + _recipient: AccountId, _initial_amount: Self::Balance, _start: u64, _end: Option, @@ -191,7 +194,7 @@ impl Auction for MockAuctionManager { _auction_type: AuctionType, _item_id: ItemId, _end: Option, - _recipient: u128, + _recipient: AccountId, _initial_amount: Self::Balance, _start: u64, _listing_level: ListingLevel, @@ -203,19 +206,19 @@ impl Auction for MockAuctionManager { fn remove_auction(_id: u64, _item_id: ItemId) {} - fn auction_bid_handler(from: AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult { + fn auction_bid_handler(_from: AccountId, _id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } - fn buy_now_handler(from: AccountId, auction_id: AuctionId, value: Self::Balance) -> DispatchResult { + fn buy_now_handler(_from: AccountId, _auction_id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } fn local_auction_bid_handler( _now: u64, _id: u64, - _new_bid: (u128, Self::Balance), - _last_bid: Option<(u128, Self::Balance)>, + _new_bid: (AccountId, Self::Balance), + _last_bid: Option<(AccountId, Self::Balance)>, _social_currency_id: FungibleTokenId, ) -> DispatchResult { Ok(()) @@ -223,7 +226,7 @@ impl Auction for MockAuctionManager { fn collect_royalty_fee( _high_bid_price: &Self::Balance, - _high_bidder: &u128, + _high_bidder: &AccountId, _asset_id: &(u32, u64), _social_currency_id: FungibleTokenId, ) -> DispatchResult { @@ -262,6 +265,8 @@ impl pallet_nft::Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = AccountPublic; } parameter_types! { diff --git a/pallets/reward/src/tests.rs b/pallets/reward/src/tests.rs index 323fb03eb..7cf44dbcb 100644 --- a/pallets/reward/src/tests.rs +++ b/pallets/reward/src/tests.rs @@ -17,16 +17,17 @@ #![cfg(test)] -use frame_support::{assert_err, assert_noop, assert_ok, sp_runtime::runtime_logger}; +use frame_support::{assert_noop, assert_ok}; +use hex_literal::hex; use sp_std::collections::btree_map::BTreeMap; use sp_std::default::Default; -use super::*; use core_primitives::Attributes; -use hex_literal::hex; -use mock::{Balance, RuntimeEvent, *}; +use mock::{Balance, *}; use primitives::{CampaignInfo, FungibleTokenId, Hash}; +use super::*; + fn init_test_nft(owner: RuntimeOrigin) { //Create group collection before class assert_ok!(NFTModule::create_group(RuntimeOrigin::root(), vec![1], vec![1])); @@ -109,6 +110,13 @@ fn test_claim_hash(who: AccountId, balance: Balance) -> Hash { keccak_256(&keccak_256(&leaf)).into() } +fn test_claim_hash_account_u128(who: u128, balance: Balance) -> Hash { + let mut leaf: Vec = who.encode(); + leaf.extend(balance.encode()); + + keccak_256(&keccak_256(&leaf)).into() +} + fn test_claim_nft_hash(who: AccountId, token: (ClassId, TokenId)) -> Hash { let mut leaf: Vec = who.encode(); leaf.extend(token.0.encode()); @@ -227,7 +235,7 @@ fn create_multicurrency_campaign_works() { #[test] fn create_nft_campaign_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); assert_noop!( @@ -262,7 +270,7 @@ fn create_nft_campaign_fails() { #[test] fn create_campaign_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_noop!( Reward::create_campaign( @@ -572,7 +580,11 @@ fn set_reward_fails() { ); assert_noop!( - Reward::set_reward(RuntimeOrigin::signed(ALICE), 0, vec![(BOB, 3), (100, 3), (102, 3)]), + Reward::set_reward( + RuntimeOrigin::signed(ALICE), + 0, + vec![(BOB, 3), ([100; 32].into(), 3), ([102; 32].into(), 3)] + ), Error::::RewardsListSizeAboveMaximum ); @@ -584,7 +596,7 @@ fn set_reward_fails() { ); assert_noop!( - Reward::set_reward(RuntimeOrigin::signed(3), 0, vec![(BOB, 5)]), + Reward::set_reward(RuntimeOrigin::signed(CHARLIE), 0, vec![(BOB, 5)]), Error::::InvalidSetRewardOrigin ); @@ -674,7 +686,7 @@ fn set_reward_root_fails() { ); assert_noop!( - Reward::set_reward_root(RuntimeOrigin::signed(3), 0, 5, test_hash(2u64)), + Reward::set_reward_root(RuntimeOrigin::signed(CHARLIE), 0, 5, test_hash(2u64)), Error::::InvalidSetRewardOrigin ); @@ -706,7 +718,7 @@ fn set_reward_root_fails() { #[test] fn set_nft_reward_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_ok!(Reward::add_set_reward_origin(RuntimeOrigin::signed(ALICE), ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); @@ -722,12 +734,17 @@ fn set_nft_reward_fails() { )); assert_noop!( - Reward::set_nft_reward(RuntimeOrigin::signed(3), 0, vec![(BOB, 1)], 1), + Reward::set_nft_reward(RuntimeOrigin::signed(CHARLIE), 0, vec![(BOB, 1)], 1), Error::::InvalidSetRewardOrigin ); assert_noop!( - Reward::set_nft_reward(RuntimeOrigin::signed(ALICE), 0, vec![(BOB, 1), (102, 1), (100, 1)], 3), + Reward::set_nft_reward( + RuntimeOrigin::signed(ALICE), + 0, + vec![(BOB, 1), (CHARLIE, 1), (DONNA, 1)], + 3 + ), Error::::RewardsListSizeAboveMaximum ); @@ -761,12 +778,12 @@ fn set_nft_reward_fails() { assert_ok!(Reward::set_nft_reward( RuntimeOrigin::signed(ALICE), 0, - vec![(106, 2)], + vec![([106; 32].into(), 2)], 2 )); assert_noop!( - Reward::set_nft_reward(RuntimeOrigin::signed(ALICE), 0, vec![(100, 1)], 1), + Reward::set_nft_reward(RuntimeOrigin::signed(ALICE), 0, vec![(CHARLIE, 1)], 1), Error::::RewardExceedCap ); @@ -797,7 +814,7 @@ fn set_nft_reward_fails() { #[test] fn set_nft_reward_root_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_ok!(Reward::add_set_reward_origin(RuntimeOrigin::signed(ALICE), ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); @@ -837,7 +854,7 @@ fn set_nft_reward_root_fails() { )); assert_noop!( - Reward::set_nft_reward_root(RuntimeOrigin::signed(3), 1, test_hash(2u64)), + Reward::set_nft_reward_root(RuntimeOrigin::signed(CHARLIE), 1, test_hash(2u64)), Error::::InvalidSetRewardOrigin ); @@ -1380,7 +1397,7 @@ fn claim_reward_root_fails() { #[test] fn claim_nft_reward_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_ok!(Reward::add_set_reward_origin(RuntimeOrigin::signed(ALICE), ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); @@ -1463,7 +1480,7 @@ fn claim_nft_reward_fails() { #[test] fn claim_nft_reward_root_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_ok!(Reward::add_set_reward_origin(RuntimeOrigin::signed(ALICE), ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); @@ -1742,7 +1759,7 @@ fn close_campaign_using_merkle_root_works() { RuntimeOrigin::signed(ALICE), 0, 4, - test_claim_hash(3, 3) + test_claim_hash(CHARLIE, 3) )); run_to_block(11); @@ -1799,7 +1816,7 @@ fn close_multicurrency_campaign_works() { #[test] fn close_campaign_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_ok!(Reward::create_campaign( RuntimeOrigin::signed(ALICE), BOB, @@ -1852,7 +1869,7 @@ fn close_campaign_fails() { #[test] fn close_campaign_using_merkle_root_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_ok!(Reward::add_set_reward_origin(RuntimeOrigin::signed(ALICE), ALICE)); assert_ok!(Reward::create_campaign( RuntimeOrigin::signed(ALICE), @@ -1875,7 +1892,7 @@ fn close_campaign_using_merkle_root_fails() { RuntimeOrigin::signed(ALICE), 0, 4, - test_claim_hash(3, 3) + test_claim_hash(CHARLIE, 3) )); run_to_block(17); @@ -1934,7 +1951,7 @@ fn close_campaign_using_merkle_root_fails() { #[test] fn close_nft_campaign_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); @@ -2091,7 +2108,7 @@ fn cancel_multicurrency_campaign_works() { #[test] fn cancel_nft_campaign_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); init_test_nft(RuntimeOrigin::signed(ALICE)); @@ -2142,7 +2159,7 @@ fn cancel_nft_campaign_fails() { #[test] fn cancel_campaign_fails() { ExtBuilder::default().build().execute_with(|| { - let campaign_id = 0; + let _campaign_id = 0; assert_ok!(Reward::create_campaign( RuntimeOrigin::signed(ALICE), BOB, @@ -2237,7 +2254,10 @@ fn js_encoded_data_matches_blockchain_encoded_data() { assert_eq!( leaf, - vec![2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + vec![ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ] ); // SCALE encoding for [2u128, 10u128] }); } @@ -2248,27 +2268,27 @@ fn js_generated_leafs_match_blockchain_generated_leafs() { let bob_hash = Hash::from_slice(&hex!( "64b39d59f54b02b6d862584c58735a0d3ff7c8d1ee46250809f4c244ca13d5ca" )); - assert_eq!(test_claim_hash(BOB, 10), bob_hash); + assert_eq!(test_claim_hash_account_u128(2, 10), bob_hash); let charlie_hash = Hash::from_slice(&hex!( "d90b5864238131f03c065e80a5e0c04aadb2493984702ef3bb279dcd3cb8ac7d" )); - assert_eq!(test_claim_hash(CHARLIE, 25), charlie_hash); + assert_eq!(test_claim_hash_account_u128(3, 25), charlie_hash); let donna_hash = Hash::from_slice(&hex!( "77ead2ce9a216ed6ac05f5d8a2c7d12373428794b33d56f65163073769976208" )); - assert_eq!(test_claim_hash(DONNA, 50), donna_hash); + assert_eq!(test_claim_hash_account_u128(4, 50), donna_hash); let eva_hash = Hash::from_slice(&hex!( "7ecf6a4f9809680533d36217de280ae07964f4c65595308405e2c860bc52d4bf" )); - assert_eq!(test_claim_hash(EVA, 75), eva_hash); + assert_eq!(test_claim_hash_account_u128(5, 75), eva_hash); }); } #[test] -fn merkle_proof_based_cmapaing_works_with_js_generated_root() { +fn merkle_proof_based_campaign_works_with_js_generated_root() { ExtBuilder::default().build().execute_with(|| { let campaign_id = 0; assert_ok!(Reward::add_set_reward_origin(RuntimeOrigin::signed(ALICE), ALICE)); diff --git a/pallets/spp/Cargo.toml b/pallets/spp/Cargo.toml new file mode 100644 index 000000000..30082b8de --- /dev/null +++ b/pallets/spp/Cargo.toml @@ -0,0 +1,71 @@ +[package] +authors = ['Metaverse Network '] +description = 'Metaverse Network pallet for land minting logic.' +edition = '2021' +homepage = 'https://metaverse.network' +license = 'Unlicense' +name = 'pallet-spp' +repository = 'https://github.com/bit-country' +version = '2.0.0-rc6' + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +serde = { workspace = true, optional = true } +scale-info = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +frame-benchmarking = { workspace = true, optional = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-version = { workspace = true } +sp-std = { workspace = true } +sp-io = { workspace = true } +substrate-fixed = { workspace = true } +pallet-balances = { workspace = true, optional = true } +orml-traits = { workspace = true } +orml-tokens = { workspace = true } +orml-rewards = { workspace = true } + +# local packages +core-primitives = { path = "../../traits/core-primitives", default-features = false } +primitives = { package = "bit-country-primitives", path = "../../primitives/metaverse", default-features = false } +currencies = { package = "currencies", path = "../currencies", default-features = false } +asset-manager = { package = "asset-manager", path = "../asset-manager", default-features = false } + +[dependencies.auction-manager] +default-features = false +package = 'auction-manager' +path = '../../traits/auction-manager' +version = '2.0.0-rc6' + + + +[features] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] +default = ['std'] +std = [ + 'codec/std', + "serde", + 'scale-info/std', + 'frame-support/std', + 'frame-system/std', + 'sp-runtime/std', + 'sp-core/std', + 'core-primitives/std', + 'primitives/std', + 'sp-io/std', + 'pallet-balances/std', + 'auction-manager/std', + 'frame-benchmarking/std', + 'orml-tokens/std', + "currencies/std", + "asset-manager/std", + "orml-rewards/std" +] \ No newline at end of file diff --git a/pallets/spp/src/lib.rs b/pallets/spp/src/lib.rs new file mode 100644 index 000000000..bedd0b5fe --- /dev/null +++ b/pallets/spp/src/lib.rs @@ -0,0 +1,1360 @@ +// This file is part of Metaverse.Network & Bit.Country. + +// Copyright (C) 2020-2022 Metaverse.Network & Bit.Country . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::pallet_prelude::*; +use frame_support::traits::{ExistenceRequirement, LockIdentifier}; +use frame_support::{ + dispatch::DispatchResult, + ensure, log, + traits::{Currency, Get}, + transactional, PalletId, +}; +use frame_system::ensure_signed; +use frame_system::pallet_prelude::*; +use orml_traits::{MultiCurrency, RewardHandler}; +use sp_runtime::traits::{ + BlockNumberProvider, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, UniqueSaturatedInto, +}; +use sp_runtime::{ + traits::{AccountIdConversion, Convert, Saturating, Zero}, + ArithmeticError, DispatchError, FixedPointNumber, Perbill, Permill, SaturatedConversion, +}; + +use core_primitives::*; +pub use pallet::*; +use primitives::bounded::Rate; +use primitives::{ClassId, EraIndex, FungibleTokenId, PoolId, Ratio, StakingRound, TokenId}; +pub use weights::WeightInfo; + +pub type QueueId = u32; +//#[cfg(feature = "runtime-benchmarks")] +//pub mod benchmarking; + +#[cfg(test)] +mod mock; +mod utils; + +#[cfg(test)] +mod tests; + +pub mod weights; + +const BOOSTING_ID: LockIdentifier = *b"bc/boost"; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::traits::{Currency, LockableCurrency, ReservableCurrency, WithdrawReasons}; + use orml_traits::{MultiCurrency, MultiReservableCurrency}; + use sp_core::U256; + use sp_runtime::traits::{BlockNumberProvider, CheckedAdd, CheckedMul, CheckedSub, One, UniqueSaturatedInto}; + use sp_runtime::Permill; + use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; + + use primitives::bounded::FractionalRate; + use primitives::{PoolId, StakingRound}; + + use crate::utils::{BoostInfo, BoostingRecord, PoolInfo}; + + use super::*; + + #[pallet::pallet] + #[pallet::generate_store(trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: + frame_system::Config + + orml_rewards::Config< + Share = BalanceOf, + Balance = BalanceOf, + PoolId = PoolId, + CurrencyId = FungibleTokenId, + > + { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Currency type + type Currency: Currency + + ReservableCurrency + + LockableCurrency; + /// Multi currencies type that handles different currency type in auction + type MultiCurrency: MultiReservableCurrency< + Self::AccountId, + CurrencyId = FungibleTokenId, + Balance = BalanceOf, + >; + + /// Weight implementation for estate extrinsics + type WeightInfo: WeightInfo; + + /// Minimum staking balance + #[pallet::constant] + type MinimumStake: Get>; + + /// Network fee charged on pool creation + #[pallet::constant] + type NetworkFee: Get>; + + /// Storage deposit free charged when saving data into the blockchain. + /// The fee will be unreserved after the storage is freed. + #[pallet::constant] + type StorageDepositFee: Get>; + + /// Block number provider for the relaychain. + type RelayChainBlockNumber: BlockNumberProvider>; + + #[pallet::constant] + type PoolAccount: Get; + + #[pallet::constant] + type RewardPayoutAccount: Get; + + #[pallet::constant] + type RewardHoldingAccount: Get; + + #[pallet::constant] + type MaximumQueue: Get; + + type CurrencyIdConversion: CurrencyIdManagement; + + /// Origin represented Governance + type GovernanceOrigin: EnsureOrigin<::RuntimeOrigin>; + } + + pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; + + #[pallet::storage] + #[pallet::getter(fn next_class_id)] + pub type NextPoolId = StorageValue<_, PoolId, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn fees)] + pub type Fees = StorageValue<_, (FractionalRate, FractionalRate), ValueQuery>; + + /// Keep track of Pool detail + #[pallet::storage] + #[pallet::getter(fn pool)] + pub type Pool = StorageMap<_, Twox64Concat, PoolId, PoolInfo, OptionQuery>; + + /// Pool ledger that keeps track of Pool id and balance of base currency + #[pallet::storage] + #[pallet::getter(fn pool_ledger)] + pub type PoolLedger = StorageMap<_, Twox64Concat, PoolId, BalanceOf, ValueQuery>; + + /// Network ledger that keep track of all staking across all pools + #[pallet::storage] + #[pallet::getter(fn network_ledger)] + pub type NetworkLedger = StorageMap<_, Twox64Concat, FungibleTokenId, BalanceOf, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn minimum_redeem)] + pub type MinimumRedeem = StorageMap<_, Twox64Concat, FungibleTokenId, BalanceOf, ValueQuery>; + + /// Keep track of each staking round, how many items in queue need to be redeem + #[pallet::storage] + #[pallet::getter(fn staking_round_redeem_requests)] + pub type StakingRoundRedeemQueue = StorageDoubleMap< + _, + Blake2_128Concat, + StakingRound, + Blake2_128Concat, + FungibleTokenId, + (BalanceOf, BoundedVec, FungibleTokenId), + OptionQuery, + >; + + /// Keep track of user ledger that how many queue items that needs to be unlocked + #[pallet::storage] + #[pallet::getter(fn user_redeem_requests)] + pub type UserCurrencyRedeemQueue = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Blake2_128Concat, + FungibleTokenId, + (BalanceOf, BoundedVec), + OptionQuery, + >; + + /// Keep track of queue item as well as account that locked amount of currency can be redeemed + #[pallet::storage] + #[pallet::getter(fn currency_redeem_requests)] + pub type CurrencyRedeemQueue = StorageDoubleMap< + _, + Blake2_128Concat, + FungibleTokenId, + Blake2_128Concat, + QueueId, + (T::AccountId, BalanceOf, StakingRound), + OptionQuery, + >; + + #[pallet::storage] + #[pallet::getter(fn unlock_duration)] + pub type UnlockDuration = StorageMap<_, Twox64Concat, FungibleTokenId, StakingRound>; + + #[pallet::storage] + #[pallet::getter(fn current_staking_round)] + pub type CurrentStakingRound = StorageMap<_, Twox64Concat, FungibleTokenId, StakingRound>; + + /// The current era of relaychain + /// + /// RelayChainCurrentEra : EraIndex + #[pallet::storage] + #[pallet::getter(fn relay_chain_current_era)] + pub type RelayChainCurrentEra = StorageValue<_, EraIndex, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn last_staking_round)] + pub type LastStakingRound = StorageMap<_, Twox64Concat, FungibleTokenId, StakingRound, ValueQuery>; + + /// The relaychain block number of last staking round + #[pallet::storage] + #[pallet::getter(fn last_era_updated_block)] + pub type LastEraUpdatedBlock = StorageValue<_, BlockNumberFor, ValueQuery>; + + /// The internal of relaychain block number between era. + #[pallet::storage] + #[pallet::getter(fn update_era_frequency)] + pub type UpdateEraFrequency = StorageValue<_, BlockNumberFor, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn queue_next_id)] + pub type QueueNextId = StorageMap<_, Twox64Concat, FungibleTokenId, u32, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn iteration_limit)] + pub type IterationLimit = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn boosting_record)] + /// Store boosting records for each account + pub type BoostingOf = + StorageMap<_, Twox64Concat, T::AccountId, BoostingRecord, T::BlockNumber>, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn network_boost_info)] + /// Store boosting records for each pool + pub type NetworkBoostingInfo = StorageMap<_, Twox64Concat, PoolId, BalanceOf, ValueQuery>; + + /// PoolRewardAmountPerEra: double_map Pool, FungibleTokenId => RewardAmountPerEra + #[pallet::storage] + #[pallet::getter(fn incentive_reward_amounts)] + pub type PoolRewardAmountPerEra = + StorageDoubleMap<_, Twox64Concat, PoolId, Twox64Concat, FungibleTokenId, BalanceOf, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn reward_frequency_per_era)] + pub type RewardEraFrequency = StorageValue<_, BalanceOf, ValueQuery>; + + /// The pending rewards amount, actual available rewards amount may be deducted + /// + /// PendingRewards: double_map PoolId, AccountId => BTreeMap + #[pallet::storage] + #[pallet::getter(fn pending_multi_rewards)] + pub type PendingRewards = StorageDoubleMap< + _, + Twox64Concat, + PoolId, + Twox64Concat, + T::AccountId, + BTreeMap>, + ValueQuery, + >; + + /// The estimated staking reward rate per era on relaychain. + /// + /// EstimatedRewardRatePerEra: value: Rate + #[pallet::storage] + pub type EstimatedRewardRatePerEra = StorageValue<_, FractionalRate, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn network_fee)] + /// Store network fee by currency id + pub type CurrencyNetworkFee = StorageMap<_, Twox64Concat, FungibleTokenId, BalanceOf, ValueQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub (crate) fn deposit_event)] + pub enum Event { + /// New pool created + PoolCreated { + from: T::AccountId, + pool_id: PoolId, + currency_id: FungibleTokenId, + }, + /// Deposited + Deposited { + from: T::AccountId, + pool_id: PoolId, + amount: BalanceOf, + }, + /// Redeemed + Redeemed { + from: T::AccountId, + pool_id: PoolId, + amount: BalanceOf, + }, + /// Redeemed success + RedeemSuccess { + queue_id: QueueId, + currency_id: FungibleTokenId, + to: T::AccountId, + token_amount: BalanceOf, + }, + /// Current era updated + CurrentEraUpdated { new_era_index: EraIndex }, + /// Last era updated + LastEraUpdated { last_era_block: BlockNumberFor }, + /// Update era frequency + UpdateEraFrequency { frequency: BlockNumberFor }, + /// Boosted successful + Boosted { + booster: T::AccountId, + pool_id: PoolId, + boost_info: BoostInfo>, + }, + /// Claim rewards. + ClaimRewards { + who: T::AccountId, + pool: PoolId, + reward_currency_id: FungibleTokenId, + claimed_amount: BalanceOf, + }, + /// Reward rate per era updated. + EstimatedRewardRatePerEraUpdated { reward_rate_per_era: Rate }, + /// Unlock duration updated. + UnlockDurationUpdated { + currency_id: FungibleTokenId, + unlock_duration: StakingRound, + }, + /// Iterator limit updated. + IterationLimitUpdated { new_limit: u32 }, + /// Network fee updated. + NetworkFeeUpdated { + currency_id: FungibleTokenId, + new_fee: BalanceOf, + }, + } + + #[pallet::error] + pub enum Error { + /// No permission + NoPermission, + /// Currency is not supported + CurrencyIsNotSupported, + /// No available next pool id + NoAvailablePoolId, + /// Pool doesn't exists + PoolDoesNotExist, + /// Overflow + Overflow, + /// Below minimum redemption + BelowMinimumRedeem, + /// No current staking round + NoCurrentStakingRound, + /// Unexpected + Unexpected, + /// Too many redeems + TooManyRedeems, + /// Arthimetic Overflow + ArithmeticOverflow, + /// Token type is not supported + NotSupportTokenType, + /// Unlock duration not found + UnlockDurationNotFound, + /// Staking round not found + StakingRoundNotFound, + /// Staking round redeem queue not found + StakingRoundRedeemNotFound, + /// User currency redeem queue not found + UserCurrencyRedeemQueueNotFound, + /// Redeem queue per currency not found + CurrencyRedeemQueueNotFound, + /// The last era updated block is invalid + InvalidLastEraUpdatedBlock, + /// Fail to process redeem requests + FailedToProcessRedemption, + /// Insufficient Fund + InsufficientFund, + /// Error while adding new boost + MaxVotesReached, + /// Reward distribution origin already exists + OriginsAlreadyExist, + /// Origin doesn't exists + OriginDoesNotExists, + /// Invalid rate input + InvalidRate, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_n: BlockNumberFor) -> Weight { + // let era_number = Self::get_era_index(T::RelayChainBlockNumber::current_block_number()); + let era_number = Self::get_era_index(>::block_number()); + + if !era_number.is_zero() { + let _ = Self::update_current_era(era_number).map_err(|err| err).ok(); + } + + T::WeightInfo::on_initialize() + } + } + + #[pallet::call] + impl Pallet { + #[pallet::weight(T::WeightInfo::mint_land())] + pub fn create_pool( + origin: OriginFor, + currency_id: FungibleTokenId, + max_nft_reward: u32, + commission: Rate, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Ensure currency_id supported + ensure!( + currency_id == FungibleTokenId::NativeToken(0) || currency_id == FungibleTokenId::NativeToken(1), + Error::::CurrencyIsNotSupported + ); + + // Collect pool creation fee + Self::collect_pool_creation_fee(&who, currency_id)?; + + // Ensure no pool id is zero + let current_pool_id = NextPoolId::::get(); + if current_pool_id.is_zero() { + NextPoolId::::put(1u32); + } + + // Next pool id + let next_pool_id = NextPoolId::::try_mutate(|id| -> Result { + let current_id = *id; + *id = id.checked_add(1u32).ok_or(Error::::NoAvailablePoolId)?; + Ok(current_id) + })?; + + let new_pool = PoolInfo { + creator: who.clone(), + commission, + currency_id, + max: max_nft_reward, + }; + + // Add tuple class_id, currency_id + Pool::::insert(next_pool_id, new_pool); + + // Emit event for pool creation + Self::deposit_event(Event::PoolCreated { + from: who, + pool_id: next_pool_id, + currency_id, + }); + Ok(().into()) + } + + #[pallet::weight(T::WeightInfo::mint_land())] + pub fn deposit(origin: OriginFor, pool_id: PoolId, amount: BalanceOf) -> DispatchResult { + // Ensure user is signed + let who = ensure_signed(origin)?; + // Check if pool exists + let pool_instance = Pool::::get(pool_id).ok_or(Error::::PoolDoesNotExist)?; + + // Get currencyId from pool detail + let currency_id = pool_instance.currency_id; + + // Get network ledger balance from currency id + let network_ledger_balance = Self::network_ledger(currency_id); + + // Collect deposit fee for protocol + // Assuming there's a function `collect_deposit_fee` that deducts a fee for deposits. + let amount_after_fee = Self::collect_deposit_fee(&who, currency_id, amount)?; + + let r_currency_id = T::CurrencyIdConversion::convert_to_rcurrency(currency_id) + .map_err(|_| Error::::CurrencyIsNotSupported)?; + // Calculate rAmount as receipt of amount locked. The formula based on rAmount = (amount * rAmount + // total issuance)/network ledger balance + let r_amount_total_issuance = T::MultiCurrency::total_issuance(r_currency_id); + let mut r_amount = amount_after_fee; + // This will apply for subsequence deposits - the first deposit r_amount = amount_after_fee + if network_ledger_balance != BalanceOf::::zero() { + r_amount = U256::from(amount_after_fee.saturated_into::()) + .saturating_mul(r_amount_total_issuance.saturated_into::().into()) + .checked_div(network_ledger_balance.saturated_into::().into()) + .ok_or(Error::::ArithmeticOverflow)? + .as_u128() + .saturated_into(); + } + + // Deposit rAmount to user using T::MultiCurrency::deposit + T::MultiCurrency::deposit(r_currency_id, &who, r_amount)?; + + // Update this specific pool ledger to keep track of pool balance + PoolLedger::::mutate(&pool_id, |pool| -> Result<(), Error> { + *pool = pool + .checked_add(&amount_after_fee) + .ok_or(Error::::ArithmeticOverflow)?; + Ok(()) + })?; + + NetworkLedger::::mutate(¤cy_id, |pool| -> Result<(), Error> { + *pool = pool + .checked_add(&amount_after_fee) + .ok_or(Error::::ArithmeticOverflow)?; + Ok(()) + })?; + // Transfer amount to PoolAccount using T::MultiCurrency::transfer + // Assuming `PoolAccount` is an associated type that represents the pool's account ID or a method to + // get it. + T::MultiCurrency::transfer( + currency_id, + &who, + &T::PoolAccount::get().into_account_truncating(), + amount_after_fee, + )?; + + // Emit deposit event + Self::deposit_event(Event::Deposited { + from: who, + pool_id, + amount, + }); + Ok(().into()) + } + + #[pallet::weight(T::WeightInfo::mint_land())] + pub fn redeem( + origin: OriginFor, + pool_id: PoolId, + v_currency_id: FungibleTokenId, + r_amount: BalanceOf, + ) -> DispatchResult { + // Ensure user is signed + let who = ensure_signed(origin)?; + ensure!( + r_amount >= MinimumRedeem::::get(v_currency_id), + Error::::BelowMinimumRedeem + ); + + let currency_id = T::CurrencyIdConversion::convert_to_currency(v_currency_id) + .map_err(|_| Error::::NotSupportTokenType)?; + + // Check if pool exists + let pool_instance = Pool::::get(pool_id).ok_or(Error::::PoolDoesNotExist)?; + + ensure!( + currency_id == pool_instance.currency_id, + Error::::CurrencyIsNotSupported + ); + + // Get network ledger balance from currency id + let network_ledger_balance = Self::network_ledger(currency_id); + + // Collect deposit fee for protocol + let amount_after_fee = Self::collect_redeem_fee(&who, v_currency_id, r_amount)?; + let r_amount = amount_after_fee; + // Calculate rAmount as receipt of amount locked. The formula based on rAmount = (amount * rAmount + // total issuance)/network ledger balance + let r_amount_total_issuance = T::MultiCurrency::total_issuance(v_currency_id); + let currency_amount = U256::from(r_amount.saturated_into::()) + .saturating_mul(network_ledger_balance.saturated_into::().into()) + .checked_div(r_amount_total_issuance.saturated_into::().into()) + .ok_or(Error::::ArithmeticOverflow)? + .as_u128() + .saturated_into(); + + // Check current staking era - only failed when there is no current staking era + // Staking era get checked and updated every blocks + match CurrentStakingRound::::get(currency_id) { + Some(staking_round) => { + // Calculate the staking duration to be locked + let new_staking_round = Self::calculate_next_staking_round( + Self::unlock_duration(currency_id).ok_or(Error::::UnlockDurationNotFound)?, + staking_round, + )?; + // Burn currency + T::MultiCurrency::withdraw(v_currency_id, &who, amount_after_fee)?; + + // Update pool ledger + PoolLedger::::mutate(&pool_id, |pool| -> Result<(), Error> { + *pool = pool + .checked_sub(¤cy_amount) + .ok_or(Error::::ArithmeticOverflow)?; + Ok(()) + })?; + + // Get current queue_id + let next_queue_id = Self::queue_next_id(currency_id); + + // Add request into network currency redeem queue + CurrencyRedeemQueue::::insert( + ¤cy_id, + &next_queue_id, + (&who, currency_amount, &new_staking_round), + ); + + // Handle ledger of user and currency - user,currency: total_amount_unlocked, vec![queue_id] + // Check if you already has any redeem requests + if UserCurrencyRedeemQueue::::get(&who, ¤cy_id).is_some() { + // Add new queue id into the list + UserCurrencyRedeemQueue::::mutate(&who, ¤cy_id, |value| -> Result<(), Error> { + // + if let Some((amount_need_unlocked, existing_queue)) = value { + existing_queue + .try_push(next_queue_id) + .map_err(|_| Error::::TooManyRedeems)?; + + *amount_need_unlocked = amount_need_unlocked + .checked_add(¤cy_amount) + .ok_or(Error::::ArithmeticOverflow)?; + }; + Ok(()) + })?; + } else { + let mut new_queue = BoundedVec::::default(); + new_queue + .try_push(next_queue_id) + .map_err(|_| Error::::TooManyRedeems)?; + UserCurrencyRedeemQueue::::insert(&who, ¤cy_id, (currency_amount, new_queue)); + } + + // Handle ledger of staking round - executed by hooks on every block - staking_round,currency: + // total_amount_unlocked, vec![queue_id], currency + + // Check if there any existing claim of the next staking round + if let Some((_, _, _token_id)) = StakingRoundRedeemQueue::::get(&new_staking_round, ¤cy_id) + { + StakingRoundRedeemQueue::::mutate( + &new_staking_round, + ¤cy_id, + |value| -> Result<(), Error> { + // Add new queue item + if let Some((amount_need_unlocked, existing_queue, _token_id)) = value { + existing_queue + .try_push(next_queue_id) + .map_err(|_| Error::::TooManyRedeems)?; + *amount_need_unlocked = amount_need_unlocked + .checked_add(¤cy_amount) + .ok_or(Error::::ArithmeticOverflow)?; + }; + Ok(()) + }, + )?; + } else { + let mut new_queue = BoundedVec::::default(); + new_queue + .try_push(next_queue_id) + .map_err(|_| Error::::TooManyRedeems)?; + + StakingRoundRedeemQueue::::insert( + &new_staking_round, + ¤cy_id, + (currency_amount, new_queue, currency_id), + ); + } + } + None => return Err(Error::::NoCurrentStakingRound.into()), + } + + QueueNextId::::mutate(¤cy_id, |queue_id| -> Result<(), Error> { + *queue_id = queue_id.checked_add(1).ok_or(Error::::ArithmeticOverflow)?; + Ok(()) + })?; + + // Emit deposit event + Self::deposit_event(Event::Redeemed { + from: who, + pool_id, + amount: r_amount, + }); + Ok(().into()) + } + + /// This function only for governance origin to execute when starting the protocol or + /// changes of era duration. + #[pallet::weight(< T as Config >::WeightInfo::mint_land())] + pub fn update_era_config( + origin: OriginFor, + last_era_updated_block: Option>, + frequency: Option>, + last_staking_round: StakingRound, + estimated_reward_rate_per_era: Option, + unlock_duration: Option<(FungibleTokenId, StakingRound)>, + iteration_limit: Option, + network_fee: Option<(FungibleTokenId, BalanceOf)>, + ) -> DispatchResult { + T::GovernanceOrigin::ensure_origin(origin)?; + + if let Some(change) = frequency { + UpdateEraFrequency::::put(change); + Self::deposit_event(Event::::UpdateEraFrequency { frequency: change }); + } + + if let Some(change) = last_era_updated_block { + let update_era_frequency = UpdateEraFrequency::::get(); + let current_relay_chain_block = >::block_number(); + // let current_relay_chain_block = T::RelayChainBlockNumber::current_block_number(); + if !update_era_frequency.is_zero() { + // ensure!( + // change > current_relay_chain_block.saturating_sub(update_era_frequency) + // && change <= current_relay_chain_block, + // Error::::InvalidLastEraUpdatedBlock + // ); + + LastEraUpdatedBlock::::put(change); + LastStakingRound::::insert(FungibleTokenId::NativeToken(1), last_staking_round); + Self::deposit_event(Event::::LastEraUpdated { last_era_block: change }); + } + } + + if let Some(reward_rate_per_era) = estimated_reward_rate_per_era { + EstimatedRewardRatePerEra::::mutate(|rate| -> DispatchResult { + rate.try_set(reward_rate_per_era) + .map_err(|_| Error::::InvalidRate.into()) + })?; + Self::deposit_event(Event::::EstimatedRewardRatePerEraUpdated { reward_rate_per_era }); + } + + if let Some((currency_id, staking_round)) = unlock_duration { + UnlockDuration::::insert(currency_id, staking_round.clone()); + Self::deposit_event(Event::::UnlockDurationUpdated { + currency_id, + unlock_duration: staking_round, + }) + } + + if let Some(new_limit) = iteration_limit { + IterationLimit::::put(new_limit.clone()); + Self::deposit_event(Event::::IterationLimitUpdated { new_limit }) + } + + if let Some((currency_id, new_fee)) = network_fee { + CurrencyNetworkFee::::insert(currency_id, new_fee); + Self::deposit_event(Event::::NetworkFeeUpdated { currency_id, new_fee }); + } + + Ok(()) + } + + /// This function allow reward voting for the pool + #[pallet::weight(< T as Config >::WeightInfo::mint_land())] + pub fn boost(origin: OriginFor, pool_id: PoolId, vote: BoostInfo>) -> DispatchResult { + // Ensure user is signed + let who = ensure_signed(origin)?; + + // Ensure user has balance to vote + ensure!( + vote.balance <= T::Currency::free_balance(&who), + Error::::InsufficientFund + ); + + // Check if pool exists + ensure!(Pool::::get(pool_id).is_some(), Error::::PoolDoesNotExist); + // Still need to work out some + // Convert boost conviction into shares + let vote_conviction = vote.conviction.lock_periods(); + // Calculate lock period from UnlockDuration block number x conviction + let current_block: T::BlockNumber = >::block_number(); + + let mut unlock_at = current_block.saturating_add(UpdateEraFrequency::::get()); + let mut total_balance = vote.balance; + if !vote_conviction.is_zero() { + unlock_at.saturating_mul(vote_conviction.into()); + total_balance.saturating_mul(vote_conviction.into()); + } + // Locked token + + BoostingOf::::try_mutate(who.clone(), |voting| -> DispatchResult { + let votes = &mut voting.votes; + match votes.binary_search_by_key(&pool_id, |i| i.0) { + Ok(i) => { + // User already boosted, this is adding up their boosting weight + votes[i] + .1 + .add(total_balance.clone()) + .ok_or(Error::::ArithmeticOverflow)?; + voting + .prior + .accumulate(unlock_at, votes[i].1.balance.saturating_add(total_balance)) + } + Err(i) => { + votes.insert(i, (pool_id, vote.clone())); + voting.prior.accumulate(unlock_at, total_balance); + } + } + Ok(()) + })?; + T::Currency::extend_lock( + BOOSTING_ID, + &who, + vote.balance, + frame_support::traits::WithdrawReasons::TRANSFER, + ); + + // Add shares into the rewards pool + >::add_share(&who, &pool_id, total_balance.unique_saturated_into()); + // Add shares into the network pool + >::add_share(&who, &Zero::zero(), total_balance.unique_saturated_into()); + + // Emit Boosted event + Self::deposit_event(Event::::Boosted { + booster: who.clone(), + pool_id, + boost_info: vote.clone(), + }); + + Ok(()) + } + + #[pallet::weight(< T as pallet::Config >::WeightInfo::mint_land())] + pub fn claim_rewards(origin: OriginFor, pool_id: PoolId) -> DispatchResult { + let who = ensure_signed(origin)?; + + Self::do_claim_rewards(who, pool_id) + } + } +} + +impl Pallet { + pub fn calculate_next_staking_round(a: StakingRound, b: StakingRound) -> Result { + let result = match a { + StakingRound::Era(era_a) => match b { + StakingRound::Era(era_b) => { + StakingRound::Era(era_a.checked_add(era_b).ok_or(Error::::ArithmeticOverflow)?) + } + _ => return Err(Error::::Unexpected.into()), + }, + StakingRound::Round(round_a) => match b { + StakingRound::Round(round_b) => { + StakingRound::Round(round_a.checked_add(round_b).ok_or(Error::::ArithmeticOverflow)?) + } + _ => return Err(Error::::Unexpected.into()), + }, + StakingRound::Epoch(epoch_a) => match b { + StakingRound::Epoch(epoch_b) => { + StakingRound::Epoch(epoch_a.checked_add(epoch_b).ok_or(Error::::ArithmeticOverflow)?) + } + _ => return Err(Error::::Unexpected.into()), + }, + StakingRound::Hour(hour_a) => match b { + StakingRound::Hour(hour_b) => { + StakingRound::Hour(hour_a.checked_add(hour_b).ok_or(Error::::ArithmeticOverflow)?) + } + _ => return Err(Error::::Unexpected.into()), + }, + }; + + Ok(result) + } + + pub fn collect_deposit_fee( + who: &T::AccountId, + currency_id: FungibleTokenId, + amount: BalanceOf, + ) -> Result, DispatchError> { + let (deposit_rate, _redeem_rate) = Fees::::get(); + + let deposit_fee = deposit_rate.into_inner().saturating_mul_int(amount); + let amount_exclude_fee = amount.checked_sub(&deposit_fee).ok_or(Error::::ArithmeticOverflow)?; + T::MultiCurrency::transfer( + currency_id, + who, + &T::PoolAccount::get().into_account_truncating(), + deposit_fee, + )?; + + return Ok(amount_exclude_fee); + } + + pub fn collect_redeem_fee( + who: &T::AccountId, + currency_id: FungibleTokenId, + amount: BalanceOf, + ) -> Result, DispatchError> { + let (_mint_rate, redeem_rate) = Fees::::get(); + let redeem_fee = redeem_rate.into_inner().saturating_mul_int(amount); + let amount_exclude_fee = amount.checked_sub(&redeem_fee).ok_or(Error::::ArithmeticOverflow)?; + T::MultiCurrency::transfer( + currency_id, + who, + &T::PoolAccount::get().into_account_truncating(), + redeem_fee, + )?; + + return Ok(amount_exclude_fee); + } + + pub fn collect_pool_creation_fee(who: &T::AccountId, currency_id: FungibleTokenId) -> DispatchResult { + let pool_fee = CurrencyNetworkFee::::get(currency_id); + T::MultiCurrency::transfer( + currency_id, + who, + &T::PoolAccount::get().into_account_truncating(), + pool_fee, + ) + } + + fn handle_update_staking_round(era_index: EraIndex, currency: FungibleTokenId) -> DispatchResult { + let last_staking_round = StakingRound::Era(era_index as u32); + let unlock_duration = match UnlockDuration::::get(currency) { + Some(StakingRound::Era(unlock_duration_era)) => unlock_duration_era, + Some(StakingRound::Round(unlock_duration_round)) => unlock_duration_round, + Some(StakingRound::Epoch(unlock_duration_epoch)) => unlock_duration_epoch, + Some(StakingRound::Hour(unlock_duration_hour)) => unlock_duration_hour, + _ => 0, + }; + + let current_staking_round = era_index; + + // Check current staking round queue with last staking round if there is any pending redeem requests + if let Some((_total_locked, existing_queue, currency_id)) = + StakingRoundRedeemQueue::::get(last_staking_round.clone(), currency) + { + for queue_id in existing_queue.iter().take(Self::iteration_limit() as usize) { + if let Some((account, unlock_amount, staking_round)) = + CurrencyRedeemQueue::::get(currency_id, queue_id) + { + let pool_account_balance = + T::MultiCurrency::free_balance(currency_id, &T::PoolAccount::get().into_account_truncating()); + if pool_account_balance != BalanceOf::::zero() { + Self::update_queue_request( + currency_id, + account, + queue_id, + unlock_amount, + pool_account_balance, + staking_round, + ) + .ok(); + } + } + } + } else { + LastStakingRound::::mutate(currency, |last_staking_round| -> Result<(), Error> { + match last_staking_round { + StakingRound::Era(era) => { + if current_staking_round + unlock_duration > *era { + *era = era.checked_add(1).ok_or(Error::::ArithmeticOverflow)?; + } + Ok(()) + } + StakingRound::Round(round) => { + if current_staking_round + unlock_duration > *round { + *round = round.checked_add(1).ok_or(Error::::ArithmeticOverflow)?; + } + Ok(()) + } + StakingRound::Epoch(epoch) => { + if current_staking_round + unlock_duration > *epoch { + *epoch = epoch.checked_add(1).ok_or(Error::::ArithmeticOverflow)?; + } + Ok(()) + } + StakingRound::Hour(hour) => { + if current_staking_round + unlock_duration > *hour { + *hour = hour.checked_add(1).ok_or(Error::::ArithmeticOverflow)?; + } + Ok(()) + } + _ => Ok(()), + } + })?; + }; + + Ok(()) + } + + fn handle_reward_distribution_to_network_pool() -> DispatchResult { + // Get reward per era that set up Governance + let reward_per_era = RewardEraFrequency::::get(); + // Get reward holding account + let reward_holding_origin = T::RewardHoldingAccount::get().into_account_truncating(); + let reward_holding_balance = T::Currency::free_balance(&reward_holding_origin); + + if reward_holding_balance.is_zero() { + // Ignore if reward distributor balance is zero + return Ok(()); + } + + let mut amount_to_send = reward_per_era.clone(); + // Make sure user distributor account has enough balance + if amount_to_send > reward_holding_balance { + amount_to_send = reward_holding_balance + } + + T::Currency::transfer( + &reward_holding_origin, + &Self::get_reward_payout_account_id(), + amount_to_send, + ExistenceRequirement::KeepAlive, + )?; + >::accumulate_reward(&Zero::zero(), FungibleTokenId::NativeToken(0), amount_to_send)?; + Ok(()) + } + + pub(crate) fn estimated_reward_rate_per_era() -> Rate { + EstimatedRewardRatePerEra::::get().into_inner() + } + + fn handle_reward_distribution_to_pool_treasury(previous_era: EraIndex, new_era: EraIndex) -> DispatchResult { + let era_changes = new_era.saturating_sub(previous_era); + ensure!(!era_changes.is_zero(), Error::::Unexpected); + // Get reward per era for pool treasury + let reward_rate_per_era = Self::estimated_reward_rate_per_era(); + // Get total compound reward rate based on number of era. + let reward_rate = reward_rate_per_era + .saturating_add(Rate::one()) + .saturating_pow(era_changes.unique_saturated_into()) + .saturating_sub(Rate::one()); + + let mut total_reward_staking: BalanceOf = Zero::zero(); + log::info!( + target: "pallet-spp", + "reward distribution to pool treasury era: {:?} reward rate per era {:?} with reward_rate {:?}", + era_changes, reward_rate_per_era, reward_rate + ); + if !reward_rate.is_zero() { + // iterate all pool ledgers + for (pool_id, pool_amount) in PoolLedger::::iter() { + let mut reward_staking = reward_rate.saturating_mul_int(pool_amount); + + if !reward_staking.is_zero() { + let pool_treasury_account = Self::get_pool_treasury(pool_id); + total_reward_staking = total_reward_staking.saturating_add(reward_staking); + + let pool_treasury_commission = Rate::checked_from_rational(1, 100).unwrap_or_default(); + let pool_treasury_reward_commission_amount = + pool_treasury_commission.saturating_mul_int(reward_staking); + + // Increase reward staking of pool ledger + PoolLedger::::mutate(pool_id, |total_staked| -> Result<(), Error> { + *total_staked = total_staked + .checked_add(&reward_staking) + .ok_or(Error::::ArithmeticOverflow)?; + + Ok(()) + })?; + + T::MultiCurrency::deposit( + FungibleTokenId::FungibleToken(1), + &pool_treasury_account, + pool_treasury_reward_commission_amount, + )?; + } + } + + if !total_reward_staking.is_zero() { + NetworkLedger::::mutate( + &FungibleTokenId::NativeToken(1), + |total_staked| -> Result<(), Error> { + *total_staked = total_staked + .checked_add(&total_reward_staking) + .ok_or(Error::::ArithmeticOverflow)?; + Ok(()) + }, + )?; + } + } + + Ok(()) + } + + #[transactional] + fn update_queue_request( + currency_id: FungibleTokenId, + account: T::AccountId, + queue_id: &QueueId, + mut unlock_amount: BalanceOf, + pool_account_balance: BalanceOf, + staking_round: StakingRound, + ) -> DispatchResult { + // Get minimum balance of currency + let ed = T::MultiCurrency::minimum_balance(currency_id); + let mut account_to_send = account.clone(); + + // If unlock amount less than existential deposit, to avoid error kill the process, transfer the + // unlock_amount to pool address instead + if unlock_amount < ed { + let receiver_balance = T::MultiCurrency::total_balance(currency_id, &account); + + // Check if even after receiving unlock amount, account still below ED then transfer fund to + // PoolAccount + let receiver_balance_after = receiver_balance + .checked_add(&unlock_amount) + .ok_or(ArithmeticError::Overflow)?; + if receiver_balance_after < ed { + account_to_send = T::PoolAccount::get().into_account_truncating(); + } + } + + // If pool account balance greater than unlock amount + if pool_account_balance >= unlock_amount { + // Transfer amount from PoolAccount to users + T::MultiCurrency::transfer( + currency_id, + &T::PoolAccount::get().into_account_truncating(), + &account_to_send, + unlock_amount, + )?; + + // Remove currency redeem queue + CurrencyRedeemQueue::::remove(¤cy_id, &queue_id); + + // Edit staking round redeem queue with locked amount + StakingRoundRedeemQueue::::mutate_exists( + &staking_round, + ¤cy_id, + |value| -> Result<(), Error> { + if let Some((total_locked_origin, existing_queue, _)) = value { + // If total locked == unlock_amount, then set value to zero + if total_locked_origin == &unlock_amount { + *value = None; + return Ok(()); + } + // Otherwise, deduct unlock amount + *total_locked_origin = total_locked_origin + .checked_sub(&unlock_amount) + .ok_or(Error::::ArithmeticOverflow)?; + // Only keep items that not with processed queue_id + existing_queue.retain(|x| x != queue_id); + } else { + return Err(Error::::StakingRoundRedeemNotFound); + } + Ok(()) + }, + )?; + + UserCurrencyRedeemQueue::::mutate_exists(&account, ¤cy_id, |value| -> Result<(), Error> { + if let Some((total_locked_origin, existing_queue)) = value { + if total_locked_origin == &unlock_amount { + *value = None; + return Ok(()); + } + existing_queue.retain(|x| x != queue_id); + *total_locked_origin = total_locked_origin + .checked_sub(&unlock_amount) + .ok_or(Error::::ArithmeticOverflow)?; + } else { + return Err(Error::::UserCurrencyRedeemQueueNotFound); + } + Ok(()) + })?; + } else { + // When pool account balance less than amount need to be unlocked then use pool remaining balance as + // unlock amount + unlock_amount = pool_account_balance; + T::MultiCurrency::transfer( + currency_id, + &T::PoolAccount::get().into_account_truncating(), + &account_to_send, + unlock_amount, + )?; + + CurrencyRedeemQueue::::mutate_exists(¤cy_id, &queue_id, |value| -> Result<(), Error> { + if let Some((_, total_locked_origin, _)) = value { + if total_locked_origin == &unlock_amount { + *value = None; + return Ok(()); + } + *total_locked_origin = total_locked_origin + .checked_sub(&unlock_amount) + .ok_or(Error::::ArithmeticOverflow)?; + } else { + return Err(Error::::CurrencyRedeemQueueNotFound); + } + Ok(()) + })?; + + StakingRoundRedeemQueue::::mutate_exists( + &staking_round, + ¤cy_id, + |value| -> Result<(), Error> { + if let Some((total_locked_origin, _existing_queue, _)) = value { + if total_locked_origin == &unlock_amount { + *value = None; + return Ok(()); + } + *total_locked_origin = total_locked_origin + .checked_sub(&unlock_amount) + .ok_or(Error::::ArithmeticOverflow)?; + } else { + return Err(Error::::StakingRoundRedeemNotFound); + } + Ok(()) + }, + )?; + + UserCurrencyRedeemQueue::::mutate_exists(&account, ¤cy_id, |value| -> Result<(), Error> { + if let Some((total_locked_origin, _existing_queue)) = value { + if total_locked_origin == &unlock_amount { + *value = None; + return Ok(()); + } + + *total_locked_origin = total_locked_origin + .checked_sub(&unlock_amount) + .ok_or(Error::::ArithmeticOverflow)?; + } else { + return Err(Error::::UserCurrencyRedeemQueueNotFound); + } + Ok(()) + })?; + } + + pool_account_balance + .checked_sub(&unlock_amount) + .ok_or(Error::::ArithmeticOverflow)?; + + NetworkLedger::::mutate(¤cy_id, |pool| -> Result<(), Error> { + *pool = pool.checked_sub(&unlock_amount).ok_or(Error::::ArithmeticOverflow)?; + Ok(()) + })?; + + Self::deposit_event(Event::RedeemSuccess { + queue_id: *queue_id, + currency_id, + to: account_to_send, + token_amount: unlock_amount, + }); + Ok(()) + } + + pub fn get_era_index(relaychain_block_number: BlockNumberFor) -> EraIndex { + relaychain_block_number + .checked_sub(&Self::last_era_updated_block()) + .and_then(|n| n.checked_div(&Self::update_era_frequency())) + .and_then(|n| TryInto::::try_into(n).ok()) + .unwrap_or_else(Zero::zero) + } + + fn handle_redeem_requests(era_index: EraIndex) -> DispatchResult { + for currency in CurrentStakingRound::::iter_keys() { + Self::handle_update_staking_round(era_index, currency)?; + } + Ok(()) + } + + #[transactional] + pub fn update_current_era(era_index: EraIndex) -> DispatchResult { + let previous_era = Self::relay_chain_current_era(); + let new_era = previous_era.saturating_add(era_index); + + RelayChainCurrentEra::::put(new_era); + // LastEraUpdatedBlock::::put(T::RelayChainBlockNumber::current_block_number()); + LastEraUpdatedBlock::::put(>::block_number()); + Self::handle_redeem_requests(new_era)?; + Self::handle_reward_distribution_to_network_pool()?; + Self::handle_reward_distribution_to_pool_treasury(previous_era, new_era)?; + Self::deposit_event(Event::::CurrentEraUpdated { new_era_index: new_era }); + Ok(()) + } + + pub fn get_pool_account() -> T::AccountId { + T::PoolAccount::get().into_account_truncating() + } + + pub fn get_pool_treasury(pool_id: PoolId) -> T::AccountId { + return T::PoolAccount::get().into_sub_account_truncating(pool_id); + } + + pub fn get_reward_payout_account_id() -> T::AccountId { + T::RewardPayoutAccount::get().into_account_truncating() + } + + pub fn get_reward_holding_account_id() -> T::AccountId { + T::RewardHoldingAccount::get().into_account_truncating() + } + + fn do_claim_rewards(who: T::AccountId, pool_id: PoolId) -> DispatchResult { + if pool_id.is_zero() { + >::claim_rewards(&who, &pool_id); + + PendingRewards::::mutate_exists(pool_id, &who, |maybe_pending_multi_rewards| { + if let Some(pending_multi_rewards) = maybe_pending_multi_rewards { + for (currency_id, pending_reward) in pending_multi_rewards.iter_mut() { + if pending_reward.is_zero() { + continue; + } + + let payout_amount = pending_reward.clone(); + + match Self::payout_reward(pool_id, &who, *currency_id, payout_amount) { + Ok(_) => { + // update state + *pending_reward = Zero::zero(); + + Self::deposit_event(Event::ClaimRewards { + who: who.clone(), + pool: pool_id, + reward_currency_id: FungibleTokenId::NativeToken(0), + claimed_amount: payout_amount, + }); + } + Err(e) => { + log::error!( + target: "spp", + "payout_reward: failed to payout {:?} to {:?} to pool {:?}: {:?}", + pending_reward, who, pool_id, e + ); + } + } + } + } + }) + } + + Ok(()) + } + + /// Ensure atomic + #[transactional] + fn payout_reward( + pool_id: PoolId, + who: &T::AccountId, + reward_currency_id: FungibleTokenId, + payout_amount: BalanceOf, + ) -> DispatchResult { + T::MultiCurrency::transfer( + reward_currency_id, + &Self::get_reward_payout_account_id(), + who, + payout_amount, + )?; + Ok(()) + } +} + +impl RewardHandler for Pallet { + type Balance = BalanceOf; + type PoolId = PoolId; + + /// This function trigger by orml_reward claim_rewards, it will modify and add pending reward + /// into PendingRewards for users to claim + fn payout(who: &T::AccountId, pool_id: &Self::PoolId, currency_id: FungibleTokenId, payout_amount: Self::Balance) { + if payout_amount.is_zero() { + return; + } + PendingRewards::::mutate(pool_id, who, |rewards| { + rewards + .entry(currency_id) + .and_modify(|current| *current = current.saturating_add(payout_amount)) + .or_insert(payout_amount); + }); + } +} diff --git a/pallets/spp/src/mock.rs b/pallets/spp/src/mock.rs new file mode 100644 index 000000000..d5a05cb21 --- /dev/null +++ b/pallets/spp/src/mock.rs @@ -0,0 +1,297 @@ +#![cfg(test)] + +use frame_support::traits::Nothing; +use frame_support::{construct_runtime, ord_parameter_types, parameter_types, PalletId}; +use frame_system::EnsureSignedBy; +use orml_traits::parameter_type_with_key; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{ConvertInto, IdentityLookup}, + DispatchError, Perbill, +}; +use sp_std::collections::btree_map::BTreeMap; +use sp_std::default::Default; +use sp_std::vec::Vec; + +use asset_manager::ForeignAssetMapping; +use auction_manager::{Auction, AuctionInfo, AuctionItem, AuctionType, CheckAuctionItemHandler, ListingLevel}; +use core_primitives::{CollectionType, NftClassData, TokenType}; +use primitives::{ + Amount, AssetId, Attributes, AuctionId, ClassId, FungibleTokenId, GroupCollectionId, NftMetadata, PoolId, TokenId, + LAND_CLASS_ID, +}; + +use crate as spp; + +use super::*; + +pub type AccountId = u128; +pub type Balance = u128; +pub type MetaverseId = u64; +pub type BlockNumber = u64; +pub type EstateId = u64; + +pub const ALICE: AccountId = 1; +pub const BOB: AccountId = 5; +pub const CHARLIE: AccountId = 6; +pub const DOM: AccountId = 7; +pub const BENEFICIARY_ID: AccountId = 99; +pub const AUCTION_BENEFICIARY_ID: AccountId = 100; +pub const CLASS_FUND_ID: AccountId = 123; +pub const METAVERSE_ID: MetaverseId = 0; +pub const DOLLARS: Balance = 1_000_000_000_000_000_000; + +pub const BOND_AMOUNT_1: Balance = 1000; +pub const BOND_AMOUNT_2: Balance = 2000; +pub const BOND_AMOUNT_BELOW_MINIMUM: Balance = 100; +pub const BOND_LESS_AMOUNT_1: Balance = 100; + +ord_parameter_types! { + pub const One: AccountId = ALICE; + pub const Admin: AccountId = ALICE; +} + +// Configure a mock runtime to test the pallet. + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = BlockNumber; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = frame_support::traits::Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 1; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); +} + +// pub type AdaptedBasicCurrency = +// currencies::BasicCurrencyAdapter; + +parameter_types! { + pub const GetNativeCurrencyId: FungibleTokenId = FungibleTokenId::NativeToken(0); + pub const PoolAccountPalletId: PalletId = PalletId(*b"bit/pool"); + pub const RewardPayoutAccount: PalletId = PalletId(*b"bit/payo"); + pub const RewardHoldingAccount: PalletId = PalletId(*b"bit/hold"); +} + +fn test_attributes(x: u8) -> Attributes { + let mut attr: Attributes = BTreeMap::new(); + attr.insert(vec![x, x + 5], vec![x, x + 10]); + attr +} + +parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: FungibleTokenId| -> Balance { + Default::default() + }; +} + +impl orml_tokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Amount = Amount; + type CurrencyId = FungibleTokenId; + type WeightInfo = (); + type ExistentialDeposits = ExistentialDeposits; + type CurrencyHooks = (); + type MaxLocks = (); + type ReserveIdentifier = [u8; 8]; + type MaxReserves = (); + type DustRemovalWhitelist = Nothing; +} + +pub type AdaptedBasicCurrency = currencies::BasicCurrencyAdapter; + +parameter_types! { + pub const NativeCurrencyId: FungibleTokenId = FungibleTokenId::NativeToken(0); + pub const MiningCurrencyId: FungibleTokenId = FungibleTokenId::MiningResource(0); +} + +impl currencies::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MultiSocialCurrency = Tokens; + type NativeCurrency = AdaptedBasicCurrency; + type GetNativeCurrencyId = NativeCurrencyId; + type WeightInfo = (); +} + +impl asset_manager::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type RegisterOrigin = EnsureSignedBy; +} + +impl BlockNumberProvider for MockRelayBlockNumberProvider { + type BlockNumber = BlockNumber; + + fn current_block_number() -> Self::BlockNumber { + Self::get() + } +} + +impl orml_rewards::Config for Runtime { + type Share = Balance; + type Balance = Balance; + type PoolId = PoolId; + type CurrencyId = FungibleTokenId; + type Handler = SppModule; +} + +parameter_types! { + pub const MinBlocksPerRound: u32 = 10; + pub const MinimumStake: Balance = 200; + /// Reward payments are delayed by 2 hours (2 * 300 * block_time) + pub const RewardPaymentDelay: u32 = 2; + pub const NetworkFee: Balance = 1; // Network fee + pub const MaxOffersPerEstate: u32 = 2; + pub const MinLeasePricePerBlock: Balance = 1u128; + pub const MaxLeasePeriod: u32 = 9; + pub const LeaseOfferExpiryPeriod: u32 = 6; + pub StorageDepositFee: Balance = 1; + pub const MaximumQueue: u32 = 50; + pub static MockRelayBlockNumberProvider: BlockNumber = 0; +} + +impl Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type WeightInfo = (); + type MinimumStake = MinimumStake; + type NetworkFee = NetworkFee; + type StorageDepositFee = StorageDepositFee; + type MultiCurrency = Currencies; + type PoolAccount = PoolAccountPalletId; + type MaximumQueue = MaximumQueue; + type CurrencyIdConversion = ForeignAssetMapping; + type RelayChainBlockNumber = MockRelayBlockNumberProvider; + type GovernanceOrigin = EnsureSignedBy; + type RewardPayoutAccount = RewardPayoutAccount; + type RewardHoldingAccount = RewardHoldingAccount; +} + +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + AssetManager: asset_manager::{ Pallet, Storage, Call, Event}, + Currencies: currencies::{ Pallet, Storage, Call, Event}, + Tokens: orml_tokens::{Pallet, Call, Storage, Config, Event}, + Spp: spp:: {Pallet, Call, Storage, Event}, + RewardsModule: orml_rewards + } +); + +pub type SppModule = Pallet; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +pub struct ExtBuilder { + endowed_accounts: Vec<(AccountId, FungibleTokenId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + endowed_accounts: vec![], + } + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, 1000000000), (BOB, 100000), (CHARLIE, 100000), (DOM, 100000)], + } + .assimilate_storage(&mut t) + .unwrap(); + + orml_tokens::GenesisConfig:: { + balances: self.endowed_accounts.into_iter().collect::>(), + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } + + pub fn balances(mut self, endowed_accounts: Vec<(AccountId, FungibleTokenId, Balance)>) -> Self { + self.endowed_accounts = endowed_accounts; + self + } + + pub fn ksm_setup_for_alice_and_bob(self) -> Self { + self.balances(vec![ + (ALICE, FungibleTokenId::NativeToken(1), 200000000000), //KSM + (BOB, FungibleTokenId::NativeToken(1), 200000000000), //KSM + ]) + } +} + +pub fn last_event() -> RuntimeEvent { + frame_system::Pallet::::events() + .pop() + .expect("Event expected") + .event +} + +fn next_block() { + SppModule::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); +} + +pub fn run_to_block(n: u64) { + while System::block_number() < n { + next_block(); + } +} diff --git a/pallets/spp/src/tests.rs b/pallets/spp/src/tests.rs new file mode 100644 index 000000000..e1afb21ba --- /dev/null +++ b/pallets/spp/src/tests.rs @@ -0,0 +1,781 @@ +// This file is part of Metaverse.Network & Bit.Country. + +// Copyright (C) 2020-2022 Metaverse.Network & Bit.Country . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +use frame_support::{assert_err, assert_noop, assert_ok}; +use pallet_balances::BalanceLock; +use sp_runtime::traits::BadOrigin; +use sp_runtime::{Perbill, Permill}; + +use mock::{RuntimeEvent, *}; +use primitives::bounded::FractionalRate; + +use crate::utils::{BoostInfo, BoostingConviction, BoostingRecord, PoolInfo, PriorLock}; + +use super::*; + +#[test] +fn test_one() { + ExtBuilder::default().build().execute_with(|| assert_eq!(1, 1)); +} + +fn the_lock(amount: Balance) -> BalanceLock { + BalanceLock { + id: BOOSTING_ID, + amount, + reasons: pallet_balances::Reasons::Misc, + } +} + +#[test] +fn create_ksm_pool_works() { + ExtBuilder::default() + .ksm_setup_for_alice_and_bob() + .build() + .execute_with(|| { + + // Create the first pool + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(ALICE), + FungibleTokenId::NativeToken(1), + 50, + Rate::saturating_from_rational(5, 100) + )); + + // Check the next pool id will increment + let next_pool_id: u32 = NextPoolId::::get(); + assert_eq!(next_pool_id, 2); + + // Check if the pool details as expected. + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: ALICE, + commission: Rate::saturating_from_rational(5, 100), + currency_id: FungibleTokenId::NativeToken(1), + max: 50 + } + ); + + // Create a second pool + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(BOB), + FungibleTokenId::NativeToken(1), + 10, + Permill::from_percent(1) + )); + + // Check Id will increment + let next_pool_id: u32 = NextPoolId::::get(); + assert_eq!(next_pool_id, 3); + // Check the second pool has the right information as expected + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: BOB, + commission: Permill::from_percent(1), + currency_id: FungibleTokenId::NativeToken(1), + max: 10 + } + ); + }); +} + +#[test] +fn deposit_ksm_works() { + ExtBuilder::default() + .ksm_setup_for_alice_and_bob() + .build() + .execute_with(|| { + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(ALICE), + FungibleTokenId::NativeToken(1), + 50, + Rate::saturating_from_rational(5, 100) + )); + + let next_pool_id = NextPoolId::::get(); + assert_eq!(next_pool_id, 2); + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: ALICE, + commission: Rate::saturating_from_rational(5, 100), + currency_id: FungibleTokenId::NativeToken(1), + max: 50 + } + ); + + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + // This is true because fee hasn't been set up. + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 10000); + + assert_eq!(PoolLedger::::get(1), 10000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 10000); + + // Deposit another 10000 KSM + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 20000); + + assert_eq!(PoolLedger::::get(1), 20000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 20000); + }); +} + +#[test] +fn redeem_rksm_request_works() { + ExtBuilder::default() + .ksm_setup_for_alice_and_bob() + .build() + .execute_with(|| { + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(ALICE), + FungibleTokenId::NativeToken(1), + 50, + Rate::saturating_from_rational(5, 100) + )); + + let next_pool_id = NextPoolId::::get(); + assert_eq!(next_pool_id, 2); + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: ALICE, + commission: Rate::saturating_from_rational(5, 100), + currency_id: FungibleTokenId::NativeToken(1), + max: 50 + } + ); + + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + // This is true because fee hasn't been set up. + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 10000); + + assert_eq!(PoolLedger::::get(1), 10000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 10000); + + // Deposit another 10000 KSM + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 20000); + + assert_eq!(PoolLedger::::get(1), 20000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 20000); + + assert_noop!( + SppModule::redeem(RuntimeOrigin::signed(BOB), 2, FungibleTokenId::FungibleToken(1), 10000), + Error::::PoolDoesNotExist + ); + + assert_noop!( + SppModule::redeem(RuntimeOrigin::signed(BOB), 1, FungibleTokenId::FungibleToken(0), 10000), + Error::::CurrencyIsNotSupported + ); + + assert_noop!( + SppModule::redeem(RuntimeOrigin::signed(BOB), 1, FungibleTokenId::FungibleToken(1), 10000), + Error::::NoCurrentStakingRound + ); + + UnlockDuration::::insert(FungibleTokenId::NativeToken(1), StakingRound::Era(1)); + // Bump current staking round to 1 + CurrentStakingRound::::insert(FungibleTokenId::NativeToken(1), StakingRound::Era(1)); + assert_ok!(SppModule::redeem( + RuntimeOrigin::signed(BOB), + 1, + FungibleTokenId::FungibleToken(1), + 10000 + )); + + // After Bob redeems, pool ledger 1 should have only 10000 + assert_eq!(PoolLedger::::get(1), 10000); + + // Verify if redeem queue has requests + + let queue_id = QueueNextId::::get(FungibleTokenId::NativeToken(1)); + assert_eq!(queue_id, 1); + let mut queue_items = BoundedVec::default(); + assert_ok!(queue_items.try_push(0)); + let user_redeem_queue = UserCurrencyRedeemQueue::::get(BOB, FungibleTokenId::NativeToken(1)); + let currency_redeem_queue = CurrencyRedeemQueue::::get(FungibleTokenId::NativeToken(1), 0); + let staking_round_redeem_queue = + StakingRoundRedeemQueue::::get(StakingRound::Era(2), FungibleTokenId::NativeToken(1)); + // Verify if user redeem queue has total unlocked and queue items + assert_eq!(user_redeem_queue, Some((10000, queue_items.clone()))); + // If user redeem of Era 1, fund will be released at Era 2 + assert_eq!(currency_redeem_queue, Some((BOB, 10000, StakingRound::Era(2)))); + // Redeem added into staking round redeem queue for Era 2 + assert_eq!( + staking_round_redeem_queue, + Some((10000, queue_items.clone(), FungibleTokenId::NativeToken(1))) + ); + }); +} + +#[test] +fn current_era_update_works() { + ExtBuilder::default() + .ksm_setup_for_alice_and_bob() + .build() + .execute_with(|| { + assert_eq!(SppModule::last_era_updated_block(), 0); + assert_eq!(SppModule::update_era_frequency(), 0); + assert_eq!(MockRelayBlockNumberProvider::current_block_number(), 0); + // Current relaychain block is 102. + MockRelayBlockNumberProvider::set(102); + RelayChainCurrentEra::::put(1); + IterationLimit::::put(50); + // The correct set up era config is the last era block records is 101 with duration is 100 blocks + assert_ok!(SppModule::update_era_config( + RuntimeOrigin::signed(Admin::get()), + Some(101), + Some(100), + StakingRound::Era(1), + Some(Rate::saturating_from_rational(35, 100000)) + )); + + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(ALICE), + FungibleTokenId::NativeToken(1), + 50, + Rate::saturating_from_rational(5, 100) + )); + + let next_pool_id = NextPoolId::::get(); + assert_eq!(next_pool_id, 2); + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: ALICE, + commission: Rate::saturating_from_rational(5, 100), + currency_id: FungibleTokenId::NativeToken(1), + max: 50, + } + ); + // Verify BOB account with 20000 KSM + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::NativeToken(1)).free, 20000); + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + // This is true because fee hasn't been set up. + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 10000); + // Bob KSM balance become 10000 + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::NativeToken(1)).free, 10000); + + assert_eq!(PoolLedger::::get(1), 10000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 10000); + + // Deposit another 10000 KSM + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 20000); + // Bob KSM now is 0 + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::NativeToken(1)).free, 0); + + assert_eq!(PoolLedger::::get(1), 20000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 20000); + + // Pool summary + // Pool Total deposited: 20000 + // Network deposited: 20000, NativeToken(1) + + // Bob summary + // Holding: 20000 FungibleToken(1) reciept token of NativeToken(1) + + assert_noop!( + SppModule::redeem(RuntimeOrigin::signed(BOB), 2, FungibleTokenId::FungibleToken(1), 10000), + Error::::PoolDoesNotExist + ); + + assert_noop!( + SppModule::redeem(RuntimeOrigin::signed(BOB), 1, FungibleTokenId::FungibleToken(0), 10000), + Error::::CurrencyIsNotSupported + ); + + assert_noop!( + SppModule::redeem(RuntimeOrigin::signed(BOB), 1, FungibleTokenId::FungibleToken(1), 10000), + Error::::NoCurrentStakingRound + ); + + UnlockDuration::::insert(FungibleTokenId::NativeToken(1), StakingRound::Era(1)); // Bump current staking round to 1 + CurrentStakingRound::::insert(FungibleTokenId::NativeToken(1), StakingRound::Era(1)); + + // Bob successfully redeemed + assert_ok!(SppModule::redeem( + RuntimeOrigin::signed(BOB), + 1, + FungibleTokenId::FungibleToken(1), + 10000 + )); + + // After Bob redeems, pool ledger 0 should have only 10000 + assert_eq!(PoolLedger::::get(1), 10000); + + // After Bob redeem, make sure BOB KSM balance remains the same as it will only released next era + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::NativeToken(1)).free, 0); + + // Verify if redeem queue has requests + let queue_id = QueueNextId::::get(FungibleTokenId::NativeToken(1)); + assert_eq!(queue_id, 1); + let mut queue_items = BoundedVec::default(); + assert_ok!(queue_items.try_push(0)); + let user_redeem_queue = UserCurrencyRedeemQueue::::get(BOB, FungibleTokenId::NativeToken(1)); + let currency_redeem_queue = CurrencyRedeemQueue::::get(FungibleTokenId::NativeToken(1), 0); + let staking_round_redeem_queue = + StakingRoundRedeemQueue::::get(StakingRound::Era(2), FungibleTokenId::NativeToken(1)); + // Verify if user redeem queue has total unlocked and queue items + assert_eq!(user_redeem_queue, Some((10000, queue_items.clone()))); + // If user redeem of Era 1, fund will be released at Era 2 + assert_eq!(currency_redeem_queue, Some((BOB, 10000, StakingRound::Era(2)))); + // Redeem added into staking round redeem queue for Era 2 + assert_eq!( + staking_round_redeem_queue, + Some((10000, queue_items.clone(), FungibleTokenId::NativeToken(1))) + ); + + // Move to era 2 to allow user redeem token successfully + MockRelayBlockNumberProvider::set(202); + SppModule::on_initialize(200); + + let pool_account = SppModule::get_pool_account(); + assert_eq!( + Tokens::accounts(pool_account, FungibleTokenId::NativeToken(1)).free, + 10001 + ); + + // After KSM released, BOB balance now is + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::NativeToken(1)).free, 10000); + assert_eq!( + CurrencyRedeemQueue::::get(FungibleTokenId::NativeToken(1), 0), + None + ); + assert_eq!( + UserCurrencyRedeemQueue::::get(BOB, FungibleTokenId::NativeToken(1)), + None + ); + assert_eq!( + StakingRoundRedeemQueue::::get(StakingRound::Era(2), FungibleTokenId::NativeToken(1)), + None + ); + + // Move to era 3, make sure no double redeem process + MockRelayBlockNumberProvider::set(302); + SppModule::on_initialize(300); + + // Pool account remain the same + assert_eq!( + Tokens::accounts(pool_account, FungibleTokenId::NativeToken(1)).free, + 10001 + ); + + // BOB balance remain the same + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::NativeToken(1)).free, 10000); + assert_eq!( + CurrencyRedeemQueue::::get(FungibleTokenId::NativeToken(1), 0), + None + ); + assert_eq!( + UserCurrencyRedeemQueue::::get(BOB, FungibleTokenId::NativeToken(1)), + None + ); + assert_eq!( + StakingRoundRedeemQueue::::get(StakingRound::Era(2), FungibleTokenId::NativeToken(1)), + None + ); + assert_eq!( + StakingRoundRedeemQueue::::get(StakingRound::Era(3), FungibleTokenId::NativeToken(1)), + None + ); + }); +} + +#[test] +fn boosting_works() { + ExtBuilder::default() + .ksm_setup_for_alice_and_bob() + .build() + .execute_with(|| { + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(ALICE), + FungibleTokenId::NativeToken(1), + 50, + Rate::saturating_from_rational(5, 100) + )); + + let next_pool_id = NextPoolId::::get(); + assert_eq!(next_pool_id, 2); + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: ALICE, + commission: Rate::saturating_from_rational(5, 100), + currency_id: FungibleTokenId::NativeToken(1), + max: 50 + } + ); + + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + // This is true because fee hasn't been set up. + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 10000); + + assert_eq!(PoolLedger::::get(1), 10000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 10000); + + // Deposit another 10000 KSM + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 20000); + + assert_eq!(PoolLedger::::get(1), 20000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 20000); + + // Boosting works + let bob_free_balance = Balances::free_balance(BOB); + assert_ok!(SppModule::boost( + RuntimeOrigin::signed(BOB), + 1, + BoostInfo { + balance: bob_free_balance, + conviction: BoostingConviction::None + } + )); + let boosting_of = BoostingOf::::get(BOB); + let some_record = BoostingRecord { + votes: vec![( + 1, + BoostInfo { + balance: bob_free_balance, + conviction: BoostingConviction::None, + }, + )], + prior: PriorLock(1, bob_free_balance), + }; + assert_eq!(boosting_of, some_record); + assert_eq!(Balances::usable_balance(&BOB), 0); + let pool_1_shared_rewards = RewardsModule::shares_and_withdrawn_rewards(1, BOB); + let network_shared_rewards = RewardsModule::shares_and_withdrawn_rewards(0, BOB); + assert_eq!(pool_1_shared_rewards, (bob_free_balance, Default::default())); + assert_eq!(network_shared_rewards, (bob_free_balance, Default::default())); + }); +} + +#[test] +fn boosting_and_claim_reward_works() { + ExtBuilder::default() + .ksm_setup_for_alice_and_bob() + .build() + .execute_with(|| { + // Era config set up + // Current relaychain block is 102. + MockRelayBlockNumberProvider::set(102); + RelayChainCurrentEra::::put(1); + IterationLimit::::put(50); + // The correct set up era config is the last era block records is 101 with duration is 100 blocks + assert_ok!(SppModule::update_era_config( + RuntimeOrigin::signed(Admin::get()), + Some(101), + Some(100), + StakingRound::Era(1), + Some(Rate::saturating_from_rational(35, 100000)) + )); + + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(ALICE), + FungibleTokenId::NativeToken(1), + 50, + Rate::saturating_from_rational(5, 100) + )); + + let next_pool_id = NextPoolId::::get(); + assert_eq!(next_pool_id, 2); + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: ALICE, + commission: Rate::saturating_from_rational(5, 100), + currency_id: FungibleTokenId::NativeToken(1), + max: 50 + } + ); + + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + // This is true because fee hasn't been set up. + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 10000); + + assert_eq!(PoolLedger::::get(1), 10000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 10000); + + // Deposit another 10000 KSM + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 20000); + + assert_eq!(PoolLedger::::get(1), 20000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 20000); + + // Boosting works + let bob_free_balance = Balances::free_balance(BOB); + assert_ok!(SppModule::boost( + RuntimeOrigin::signed(BOB), + 1, + BoostInfo { + balance: 15000, + conviction: BoostingConviction::None + } + )); + let boosting_of = BoostingOf::::get(BOB); + let some_record = BoostingRecord { + votes: vec![( + 1, + BoostInfo { + balance: 15000, + conviction: BoostingConviction::None, + }, + )], + prior: PriorLock(101, 15000), + }; + assert_eq!(boosting_of, some_record); + assert_eq!(Balances::usable_balance(&BOB), bob_free_balance - 15000); + let pool_1_shared_rewards = RewardsModule::shares_and_withdrawn_rewards(1, BOB); + let network_shared_rewards = RewardsModule::shares_and_withdrawn_rewards(0, BOB); + assert_eq!(pool_1_shared_rewards, (15000, Default::default())); + assert_eq!(network_shared_rewards, (15000, Default::default())); + + // Set reward per era. - 1000 NativeToken(0) per 100 blocks + RewardEraFrequency::::put(1000); + // Simulate Council transfer 10000 NativeToken to reward_payout_account so that account has + // sufficient balance for reward distribution + let reward_holding_account = SppModule::get_reward_holding_account_id(); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(ALICE), + reward_holding_account.clone(), + 10000 + )); + + // Move to era 2, now protocol distribute 1000 NEER to incentivise boosters + MockRelayBlockNumberProvider::set(202); + SppModule::on_initialize(200); + + let network_reward_pool = RewardsModule::pool_infos(0u32); + let reward_accumulated = RewardsModule::shares_and_withdrawn_rewards(0, BOB); + + // Verify after 1 era, total rewards should have 1000 NEER and 0 claimed + assert_eq!( + network_reward_pool, + orml_rewards::PoolInfo { + total_shares: 15000, + rewards: vec![(FungibleTokenId::NativeToken(0), (1000, 0))].into_iter().collect() + } + ); + + // Reward records of BOB holding 15000 shares and 0 claimed + assert_eq!(reward_accumulated, (15000, Default::default())); + // Reward distribution works, now claim rewards + let bob_balance_before_claiming_boosting_reward = Balances::free_balance(BOB); + // Bob claim rewards + assert_ok!(SppModule::claim_rewards(RuntimeOrigin::signed(BOB), 0)); + assert_eq!( + last_event(), + mock::RuntimeEvent::Spp(crate::Event::ClaimRewards { + who: BOB, + pool: 0, + reward_currency_id: FungibleTokenId::NativeToken(0), + claimed_amount: 1000, + }) + ); + + // Bob free balance now will be bob_balance_before_claiming_boosting_reward + 1000 as claimed reward + assert_eq!( + Balances::free_balance(BOB), + bob_balance_before_claiming_boosting_reward + 1000 + ); + + // Bob try to claim again but getting no reward + assert_ok!(SppModule::claim_rewards(RuntimeOrigin::signed(BOB), 0)); + // Bob balance doesn't increase + assert_eq!( + Balances::free_balance(BOB), + bob_balance_before_claiming_boosting_reward + 1000 + ); + + // Move to era 3, now protocol distribute another 1000 NEER to incentivise boosters + MockRelayBlockNumberProvider::set(302); + SppModule::on_initialize(300); + + // Bob try to claim reward for new era + assert_ok!(SppModule::claim_rewards(RuntimeOrigin::signed(BOB), 0)); + // Bob balance should increase 2000 + assert_eq!( + Balances::free_balance(BOB), + bob_balance_before_claiming_boosting_reward + 2000 + ); + + // Charlie now boost pool 1 with 15000 (share 50% of reward with Bob) + assert_ok!(SppModule::boost( + RuntimeOrigin::signed(CHARLIE), + 1, + BoostInfo { + balance: 15000, + conviction: BoostingConviction::None + } + )); + // Charlie now should have 15000 shares in the pool + assert_eq!( + RewardsModule::shares_and_withdrawn_rewards(1, CHARLIE), + (15000, Default::default()) + ); + + // Network pool ledger should have total shares of 30,000 , 2000 total reward and claimed 2000 by + // Bob. However, as Charlie boosted, network pool inflate 15,000 shares, added 50% reward and 50% + // claimed reward to avoid dilution. + assert_eq!( + RewardsModule::pool_infos(0u32), + orml_rewards::PoolInfo { + total_shares: 30000, + rewards: vec![(FungibleTokenId::NativeToken(0), (4000, 4000))] + .into_iter() + .collect() + } + ); + + let charlie_balance_before_claiming_boosting_reward = Balances::free_balance(CHARLIE); + + // Move to era 4, now protocol distribute another 1000 NEER to incentivise boosters + MockRelayBlockNumberProvider::set(402); + SppModule::on_initialize(400); + + // Bob try to claim reward for new era + assert_ok!(SppModule::claim_rewards(RuntimeOrigin::signed(BOB), 0)); + // Bob balance should increase 500 as Charlie shares 50% rewards + assert_eq!( + Balances::free_balance(BOB), + bob_balance_before_claiming_boosting_reward + 2500 + ); + + // Charlie try to claim reward for new era + assert_ok!(SppModule::claim_rewards(RuntimeOrigin::signed(CHARLIE), 0)); + // Charlie balance should increase 500 + assert_eq!( + Balances::free_balance(CHARLIE), + charlie_balance_before_claiming_boosting_reward + 500 + ); + }); +} + +#[test] +fn reward_distribution_works() { + ExtBuilder::default() + .ksm_setup_for_alice_and_bob() + .build() + .execute_with(|| { + // Era config set up + // Current relaychain block is 102. + MockRelayBlockNumberProvider::set(102); + RelayChainCurrentEra::::put(1); + IterationLimit::::put(50); + UnlockDuration::::insert(FungibleTokenId::NativeToken(1), StakingRound::Era(1)); // Bump current staking round to 1 + CurrentStakingRound::::insert(FungibleTokenId::NativeToken(1), StakingRound::Era(1)); + // The correct set up era config is the last era block records is 101 with duration is 100 blocks + assert_ok!(SppModule::update_era_config( + RuntimeOrigin::signed(Admin::get()), + Some(101), + Some(100), + StakingRound::Era(1), + Some(Rate::saturating_from_rational(20, 100)) // Set reward rate per era is 20%. + )); + + assert_ok!(SppModule::create_pool( + RuntimeOrigin::signed(ALICE), + FungibleTokenId::NativeToken(1), + 50, + Rate::saturating_from_rational(5, 100) + )); + + let next_pool_id = NextPoolId::::get(); + assert_eq!(next_pool_id, 2); + assert_eq!( + Pool::::get(next_pool_id - 1).unwrap(), + PoolInfo:: { + creator: ALICE, + commission: Rate::saturating_from_rational(5, 100), + currency_id: FungibleTokenId::NativeToken(1), + max: 50 + } + ); + + assert_ok!(SppModule::deposit(RuntimeOrigin::signed(BOB), 1, 10000)); + // This is true because fee hasn't been set up. + assert_eq!(Tokens::accounts(BOB, FungibleTokenId::FungibleToken(1)).free, 10000); + + assert_eq!(PoolLedger::::get(1), 10000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 10000); + + // Boosting works + let bob_free_balance = Balances::free_balance(BOB); + assert_ok!(SppModule::boost( + RuntimeOrigin::signed(BOB), + 1, + BoostInfo { + balance: 15000, + conviction: BoostingConviction::None + } + )); + let boosting_of = BoostingOf::::get(BOB); + let some_record = BoostingRecord { + votes: vec![( + 1, + BoostInfo { + balance: 15000, + conviction: BoostingConviction::None, + }, + )], + prior: PriorLock(101, 15000), + }; + assert_eq!(boosting_of, some_record); + assert_eq!(Balances::usable_balance(&BOB), bob_free_balance - 15000); + let pool_1_shared_rewards = RewardsModule::shares_and_withdrawn_rewards(1, BOB); + let network_shared_rewards = RewardsModule::shares_and_withdrawn_rewards(0, BOB); + assert_eq!(pool_1_shared_rewards, (15000, Default::default())); + assert_eq!(network_shared_rewards, (15000, Default::default())); + + // Charlie boosted with 15000 Native token + assert_ok!(SppModule::boost( + RuntimeOrigin::signed(CHARLIE), + 1, + BoostInfo { + balance: 15000, + conviction: BoostingConviction::None + } + )); + // Charlie now should have 15000 shares in the pool + assert_eq!( + RewardsModule::shares_and_withdrawn_rewards(1, CHARLIE), + (15000, Default::default()) + ); + + // Move to era 2 + MockRelayBlockNumberProvider::set(202); + SppModule::on_initialize(200); + + assert_ok!(SppModule::handle_reward_distribution_to_pool_treasury(1, 2)); + let pool_treasury = SppModule::get_pool_treasury(1); + + assert_eq!( + Currencies::free_balance(FungibleTokenId::FungibleToken(1), &pool_treasury), + 20 + ); + + assert_eq!(Currencies::total_issuance(FungibleTokenId::FungibleToken(1)), 10020); + assert_eq!(PoolLedger::::get(1), 12000); + assert_eq!(NetworkLedger::::get(FungibleTokenId::NativeToken(1)), 12000); + }); +} diff --git a/pallets/spp/src/utils.rs b/pallets/spp/src/utils.rs new file mode 100644 index 000000000..f5c70a688 --- /dev/null +++ b/pallets/spp/src/utils.rs @@ -0,0 +1,205 @@ +// This file is part of Metaverse.Network & Bit.Country. + +// Copyright (C) 2020-2022 Metaverse.Network & Bit.Country . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_runtime::{ + traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, IntegerSquareRoot, Saturating, Zero}, + Permill, RuntimeDebug, +}; +use sp_std::vec::Vec; + +use primitives::bounded::{FractionalRate, Rate}; +use primitives::{FungibleTokenId, PoolId}; + +// Helper methods to compute the issuance rate for undeployed land. + +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(Eq, PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PoolInfo { + pub creator: AccountId, + pub commission: Rate, + /// Currency id of the pool + pub currency_id: FungibleTokenId, + /// Max nft rewards + pub max: u32, +} + +/// Amount of votes and capital placed in delegation for an account. +#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct BoostingDelegations { + /// The number of votes (this is post-conviction). + pub votes: Balance, + /// The amount of raw capital, used for the turnout. + pub capital: Balance, +} + +/// A value denoting the strength of conviction of a vote. +#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo)] +pub enum BoostingConviction { + /// 0.1x votes, unlocked. + None, + /// 1x votes, locked for an enactment period following a successful vote. + Locked1x, + /// 2x votes, locked for 2x enactment periods following a successful vote. + Locked2x, + /// 3x votes, locked for 4x... + Locked3x, + /// 4x votes, locked for 8x... + Locked4x, + /// 5x votes, locked for 16x... + Locked5x, + /// 6x votes, locked for 32x... + Locked6x, +} + +impl Default for BoostingConviction { + fn default() -> Self { + BoostingConviction::None + } +} + +impl From for u8 { + fn from(c: BoostingConviction) -> u8 { + match c { + BoostingConviction::None => 0, + BoostingConviction::Locked1x => 1, + BoostingConviction::Locked2x => 2, + BoostingConviction::Locked3x => 3, + BoostingConviction::Locked4x => 4, + BoostingConviction::Locked5x => 5, + BoostingConviction::Locked6x => 6, + } + } +} + +impl TryFrom for BoostingConviction { + type Error = (); + fn try_from(i: u8) -> Result { + Ok(match i { + 0 => BoostingConviction::None, + 1 => BoostingConviction::Locked1x, + 2 => BoostingConviction::Locked2x, + 3 => BoostingConviction::Locked3x, + 4 => BoostingConviction::Locked4x, + 5 => BoostingConviction::Locked5x, + 6 => BoostingConviction::Locked6x, + _ => return Err(()), + }) + } +} + +impl BoostingConviction { + /// The amount of time (in number of periods) that our conviction implies a successful voter's + /// balance should be locked for. + pub fn lock_periods(self) -> u32 { + match self { + BoostingConviction::None => 0, + BoostingConviction::Locked1x => 1, + BoostingConviction::Locked2x => 2, + BoostingConviction::Locked3x => 4, + BoostingConviction::Locked4x => 8, + BoostingConviction::Locked5x => 16, + BoostingConviction::Locked6x => 32, + } + } + + /// The votes of a voter of the given `balance` with our conviction. + pub fn votes + Zero + Copy + CheckedMul + CheckedDiv + Bounded>( + self, + capital: B, + ) -> BoostingDelegations { + let votes = match self { + BoostingConviction::None => capital.checked_div(&10u8.into()).unwrap_or_else(Zero::zero), + x => capital.checked_mul(&u8::from(x).into()).unwrap_or_else(B::max_value), + }; + BoostingDelegations { votes, capital } + } +} + +impl Bounded for BoostingConviction { + fn min_value() -> Self { + BoostingConviction::None + } + fn max_value() -> Self { + BoostingConviction::Locked6x + } +} + +#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct BoostInfo { + pub(crate) balance: Balance, + pub(crate) conviction: BoostingConviction, +} + +impl BoostInfo { + /// Returns `Some` of the lock periods that the account is locked for, assuming that the + /// referendum passed if `approved` is `true`. + pub fn get_locked_period(self) -> (u32, Balance) { + return (self.conviction.lock_periods(), self.balance); + } + + pub fn add(&mut self, balance: Balance) -> Option<()> { + self.balance.saturating_add(balance.into()); + Some(()) + } +} + +/// A "prior" lock, i.e. a lock for some now-forgotten reason. +#[derive(Encode, Decode, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo)] +pub struct PriorLock(pub(crate) BlockNumber, pub(crate) Balance); + +impl PriorLock { + /// Accumulates an additional lock. + pub fn accumulate(&mut self, until: BlockNumber, amount: Balance) { + self.0 = self.0.max(until); + self.1 = self.1.max(amount); + } + + pub fn locked(&self) -> Balance { + self.1 + } + + pub fn update(&mut self, now: BlockNumber) { + if now >= self.0 { + self.0 = Zero::zero(); + self.1 = Zero::zero(); + } + } +} + +#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct BoostingRecord { + pub(crate) votes: Vec<(PoolId, BoostInfo)>, + pub(crate) prior: PriorLock, +} + +impl BoostingRecord { + pub fn update(&mut self, now: BlockNumber) { + self.prior.update(now); + } + + /// The amount of this account's balance that much currently be locked due to voting. + pub fn locked_balance(&self) -> Balance { + self.votes + .iter() + .map(|i| i.1.balance) + .fold(self.prior.locked(), |a, i| a.max(i)) + } +} diff --git a/pallets/spp/src/weights.rs b/pallets/spp/src/weights.rs new file mode 100644 index 000000000..f848ec15c --- /dev/null +++ b/pallets/spp/src/weights.rs @@ -0,0 +1,699 @@ +// This file is part of Metaverse.Network & Bit.Country. + +// Copyright (C) 2020-2022 Metaverse.Network & Bit.Country . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for estate +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-18, STEPS: `20`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/metaverse-node +// benchmark +// pallet +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// estate +// --extrinsic +// * +// --steps +// 20 +// --repeat +// 10 +// --template=./template/weight-template.hbs +// --output +// ./pallets/estate/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for estate. +pub trait WeightInfo { fn mint_land() -> Weight; fn mint_lands() -> Weight; fn transfer_land() -> Weight; fn mint_estate() -> Weight; fn dissolve_estate() -> Weight; fn add_land_unit_to_estate() -> Weight; fn remove_land_unit_from_estate() -> Weight; fn create_estate() -> Weight; fn transfer_estate() -> Weight; fn issue_undeployed_land_blocks() -> Weight; fn freeze_undeployed_land_blocks() -> Weight; fn unfreeze_undeployed_land_blocks() -> Weight; fn approve_undeployed_land_blocks() -> Weight; fn unapprove_undeployed_land_blocks() -> Weight; fn transfer_undeployed_land_blocks() -> Weight; fn deploy_land_block() -> Weight; fn burn_undeployed_land_blocks() -> Weight; fn create_lease_offer() -> Weight; fn accept_lease_offer() -> Weight; fn cancel_lease() -> Weight; fn remove_expired_lease() -> Weight; fn remove_lease_offer() -> Weight; fn collect_rent() -> Weight; fn on_initialize() -> Weight;} + +/// Weights for estate using the for collator node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { // Storage: Estate LandUnits (r:1 w:1) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: Metaverse Metaverses (r:1 w:0) + // Proof Skipped: Metaverse Metaverses (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:1) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: Estate AllLandUnitsCount (r:1 w:1) + // Proof Skipped: Estate AllLandUnitsCount (max_values: Some(1), max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:1) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn mint_land() -> Weight { + // Proof Size summary in bytes: + // Measured: `2339` + // Estimated: `36660` + // Minimum execution time: 56_882 nanoseconds. + Weight::from_parts(59_273_000, 36660) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) + } + // Storage: Estate LandUnits (r:2 w:2) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: Metaverse Metaverses (r:1 w:0) + // Proof Skipped: Metaverse Metaverses (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:2 w:2) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:1) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: Estate AllLandUnitsCount (r:1 w:1) + // Proof Skipped: Estate AllLandUnitsCount (max_values: Some(1), max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:2) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn mint_lands() -> Weight { + // Proof Size summary in bytes: + // Measured: `2339` + // Estimated: `41610` + // Minimum execution time: 82_026 nanoseconds. + Weight::from_parts(83_541_000, 41610) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(10)) + } + // Storage: Estate LandUnits (r:1 w:1) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT StackableCollection (r:1 w:0) + // Proof Skipped: OrmlNFT StackableCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:0) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:2) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn transfer_land() -> Weight { + // Proof Size summary in bytes: + // Measured: `1915` + // Estimated: `28255` + // Minimum execution time: 46_193 nanoseconds. + Weight::from_parts(47_423_000, 28255) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Estate NextEstateId (r:1 w:1) + // Proof Skipped: Estate NextEstateId (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Metaverse Metaverses (r:1 w:0) + // Proof Skipped: Metaverse Metaverses (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:1) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: Estate LandUnits (r:1 w:1) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: Estate AllLandUnitsCount (r:1 w:1) + // Proof Skipped: Estate AllLandUnitsCount (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate AllEstatesCount (r:1 w:1) + // Proof Skipped: Estate AllEstatesCount (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate EstateOwner (r:0 w:1) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Estate Estates (r:0 w:1) + // Proof Skipped: Estate Estates (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:1) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn mint_estate() -> Weight { + // Proof Size summary in bytes: + // Measured: `2356` + // Estimated: `47210` + // Minimum execution time: 62_931 nanoseconds. + Weight::from_parts(64_479_000, 47210) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(11)) + } + // Storage: Estate EstateOwner (r:1 w:1) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:2 w:2) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Estate Estates (r:1 w:1) + // Proof Skipped: Estate Estates (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:2 w:2) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: Estate AllEstatesCount (r:1 w:1) + // Proof Skipped: Estate AllEstatesCount (max_values: Some(1), max_size: None, mode: Measured) + // Storage: System Account (r:2 w:2) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate LandUnits (r:1 w:1) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: Metaverse Metaverses (r:1 w:0) + // Proof Skipped: Metaverse Metaverses (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:2) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn dissolve_estate() -> Weight { + // Proof Size summary in bytes: + // Measured: `3118` + // Estimated: `67224` + // Minimum execution time: 99_063 nanoseconds. + Weight::from_parts(110_008_000, 67224) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(13)) + } + // Storage: Estate EstateOwner (r:1 w:0) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:2 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Estate Estates (r:1 w:1) + // Proof Skipped: Estate Estates (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate LandUnits (r:1 w:1) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:1) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:1) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn add_land_unit_to_estate() -> Weight { + // Proof Size summary in bytes: + // Measured: `2593` + // Estimated: `38079` + // Minimum execution time: 69_608 nanoseconds. + Weight::from_parts(71_706_000, 38079) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) + } + // Storage: Estate EstateOwner (r:1 w:0) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:2 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Estate Estates (r:1 w:1) + // Proof Skipped: Estate Estates (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:2 w:2) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate LandUnits (r:1 w:1) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: Metaverse Metaverses (r:1 w:0) + // Proof Skipped: Metaverse Metaverses (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:1) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:1) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn remove_land_unit_from_estate() -> Weight { + // Proof Size summary in bytes: + // Measured: `3027` + // Estimated: `60226` + // Minimum execution time: 86_578 nanoseconds. + Weight::from_parts(90_257_000, 60226) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(8)) + } + // Storage: System Account (r:2 w:2) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate NextEstateId (r:1 w:1) + // Proof Skipped: Estate NextEstateId (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Metaverse Metaverses (r:1 w:0) + // Proof Skipped: Metaverse Metaverses (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:3 w:3) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:2 w:2) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: Estate LandUnits (r:2 w:2) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: Estate AllEstatesCount (r:1 w:1) + // Proof Skipped: Estate AllEstatesCount (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate EstateOwner (r:0 w:1) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Estate Estates (r:0 w:1) + // Proof Skipped: Estate Estates (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:3) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn create_estate() -> Weight { + // Proof Size summary in bytes: + // Measured: `3192` + // Estimated: `66058` + // Minimum execution time: 121_302 nanoseconds. + Weight::from_parts(131_741_000, 66058) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(17)) + } + // Storage: Estate EstateOwner (r:1 w:1) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Estate Estates (r:1 w:0) + // Proof Skipped: Estate Estates (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeases (r:1 w:0) + // Proof Skipped: Estate EstateLeases (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT StackableCollection (r:1 w:0) + // Proof Skipped: OrmlNFT StackableCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:0) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:2) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn transfer_estate() -> Weight { + // Proof Size summary in bytes: + // Measured: `2025` + // Estimated: `38025` + // Minimum execution time: 52_643 nanoseconds. + Weight::from_parts(54_808_000, 38025) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate NextUndeployedLandBlockId (r:1 w:1) + // Proof Skipped: Estate NextUndeployedLandBlockId (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate TotalUndeployedLandUnit (r:1 w:1) + // Proof Skipped: Estate TotalUndeployedLandUnit (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate UndeployedLandBlocks (r:0 w:20) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: Estate UndeployedLandBlocksOwner (r:0 w:20) + // Proof Skipped: Estate UndeployedLandBlocksOwner (max_values: None, max_size: None, mode: Measured) + fn issue_undeployed_land_blocks() -> Weight { + // Proof Size summary in bytes: + // Measured: `1558` + // Estimated: `9825` + // Minimum execution time: 159_581 nanoseconds. + Weight::from_parts(162_875_000, 9825) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(43)) + } + // Storage: Estate UndeployedLandBlocks (r:1 w:1) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + fn freeze_undeployed_land_blocks() -> Weight { + // Proof Size summary in bytes: + // Measured: `1442` + // Estimated: `7834` + // Minimum execution time: 21_762 nanoseconds. + Weight::from_parts(22_833_000, 7834) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Estate UndeployedLandBlocks (r:1 w:1) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + fn unfreeze_undeployed_land_blocks() -> Weight { + // Proof Size summary in bytes: + // Measured: `1442` + // Estimated: `7834` + // Minimum execution time: 20_225 nanoseconds. + Weight::from_parts(21_423_000, 7834) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Estate UndeployedLandBlocks (r:1 w:1) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + fn approve_undeployed_land_blocks() -> Weight { + // Proof Size summary in bytes: + // Measured: `1442` + // Estimated: `7834` + // Minimum execution time: 20_246 nanoseconds. + Weight::from_parts(21_819_000, 7834) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Estate UndeployedLandBlocks (r:1 w:1) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + fn unapprove_undeployed_land_blocks() -> Weight { + // Proof Size summary in bytes: + // Measured: `1475` + // Estimated: `7900` + // Minimum execution time: 20_346 nanoseconds. + Weight::from_parts(21_237_000, 7900) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate UndeployedLandBlocks (r:1 w:1) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: Estate UndeployedLandBlocksOwner (r:0 w:2) + // Proof Skipped: Estate UndeployedLandBlocksOwner (max_values: None, max_size: None, mode: Measured) + fn transfer_undeployed_land_blocks() -> Weight { + // Proof Size summary in bytes: + // Measured: `2040` + // Estimated: `13673` + // Minimum execution time: 38_679 nanoseconds. + Weight::from_parts(41_173_000, 13673) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: Metaverse MetaverseOwner (r:1 w:0) + // Proof Skipped: Metaverse MetaverseOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Estate UndeployedLandBlocks (r:1 w:1) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:2 w:2) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate LandUnits (r:1 w:1) + // Proof Skipped: Estate LandUnits (max_values: None, max_size: None, mode: Measured) + // Storage: Metaverse Metaverses (r:1 w:0) + // Proof Skipped: Metaverse Metaverses (max_values: None, max_size: None, mode: Measured) + // Storage: Nft LockedCollection (r:1 w:0) + // Proof Skipped: Nft LockedCollection (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT NextTokenId (r:1 w:1) + // Proof Skipped: OrmlNFT NextTokenId (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Classes (r:1 w:1) + // Proof Skipped: OrmlNFT Classes (max_values: None, max_size: None, mode: Measured) + // Storage: Estate AllLandUnitsCount (r:1 w:1) + // Proof Skipped: Estate AllLandUnitsCount (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate TotalUndeployedLandUnit (r:1 w:1) + // Proof Skipped: Estate TotalUndeployedLandUnit (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate UndeployedLandBlocksOwner (r:0 w:1) + // Proof Skipped: Estate UndeployedLandBlocksOwner (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT TokensByOwner (r:0 w:1) + // Proof Skipped: OrmlNFT TokensByOwner (max_values: None, max_size: None, mode: Measured) + fn deploy_land_block() -> Weight { + // Proof Size summary in bytes: + // Measured: `2802` + // Estimated: `64897` + // Minimum execution time: 91_163 nanoseconds. + Weight::from_parts(100_659_000, 64897) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(11)) + } + // Storage: Estate UndeployedLandBlocks (r:1 w:1) + // Proof Skipped: Estate UndeployedLandBlocks (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: Estate TotalUndeployedLandUnit (r:1 w:1) + // Proof Skipped: Estate TotalUndeployedLandUnit (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Estate UndeployedLandBlocksOwner (r:0 w:1) + // Proof Skipped: Estate UndeployedLandBlocksOwner (max_values: None, max_size: None, mode: Measured) + fn burn_undeployed_land_blocks() -> Weight { + // Proof Size summary in bytes: + // Measured: `1304` + // Estimated: `10661` + // Minimum execution time: 23_162 nanoseconds. + Weight::from_parts(32_196_000, 10661) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: Estate EstateOwner (r:1 w:0) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:0) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeaseOffers (r:2 w:1) + // Proof Skipped: Estate EstateLeaseOffers (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeases (r:1 w:0) + // Proof Skipped: Estate EstateLeases (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn create_lease_offer() -> Weight { + // Proof Size summary in bytes: + // Measured: `1986` + // Estimated: `27383` + // Minimum execution time: 94_497 nanoseconds. + Weight::from_parts(98_902_000, 27383) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Estate EstateLeases (r:1 w:1) + // Proof Skipped: Estate EstateLeases (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateOwner (r:1 w:0) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: Auction ItemsInAuction (r:1 w:0) + // Proof Skipped: Auction ItemsInAuction (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeaseOffers (r:1 w:1) + // Proof Skipped: Estate EstateLeaseOffers (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Storage: Estate EstateLeasors (r:0 w:1) + // Proof Skipped: Estate EstateLeasors (max_values: None, max_size: None, mode: Measured) + fn accept_lease_offer() -> Weight { + // Proof Size summary in bytes: + // Measured: `2311` + // Estimated: `28844` + // Minimum execution time: 53_956 nanoseconds. + Weight::from_parts(57_019_000, 28844) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + // Storage: Estate EstateLeases (r:1 w:1) + // Proof Skipped: Estate EstateLeases (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeasors (r:1 w:1) + // Proof Skipped: Estate EstateLeasors (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateOwner (r:1 w:0) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn cancel_lease() -> Weight { + // Proof Size summary in bytes: + // Measured: `4017` + // Estimated: `28571` + // Minimum execution time: 55_907 nanoseconds. + Weight::from_parts(57_720_000, 28571) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Estate EstateLeases (r:1 w:1) + // Proof Skipped: Estate EstateLeases (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeasors (r:1 w:1) + // Proof Skipped: Estate EstateLeasors (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateOwner (r:1 w:0) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:1) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn remove_expired_lease() -> Weight { + // Proof Size summary in bytes: + // Measured: `4017` + // Estimated: `28571` + // Minimum execution time: 56_789 nanoseconds. + Weight::from_parts(57_681_000, 28571) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Estate EstateLeaseOffers (r:1 w:1) + // Proof Skipped: Estate EstateLeaseOffers (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn remove_lease_offer() -> Weight { + // Proof Size summary in bytes: + // Measured: `3250` + // Estimated: `8328` + // Minimum execution time: 33_999 nanoseconds. + Weight::from_parts(41_923_000, 8328) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + // Storage: Estate EstateOwner (r:1 w:0) + // Proof Skipped: Estate EstateOwner (max_values: None, max_size: None, mode: Measured) + // Storage: OrmlNFT Tokens (r:1 w:0) + // Proof Skipped: OrmlNFT Tokens (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeasors (r:1 w:0) + // Proof Skipped: Estate EstateLeasors (max_values: None, max_size: None, mode: Measured) + // Storage: Estate EstateLeases (r:1 w:1) + // Proof Skipped: Estate EstateLeases (max_values: None, max_size: None, mode: Measured) + // Storage: System Account (r:1 w:1) + // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn collect_rent() -> Weight { + // Proof Size summary in bytes: + // Measured: `4017` + // Estimated: `28571` + // Minimum execution time: 51_821 nanoseconds. + Weight::from_parts(53_171_000, 28571) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + fn on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 176 nanoseconds. + Weight::from_parts(191_000, 0) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { fn mint_land() -> Weight { + Weight::from_parts(59_273_000, 36660) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(7)) + } + fn mint_lands() -> Weight { + Weight::from_parts(83_541_000, 41610) + .saturating_add(RocksDbWeight::get().reads(10)) + .saturating_add(RocksDbWeight::get().writes(10)) + } + fn transfer_land() -> Weight { + Weight::from_parts(47_423_000, 28255) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + fn mint_estate() -> Weight { + Weight::from_parts(64_479_000, 47210) + .saturating_add(RocksDbWeight::get().reads(10)) + .saturating_add(RocksDbWeight::get().writes(11)) + } + fn dissolve_estate() -> Weight { + Weight::from_parts(110_008_000, 67224) + .saturating_add(RocksDbWeight::get().reads(14)) + .saturating_add(RocksDbWeight::get().writes(13)) + } + fn add_land_unit_to_estate() -> Weight { + Weight::from_parts(71_706_000, 38079) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(6)) + } + fn remove_land_unit_from_estate() -> Weight { + Weight::from_parts(90_257_000, 60226) + .saturating_add(RocksDbWeight::get().reads(12)) + .saturating_add(RocksDbWeight::get().writes(8)) + } + fn create_estate() -> Weight { + Weight::from_parts(131_741_000, 66058) + .saturating_add(RocksDbWeight::get().reads(14)) + .saturating_add(RocksDbWeight::get().writes(17)) + } + fn transfer_estate() -> Weight { + Weight::from_parts(54_808_000, 38025) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + fn issue_undeployed_land_blocks() -> Weight { + Weight::from_parts(162_875_000, 9825) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(43)) + } + fn freeze_undeployed_land_blocks() -> Weight { + Weight::from_parts(22_833_000, 7834) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + fn unfreeze_undeployed_land_blocks() -> Weight { + Weight::from_parts(21_423_000, 7834) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + fn approve_undeployed_land_blocks() -> Weight { + Weight::from_parts(21_819_000, 7834) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + fn unapprove_undeployed_land_blocks() -> Weight { + Weight::from_parts(21_237_000, 7900) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + fn transfer_undeployed_land_blocks() -> Weight { + Weight::from_parts(41_173_000, 13673) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + fn deploy_land_block() -> Weight { + Weight::from_parts(100_659_000, 64897) + .saturating_add(RocksDbWeight::get().reads(13)) + .saturating_add(RocksDbWeight::get().writes(11)) + } + fn burn_undeployed_land_blocks() -> Weight { + Weight::from_parts(32_196_000, 10661) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + fn create_lease_offer() -> Weight { + Weight::from_parts(98_902_000, 27383) + .saturating_add(RocksDbWeight::get().reads(7)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + fn accept_lease_offer() -> Weight { + Weight::from_parts(57_019_000, 28844) + .saturating_add(RocksDbWeight::get().reads(6)) + .saturating_add(RocksDbWeight::get().writes(5)) + } + fn cancel_lease() -> Weight { + Weight::from_parts(57_720_000, 28571) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + fn remove_expired_lease() -> Weight { + Weight::from_parts(57_681_000, 28571) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + fn remove_lease_offer() -> Weight { + Weight::from_parts(41_923_000, 8328) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + fn collect_rent() -> Weight { + Weight::from_parts(53_171_000, 28571) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + fn on_initialize() -> Weight { + Weight::from_parts(191_000, 0) + } +} diff --git a/pallets/xcm-interface/Cargo.toml b/pallets/xcm-interface/Cargo.toml new file mode 100644 index 000000000..1a446831b --- /dev/null +++ b/pallets/xcm-interface/Cargo.toml @@ -0,0 +1,70 @@ +[package] +authors = ['Metaverse Network '] +description = 'Metaverse Network pallet for xcm interface logic.' +edition = '2021' +homepage = 'https://metaverse.network' +license = 'Unlicense' +name = 'pallet-xcm-interface' +repository = 'https://github.com/bit-country' +version = '2.0.0-rc6' + +[dependencies] +log = { version = "0.4.17", default-features = false } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } +frame-benchmarking = { workspace = true, optional = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-core = { workspace = true } +sp-std = { workspace = true } +pallet-xcm = { workspace = true } +xcm = { package = "staging-xcm", workspace = true } +# local packages +core-primitives = { path = "../../traits/core-primitives", default-features = false } +primitives = { package = "bit-country-primitives", path = "../../primitives/metaverse", default-features = false } +currencies = { package = "currencies", path = "../currencies", default-features = false } +asset-manager = { package = "asset-manager", path = "../asset-manager", default-features = false } + +#orml +orml-tokens = { workspace = true } +orml-traits = { workspace = true } + +[dev-dependencies] +insta = { version = "1.31.0" } + +cumulus-primitives-core = { workspace = true } +pallet-balances = { workspace = true } +sp-io = { workspace = true } +xcm-builder = { package = "staging-xcm-builder", workspace = true } +xcm-executor = { package = "staging-xcm-executor", workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "orml-traits/std", + "pallet-xcm/std", + "primitives/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", + "xcm/std", +] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-xcm/try-runtime", +] diff --git a/pallets/xcm-interface/src/lib.rs b/pallets/xcm-interface/src/lib.rs new file mode 100644 index 000000000..a30eb952c --- /dev/null +++ b/pallets/xcm-interface/src/lib.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/primitives/metaverse/src/bounded.rs b/primitives/metaverse/src/bounded.rs new file mode 100644 index 000000000..5b13feee1 --- /dev/null +++ b/primitives/metaverse/src/bounded.rs @@ -0,0 +1,249 @@ +// This file is part of Metaverse.Network & Bit.Country. + +// Copyright (C) 2020-2022 Metaverse.Network & Bit.Country . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::traits::Get; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize}; +use sp_runtime::{ + traits::{CheckedSub, One, Zero}, + FixedPointNumber, FixedU128, RuntimeDebug, +}; +use sp_std::{marker::PhantomData, prelude::*, result::Result}; + +use crate::{Balance, BlockNumber}; + +pub type Rate = FixedU128; + +/// The bounded type errors. +#[derive(RuntimeDebug, PartialEq, Eq)] +pub enum Error { + /// The value is out of bound. + OutOfBounds, + /// The change diff exceeds the max absolute value. + ExceedMaxChangeAbs, +} +/// An abstract definition of bounded type. The type is within the range of `Range` +/// and while update the inner value, the max absolute value of the diff is `MaxChangeAbs`. +/// The `Default` value is minimum value of the range. +#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] +#[derive(Encode, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] +#[scale_info(skip_type_params(Range, MaxChangeAbs))] +pub struct BoundedType( + T, + #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData<(Range, MaxChangeAbs)>, +); + +impl, MaxChangeAbs: Get> Decode + for BoundedType +{ + fn decode(input: &mut I) -> Result { + let inner = T::decode(input)?; + Self::try_from(inner).map_err(|_| "BoundedType: value out of bounds".into()) + } +} + +#[cfg(feature = "std")] +impl<'de, T, Range, MaxChangeAbs> Deserialize<'de> for BoundedType +where + T: Encode + Decode + CheckedSub + PartialOrd + Deserialize<'de>, + Range: Get<(T, T)>, + MaxChangeAbs: Get, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value: T = T::deserialize(deserializer)?; + Self::try_from(value).map_err(|_| SerdeError::custom("out of bounds")) + } +} + +impl, MaxChangeAbs: Get> Default + for BoundedType +{ + fn default() -> Self { + let (min, _) = Range::get(); + Self(min, PhantomData) + } +} + +impl BoundedType +where + T: Encode + Decode + CheckedSub + PartialOrd, + Range: Get<(T, T)>, + MaxChangeAbs: Get, +{ + /// Try to create a new instance of `BoundedType`. Returns `Err` if out of bound. + pub fn try_from(value: T) -> Result { + let (min, max) = Range::get(); + if value < min || value > max { + return Err(Error::OutOfBounds); + } + Ok(Self(value, PhantomData)) + } + + /// Set the inner value. Returns `Err` if out of bound or the diff with current value exceeds + /// the max absolute value. + pub fn try_set(&mut self, value: T) -> Result<(), Error> { + let (min, max) = Range::get(); + let max_change_abs = MaxChangeAbs::get(); + let old_value = &self.0; + if value < min || value > max { + return Err(Error::OutOfBounds); + } + + let abs = if value > *old_value { + value + .checked_sub(old_value) + .expect("greater number subtracting smaller one can't underflow; qed") + } else { + old_value + .checked_sub(&value) + .expect("greater number subtracting smaller one can't underflow; qed") + }; + if abs > max_change_abs { + return Err(Error::ExceedMaxChangeAbs); + } + + self.0 = value; + Ok(()) + } + + pub fn into_inner(self) -> T { + self.0 + } + + pub fn inner(&self) -> &T { + &self.0 + } +} + +/// Fractional range between `Rate::zero()` and `Rate::one()`. +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] +pub struct Fractional; +impl Get<(Rate, Rate)> for Fractional { + fn get() -> (Rate, Rate) { + (Rate::zero(), Rate::one()) + } +} + +/// Maximum absolute change is 1/5. +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] +pub struct OneFifth; +impl Get for OneFifth { + fn get() -> Rate { + Rate::saturating_from_rational(1, 5) + } +} + +/// Maximum absolute change is 1/2. +#[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] +pub struct OneHalf; +impl Get for OneHalf { + fn get() -> Rate { + Rate::saturating_from_rational(1, 2) + } +} + +pub type BoundedRate = BoundedType; + +/// Fractional rate. +/// +/// The range is between 0 to 1, and max absolute value of change diff is 1/2. +pub type FractionalRate = BoundedRate; + +pub type BoundedBalance = BoundedType; + +pub type BoundedBlockNumber = BoundedType; + +#[cfg(test)] +mod tests { + use frame_support::{assert_err, assert_ok}; + + use super::*; + + #[test] + fn fractional_rate_works() { + assert_err!( + FractionalRate::try_from(Rate::from_rational(11, 10)), + Error::OutOfBounds + ); + + let mut rate = FractionalRate::try_from(Rate::from_rational(8, 10)).unwrap(); + assert_ok!(rate.try_set(Rate::from_rational(10, 10))); + assert_err!(rate.try_set(Rate::from_rational(11, 10)), Error::OutOfBounds); + assert_err!(rate.try_set(Rate::from_rational(79, 100)), Error::ExceedMaxChangeAbs); + + assert_eq!(FractionalRate::default().into_inner(), Rate::zero()); + } + + #[test] + fn encode_decode_works() { + let rate = FractionalRate::try_from(Rate::from_rational(8, 10)).unwrap(); + let encoded = rate.encode(); + assert_eq!(FractionalRate::decode(&mut &encoded[..]).unwrap(), rate); + + assert_eq!(encoded, Rate::from_rational(8, 10).encode()); + } + + #[test] + fn decode_fails_if_out_of_bounds() { + let bad_rate = BoundedType::(Rate::from_rational(11, 10), PhantomData); + let bad_rate_encoded = bad_rate.encode(); + assert_err!( + FractionalRate::decode(&mut &bad_rate_encoded[..]), + "BoundedType: value out of bounds" + ); + } + + #[test] + fn ser_de_works() { + let rate = FractionalRate::try_from(Rate::from_rational(8, 10)).unwrap(); + assert_eq!(serde_json::json!(&rate).to_string(), r#""800000000000000000""#); + + let deserialized: FractionalRate = serde_json::from_str(r#""800000000000000000""#).unwrap(); + assert_eq!(deserialized, rate); + } + + #[test] + fn deserialize_fails_if_out_of_bounds() { + let failed: Result = serde_json::from_str(r#""1100000000000000000""#); + match failed { + Err(msg) => assert_eq!(msg.to_string(), "out of bounds"), + _ => panic!("should fail"), + } + } + + #[test] + fn bounded_type_default_is_range_min() { + #[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] + pub struct OneToTwo; + impl Get<(Rate, Rate)> for OneToTwo { + fn get() -> (Rate, Rate) { + (Rate::one(), Rate::from_rational(2, 1)) + } + } + + type BoundedRateOneToTwo = BoundedRate; + + assert_eq!(BoundedRateOneToTwo::default().into_inner(), Rate::one()); + } +} diff --git a/primitives/metaverse/src/lib.rs b/primitives/metaverse/src/lib.rs index fe456f3ad..ad1544bc9 100644 --- a/primitives/metaverse/src/lib.rs +++ b/primitives/metaverse/src/lib.rs @@ -32,9 +32,9 @@ use sp_runtime::{FixedU128, OpaqueExtrinsic as UncheckedExtrinsic}; use sp_std::collections::btree_map::BTreeMap; use sp_std::prelude::*; use sp_std::vec::Vec; - use xcm::v3::MultiLocation; +pub mod bounded; pub mod continuum; pub mod estate; pub mod evm; @@ -105,6 +105,8 @@ pub type ReferendumId = u64; pub type LandId = u64; /// EstateId pub type EstateId = u64; +/// Number of era on relaychain +pub type EraIndex = u32; /// Social Token Id type pub type TokenId = u64; /// Undeployed LandBlock Id type @@ -133,6 +135,8 @@ pub type TrieIndex = u32; pub type CampaignId = u32; /// Index used for claim rewrads for merkle root campaigns pub type ClaimId = u64; +/// Pool Id to keep track of each pool +pub type PoolId = u32; /// Land Token Class Id pub const LAND_CLASS_ID: ClassId = 15; @@ -193,7 +197,7 @@ impl FungibleTokenId { pub fn decimals(&self) -> u8 { match self { FungibleTokenId::NativeToken(0) => 18, // Native token - FungibleTokenId::NativeToken(1) | FungibleTokenId::NativeToken(2) | FungibleTokenId::Stable(0) => 12, // KSM KAR KUSD + FungibleTokenId::NativeToken(1) | FungibleTokenId::NativeToken(2) | FungibleTokenId::Stable(0) => 12, // KSM FungibleTokenId::MiningResource(0) => 18, _ => 18, } @@ -461,3 +465,53 @@ pub struct CampaignInfo, } +// For multiple time calculation type +#[derive(Encode, Decode, Clone, RuntimeDebug, Eq, TypeInfo, MaxEncodedLen)] +pub enum StakingRound { + Era(#[codec(compact)] u32), + Round(#[codec(compact)] u32), + Epoch(#[codec(compact)] u32), + Hour(#[codec(compact)] u32), +} + +impl Default for StakingRound { + fn default() -> Self { + StakingRound::Era(0u32) + } +} + +impl PartialEq for StakingRound { + fn eq(&self, other: &Self) -> bool { + match (&self, other) { + (Self::Era(a), Self::Era(b)) => a.eq(b), + (Self::Round(a), Self::Round(b)) => a.eq(b), + (Self::Epoch(a), Self::Epoch(b)) => a.eq(b), + (Self::Hour(a), Self::Hour(b)) => a.eq(b), + _ => false, + } + } +} + +impl Ord for StakingRound { + fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { + match (&self, other) { + (Self::Era(a), Self::Era(b)) => a.cmp(b), + (Self::Round(a), Self::Round(b)) => a.cmp(b), + (Self::Epoch(a), Self::Epoch(b)) => a.cmp(b), + (Self::Hour(a), Self::Hour(b)) => a.cmp(b), + _ => sp_std::cmp::Ordering::Less, + } + } +} + +impl PartialOrd for StakingRound { + fn partial_cmp(&self, other: &Self) -> Option { + match (&self, other) { + (Self::Era(a), Self::Era(b)) => Some(a.cmp(b)), + (Self::Round(a), Self::Round(b)) => Some(a.cmp(b)), + (Self::Epoch(a), Self::Epoch(b)) => Some(a.cmp(b)), + (Self::Hour(a), Self::Hour(b)) => Some(a.cmp(b)), + _ => None, + } + } +} diff --git a/runtime/common/src/currencies.rs b/runtime/common/src/currencies.rs index 540aae788..3a9fc1e6e 100644 --- a/runtime/common/src/currencies.rs +++ b/runtime/common/src/currencies.rs @@ -1,24 +1,23 @@ use frame_support::pallet_prelude::Get; use frame_support::traits::{Currency, OriginTrait}; use orml_traits::{BasicCurrency, MultiCurrency as MultiCurrencyTrait}; -use pallet_evm::Context; + use pallet_evm::{ - AddressMapping, ExitRevert, ExitSucceed, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, - PrecompileResult, PrecompileSet, + ExitRevert, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet, }; use sp_core::{H160, U256}; -use sp_runtime::traits::{AccountIdConversion, Dispatchable, Zero}; +use sp_runtime::traits::Dispatchable; use sp_std::{marker::PhantomData, prelude::*}; use evm_mapping::AddressMapping as EvmMapping; -use evm_mapping::EvmAddressMapping; + use precompile_utils::data::{Address, EvmData, EvmDataWriter}; use precompile_utils::handle::PrecompileHandleExt; use precompile_utils::modifier::FunctionModifier; use precompile_utils::prelude::RuntimeHelper; use precompile_utils::{succeed, EvmResult}; use primitives::evm::{Erc20Mapping, Output}; -use primitives::{evm, AssetIds, AssetMetadata, Balance, FungibleTokenId}; +use primitives::{AssetIds, Balance, FungibleTokenId}; #[precompile_utils_macro::generate_function_selector] #[derive(Debug, PartialEq)] @@ -114,7 +113,7 @@ where })) } - fn is_precompile(&self, address: H160) -> bool { + fn is_precompile(&self, _address: H160) -> bool { todo!() } } @@ -143,7 +142,7 @@ where if let Some(currency_id) = Runtime::decode_evm_address(address) { log::debug!(target: "evm", "multicurrency: currency id: {:?}", currency_id); - let result = { + let _result = { let selector = match handle.read_selector() { Ok(selector) => selector, Err(e) => return Err(e), @@ -193,7 +192,10 @@ where >, BalanceOf: TryFrom + Into + EvmData, { - fn not_supported(currency_id: FungibleTokenId, handle: &mut impl PrecompileHandle) -> EvmResult { + fn not_supported( + _currency_id: FungibleTokenId, + _handle: &mut impl PrecompileHandle, + ) -> EvmResult { Err(PrecompileFailure::Error { exit_status: pallet_evm::ExitError::Other("not supported".into()), }) diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 7dd0aa42d..56fc2368e 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -16,22 +16,17 @@ // limitations under the License. #![cfg_attr(not(feature = "std"), no_std)] -use codec::Encode; -use cumulus_pallet_parachain_system::CheckAssociatedRelayNumber; use frame_support::{ traits::Get, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, }; use orml_traits::currency::MutationHooks; -use polkadot_parachain::primitives::RelayChainBlockNumber; + use sp_runtime::{FixedPointNumber, FixedU128}; use sp_std::{marker::PhantomData, prelude::*}; use xcm::latest::prelude::*; use xcm_builder::TakeRevenue; -use xcm_executor::{ - traits::{DropAssets, WeightTrader}, - Assets, -}; +use xcm_executor::{traits::WeightTrader, Assets}; use primitives::BuyWeightRate; diff --git a/runtime/common/src/mock.rs b/runtime/common/src/mock.rs index 7d99dbf43..dbe1ecb1c 100644 --- a/runtime/common/src/mock.rs +++ b/runtime/common/src/mock.rs @@ -1,40 +1,35 @@ -use std::ptr::hash; - use frame_support::{ construct_runtime, dispatch::DispatchResult, parameter_types, - traits::{AsEnsureOriginWithArg, Everything, Nothing}, + traits::{Everything, Nothing}, weights::Weight, PalletId, }; -use frame_system::{EnsureNever, EnsureRoot}; -use hex_literal::hex; +use frame_system::EnsureRoot; + use orml_traits::parameter_type_with_key; -use pallet_evm::{AddressMapping, PrecompileHandle, PrecompileOutput}; use pallet_evm::{EnsureAddressNever, EnsureAddressRoot, HashedAddressMapping, Precompile, PrecompileSet}; -use scale_info::TypeInfo; -use serde::{Deserialize, Serialize}; -use sp_core::{Blake2Hasher, Decode, Encode, Hasher, MaxEncodedLen, H160, H256, U256}; -use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, ConstU32, IdentityLookup}; -use sp_runtime::{AccountId32, DispatchError, Perbill}; +use pallet_evm::{PrecompileHandle, PrecompileOutput}; + +use sp_core::{MaxEncodedLen, H160, H256, U256}; +use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, IdentityLookup, Verify}; +use sp_runtime::{AccountId32, DispatchError, MultiSignature, Perbill}; use auction_manager::{Auction, AuctionInfo, AuctionItem, AuctionType, CheckAuctionItemHandler, ListingLevel}; use core_primitives::{NftAssetData, NftClassData}; use evm_mapping::AddressMapping as AddressMappingEvm; use evm_mapping::EvmAddressMapping; - use precompile_utils::precompile_set::*; use precompile_utils::EvmResult; use primitives::evm::{ CurrencyIdType, Erc20Mapping, EvmAddress, H160_POSITION_CURRENCY_ID_TYPE, H160_POSITION_TOKEN, H160_POSITION_TOKEN_NFT, H160_POSITION_TOKEN_NFT_CLASS_ID_END, }; -use primitives::{Amount, AuctionId, ClassId, FungibleTokenId, GroupCollectionId, ItemId, TokenId}; +use primitives::{Amount, AuctionId, ClassId, FungibleTokenId, ItemId, TokenId}; use crate::currencies::MultiCurrencyPrecompile; use crate::nft::NftPrecompile; -use crate::precompiles::MetaverseNetworkPrecompiles; use super::*; @@ -45,6 +40,8 @@ pub type Balance = u128; pub type BlockNumber = u32; pub type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; pub type Block = frame_system::mocking::MockBlock; +type Signature = MultiSignature; +type AccountPublic = ::Signer; pub const COLLECTION_ID: u64 = 0; pub const CLASS_ID: ClassId = 0u32; @@ -141,7 +138,7 @@ where } } - fn is_precompile(&self, address: H160) -> bool { + fn is_precompile(&self, _address: H160) -> bool { true } } @@ -310,7 +307,7 @@ impl Auction for MockAuctionManager { None } - fn auction_item(id: AuctionId) -> Option> { + fn auction_item(_id: AuctionId) -> Option> { None } @@ -318,7 +315,7 @@ impl Auction for MockAuctionManager { Ok(()) } - fn update_auction_item(id: AuctionId, item_id: ItemId) -> DispatchResult { + fn update_auction_item(_id: AuctionId, _item_id: ItemId) -> DispatchResult { Ok(()) } @@ -347,11 +344,11 @@ impl Auction for MockAuctionManager { fn remove_auction(_id: u64, _item_id: ItemId) {} - fn auction_bid_handler(from: AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult { + fn auction_bid_handler(_from: AccountId, _id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } - fn buy_now_handler(from: AccountId, auction_id: AuctionId, value: Self::Balance) -> DispatchResult { + fn buy_now_handler(_from: AccountId, _auction_id: AuctionId, _value: Self::Balance) -> DispatchResult { Ok(()) } @@ -439,6 +436,8 @@ impl nft_pallet::Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = AccountPublic; } // Configure a mock runtime to test the pallet. diff --git a/runtime/common/src/nft.rs b/runtime/common/src/nft.rs index e10cebea6..e03599195 100644 --- a/runtime/common/src/nft.rs +++ b/runtime/common/src/nft.rs @@ -1,27 +1,25 @@ use core_primitives::{Attributes, CollectionType, NftMetadata, TokenType}; use evm_mapping::AddressMapping as EvmMapping; -use evm_mapping::EvmAddressMapping; + use frame_support::pallet_prelude::Get; use frame_support::traits::{Currency, OriginTrait}; use frame_system::RawOrigin; use orml_traits::{BasicCurrency, MultiCurrency}; use pallet_evm::{ - AddressMapping, ExitRevert, ExitSucceed, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, - PrecompileResult, PrecompileSet, + ExitRevert, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet, }; use sp_core::{H160, U256}; use sp_runtime::traits::{AccountIdConversion, Dispatchable}; use sp_runtime::Perbill; use sp_std::{marker::PhantomData, prelude::*}; -use codec::{DecodeAll, Encode}; use precompile_utils::data::{Address, EvmData, EvmDataWriter}; use precompile_utils::handle::PrecompileHandleExt; use precompile_utils::modifier::FunctionModifier; use precompile_utils::prelude::RuntimeHelper; use precompile_utils::{succeed, EvmResult}; use primitives::evm::{Erc20Mapping, Output}; -use primitives::{evm, Balance, ClassId, GroupCollectionId, TokenId}; +use primitives::{ClassId, GroupCollectionId, TokenId}; #[precompile_utils_macro::generate_function_selector] #[derive(Debug, PartialEq)] @@ -119,7 +117,7 @@ where Some(result) } - fn is_precompile(&self, address: H160) -> bool { + fn is_precompile(&self, _address: H160) -> bool { todo!() } } @@ -449,7 +447,7 @@ where let class_id = input.read::>()?.into(); // Build call info - let owner: H160 = input.read::
()?.into(); + let _owner: H160 = input.read::
()?.into(); let who = ::AddressMapping::get_account_id(&handle.context().caller); log::debug!(target: "evm", "withdraw funds from class {:?} fund", class_id); diff --git a/runtime/common/src/precompiles.rs b/runtime/common/src/precompiles.rs index 6774a1d83..6f1ce2d1e 100644 --- a/runtime/common/src/precompiles.rs +++ b/runtime/common/src/precompiles.rs @@ -1,4 +1,4 @@ -use pallet_evm::{ExitRevert, Precompile, PrecompileFailure, PrecompileHandle, PrecompileResult, PrecompileSet}; +use pallet_evm::{Precompile, PrecompileHandle, PrecompileResult, PrecompileSet}; use pallet_evm_precompile_blake2::Blake2F; use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; use pallet_evm_precompile_dispatch::Dispatch; @@ -78,7 +78,7 @@ where } } - fn is_precompile(&self, address: H160) -> bool { + fn is_precompile(&self, _address: H160) -> bool { // sp_std::vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 1024, 1025, 1026, 1027, 400] // .into_iter() // .map(hash) diff --git a/runtime/common/src/tests/currencies.rs b/runtime/common/src/tests/currencies.rs index 8ab5cf926..612cede31 100644 --- a/runtime/common/src/tests/currencies.rs +++ b/runtime/common/src/tests/currencies.rs @@ -1,5 +1,3 @@ -use asset_manager::BalanceOf; -use frame_support::assert_noop; use hex_literal::hex; use sp_core::{H160, U256}; use sp_runtime::traits::Zero; @@ -242,7 +240,7 @@ fn balance_of_native_currencies_works() { .with_balances(vec![(alice_account_id(), 100000)]) .build() .execute_with(|| { - let mut evm_writer = EvmDataWriter::new_with_selector(Action::BalanceOf); + let _evm_writer = EvmDataWriter::new_with_selector(Action::BalanceOf); EvmMapping::claim_default_account(RuntimeOrigin::signed(alice_account_id())); precompiles() .prepare_test( diff --git a/runtime/common/src/tests/nft.rs b/runtime/common/src/tests/nft.rs index e17f1cc46..06701033c 100644 --- a/runtime/common/src/tests/nft.rs +++ b/runtime/common/src/tests/nft.rs @@ -1,23 +1,20 @@ -use frame_support::assert_noop; -use hex_literal::hex; -use sp_core::{ByteArray, H160, U256}; -use sp_runtime::traits::{AccountIdConversion, Zero}; +use sp_core::{ByteArray, U256}; +use sp_runtime::traits::AccountIdConversion; use sp_runtime::Perbill; use sp_std::collections::btree_map::BTreeMap; use precompile_utils::data::{Address, Bytes, EvmDataWriter}; use precompile_utils::testing::*; -use primitives::evm::Output; + use primitives::FungibleTokenId; use crate::mock::*; use crate::nft::Action; -use evm_mapping::AddressMapping as AddressMappingEvm; + use orml_nft::Pallet as NftModule; use orml_traits::BasicCurrency; -use pallet_evm::AddressMapping; -use core_primitives::{Attributes, CollectionType, NftAssetData, NftClassData, NftMetadata, TokenType}; +use core_primitives::{Attributes, CollectionType, NftMetadata, TokenType}; fn precompiles() -> Precompiles { PrecompilesValue::get() diff --git a/runtime/continuum/src/lib.rs b/runtime/continuum/src/lib.rs index 395a5d14c..9ad479369 100644 --- a/runtime/continuum/src/lib.rs +++ b/runtime/continuum/src/lib.rs @@ -1452,6 +1452,8 @@ impl nft::Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = ::Signer; } parameter_types! { diff --git a/runtime/continuum/src/weights/module_nft.rs b/runtime/continuum/src/weights/module_nft.rs index 86909c591..1bd3bbfb2 100644 --- a/runtime/continuum/src/weights/module_nft.rs +++ b/runtime/continuum/src/weights/module_nft.rs @@ -66,4 +66,9 @@ impl nft::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + fn mint_pre_signed() -> Weight { + Weight::from_parts(91_000_000, 19036) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } } diff --git a/runtime/metaverse/Cargo.toml b/runtime/metaverse/Cargo.toml index 03fe82227..216dca109 100644 --- a/runtime/metaverse/Cargo.toml +++ b/runtime/metaverse/Cargo.toml @@ -84,6 +84,7 @@ orml-tokens = { workspace = true } orml-traits = { workspace = true } orml-nft = { workspace = true } orml-oracle = { workspace = true } +orml-rewards = { workspace = true } orml-benchmarking = { workspace = true, optional = true } # metaverse dependencies primitives = { package = "bit-country-primitives", path = "../../primitives/metaverse", default-features = false } @@ -104,6 +105,7 @@ core-primitives = { path = "../../traits/core-primitives", default-features = fa metaverse-runtime-common = { path = "../common", default-features = false } asset-manager = { path = "../../pallets/asset-manager", default-features = false } evm-mapping = { package = "pallet-evm-mapping", path = "../../pallets/evm-mapping", default-features = false } +spp = { package = "pallet-spp", path = "../../pallets/spp", default-features = false } modules-bridge = { path = "../../modules/bridge", default-features = false } @@ -114,6 +116,18 @@ pallet-contracts-primitives = { workspace = true } # XCM builder ( need to be used to build the runtime benchmarking correctly) xcm-builder = { workspace = true } +# Cumulus Dependencies +cumulus-pallet-aura-ext = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-dmp-queue = { workspace = true } +cumulus-pallet-xcm = { workspace = true } +cumulus-pallet-xcmp-queue = { workspace = true } +cumulus-primitives-core = { workspace = true } +cumulus-primitives-timestamp = { workspace = true } +cumulus-primitives-utility = { workspace = true } +cumulus-pallet-session-benchmarking = { workspace = true } +parachain-info = { workspace = true } + [build-dependencies] substrate-wasm-builder = { workspace = true } @@ -162,6 +176,7 @@ std = [ "orml-tokens/std", "orml-nft/std", "orml-oracle/std", + "orml-rewards/std", "primitives/std", "metaverse/std", "auction/std", @@ -176,6 +191,7 @@ std = [ "economy/std", "emergency/std", "evm-mapping/std", + "spp/std", "pallet-utility/std", "pallet-collator-selection/std", "orml-benchmarking/std", @@ -189,7 +205,14 @@ std = [ "pallet-contracts-primitives/std", "frame-try-runtime/std", "metaverse-runtime-common/std", - "modules-bridge/std" + "modules-bridge/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-pallet-xcm/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "cumulus-primitives-utility/std", ] runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", diff --git a/runtime/metaverse/src/lib.rs b/runtime/metaverse/src/lib.rs index 7da3a3aa7..a0b61b2fa 100644 --- a/runtime/metaverse/src/lib.rs +++ b/runtime/metaverse/src/lib.rs @@ -24,6 +24,7 @@ extern crate orml_benchmarking; use codec::{Decode, Encode, MaxEncodedLen}; +use cumulus_pallet_parachain_system::RelaychainBlockNumberProvider; // pub use this so we can import it in the chain spec. #[cfg(feature = "std")] pub use fp_evm::GenesisAccount; @@ -60,6 +61,7 @@ use pallet_evm::{ }; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; +use polkadot_primitives::v2::MAX_POV_SIZE; use scale_info::TypeInfo; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -68,7 +70,7 @@ use sp_core::{ sp_std::marker::PhantomData, ConstBool, OpaqueMetadata, H160, H256, U256, }; -use sp_runtime::traits::DispatchInfoOf; +use sp_runtime::traits::{BlockNumberProvider, DispatchInfoOf}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; use sp_runtime::{ @@ -85,6 +87,8 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +//use pallet_evm::{EnsureAddressTruncated, HashedAddressMapping}; +use asset_manager::ForeignAssetMapping; pub use constants::{currency::*, time::*}; use core_primitives::{NftAssetData, NftClassData}; // External imports @@ -92,13 +96,11 @@ use currencies::BasicCurrencyAdapter; pub use estate::{MintingRateInfo, Range as MintingRange}; use evm_mapping::EvmAddressMapping; use metaverse_runtime_common::{precompiles::MetaverseNetworkPrecompiles, CurrencyHooks}; -use primitives::{Amount, Balance, BlockNumber, ClassId, FungibleTokenId, Moment, NftId, RoundIndex, TokenId}; -//use pallet_evm::{EnsureAddressTruncated, HashedAddressMapping}; -use polkadot_primitives::v2::MAX_POV_SIZE; use primitives::evm::{ CurrencyIdType, Erc20Mapping, EvmAddress, H160_POSITION_CURRENCY_ID_TYPE, H160_POSITION_FUNGIBLE_TOKEN, H160_POSITION_MINING_RESOURCE, H160_POSITION_TOKEN, H160_POSITION_TOKEN_NFT, H160_POSITION_TOKEN_NFT_CLASS_ID_END, }; +use primitives::{Amount, Balance, BlockNumber, ClassId, FungibleTokenId, Moment, NftId, PoolId, RoundIndex, TokenId}; // primitives imports use crate::opaque::SessionKeys; @@ -180,7 +182,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 92, + spec_version: 98, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -364,6 +366,10 @@ parameter_types! { pub const EconomyTreasury: PalletId = PalletId(*b"bit/econ"); pub const LocalMetaverseFundPalletId: PalletId = PalletId(*b"bit/meta"); pub const BridgeSovereignPalletId: PalletId = PalletId(*b"bit/brgd"); + pub const PoolAccountPalletId: PalletId = PalletId(*b"bit/pool"); + pub const RewardPayoutAccountPalletId: PalletId = PalletId(*b"bit/pout"); + pub const RewardHoldingAccountPalletId: PalletId = PalletId(*b"bit/hold"); + pub const MaxAuthorities: u32 = 50; pub const MaxSetIdSessionEntries: u64 = u64::MAX; } @@ -588,6 +594,8 @@ impl nft::Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = ::Signer; } parameter_types! { @@ -1435,6 +1443,44 @@ impl modules_bridge::Config for Runtime { type PalletId = BridgeSovereignPalletId; } +impl orml_rewards::Config for Runtime { + type Share = Balance; + type Balance = Balance; + type PoolId = PoolId; + type CurrencyId = FungibleTokenId; + type Handler = Spp; +} + +parameter_types! { + pub const MaximumQueue: u32 = 50; + pub const MockRelayBlockNumberProvider: BlockNumber = 0; +} + +impl BlockNumberProvider for MockRelayBlockNumberProvider { + type BlockNumber = BlockNumber; + + fn current_block_number() -> Self::BlockNumber { + Self::get() + } +} + +impl spp::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MultiCurrency = Currencies; + type WeightInfo = weights::module_spp::WeightInfo; + type MinimumStake = MinimumStake; + type NetworkFee = NetworkFee; + type StorageDepositFee = StorageDepositFee; + type RelayChainBlockNumber = MockRelayBlockNumberProvider; + type PoolAccount = PoolAccountPalletId; + type RewardPayoutAccount = RewardPayoutAccountPalletId; + type RewardHoldingAccount = RewardHoldingAccountPalletId; + type MaximumQueue = MaximumQueue; + type CurrencyIdConversion = ForeignAssetMapping; + type GovernanceOrigin = EnsureRootOrTwoThirdsCouncilCollective; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime where @@ -1508,6 +1554,10 @@ construct_runtime!( // Bridge BridgeSupport: modules_bridge::{Pallet, Call, Storage, Event}, + + // Spp + Spp: spp::{Pallet, Call, Storage, Event}, + Rewards: orml_rewards::{Pallet, Storage} } ); diff --git a/runtime/metaverse/src/weights/mod.rs b/runtime/metaverse/src/weights/mod.rs index 8d70a266d..f934833ce 100644 --- a/runtime/metaverse/src/weights/mod.rs +++ b/runtime/metaverse/src/weights/mod.rs @@ -9,3 +9,4 @@ pub mod module_metaverse; pub mod module_mining; pub mod module_nft; pub mod module_reward; +pub mod module_spp; diff --git a/runtime/metaverse/src/weights/module_nft.rs b/runtime/metaverse/src/weights/module_nft.rs index 86909c591..1bd3bbfb2 100644 --- a/runtime/metaverse/src/weights/module_nft.rs +++ b/runtime/metaverse/src/weights/module_nft.rs @@ -66,4 +66,9 @@ impl nft::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + fn mint_pre_signed() -> Weight { + Weight::from_parts(91_000_000, 19036) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } } diff --git a/runtime/metaverse/src/weights/module_spp.rs b/runtime/metaverse/src/weights/module_spp.rs new file mode 100644 index 000000000..8e4985b6e --- /dev/null +++ b/runtime/metaverse/src/weights/module_spp.rs @@ -0,0 +1,168 @@ +// This file is part of Metaverse.Network & Bit.Country. + +// Copyright (C) 2020-2022 Metaverse.Network & Bit.Country . +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for estate +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-11-03, STEPS: `20`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// ./target/release/metaverse-node +// benchmark +// --chain=dev +// --pallet=estate +// --extrinsic=* +// --steps=20 +// --repeat=10 +// --execution=wasm +// --wasm-execution=compiled +// --template=./template/runtime-weight-template.hbs +// --output +// ./pallets/estate/src/weights.rs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +/// Weight functions for estate. +pub struct WeightInfo(PhantomData); + +impl spp::WeightInfo for WeightInfo { + fn mint_land() -> Weight { + Weight::from_parts(59_273_000, 36660) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) + } + fn mint_lands() -> Weight { + Weight::from_parts(83_541_000, 41610) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(10)) + } + fn transfer_land() -> Weight { + Weight::from_parts(47_423_000, 28255) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + fn mint_estate() -> Weight { + Weight::from_parts(64_479_000, 47210) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(11)) + } + fn dissolve_estate() -> Weight { + Weight::from_parts(110_008_000, 67224) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(13)) + } + fn add_land_unit_to_estate() -> Weight { + Weight::from_parts(71_706_000, 38079) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) + } + fn remove_land_unit_from_estate() -> Weight { + Weight::from_parts(90_257_000, 60226) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(8)) + } + fn create_estate() -> Weight { + Weight::from_parts(131_741_000, 66058) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(17)) + } + fn transfer_estate() -> Weight { + Weight::from_parts(54_808_000, 38025) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) + } + fn issue_undeployed_land_blocks() -> Weight { + Weight::from_parts(162_875_000, 9825) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(43)) + } + fn freeze_undeployed_land_blocks() -> Weight { + Weight::from_parts(22_833_000, 7834) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn unfreeze_undeployed_land_blocks() -> Weight { + Weight::from_parts(21_423_000, 7834) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn approve_undeployed_land_blocks() -> Weight { + Weight::from_parts(21_819_000, 7834) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn unapprove_undeployed_land_blocks() -> Weight { + Weight::from_parts(21_237_000, 7900) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn transfer_undeployed_land_blocks() -> Weight { + Weight::from_parts(41_173_000, 13673) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + fn deploy_land_block() -> Weight { + Weight::from_parts(100_659_000, 64897) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(11)) + } + fn burn_undeployed_land_blocks() -> Weight { + Weight::from_parts(32_196_000, 10661) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + fn create_lease_offer() -> Weight { + Weight::from_parts(98_902_000, 27383) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(2)) + } + fn accept_lease_offer() -> Weight { + Weight::from_parts(57_019_000, 28844) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) + } + fn cancel_lease() -> Weight { + Weight::from_parts(57_720_000, 28571) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + fn remove_expired_lease() -> Weight { + Weight::from_parts(57_681_000, 28571) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) + } + fn remove_lease_offer() -> Weight { + Weight::from_parts(41_923_000, 8328) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + fn collect_rent() -> Weight { + Weight::from_parts(53_171_000, 28571) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + } + fn on_initialize() -> Weight { + Weight::from_parts(191_000, 0) + } +} \ No newline at end of file diff --git a/runtime/pioneer/src/lib.rs b/runtime/pioneer/src/lib.rs index ec66d3f43..2e50e8558 100644 --- a/runtime/pioneer/src/lib.rs +++ b/runtime/pioneer/src/lib.rs @@ -1452,6 +1452,8 @@ impl nft::Config for Runtime { type AssetMintingFee = AssetMintingFee; type ClassMintingFee = ClassMintingFee; type StorageDepositFee = StorageDepositFee; + type OffchainSignature = Signature; + type OffchainPublic = ::Signer; } parameter_types! { diff --git a/runtime/pioneer/src/weights/module_nft.rs b/runtime/pioneer/src/weights/module_nft.rs index 86909c591..1bd3bbfb2 100644 --- a/runtime/pioneer/src/weights/module_nft.rs +++ b/runtime/pioneer/src/weights/module_nft.rs @@ -66,4 +66,9 @@ impl nft::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + fn mint_pre_signed() -> Weight { + Weight::from_parts(91_000_000, 19036) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) + } } diff --git a/traits/core-primitives/src/lib.rs b/traits/core-primitives/src/lib.rs index 97c02e08c..5aa8b55df 100644 --- a/traits/core-primitives/src/lib.rs +++ b/traits/core-primitives/src/lib.rs @@ -162,6 +162,24 @@ pub struct MetaverseFund { pub currency_id: FungibleTokenId, } +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PreSignedMint { + /// A collection of the item to be minted. + pub class_id: ClassId, + /// TokenId. + pub token_id: Option, + /// Additional item's key-value attributes. + pub attributes: Attributes, + /// Additional item's metadata. + pub metadata: NftMetadata, + /// Restrict the claim to a particular account. + pub only_account: Option, + /// A deadline for the signature. + pub expired: BlockNumber, + /// An optional price the claimer would need to pay for the mint. + pub mint_price: Option, +} + pub trait MetaverseTrait { /// Create metaverse fn create_metaverse(who: &AccountId, metadata: MetaverseMetadata) -> MetaverseId; @@ -384,3 +402,9 @@ impl MiningResourceRateInfo { self.mining_reward = mining_reward; } } + +pub trait CurrencyIdManagement { + fn check_token_exist(currency_id: FungibleTokenId) -> bool; + fn convert_to_rcurrency(currency_id: FungibleTokenId) -> Result; + fn convert_to_currency(currency_id: FungibleTokenId) -> Result; +}