From 25e7a6fa6d2101f2742c5695ef0bc7464eeec2cc Mon Sep 17 00:00:00 2001 From: str-mv <51784859+str-mv@users.noreply.github.com> Date: Fri, 18 Jun 2021 07:52:46 +0000 Subject: [PATCH] Merge pull request #155 from usetech-llc/release/v3.0.0 Release/v3.0.0 --- --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -9,6 +9,6 @@ export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" && \ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \ nvm install v12.20.1 && \ - rustup toolchain install nightly-2020-10-01 && \ - rustup default nightly-2020-10-01 && \ + rustup toolchain install nightly-2021-03-01 && \ + rustup default nightly-2021-03-01 && \ rustup target add wasm32-unknown-unknown \ No newline at end of file --- a/.github/workflows/main.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Docker build - -on: - push: - branches: [ master ] - schedule: - - cron: '* 1 * * *' - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Docker login - run: docker login -u gzusetech -p "$TOKEN" - env: - TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }} - - name: Build image - run: docker build -t usetechcorp/nft_parachain . - - name: Push the image to Docker hub - run: docker push usetechcorp/nft_parachain:latest - --- /dev/null +++ b/.github/workflows/node_build_test.yml @@ -0,0 +1,44 @@ +name: Build & test + +# Controls when the action will run. +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ develop ] + # pull_request: + # branches: [ develop ] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build: + # The type of runner that the job will run on + runs-on: ubuntu-20.04 + + # if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + #runs ssh connection + - name: Go to server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SERVER_IP }} + username: ${{ secrets.SERVER_USERNAME }} + key: ${{ secrets.KEY }} + port: ${{ secrets.SERVER_PORT }} + # command_timeout: 200m + script: | + eval $(ssh-agent -s) + ssh-add /home/devops/.ssh/git_hub + git clone git@github.com:usetech-llc/nft_private.git + cd nft_private + git checkout develop + # git pull --all + chmod +x ci_node.sh + ./ci_node.sh + rm -rf /home/polkadot/nft_private \ No newline at end of file --- a/.github/workflows/notify.yml +++ b/.github/workflows/notify.yml @@ -6,8 +6,8 @@ build: runs-on: ubuntu-latest steps: - - uses: avkviring/telegram-github-action@v0.0.8 + - uses: avkviring/telegram-github-action@v0.0.13 env: telegram_to: ${{ secrets.TELEGRAM_TO }} telegram_token: ${{ secrets.TELEGRAM_TOKEN }} - event: ${{ toJson(github.event) }} \ No newline at end of file + event: ${{ toJson(github.event) }} --- a/Cargo.lock +++ b/Cargo.lock @@ -16,7 +16,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ - "gimli 0.23.0", + "gimli", ] [[package]] @@ -380,6 +380,12 @@ ] [[package]] +name = "base-x" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" + +[[package]] name = "base58" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -439,12 +445,14 @@ [[package]] name = "bitvec" -version = "0.17.4" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +checksum = "f5011ffc90248764d7005b0e10c7294f5aa1bd87d9dd7248f4ad475b347c294d" dependencies = [ - "either", + "funty", "radium", + "tap", + "wyz", ] [[package]] @@ -480,6 +488,32 @@ ] [[package]] +name = "blake2s_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq", +] + +[[package]] +name = "blake3" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "cc", + "cfg-if 0.1.10", + "constant_time_eq", + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -555,6 +589,15 @@ ] [[package]] +name = "build-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f" +dependencies = [ + "semver 0.6.0", +] + +[[package]] name = "bumpalo" version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -562,9 +605,9 @@ [[package]] name = "byte-slice-cast" -version = "0.3.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" +checksum = "65c1bf4a04a88c54f589125563643d773f3254b5c38571395e2b591c693bbc81" [[package]] name = "byte-tools" @@ -608,6 +651,28 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] +name = "cargo-platform" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" +dependencies = [ + "cargo-platform", + "semver 0.11.0", + "semver-parser 0.10.2", + "serde", + "serde_json", +] + +[[package]] name = "cc" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -674,6 +739,17 @@ ] [[package]] +name = "cid" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff0e3bc0b6446b3f9663c1a6aba6ef06c5aeaa1bc92bd18077be337198ab9768" +dependencies = [ + "multibase", + "multihash", + "unsigned-varint 0.5.1", +] + +[[package]] name = "cipher" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -755,6 +831,16 @@ checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" [[package]] +name = "cpp_demangle" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44919ecaf6f99e8e737bc239408931c9a01e9a6c74814fee8242dd2506b65390" +dependencies = [ + "cfg-if 1.0.0", + "glob", +] + +[[package]] name = "cpuid-bool" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -768,25 +854,25 @@ [[package]] name = "cranelift-bforest" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dcc286b052ee24a1e5a222e7c1125e6010ad35b0f248709b9b3737a8fedcfdf" +checksum = "4066fd63b502d73eb8c5fa6bcab9c7962b05cd580f6b149ee83a8e730d8ce7fb" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9badfe36176cb653506091693bc2bb1970c9bddfcd6ec7fac404f7eaec6f38" +checksum = "1a54e4beb833a3c873a18a8fe735d73d732044004c7539a072c8faa35ccb0c60" dependencies = [ "byteorder", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", "cranelift-entity", - "gimli 0.21.0", + "gimli", "log", "regalloc", "serde", @@ -797,9 +883,9 @@ [[package]] name = "cranelift-codegen-meta" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3f460031861e4f4ad510be62b2ae50bba6cc886b598a36f9c0a970feab9598" +checksum = "c54cac7cacb443658d8f0ff36a3545822613fa202c946c0891897843bc933810" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -807,24 +893,24 @@ [[package]] name = "cranelift-codegen-shared" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ad12409e922e7697cd0bdc7dc26992f64a77c31880dfe5e3c7722f4710206d" +checksum = "a109760aff76788b2cdaeefad6875a73c2b450be13906524f6c2a81e05b8d83c" [[package]] name = "cranelift-entity" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97cdc58972ea065d107872cfb9079f4c92ade78a8af85aaff519a65b5d13f71" +checksum = "3b044234aa32531f89a08b487630ddc6744696ec04c8123a1ad388de837f5de3" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef419efb4f94ecc02e5d9fbcc910d2bb7f0040e2de570e63a454f883bc891d6" +checksum = "5452b3e4e97538ee5ef2cc071301c69a86c7adf2770916b9d04e9727096abd93" dependencies = [ "cranelift-codegen", "log", @@ -834,9 +920,9 @@ [[package]] name = "cranelift-native" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e69d44d59826eef6794066ac2c0f4ad3975f02d97030c60dbc04e3886adf36e" +checksum = "f68035c10b2e80f26cc29c32fa824380877f38483504c2a47b54e7da311caaf3" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -845,17 +931,19 @@ [[package]] name = "cranelift-wasm" -version = "0.66.0" +version = "0.69.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "979df666b1304624abe99738e9e0e7c7479ee5523ba4b8b237df9ff49996acbb" +checksum = "a530eb9d1c95b3309deb24c3d179d8b0ba5837ed98914a429787c395f614949d" dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", + "itertools", "log", "serde", + "smallvec 1.6.1", "thiserror", - "wasmparser 0.59.0", + "wasmparser", ] [[package]] @@ -1050,6 +1138,26 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" [[package]] +name = "data-encoding-macro" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a94feec3d2ba66c0b6621bca8bc6f68415b1e5c69af3586fdd0af9fd9f29b17" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f83e699727abca3c56e187945f303389590305ab2f0185ea445aa66e8d5f2a" +dependencies = [ + "data-encoding", + "syn", +] + +[[package]] name = "derive_more" version = "0.99.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1080,21 +1188,21 @@ [[package]] name = "directories" -version = "2.0.2" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" dependencies = [ - "cfg-if 0.1.10", "dirs-sys", ] [[package]] -name = "directories" -version = "3.0.1" +name = "directories-next" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" dependencies = [ - "dirs-sys", + "cfg-if 1.0.0", + "dirs-sys-next", ] [[package]] @@ -1104,11 +1212,22 @@ checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ "libc", - "redox_users", + "redox_users 0.3.5", "winapi 0.3.9", ] [[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users 0.4.0", + "winapi 0.3.9", +] + +[[package]] name = "dns-parser" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1322,17 +1441,17 @@ [[package]] name = "finality-grandpa" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8feb87a63249689640ac9c011742c33139204e3c134293d3054022276869133b" +checksum = "2cd795898c348a8ec9edc66ec9e014031c764d4c88cc26d09b492cd93eb41339" dependencies = [ "either", "futures 0.3.12", - "futures-timer 2.0.2", + "futures-timer 3.0.2", "log", "num-traits", "parity-scale-codec", - "parking_lot 0.9.0", + "parking_lot 0.11.1", ] [[package]] @@ -1390,8 +1509,9 @@ [[package]] name = "fork-tree" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632b95f97f332b2ff5bc3a42bc8e28772b067e333830e03fd046504f11cd0fb8" dependencies = [ "parity-scale-codec", ] @@ -1408,14 +1528,15 @@ [[package]] name = "frame-benchmarking" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70fe99487f84579a3f2c4ba52650fec875492eea41be0e4eea8019187f105052" dependencies = [ "frame-support", "frame-system", "linregress", "parity-scale-codec", - "paste", + "paste 1.0.4", "sp-api", "sp-io", "sp-runtime", @@ -1426,8 +1547,9 @@ [[package]] name = "frame-benchmarking-cli" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2921b7890c5e4421a0b2eafbf835417eed8127b1cec3e1a0389515069f11d219" dependencies = [ "Inflector", "chrono", @@ -1449,8 +1571,9 @@ [[package]] name = "frame-executive" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1da8fd471442bee91b9b3f587ec832e3f47800374fdb89b4a66591cd7c42b29f" dependencies = [ "frame-support", "frame-system", @@ -1465,8 +1588,9 @@ [[package]] name = "frame-metadata" -version = "12.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "073f7bef18421362441a1708f8528e442234954611f95bdc554b313fb321948e" dependencies = [ "parity-scale-codec", "serde", @@ -1476,17 +1600,18 @@ [[package]] name = "frame-support" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e521e6214615bd82ba6b5fc7fd40a9cc14fdeb40f83da5eba12aa2f8179fb8" dependencies = [ "bitflags", "frame-metadata", "frame-support-procedural", - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "log", "once_cell", "parity-scale-codec", - "paste", + "paste 1.0.4", "serde", "smallvec 1.6.1", "sp-arithmetic", @@ -1494,6 +1619,7 @@ "sp-inherents", "sp-io", "sp-runtime", + "sp-staking", "sp-state-machine", "sp-std", "sp-tracing", @@ -1501,8 +1627,9 @@ [[package]] name = "frame-support-procedural" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2668e24cbaba7f0e91d0c92a94bd1ae425a942608ad0b775db32477f5df4da9e" dependencies = [ "Inflector", "frame-support-procedural-tools", @@ -1513,8 +1640,9 @@ [[package]] name = "frame-support-procedural-tools" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f88cfd111e004590f4542b75e6d3302137b9067d7e7219e4ac47a535c3b5c1" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -1525,8 +1653,9 @@ [[package]] name = "frame-support-procedural-tools-derive" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79285388b120ac96c15a791c56b26b9264f7231324fbe0fd05026acd92bf2e6a" dependencies = [ "proc-macro2", "quote", @@ -1535,11 +1664,12 @@ [[package]] name = "frame-system" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fedbff05d665c00bf4e089b4377fcb15b8bd37ebc3e5fc06665474cf6e25d7" dependencies = [ "frame-support", - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-scale-codec", "serde", "sp-core", @@ -1551,8 +1681,9 @@ [[package]] name = "frame-system-benchmarking" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e93602f58cdab9820b6d607b7b50834d9b878efa33405a65c89ebfb5a596b584" dependencies = [ "frame-benchmarking", "frame-support", @@ -1565,8 +1696,9 @@ [[package]] name = "frame-system-rpc-runtime-api" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cb9d2f86a903fdee4ca3d660c767e69a743cee8aeb103563a14ea52e9f0001d" dependencies = [ "parity-scale-codec", "sp-api", @@ -1607,6 +1739,12 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] name = "futures" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1841,20 +1979,14 @@ [[package]] name = "gimli" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" dependencies = [ "fallible-iterator", "indexmap", "stable_deref_trait", ] - -[[package]] -name = "gimli" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" [[package]] name = "glob" @@ -2229,9 +2361,9 @@ [[package]] name = "impl-codec" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" +checksum = "df170efa359aebdd5cb7fe78edcc67107748e4737bdca8a8fb40d15ea7a877ed" dependencies = [ "parity-scale-codec", ] @@ -2243,17 +2375,6 @@ checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" dependencies = [ "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" -dependencies = [ - "proc-macro2", - "quote", - "syn", ] [[package]] @@ -2509,9 +2630,9 @@ [[package]] name = "kvdb" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92312348daade49976a6dc59263ad39ed54f840aacb5664874f7c9aa16e5f848" +checksum = "8891bd853eff90e33024195d79d578dc984c82f9e0715fcd2b525a0c19d52811" dependencies = [ "parity-util-mem", "smallvec 1.6.1", @@ -2519,9 +2640,9 @@ [[package]] name = "kvdb-memorydb" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "986052a8d16c692eaebe775391f9a3ac26714f3907132658500b601dec94c8c2" +checksum = "30a0da8e08caf08d384a620ec19bb6c9b85c84137248e202617fb91881f25912" dependencies = [ "kvdb", "parity-util-mem", @@ -2530,9 +2651,9 @@ [[package]] name = "kvdb-rocksdb" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d92c36be64baba5ea549116ff0d7ffd445456a7be8aaee21ec05882b980cd11" +checksum = "34446c373ccc494c2124439281c198c7636ccdc2752c06722bbffd56d459c1e4" dependencies = [ "fs-swap", "kvdb", @@ -3146,13 +3267,12 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] -name = "memmap" -version = "0.7.0" +name = "memmap2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +checksum = "04e3e85b970d650e2ae6d70592474087051c11c54da7f7b4949725c5735fbcc6" dependencies = [ "libc", - "winapi 0.3.9", ] [[package]] @@ -3175,9 +3295,9 @@ [[package]] name = "memory-db" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbd2a22f201c03cc1706a727842490abfea17b7b53260358239828208daba3c" +checksum = "814bbecfc0451fc314eeea34f05bbcd5b98a7ad7af37faee088b86a1e633f1d4" dependencies = [ "hash-db", "hashbrown", @@ -3315,15 +3435,30 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" [[package]] +name = "multibase" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b78c60039650ff12e140ae867ef5299a58e19dded4d334c849dc7177083667e2" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + +[[package]] name = "multihash" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" dependencies = [ + "blake2b_simd", + "blake2s_simd", + "blake3", "digest 0.9.0", "generic-array 0.14.4", "multihash-derive", "sha2 0.9.3", + "sha3", "unsigned-varint 0.5.1", ] @@ -3456,7 +3591,7 @@ [[package]] name = "nft-runtime" -version = "2.1.0" +version = "3.0.0" dependencies = [ "frame-benchmarking", "frame-executive", @@ -3494,7 +3629,7 @@ "sp-std", "sp-transaction-pool", "sp-version", - "substrate-wasm-builder-runner", + "substrate-wasm-builder", ] [[package]] @@ -3584,19 +3719,12 @@ [[package]] name = "object" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" - -[[package]] -name = "object" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ "crc32fast", "indexmap", - "wasmparser 0.57.0", ] [[package]] @@ -3643,8 +3771,9 @@ [[package]] name = "pallet-aura" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ff6054e982e7841a2519c988680620a85c1da5cd32363998a30302ed47f6f9" dependencies = [ "frame-support", "frame-system", @@ -3654,7 +3783,6 @@ "serde", "sp-application-crypto", "sp-consensus-aura", - "sp-inherents", "sp-runtime", "sp-std", "sp-timestamp", @@ -3662,12 +3790,13 @@ [[package]] name = "pallet-authorship" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47433a94141451e7079aabf3ca28f2bde8c642d84b568be9626e9b7cae8b11b1" dependencies = [ "frame-support", "frame-system", - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-scale-codec", "sp-authorship", "sp-inherents", @@ -3677,8 +3806,9 @@ [[package]] name = "pallet-balances" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41aaeaf084e594273f82bcbf96416ef1fcab602e15dd1df04b9930eceb2eb518" dependencies = [ "frame-benchmarking", "frame-support", @@ -3691,15 +3821,16 @@ [[package]] name = "pallet-contracts" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0979c1dd82fc56a87b37311006fe56f406de027c24591353058e9e9fc56487c" dependencies = [ "frame-support", "frame-system", "pallet-contracts-primitives", "pallet-contracts-proc-macro", "parity-scale-codec", - "parity-wasm", + "parity-wasm 0.41.0", "pwasm-utils 0.16.0", "serde", "sp-core", @@ -3712,8 +3843,9 @@ [[package]] name = "pallet-contracts-primitives" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "621d75148763349f72e76e79f62365d28adb51e3f2e0285e4e8b8600ae600978" dependencies = [ "bitflags", "parity-scale-codec", @@ -3723,8 +3855,9 @@ [[package]] name = "pallet-contracts-proc-macro" -version = "0.1.0" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90046017aeee3f77752a6c77cdfb1bc93eb728591dc6edad36e2706f7626fd50" dependencies = [ "proc-macro2", "quote", @@ -3733,8 +3866,9 @@ [[package]] name = "pallet-contracts-rpc" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22491e3c304819f96c83d02e43bd99128e4e42a57da4d6a9d4b5193778da915b" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -3752,8 +3886,9 @@ [[package]] name = "pallet-contracts-rpc-runtime-api" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4b410cb148e68256e3827854a67ec34b16157f448e78173219dcd6a8ec7343" dependencies = [ "pallet-contracts-primitives", "parity-scale-codec", @@ -3764,8 +3899,9 @@ [[package]] name = "pallet-grandpa" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c012cb0337ce1eaf0685be2777bce1ef8c5d7b7be77ea33916c316b40af43fa" dependencies = [ "frame-benchmarking", "frame-support", @@ -3785,12 +3921,11 @@ [[package]] name = "pallet-nft" -version = "2.1.0" +version = "3.0.0" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log", "pallet-balances", "pallet-contracts", "pallet-randomness-collective-flip", @@ -3806,8 +3941,9 @@ [[package]] name = "pallet-randomness-collective-flip" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3ea6fa9aa36735ec11d7ec4d97dd6472650c0656fdc6d4adaca2578bd71134" dependencies = [ "frame-support", "frame-system", @@ -3819,12 +3955,13 @@ [[package]] name = "pallet-session" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d243c3ccac56a4c55fade6be5c5af1de07fac374fa7856377980a76b0c193cf" dependencies = [ "frame-support", "frame-system", - "impl-trait-for-tuples 0.1.3", + "impl-trait-for-tuples", "pallet-timestamp", "parity-scale-codec", "serde", @@ -3839,8 +3976,9 @@ [[package]] name = "pallet-sudo" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a96774302e3824b7924c2465935ca4d558ea5f6a762c043fbc45fd2646ce89" dependencies = [ "frame-support", "frame-system", @@ -3853,13 +3991,14 @@ [[package]] name = "pallet-timestamp" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b17dd274716a55a2c3e34d9c0ed66aaac3d7e0393ec9fd985e2b8532d697a7f3" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-scale-codec", "serde", "sp-inherents", @@ -3871,8 +4010,9 @@ [[package]] name = "pallet-transaction-payment" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e10dc1a10dd3f52edb20d3885cf5b2b16f26273a4d93e61331c6691fb13ab3" dependencies = [ "frame-support", "frame-system", @@ -3887,8 +4027,9 @@ [[package]] name = "pallet-transaction-payment-rpc" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7835717b7d8fb59c33dd73f083c68a6d143a1dbe6029364c63ea7f4cb0ba3f9c" dependencies = [ "jsonrpc-core", "jsonrpc-core-client", @@ -3904,8 +4045,9 @@ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a92d3383260d0d19d9a36f40766d48d779fd19baccba8b20c3e7d2670a26ee1" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -3915,12 +4057,13 @@ [[package]] name = "pallet-treasury" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19f881664d42d1c33dd67e690d6bddd35d38723fcc099b19304f9723fc3070c" dependencies = [ "frame-support", "frame-system", - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "pallet-balances", "parity-scale-codec", "serde", @@ -3930,8 +4073,9 @@ [[package]] name = "pallet-vesting" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4e1af42bbdf1d477c3762387c74855f24bca47700df3ce7d9428045986b544" dependencies = [ "enumflags2", "frame-support", @@ -3944,16 +4088,18 @@ [[package]] name = "parity-db" -version = "0.1.2" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d595e372d119261593297debbe4193811a4dc811d2a1ccbb8caaa6666ad7ab" +checksum = "111e193c96758d476d272093a853882668da17489f76bf4361b8decae0b6c515" dependencies = [ "blake2-rfc", "crc32fast", + "hex", "libc", "log", - "memmap", - "parking_lot 0.10.2", + "memmap2", + "parking_lot 0.11.1", + "rand 0.8.3", ] [[package]] @@ -3976,9 +4122,9 @@ [[package]] name = "parity-scale-codec" -version = "1.3.6" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79602888a81ace83e3d1d4b2873286c1f5f906c84db667594e8db8da3506c383" +checksum = "0cd3dab59b5cf4bc81069ade0fc470341a1ef3ad5fa73e5a8943bed2ec12b2e8" dependencies = [ "arrayvec 0.5.2", "bitvec", @@ -3989,9 +4135,9 @@ [[package]] name = "parity-scale-codec-derive" -version = "1.2.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db82bb1c18fc00176004462dd809b2a6d851669550aa17af6dacd21ae0c14" +checksum = "fa04976a81fde04924b40cc4036c4d12841e8bb04325a5cf2ada75731a150a7d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4026,13 +4172,13 @@ [[package]] name = "parity-util-mem" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f17f15cb05897127bf36a240085a1f0bbef7bce3024849eccf7f93f6171bc27" +checksum = "664a8c6b8e62d8f9f2f937e391982eb433ab285b4cd9545b342441e04a906e42" dependencies = [ "cfg-if 1.0.0", "hashbrown", - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-util-mem-derive", "parking_lot 0.11.1", "primitive-types", @@ -4053,6 +4199,15 @@ [[package]] name = "parity-wasm" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ad52817c4d343339b3bc2e26861bd21478eda0b7509acf83505727000512ac" +dependencies = [ + "byteorder", +] + +[[package]] +name = "parity-wasm" version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" @@ -4167,6 +4322,12 @@ ] [[package]] +name = "paste" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" + +[[package]] name = "paste-impl" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4337,9 +4498,9 @@ [[package]] name = "platforms" -version = "0.2.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e" +checksum = "989d43012e2ca1c4a02507c67282691a0a3207f9dc67cec596b43fe925b3d325" [[package]] name = "polling" @@ -4383,9 +4544,9 @@ [[package]] name = "primitive-types" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3824ae2c5e27160113b9e029a10ec9e3f0237bad8029f69c7724393c9fdefd8" +checksum = "2415937401cb030a2a0a4d922483f945fa068f52a7dbb22ce0fe5f2b6f6adace" dependencies = [ "fixed-hash", "impl-codec", @@ -4449,11 +4610,11 @@ [[package]] name = "prometheus" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d70cf4412832bcac9cffe27906f4a66e450d323525e977168c70d1b36120ae" +checksum = "c8425533e7122f0c3cc7a37e6244b16ad3a2cc32ae7ac6276e2a75da0d9c200d" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "fnv", "lazy_static", "parking_lot 0.11.1", @@ -4513,6 +4674,15 @@ ] [[package]] +name = "psm" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abf49e5417290756acfd26501536358560c4a5cc4a0934d390939acb3e7083a" +dependencies = [ + "cc", +] + +[[package]] name = "pwasm-utils" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4520,7 +4690,7 @@ dependencies = [ "byteorder", "log", - "parity-wasm", + "parity-wasm 0.41.0", ] [[package]] @@ -4531,7 +4701,7 @@ dependencies = [ "byteorder", "log", - "parity-wasm", + "parity-wasm 0.41.0", ] [[package]] @@ -4568,9 +4738,9 @@ [[package]] name = "radium" -version = "0.3.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" [[package]] name = "rand" @@ -4712,9 +4882,9 @@ [[package]] name = "raw-cpuid" -version = "7.0.4" +version = "8.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb71f708fe39b2c5e98076204c3cc094ee5a4c12c4cdb119a2b72dc34164f41" +checksum = "1fdf7d9dbd43f3d81d94a49c1c3df73cc2b3827995147e6cf7f89d4ec5483e73" dependencies = [ "bitflags", "cc", @@ -4788,6 +4958,16 @@ ] [[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom 0.2.2", + "redox_syscall 0.2.5", +] + +[[package]] name = "ref-cast" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4809,9 +4989,9 @@ [[package]] name = "regalloc" -version = "0.0.27" +version = "0.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ba8aaf5fe7cf307c6dbdaeed85478961d29e25e3bee5169e11b92fa9f027a8" +checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" dependencies = [ "log", "rustc-hash", @@ -4944,7 +5124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", ] [[package]] @@ -5021,9 +5201,19 @@ ] [[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] name = "sc-basic-authorship" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de86afb63617599821312bda08882451ff2b49d9c45e22513ddff5a07c6d966e" dependencies = [ "futures 0.3.12", "futures-timer 3.0.2", @@ -5045,8 +5235,9 @@ [[package]] name = "sc-block-builder" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9862161f9d09d870401c7256c89ad1eb3afa56a61f7d7135c2bac76ff7152955" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -5062,10 +5253,11 @@ [[package]] name = "sc-chain-spec" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d97030776b49bc9c109e2d349212d8f2500637761048e1af5b7ce2dfd994c7" dependencies = [ - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-scale-codec", "sc-chain-spec-derive", "sc-consensus-babe", @@ -5083,8 +5275,9 @@ [[package]] name = "sc-chain-spec-derive" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f14985513db9798fcedea58bdc8a08f1c6b3a515d6546ced7467b059b7982c4" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5094,8 +5287,9 @@ [[package]] name = "sc-cli" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ec1647b5c1483fa05f7f32e436d0e378e2f3d5696a5a30bddf66f5faf28acb4" dependencies = [ "chrono", "fdlimit", @@ -5132,8 +5326,9 @@ [[package]] name = "sc-client-api" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d8b2c8dc0cee9ac56e87ad50c980edbdeb35bdd5b5d9da4ae90567423363be" dependencies = [ "derive_more", "fnv", @@ -5166,8 +5361,9 @@ [[package]] name = "sc-client-db" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5741e447d71ff36c147f961b2271b6b3fad0cc347e96936bc8b63ddffa594b27" dependencies = [ "blake2-rfc", "hash-db", @@ -5196,8 +5392,9 @@ [[package]] name = "sc-consensus" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f20cc8b8a74e218365ac4187bce26ea631d58d221caa1797bc6ec8056dba33" dependencies = [ "sc-client-api", "sp-blockchain", @@ -5207,8 +5404,9 @@ [[package]] name = "sc-consensus-aura" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e0d32ccddef567a0fe373729aa4da51b2d437cbb102b9810400c9e77e040c1d" dependencies = [ "derive_more", "futures 0.3.12", @@ -5226,6 +5424,7 @@ "sp-blockchain", "sp-consensus", "sp-consensus-aura", + "sp-consensus-slots", "sp-core", "sp-inherents", "sp-io", @@ -5238,8 +5437,9 @@ [[package]] name = "sc-consensus-babe" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d52048476e0fcb53feae8ca919a602104f1ba0b89a729b496440f36b332961" dependencies = [ "derive_more", "fork-tree", @@ -5269,6 +5469,7 @@ "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-consensus-slots", "sp-consensus-vrf", "sp-core", "sp-inherents", @@ -5283,8 +5484,9 @@ [[package]] name = "sc-consensus-epochs" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "326313ffb249a526e8ee8e08af9fdf0c4459cebeaa760b934e9df3985b68e4df" dependencies = [ "fork-tree", "parity-scale-codec", @@ -5296,8 +5498,9 @@ [[package]] name = "sc-consensus-slots" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e09ff8b680d449102da9717a70c3bbbbb981fd4cf1bfbafc1739d954eb0898" dependencies = [ "futures 0.3.12", "futures-timer 3.0.2", @@ -5322,8 +5525,9 @@ [[package]] name = "sc-consensus-uncles" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37294bae6d787eecf2b15255dc75cd559b4ad813e0efcf28cd4423e218931b80" dependencies = [ "log", "sc-client-api", @@ -5336,15 +5540,16 @@ [[package]] name = "sc-executor" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bace6a35999d2da7311d8fb98a29c1e89dbf0d14e50ac14140f2c38089819f46" dependencies = [ "derive_more", "lazy_static", "libsecp256k1", "log", "parity-scale-codec", - "parity-wasm", + "parity-wasm 0.41.0", "parking_lot 0.11.1", "sc-executor-common", "sc-executor-wasmi", @@ -5365,12 +5570,13 @@ [[package]] name = "sc-executor-common" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87004102a8e95f432f1c624c7fa7fb0edc5995db2e0fcbabbb697f1955e7c1d2" dependencies = [ "derive_more", "parity-scale-codec", - "parity-wasm", + "parity-wasm 0.41.0", "sp-allocator", "sp-core", "sp-serializer", @@ -5381,8 +5587,9 @@ [[package]] name = "sc-executor-wasmi" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3d7b6db2df5f2c24848883a855a8276363f00cef5b49744974f7e1203bf274" dependencies = [ "log", "parity-scale-codec", @@ -5396,12 +5603,13 @@ [[package]] name = "sc-executor-wasmtime" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24673c981fad2dff4398a09a1086579e2774f18d81639fa2bd9cb215e6dd9e36" dependencies = [ "log", "parity-scale-codec", - "parity-wasm", + "parity-wasm 0.41.0", "pwasm-utils 0.14.0", "sc-executor-common", "scoped-tls", @@ -5414,8 +5622,9 @@ [[package]] name = "sc-finality-grandpa" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e87e63c57933e173a8643ff197b579e3fc5c91b16ca006096f482de8159318" dependencies = [ "derive_more", "finality-grandpa", @@ -5426,7 +5635,7 @@ "log", "parity-scale-codec", "parking_lot 0.11.1", - "pin-project 0.4.27", + "pin-project 1.0.5", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -5452,8 +5661,9 @@ [[package]] name = "sc-informant" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4c8994853e1158dc4f448b014aa83eef56ced214ec0af316eecf4a6ca3268f" dependencies = [ "ansi_term 0.12.1", "futures 0.3.12", @@ -5470,8 +5680,9 @@ [[package]] name = "sc-keystore" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d966ed36c404eced656bd63aad8a30d2c1a14633f07cd1d7d9c11b62f75a7905" dependencies = [ "async-trait", "derive_more", @@ -5490,8 +5701,9 @@ [[package]] name = "sc-light" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8dbcb2951f7cf76ddf97ed26dcef0dab79d76745de4a8f169d58236ea8704" dependencies = [ "hash-db", "lazy_static", @@ -5509,8 +5721,9 @@ [[package]] name = "sc-network" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20fb4ed5d6b86faafb0743c8c2fd1c89b52cde7697373b254c7553800efaebbf" dependencies = [ "async-std", "async-trait", @@ -5518,6 +5731,7 @@ "bitflags", "bs58", "bytes 1.0.1", + "cid", "derive_more", "either", "erased-serde", @@ -5535,7 +5749,7 @@ "nohash-hasher", "parity-scale-codec", "parking_lot 0.11.1", - "pin-project 0.4.27", + "pin-project 1.0.5", "prost", "prost-build", "rand 0.7.3", @@ -5561,8 +5775,9 @@ [[package]] name = "sc-network-gossip" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2cd5487d6f8051863a186e2aea4c233a07bb691780d3b117c9d6ffe1ff9a8fe" dependencies = [ "futures 0.3.12", "futures-timer 3.0.2", @@ -5577,8 +5792,9 @@ [[package]] name = "sc-offchain" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc91fc71c128748a3393cb3421e12a7759ccffcc1cc4a9e6ff4ead6cc68ba48" dependencies = [ "bytes 0.5.6", "fnv", @@ -5604,8 +5820,9 @@ [[package]] name = "sc-peerset" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce454e528e7797a239e734d0d66bf904d48be47aa92691ac7546a45ec32a64cf" dependencies = [ "futures 0.3.12", "libp2p", @@ -5617,8 +5834,9 @@ [[package]] name = "sc-proposer-metrics" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecfc2c6cc5dc0ecb1109cce9773b50ad9a3cdbf239dc702ef9071949244dcf3e" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -5626,8 +5844,9 @@ [[package]] name = "sc-rpc" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "750397c6aa5a4f922cac99599ad74a4082e3e87553d51ceb4c48abfa056ff32c" dependencies = [ "futures 0.3.12", "hash-db", @@ -5660,8 +5879,9 @@ [[package]] name = "sc-rpc-api" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc8393410297df2885efec20d0629a9833b4fd9e4ad83a92471e1ea0c11a0a54" dependencies = [ "derive_more", "futures 0.3.12", @@ -5684,8 +5904,9 @@ [[package]] name = "sc-rpc-server" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c76164897bd3b0d04c2d6aeeb4d3492c86e324b0b08f408b847ea35421b589" dependencies = [ "futures 0.1.30", "jsonrpc-core", @@ -5702,10 +5923,11 @@ [[package]] name = "sc-service" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9315b44eb991ca4f477d889bbd649a2b4b557f963fe48ec5a36c3422518e4a0" dependencies = [ - "directories 3.0.1", + "directories", "exit-future", "futures 0.1.30", "futures 0.3.12", @@ -5718,7 +5940,7 @@ "parity-scale-codec", "parity-util-mem", "parking_lot 0.11.1", - "pin-project 0.4.27", + "pin-project 1.0.5", "rand 0.7.3", "sc-block-builder", "sc-chain-spec", @@ -5765,8 +5987,9 @@ [[package]] name = "sc-state-db" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f144043d5860ce133f701fa78679d6278f2dfc698686beb5f6d892c267e9d92" dependencies = [ "log", "parity-scale-codec", @@ -5780,15 +6003,16 @@ [[package]] name = "sc-telemetry" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05040c594b331d90d7341e82c6dc6a3eb7bb2afb4e5dc9c36a79a6754166057" dependencies = [ "chrono", "futures 0.3.12", "libp2p", "log", "parking_lot 0.11.1", - "pin-project 0.4.27", + "pin-project 1.0.5", "rand 0.7.3", "serde", "serde_json", @@ -5802,8 +6026,9 @@ [[package]] name = "sc-tracing" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef0a4aa327b8bc89d9c5ae57a2f493d8f54ccd706f6763614ab522559fe481d8" dependencies = [ "ansi_term 0.12.1", "atty", @@ -5830,8 +6055,9 @@ [[package]] name = "sc-tracing-proc-macro" -version = "2.0.0" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec18b0506911e6d624d9ea8f8cc5f503e7944a0fe7d37de95ee84033cf160ebc" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5841,8 +6067,9 @@ [[package]] name = "sc-transaction-graph" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87b385b8f66cce185478c500ad3de8f4775ab0e948c31561aeac78a27bedc654" dependencies = [ "derive_more", "futures 0.3.12", @@ -5863,8 +6090,9 @@ [[package]] name = "sc-transaction-pool" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f4331ea8da2ff45a9466637f90f5cc89f9d31fcd1cd20f74f2520b33bff069" dependencies = [ "futures 0.3.12", "futures-diagnose", @@ -5992,11 +6220,30 @@ [[package]] name = "semver" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", + "serde", ] [[package]] @@ -6006,6 +6253,15 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] name = "serde" version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6147,7 +6403,7 @@ "approx", "num-complex", "num-traits", - "paste", + "paste 0.1.18", ] [[package]] @@ -6218,8 +6474,9 @@ [[package]] name = "sp-allocator" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec5f988ad0cabdb646318cb515a91e9d89062debc9728f9b634d73acab3f3f39" dependencies = [ "log", "sp-core", @@ -6230,8 +6487,9 @@ [[package]] name = "sp-api" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63c3460d5daecf67df542c34c2bbd636214a5a200d4bddcfa2ffb9e72c346af" dependencies = [ "hash-db", "parity-scale-codec", @@ -6246,8 +6504,9 @@ [[package]] name = "sp-api-proc-macro" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "289624f4fe0f61e63a5019ed26c3bc732b5145eb52796ac6053cd72656d947a1" dependencies = [ "blake2-rfc", "proc-macro-crate", @@ -6258,8 +6517,9 @@ [[package]] name = "sp-application-crypto" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c52e2e6d43036b97c4fce1ed87c5262c1ffdc78c655ada4d3024a3f8094bdd2c" dependencies = [ "parity-scale-codec", "serde", @@ -6270,8 +6530,9 @@ [[package]] name = "sp-arithmetic" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f1c69966c192d1dee8521f0b29ece2b14db07b9b44d801a94e295234761645" dependencies = [ "integer-sqrt", "num-traits", @@ -6283,8 +6544,9 @@ [[package]] name = "sp-authorship" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec68fb8e5a37548b06c14ee91a9c574cc330324c86d37810ec29dd4f8bc68d7" dependencies = [ "parity-scale-codec", "sp-inherents", @@ -6294,8 +6556,9 @@ [[package]] name = "sp-block-builder" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0adc979dbe619f56d664ebd1293dce13fcad6b8a47bcdd620ed53a454d330d12" dependencies = [ "parity-scale-codec", "sp-api", @@ -6306,8 +6569,9 @@ [[package]] name = "sp-blockchain" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8007c1ad8e9fb6cd8eed4e0fc91504a9ca4b228e1315302a2fbb0ac7f509f1b" dependencies = [ "futures 0.3.12", "log", @@ -6324,8 +6588,9 @@ [[package]] name = "sp-chain-spec" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a24beb11980d0c755ead0c05f3f966c490e4a3730785c04c03855fada65d697" dependencies = [ "serde", "serde_json", @@ -6333,8 +6598,9 @@ [[package]] name = "sp-consensus" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884db6c4b03f0f2fb2993127a2db95fc740fcd3496746dcaa6829c9868e7dc75" dependencies = [ "futures 0.3.12", "futures-timer 3.0.2", @@ -6359,12 +6625,14 @@ [[package]] name = "sp-consensus-aura" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd00fc95b26393522be1394fb67cc536736cc5a902dec0d3e2827909b7c1118" dependencies = [ "parity-scale-codec", "sp-api", "sp-application-crypto", + "sp-consensus-slots", "sp-inherents", "sp-runtime", "sp-std", @@ -6373,8 +6641,9 @@ [[package]] name = "sp-consensus-babe" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a153085b1542b5cbe23686433cd36d1a634964f1b707671d0ffb01d8d9313047" dependencies = [ "merlin", "parity-scale-codec", @@ -6393,17 +6662,20 @@ [[package]] name = "sp-consensus-slots" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32bd501ab76c827d74f145063cd8cb993a9f634dac93c9b0d909111cd5900a6a" dependencies = [ "parity-scale-codec", + "sp-arithmetic", "sp-runtime", ] [[package]] name = "sp-consensus-vrf" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030895d70bf3095c857f4727a7cce7c43af29efe3413bb547ee28700f7d78766" dependencies = [ "parity-scale-codec", "schnorrkel", @@ -6414,8 +6686,9 @@ [[package]] name = "sp-core" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abbc8d4e9b8a7d5819ed26f1374017bb32833ef4890e4ff065e1da30669876bc" dependencies = [ "base58", "blake2-rfc", @@ -6458,8 +6731,9 @@ [[package]] name = "sp-database" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8c3f018913eef191d95c824657c5759c459d28670e654fa34f5d9bd5e6f0492" dependencies = [ "kvdb", "parking_lot 0.11.1", @@ -6467,8 +6741,9 @@ [[package]] name = "sp-debug-derive" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e80275f23b4e7ba8f54dec5f90f016530e7307d2ee9445f617ab986cbe97f31e" dependencies = [ "proc-macro2", "quote", @@ -6477,8 +6752,9 @@ [[package]] name = "sp-externalities" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fdc625f8c7b13b9a136d334888b21b5743d2081cb666cb03efca1dc9b8f74d1" dependencies = [ "environmental", "parity-scale-codec", @@ -6488,8 +6764,9 @@ [[package]] name = "sp-finality-grandpa" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702e0be150e1b557df42326ec9b82c2010366631d03be27c69912d446abbf87a" dependencies = [ "finality-grandpa", "log", @@ -6505,8 +6782,9 @@ [[package]] name = "sp-inherents" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2542380b535c6941502a0a3069a657eb5abb70fd67b11afa164d4a4b038ba73a" dependencies = [ "parity-scale-codec", "parking_lot 0.11.1", @@ -6517,8 +6795,9 @@ [[package]] name = "sp-io" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fd69f0a6e91bedc2fb1c5cc3689c212474b6c918274cb4cb14dbbe3c428c14" dependencies = [ "futures 0.3.12", "hash-db", @@ -6541,8 +6820,9 @@ [[package]] name = "sp-keyring" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b59f2b0e94b2048d4984aa6eb40eef2e4c05d3adf27a083dd3c9b0fce74ef7a" dependencies = [ "lazy_static", "sp-core", @@ -6552,8 +6832,9 @@ [[package]] name = "sp-keystore" -version = "0.8.0" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6ccd2baf189112355338e8b224dc513cd239b974dbd717f12b3dc7a7248c3b" dependencies = [ "async-trait", "derive_more", @@ -6569,8 +6850,9 @@ [[package]] name = "sp-offchain" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd80eedcedcc8342e77c26d59ad90b6904715a862731fa16616650773570e63" dependencies = [ "sp-api", "sp-core", @@ -6579,16 +6861,18 @@ [[package]] name = "sp-panic-handler" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54702e109f1c8a870dd4065a497d2612d42cec5817126e96cc0658c5ea975784" dependencies = [ "backtrace", ] [[package]] name = "sp-rpc" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e5b1ed655d11449073b914b048895f45241e02b3919d1d0187f315435fee18" dependencies = [ "serde", "sp-core", @@ -6596,16 +6880,17 @@ [[package]] name = "sp-runtime" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa4b353b76f04616dbdb8d269d58dcac47acb31c006d3b70e7b64233e68695e" dependencies = [ "either", "hash256-std-hasher", - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "log", "parity-scale-codec", "parity-util-mem", - "paste", + "paste 1.0.4", "rand 0.7.3", "serde", "sp-application-crypto", @@ -6617,10 +6902,11 @@ [[package]] name = "sp-runtime-interface" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5c88b4bc8d607e4e2ff767a85db58cf7101f3dd6064f06929342ea67fe8fb" dependencies = [ - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-scale-codec", "primitive-types", "sp-externalities", @@ -6634,8 +6920,9 @@ [[package]] name = "sp-runtime-interface-proc-macro" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a6c7c2251512c9e533d15db8a863b06ece1cbee778130dd9adbe44b6b39aa9" dependencies = [ "Inflector", "proc-macro-crate", @@ -6646,8 +6933,9 @@ [[package]] name = "sp-sandbox" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e92caf4555d676d8f0b67def0041da789f79a5d5f341130496f15a6261926cc" dependencies = [ "parity-scale-codec", "sp-core", @@ -6659,8 +6947,9 @@ [[package]] name = "sp-serializer" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d793f01eb9eea9f30ffc63b821170068b9f0d9edf715d8ba77dc4de9c300f" dependencies = [ "serde", "serde_json", @@ -6668,8 +6957,9 @@ [[package]] name = "sp-session" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7cf161533725a78083b04f3269effe4c3b4b6ce5f655019b3eec3e729ba4d4" dependencies = [ "parity-scale-codec", "sp-api", @@ -6681,8 +6971,9 @@ [[package]] name = "sp-staking" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc729eb10f8809c61a1fe439ac118a4413de004aaf863003ee8752ac0b596e73" dependencies = [ "parity-scale-codec", "sp-runtime", @@ -6691,8 +6982,9 @@ [[package]] name = "sp-state-machine" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fa4143e58e9130f726d4e8a9b86f3530a8bd19a2eedcdcf4af205f4b5a6d4f" dependencies = [ "hash-db", "log", @@ -6713,13 +7005,15 @@ [[package]] name = "sp-std" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35391ea974fa5ee869cb094d5b437688fbf3d8127d64d1b9fed5822a1ed39b12" [[package]] name = "sp-storage" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86af458d4a0251c490cdde9dcaaccb88d398f3b97ac6694cdd49ed9337e6b961" dependencies = [ "impl-serde", "parity-scale-codec", @@ -6731,8 +7025,9 @@ [[package]] name = "sp-tasks" -version = "2.0.0" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c585340cbee96c53a9b43fd07d81edf6cebeb80e4ca7c0ee79b856c0b1883a0e" dependencies = [ "log", "sp-core", @@ -6744,10 +7039,11 @@ [[package]] name = "sp-timestamp" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27387c541197b9f47f3d9ddcab5649a3ecdca582d2f2ea2b511af24a3d3cbf83" dependencies = [ - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-scale-codec", "sp-api", "sp-inherents", @@ -6758,8 +7054,9 @@ [[package]] name = "sp-tracing" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567382d8d4e14fb572752863b5cd57a78f9e9a6583332b590b726f061f3ea957" dependencies = [ "log", "parity-scale-codec", @@ -6771,8 +7068,9 @@ [[package]] name = "sp-transaction-pool" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264d3b7ea31483eddffa2cc7f28c4d9c022598e456a985fd1cb5879a4609853" dependencies = [ "derive_more", "futures 0.3.12", @@ -6787,8 +7085,9 @@ [[package]] name = "sp-trie" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b85b7f745da41ef825c6f7b93f1fdc897b03df94a4884adfbb70fbcd0aed1298" dependencies = [ "hash-db", "memory-db", @@ -6801,8 +7100,9 @@ [[package]] name = "sp-utils" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ec2a5f924f7affd1e959f8f3c02bd87cdfa0e11c71a4cbc075f955ead8c1a1" dependencies = [ "futures 0.3.12", "futures-core", @@ -6813,8 +7113,9 @@ [[package]] name = "sp-version" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbeffa538a13d715d30e01d57a2636ba32845b737a29a3ea32403576588222e7" dependencies = [ "impl-serde", "parity-scale-codec", @@ -6825,10 +7126,11 @@ [[package]] name = "sp-wasm-interface" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b214e125666a6416cf30a70cc6a5dacd34a4e5197f8a3d479f714af7e1dc7a47" dependencies = [ - "impl-trait-for-tuples 0.2.1", + "impl-trait-for-tuples", "parity-scale-codec", "sp-std", "wasmi", @@ -6912,18 +7214,18 @@ [[package]] name = "strum" -version = "0.16.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.16.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" dependencies = [ "heck", "proc-macro2", @@ -6946,16 +7248,18 @@ [[package]] name = "substrate-build-script-utils" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd540ba72520174c2c73ce96bf507eeba3cc8a481f58be92525b69110e1fa645" dependencies = [ "platforms", ] [[package]] name = "substrate-frame-rpc-system" -version = "2.0.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e46123ec4a690d91967de07cd6af4dde90d14519a1a8d43f61bd3f78dd3d0ef" dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.12", @@ -6977,8 +7281,9 @@ [[package]] name = "substrate-prometheus-endpoint" -version = "0.8.1" -source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb561c19a121e1c89daa79dbfa67a55080f813caa47fd231833a0669696d508" dependencies = [ "async-std", "derive_more", @@ -6990,10 +7295,20 @@ ] [[package]] -name = "substrate-wasm-builder-runner" -version = "1.0.6" +name = "substrate-wasm-builder" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2a965994514ab35d3893e9260245f2947fd1981cdd4fffd2c6e6d1a9ce02e6a" +checksum = "93a3d51ad6abbc408b03ea962062bfcc959b438a318d7d4bedd181e1effd0610" +dependencies = [ + "ansi_term 0.12.1", + "atty", + "build-helper", + "cargo_metadata", + "tempfile", + "toml", + "walkdir", + "wasm-gc-api", +] [[package]] name = "subtle" @@ -7037,10 +7352,16 @@ checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] name = "target-lexicon" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" +checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" [[package]] name = "tempfile" @@ -7752,6 +8073,17 @@ checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi 0.3.9", + "winapi-util", +] + +[[package]] name = "want" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7851,6 +8183,17 @@ checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" [[package]] +name = "wasm-gc-api" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c32691b6c7e6c14e7f8fd55361a9088b507aa49620fcd06c09b3a1082186b9" +dependencies = [ + "log", + "parity-wasm 0.32.0", + "rustc-demangle", +] + +[[package]] name = "wasm-timer" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7875,7 +8218,7 @@ "memory_units", "num-rational", "num-traits", - "parity-wasm", + "parity-wasm 0.41.0", "wasmi-validation", ] @@ -7885,38 +8228,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93" dependencies = [ - "parity-wasm", + "parity-wasm 0.41.0", ] [[package]] name = "wasmparser" -version = "0.57.0" +version = "0.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" - -[[package]] -name = "wasmparser" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" +checksum = "89a30c99437829ede826802bfcf28500cf58df00e66cb9114df98813bc145ff1" [[package]] name = "wasmtime" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd3c4f449382779ef6e0a7c3ec6752ae614e20a42e4100000c3efdc973100e2" +checksum = "7426055cb92bd9a1e9469b48154d8d6119cd8c498c8b70284e420342c05dc45d" dependencies = [ "anyhow", "backtrace", - "cfg-if 0.1.10", - "lazy_static", + "bincode", + "cfg-if 1.0.0", + "cpp_demangle", + "indexmap", "libc", "log", "region", "rustc-demangle", + "serde", "smallvec 1.6.1", "target-lexicon", - "wasmparser 0.59.0", + "wasmparser", + "wasmtime-cache", "wasmtime-environ", "wasmtime-jit", "wasmtime-profiling", @@ -7926,73 +8267,100 @@ ] [[package]] +name = "wasmtime-cache" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c01d9287e36921e46f5887a47007824ae5dbb9b7517a2d565660ab4471478709" +dependencies = [ + "anyhow", + "base64 0.13.0", + "bincode", + "directories-next", + "errno", + "file-per-thread-logger", + "libc", + "log", + "serde", + "sha2 0.9.3", + "toml", + "winapi 0.3.9", + "zstd", +] + +[[package]] +name = "wasmtime-cranelift" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4134ed3a4316cd0de0e546c6004850afe472b0fa3fcdc2f2c15f8d449562d962" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-wasm", + "wasmtime-environ", +] + +[[package]] name = "wasmtime-debug" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e634af9067a3af6cf2c7d33dc3b84767ddaf5d010ba68e80eecbcea73d4a349" +checksum = "e91fa931df6dd8af2b02606307674d3bad23f55473d5f4c809dddf7e4c4dc411" dependencies = [ "anyhow", - "gimli 0.21.0", + "gimli", "more-asserts", - "object 0.20.0", + "object 0.22.0", "target-lexicon", "thiserror", - "wasmparser 0.59.0", + "wasmparser", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f85619a94ee4034bd5bb87fc3dcf71fd2237b81c840809da1201061eec9ab3" +checksum = "a1098871dc3120aaf8190d79153e470658bb79f63ee9ca31716711e123c28220" dependencies = [ "anyhow", - "base64 0.12.3", - "bincode", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "cranelift-codegen", "cranelift-entity", - "cranelift-frontend", "cranelift-wasm", - "directories 2.0.2", - "errno", - "file-per-thread-logger", + "gimli", "indexmap", - "libc", "log", "more-asserts", - "rayon", "serde", - "sha2 0.8.2", "thiserror", - "toml", - "wasmparser 0.59.0", - "winapi 0.3.9", - "zstd", + "wasmparser", ] [[package]] name = "wasmtime-jit" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e914c013c7a9f15f4e429d5431f2830fb8adb56e40567661b69c5ec1d645be23" +checksum = "738bfcd1561ede8bb174215776fd7d9a95d5f0a47ca3deabe0282c55f9a89f68" dependencies = [ + "addr2line", "anyhow", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "cranelift-codegen", "cranelift-entity", "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli 0.21.0", + "gimli", "log", "more-asserts", - "object 0.20.0", + "object 0.22.0", + "rayon", "region", + "serde", "target-lexicon", "thiserror", - "wasmparser 0.59.0", + "wasmparser", + "wasmtime-cranelift", "wasmtime-debug", "wasmtime-environ", "wasmtime-obj", @@ -8003,13 +8371,13 @@ [[package]] name = "wasmtime-obj" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e81d8e02e9bc9fe2da9b6d48bbc217f96e089f7df613f11a28a3958abc44641e" +checksum = "3e96d77f1801131c5e86d93e42a3cf8a35402107332c202c245c83f34888a906" dependencies = [ "anyhow", "more-asserts", - "object 0.20.0", + "object 0.22.0", "target-lexicon", "wasmtime-debug", "wasmtime-environ", @@ -8017,16 +8385,16 @@ [[package]] name = "wasmtime-profiling" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8d4d1af8dd5f7096cfcc89dd668d358e52980c38cce199643372ffd6590e27" +checksum = "60bb672c9d894776d7b9250dd9b4fe890f8760201ee4f53e5f2da772b6c4debb" dependencies = [ "anyhow", - "cfg-if 0.1.10", - "gimli 0.21.0", + "cfg-if 1.0.0", + "gimli", "lazy_static", "libc", - "object 0.19.0", + "object 0.22.0", "scroll", "serde", "target-lexicon", @@ -8036,19 +8404,20 @@ [[package]] name = "wasmtime-runtime" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a25f140bbbaadb07c531cba99ce1a966dba216138dc1b2a0ddecec851a01a93" +checksum = "a978086740949eeedfefcee667b57a9e98d9a7fc0de382fcfa0da30369e3530d" dependencies = [ "backtrace", "cc", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "indexmap", "lazy_static", "libc", "log", - "memoffset 0.5.6", + "memoffset 0.6.1", "more-asserts", + "psm", "region", "thiserror", "wasmtime-environ", @@ -8184,6 +8553,12 @@ ] [[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + +[[package]] name = "x25519-dalek" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,8 @@ FROM phusion/baseimage:18.04-1.0.0 as builder LABEL maintainer="UniqueNetwork.io" -ENV WASM_TOOLCHAIN=nightly-2021-01-27 -ENV NATIVE_TOOLCHAIN=1.49.0 +ENV WASM_TOOLCHAIN=nightly-2021-03-01 +# ENV NATIVE_TOOLCHAIN=1.50.0 ARG PROFILE=release @@ -25,10 +25,10 @@ RUN export PATH="/cargo-home/bin:$PATH" && \ export CARGO_HOME="/cargo-home" && \ rustup toolchain uninstall $(rustup toolchain list) && \ - rustup toolchain install $NATIVE_TOOLCHAIN && \ + # rustup toolchain install $NATIVE_TOOLCHAIN && \ rustup toolchain install $WASM_TOOLCHAIN && \ rustup target add wasm32-unknown-unknown --toolchain $WASM_TOOLCHAIN && \ - rustup default $NATIVE_TOOLCHAIN && \ + rustup default $WASM_TOOLCHAIN && \ rustup target list --installed && \ rustup show --- /dev/null +++ b/Dockerfile-tests @@ -0,0 +1,30 @@ +# ===== Integration Tests ====== + + +FROM ubuntu:18.04 +LABEL maintainer="UniqueNetwork.io" + +RUN apt-get -y update; apt-get -y upgrade; apt-get -y install curl + + +RUN mkdir nft_parachain +WORKDIR /nft_parachain + +COPY . . + +RUN apt-get -y update && \ + apt-get -y upgrade && \ + apt-get -y install curl && \ + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash && \ + export NVM_DIR="$HOME/.nvm" && \ + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \ + nvm install v15.0.1 && \ + nvm use v15.0.1 && \ + npm install --save @polkadot/api + +CMD export NVM_DIR="$HOME/.nvm" && \ + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \ + cd tests && \ + npm install --global yarn && \ + yarn install && \ + yarn test --- /dev/null +++ b/Dockerfile-unit @@ -0,0 +1,39 @@ +# ===== Unit Tests ====== + +FROM phusion/baseimage:18.04-1.0.0 +LABEL maintainer="UniqueNetwork.io" + +ENV WASM_TOOLCHAIN=nightly-2021-03-01 +# ENV NATIVE_TOOLCHAIN=1.50.0 + +ARG PROFILE=release + +RUN apt-get update && \ + apt-get dist-upgrade -y -o Dpkg::Options::="--force-confold" && \ + apt-get install -y cmake pkg-config libssl-dev git clang + +# Get project and run it +#RUN git clone https://github.com/usetech-llc/nft_parachain /nft_parachain +RUN mkdir nft_parachain +WORKDIR /nft_parachain +COPY . . + +RUN export CARGO_HOME="/cargo-home" && curl https://sh.rustup.rs -sSf | sh -s -- -y +RUN export PATH="/cargo-home/bin:$PATH" && \ + export CARGO_HOME="/cargo-home" && \ + cargo fetch +RUN export PATH="/cargo-home/bin:$PATH" && \ + export CARGO_HOME="/cargo-home" && \ + rustup toolchain uninstall $(rustup toolchain list) && \ + # rustup toolchain install $NATIVE_TOOLCHAIN && \ + rustup toolchain install $WASM_TOOLCHAIN && \ + rustup target add wasm32-unknown-unknown --toolchain $WASM_TOOLCHAIN && \ + rustup default $WASM_TOOLCHAIN && \ + rustup target list --installed && \ + rustup show + +RUN export PATH="/cargo-home/bin:$PATH" && \ + export CARGO_HOME="/cargo-home" && \ + cargo build "--$PROFILE" + #cargo test +ENV PATH "$PATH:/cargo-home/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" --- a/README.md +++ b/README.md @@ -63,18 +63,17 @@ 2. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall `. -3. Install stable toolchain 1.49.0 and make it default, install nightly 2021-01-27: +3. Install install nightly 2021-04-23 and make it default: ```bash -rustup toolchain install 1.49.0 -rustup toolchain install nightly-2020-01-27 -rustup default nightly-2021-01-27 +rustup toolchain install nightly-2021-04-23 +rustup default nightly-2021-04-23 ``` 4. Add wasm target for nightly toolchain: ```bash -rustup target add wasm32-unknown-unknown --toolchain nightly-2021-01-27 +rustup target add wasm32-unknown-unknown --toolchain nightly-2021-04-23 ``` 5. Build: @@ -134,6 +133,81 @@ Additional CLI usage options are available and may be shown by running `cargo run -- --help`. +## Building and Running as Parachain locally + +Rust toolchain: nightly-2021-04-23 +Note: checkout this project and polkadot project (see below) in the sibling folders (both under the same folder) + +### Parachain Code and Other Configurations + +Some changes need to be made in the parachain code depending on the relay chain it connects to + +1. Chain Spec (incl. chain_spec.rs) +``` +Extensions { + relay_chain: "rococo".into(), + para_id: PARA_ID, +} +``` + +2. All collators need to have at least existential balance + + + + +### Build relay + +``` +git clone https://github.com/paritytech/polkadot.git +cd polkadot +git checkout aa386760 +cargo build --release +``` + +### Build parachain + +Run in the root of this project: +``` +cargo --build +``` + +### Run 4-node Relay + +1. Download `rococo-custom-4.json` chain spec here: https://substrate.dev/cumulus-workshop/shared/chainspecs/rococo-custom-4.json +2. Use these instructions to launch 4 nodes: https://substrate.dev/cumulus-workshop/#/en/2-relay-chain/1-launch + +Example (Run in polkadot folder. Replace `12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on` with output from Alice node): +``` +./target/release/polkadot --alice --validator --base-path ./cumulus_relay0 --chain rococo-custom-4.json --port 50555 --ws-port 9944 +./target/release/polkadot --bob --validator --base-path ./cumulus_relay1 --chain rococo-custom-4.json --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on --port 50556 --ws-port 9945 +./target/release/polkadot --charlie --validator --base-path ./cumulus_relay1 --chain rococo-custom-4.json --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on --port 50557 --ws-port 9946 +./target/release/polkadot --dave --validator --base-path ./cumulus_relay1 --chain rococo-custom-4.json --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on --port 50558 --ws-port 9947 + +``` + +3. Export genesis state and runtime wasm from NFT parachain: + +Run from this project root: +``` +./target/release/nft export-genesis-state --parachain-id 2000 > ./resources/para-2000-genesis +./target/release/nft export-genesis-wasm > ./resources/para-2000-wasm +``` + +4. Run two parachain nodes: + +Replace `12D3KooWN1ah2bFQSysEFnwZqcmcVpDDR8UedXyo6xfzV1zDNMNg` with Alice or Bob relay ID + +Run from this project root: +``` +./target/release/nft --alice --collator --force-authoring --base-path ./tmp/parachain-alice --parachain-id 2000 --port 40333 --ws-port 9844 -- --execution wasm --chain ../polkadot/rococo-custom-4.json --port 30343 --ws-port 9977 +./target/release/nft --bob --collator --force-authoring --parachain-id 2000 --base-path ./tmp/parachain/bob --port 40334 --ws-port 9845 -- --execution wasm --chain ../polkadot/rococo-custom-4.json --port 30344 --ws-port 9978 --bootnodes /ip4/127.0.0.1/tcp/50556/p2p/12D3KooWN1ah2bFQSysEFnwZqcmcVpDDR8UedXyo6xfzV1zDNMNg +``` + +4. Reserve parachain ID as described here: https://substrate.dev/cumulus-workshop/#/en/2-relay-chain/2-reserve + +5. Register parachain in relay as described here: https://substrate.dev/cumulus-workshop/#/en/3-parachains/2-register + + ## Run Integration Tests 1. Install all needed dependecies @@ -152,12 +226,12 @@ First of all, add rust toolchain and make it default. ```bash -rustup target add wasm32-unknown-unknown --toolchain nightly-2020-10-01 +rustup target add wasm32-unknown-unknown --toolchain nightly-2021-04-23 ``` Then in "/node/src" run build command below ```bash -cargo +nightly-2020-10-01 build --release --features runtime-benchmarks +cargo +nightly-2021-04-23 build --release --features runtime-benchmarks ``` Run benchmark --- /dev/null +++ b/ci_node.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +docker-compose -f docker-compose-tests.yml up -d --build --force-recreate --no-deps + +# validate if testing container finished +while [ "$(docker ps | grep unit_test | wc -l)" -ge 1 ]; do echo "Unit test in process" && date && sleep 60; done && docker logs unit_test &> /home/polkadot/unit_test.log & \ +while [ "$(docker ps | grep integration_test | wc -l)" -ge 1 ]; do echo "Integration test in process" && sleep 60; done && docker logs integration_test &> /home/polkadot/integration_test.log +docker-compose -f docker-compose-tests.yml down -v +echo "Wrokflow finished" +docker system prune --force \ No newline at end of file --- /dev/null +++ b/docker-compose-tests.yml @@ -0,0 +1,46 @@ +version: "3.5" + +services: + node_validator1: + image: nft_node_test + container_name: validator1_test + ports: + - 9944:9944 + build: + context: ./ + dockerfile: Dockerfile +# volumes: +# - ./chain-data:/chain-data + networks: + - node_test_network + command: bash -c "/usr/local/bin/nft --dev --tmp --ws-external --rpc-external" + + integration_tests: + container_name: integration_test + image: int_test + build: + context: ./ + dockerfile: Dockerfile-tests + volumes: + - ./tests/src/config_docker.ts:/nft_parachain/tests/src/config.ts + networks: + - node_test_network + depends_on: + - node_validator1 + + unit_tests: + container_name: unit_test + image: nft_unit_test + build: + context: ./ + dockerfile: Dockerfile-unit + container_name: unit_test + networks: + - node_test_network + # command: bash -c 'while true; do sleep 20; df -h; done' + command: bash -c 'cargo test' + +networks: + node_test_network: + name: node_test_network + driver: bridge \ No newline at end of file --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -1,7 +1,5 @@ -[build-dependencies.substrate-build-script-utils] -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -version = '2.0.1' +[build-dependencies] +substrate-build-script-utils = '3.0.0' [[bin]] name = 'nft' @@ -29,36 +27,37 @@ jsonrpc-core = '15.0.0' # Substrate dependencies -nft-runtime = { path = '../runtime', version = '2.1.0' } -frame-benchmarking = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -frame-benchmarking-cli = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -pallet-transaction-payment-rpc = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-basic-authorship = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-cli = { features = ['wasmtime'], version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sc-client-api = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-consensus = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-consensus-aura = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-executor = { features = ['wasmtime'], version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sc-finality-grandpa = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-rpc = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-rpc-api = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-service = { features = ['wasmtime'], version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sc-transaction-pool = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-api = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-block-builder = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-blockchain = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-consensus = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-consensus-aura = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-core = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-finality-grandpa = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-inherents = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-runtime = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sp-transaction-pool = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-network = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -substrate-frame-rpc-system = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -pallet-contracts-rpc = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} -sc-keystore = { version = "2.0.0", git = "https://github.com/usetech-llc/substrate.git", branch = 'unique'} -sc-telemetry = { version = "2.0.0", git = "https://github.com/usetech-llc/substrate.git", branch = 'unique'} +nft-runtime = { path = '../runtime', version = '3.0.0' } +frame-benchmarking = '3.0.0' +frame-benchmarking-cli = '3.0.0' +pallet-transaction-payment-rpc = '3.0.0' +sc-basic-authorship = '0.9.0' +sc-cli = { features = ['wasmtime'], version = '0.9.0' } +sc-client-api = '3.0.0' +sc-consensus = '0.9.0' +sc-consensus-aura = '0.9.0' +sc-executor = { features = ['wasmtime'], version = '0.9.0' } +sc-finality-grandpa = '0.9.0' + +sc-keystore = '3.0.0' +sc-rpc = '3.0.0' +sc-rpc-api = '0.9.0' +sc-service = { features = ['wasmtime'], version = '0.9.0' } +sc-transaction-pool = '3.0.0' +sp-api = '3.0.0' +sp-block-builder = '3.0.0' +sp-blockchain = '3.0.0' +sp-consensus = '0.9.0' +sp-consensus-aura = '0.9.0' +sp-core = '3.0.0' +sp-finality-grandpa = '3.0.0' +sp-inherents = '3.0.0' +sp-runtime = '3.0.0' +sp-transaction-pool = '3.0.0' +substrate-frame-rpc-system = '3.0.0' +sc-network = '0.9.0' +pallet-contracts-rpc = '3.0.0' +sc-telemetry = '3.0.0' serde = { version = "1.0.102", features = ["derive"] } serde_json = "1.0.41" --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -15,6 +15,7 @@ use sp_finality_grandpa::AuthorityId as GrandpaId; use sp_runtime::traits::{IdentifyAccount, Verify}; use serde_json::map::Map; +// use crate::chain_spec::api::chain_extension::*; // Note this is the URL for the telemetry server //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -179,9 +180,9 @@ .collect(), }), pallet_nft: Some(NftConfig { - collection: vec![( + collection_id: vec![( 1, - CollectionType { + Collection { owner: get_account_id_from_seed::("Alice"), mode: CollectionMode::NFT, access: AccessMode::Normal, @@ -192,8 +193,7 @@ mint_mode: false, offchain_schema: vec![], schema_version: SchemaVersion::default(), - sponsor: get_account_id_from_seed::("Alice"), - sponsor_confirmed: true, + sponsorship: SponsorshipState::Confirmed(get_account_id_from_seed::("Alice")), const_on_chain_schema: vec![], variable_on_chain_schema: vec![], limits: CollectionLimits::default() --- a/node/src/service.rs +++ b/node/src/service.rs @@ -16,7 +16,6 @@ use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; use sc_finality_grandpa::SharedVoterState; use sc_keystore::LocalKeystore; -use sc_telemetry::TelemetrySpan; // Our native executor instance. native_executor_instance!( @@ -42,7 +41,6 @@ AuraPair >, sc_finality_grandpa::LinkHalf, - Option, ) >, ServiceError> { if config.keystore_remote.is_some() { @@ -51,7 +49,7 @@ } let inherent_data_providers = sp_inherents::InherentDataProviders::new(); - let (client, backend, keystore_container, task_manager, telemetry_span) = + let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::(&config)?; let client = Arc::new(client); @@ -59,6 +57,7 @@ let transaction_pool = sc_transaction_pool::BasicPool::new_full( config.transaction_pool.clone(), + config.role.is_authority().into(), config.prometheus_registry(), task_manager.spawn_handle(), client.clone(), @@ -84,15 +83,9 @@ )?; Ok(sc_service::PartialComponents { - client, - backend, - task_manager, - import_queue, - keystore_container, - select_chain, - transaction_pool, + client, backend, task_manager, import_queue, keystore_container, select_chain, transaction_pool, inherent_data_providers, - other: (aura_block_import, grandpa_link, telemetry_span), + other: (aura_block_import, grandpa_link), }) } @@ -106,15 +99,9 @@ /// Builds a new service for a full client. pub fn new_full(mut config: Configuration) -> Result { let sc_service::PartialComponents { - client, - backend, - mut task_manager, - import_queue, - mut keystore_container, - select_chain, - transaction_pool, + client, backend, mut task_manager, import_queue, mut keystore_container, select_chain, transaction_pool, inherent_data_providers, - other: (block_import, grandpa_link, telemetry_span), + other: (block_import, grandpa_link), } = new_partial(&config)?; if let Some(url) = &config.keystore_remote { @@ -182,7 +169,6 @@ network_status_sinks, system_rpc_tx, config, - telemetry_span, }, )?; @@ -197,7 +183,7 @@ let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); - let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _,_>( + let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _, _>( sc_consensus_aura::slot_duration(&*client)?, client.clone(), select_chain, @@ -262,10 +248,9 @@ network_starter.start_network(); Ok(task_manager) } - /// Builds a new service for a light client. pub fn new_light(mut config: Configuration) -> Result { - let (client, backend, keystore_container, mut task_manager, on_demand, telemetry_span) = + let (client, backend, keystore_container, mut task_manager, on_demand) = sc_service::new_light_parts::(&config)?; config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); @@ -332,7 +317,6 @@ network, network_status_sinks, system_rpc_tx, - telemetry_span, })?; network_starter.start_network(); --- /dev/null +++ b/node_build_test.yml @@ -0,0 +1,44 @@ +name: Build & test + +# Controls when the action will run. +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ develop ] + # pull_request: + # branches: [ develop ] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build: + # The type of runner that the job will run on + runs-on: ubuntu-20.04 + + # if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + #runs ssh connection + - name: Go to server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SERVER_IP }} + username: ${{ secrets.SERVER_USERNAME }} + key: ${{ secrets.KEY }} + port: ${{ secrets.SERVER_PORT }} + # command_timeout: 200m + script: | + eval $(ssh-agent -s) + ssh-add /home/devops/.ssh/git_hub + git clone git@github.com:usetech-llc/nft_private.git + cd nft_private + git checkout develop + # git pull --all + chmod +x ci_node.sh + ./ci_node.sh + rm -rf /home/polkadot/nft_private \ No newline at end of file --- a/pallets/nft/Cargo.toml +++ b/pallets/nft/Cargo.toml @@ -6,7 +6,7 @@ license = 'Unlicense' name = 'pallet-nft' repository = 'https://github.com/substrate-developer-hub/nft/' -version = '2.1.0' +version = '3.0.0' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -16,101 +16,35 @@ default-features = false features = ['derive'] package = 'parity-scale-codec' -version = '1.3.6' - -[dependencies.frame-support] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -version = '2.0.1' - -[dependencies.frame-system] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -version = '2.0.1' - -[dev-dependencies.sp-core] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -version = '2.0.1' - -[dev-dependencies.sp-io] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -version = '2.0.1' +version = '2.0.0' -[dependencies.sp-runtime] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -version = '2.0.1' - [dependencies] -# third-party dependencies -serde = { version = "1.0.102", features = ["derive"] } -log = "0.4.8" - -[dependencies.sp-std] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -version = '2.0.1' - -[dependencies.transaction-payment] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -package = 'pallet-transaction-payment' -branch = 'unique' -version = '2.0.1' - -[dependencies.frame-benchmarking] -version = "2.0.1" -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -branch = 'unique' -optional = true - -[dependencies.pallet-contracts] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -package = 'pallet-contracts' -branch = 'unique' -version = '2.0.1' +serde = { version = "1.0.119" } +frame-support = { default-features = false, version = '3.0.0' } +frame-system = { default-features = false, version = '3.0.0' } +pallet-balances = { default-features = false, version = '3.0.0' } +pallet-timestamp = { default-features = false, version = '3.0.0' } +pallet-randomness-collective-flip = { default-features = false, version = '3.0.0' } +sp-std = { default-features = false, version = '3.0.0' } +frame-benchmarking = { default-features = false, version = '3.0.0', optional = true } +sp-core = { default-features = false, version = '3.0.0' } +sp-io = { default-features = false, version = '3.0.0' } +sp-runtime = { default-features = false, version = '3.0.0' } +pallet-contracts = { default-features = false, version = '3.0.0' } +pallet-transaction-payment = { default-features = false, version = "3.0.0" } -[dependencies.pallet-balances] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -package = 'pallet-balances' -branch = 'unique' -version = '2.0.1' - -[dependencies.pallet-timestamp] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -package = 'pallet-timestamp' -branch = 'unique' -version = '2.0.1' - -[dependencies.pallet-randomness-collective-flip] -default-features = false -git = 'https://github.com/usetech-llc/substrate.git' -package = 'pallet-randomness-collective-flip' -branch = 'unique' -version = '2.0.1' - [features] default = ['std'] std = [ 'codec/std', - "serde/std", + 'serde/std', 'frame-support/std', 'frame-system/std', 'pallet-balances/std', 'pallet-timestamp/std', + 'pallet-contracts/std', 'pallet-randomness-collective-flip/std', + 'pallet-transaction-payment/std', 'sp-std/std', 'sp-runtime/std', 'frame-benchmarking/std', --- a/pallets/nft/src/default_weights.rs +++ b/pallets/nft/src/default_weights.rs @@ -127,6 +127,11 @@ .saturating_add(DbWeight::get().reads(0 as Weight)) .saturating_add(DbWeight::get().writes(2 as Weight)) } + fn set_variable_meta_data_sponsoring_rate_limit() -> Weight { + (3_500_000 as Weight) + .saturating_add(DbWeight::get().reads(2 as Weight)) + .saturating_add(DbWeight::get().writes(1 as Weight)) + } fn toggle_contract_white_list() -> Weight { (3_000_000 as Weight) .saturating_add(DbWeight::get().reads(0 as Weight)) --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -13,6 +13,7 @@ #[cfg(feature = "std")] pub use serde::*; +use core::ops::{Deref, DerefMut}; use codec::{Decode, Encode}; pub use frame_support::{ construct_runtime, decl_event, decl_module, decl_storage, decl_error, @@ -20,7 +21,7 @@ ensure, fail, parameter_types, traits::{ Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced, - Randomness, IsSubType, + Randomness, IsSubType, WithdrawReasons, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, @@ -28,13 +29,14 @@ WeightToFeePolynomial, DispatchClass, }, StorageValue, + transactional, }; use frame_system::{self as system, ensure_signed, ensure_root}; use sp_runtime::sp_std::prelude::Vec; use sp_runtime::{ traits::{ - DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero, + Hash, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero, }, transaction_validity::{ TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -43,7 +45,7 @@ }; use sp_runtime::traits::StaticLookup; use pallet_contracts::chain_extension::UncheckedFrom; -use transaction_payment::OnChargeTransaction; +use pallet_transaction_payment::OnChargeTransaction; #[cfg(test)] mod mock; @@ -123,10 +125,46 @@ pub fraction: u128, } -#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)] +#[derive(Encode, Decode, Debug, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct CollectionType { - pub owner: AccountId, +pub enum SponsorshipState { + /// The fees are applied to the transaction sender + Disabled, + Unconfirmed(AccountId), + /// Transactions are sponsored by specified account + Confirmed(AccountId), +} + +impl SponsorshipState { + fn sponsor(&self) -> Option<&AccountId> { + match self { + Self::Confirmed(sponsor) => Some(sponsor), + _ => None, + } + } + + fn pending_sponsor(&self) -> Option<&AccountId> { + match self { + Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor), + _ => None, + } + } + + fn confirmed(&self) -> bool { + matches!(self, Self::Confirmed(_)) + } +} + +impl Default for SponsorshipState { + fn default() -> Self { + Self::Disabled + } +} + +#[derive(Encode, Decode, Clone, PartialEq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Collection { + pub owner: T::AccountId, pub mode: CollectionMode, pub access: AccessMode, pub decimal_points: DecimalPoints, @@ -136,14 +174,32 @@ pub mint_mode: bool, pub offchain_schema: Vec, pub schema_version: SchemaVersion, - pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender - pub sponsor_confirmed: bool, // False if sponsor address has not yet confirmed sponsorship. True otherwise. - pub limits: CollectionLimits, // Collection private restrictions + pub sponsorship: SponsorshipState, + pub limits: CollectionLimits, // Collection private restrictions pub variable_on_chain_schema: Vec, // pub const_on_chain_schema: Vec, // } -#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)] +pub struct CollectionHandle { + pub id: CollectionId, + collection: Collection, +} + +impl Deref for CollectionHandle { + type Target = Collection; + + fn deref(&self) -> &Self::Target { + &self.collection + } +} + +impl DerefMut for CollectionHandle { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.collection + } +} + +#[derive(Encode, Decode, Debug, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct NftItemType { pub owner: AccountId, @@ -157,7 +213,7 @@ pub value: u128, } -#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)] +#[derive(Encode, Decode, Debug, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct ReFungibleItemType { pub owner: Vec>, @@ -178,9 +234,13 @@ #[derive(Encode, Decode, Debug, Clone, PartialEq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct CollectionLimits { +pub struct CollectionLimits { pub account_token_ownership_limit: u32, pub sponsored_data_size: u32, + /// None - setVariableMetadata is not sponsored + /// Some(v) - setVariableMetadata is sponsored + /// if there is v block between txs + pub sponsored_data_rate_limit: Option, pub token_limit: u32, // Timeouts for item types in passed blocks @@ -189,12 +249,13 @@ pub owner_can_destroy: bool, } -impl Default for CollectionLimits { - fn default() -> CollectionLimits { - CollectionLimits { +impl Default for CollectionLimits { + fn default() -> Self { + Self { account_token_ownership_limit: 10_000_000, token_limit: u32::max_value(), - sponsored_data_size: u32::max_value(), + sponsored_data_size: u32::MAX, + sponsored_data_rate_limit: None, sponsor_transfer_timeout: 14400, owner_can_transfer: true, owner_can_destroy: true @@ -247,6 +308,7 @@ fn set_schema_version() -> Weight; fn set_chain_limits() -> Weight; fn set_contract_sponsoring_rate_limit() -> Weight; + fn set_variable_meta_data_sponsoring_rate_limit() -> Weight; fn toggle_contract_white_list() -> Weight; fn add_to_contract_white_list() -> Weight; fn remove_from_contract_white_list() -> Weight; @@ -382,18 +444,26 @@ AccountTokenLimitExceeded, /// Collection limit bounds per collection exceeded CollectionLimitBoundsExceeded, + /// Tried to enable permissions which are only permitted to be disabled + OwnerPermissionsCantBeReverted, /// Schema data size limit bound exceeded SchemaDataLimitExceeded, /// Maximum refungibility exceeded - WrongRefungiblePieces + WrongRefungiblePieces, + /// createRefungible should be called with one owner + BadCreateRefungibleCall, } } -pub trait Config: system::Config + Sized + transaction_payment::Config + pallet_contracts::Config { +pub trait Config: system::Config + Sized + pallet_transaction_payment::Config + pallet_contracts::Config { type Event: From> + Into<::Event>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + type Currency: Currency; + type CollectionCreationPrice: Get<<::Currency as Currency>::Balance>; + type TreasuryAccountId: Get; } #[cfg(feature = "runtime-benchmarks")] @@ -401,59 +471,124 @@ // #endregion +// # Used definitions +// +// ## User control levels +// +// chain-controlled - key is uncontrolled by user +// i.e autoincrementing index +// can use non-cryptographic hash +// real - key is controlled by user +// but it is hard to generate enough colliding values, i.e owner of signed txs +// can use non-cryptographic hash +// controlled - key is completly controlled by users +// i.e maps with mutable keys +// should use cryptographic hash +// +// ## User control level downgrade reasons +// +// ?1 - chain-controlled -> controlled +// collections/tokens can be destroyed, resulting in massive holes +// ?2 - chain-controlled -> controlled +// same as ?1, but can be only added, resulting in easier exploitation +// ?3 - real -> controlled +// no confirmation required, so addresses can be easily generated decl_storage! { trait Store for Module as Nft { - // Private members - NextCollectionID: CollectionId; + //#region Private members + /// Id of next collection CreatedCollectionCount: u32; + /// Used for migrations ChainVersion: u64; - ItemListIndex: map hasher(identity) CollectionId => TokenId; + /// Id of last collection token + /// Collection id (controlled?1) + ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId; + //#endregion - // Chain limits struct + //#region Chain limits struct pub ChainLimit get(fn chain_limit) config(): ChainLimits; + //#endregion - // Bound counters - CollectionCount: u32; + //#region Bound counters + /// Amount of collections destroyed, used for total amount tracking with + /// CreatedCollectionCount + DestroyedCollectionCount: u32; + /// Total amount of account owned tokens (NFTs + RFTs + unique fungibles) + /// Account id (real) pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32; + //#endregion - // Basic collections - pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType; - pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec; - pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool; + //#region Basic collections + /// Collection info + /// Collection id (controlled?1) + pub CollectionById get(fn collection_id) config(): map hasher(blake2_128_concat) CollectionId => Option> = None; + /// List of collection admins + /// Collection id (controlled?2) + pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec; + /// Whitelisted collection users + /// Collection id (controlled?2), user id (controlled?3) + pub WhiteList get(fn white_list): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => bool; + //#endregion - /// Balance owner per collection map - pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128; + /// How many of collection items user have + /// Collection id (controlled?2), account id (real) + pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => u128; - /// second parameter: item id + owner account id + spender account id - pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128; + /// Amount of items which spender can transfer out of owners account (via transferFrom) + /// Collection id (controlled?2), (token id (controlled ?2) + owner account id (real) + spender account id (controlled?3)) + /// TODO: Off chain worker should remove from this map when token gets removed + pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128; - /// Item collections - pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType; - pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType; - pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType; + //#region Item collections + /// Collection id (controlled?2), token id (controlled?1) + pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option>; + /// Collection id (controlled?2), owner (controlled?2) + pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType; + /// Collection id (controlled?2), token id (controlled?1) + pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option>; + //#endregion - /// Index list - pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec; + //#region Index list + /// Collection id (controlled?2), tokens owner (controlled?2) + pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => Vec; + //#endregion - /// Tokens transfer baskets - pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber; - pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber; - pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber; - pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber; + //#region Tokens transfer rate limit baskets + /// (Collection id (controlled?2), who created (real)) + /// TODO: Off chain worker should remove from this map when collection gets removed + pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber; + /// Collection id (controlled?2), token id (controlled?2) + pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber; + /// Collection id (controlled?2), owning user (real) + pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber; + /// Collection id (controlled?2), token id (controlled?2) + pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber; + //#endregion - // Contract Sponsorship and Ownership - pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId; + /// Variable metadata sponsoring + /// Collection id (controlled?2), token id (controlled?2) + pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option = None; + + //#region Contract Sponsorship and Ownership + /// Contract address (real) + pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => Option; + /// Contract address (real) pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool; + /// (Contract address(real), caller (real)) pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber; + /// Contract address (real) pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber; + /// Contract address (real) pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; - pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; + /// Contract address (real) => Whitelisted user (controlled?3) + pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(blake2_128_concat) T::AccountId => bool; + //#endregion } add_extra_genesis { build(|config: &GenesisConfig| { // Modification of storage - for (_num, _c) in &config.collection { + for (_num, _c) in &config.collection_id { >::init_collection(_c); } @@ -486,7 +621,7 @@ /// * mode: [CollectionMode] converted into u8. /// /// * account_id: Collection owner. - Created(CollectionId, u8, AccountId), + CollectionCreated(CollectionId, u8, AccountId), /// New item was created. /// @@ -520,6 +655,17 @@ /// /// * amount: Always 1 for NFT Transfer(CollectionId, TokenId, AccountId, AccountId, u128), + + /// * collection_id + /// + /// * item_id + /// + /// * sender + /// + /// * spender + /// + /// * amount + Approved(CollectionId, TokenId, AccountId, AccountId, u128), } ); @@ -532,14 +678,6 @@ type Error = Error; fn on_initialize(now: T::BlockNumber) -> Weight { - - if ChainVersion::get() < 2 - { - let value = NextCollectionID::get(); - CreatedCollectionCount::put(value); - ChainVersion::put(2); - } - 0 } @@ -560,6 +698,7 @@ /// * mode: [CollectionMode] collection type and type dependent data. // returns collection ID #[weight = ::WeightInfo::create_collection()] + #[transactional] pub fn create_collection(origin, collection_name: Vec, collection_description: Vec, @@ -569,13 +708,31 @@ // Anyone can create a collection let who = ensure_signed(origin)?; + // Take a (non-refundable) deposit of collection creation + let mut imbalance = <<::Currency as Currency>::PositiveImbalance>::zero(); + imbalance.subsume(<::Currency as Currency>::deposit_creating( + &T::TreasuryAccountId::get(), + T::CollectionCreationPrice::get(), + )); + ::Currency::settle( + &who, + imbalance, + WithdrawReasons::TRANSFER, + ExistenceRequirement::KeepAlive, + ).map_err(|_| Error::::NoPermission)?; + let decimal_points = match mode { CollectionMode::Fungible(points) => points, _ => 0 }; + let chain_limit = ChainLimit::get(); + + let created_count = CreatedCollectionCount::get(); + let destroyed_count = DestroyedCollectionCount::get(); + // bound Total number of collections - ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::::TotalCollectionsLimitExceeded); + ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::::TotalCollectionsLimitExceeded); // check params ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::::CollectionDecimalPointLimitExceeded); @@ -584,20 +741,19 @@ ensure!(token_prefix.len() <= 16, Error::::CollectionTokenPrefixLimitExceeded); // Generate next collection ID - let next_id = CreatedCollectionCount::get() - .checked_add(1) - .ok_or(Error::::NumOverflow)?; - - // bound counter - let total = CollectionCount::get() + let next_id = created_count .checked_add(1) .ok_or(Error::::NumOverflow)?; CreatedCollectionCount::put(next_id); - CollectionCount::put(total); + let limits = CollectionLimits { + sponsored_data_size: chain_limit.custom_data_limit, + ..Default::default() + }; + // Create new collection - let new_collection = CollectionType { + let new_collection = Collection { owner: who.clone(), name: collection_name, mode: mode.clone(), @@ -608,18 +764,17 @@ token_prefix: token_prefix, offchain_schema: Vec::new(), schema_version: SchemaVersion::ImageURL, - sponsor: T::AccountId::default(), - sponsor_confirmed: false, + sponsorship: SponsorshipState::Disabled, variable_on_chain_schema: Vec::new(), const_on_chain_schema: Vec::new(), - limits: CollectionLimits::default() + limits, }; // Add new collection to map - >::insert(next_id, new_collection); + >::insert(next_id, new_collection); // call event - Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone())); + Self::deposit_event(RawEvent::CollectionCreated(next_id, mode.into(), who.clone())); Ok(()) } @@ -634,17 +789,22 @@ /// /// * collection_id: collection to destroy. #[weight = ::WeightInfo::destroy_collection()] + #[transactional] pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_permissions(collection_id, sender)?; + let collection = Self::get_collection(collection_id)?; + Self::check_owner_permissions(&collection, sender)?; + if !collection.limits.owner_can_destroy { + fail!(Error::::NoPermission); + } >::remove_prefix(collection_id); >::remove_prefix(collection_id); >::remove_prefix(collection_id); ::remove(collection_id); >::remove(collection_id); - >::remove(collection_id); + >::remove(collection_id); >::remove_prefix(collection_id); >::remove_prefix(collection_id); @@ -655,15 +815,11 @@ >::remove_prefix(collection_id); >::remove_prefix(collection_id); - if CollectionCount::get() > 0 - { - // bound couter - let total = CollectionCount::get() - .checked_sub(1) - .ok_or(Error::::NumOverflow)?; + >::remove_prefix(collection_id); - CollectionCount::put(total); - } + DestroyedCollectionCount::put(DestroyedCollectionCount::get() + .checked_add(1) + .ok_or(Error::::NumOverflow)?); Ok(()) } @@ -681,10 +837,12 @@ /// /// * address. #[weight = ::WeightInfo::add_to_white_list()] + #[transactional] pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{ let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender)?; + let collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&collection, sender)?; >::insert(collection_id, address, true); @@ -704,10 +862,12 @@ /// /// * address. #[weight = ::WeightInfo::remove_from_white_list()] + #[transactional] pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{ let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender)?; + let collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&collection, sender)?; >::remove(collection_id, address); @@ -726,14 +886,15 @@ /// /// * mode: [AccessMode] #[weight = ::WeightInfo::set_public_access_mode()] + #[transactional] pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_permissions(collection_id, sender)?; - let mut target_collection = >::get(collection_id); + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_permissions(&target_collection, sender)?; target_collection.access = mode; - >::insert(collection_id, target_collection); + Self::save_collection(target_collection); Ok(()) } @@ -752,14 +913,15 @@ /// /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above. #[weight = ::WeightInfo::set_mint_permission()] + #[transactional] pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_permissions(collection_id, sender)?; - let mut target_collection = >::get(collection_id); + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_permissions(&target_collection, sender)?; target_collection.mint_mode = mint_permission; - >::insert(collection_id, target_collection); + Self::save_collection(target_collection); Ok(()) } @@ -776,13 +938,14 @@ /// /// * new_owner. #[weight = ::WeightInfo::change_collection_owner()] + #[transactional] pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_permissions(collection_id, sender)?; - let mut target_collection = >::get(collection_id); + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_permissions(&target_collection, sender)?; target_collection.owner = new_owner; - >::insert(collection_id, target_collection); + Self::save_collection(target_collection); Ok(()) } @@ -801,24 +964,23 @@ /// /// * new_admin_id: Address of new admin to add. #[weight = ::WeightInfo::add_collection_admin()] + #[transactional] pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender)?; - let mut admin_arr: Vec = Vec::new(); + let collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&collection, sender)?; + let mut admin_arr = >::get(collection_id); - if >::contains_key(collection_id) - { - admin_arr = >::get(collection_id); - ensure!(!admin_arr.contains(&new_admin_id), Error::::AlreadyAdmin); + match admin_arr.binary_search(&new_admin_id) { + Ok(_) => {}, + Err(idx) => { + let limits = ChainLimit::get(); + ensure!(admin_arr.len() < limits.collections_admins_limit as usize, Error::::CollectionAdminsLimitExceeded); + admin_arr.insert(idx, new_admin_id); + >::insert(collection_id, admin_arr); + } } - - // Number of collection admins - ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::::CollectionAdminsLimitExceeded); - - admin_arr.push(new_admin_id); - >::insert(collection_id, admin_arr); - Ok(()) } @@ -835,16 +997,21 @@ /// /// * account_id: Address of admin to remove. #[weight = ::WeightInfo::remove_collection_admin()] + #[transactional] pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender)?; - ensure!(>::contains_key(collection_id), Error::::AdminNotFound); - + let collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&collection, sender)?; let mut admin_arr = >::get(collection_id); - admin_arr.retain(|i| *i != account_id); - >::insert(collection_id, admin_arr); + match admin_arr.binary_search(&account_id) { + Ok(idx) => { + admin_arr.remove(idx); + >::insert(collection_id, admin_arr); + }, + Err(_) => {} + } Ok(()) } @@ -858,17 +1025,15 @@ /// /// * new_sponsor. #[weight = ::WeightInfo::set_collection_sponsor()] + #[transactional] pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult { let sender = ensure_signed(origin)?; - ensure!(>::contains_key(collection_id), Error::::CollectionNotFound); + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_permissions(&target_collection, sender)?; - let mut target_collection = >::get(collection_id); - ensure!(sender == target_collection.owner, Error::::NoPermission); - - target_collection.sponsor = new_sponsor; - target_collection.sponsor_confirmed = false; - >::insert(collection_id, target_collection); + target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor); + Self::save_collection(target_collection); Ok(()) } @@ -881,16 +1046,19 @@ /// /// * collection_id. #[weight = ::WeightInfo::confirm_sponsorship()] + #[transactional] pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult { let sender = ensure_signed(origin)?; - ensure!(>::contains_key(collection_id), Error::::CollectionNotFound); - let mut target_collection = >::get(collection_id); - ensure!(sender == target_collection.sponsor, Error::::ConfirmUnsetSponsorFail); + let mut target_collection = Self::get_collection(collection_id)?; + ensure!( + target_collection.sponsorship.pending_sponsor() == Some(&sender), + Error::::ConfirmUnsetSponsorFail + ); - target_collection.sponsor_confirmed = true; - >::insert(collection_id, target_collection); + target_collection.sponsorship = SponsorshipState::Confirmed(sender); + Self::save_collection(target_collection); Ok(()) } @@ -905,17 +1073,16 @@ /// /// * collection_id. #[weight = ::WeightInfo::remove_collection_sponsor()] + #[transactional] pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult { let sender = ensure_signed(origin)?; - ensure!(>::contains_key(collection_id), Error::::CollectionNotFound); - let mut target_collection = >::get(collection_id); - ensure!(sender == target_collection.owner, Error::::NoPermission); + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_permissions(&target_collection, sender)?; - target_collection.sponsor = T::AccountId::default(); - target_collection.sponsor_confirmed = false; - >::insert(collection_id, target_collection); + target_collection.sponsorship = SponsorshipState::Disabled; + Self::save_collection(target_collection); Ok(()) } @@ -945,22 +1112,21 @@ // .saturating_add(RocksDbWeight::get().writes(8 as Weight))] #[weight = ::WeightInfo::create_item(data.len())] + #[transactional] pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::collection_exists(collection_id)?; + let target_collection = Self::get_collection(collection_id)?; - let target_collection = >::get(collection_id); - - Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?; + Self::can_create_items_in_collection(&target_collection, &sender, &owner, 1)?; Self::validate_create_item_args(&target_collection, &data)?; - Self::create_item_no_validation(collection_id, owner, data)?; + Self::create_item_no_validation(&target_collection, owner, data)?; Ok(()) } - /// This method creates multiple instances of NFT Collection created with CreateCollection method. + /// This method creates multiple items in a collection created with CreateCollection method. /// /// # Permissions /// @@ -981,21 +1147,21 @@ #[weight = ::WeightInfo::create_item(items_data.into_iter() .map(|data| { data.len() }) .sum())] + #[transactional] pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec) -> DispatchResult { ensure!(items_data.len() > 0, Error::::EmptyArgument); let sender = ensure_signed(origin)?; - Self::collection_exists(collection_id)?; - let target_collection = >::get(collection_id); + let target_collection = Self::get_collection(collection_id)?; - Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?; + Self::can_create_items_in_collection(&target_collection, &sender, &owner, items_data.len() as u32)?; for data in &items_data { Self::validate_create_item_args(&target_collection, data)?; } for data in &items_data { - Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?; + Self::create_item_no_validation(&target_collection, owner.clone(), data.clone())?; } Ok(()) @@ -1015,31 +1181,36 @@ /// /// * item_id: ID of NFT to burn. #[weight = ::WeightInfo::burn_item()] + #[transactional] pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::collection_exists(collection_id)?; // Transfer permissions check - let target_collection = >::get(collection_id); - ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || - Self::is_owner_or_admin_permissions(collection_id, sender.clone()), - Error::::NoPermission); + let target_collection = Self::get_collection(collection_id)?; + ensure!( + Self::is_item_owner(sender.clone(), &target_collection, item_id) || + ( + target_collection.limits.owner_can_transfer && + Self::is_owner_or_admin_permissions(&target_collection, sender.clone()) + ), + Error::::NoPermission + ); if target_collection.access == AccessMode::WhiteList { - Self::check_white_list(collection_id, &sender)?; + Self::check_white_list(&target_collection, &sender)?; } match target_collection.mode { - CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?, - CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?, - CollectionMode::ReFungible => Self::burn_refungible_item(collection_id, item_id, &sender)?, + CollectionMode::NFT => Self::burn_nft_item(&target_collection, item_id)?, + CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, &target_collection, value)?, + CollectionMode::ReFungible => Self::burn_refungible_item(&target_collection, item_id, &sender)?, _ => () }; // call event - Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id)); + Self::deposit_event(RawEvent::ItemDestroyed(target_collection.id, item_id)); Ok(()) } @@ -1068,9 +1239,12 @@ /// * Fungible Mode: Must specify transferred amount /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1) #[weight = ::WeightInfo::transfer()] + #[transactional] pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::transfer_internal(sender, recipient, collection_id, item_id, value) + let collection = Self::get_collection(collection_id)?; + + Self::transfer_internal(sender, recipient, &collection, item_id, value) } /// Set, change, or remove approved address to transfer the ownership of the NFT. @@ -1089,23 +1263,26 @@ /// /// * item_id: ID of the item. #[weight = ::WeightInfo::approve()] + #[transactional] pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult { let sender = ensure_signed(origin)?; + let target_collection = Self::get_collection(collection_id)?; - Self::collection_exists(collection_id)?; - Self::token_exists(collection_id, item_id, &sender)?; + Self::token_exists(&target_collection, item_id)?; // Transfer permissions check - let target_collection = >::get(collection_id); - let allowance_limit = if Self::is_owner_or_admin_permissions( - collection_id, - sender.clone(), - ) { + let bypasses_limits = target_collection.limits.owner_can_transfer && + Self::is_owner_or_admin_permissions( + &target_collection, + sender.clone(), + ); + + let allowance_limit = if bypasses_limits { None } else if let Some(amount) = Self::owned_amount( sender.clone(), - collection_id, + &target_collection, item_id, ) { Some(amount) @@ -1114,20 +1291,19 @@ }; if target_collection.access == AccessMode::WhiteList { - Self::check_white_list(collection_id, &sender)?; - Self::check_white_list(collection_id, &spender)?; + Self::check_white_list(&target_collection, &sender)?; + Self::check_white_list(&target_collection, &spender)?; } - let allowance_exists = >::contains_key(collection_id, (item_id, &sender, &spender)); - let mut allowance: u128 = amount; - if allowance_exists { - allowance += >::get(collection_id, (item_id, &sender, &spender)); - } + let allowance: u128 = amount + .checked_add(>::get(collection_id, (item_id, &sender, &spender))) + .ok_or(Error::::NumOverflow)?; if let Some(limit) = allowance_limit { ensure!(limit >= allowance, Error::::TokenValueTooLow); } >::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance); + Self::deposit_event(RawEvent::Approved(target_collection.id, item_id, sender, spender, allowance)); Ok(()) } @@ -1151,35 +1327,35 @@ /// /// * value: Amount to transfer. #[weight = ::WeightInfo::transfer_from()] + #[transactional] pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult { let sender = ensure_signed(origin)?; - let mut appoved_transfer = false; + let target_collection = Self::get_collection(collection_id)?; // Check approval - let mut approval: u128 = 0; - if >::contains_key(collection_id, (item_id, &from, &sender)) { - approval = >::get(collection_id, (item_id, &from, &sender)); - ensure!(approval >= value, Error::::TokenValueNotEnough); - appoved_transfer = true; - } - - let target_collection = >::get(collection_id); + let approval: u128 = >::get(collection_id, (item_id, &from, &sender)); // Limits check - Self::is_correct_transfer(collection_id, &target_collection, &recipient)?; + Self::is_correct_transfer(&target_collection, &recipient)?; // Transfer permissions check - ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()), - Error::::NoPermission); + ensure!( + approval >= value || + ( + target_collection.limits.owner_can_transfer && + Self::is_owner_or_admin_permissions(&target_collection, sender.clone()) + ), + Error::::NoPermission + ); if target_collection.access == AccessMode::WhiteList { - Self::check_white_list(collection_id, &sender)?; - Self::check_white_list(collection_id, &recipient)?; + Self::check_white_list(&target_collection, &sender)?; + Self::check_white_list(&target_collection, &recipient)?; } // Reduce approval by transferred amount or remove if remaining approval drops to 0 - if approval.checked_sub(value).unwrap_or(0) > 0 { + if approval.saturating_sub(value) > 0 { >::insert(collection_id, (item_id, &from, &sender), approval - value); } else { @@ -1188,12 +1364,13 @@ match target_collection.mode { - CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?, - CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?, - CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?, + CollectionMode::NFT => Self::transfer_nft(&target_collection, item_id, from.clone(), recipient.clone())?, + CollectionMode::Fungible(_) => Self::transfer_fungible(&target_collection, value, &from, &recipient)?, + CollectionMode::ReFungible => Self::transfer_refungible(&target_collection, item_id, value, from.clone(), recipient.clone())?, _ => () }; + Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, from, recipient, value)); Ok(()) } @@ -1225,6 +1402,7 @@ /// /// * schema: String representing the offchain data schema. #[weight = ::WeightInfo::set_variable_meta_data()] + #[transactional] pub fn set_variable_meta_data ( origin, collection_id: CollectionId, @@ -1233,21 +1411,20 @@ ) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::collection_exists(collection_id)?; - Self::token_exists(collection_id, item_id, &sender)?; + let target_collection = Self::get_collection(collection_id)?; + Self::token_exists(&target_collection, item_id)?; ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::::TokenVariableDataLimitExceeded); // Modify permissions check - let target_collection = >::get(collection_id); - ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || - Self::is_owner_or_admin_permissions(collection_id, sender.clone()), + ensure!(Self::is_item_owner(sender.clone(), &target_collection, item_id) || + Self::is_owner_or_admin_permissions(&target_collection, sender.clone()), Error::::NoPermission); match target_collection.mode { - CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?, - CollectionMode::ReFungible => Self::set_re_fungible_variable_data(collection_id, item_id, data)?, + CollectionMode::NFT => Self::set_nft_variable_data(&target_collection, item_id, data)?, + CollectionMode::ReFungible => Self::set_re_fungible_variable_data(&target_collection, item_id, data)?, CollectionMode::Fungible(_) => fail!(Error::::CantStoreMetadataInFungibleTokens), _ => fail!(Error::::UnexpectedCollectionType) }; @@ -1270,16 +1447,17 @@ /// /// * schema: SchemaVersion: enum #[weight = ::WeightInfo::set_schema_version()] + #[transactional] pub fn set_schema_version( origin, collection_id: CollectionId, version: SchemaVersion ) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender.clone())?; - let mut target_collection = >::get(collection_id); + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?; target_collection.schema_version = version; - >::insert(collection_id, target_collection); + Self::save_collection(target_collection); Ok(()) } @@ -1297,20 +1475,21 @@ /// /// * schema: String representing the offchain data schema. #[weight = ::WeightInfo::set_offchain_schema()] + #[transactional] pub fn set_offchain_schema( origin, collection_id: CollectionId, schema: Vec ) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender.clone())?; + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?; // check schema limit ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, ""); - let mut target_collection = >::get(collection_id); target_collection.offchain_schema = schema; - >::insert(collection_id, target_collection); + Self::save_collection(target_collection); Ok(()) } @@ -1328,20 +1507,21 @@ /// /// * schema: String representing the const on-chain data schema. #[weight = ::WeightInfo::set_const_on_chain_schema()] + #[transactional] pub fn set_const_on_chain_schema ( origin, collection_id: CollectionId, schema: Vec ) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender.clone())?; + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?; // check schema limit ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, ""); - let mut target_collection = >::get(collection_id); target_collection.const_on_chain_schema = schema; - >::insert(collection_id, target_collection); + Self::save_collection(target_collection); Ok(()) } @@ -1359,26 +1539,28 @@ /// /// * schema: String representing the variable on-chain data schema. #[weight = ::WeightInfo::set_const_on_chain_schema()] + #[transactional] pub fn set_variable_on_chain_schema ( origin, collection_id: CollectionId, schema: Vec ) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_or_admin_permissions(collection_id, sender.clone())?; + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?; // check schema limit ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, ""); - let mut target_collection = >::get(collection_id); target_collection.variable_on_chain_schema = schema; - >::insert(collection_id, target_collection); + Self::save_collection(target_collection); Ok(()) } // Sudo permissions function #[weight = ::WeightInfo::set_chain_limits()] + #[transactional] pub fn set_chain_limits( origin, limits: ChainLimits @@ -1403,6 +1585,7 @@ /// * enable flag /// #[weight = ::WeightInfo::enable_contract_sponsoring()] + #[transactional] pub fn enable_contract_sponsoring( origin, contract_address: T::AccountId, @@ -1438,6 +1621,7 @@ /// -`rate_limit`: Number of blocks to wait until the next sponsored transaction is allowed /// #[weight = ::WeightInfo::set_contract_sponsoring_rate_limit()] + #[transactional] pub fn set_contract_sponsoring_rate_limit( origin, contract_address: T::AccountId, @@ -1465,6 +1649,7 @@ /// /// - `enable`: . #[weight = ::WeightInfo::toggle_contract_white_list()] + #[transactional] pub fn toggle_contract_white_list( origin, contract_address: T::AccountId, @@ -1476,7 +1661,11 @@ >::insert(contract_address.clone(), sender.clone()); Self::ensure_contract_owned(sender, &contract_address)?; - >::insert(contract_address, enable); + if enable { + >::insert(contract_address, true); + } else { + >::remove(contract_address); + } Ok(()) } @@ -1492,6 +1681,7 @@ /// /// -`account_address`: Address to add. #[weight = ::WeightInfo::add_to_contract_white_list()] + #[transactional] pub fn add_to_contract_white_list( origin, contract_address: T::AccountId, @@ -1519,6 +1709,7 @@ /// /// -`account_address`: Address to remove. #[weight = ::WeightInfo::remove_from_contract_white_list()] + #[transactional] pub fn remove_from_contract_white_list( origin, contract_address: T::AccountId, @@ -1535,29 +1726,36 @@ } #[weight = ::WeightInfo::set_collection_limits()] + #[transactional] pub fn set_collection_limits( origin, collection_id: u32, - limits: CollectionLimits, + new_limits: CollectionLimits, ) -> DispatchResult { let sender = ensure_signed(origin)?; - Self::check_owner_permissions(collection_id, sender.clone())?; - let mut target_collection = >::get(collection_id); + let mut target_collection = Self::get_collection(collection_id)?; + Self::check_owner_permissions(&target_collection, sender.clone())?; + let old_limits = &target_collection.limits; let chain_limits = ChainLimit::get(); - let climits = target_collection.limits; // collection bounds - ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT && - limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, + ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT && + new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && + new_limits.sponsored_data_size <= chain_limits.custom_data_limit, Error::::CollectionLimitBoundsExceeded); // token_limit check prev - ensure!(climits.token_limit > limits.token_limit && - limits.token_limit <= chain_limits.account_token_ownership_limit, - Error::::AccountTokenLimitExceeded); + ensure!(old_limits.token_limit >= new_limits.token_limit, Error::::CollectionTokenLimitExceeded); + ensure!(new_limits.token_limit > 0, Error::::CollectionTokenLimitExceeded); - target_collection.limits = limits; - >::insert(collection_id, target_collection); + ensure!( + (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) && + (old_limits.owner_can_destroy || !new_limits.owner_can_destroy), + Error::::OwnerPermissionsCantBeReverted, + ); + + target_collection.limits = new_limits; + Self::save_collection(target_collection); Ok(()) } @@ -1566,38 +1764,36 @@ impl Module { - pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult { - - let target_collection = >::get(collection_id); - + pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, target_collection: &CollectionHandle, item_id: TokenId, value: u128) -> DispatchResult { // Limits check - Self::is_correct_transfer(collection_id, &target_collection, &recipient)?; + Self::is_correct_transfer(target_collection, &recipient)?; // Transfer permissions check - ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || - Self::is_owner_or_admin_permissions(collection_id, sender.clone()), + ensure!(Self::is_item_owner(sender.clone(), target_collection, item_id) || + Self::is_owner_or_admin_permissions(target_collection, sender.clone()), Error::::NoPermission); if target_collection.access == AccessMode::WhiteList { - Self::check_white_list(collection_id, &sender)?; - Self::check_white_list(collection_id, &recipient)?; + Self::check_white_list(target_collection, &sender)?; + Self::check_white_list(target_collection, &recipient)?; } match target_collection.mode { - CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?, - CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?, - CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?, + CollectionMode::NFT => Self::transfer_nft(target_collection, item_id, sender.clone(), recipient.clone())?, + CollectionMode::Fungible(_) => Self::transfer_fungible(target_collection, value, &sender, &recipient)?, + CollectionMode::ReFungible => Self::transfer_refungible(target_collection, item_id, value, sender.clone(), recipient.clone())?, _ => () }; - Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value)); + Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, sender, recipient, value)); Ok(()) } - fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType, recipient: &T::AccountId) -> DispatchResult { + fn is_correct_transfer(collection: &CollectionHandle, recipient: &T::AccountId) -> DispatchResult { + let collection_id = collection.id; // check token limit and account token limit let account_items: u32 = >::get(collection_id, recipient).len() as u32; @@ -1606,24 +1802,29 @@ Ok(()) } - fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult { + fn can_create_items_in_collection(collection: &CollectionHandle, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult { + let collection_id = collection.id; // check token limit and account token limit - let total_items: u32 = ItemListIndex::get(collection_id); - let account_items: u32 = >::get(collection_id, owner).len() as u32; - ensure!(collection.limits.token_limit > total_items, Error::::CollectionTokenLimitExceeded); - ensure!(collection.limits.account_token_ownership_limit > account_items, Error::::AccountTokenLimitExceeded); + let total_items: u32 = ItemListIndex::get(collection_id) + .checked_add(amount) + .ok_or(Error::::CollectionTokenLimitExceeded)?; + let account_items: u32 = (>::get(collection_id, owner).len() as u32) + .checked_add(amount) + .ok_or(Error::::AccountTokenLimitExceeded)?; + ensure!(collection.limits.token_limit >= total_items, Error::::CollectionTokenLimitExceeded); + ensure!(collection.limits.account_token_ownership_limit >= account_items, Error::::AccountTokenLimitExceeded); - if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) { + if !Self::is_owner_or_admin_permissions(collection, sender.clone()) { ensure!(collection.mint_mode == true, Error::::PublicMintingNotAllowed); - Self::check_white_list(collection_id, owner)?; - Self::check_white_list(collection_id, sender)?; + Self::check_white_list(collection, owner)?; + Self::check_white_list(collection, sender)?; } Ok(()) } - fn validate_create_item_args(target_collection: &CollectionType, data: &CreateItemData) -> DispatchResult { + fn validate_create_item_args(target_collection: &CollectionHandle, data: &CreateItemData) -> DispatchResult { match target_collection.mode { CollectionMode::NFT => { @@ -1661,7 +1862,7 @@ Ok(()) } - fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult { + fn create_item_no_validation(collection: &CollectionHandle, owner: T::AccountId, data: CreateItemData) -> DispatchResult { match data { CreateItemData::NFT(data) => { @@ -1671,10 +1872,10 @@ variable_data: data.variable_data }; - Self::add_nft_item(collection_id, item)?; + Self::add_nft_item(collection, item)?; }, CreateItemData::Fungible(data) => { - Self::add_fungible_item(collection_id, &owner, data.value)?; + Self::add_fungible_item(collection, &owner, data.value)?; }, CreateItemData::ReFungible(data) => { let mut owner_list = Vec::new(); @@ -1686,27 +1887,22 @@ variable_data: data.variable_data }; - Self::add_refungible_item(collection_id, item)?; + Self::add_refungible_item(collection, item)?; } }; - // call event - Self::deposit_event(RawEvent::ItemCreated(collection_id, ::get(collection_id), owner)); - Ok(()) } - fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult { + fn add_fungible_item(collection: &CollectionHandle, owner: &T::AccountId, value: u128) -> DispatchResult { + let collection_id = collection.id; // Does new owner already have an account? - let mut balance: u128 = 0; - if >::contains_key(collection_id, owner) { - balance = >::get(collection_id, owner).value; - } + let balance: u128 = >::get(collection_id, owner).value; // Mint let item = FungibleItemType { - value: balance + value + value: balance.checked_add(value).ok_or(Error::::NumOverflow)?, }; >::insert(collection_id, (*owner).clone(), item); @@ -1716,18 +1912,27 @@ .ok_or(Error::::NumOverflow)?; >::insert(collection_id, (*owner).clone(), new_balance); + Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone())); Ok(()) } - fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType) -> DispatchResult { + fn add_refungible_item(collection: &CollectionHandle, item: ReFungibleItemType) -> DispatchResult { + let collection_id = collection.id; + let current_index = ::get(collection_id) .checked_add(1) .ok_or(Error::::NumOverflow)?; let itemcopy = item.clone(); - let value = item.owner.first().unwrap().fraction; - let owner = item.owner.first().unwrap().owner.clone(); + ensure!( + item.owner.len() == 1, + Error::::BadCreateRefungibleCall, + ); + let item_owner = item.owner.first().expect("only one owner is defined"); + let value = item_owner.fraction; + let owner = item_owner.owner.clone(); + Self::add_token_index(collection_id, current_index, &owner)?; ::insert(collection_id, current_index); @@ -1739,10 +1944,13 @@ .ok_or(Error::::NumOverflow)?; >::insert(collection_id, owner.clone(), new_balance); + Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, owner)); Ok(()) } - fn add_nft_item(collection_id: CollectionId, item: NftItemType) -> DispatchResult { + fn add_nft_item(collection: &CollectionHandle, item: NftItemType) -> DispatchResult { + let collection_id = collection.id; + let current_index = ::get(collection_id) .checked_add(1) .ok_or(Error::::NumOverflow)?; @@ -1759,25 +1967,24 @@ .ok_or(Error::::NumOverflow)?; >::insert(collection_id, item_owner.clone(), new_balance); + Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, item_owner)); Ok(()) } fn burn_refungible_item( - collection_id: CollectionId, + collection: &CollectionHandle, item_id: TokenId, owner: &T::AccountId, ) -> DispatchResult { - ensure!( - >::contains_key(collection_id, item_id), - Error::::TokenNotFound - ); - let mut token = >::get(collection_id, item_id); + let collection_id = collection.id; + + let mut token = >::get(collection_id, item_id) + .ok_or(Error::::TokenNotFound)?; let rft_balance = token .owner .iter() - .filter(|&i| i.owner == *owner) - .next() - .unwrap(); + .find(|&i| i.owner == *owner) + .ok_or(Error::::TokenNotFound)?; Self::remove_token_index(collection_id, item_id, owner)?; // update balance @@ -1791,13 +1998,14 @@ .owner .iter() .position(|i| i.owner == *owner) - .unwrap(); + .expect("owned item is exists"); token.owner.remove(index); let owner_count = token.owner.len(); // Burn the token completely if this was the last (only) owner if owner_count == 0 { >::remove(collection_id, item_id); + >::remove(collection_id, item_id); } else { >::insert(collection_id, item_id, token); @@ -1806,12 +2014,11 @@ Ok(()) } - fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult { - ensure!( - >::contains_key(collection_id, item_id), - Error::::TokenNotFound - ); - let item = >::get(collection_id, item_id); + fn burn_nft_item(collection: &CollectionHandle, item_id: TokenId) -> DispatchResult { + let collection_id = collection.id; + + let item = >::get(collection_id, item_id) + .ok_or(Error::::TokenNotFound)?; Self::remove_token_index(collection_id, item_id, &item.owner)?; // update balance @@ -1820,15 +2027,14 @@ .ok_or(Error::::NumOverflow)?; >::insert(collection_id, item.owner.clone(), new_balance); >::remove(collection_id, item_id); + >::remove(collection_id, item_id); Ok(()) } - fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult { - ensure!( - >::contains_key(collection_id, owner), - Error::::TokenNotFound - ); + fn burn_fungible_item(owner: &T::AccountId, collection: &CollectionHandle, value: u128) -> DispatchResult { + let collection_id = collection.id; + let mut balance = >::get(collection_id, owner); ensure!(balance.value >= value, Error::::TokenValueNotEnough); @@ -1849,18 +2055,20 @@ Ok(()) } - fn collection_exists(collection_id: CollectionId) -> DispatchResult { - ensure!( - >::contains_key(collection_id), - Error::::CollectionNotFound - ); - Ok(()) + pub fn get_collection(collection_id: CollectionId) -> Result, sp_runtime::DispatchError> { + Ok(>::get(collection_id) + .map(|collection| CollectionHandle { + id: collection_id, + collection + }) + .ok_or(Error::::CollectionNotFound)?) } - fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult { - Self::collection_exists(collection_id)?; + fn save_collection(collection: CollectionHandle) { + >::insert(collection.id, collection.collection); + } - let target_collection = >::get(collection_id); + fn check_owner_permissions(target_collection: &CollectionHandle, subject: T::AccountId) -> DispatchResult { ensure!( subject == target_collection.owner, Error::::NoPermission @@ -1868,57 +2076,33 @@ Ok(()) } - - fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool { - let target_collection = >::get(collection_id); - let mut result: bool = subject == target_collection.owner; - let exists = >::contains_key(collection_id); - if !result & exists { - if >::get(collection_id).contains(&subject) { - result = true - } - } - - result + fn is_owner_or_admin_permissions(collection: &CollectionHandle, subject: T::AccountId) -> bool { + subject == collection.owner || >::get(collection.id).contains(&subject) } fn check_owner_or_admin_permissions( - collection_id: CollectionId, + collection: &CollectionHandle, subject: T::AccountId, ) -> DispatchResult { - Self::collection_exists(collection_id)?; - let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone()); + ensure!(Self::is_owner_or_admin_permissions(collection, subject), Error::::NoPermission); - ensure!( - result, - Error::::NoPermission - ); Ok(()) } fn owned_amount( subject: T::AccountId, - collection_id: CollectionId, + target_collection: &CollectionHandle, item_id: TokenId, ) -> Option { - let target_collection = >::get(collection_id); + let collection_id = target_collection.id; match target_collection.mode { - CollectionMode::NFT => { - if >::get(collection_id, item_id).owner == subject { - return Some(1) - } - None - }, - CollectionMode::Fungible(_) => { - if >::contains_key(collection_id, &subject) { - return Some(>::get(collection_id, &subject) - .value); - } - None - }, - CollectionMode::ReFungible => >::get(collection_id, item_id) + CollectionMode::NFT => (>::get(collection_id, item_id)?.owner == subject) + .then(|| 1), + CollectionMode::Fungible(_) => Some(>::get(collection_id, &subject) + .value), + CollectionMode::ReFungible => >::get(collection_id, item_id)? .owner .iter() .find(|i| i.owner == subject) @@ -1927,27 +2111,16 @@ } } - fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool { - let target_collection = >::get(collection_id); - + fn is_item_owner(subject: T::AccountId, target_collection: &CollectionHandle, item_id: TokenId) -> bool { match target_collection.mode { - CollectionMode::NFT => { - >::get(collection_id, item_id).owner == subject - } - CollectionMode::Fungible(_) => { - >::contains_key(collection_id, &subject) - } - CollectionMode::ReFungible => { - >::get(collection_id, item_id) - .owner - .iter() - .any(|i| i.owner == subject) - } - CollectionMode::Invalid => false, + CollectionMode::Fungible(_) => true, + _ => Self::owned_amount(subject, target_collection, item_id).is_some(), } } - fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult { + fn check_white_list(collection: &CollectionHandle, address: &T::AccountId) -> DispatchResult { + let collection_id = collection.id; + let mes = Error::::AddresNotInWhiteList; ensure!(>::contains_key(collection_id, address), mes); @@ -1957,15 +2130,14 @@ /// Check if token exists. In case of Fungible, check if there is an entry for /// the owner in fungible balances double map fn token_exists( - collection_id: CollectionId, + target_collection: &CollectionHandle, item_id: TokenId, - owner: &T::AccountId ) -> DispatchResult { - let target_collection = >::get(collection_id); + let collection_id = target_collection.id; let exists = match target_collection.mode { CollectionMode::NFT => >::contains_key(collection_id, item_id), - CollectionMode::Fungible(_) => >::contains_key(collection_id, owner), + CollectionMode::Fungible(_) => true, CollectionMode::ReFungible => >::contains_key(collection_id, item_id), _ => false }; @@ -1975,18 +2147,18 @@ } fn transfer_fungible( - collection_id: CollectionId, + collection: &CollectionHandle, value: u128, owner: &T::AccountId, recipient: &T::AccountId, ) -> DispatchResult { - Self::token_exists(collection_id, 0, owner)?; + let collection_id = collection.id; let mut balance = >::get(collection_id, owner); ensure!(balance.value >= value, Error::::TokenValueTooLow); // Send balance to recipient (updates balanceOf of recipient) - Self::add_fungible_item(collection_id, recipient, value)?; + Self::add_fungible_item(collection, recipient, value)?; // update balanceOf of sender >::insert(collection_id, (*owner).clone(), balance.value - value); @@ -2004,21 +2176,22 @@ } fn transfer_refungible( - collection_id: CollectionId, + collection: &CollectionHandle, item_id: TokenId, value: u128, owner: T::AccountId, new_owner: T::AccountId, ) -> DispatchResult { - Self::token_exists(collection_id, item_id, &owner)?; + let collection_id = collection.id; + let full_item = >::get(collection_id, item_id) + .ok_or(Error::::TokenNotFound)?; - let full_item = >::get(collection_id, item_id); let item = full_item .owner .iter() .filter(|i| i.owner == owner) .next() - .ok_or(Error::::NumOverflow)?; + .ok_or(Error::::TokenNotFound)?; let amount = item.fraction; ensure!(amount >= value, Error::::TokenValueTooLow); @@ -2029,10 +2202,10 @@ .ok_or(Error::::NumOverflow)?; >::insert(collection_id, item.owner.clone(), balance_old_owner); - let balancenew_owner = >::get(collection_id, new_owner.clone()) + let balance_new_owner = >::get(collection_id, new_owner.clone()) .checked_add(value) .ok_or(Error::::NumOverflow)?; - >::insert(collection_id, new_owner.clone(), balancenew_owner); + >::insert(collection_id, new_owner.clone(), balance_new_owner); let old_owner = item.owner.clone(); let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner); @@ -2046,7 +2219,7 @@ .owner .iter_mut() .find(|i| i.owner == owner) - .unwrap() + .expect("old owner does present in refungible") .owner = new_owner.clone(); >::insert(collection_id, item_id, new_full_item); @@ -2058,7 +2231,7 @@ .owner .iter_mut() .find(|i| i.owner == owner) - .unwrap() + .expect("old owner does present in refungible") .fraction -= value; // separate amount @@ -2068,7 +2241,7 @@ .owner .iter_mut() .find(|i| i.owner == new_owner) - .unwrap() + .expect("new owner has account") .fraction += value; } else { // new owner do not have account @@ -2086,14 +2259,14 @@ } fn transfer_nft( - collection_id: CollectionId, + collection: &CollectionHandle, item_id: TokenId, sender: T::AccountId, new_owner: T::AccountId, ) -> DispatchResult { - Self::token_exists(collection_id, item_id, &sender)?; - - let mut item = >::get(collection_id, item_id); + let collection_id = collection.id; + let mut item = >::get(collection_id, item_id) + .ok_or(Error::::TokenNotFound)?; ensure!( sender == item.owner, @@ -2123,11 +2296,13 @@ } fn set_re_fungible_variable_data( - collection_id: CollectionId, + collection: &CollectionHandle, item_id: TokenId, data: Vec ) -> DispatchResult { - let mut item = >::get(collection_id, item_id); + let collection_id = collection.id; + let mut item = >::get(collection_id, item_id) + .ok_or(Error::::TokenNotFound)?; item.variable_data = data; @@ -2137,11 +2312,13 @@ } fn set_nft_variable_data( - collection_id: CollectionId, + collection: &CollectionHandle, item_id: TokenId, data: Vec ) -> DispatchResult { - let mut item = >::get(collection_id, item_id); + let collection_id = collection.id; + let mut item = >::get(collection_id, item_id) + .ok_or(Error::::TokenNotFound)?; item.variable_data = data; @@ -2150,7 +2327,7 @@ Ok(()) } - fn init_collection(item: &CollectionType) { + fn init_collection(item: &Collection) { // check params assert!( item.decimal_points <= MAX_DECIMAL_POINTS, @@ -2230,7 +2407,6 @@ } fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult { - // add to account limit if >::contains_key(owner) { @@ -2305,12 +2481,7 @@ } fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult { - if >::contains_key(contract.clone()) { - let owner = >::get(contract); - ensure!(account == owner, Error::::NoPermission); - } else { - fail!(Error::::NoPermission); - } + ensure!(>::get(contract) == Some(account), Error::::NoPermission); Ok(()) } @@ -2323,7 +2494,7 @@ /// Fee multiplier. pub type Multiplier = FixedU128; -type BalanceOf = <::OnChargeTransaction as transaction_payment::OnChargeTransaction>::Balance; +type BalanceOf = <::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction>::Balance; /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. @@ -2358,7 +2529,7 @@ where T::Call: Dispatchable, { - >::compute_fee(len as u32, info, tip) + >::compute_fee(len as u32, info, tip) } fn get_priority(len: usize, info: &DispatchInfoOf, final_fee: BalanceOf) -> TransactionPriority { @@ -2382,65 +2553,55 @@ ) -> Result< ( BalanceOf, - <::OnChargeTransaction as transaction_payment::OnChargeTransaction>::LiquidityInfo, + <::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction>::LiquidityInfo, ), TransactionValidityError, > { let tip = self.0; - // Set fee based on call type. Creating collection costs 1 Unique. - // All other transactions have traditional fees so far - // let fee = match call.is_sub_type() { - // Some(Call::create_collection(..)) => >::from(1_000_000_000), - // _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes - // // _ => >::from(100) - // }; let fee = Self::traditional_fee(len, info, tip); // Only mess with balances if fee is not zero. if fee.is_zero() { - return <::OnChargeTransaction as transaction_payment::OnChargeTransaction>::withdraw_fee(who, call, info, fee, tip) + return <::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction>::withdraw_fee(who, call, info, fee, tip) .map(|i| (fee, i)); } // Determine who is paying transaction fee based on ecnomic model // Parse call to extract collection ID and access collection sponsor - let mut sponsor: T::AccountId = match IsSubType::>::is_sub_type(call) { + let mut sponsor: Option = (|| match IsSubType::>::is_sub_type(call) { Some(Call::create_item(collection_id, _owner, _properties)) => { + let collection = >::get(collection_id)?; // sponsor timeout let block_number = >::block_number() as T::BlockNumber; - let limit = >::get(collection_id).limits.sponsor_transfer_timeout; - let mut sponsored = true; + let limit = collection.limits.sponsor_transfer_timeout; if >::contains_key((collection_id, &who)) { let last_tx_block = >::get((collection_id, &who)); let limit_time = last_tx_block + limit.into(); if block_number <= limit_time { - sponsored = false; + return None; } } - if sponsored { - >::insert((collection_id, who.clone()), block_number); - } + >::insert((collection_id, who.clone()), block_number); // check free create limit - if (>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) && - (>::get(collection_id).sponsor_confirmed) && - (sponsored) - { - >::get(collection_id).sponsor + if collection.limits.sponsored_data_size >= (_properties.len() as u32) { + collection.sponsorship.sponsor() + .cloned() } else { - T::AccountId::default() + None } } Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => { + let collection = >::get(collection_id)?; let mut sponsor_transfer = false; - if >::get(collection_id).sponsor_confirmed { + if collection.sponsorship.confirmed() { - let collection_limits = >::get(collection_id).limits; - let collection_mode = >::get(collection_id).mode; + let collection_limits = collection.limits; + let collection_mode = collection.mode; // sponsor timeout let block_number = >::block_number() as T::BlockNumber; @@ -2522,17 +2683,67 @@ } if !sponsor_transfer { - T::AccountId::default() + None + } else { + collection.sponsorship.sponsor() + .cloned() + } + } + + Some(Call::set_variable_meta_data(collection_id, item_id, data)) => { + let mut sponsor_metadata_changes = false; + + let collection = >::get(collection_id)?; + + if + collection.sponsorship.confirmed() && + // Can't sponsor fungible collection, this tx will be rejected + // as invalid + !matches!(collection.mode, CollectionMode::Fungible(_)) && + data.len() <= collection.limits.sponsored_data_size as usize + { + if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit { + let block_number = >::block_number() as T::BlockNumber; + + if >::get(collection_id, item_id) + .map(|last_block| block_number - last_block > rate_limit) + .unwrap_or(true) + { + sponsor_metadata_changes = true; + >::insert(collection_id, item_id, block_number); + } + } + } + + if !sponsor_metadata_changes { + None } else { - >::get(collection_id).sponsor + collection.sponsorship.sponsor().cloned() } } - _ => T::AccountId::default(), - }; + _ => None, + })(); + + match IsSubType::>::is_sub_type(call) { + Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => { + + let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default()); + + let owned_contract = >::get(called_contract.clone()).as_ref() == Some(who); + let white_list_enabled = >::contains_key(called_contract.clone()); + + if !owned_contract && white_list_enabled { + if !>::contains_key(called_contract.clone(), who) { + return Err(InvalidTransaction::Call.into()); + } + } + }, + _ => {}, + } // Sponsor smart contracts - sponsor = match IsSubType::>::is_sub_type(call) { + sponsor = sponsor.or_else(|| match IsSubType::>::is_sub_type(call) { // On instantiation: set the contract owner Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => { @@ -2544,23 +2755,27 @@ ); >::insert(new_contract_address.clone(), who.clone()); - T::AccountId::default() + None }, + // On instantiation with code: set the contract owner + Some(pallet_contracts::Call::instantiate_with_code(_endowment, _gas_limit, _code, _data, _salt)) => { + + let new_contract_address = >::contract_address( + &who, + &T::Hashing::hash(&_code), + _salt, + ); + + >::insert(new_contract_address.clone(), who.clone()); + + None + } + // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => { let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default()); - - let owned_contract = >::contains_key(called_contract.clone()) - && >::get(called_contract.clone()) == *who; - let white_list_enabled = >::contains_key(called_contract.clone()) && >::get(called_contract.clone()); - - if !owned_contract && white_list_enabled { - if !>::contains_key(called_contract.clone(), who) { - return Err(InvalidTransaction::Call.into()); - } - } let mut sponsor_transfer = false; if >::contains_key(called_contract.clone()) { @@ -2577,28 +2792,23 @@ sponsor_transfer = false; } - - let mut sp = T::AccountId::default(); if sponsor_transfer { if >::contains_key(called_contract.clone()) { if >::get(called_contract.clone()) { - sp = called_contract; + return Some(called_contract); } } } - sp + None }, - _ => sponsor, - }; + _ => None, + }); - let mut who_pays_fee: T::AccountId = sponsor.clone(); - if sponsor == T::AccountId::default() { - who_pays_fee = who.clone(); - } + let who_pays_fee = sponsor.unwrap_or_else(|| who.clone()); - <::OnChargeTransaction as transaction_payment::OnChargeTransaction>::withdraw_fee(&who_pays_fee, call, info, fee, tip) + <::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction>::withdraw_fee(&who_pays_fee, call, info, fee, tip) .map(|i| (fee, i)) } } @@ -2622,7 +2832,7 @@ // who pays fee Self::AccountId, // imbalance resulting from withdrawing the fee - <::OnChargeTransaction as transaction_payment::OnChargeTransaction>::LiquidityInfo, + <::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction>::LiquidityInfo, ); fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { Ok(()) @@ -2661,15 +2871,15 @@ _result: &DispatchResult, ) -> Result<(), TransactionValidityError> { let (tip, who, imbalance) = pre; - let actual_fee = transaction_payment::Module::::compute_actual_fee( + let actual_fee = pallet_transaction_payment::Module::::compute_actual_fee( len as u32, info, post_info, tip, ); - ::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?; + ::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?; Ok(()) } } -// #endregion +// #endregion \ No newline at end of file --- a/pallets/nft/src/mock.rs +++ b/pallets/nft/src/mock.rs @@ -1,43 +1,45 @@ -// Creating mock runtime here - -use crate::{Module, Config}; - -use frame_support::{ - impl_outer_origin, parameter_types, - weights::{Weight, IdentityFee}, -}; -use frame_system as system; -use system::limits::{BlockLength, BlockWeights}; -use transaction_payment::{self, CurrencyAdapter}; +use crate as pallet_template; use sp_core::H256; +use frame_support::{ + parameter_types, + weights::IdentityFee, +}; use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, + traits::{BlakeTwo256, IdentityLookup}, + testing::Header, + Perbill, }; -use pallet_contracts::WeightInfo; -pub use pallet_balances; +use pallet_transaction_payment::{ CurrencyAdapter}; +use frame_system as system; -impl_outer_origin! { - pub enum Origin for Test {} -} +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Module, Call, Config, Storage, Event}, + TemplateModule: pallet_template::{Module, Call, Storage}, + Balances: pallet_balances::{Module, Call, Storage}, + } +); -// For testing the pallet, we construct most of a mock runtime. This means -// first constructing a configuration type (`Test`) which `impl`s each of the -// configuration traits of pallets we want to use. -#[derive(Clone, Eq, PartialEq)] -pub struct Test; parameter_types! { - pub const BlockHashCount: u64 = 250; - pub TestBlockWeights: BlockWeights = BlockWeights::default(); - pub TestBlockLength: BlockLength = BlockLength::default(); - pub SS58Prefix: u8 = 0; + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; } impl system::Config for Test { type BaseCallFilter = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); type Origin = Origin; - type Call = (); + type Call = Call; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -47,24 +49,20 @@ type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; - type BlockWeights = TestBlockWeights; - type DbWeight = (); - type BlockLength = TestBlockLength; type Version = (); - type PalletInfo = (); + type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); + type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; - type SystemWeightInfo = (); } parameter_types! { pub const ExistentialDeposit: u64 = 1; pub const MaxLocks: u32 = 50; } - -type System = frame_system::Module; +//frame_system::Module; impl pallet_balances::Config for Test { type AccountStore = System; type Balance = u64; @@ -79,13 +77,12 @@ pub const TransactionByteFee: u64 = 1; } -impl transaction_payment::Config for Test { +impl pallet_transaction_payment::Config for Test { type OnChargeTransaction = CurrencyAdapter, ()>; type TransactionByteFee = TransactionByteFee; type WeightToFee = IdentityFee; type FeeMultiplierUpdate = (); } - parameter_types! { pub const MinimumPeriod: u64 = 1; @@ -110,12 +107,8 @@ pub const SignedClaimHandicap: u32 = 2; pub const MaxDepth: u32 = 32; pub const MaxValueSize: u32 = 16 * 1024; - pub DeletionWeightLimit: Weight = Perbill::from_percent(10) * - TestBlockWeights::get().max_block; - pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / ( - ::WeightInfo::on_initialize_per_queue_item(1) - - ::WeightInfo::on_initialize_per_queue_item(0) - )) / 5) as u32; + pub DeletionWeightLimit: u64 = u64::MAX;//Perbill::from_percent(10); + pub DeletionQueueDepth: u32 = 10; } impl pallet_contracts::Config for Test { @@ -136,23 +129,25 @@ type DeletionQueueDepth = DeletionQueueDepth; type MaxValueSize = MaxValueSize; type ChainExtension = (); + type MaxCodeSize = (); type WeightPrice = (); type WeightInfo = pallet_contracts::weights::SubstrateWeight; } -impl Config for Test { +parameter_types! { + pub const CollectionCreationPrice: u32 = 0; + pub TreasuryAccountId: u64 = 1234; +} + +impl pallet_template::Config for Test { type Event = (); type WeightInfo = (); - + type CollectionCreationPrice = CollectionCreationPrice; + type Currency = pallet_balances::Module; + type TreasuryAccountId = TreasuryAccountId; } -pub type TemplateModule = Module; - -// This function basically just builds a genesis storage key/value store according to -// our desired mockup. +// Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - system::GenesisConfig::default() - .build_storage::() - .unwrap() - .into() -} + system::GenesisConfig::default().build_storage::().unwrap().into() +} \ No newline at end of file --- a/pallets/nft/src/tests.rs +++ b/pallets/nft/src/tests.rs @@ -55,11 +55,11 @@ let saved_col_name: Vec = "Test1\0".encode_utf16().collect::>(); let saved_description: Vec = "TestDescription1\0".encode_utf16().collect::>(); let saved_prefix: Vec = b"token_prefix1\0".to_vec(); - assert_eq!(TemplateModule::collection(id).owner, owner); - assert_eq!(TemplateModule::collection(id).name, saved_col_name); - assert_eq!(TemplateModule::collection(id).mode, *mode); - assert_eq!(TemplateModule::collection(id).description, saved_description); - assert_eq!(TemplateModule::collection(id).token_prefix, saved_prefix); + assert_eq!(TemplateModule::collection_id(id).unwrap().owner, owner); + assert_eq!(TemplateModule::collection_id(id).unwrap().name, saved_col_name); + assert_eq!(TemplateModule::collection_id(id).unwrap().mode, *mode); + assert_eq!(TemplateModule::collection_id(id).unwrap().description, saved_description); + assert_eq!(TemplateModule::collection_id(id).unwrap().token_prefix, saved_prefix); id } @@ -89,7 +89,7 @@ let collection_id = create_test_collection(&CollectionMode::NFT, 1); assert_ok!(TemplateModule::set_schema_version(origin1, collection_id, SchemaVersion::Unique)); - assert_eq!(TemplateModule::collection(collection_id).schema_version, SchemaVersion::Unique); + assert_eq!(TemplateModule::collection_id(collection_id).unwrap().schema_version, SchemaVersion::Unique); }); } @@ -121,8 +121,9 @@ let data = default_nft_data(); create_test_item(collection_id, &data.clone().into()); - assert_eq!(TemplateModule::nft_item_id(collection_id, 1).const_data, data.const_data); - assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, data.variable_data); + let item = TemplateModule::nft_item_id(collection_id, 1).unwrap(); + assert_eq!(item.const_data, data.const_data); + assert_eq!(item.variable_data, data.variable_data); }); } @@ -146,8 +147,9 @@ items_data.clone().into_iter().map(|d| { d.into() }).collect() )); for (index, data) in items_data.iter().enumerate() { - assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as TokenId).const_data.to_vec(), data.const_data); - assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as TokenId).variable_data.to_vec(), data.variable_data); + let item = TemplateModule::nft_item_id(1, (index + 1) as TokenId).unwrap(); + assert_eq!(item.const_data.to_vec(), data.const_data); + assert_eq!(item.variable_data.to_vec(), data.variable_data); } }); } @@ -160,16 +162,17 @@ let data = default_re_fungible_data(); create_test_item(collection_id, &data.clone().into()); + let item = TemplateModule::refungible_item_id(collection_id, 1).unwrap(); assert_eq!( - TemplateModule::refungible_item_id(collection_id, 1).const_data, + item.const_data, data.const_data ); assert_eq!( - TemplateModule::refungible_item_id(collection_id, 1).variable_data, + item.variable_data, data.variable_data ); assert_eq!( - TemplateModule::refungible_item_id(collection_id, 1).owner[0], + item.owner[0], Ownership { owner: 1, fraction: 1023 @@ -197,7 +200,7 @@ )); for (index, data) in items_data.iter().enumerate() { - let item = TemplateModule::refungible_item_id(1, (index + 1) as TokenId); + let item = TemplateModule::refungible_item_id(1, (index + 1) as TokenId).unwrap(); assert_eq!(item.const_data.to_vec(), data.const_data); assert_eq!(item.variable_data.to_vec(), data.variable_data); assert_eq!( @@ -299,28 +302,31 @@ let origin1 = Origin::signed(1); let origin2 = Origin::signed(2); - assert_eq!( - TemplateModule::refungible_item_id(collection_id, 1).const_data, - data.const_data - ); - assert_eq!( - TemplateModule::refungible_item_id(collection_id, 1).variable_data, - data.variable_data - ); - assert_eq!( - TemplateModule::refungible_item_id(collection_id, 1).owner[0], - Ownership { - owner: 1, - fraction: 1023 - } - ); + { + let item = TemplateModule::refungible_item_id(collection_id, 1).unwrap(); + assert_eq!( + item.const_data, + data.const_data + ); + assert_eq!( + item.variable_data, + data.variable_data + ); + assert_eq!( + item.owner[0], + Ownership { + owner: 1, + fraction: 1023 + } + ); + } assert_eq!(TemplateModule::balance_count(1, 1), 1023); assert_eq!(TemplateModule::address_tokens(1, 1), [1]); // change owner scenario assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1023)); assert_eq!( - TemplateModule::refungible_item_id(1, 1).owner[0], + TemplateModule::refungible_item_id(1, 1).unwrap().owner[0], Ownership { owner: 2, fraction: 1023 @@ -333,20 +339,23 @@ // split item scenario assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500)); - assert_eq!( - TemplateModule::refungible_item_id(1, 1).owner[0], - Ownership { - owner: 2, - fraction: 523 - } - ); - assert_eq!( - TemplateModule::refungible_item_id(1, 1).owner[1], - Ownership { - owner: 3, - fraction: 500 - } - ); + { + let item = TemplateModule::refungible_item_id(1, 1).unwrap(); + assert_eq!( + item.owner[0], + Ownership { + owner: 2, + fraction: 523 + } + ); + assert_eq!( + item.owner[1], + Ownership { + owner: 3, + fraction: 500 + } + ); + } assert_eq!(TemplateModule::balance_count(1, 2), 523); assert_eq!(TemplateModule::balance_count(1, 3), 500); assert_eq!(TemplateModule::address_tokens(1, 2), [1]); @@ -354,20 +363,23 @@ // split item and new owner has account scenario assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200)); - assert_eq!( - TemplateModule::refungible_item_id(1, 1).owner[0], - Ownership { - owner: 2, - fraction: 323 - } - ); - assert_eq!( - TemplateModule::refungible_item_id(1, 1).owner[1], - Ownership { - owner: 3, - fraction: 700 - } - ); + { + let item = TemplateModule::refungible_item_id(1, 1).unwrap(); + assert_eq!( + item.owner[0], + Ownership { + owner: 2, + fraction: 323 + } + ); + assert_eq!( + item.owner[1], + Ownership { + owner: 3, + fraction: 700 + } + ); + } assert_eq!(TemplateModule::balance_count(1, 2), 323); assert_eq!(TemplateModule::balance_count(1, 3), 700); assert_eq!(TemplateModule::address_tokens(1, 2), [1]); @@ -390,7 +402,7 @@ let origin1 = Origin::signed(1); // default scenario assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000)); - assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 2); + assert_eq!(TemplateModule::nft_item_id(1, 1).unwrap().owner, 2); assert_eq!(TemplateModule::balance_count(1, 1), 0); assert_eq!(TemplateModule::balance_count(1, 2), 1); // assert_eq!(TemplateModule::address_tokens(1, 1), []); @@ -456,7 +468,7 @@ let data = default_nft_data(); create_test_item(collection_id, &data.clone().into()); - assert_eq!(TemplateModule::nft_item_id(1, 1).const_data, data.const_data); + assert_eq!(TemplateModule::nft_item_id(1, 1).unwrap().const_data, data.const_data); assert_eq!(TemplateModule::balance_count(1, 1), 1); assert_eq!(TemplateModule::address_tokens(1, 1), [1]); @@ -605,7 +617,7 @@ 1, 1, 4 - ), Error::::TokenValueNotEnough); + ), Error::::NoPermission); }); } @@ -622,7 +634,7 @@ collection_id, 2 )); - assert_eq!(TemplateModule::collection(collection_id).owner, 2); + assert_eq!(TemplateModule::collection_id(collection_id).unwrap().owner, 2); }); } @@ -685,7 +697,7 @@ assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5)); assert_noop!( TemplateModule::burn_item(origin1.clone(), 1, 1, 5), - Error::::TokenNotFound + Error::::TokenValueNotEnough ); assert_eq!(TemplateModule::balance_count(1, 1), 0); @@ -807,9 +819,9 @@ assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1); assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 5); assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1023); - assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1); + assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).unwrap().owner, 1); assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).value, 5); - assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1); + assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).unwrap().owner[0].owner, 1); }); } @@ -1841,8 +1853,8 @@ let origin1 = Origin::signed(1); assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, b"test const on chain schema".to_vec())); - assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"test const on chain schema".to_vec()); - assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"".to_vec()); + assert_eq!(TemplateModule::collection_id(collection_id).unwrap().const_on_chain_schema, b"test const on chain schema".to_vec()); + assert_eq!(TemplateModule::collection_id(collection_id).unwrap().variable_on_chain_schema, b"".to_vec()); }); } @@ -1856,8 +1868,8 @@ let origin1 = Origin::signed(1); assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, b"test variable on chain schema".to_vec())); - assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"".to_vec()); - assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"test variable on chain schema".to_vec()); + assert_eq!(TemplateModule::collection_id(collection_id).unwrap().const_on_chain_schema, b"".to_vec()); + assert_eq!(TemplateModule::collection_id(collection_id).unwrap().variable_on_chain_schema, b"test variable on chain schema".to_vec()); }); } @@ -1876,7 +1888,7 @@ let variable_data = b"test set_variable_meta_data method.".to_vec(); assert_ok!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone())); - assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, variable_data); + assert_eq!(TemplateModule::nft_item_id(collection_id, 1).unwrap().variable_data, variable_data); }); } @@ -1895,7 +1907,7 @@ let variable_data = b"test set_variable_meta_data method.".to_vec(); assert_ok!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone())); - assert_eq!(TemplateModule::refungible_item_id(collection_id, 1).variable_data, variable_data); + assert_eq!(TemplateModule::refungible_item_id(collection_id, 1).unwrap().variable_data, variable_data); }); } --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -5,60 +5,60 @@ license = 'All Rights Reserved' name = 'nft-runtime' repository = 'https://github.com/usetech-llc/nft_parachain/' -version = '2.1.0' +version = '3.0.0' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] [build-dependencies] -wasm-builder-runner = { package = 'substrate-wasm-builder-runner', version = '1.0.5' } +substrate-wasm-builder = '4.0.0' # alias "parity-scale-code" to "codec" [dependencies.codec] default-features = false features = ['derive'] package = 'parity-scale-codec' -version = '1.3.4' +version = '2.0.0' [dependencies] hex-literal = { optional = true, version = '0.3.1' } -serde = { features = ['derive'], optional = true, version = '1.0.101' } +serde = { features = ['derive'], optional = true, version = '1.0.119' } # local dependencies -pallet-nft = { path = '../pallets/nft', default-features = false, version = '2.1.0' } +pallet-nft = { path = '../pallets/nft', default-features = false, version = '3.0.0' } # Substrate dependencies -frame-benchmarking = { default-features = false, optional = true, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -frame-executive = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -frame-support = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -frame-system = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -frame-system-benchmarking = { default-features = false, optional = true, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -frame-system-rpc-runtime-api = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-aura = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-balances = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-contracts = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-contracts-primitives = { default-features = false, version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-contracts-rpc-runtime-api = { default-features = false, version = '0.8.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-grandpa = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-randomness-collective-flip = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-sudo = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-timestamp = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-transaction-payment = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-treasury = { version = "2.0.1", default-features = false, git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -pallet-vesting = { version = "2.0.1", default-features = false, git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-api = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-arithmetic = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-block-builder = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-consensus-aura = { default-features = false, version = '0.8.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-core = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-inherents = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-offchain = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-runtime = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-session = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-std = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-transaction-pool = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } -sp-version = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' } +frame-benchmarking = { default-features = false, optional = true, version = '3.0.0' } +frame-executive = { default-features = false, version = '3.0.0' } +frame-support = { default-features = false, version = '3.0.0' } +frame-system = { default-features = false, version = '3.0.0' } +frame-system-benchmarking = { default-features = false, optional = true, version = '3.0.0' } +frame-system-rpc-runtime-api = { default-features = false, version = '3.0.0' } +pallet-aura = { default-features = false, version = '3.0.0' } +pallet-balances = { default-features = false, version = '3.0.0' } +pallet-contracts = { default-features = false, version = '3.0.0' } +pallet-contracts-primitives = { default-features = false, version = '3.0.0' } +pallet-contracts-rpc-runtime-api = { default-features = false, version = '3.0.0' } +pallet-grandpa = { default-features = false, version = '3.0.0' } +pallet-randomness-collective-flip = { default-features = false, version = '3.0.0' } +pallet-sudo = { default-features = false, version = '3.0.0' } +pallet-timestamp = { default-features = false, version = '3.0.0' } +pallet-transaction-payment = { default-features = false, version = '3.0.0' } +pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = '3.0.0' } +pallet-treasury = { default-features = false, version = "3.0.0" } +pallet-vesting = { default-features = false, version = "3.0.0" } +sp-arithmetic = { default-features = false, version = '3.0.0' } +sp-api = { default-features = false, version = '3.0.0' } +sp-block-builder = { default-features = false, version = '3.0.0' } +sp-consensus-aura = { default-features = false, version = '0.9.0' } +sp-core = { default-features = false, version = '3.0.0' } +sp-inherents = { default-features = false, version = '3.0.0' } +sp-offchain = { default-features = false, version = '3.0.0' } +sp-runtime = { default-features = false, version = '3.0.0' } +sp-session = { default-features = false, version = '3.0.0' } +sp-std = { default-features = false, version = '3.0.0' } +sp-transaction-pool = { default-features = false, version = '3.0.0' } +sp-version = { default-features = false, version = '3.0.0' } smallvec = "1.4.1" [features] --- a/runtime/build.rs +++ b/runtime/build.rs @@ -1,10 +1,9 @@ -use wasm_builder_runner::WasmBuilder; +use substrate_wasm_builder::WasmBuilder; fn main() { WasmBuilder::new() .with_current_project() - .with_wasm_builder_from_crates("2.0.0") - .export_heap_base() .import_memory() + .export_heap_base() .build() -} +} \ No newline at end of file --- a/runtime/src/chain_extension.rs +++ b/runtime/src/chain_extension.rs @@ -33,7 +33,7 @@ /// The chain Extension of NFT pallet pub struct NFTExtension; -impl ChainExtension for NFTExtension { +impl ChainExtension for NFTExtension { fn call(func_id: u32, env: Environment) -> Result where ::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]>, @@ -60,7 +60,9 @@ } let recipient = AccountId32::from(bytes_rec); - match pallet_nft::Module::::transfer_internal(sender, recipient, input.collection_id, input.token_id, input.amount) { + let collection = pallet_nft::Module::::get_collection(input.collection_id)?; + + match pallet_nft::Module::::transfer_internal(sender, recipient, &collection, input.token_id, input.amount) { Ok(_) => Ok(RetVal::Converging(func_id)), _ => Err(DispatchError::Other("Transfer error")) } @@ -71,4 +73,3 @@ } } } - --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -24,7 +24,7 @@ create_runtime_str, generic, impl_opaque_keys, traits::{ Convert, ConvertInto, BlakeTwo256, Block as BlockT, IdentifyAccount, - IdentityLookup, NumberFor, Verify, + IdentityLookup, NumberFor, Verify, AccountIdConversion, }, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, MultiSignature, @@ -35,7 +35,7 @@ pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; // A few exports that help ease life for downstream crates. pub use pallet_balances::Call as BalancesCall; -pub use pallet_contracts::{Schedule as ContractsSchedule, WeightInfo}; +pub use pallet_contracts::{Schedule as ContractsSchedule }; pub use frame_support::{ construct_runtime, dispatch::DispatchResult, @@ -47,10 +47,11 @@ }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, - DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, + DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients }, }; +use pallet_contracts::weights::WeightInfo; // #[cfg(any(feature = "std", test))] use frame_system::{ self as system, @@ -64,7 +65,7 @@ pub use pallet_timestamp::Call as TimestampCall; mod chain_extension; -use crate::chain_extension::NFTExtension; +use crate::chain_extension::{ NFTExtension, Imbalance }; /// Struct that handles the conversion of Balance -> `u64`. This is used for /// staking's election calculation. @@ -229,6 +230,21 @@ } } +// impl OnUnbalanced for DealWithFees { +// fn on_unbalanceds(mut fees_then_tips: impl Iterator) { +// if let Some(fees) = fees_then_tips.next() { +// // for fees, 100% to treasury +// let mut split = fees.ration(100, 0); +// if let Some(tips) = fees_then_tips.next() { +// // for tips, if any, 100% to treasury +// tips.ration_merge_into(100, 0, &mut split); +// } +// Treasury::on_unbalanced(split.0); +// // Author::on_unbalanced(split.1); +// } +// } +// } + /// We assume that ~10% of the block weight is consumed by `on_initalize` handlers. /// This is used to limit the maximal weight of a single extrinsic. const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); @@ -388,6 +404,7 @@ pub const SignedClaimHandicap: u32 = 2; pub const MaxDepth: u32 = 32; pub const MaxValueSize: u32 = 16 * 1024; + pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb // The lazy deletion runs inside on_initialize. pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO * RuntimeBlockWeights::get().max_block; @@ -420,6 +437,7 @@ type ChainExtension = NFTExtension; type DeletionQueueDepth = DeletionQueueDepth; type DeletionWeightLimit = DeletionWeightLimit; + type MaxCodeSize = MaxCodeSize; } parameter_types! { @@ -502,10 +520,18 @@ type WeightInfo = (); } +parameter_types! { + pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account(); + pub const CollectionCreationPrice: Balance = 100 * UNIQUE; +} + /// Used for the module nft in `./nft.rs` impl pallet_nft::Config for Runtime { type Event = Event; type WeightInfo = nft_weights::WeightInfo; + type Currency = Balances; + type CollectionCreationPrice = CollectionCreationPrice; + type TreasuryAccountId = TreasuryAccountId; } construct_runtime!( @@ -518,7 +544,7 @@ RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, Contracts: pallet_contracts::{Module, Call, Config, Storage, Event}, Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent}, - Aura: pallet_aura::{Module, Config, Inherent}, + Aura: pallet_aura::{Module, Config }, Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event}, Balances: pallet_balances::{Module, Call, Storage, Config, Event}, TransactionPayment: pallet_transaction_payment::{Module, Storage}, @@ -738,4 +764,4 @@ Ok(batches) } } -} +} \ No newline at end of file --- a/runtime/src/nft_weights.rs +++ b/runtime/src/nft_weights.rs @@ -133,6 +133,11 @@ .saturating_add(DbWeight::get().reads(0 as Weight)) .saturating_add(DbWeight::get().writes(2 as Weight)) } + fn set_variable_meta_data_sponsoring_rate_limit() -> Weight { + (3_500_000 as Weight) + .saturating_add(DbWeight::get().reads(1 as Weight)) + .saturating_add(DbWeight::get().writes(2 as Weight)) + } fn toggle_contract_white_list() -> Weight { (3_000_000 as Weight) .saturating_add(DbWeight::get().reads(0 as Weight)) --- a/runtime_types.json +++ b/runtime_types.json @@ -1,102 +1,103 @@ { - "AccessMode": { - "_enum": [ - "Normal", - "WhiteList" - ] - }, - "DecimalPoints": "u8", - "CollectionMode": { - "_enum": { - "Invalid": null, - "NFT": null, - "Fungible": "DecimalPoints", - "ReFungible": null - } - }, - "Ownership": { - "Owner": "AccountId", - "Fraction": "u128" - }, - "FungibleItemType": { - "Value": "u128" - }, - "NftItemType": { - "Owner": "AccountId", - "ConstData": "Vec", - "VariableData": "Vec" - }, - "ReFungibleItemType": { - "Owner": "Vec>", - "ConstData": "Vec", - "VariableData": "Vec" - }, - "CollectionType": { - "Owner": "AccountId", - "Mode": "CollectionMode", - "Access": "AccessMode", - "DecimalPoints": "DecimalPoints", - "Name": "Vec", - "Description": "Vec", - "TokenPrefix": "Vec", - "MintMode": "bool", - "OffchainSchema": "Vec", - "SchemaVersion": "SchemaVersion", - "Sponsor": "AccountId", - "SponsorConfirmed": "bool", - "Limits": "CollectionLimits", - "VariableOnChainSchema": "Vec", - "ConstOnChainSchema": "Vec" - }, - "RawData": "Vec", - "Address": "AccountId", - "LookupSource": "AccountId", - "Weight": "u64", - "CreateNftData": { - "const_data": "Vec", - "variable_data": "Vec" - }, - "CreateFungibleData": { - "value": "u128" - }, - "CreateReFungibleData": { - "const_data": "Vec", - "variable_data": "Vec", - "pieces": "u128" - }, - "CreateItemData": { - "_enum": { - "NFT": "CreateNftData", - "Fungible": "CreateFungibleData", - "ReFungible": "CreateReFungibleData" - } - }, - "SchemaVersion": { - "_enum": [ - "ImageURL", - "Unique" - ] - }, - "CollectionId": "u32", - "TokenId": "u32", - "ChainLimits": { - "CollectionNumbersLimit": "u32", - "AccountTokenOwnershipLimit": "u32", - "CollectionAdminsLimit": "u64", - "CustomDataLimit": "u32", - "NftSponsorTimeout": "u32", - "FungibleSponsorTimeout": "u32", - "RefungibleSponsorTimeout": "u32", - "OffchainSchemaLimit": "u32", - "VariableOnChainSchemaLimit": "u32", - "ConstOnChainSchemaLimit": "u32" - }, - "CollectionLimits": { - "AccountTokenOwnershipLimit": "u32", - "SponsoredMintSize": "u32", - "TokenLimit": "u32", - "SponsorTimeout": "u32", - "OwnerCanTransfer": "bool", - "OwnerCanDestroy": "bool" + "AccessMode": { + "_enum": [ + "Normal", + "WhiteList" + ] + }, + "DecimalPoints": "u8", + "CollectionMode": { + "_enum": { + "Invalid": null, + "NFT": null, + "Fungible": "DecimalPoints", + "ReFungible": null + } + }, + "Ownership": { + "Owner": "AccountId", + "Fraction": "u128" + }, + "FungibleItemType": { + "Value": "u128" + }, + "NftItemType": { + "Owner": "AccountId", + "ConstData": "Vec", + "VariableData": "Vec" + }, + "ReFungibleItemType": { + "Owner": "Vec>", + "ConstData": "Vec", + "VariableData": "Vec" + }, + "Collection": { + "Owner": "AccountId", + "Mode": "CollectionMode", + "Access": "AccessMode", + "DecimalPoints": "DecimalPoints", + "Name": "Vec", + "Description": "Vec", + "TokenPrefix": "Vec", + "MintMode": "bool", + "OffchainSchema": "Vec", + "SchemaVersion": "SchemaVersion", + "Sponsor": "AccountId", + "SponsorConfirmed": "bool", + "Limits": "CollectionLimits", + "VariableOnChainSchema": "Vec", + "ConstOnChainSchema": "Vec" + }, + "RawData": "Vec", + "Address": "AccountId", + "LookupSource": "AccountId", + "Weight": "u64", + "CreateNftData": { + "const_data": "Vec", + "variable_data": "Vec" + }, + "CreateFungibleData": { + "value": "u128" + }, + "CreateReFungibleData": { + "const_data": "Vec", + "variable_data": "Vec", + "pieces": "u128" + }, + "CreateItemData": { + "_enum": { + "NFT": "CreateNftData", + "Fungible": "CreateFungibleData", + "ReFungible": "CreateReFungibleData" } -} \ No newline at end of file + }, + "SchemaVersion": { + "_enum": [ + "ImageURL", + "Unique" + ] + }, + "CollectionId": "u32", + "TokenId": "u32", + "ChainLimits": { + "CollectionNumbersLimit": "u32", + "AccountTokenOwnershipLimit": "u32", + "CollectionAdminsLimit": "u64", + "CustomDataLimit": "u32", + "NftSponsorTimeout": "u32", + "FungibleSponsorTimeout": "u32", + "RefungibleSponsorTimeout": "u32", + "OffchainSchemaLimit": "u32", + "VariableOnChainSchemaLimit": "u32", + "ConstOnChainSchemaLimit": "u32" + }, + "CollectionLimits": { + "AccountTokenOwnershipLimit": "u32", + "SponsoredMintSize": "u32", + "TokenLimit": "u32", + "SponsorTimeout": "u32", + "OwnerCanTransfer": "bool", + "OwnerCanDestroy": "bool" + }, + "AccountInfo": "AccountInfoWithDualRefCount" +} --- a/tests/package.json +++ b/tests/package.json @@ -25,10 +25,14 @@ "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts", "testSetVariableMetaData": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetaData.test.ts", "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts", + "testSetCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionSponsor.test.ts", + "testConfirmSponsorship": "mocha --timeout 9999999 -r ts-node/register ./**/confirmSponsorship.test.ts", "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts", + "testRemoveCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionSponsor.test.ts", "testRemoveFromWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromWhiteList.test.ts", "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts", "testCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts", + "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts", "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts", "testCreateMultipleItems": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItems.test.ts", "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts", @@ -41,9 +45,11 @@ "testSetMintPermission": "mocha --timeout 9999999 -r ts-node/register ./**/setMintPermission.test.ts", "testCreditFeesToTreasury": "mocha --timeout 9999999 -r ts-node/register ./**/creditFeesToTreasury.test.ts", "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts", + "testRemoveFromContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromContractWhiteList.test.ts", "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts", "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts", - "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts" + "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts", + "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts" }, "author": "", "license": "SEE LICENSE IN ../LICENSE", --- a/tests/src/addCollectionAdmin.test.ts +++ b/tests/src/addCollectionAdmin.test.ts @@ -1,135 +1,135 @@ -// -// This file is subject to the terms and conditions defined in -// file 'LICENSE', which is part of this source code package. -// - -import { ApiPromise } from '@polkadot/api'; -import BN from 'bn.js'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import privateKey from './substrate/privateKey'; -import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api'; -import {createCollectionExpectSuccess, destroyCollectionExpectSuccess} from './util/helpers'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => { - it('Add collection admin.', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKey('//Alice'); - const bob = privateKey('//Bob'); - - const collection: any = (await api.query.nft.collection(collectionId)); - expect(collection.Owner.toString()).to.be.eq(alice.address); - - const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address); - await submitTransactionAsync(alice, changeAdminTx); - - const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); - expect(adminListAfterAddAdmin).to.be.contains(bob.address); - }); - }); - - it('Add admin using added collection admin.', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//CHARLIE'); - - const collection: any = (await api.query.nft.collection(collectionId)); - expect(collection.Owner.toString()).to.be.eq(Alice.address); - - const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address); - await submitTransactionAsync(Alice, changeAdminTx); - - const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); - expect(adminListAfterAddAdmin).to.be.contains(Bob.address); - - const changeAdminTxCharlie = api.tx.nft.addCollectionAdmin(collectionId, Charlie.address); - await submitTransactionAsync(Bob, changeAdminTxCharlie); - const adminListAfterAddNewAdmin: any = (await api.query.nft.adminList(collectionId)); - expect(adminListAfterAddNewAdmin).to.be.contains(Bob.address); - expect(adminListAfterAddNewAdmin).to.be.contains(Charlie.address); - }); - }); -}); - -describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => { - it("Not owner can't add collection admin.", async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKey('//Alice'); - const nonOwner = privateKey('//Bob_stash'); - - const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, alice.address); - await expect(submitTransactionExpectFailAsync(nonOwner, changeAdminTx)).to.be.rejected; - - const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); - expect(adminListAfterAddAdmin).not.to.be.contains(alice.address); - - // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); - }); - }); - it("Can't add collection admin of not existing collection.", async () => { - await usingApi(async (api) => { - // tslint:disable-next-line: no-bitwise - const collectionId = (1 << 32) - 1; - const alice = privateKey('//Alice'); - const bob = privateKey('//Bob'); - - const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address); - await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected; - - // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); - }); - }); - - it("Can't add an admin to a destroyed collection.", async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - await destroyCollectionExpectSuccess(collectionId); - const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address); - await expect(submitTransactionExpectFailAsync(Alice, changeOwnerTx)).to.be.rejected; - - // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); - }); - }); - - it('Add an admin to a collection that has reached the maximum number of admins limit', async () => { - await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const accounts = [ - 'GsvVmjr1CBHwQHw84pPHMDxgNY3iBLz6Qn7qS3CH8qPhrHz', - 'FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP', - 'JKspFU6ohf1Grg3Phdzj2pSgWvsYWzSfKghhfzMbdhNBWs5', - 'Fr4NzY1udSFFLzb2R3qxVQkwz9cZraWkyfH4h3mVVk7BK7P', - 'DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK', - 'HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam', - 'DE14BzQ1bDXWPKeLoAqdLAm1GpyAWaWF1knF74cEZeomTBM', - ]; - const collectionId = await createCollectionExpectSuccess(); - - const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN }; - const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber(); - expect(chainAdminLimit).to.be.equal(5); - - for (let i = 0; i < chainAdminLimit; i++) { - const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, accounts[i]); - await submitTransactionAsync(Alice, changeAdminTx); - const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); - expect(adminListAfterAddAdmin).to.be.contains(accounts[i]); - } - - const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainAdminLimit]); - await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected; - }); - }); -}); +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +import { ApiPromise } from '@polkadot/api'; +import BN from 'bn.js'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from './substrate/privateKey'; +import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api'; +import {createCollectionExpectSuccess, destroyCollectionExpectSuccess} from './util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => { + it('Add collection admin.', async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const alice = privateKey('//Alice'); + const bob = privateKey('//Bob'); + + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); + expect(collection.Owner.toString()).to.be.eq(alice.address); + + const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address); + await submitTransactionAsync(alice, changeAdminTx); + + const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); + expect(adminListAfterAddAdmin).to.be.contains(bob.address); + }); + }); + + it('Add admin using added collection admin.', async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const Charlie = privateKey('//CHARLIE'); + + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); + expect(collection.Owner.toString()).to.be.eq(Alice.address); + + const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address); + await submitTransactionAsync(Alice, changeAdminTx); + + const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); + expect(adminListAfterAddAdmin).to.be.contains(Bob.address); + + const changeAdminTxCharlie = api.tx.nft.addCollectionAdmin(collectionId, Charlie.address); + await submitTransactionAsync(Bob, changeAdminTxCharlie); + const adminListAfterAddNewAdmin: any = (await api.query.nft.adminList(collectionId)); + expect(adminListAfterAddNewAdmin).to.be.contains(Bob.address); + expect(adminListAfterAddNewAdmin).to.be.contains(Charlie.address); + }); + }); +}); + +describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => { + it("Not owner can't add collection admin.", async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const alice = privateKey('//Alice'); + const nonOwner = privateKey('//Bob_stash'); + + const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, alice.address); + await expect(submitTransactionExpectFailAsync(nonOwner, changeAdminTx)).to.be.rejected; + + const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); + expect(adminListAfterAddAdmin).not.to.be.contains(alice.address); + + // Verifying that nothing bad happened (network is live, new collections can be created, etc.) + await createCollectionExpectSuccess(); + }); + }); + it("Can't add collection admin of not existing collection.", async () => { + await usingApi(async (api) => { + // tslint:disable-next-line: no-bitwise + const collectionId = (1 << 32) - 1; + const alice = privateKey('//Alice'); + const bob = privateKey('//Bob'); + + const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address); + await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected; + + // Verifying that nothing bad happened (network is live, new collections can be created, etc.) + await createCollectionExpectSuccess(); + }); + }); + + it("Can't add an admin to a destroyed collection.", async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + await destroyCollectionExpectSuccess(collectionId); + const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address); + await expect(submitTransactionExpectFailAsync(Alice, changeOwnerTx)).to.be.rejected; + + // Verifying that nothing bad happened (network is live, new collections can be created, etc.) + await createCollectionExpectSuccess(); + }); + }); + + it('Add an admin to a collection that has reached the maximum number of admins limit', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const accounts = [ + 'GsvVmjr1CBHwQHw84pPHMDxgNY3iBLz6Qn7qS3CH8qPhrHz', + 'FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP', + 'JKspFU6ohf1Grg3Phdzj2pSgWvsYWzSfKghhfzMbdhNBWs5', + 'Fr4NzY1udSFFLzb2R3qxVQkwz9cZraWkyfH4h3mVVk7BK7P', + 'DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK', + 'HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam', + 'DE14BzQ1bDXWPKeLoAqdLAm1GpyAWaWF1knF74cEZeomTBM', + ]; + const collectionId = await createCollectionExpectSuccess(); + + const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN }; + const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber(); + expect(chainAdminLimit).to.be.equal(5); + + for (let i = 0; i < chainAdminLimit; i++) { + const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, accounts[i]); + await submitTransactionAsync(Alice, changeAdminTx); + const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId)); + expect(adminListAfterAddAdmin).to.be.contains(accounts[i]); + } + + const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainAdminLimit]); + await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected; + }); + }); +}); --- a/tests/src/approve.test.ts +++ b/tests/src/approve.test.ts @@ -14,19 +14,22 @@ createCollectionExpectSuccess, createItemExpectSuccess, destroyCollectionExpectSuccess, + setCollectionLimitsExpectSuccess, transferExpectSuccess, } from './util/helpers'; chai.use(chaiAsPromised); -let Alice: IKeyringPair; -let Bob: IKeyringPair; +describe('Integration Test approve(spender, collection_id, item_id, amount):', () => { + let Alice: IKeyringPair; + let Bob: IKeyringPair; + let Charlie: IKeyringPair; -describe.only('Integration Test approve(spender, collection_id, item_id, amount):', () => { before(async () => { await usingApi(async () => { Alice = privateKey('//Alice'); Bob = privateKey('//Bob'); + Charlie = privateKey('//Charlie'); }); }); @@ -64,13 +67,25 @@ await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 1); await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 0); }); + + it('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async () => { + const collectionId = await createCollectionExpectSuccess(); + const itemId = await createItemExpectSuccess(Alice, collectionId, 'NFT', Bob.address); + + await approveExpectSuccess(collectionId, itemId, Alice, Charlie); + }); }); -describe.only('Negative Integration Test approve(spender, collection_id, item_id, amount):', () => { +describe('Negative Integration Test approve(spender, collection_id, item_id, amount):', () => { + let Alice: IKeyringPair; + let Bob: IKeyringPair; + let Charlie: IKeyringPair; + before(async () => { await usingApi(async (api) => { Alice = privateKey('//Alice'); Bob = privateKey('//Bob'); + Charlie = privateKey('//Charlie'); }); }); @@ -108,9 +123,6 @@ // nft const nftCollectionId = await createCollectionExpectSuccess(); await approveExpectFail(nftCollectionId, 2, Alice, Bob); - // fungible - const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - await approveExpectFail(fungibleCollectionId, 2, Alice, Bob); // reFungible const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); @@ -156,4 +168,12 @@ await approveExpectSuccess(nftCollectionId, newNftTokenId, Bob, Alice, 10); await approveExpectFail(nftCollectionId, newNftTokenId, Bob, Alice, 1); }); + + it('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async () => { + const collectionId = await createCollectionExpectSuccess(); + const itemId = await createItemExpectSuccess(Alice, collectionId, 'NFT', Bob.address); + await setCollectionLimitsExpectSuccess(Alice, collectionId, { OwnerCanTransfer: false }); + + await approveExpectFail(collectionId, itemId, Alice, Charlie); + }); }); --- a/tests/src/burnItem.test.ts +++ b/tests/src/burnItem.test.ts @@ -46,8 +46,7 @@ // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.true; // tslint:disable-next-line:no-unused-expression - expect(item).to.be.not.null; - expect(item.Owner).to.be.equal(nullPublicKey); + expect(item).to.be.null; }); }); @@ -88,8 +87,7 @@ // What to expect expect(result.success).to.be.true; - expect(balance).to.be.not.null; - expect(balance.Owner.length).to.be.equal(0); + expect(balance).to.be.null; }); }); --- a/tests/src/change-collection-owner.test.ts +++ b/tests/src/change-collection-owner.test.ts @@ -19,13 +19,13 @@ const alice = privateKey('//Alice'); const bob = privateKey('//Bob'); - const collection: any = (await api.query.nft.collection(collectionId)); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); expect(collection.Owner.toString()).to.be.eq(alice.address); const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address); await submitTransactionAsync(alice, changeOwnerTx); - const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId)); + const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON(); expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(bob.address); }); }); @@ -41,7 +41,7 @@ const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address); await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected; - const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId)); + const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON(); expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(alice.address); // Verifying that nothing bad happened (network is live, new collections can be created, etc.) --- /dev/null +++ b/tests/src/check-event/burnItemEvent.test.ts @@ -0,0 +1,41 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits +import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from '../substrate/privateKey'; +import usingApi, {submitTransactionAsync} from '../substrate/substrate-api'; +import { createCollectionExpectSuccess, createItemExpectSuccess, nftEventMessage } from '../util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Burn Item event ', () => { + let Alice: IKeyringPair; + const checkSection = 'ItemDestroyed'; + const checkTreasury = 'Deposit'; + const checkSystem = 'ExtrinsicSuccess'; + before(async () => { + await usingApi(async () => { + Alice = privateKey('//Alice'); + }); + }); + it('Check event from burnItem(): ', async () => { + await usingApi(async (api: ApiPromise) => { + const collectionID = await createCollectionExpectSuccess(); + const itemID = await createItemExpectSuccess(Alice, collectionID, 'NFT'); + const burnItem = api.tx.nft.burnItem(collectionID, itemID, 1); + const events = await submitTransactionAsync(Alice, burnItem); + const msg = JSON.stringify(nftEventMessage(events)); + expect(msg).to.be.contain(checkSection); + expect(msg).to.be.contain(checkTreasury); + expect(msg).to.be.contain(checkSystem); + }); + }); +}); + --- /dev/null +++ b/tests/src/check-event/createCollectionEvent.test.ts @@ -0,0 +1,39 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits +import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from '../substrate/privateKey'; +import usingApi, {submitTransactionAsync} from '../substrate/substrate-api'; +import { nftEventMessage } from '../util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Create collection event ', () => { + let Alice: IKeyringPair; + const checkSection = 'CollectionCreated'; + const checkTreasury = 'Deposit'; + const checkSystem = 'ExtrinsicSuccess'; + before(async () => { + await usingApi(async () => { + Alice = privateKey('//Alice'); + }); + }); + it('Check event from createCollection(): ', async () => { + await usingApi(async (api: ApiPromise) => { + const tx = api.tx.nft.createCollection('0x31', '0x32', '0x33', 'NFT'); + const events = await submitTransactionAsync(Alice, tx); + const msg = JSON.stringify(nftEventMessage(events)); + expect(msg).to.be.contain(checkSection); + expect(msg).to.be.contain(checkTreasury); + expect(msg).to.be.contain(checkSystem); + }); + }); +}); + \ No newline at end of file --- /dev/null +++ b/tests/src/check-event/createItemEvent.test.ts @@ -0,0 +1,40 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits +import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from '../substrate/privateKey'; +import usingApi, {submitTransactionAsync} from '../substrate/substrate-api'; +import { createCollectionExpectSuccess, createItemExpectSuccess, nftEventMessage } from '../util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Create Item event ', () => { + let Alice: IKeyringPair; + const checkSection = 'ItemCreated'; + const checkTreasury = 'Deposit'; + const checkSystem = 'ExtrinsicSuccess'; + before(async () => { + await usingApi(async () => { + Alice = privateKey('//Alice'); + }); + }); + it('Check event from createItem(): ', async () => { + await usingApi(async (api: ApiPromise) => { + const collectionID = await createCollectionExpectSuccess(); + const createItem = api.tx.nft.createItem(collectionID, Alice.address, 'NFT'); + const events = await submitTransactionAsync(Alice, createItem); + const msg = JSON.stringify(nftEventMessage(events)); + expect(msg).to.be.contain(checkSection); + expect(msg).to.be.contain(checkTreasury); + expect(msg).to.be.contain(checkSystem); + }); + }); +}); + --- /dev/null +++ b/tests/src/check-event/createMultipleItemsEvent.test.ts @@ -0,0 +1,41 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits +import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from '../substrate/privateKey'; +import usingApi, {submitTransactionAsync} from '../substrate/substrate-api'; +import { createCollectionExpectSuccess, createItemExpectSuccess, nftEventMessage } from '../util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Create Multiple Items Event event ', () => { + let Alice: IKeyringPair; + const checkSection = 'ItemCreated (x3)'; + const checkTreasury = 'Deposit'; + const checkSystem = 'ExtrinsicSuccess'; + before(async () => { + await usingApi(async () => { + Alice = privateKey('//Alice'); + }); + }); + it('Check event from createMultipleItems(): ', async () => { + await usingApi(async (api: ApiPromise) => { + const collectionID = await createCollectionExpectSuccess(); + const args = [{ nft: ['0x31', '0x31'] }, { nft: ['0x32', '0x32'] }, { nft: ['0x33', '0x33'] }]; + const createMultipleItems = api.tx.nft.createMultipleItems(collectionID, Alice.address, args); + const events = await submitTransactionAsync(Alice, createMultipleItems); + const msg = JSON.stringify(nftEventMessage(events)); + expect(msg).to.be.contain(checkSection); + expect(msg).to.be.contain(checkTreasury); + expect(msg).to.be.contain(checkSystem); + }); + }); +}); + --- /dev/null +++ b/tests/src/check-event/destroyCollectionEvent.test.ts @@ -0,0 +1,38 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits +import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from '../substrate/privateKey'; +import usingApi, {submitTransactionAsync} from '../substrate/substrate-api'; +import { createCollectionExpectSuccess, nftEventMessage } from '../util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Destroy collection event ', () => { + let Alice: IKeyringPair; + const checkTreasury = 'Deposit'; + const checkSystem = 'ExtrinsicSuccess'; + before(async () => { + await usingApi(async () => { + Alice = privateKey('//Alice'); + }); + }); + it('Check event from destroyCollection(): ', async () => { + await usingApi(async (api: ApiPromise) => { + const collectionID = await createCollectionExpectSuccess(); + const destroyCollection = api.tx.nft.destroyCollection(collectionID); + const events = await submitTransactionAsync(Alice, destroyCollection); + const msg = JSON.stringify(nftEventMessage(events)); + expect(msg).to.be.contain(checkTreasury); + expect(msg).to.be.contain(checkSystem); + }); + }); +}); + --- /dev/null +++ b/tests/src/check-event/transferEvent.test.ts @@ -0,0 +1,44 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits +import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from '../substrate/privateKey'; +import usingApi, {submitTransactionAsync} from '../substrate/substrate-api'; +import { createCollectionExpectSuccess, createItemExpectSuccess, nftEventMessage } from '../util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Transfer event ', () => { + let Alice: IKeyringPair; + let Bob: IKeyringPair; + const checkSection = 'Transfer'; + const checkTreasury = 'Deposit'; + const checkSystem = 'ExtrinsicSuccess'; + before(async () => { + await usingApi(async () => { + Alice = privateKey('//Alice'); + Bob = privateKey('//Bob'); + }); + }); + it('Check event from transfer(): ', async () => { + await usingApi(async (api: ApiPromise) => { + const collectionID = await createCollectionExpectSuccess(); + const itemID = await createItemExpectSuccess(Alice, collectionID, 'NFT'); + const transfer = api.tx.nft.transfer(Bob.address, collectionID, itemID, 1); + const events = await submitTransactionAsync(Alice, transfer); + const msg = JSON.stringify(nftEventMessage(events)); + expect(msg).to.be.contain(checkSection); + expect(msg).to.be.contain(checkTreasury); + expect(msg).to.be.contain(checkSystem); + }); + }); +}); + + --- /dev/null +++ b/tests/src/check-event/transferFromEvent.test.ts @@ -0,0 +1,43 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits +import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from '../substrate/privateKey'; +import usingApi, {submitTransactionAsync} from '../substrate/substrate-api'; +import { createCollectionExpectSuccess, createItemExpectSuccess, nftEventMessage } from '../util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Transfer from event ', () => { + let Alice: IKeyringPair; + let Bob: IKeyringPair; + const checkSection = 'Transfer'; + const checkTreasury = 'Deposit'; + const checkSystem = 'ExtrinsicSuccess'; + before(async () => { + await usingApi(async () => { + Alice = privateKey('//Alice'); + Bob = privateKey('//Bob'); + }); + }); + it('Check event from transferFrom(): ', async () => { + await usingApi(async (api: ApiPromise) => { + const collectionID = await createCollectionExpectSuccess(); + const itemID = await createItemExpectSuccess(Alice, collectionID, 'NFT'); + const transferFrom = api.tx.nft.transferFrom(Alice.address, Bob.address, collectionID, itemID, 1); + const events = await submitTransactionAsync(Alice, transferFrom); + const msg = JSON.stringify(nftEventMessage(events)); + expect(msg).to.be.contain(checkSection); + expect(msg).to.be.contain(checkTreasury); + expect(msg).to.be.contain(checkSystem); + }); + }); +}); + --- /dev/null +++ b/tests/src/config_docker.ts @@ -0,0 +1,12 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +import process from 'process'; + +const config = { + substrateUrl: process.env.substrateUrl || 'ws://172.17.0.1:9944' +} + +export default config; \ No newline at end of file --- a/tests/src/contracts.test.ts +++ b/tests/src/contracts.test.ts @@ -63,13 +63,13 @@ const collectionId = await createCollectionExpectSuccess(); const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT'); const [contract, deployer] = await deployTransferContract(api); - const tokenBefore: any = await api.query.nft.nftItemList(collectionId, tokenId); + const tokenBefore: any = (await api.query.nft.nftItemList(collectionId, tokenId) as any).unwrap(); // Transfer const transferTx = contract.tx.transfer(value, gasLimit, bob.address, collectionId, tokenId, 1); const events = await submitTransactionAsync(alice, transferTx); const result = getGenericResult(events); - const tokenAfter: any = await api.query.nft.nftItemList(collectionId, tokenId); + const tokenAfter: any = (await api.query.nft.nftItemList(collectionId, tokenId) as any).unwrap(); // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.true; --- a/tests/src/createCollection.test.ts +++ b/tests/src/createCollection.test.ts @@ -1,59 +1,59 @@ -// -// This file is subject to the terms and conditions defined in -// file 'LICENSE', which is part of this source code package. -// - -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { default as usingApi } from './substrate/substrate-api'; -import { createCollectionExpectFailure, createCollectionExpectSuccess } from './util/helpers'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -describe('integration test: ext. createCollection():', () => { - it('Create new NFT collection', async () => { - await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); - }); - it('Create new NFT collection whith collection_name of maximum length (64 bytes)', async () => { - await createCollectionExpectSuccess({name: 'A'.repeat(64)}); - }); - it('Create new NFT collection whith collection_description of maximum length (256 bytes)', async () => { - await createCollectionExpectSuccess({description: 'A'.repeat(256)}); - }); - it('Create new NFT collection whith token_prefix of maximum length (16 bytes)', async () => { - await createCollectionExpectSuccess({tokenPrefix: 'A'.repeat(16)}); - }); - it('Create new Fungible collection', async () => { - await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - }); - it('Create new ReFungible collection', async () => { - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - }); -}); - -describe('(!negative test!) integration test: ext. createCollection():', () => { - it('(!negative test!) create new NFT collection whith incorrect data (mode)', async () => { - await usingApi(async (api) => { - const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString(), 10); - - const badTransaction = async () => { - await createCollectionExpectSuccess({mode: {type: 'Invalid'}}); - }; - // tslint:disable-next-line:no-unused-expression - expect(badTransaction()).to.be.rejected; - - const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString(), 10); - expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Incorrect collection created.'); - }); - }); - it('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async () => { - await createCollectionExpectFailure({ name: 'A'.repeat(65), mode: {type: 'NFT'}}); - }); - it('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async () => { - await createCollectionExpectFailure({ description: 'A'.repeat(257), mode: { type: 'NFT' }}); - }); - it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => { - await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17), mode: {type: 'NFT'}}); - }); -}); +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import { default as usingApi } from './substrate/substrate-api'; +import { createCollectionExpectFailure, createCollectionExpectSuccess } from './util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('integration test: ext. createCollection():', () => { + it('Create new NFT collection', async () => { + await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); + }); + it('Create new NFT collection whith collection_name of maximum length (64 bytes)', async () => { + await createCollectionExpectSuccess({name: 'A'.repeat(64)}); + }); + it('Create new NFT collection whith collection_description of maximum length (256 bytes)', async () => { + await createCollectionExpectSuccess({description: 'A'.repeat(256)}); + }); + it('Create new NFT collection whith token_prefix of maximum length (16 bytes)', async () => { + await createCollectionExpectSuccess({tokenPrefix: 'A'.repeat(16)}); + }); + it('Create new Fungible collection', async () => { + await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + }); + it('Create new ReFungible collection', async () => { + await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); + }); +}); + +describe('(!negative test!) integration test: ext. createCollection():', () => { + it('(!negative test!) create new NFT collection whith incorrect data (mode)', async () => { + await usingApi(async (api) => { + const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10); + + const badTransaction = async () => { + await createCollectionExpectSuccess({mode: {type: 'Invalid'}}); + }; + // tslint:disable-next-line:no-unused-expression + expect(badTransaction()).to.be.rejected; + + const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10); + expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Incorrect collection created.'); + }); + }); + it('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async () => { + await createCollectionExpectFailure({ name: 'A'.repeat(65), mode: {type: 'NFT'}}); + }); + it('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async () => { + await createCollectionExpectFailure({ description: 'A'.repeat(257), mode: { type: 'NFT' }}); + }); + it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => { + await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17), mode: {type: 'NFT'}}); + }); +}); --- a/tests/src/createMultipleItems.test.ts +++ b/tests/src/createMultipleItems.test.ts @@ -11,7 +11,9 @@ import { createCollectionExpectSuccess, destroyCollectionExpectSuccess, + getGenericResult, IReFungibleTokenDataType, + setCollectionLimitsExpectSuccess, } from './util/helpers'; chai.use(chaiAsPromised); @@ -36,9 +38,9 @@ await submitTransactionAsync(Alice, createMultipleItemsTx); const itemsListIndexAfter = await api.query.nft.itemListIndex(collectionId) as unknown as BN; expect(itemsListIndexAfter.toNumber()).to.be.equal(3); - const token1Data = await api.query.nft.nftItemList(collectionId, 1) as unknown as ITokenDataType; - const token2Data = await api.query.nft.nftItemList(collectionId, 2) as unknown as ITokenDataType; - const token3Data = await api.query.nft.nftItemList(collectionId, 3) as unknown as ITokenDataType; + const token1Data = (await api.query.nft.nftItemList(collectionId, 1)).toJSON() as unknown as ITokenDataType; + const token2Data = (await api.query.nft.nftItemList(collectionId, 2)).toJSON() as unknown as ITokenDataType; + const token3Data = (await api.query.nft.nftItemList(collectionId, 3)).toJSON() as unknown as ITokenDataType; expect(token1Data.Owner.toString()).to.be.equal(Alice.address); expect(token2Data.Owner.toString()).to.be.equal(Alice.address); @@ -70,9 +72,9 @@ await submitTransactionAsync(Alice, createMultipleItemsTx); const itemsListIndexAfter = await api.query.nft.itemListIndex(collectionId) as unknown as BN; expect(itemsListIndexAfter.toNumber()).to.be.equal(3); - const token1Data = await api.query.nft.reFungibleItemList(collectionId, 1) as unknown as IReFungibleTokenDataType; - const token2Data = await api.query.nft.reFungibleItemList(collectionId, 2) as unknown as IReFungibleTokenDataType; - const token3Data = await api.query.nft.reFungibleItemList(collectionId, 3) as unknown as IReFungibleTokenDataType; + const token1Data = (await api.query.nft.reFungibleItemList(collectionId, 1) as any).unwrap() as unknown as IReFungibleTokenDataType; + const token2Data = (await api.query.nft.reFungibleItemList(collectionId, 2) as any).unwrap() as unknown as IReFungibleTokenDataType; + const token3Data = (await api.query.nft.reFungibleItemList(collectionId, 3) as any).unwrap() as unknown as IReFungibleTokenDataType; expect(token1Data.Owner[0].Owner.toString()).to.be.equal(Alice.address); expect(token1Data.Owner[0].Fraction.toNumber()).to.be.equal(1); @@ -92,6 +94,25 @@ expect(token3Data.VariableData.toString()).to.be.equal('0x33'); }); }); + + it('Can mint amount of items equals to collection limits', async () => { + await usingApi(async (api) => { + const alice = privateKey('//Alice'); + + const collectionId = await createCollectionExpectSuccess(); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + TokenLimit: 2, + }); + const args = [ + { nft: ['A', 'A'] }, + { nft: ['B', 'B'] }, + ]; + const createMultipleItemsTx = api.tx.nft.createMultipleItems(collectionId, alice.address, args); + const events = await submitTransactionAsync(alice, createMultipleItemsTx); + const result = getGenericResult(events); + expect(result.success).to.be.true; + }); + }); }); describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => { @@ -175,4 +196,21 @@ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTx)).to.be.rejected; }); }); + + it('Fails when minting tokens exceeds collectionLimits amount', async () => { + await usingApi(async (api) => { + const alice = privateKey('//Alice'); + + const collectionId = await createCollectionExpectSuccess(); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + TokenLimit: 1, + }); + const args = [ + { nft: ['A', 'A'] }, + { nft: ['B', 'B'] }, + ]; + const createMultipleItemsTx = api.tx.nft.createMultipleItems(collectionId, alice.address, args); + await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected; + }); + }); }); --- a/tests/src/creditFeesToTreasury.test.ts +++ b/tests/src/creditFeesToTreasury.test.ts @@ -25,6 +25,7 @@ const Treasury = "5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z"; const saneMinimumFee = 0.05; const saneMaximumFee = 0.5; +const createCollectionDeposit = 100; let alice: IKeyringPair; let bob: IKeyringPair; @@ -127,8 +128,8 @@ const aliceBalanceAfter = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString()); const fee = aliceBalanceBefore.minus(aliceBalanceAfter); - expect(fee.dividedBy(1e15).toNumber()).to.be.lessThan(saneMaximumFee); - expect(fee.dividedBy(1e15).toNumber()).to.be.greaterThan(saneMinimumFee); + expect(fee.dividedBy(1e15).toNumber()).to.be.lessThan(saneMaximumFee + createCollectionDeposit); + expect(fee.dividedBy(1e15).toNumber()).to.be.greaterThan(saneMinimumFee + createCollectionDeposit); }); }); --- a/tests/src/destroyCollection.test.ts +++ b/tests/src/destroyCollection.test.ts @@ -3,10 +3,12 @@ // file 'LICENSE', which is part of this source code package. // +import { IKeyringPair } from '@polkadot/types/types'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; +import privateKey from './substrate/privateKey'; import { default as usingApi } from "./substrate/substrate-api"; -import { createCollectionExpectSuccess, destroyCollectionExpectSuccess, destroyCollectionExpectFailure } from "./util/helpers"; +import { createCollectionExpectSuccess, destroyCollectionExpectSuccess, destroyCollectionExpectFailure, setCollectionLimitsExpectSuccess } from "./util/helpers"; chai.use(chaiAsPromised); @@ -26,6 +28,14 @@ }); describe('(!negative test!) integration test: ext. destroyCollection():', () => { + let alice: IKeyringPair; + + before(async () => { + await usingApi(async (api) => { + alice = privateKey('//Alice'); + }); + }); + it('(!negative test!) Destroy a collection that never existed', async () => { await usingApi(async (api) => { // Find the collection that never existed @@ -43,4 +53,10 @@ await destroyCollectionExpectFailure(collectionId, '//Bob'); await destroyCollectionExpectSuccess(collectionId, '//Alice'); }); + it('fails when OwnerCanDestroy == false', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionLimitsExpectSuccess(alice, collectionId, { OwnerCanDestroy: false }); + + await destroyCollectionExpectFailure(collectionId, '//Alice'); + }); }); --- a/tests/src/removeCollectionAdmin.test.ts +++ b/tests/src/removeCollectionAdmin.test.ts @@ -19,7 +19,7 @@ const collectionId = await createCollectionExpectSuccess(); const Alice = privateKey('//Alice'); const Bob = privateKey('//Bob'); - const collection: any = (await api.query.nft.collection(collectionId)); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); expect(collection.Owner.toString()).to.be.eq(Alice.address); // first - add collection admin Bob const addAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address); @@ -36,6 +36,19 @@ expect(adminListAfterRemoveAdmin).not.to.be.contains(Bob.address); }); }); + + it('Remove admin from collection that has no admins', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const collectionId = await createCollectionExpectSuccess(); + + const adminListBeforeAddAdmin: any = (await api.query.nft.adminList(collectionId)); + expect(adminListBeforeAddAdmin).to.have.lengthOf(0); + + const tx = api.tx.nft.removeCollectionAdmin(collectionId, Alice.address); + await submitTransactionAsync(Alice, tx); + }); + }); }); describe('Negative Integration Test removeCollectionAdmin(collection_id, account_id):', () => { @@ -68,19 +81,6 @@ // Verifying that nothing bad happened (network is live, new collections can be created, etc.) await createCollectionExpectSuccess(); - }); - }); - - it('Remove admin from collection that has no admins', async () => { - await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const collectionId = await createCollectionExpectSuccess(); - - const adminListBeforeAddAdmin: any = (await api.query.nft.adminList(collectionId)); - expect(adminListBeforeAddAdmin).to.have.lengthOf(0); - - const tx = api.tx.nft.removeCollectionAdmin(collectionId, Alice.address); - await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected; }); }); }); --- a/tests/src/removeFromContractWhiteList.test.ts +++ b/tests/src/removeFromContractWhiteList.test.ts @@ -13,8 +13,10 @@ describe('Integration Test removeFromContractWhiteList', () => { let bob: IKeyringPair; - before(() => { - bob = privateKey('//Bob'); + before(async () => { + await usingApi(async () => { + bob = privateKey('//Bob'); + }); }); it('user is no longer whitelisted after removal', async () => { @@ -56,9 +58,11 @@ let alice: IKeyringPair; let bob: IKeyringPair; - before(() => { - alice = privateKey('//Alice'); - bob = privateKey('//Bob'); + before(async () => { + await usingApi(async () => { + alice = privateKey('//Alice'); + bob = privateKey('//Bob'); + }); }); it('fails when called with non-contract address', async () => { --- a/tests/src/rpc.load.ts +++ b/tests/src/rpc.load.ts @@ -110,7 +110,7 @@ }); }); - it.only('Smart Contract RPC Load Test', async () => { + it('Smart Contract RPC Load Test', async () => { await usingApi(async api => { // Deploy smart contract --- a/tests/src/setCollectionLimits.test.ts +++ b/tests/src/setCollectionLimits.test.ts @@ -14,6 +14,8 @@ createCollectionExpectSuccess, getCreatedCollectionCount, getCreateItemResult, getDetailedCollectionInfo, + setCollectionLimitsExpectFailure, + setCollectionLimitsExpectSuccess, } from './util/helpers'; chai.use(chaiAsPromised); @@ -26,21 +28,8 @@ const accountTokenOwnershipLimit = 0; const sponsoredDataSize = 0; const sponsoredMintSize = 0; -const tokenLimit = 0; - -describe('hooks', () => { - before(async () => { - await usingApi(async () => { - const keyring = new Keyring({ type: 'sr25519' }); - alice = keyring.addFromUri('//Alice'); - }); - }); - it('choose or create collection for testing', async () => { - await usingApi(async () => { - collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); - }); - }); -}); +const sponsorTimeout = 1; +const tokenLimit = 1; describe('setCollectionLimits positive', () => { let tx; @@ -48,6 +37,7 @@ await usingApi(async () => { const keyring = new Keyring({ type: 'sr25519' }); alice = keyring.addFromUri('//Alice'); + collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); }); }); it('execute setCollectionLimits with predefined params ', async () => { @@ -55,25 +45,28 @@ tx = api.tx.nft.setCollectionLimits( collectionIdForTesting, { - accountTokenOwnershipLimit, - sponsoredDataSize, - sponsoredMintSize, - tokenLimit, + AccountTokenOwnershipLimit: accountTokenOwnershipLimit, + SponsoredMintSize: sponsoredDataSize, + TokenLimit: tokenLimit, + SponsorTimeout: sponsorTimeout, + OwnerCanTransfer: true, + OwnerCanDestroy: true }, ); const events = await submitTransactionAsync(alice, tx); const result = getCreateItemResult(events); + + // get collection limits defined previously + const collectionInfo = await getDetailedCollectionInfo(api, collectionIdForTesting) as ICollectionInterface; + // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.true; - }); - }); - it('get collection limits defined in previous test', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionInfo = await getDetailedCollectionInfo(api, collectionIdForTesting) as ICollectionInterface; - expect(collectionInfo.Limits.AccountTokenOwnershipLimit.toNumber()).to.be.equal(accountTokenOwnershipLimit); - expect(collectionInfo.Limits.SponsoredMintSize.toNumber()).to.be.equal(sponsoredMintSize); - expect(collectionInfo.Limits.TokenLimit.toNumber()).to.be.equal(tokenLimit); - expect(collectionInfo.Limits.SponsorTimeout.toNumber()).to.be.equal(sponsoredDataSize); + expect(collectionInfo.Limits.AccountTokenOwnershipLimit).to.be.equal(accountTokenOwnershipLimit); + expect(collectionInfo.Limits.SponsoredDataSize).to.be.equal(sponsoredDataSize); + expect(collectionInfo.Limits.TokenLimit).to.be.equal(tokenLimit); + expect(collectionInfo.Limits.SponsorTimeout).to.be.equal(sponsorTimeout); + expect(collectionInfo.Limits.OwnerCanTransfer).to.be.true; + expect(collectionInfo.Limits.OwnerCanDestroy).to.be.true; }); }); }); @@ -85,6 +78,7 @@ const keyring = new Keyring({ type: 'sr25519' }); alice = keyring.addFromUri('//Alice'); bob = keyring.addFromUri('//Bob'); + collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); }); }); it('execute setCollectionLimits for not exists collection', async () => { @@ -131,4 +125,44 @@ await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected; }); }); + + it('fails when trying to enable OwnerCanTransfer after it was disabled', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + AccountTokenOwnershipLimit: accountTokenOwnershipLimit, + SponsoredMintSize: sponsoredDataSize, + TokenLimit: tokenLimit, + SponsorTimeout: sponsorTimeout, + OwnerCanTransfer: false, + OwnerCanDestroy: true + }); + await setCollectionLimitsExpectFailure(alice, collectionId, { + AccountTokenOwnershipLimit: accountTokenOwnershipLimit, + SponsoredMintSize: sponsoredDataSize, + TokenLimit: tokenLimit, + SponsorTimeout: sponsorTimeout, + OwnerCanTransfer: true, + OwnerCanDestroy: true + }); + }); + + it('fails when trying to enable OwnerCanDestroy after it was disabled', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + AccountTokenOwnershipLimit: accountTokenOwnershipLimit, + SponsoredMintSize: sponsoredDataSize, + TokenLimit: tokenLimit, + SponsorTimeout: sponsorTimeout, + OwnerCanTransfer: true, + OwnerCanDestroy: false + }); + await setCollectionLimitsExpectFailure(alice, collectionId, { + AccountTokenOwnershipLimit: accountTokenOwnershipLimit, + SponsoredMintSize: sponsoredDataSize, + TokenLimit: tokenLimit, + SponsorTimeout: sponsorTimeout, + OwnerCanTransfer: true, + OwnerCanDestroy: true + }); + }); }); --- a/tests/src/setConstOnChainSchema.test.ts +++ b/tests/src/setConstOnChainSchema.test.ts @@ -36,7 +36,7 @@ it('Run extrinsic with parameters of the collection id, set the scheme', async () => { await usingApi(async (api) => { const collectionId = await createCollectionExpectSuccess(); - const collection: any = (await api.query.nft.collection(collectionId)); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); expect(collection.Owner.toString()).to.be.eq(Alice.address); const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema); await submitTransactionAsync(Alice, setShema); @@ -48,7 +48,7 @@ const collectionId = await createCollectionExpectSuccess(); const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema); await submitTransactionAsync(Alice, setShema); - const collection: any = (await api.query.nft.collection(collectionId)); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); expect(collection.ConstOnChainSchema.toString()).to.be.eq(Shema); }); @@ -86,7 +86,7 @@ it('Execute method not on behalf of the collection owner', async () => { await usingApi(async (api) => { const collectionId = await createCollectionExpectSuccess(); - const collection: any = (await api.query.nft.collection(collectionId)); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); expect(collection.Owner.toString()).to.be.eq(Alice.address); const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema); await expect(submitTransactionExpectFailAsync(Bob, setShema)).to.be.rejected; --- a/tests/src/setOffchainSchema.test.ts +++ b/tests/src/setOffchainSchema.test.ts @@ -36,7 +36,7 @@ await setOffchainSchemaExpectSuccess(alice, collectionId, DATA); const collection = await queryCollectionExpectSuccess(collectionId); - expect(Array.from(collection.OffchainSchema)).to.be.deep.equal(DATA); + expect(collection.OffchainSchema).to.be.equal('0x' + Buffer.from(DATA).toString('hex')); }); }); --- a/tests/src/setVariableMetaData.test.ts +++ b/tests/src/setVariableMetaData.test.ts @@ -41,7 +41,7 @@ it('verify data was set', async () => { await usingApi(async api => { - const item: any = await api.query.nft.nftItemList(collectionId, tokenId); + const item: any = (await api.query.nft.nftItemList(collectionId, tokenId) as any).unwrap(); expect(Array.from(item.VariableData)).to.deep.equal(Array.from(data)); }); --- /dev/null +++ b/tests/src/setVariableMetadataSponsoringRateLimit.test.ts @@ -0,0 +1,80 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +import { IKeyringPair } from '@polkadot/types/types'; +import privateKey from './substrate/privateKey'; +import usingApi from './substrate/substrate-api'; +import { + confirmSponsorshipExpectSuccess, + createCollectionExpectSuccess, + createItemExpectSuccess, + findUnusedAddress, + setCollectionLimitsExpectSuccess, + setCollectionSponsorExpectSuccess, + setVariableMetaDataExpectFailure, + setVariableMetaDataExpectSuccess, +} from './util/helpers'; + +describe('Integration Test setVariableMetadataSponsoringRateLimit', () => { + let alice: IKeyringPair; + let userWithNoBalance: IKeyringPair; + + before(async () => { + await usingApi(async (api) => { + alice = privateKey('//Alice'); + userWithNoBalance = await findUnusedAddress(api); + }); + }); + + it('sponsored setVariableMetaData can be called twice with pause for free', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionSponsorExpectSuccess(collectionId, alice.address); + await confirmSponsorshipExpectSuccess(collectionId); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + SponsoredDataRateLimit: 0, + }); + + const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address); + await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]); + await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]); + }); + + it('sponsored setVariableMetaData can\'t be called twice without pause for free', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionSponsorExpectSuccess(collectionId, alice.address); + await confirmSponsorshipExpectSuccess(collectionId); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + SponsoredDataRateLimit: 10, + }); + + const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address); + await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]); + await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2, 3]); + }); + + it('sponsored setVariableMetaData can\'t be called for free with variable metadata above collection limits', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionSponsorExpectSuccess(collectionId, alice.address); + await confirmSponsorshipExpectSuccess(collectionId); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + SponsoredDataRateLimit: 0, + SponsoredDataSize: 1, + }); + const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address); + + await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1]); + await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2]); + }); + + it('Default value of rate limit does not sponsor setting variable metadata', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionSponsorExpectSuccess(collectionId, alice.address); + await confirmSponsorshipExpectSuccess(collectionId); + + const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address); + await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1]); + }); + +}); --- a/tests/src/setVariableOnChainSchema.test.ts +++ b/tests/src/setVariableOnChainSchema.test.ts @@ -1,96 +1,96 @@ -// -// This file is subject to the terms and conditions defined in -// file 'LICENSE', which is part of this source code package. -// - -import { Keyring } from '@polkadot/api'; -import { IKeyringPair } from '@polkadot/types/types'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api'; -import { - createCollectionExpectSuccess, - destroyCollectionExpectSuccess, -} from './util/helpers'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -let Alice: IKeyringPair; -let Bob: IKeyringPair; -let Schema: any; -let largeSchema: any; - -before(async () => { - await usingApi(async (api) => { - const keyring = new Keyring({ type: 'sr25519' }); - Alice = keyring.addFromUri('//Alice'); - Bob = keyring.addFromUri('//Bob'); - Schema = '0x31'; - largeSchema = new Array(4097).fill(0xff); - - }); -}); -describe('Integration Test ext. setVariableOnChainSchema()', () => { - - it('Run extrinsic with parameters of the collection id, set the scheme', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const collection: any = (await api.query.nft.collection(collectionId)); - expect(collection.Owner.toString()).to.be.eq(Alice.address); - const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); - await submitTransactionAsync(Alice, setSchema); - }); - }); - - it('Checking collection data using the setVariableOnChainSchema parameter', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); - await submitTransactionAsync(Alice, setSchema); - const collection: any = (await api.query.nft.collection(collectionId)); - expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema); - - }); - }); -}); - -describe('Negative Integration Test ext. setVariableOnChainSchema()', () => { - - it('Set a non-existent collection', async () => { - await usingApi(async (api) => { - // tslint:disable-next-line: radix - const collectionId = parseInt((await api.query.nft.createdCollectionCount()).toString()) + 1; - const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); - await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected; - }); - }); - - it('Set a previously deleted collection', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - await destroyCollectionExpectSuccess(collectionId); - const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); - await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected; - }); - }); - - it('Set invalid data in schema (size too large:> 1024b)', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, largeSchema); - await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected; - }); - }); - - it('Execute method not on behalf of the collection owner', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - const collection: any = (await api.query.nft.collection(collectionId)); - expect(collection.Owner.toString()).to.be.eq(Alice.address); - const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); - await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected; - }); - }); - -}); +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +import { Keyring } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api'; +import { + createCollectionExpectSuccess, + destroyCollectionExpectSuccess, +} from './util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +let Alice: IKeyringPair; +let Bob: IKeyringPair; +let Schema: any; +let largeSchema: any; + +before(async () => { + await usingApi(async (api) => { + const keyring = new Keyring({ type: 'sr25519' }); + Alice = keyring.addFromUri('//Alice'); + Bob = keyring.addFromUri('//Bob'); + Schema = '0x31'; + largeSchema = new Array(4097).fill(0xff); + + }); +}); +describe('Integration Test ext. setVariableOnChainSchema()', () => { + + it('Run extrinsic with parameters of the collection id, set the scheme', async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); + expect(collection.Owner.toString()).to.be.eq(Alice.address); + const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); + await submitTransactionAsync(Alice, setSchema); + }); + }); + + it('Checking collection data using the setVariableOnChainSchema parameter', async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); + await submitTransactionAsync(Alice, setSchema); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); + expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema); + + }); + }); +}); + +describe('Negative Integration Test ext. setVariableOnChainSchema()', () => { + + it('Set a non-existent collection', async () => { + await usingApi(async (api) => { + // tslint:disable-next-line: radix + const collectionId = parseInt((await api.query.nft.createdCollectionCount()).toString()) + 1; + const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); + await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected; + }); + }); + + it('Set a previously deleted collection', async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + await destroyCollectionExpectSuccess(collectionId); + const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); + await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected; + }); + }); + + it('Set invalid data in schema (size too large:> 1024b)', async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, largeSchema); + await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected; + }); + }); + + it('Execute method not on behalf of the collection owner', async () => { + await usingApi(async (api) => { + const collectionId = await createCollectionExpectSuccess(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); + expect(collection.Owner.toString()).to.be.eq(Alice.address); + const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); + await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected; + }); + }); + +}); --- a/tests/src/transferFrom.test.ts +++ b/tests/src/transferFrom.test.ts @@ -3,6 +3,7 @@ // file 'LICENSE', which is part of this source code package. // import { ApiPromise } from '@polkadot/api'; +import { IKeyringPair } from '@polkadot/types/types'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; import privateKey from './substrate/privateKey'; @@ -18,17 +19,27 @@ transferFromExpectFail, transferFromExpectSuccess, burnItemExpectSuccess, + setCollectionLimitsExpectSuccess, } from './util/helpers'; chai.use(chaiAsPromised); const expect = chai.expect; describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => { + let Alice: IKeyringPair; + let Bob: IKeyringPair; + let Charlie: IKeyringPair; + + before(async () => { + await usingApi(async (api) => { + Alice = privateKey('//Alice'); + Bob = privateKey('//Bob'); + Charlie = privateKey('//Charlie'); + }); + }); + it('Execute the extrinsic and check nftItemList - owner of token', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); // nft const nftCollectionId = await createCollectionExpectSuccess(); const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); @@ -66,14 +77,30 @@ expect((await getAllowance(fungibleCollectionId, newFungibleTokenId, alice.address, bob.address)).toString()).to.equal('0'); }); }); + + it('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async () => { + const collectionId = await createCollectionExpectSuccess(); + const itemId = await createItemExpectSuccess(Alice, collectionId, 'NFT', Bob.address); + + await transferFromExpectSuccess(collectionId, itemId, Alice, Bob, Charlie); + }); }); describe('Negative Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => { + let Alice: IKeyringPair; + let Bob: IKeyringPair; + let Charlie: IKeyringPair; + + before(async () => { + await usingApi(async (api) => { + Alice = privateKey('//Alice'); + Bob = privateKey('//Bob'); + Charlie = privateKey('//Charlie'); + }); + }); + it('transferFrom for a collection that does not exist', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); // nft const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number; await approveExpectFail(nftCollectionCount + 1, 1, Alice, Bob); @@ -113,9 +140,6 @@ it('transferFrom for not approved address', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); // nft const nftCollectionId = await createCollectionExpectSuccess(); const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); @@ -137,9 +161,6 @@ it('transferFrom incorrect token count', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); // nft const nftCollectionId = await createCollectionExpectSuccess(); const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); @@ -164,9 +185,6 @@ it('execute transferFrom from account that is not owner of collection', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); const Dave = privateKey('//Dave'); // nft const nftCollectionId = await createCollectionExpectSuccess(); @@ -206,9 +224,6 @@ }); it( 'transferFrom burnt token before approve NFT', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); // nft const nftCollectionId = await createCollectionExpectSuccess(); const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); @@ -219,22 +234,16 @@ }); it( 'transferFrom burnt token before approve Fungible', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); await burnItemExpectSuccess(Alice, fungibleCollectionId, 1, 10); - await approveExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob); + await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob); await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1); }); }); it( 'transferFrom burnt token before approve ReFungible', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1); @@ -246,9 +255,6 @@ it( 'transferFrom burnt token after approve NFT', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); // nft const nftCollectionId = await createCollectionExpectSuccess(); const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); @@ -259,9 +265,6 @@ }); it( 'transferFrom burnt token after approve Fungible', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob); @@ -272,9 +275,6 @@ }); it( 'transferFrom burnt token after approve ReFungible', async () => { await usingApi(async (api: ApiPromise) => { - const Alice = privateKey('//Alice'); - const Bob = privateKey('//Bob'); - const Charlie = privateKey('//Charlie'); const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob); @@ -282,5 +282,13 @@ await transferFromExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice, Charlie, 1); }); - }); + }); + + it('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async () => { + const collectionId = await createCollectionExpectSuccess(); + const itemId = await createItemExpectSuccess(Alice, collectionId, 'NFT', Bob.address); + await setCollectionLimitsExpectSuccess(Alice, collectionId, { OwnerCanTransfer: false }); + + await transferFromExpectFail(collectionId, itemId, Alice, Bob, Charlie); + }); }); --- a/tests/src/types.ts +++ b/tests/src/types.ts @@ -13,10 +13,13 @@ Description: [BN, BN]; // utf16 isReFungible: boolean; Limits: { - AccountTokenOwnershipLimit: BN; - SponsoredMintSize: BN; - TokenLimit: BN; - SponsorTimeout: BN; + AccountTokenOwnershipLimit: number; + SponsoredDataSize: number; + SponsoredDataRateLimit?: number, + TokenLimit: number; + SponsorTimeout: number; + OwnerCanTransfer: boolean; + OwnerCanDestroy: boolean; }; MintMode: boolean; Mode: { --- a/tests/src/util/contracthelpers.ts +++ b/tests/src/util/contracthelpers.ts @@ -20,35 +20,20 @@ const gasLimit = '200000000000'; const endowment = '100000000000000000'; -function deployBlueprint(alice: IKeyringPair, code: CodePromise): Promise { - return new Promise(async (resolve, reject) => { - const unsub = await code - .createBlueprint() - .signAndSend(alice, (result) => { +function deployContract(alice: IKeyringPair, code: CodePromise, constructor: string = 'default', ...args: any[]): Promise { + return new Promise(async (resolve, reject) => { + const unsub = await (code as any) + .tx[constructor]({value: endowment, gasLimit}, ...args) + .signAndSend(alice, (result: any) => { if (result.status.isInBlock || result.status.isFinalized) { // here we have an additional field in the result, containing the blueprint - resolve(result.blueprint); + resolve((result as any).contract); unsub(); } }) }); } - -function deployContract(alice: IKeyringPair, blueprint: Blueprint) : Promise { - return new Promise(async (resolve, reject) => { - const initValue = true; - const unsub = await blueprint.tx - .new(endowment, gasLimit, initValue) - .signAndSend(alice, (result) => { - if (result.status.isInBlock || result.status.isFinalized) { - unsub(); - resolve(result); - } - }); - }); -} - async function prepareDeployer(api: ApiPromise) { // Find unused address const deployer = await findUnusedAddress(api); @@ -74,8 +59,7 @@ const code = new CodePromise(api, abi, wasm); - const blueprint = await deployBlueprint(deployer, code); - const contract = (await deployContract(deployer, blueprint))['contract'] as Contract; + const contract = (await deployContract(deployer, code, 'new', true)) as Contract; const initialGetResponse = await getFlipValue(contract, deployer); expect(initialGetResponse).to.be.true; @@ -128,8 +112,7 @@ const code = new CodePromise(api, abi, wasm); - const blueprint = await deployBlueprint(deployer, code); - const contract = (await instantiateTransferContract(deployer, blueprint))['contract'] as Contract; + const contract = await deployContract(deployer, code); return [contract, deployer]; } --- a/tests/src/util/helpers.ts +++ b/tests/src/util/helpers.ts @@ -63,12 +63,39 @@ Value: BN; } +interface IGetMessage { + checkMsgNftMethod: string; + checkMsgTrsMethod: string; + checkMsgSysMethod: string; +} + export interface IReFungibleTokenDataType { Owner: IReFungibleOwner[]; ConstData: number[]; VariableData: number[]; } +export function nftEventMessage(events: EventRecord[]): IGetMessage { + let checkMsgNftMethod: string = ''; + let checkMsgTrsMethod: string = ''; + let checkMsgSysMethod: string = ''; + events.forEach(({ event: { method, section } }) => { + if (section === 'nft') { + checkMsgNftMethod = method; + } else if (section === 'treasury') { + checkMsgTrsMethod = method; + } else if (section === 'system') { + checkMsgSysMethod = method; + } else { return null; } + }); + const result: IGetMessage = { + checkMsgNftMethod, + checkMsgTrsMethod, + checkMsgSysMethod, + }; + return result; +} + export function getGenericResult(events: EventRecord[]): GenericResult { const result: GenericResult = { success: false, @@ -82,6 +109,8 @@ return result; } + + export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult { let success = false; let collectionId: number = 0; @@ -89,7 +118,7 @@ // console.log(` ${phase}: ${section}.${method}:: ${data}`); if (method == 'ExtrinsicSuccess') { success = true; - } else if ((section == 'nft') && (method == 'Created')) { + } else if ((section == 'nft') && (method == 'CollectionCreated')) { collectionId = parseInt(data[0].toString()); } }); @@ -212,7 +241,7 @@ const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10); // Get the collection - const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON(); + const collection: any = (await api.query.nft.collectionById(result.collectionId)).toJSON(); // What to expect // tslint:disable-next-line:no-unused-expression @@ -324,12 +353,41 @@ const result = getDestroyResult(events); // Get the collection - const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); // What to expect expect(result).to.be.true; - expect(collection).to.be.not.null; - expect(collection.Owner).to.be.equal(nullPublicKey); + expect(collection).to.be.null; + }); +} + +export async function queryCollectionLimits(collectionId: number) { + return await usingApi(async (api) => { + return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits; + }); +} + +export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) { + await usingApi(async (api) => { + const oldLimits = await queryCollectionLimits(collectionId); + const newLimits = { ...oldLimits as any, ...limits }; + const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits); + const events = await submitTransactionAsync(sender, tx); + const result = getGenericResult(events); + + expect(result.success).to.be.true; + }); +} + +export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) { + await usingApi(async (api) => { + const oldLimits = await queryCollectionLimits(collectionId); + const newLimits = { ...oldLimits as any, ...limits }; + const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits); + const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; + const result = getGenericResult(events); + + expect(result.success).to.be.false; }); } @@ -343,12 +401,13 @@ const result = getGenericResult(events); // Get the collection - const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); // What to expect expect(result.success).to.be.true; - expect(collection.Sponsor.toString()).to.be.equal(sponsor.toString()); - expect(collection.SponsorConfirmed).to.be.false; + expect(collection.Sponsorship).to.deep.equal({ + Unconfirmed: sponsor.toString(), + }); }); } @@ -362,12 +421,11 @@ const result = getGenericResult(events); // Get the collection - const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); // What to expect expect(result.success).to.be.true; - expect(collection.Sponsor).to.be.equal(nullPublicKey); - expect(collection.SponsorConfirmed).to.be.false; + expect(collection.Sponsorship).to.be.deep.equal({ Disabled: null }); }); } @@ -401,12 +459,13 @@ const result = getGenericResult(events); // Get the collection - const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); // What to expect expect(result.success).to.be.true; - expect(collection.Sponsor).to.be.equal(sender.address); - expect(collection.SponsorConfirmed).to.be.true; + expect(collection.Sponsorship).to.be.deep.equal({ + Confirmed: sender.address, + }); }); } @@ -569,8 +628,7 @@ // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.true; // tslint:disable-next-line:no-unused-expression - expect(item).to.be.not.null; - expect(item.Owner).to.be.equal(nullPublicKey); + expect(item).to.be.null; }); } @@ -611,16 +669,16 @@ // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.true; if (type === 'NFT') { - const nftItemData = await api.query.nft.nftItemList(collectionId, tokenId) as unknown as ITokenDataType; + const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).unwrap() as ITokenDataType; expect(nftItemData.Owner.toString()).to.be.equal(accountTo.address); } if (type === 'Fungible') { - const balanceAfter = await api.query.nft.balance(collectionId, accountTo.address) as unknown as BN; + const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, accountTo.address) as any).Value as unknown as BN; expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString()); } if (type === 'ReFungible') { const nftItemData = - await api.query.nft.reFungibleItemList(collectionId, tokenId) as unknown as IReFungibleTokenDataType; + (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).unwrap() as IReFungibleTokenDataType; expect(nftItemData.Owner[0].Owner.toString()).to.be.equal(accountTo.address); expect(nftItemData.Owner[0].Fraction.toNumber()).to.be.equal(value); } @@ -667,18 +725,18 @@ expect(result.recipient).to.be.equal(recipient.address); expect(result.value.toString()).to.be.equal(value.toString()); if (type === 'NFT') { - const nftItemData = await api.query.nft.nftItemList(collectionId, tokenId) as unknown as ITokenDataType; + const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType; expect(nftItemData.Owner.toString()).to.be.equal(recipient.address); } if (type === 'Fungible') { - const balanceAfter = await api.query.nft.balance(collectionId, recipient.address) as unknown as BN; + const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, recipient.address) as any).Value as unknown as BN; expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString()); } if (type === 'ReFungible') { const nftItemData = - await api.query.nft.reFungibleItemList(collectionId, tokenId) as unknown as IReFungibleTokenDataType; + (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType; expect(nftItemData.Owner[0].Owner.toString()).to.be.equal(recipient.address); - expect(nftItemData.Owner[0].Fraction.toNumber()).to.be.equal(value); + expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString()); } }); } @@ -808,7 +866,7 @@ const result = getGenericResult(events); // Get the collection - const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); // What to expect // tslint:disable-next-line:no-unused-expression @@ -834,7 +892,7 @@ const result = getGenericResult(events); // Get the collection - const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); + const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON(); // What to expect // tslint:disable-next-line:no-unused-expression @@ -916,7 +974,7 @@ export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number) : Promise => { - return await api.query.nft.collection(collectionId) as unknown as ICollectionInterface; + return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface; }; export const getCreatedCollectionCount = async (api: ApiPromise): Promise => { @@ -926,6 +984,6 @@ export async function queryCollectionExpectSuccess(collectionId: number): Promise { return await usingApi(async (api) => { - return (await api.query.nft.collection(collectionId)) as unknown as ICollectionInterface; + return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface; }); } -- gitstuff