difftreelog
Merge branch 'develop' into feature/multi-assets-redone
in: master
108 files changed
.docker/Dockerfile-chain-dev-unitdiffbeforeafterboth232324WORKDIR /dev_chain24WORKDIR /dev_chain252526RUN cargo test --features=limit-testing26CMD cargo test --features=limit-testing2727.docker/Dockerfile-parachain-node-onlydiffbeforeafterbothno changes
.docker/docker-compose.tmp-node.j2diffbeforeafterbothno changes
.docker/forkless-config/launch-config-forkless-data.j2diffbeforeafterboth86 },86 },87 "parachains": [87 "parachains": [88 {88 {89 "bin": "/unique-chain/target/release/unique-collator",89 "bin": "/unique-chain/current/release/unique-collator",90 "upgradeBin": "/unique-chain/target/release/unique-collator",90 "upgradeBin": "/unique-chain/target/release/unique-collator",91 "upgradeWasm": "/unique-chain/target/release/wbuild/{{ FEATURE }}/{{ RUNTIME }}_runtime.compact.compressed.wasm",91 "upgradeWasm": "/unique-chain/target/release/wbuild/{{ FEATURE }}/{{ RUNTIME }}_runtime.compact.compressed.wasm",92 "id": "1000",92 "id": "1000",.docker/forkless-config/launch-config-forkless-nodata.j2diffbeforeafterboth101 "--rpc-cors=all",101 "--rpc-cors=all",102 "--unsafe-rpc-external",102 "--unsafe-rpc-external",103 "--unsafe-ws-external",103 "--unsafe-ws-external",104 "-lxcm=trace"104 "-lxcm=trace",105 "--ws-max-connections=1000"105 ]106 ]106 },107 },107 {108 {113 "--rpc-cors=all",114 "--rpc-cors=all",114 "--unsafe-rpc-external",115 "--unsafe-rpc-external",115 "--unsafe-ws-external",116 "--unsafe-ws-external",116 "-lxcm=trace"117 "-lxcm=trace",118 "--ws-max-connections=1000"117 ]119 ]118 }120 }119 ]121 ].github/workflows/build-test-master.ymldiffbeforeafterbothno changes
.github/workflows/codestyle.ymldiffbeforeafterboth49 run: cargo fmt -- --check # In that mode it returns only exit code.49 run: cargo fmt -- --check # In that mode it returns only exit code.50 - name: Cargo fmt state50 - name: Cargo fmt state51 if: success()51 if: success()52 run: echo "Nothing to do. Cargo fmt returned exit code 0."52 run: echo "Nothing to do. Command 'cargo fmt -- --check' returned exit code 0."5353545455 clippy:55 clippy:.github/workflows/dev-build-tests.ymldiffbeforeafterboth125 run: docker-compose -f ".docker/docker-compose-dev.yaml" -f ".docker/docker-compose.${{ matrix.network }}.yml" down125 run: docker-compose -f ".docker/docker-compose-dev.yaml" -f ".docker/docker-compose.${{ matrix.network }}.yml" down126127128 dev_build_unit_test:129 # The type of runner that the job will run on130 runs-on: [self-hosted-ci,medium]131 timeout-minutes: 1380132133 name: unit tests134135136 continue-on-error: true #Do not stop testing of matrix runs failed. As it decided during PR review - it required 50/50& Let's check it with false.137138139 steps:140 - name: Skip if pull request is in Draft141 # `if: github.event.pull_request.draft == true` should be kept here, at142 # the step level, rather than at the job level. The latter is not143 # recommended because when the PR is moved from "Draft" to "Ready to144 # review" the workflow will immediately be passing (since it was skipped),145 # even though it hasn't actually ran, since it takes a few seconds for146 # the workflow to start. This is also disclosed in:147 # https://github.community/t/dont-run-actions-on-draft-pull-requests/16817/17148 # That scenario would open an opportunity for the check to be bypassed:149 # 1. Get your PR approved150 # 2. Move it to Draft151 # 3. Push whatever commits you want152 # 4. Move it to "Ready for review"; now the workflow is passing (it was153 # skipped) and "Check reviews" is also passing (it won't be updated154 # until the workflow is finished)155 if: github.event.pull_request.draft == true156 run: exit 1157158 - name: Clean Workspace159 uses: AutoModality/action-clean@v1.1.0160161 # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it162 - uses: actions/checkout@v3163 with:164 ref: ${{ github.head_ref }} #Checking out head commit165166 - name: Read .env file167 uses: xom9ikk/dotenv@v1.0.2168169 - name: Generate ENV related extend file for docker-compose170 uses: cuchi/jinja2-action@v1.2.0171 with:172 template: .docker/docker-compose.tmp-unit.j2173 output_file: .docker/docker-compose.unit.yml174 variables: |175 RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}176 FEATURE=${{ matrix.features }}177 178179 - name: Show build configuration180 run: cat .docker/docker-compose.unit.yml181182 - name: Build the stack183 run: docker-compose -f ".docker/docker-compose-dev.yaml" -f ".docker/docker-compose.unit.yml" up -d --build --remove-orphans184185186 - name: Stop running containers187 if: always() # run this step always188 run: docker-compose -f ".docker/docker-compose-dev.yaml" -f ".docker/docker-compose.unit.yml" down189126.github/workflows/nodes-only-update.ymldiffbeforeafterbothno changes
.github/workflows/unit-test.ymldiffbeforeafterbothno changes
.maintain/frame-weight-template.hbsdiffbeforeafterboth14#![cfg_attr(rustfmt, rustfmt_skip)]14#![cfg_attr(rustfmt, rustfmt_skip)]15#![allow(unused_parens)]15#![allow(unused_parens)]16#![allow(unused_imports)]16#![allow(unused_imports)]17#![allow(missing_docs)]17#![allow(clippy::unnecessary_cast)]18#![allow(clippy::unnecessary_cast)]181919use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};20use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};Cargo.lockdiffbeforeafterboth1771 "zeroize",1771 "zeroize",1772]1772]17731774[[package]]1775name = "darling"1776version = "0.13.4"1777source = "registry+https://github.com/rust-lang/crates.io-index"1778checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"1779dependencies = [1780 "darling_core",1781 "darling_macro",1782]17831784[[package]]1785name = "darling_core"1786version = "0.13.4"1787source = "registry+https://github.com/rust-lang/crates.io-index"1788checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"1789dependencies = [1790 "fnv",1791 "ident_case",1792 "proc-macro2",1793 "quote",1794 "strsim",1795 "syn",1796]17971798[[package]]1799name = "darling_macro"1800version = "0.13.4"1801source = "registry+https://github.com/rust-lang/crates.io-index"1802checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"1803dependencies = [1804 "darling_core",1805 "quote",1806 "syn",1807]180817731809[[package]]1774[[package]]1810name = "data-encoding"1775name = "data-encoding"220421692205[[package]]2170[[package]]2206name = "evm-coder"2171name = "evm-coder"2207version = "0.1.1"2172version = "0.1.3"2208dependencies = [2173dependencies = [2209 "ethereum",2174 "ethereum",2210 "evm-coder-macros",2175 "evm-coder-procedural",2211 "evm-core",2176 "evm-core",2212 "hex",2177 "hex",2213 "hex-literal",2178 "hex-literal",2214 "impl-trait-for-tuples",2179 "impl-trait-for-tuples",2215 "primitive-types",2180 "primitive-types",2181 "sp-std",2216]2182]221721832218[[package]]2184[[package]]2219name = "evm-coder-macros"2185name = "evm-coder-procedural"2220version = "0.1.0"2186version = "0.2.0"2221dependencies = [2187dependencies = [2222 "Inflector",2188 "Inflector",2223 "darling",2224 "hex",2189 "hex",2225 "proc-macro2",2190 "proc-macro2",2226 "quote",2191 "quote",2227 "sha3 0.9.1",2192 "sha3 0.10.2",2228 "syn",2193 "syn",2229]2194]223021952345[[package]]2310[[package]]2346name = "fc-consensus"2311name = "fc-consensus"2347version = "2.0.0-dev"2312version = "2.0.0-dev"2348source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2313source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2349dependencies = [2314dependencies = [2350 "async-trait",2315 "async-trait",2351 "fc-db",2316 "fc-db",2364[[package]]2329[[package]]2365name = "fc-db"2330name = "fc-db"2366version = "2.0.0-dev"2331version = "2.0.0-dev"2367source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2332source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2368dependencies = [2333dependencies = [2369 "fp-storage",2334 "fp-storage",2370 "kvdb-rocksdb",2335 "kvdb-rocksdb",2380[[package]]2345[[package]]2381name = "fc-mapping-sync"2346name = "fc-mapping-sync"2382version = "2.0.0-dev"2347version = "2.0.0-dev"2383source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2348source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2384dependencies = [2349dependencies = [2385 "fc-db",2350 "fc-db",2386 "fp-consensus",2351 "fp-consensus",2397[[package]]2362[[package]]2398name = "fc-rpc"2363name = "fc-rpc"2399version = "2.0.0-dev"2364version = "2.0.0-dev"2400source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2365source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2401dependencies = [2366dependencies = [2402 "ethereum",2367 "ethereum",2403 "ethereum-types",2368 "ethereum-types",2437[[package]]2402[[package]]2438name = "fc-rpc-core"2403name = "fc-rpc-core"2439version = "1.1.0-dev"2404version = "1.1.0-dev"2440source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2405source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2441dependencies = [2406dependencies = [2442 "ethereum",2407 "ethereum",2443 "ethereum-types",2408 "ethereum-types",2578[[package]]2543[[package]]2579name = "fp-consensus"2544name = "fp-consensus"2580version = "2.0.0-dev"2545version = "2.0.0-dev"2581source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2546source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2582dependencies = [2547dependencies = [2583 "ethereum",2548 "ethereum",2584 "parity-scale-codec 3.1.5",2549 "parity-scale-codec 3.1.5",2590[[package]]2555[[package]]2591name = "fp-evm"2556name = "fp-evm"2592version = "3.0.0-dev"2557version = "3.0.0-dev"2593source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2558source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2594dependencies = [2559dependencies = [2595 "evm",2560 "evm",2596 "frame-support",2561 "frame-support",2604[[package]]2569[[package]]2605name = "fp-evm-mapping"2570name = "fp-evm-mapping"2606version = "0.1.0"2571version = "0.1.0"2607source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2572source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2608dependencies = [2573dependencies = [2609 "frame-support",2574 "frame-support",2610 "sp-core",2575 "sp-core",2613[[package]]2578[[package]]2614name = "fp-rpc"2579name = "fp-rpc"2615version = "3.0.0-dev"2580version = "3.0.0-dev"2616source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2581source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2617dependencies = [2582dependencies = [2618 "ethereum",2583 "ethereum",2619 "ethereum-types",2584 "ethereum-types",2630[[package]]2595[[package]]2631name = "fp-self-contained"2596name = "fp-self-contained"2632version = "1.0.0-dev"2597version = "1.0.0-dev"2633source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2598source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2634dependencies = [2599dependencies = [2635 "ethereum",2600 "ethereum",2636 "frame-support",2601 "frame-support",2646[[package]]2611[[package]]2647name = "fp-storage"2612name = "fp-storage"2648version = "2.0.0"2613version = "2.0.0"2649source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"2614source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"2650dependencies = [2615dependencies = [2651 "parity-scale-codec 3.1.5",2616 "parity-scale-codec 3.1.5",2652]2617]3428 "winapi",3393 "winapi",3429]3394]34303431[[package]]3432name = "ident_case"3433version = "1.0.1"3434source = "registry+https://github.com/rust-lang/crates.io-index"3435checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"343633953437[[package]]3396[[package]]3438name = "idna"3397name = "idna"5531[[package]]5490[[package]]5532name = "pallet-base-fee"5491name = "pallet-base-fee"5533version = "1.0.0"5492version = "1.0.0"5534source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"5493source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"5535dependencies = [5494dependencies = [5536 "fp-evm",5495 "fp-evm",5537 "frame-support",5496 "frame-support",563855975639[[package]]5598[[package]]5640name = "pallet-common"5599name = "pallet-common"5641version = "0.1.5"5600version = "0.1.8"5642dependencies = [5601dependencies = [5643 "ethereum",5602 "ethereum",5644 "evm-coder",5603 "evm-coder",5746[[package]]5705[[package]]5747name = "pallet-ethereum"5706name = "pallet-ethereum"5748version = "4.0.0-dev"5707version = "4.0.0-dev"5749source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"5708source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"5750dependencies = [5709dependencies = [5751 "ethereum",5710 "ethereum",5752 "ethereum-types",5711 "ethereum-types",5775[[package]]5734[[package]]5776name = "pallet-evm"5735name = "pallet-evm"5777version = "6.0.0-dev"5736version = "6.0.0-dev"5778source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#64915c0986fcf2bbe942794b838c0cf359c93c21"5737source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.27#69945f20e8dc06ab9e0dd636848a8db6a408c71c"5779dependencies = [5738dependencies = [5780 "evm",5739 "evm",5781 "fp-evm",5740 "fp-evm",581957785820[[package]]5779[[package]]5821name = "pallet-evm-contract-helpers"5780name = "pallet-evm-contract-helpers"5822version = "0.1.2"5781version = "0.2.0"5823dependencies = [5782dependencies = [5824 "evm-coder",5783 "evm-coder",5825 "fp-evm-mapping",5784 "fp-evm-mapping",590358625904[[package]]5863[[package]]5905name = "pallet-fungible"5864name = "pallet-fungible"5906version = "0.1.3"5865version = "0.1.5"5907dependencies = [5866dependencies = [5908 "ethereum",5867 "ethereum",5909 "evm-coder",5868 "evm-coder",614561046146[[package]]6105[[package]]6147name = "pallet-nonfungible"6106name = "pallet-nonfungible"6148version = "0.1.4"6107version = "0.1.5"6149dependencies = [6108dependencies = [6150 "ethereum",6109 "ethereum",6151 "evm-coder",6110 "evm-coder",626762266268[[package]]6227[[package]]6269name = "pallet-refungible"6228name = "pallet-refungible"6270version = "0.2.3"6229version = "0.2.4"6271dependencies = [6230dependencies = [6272 "derivative",6231 "derivative",6273 "ethereum",6232 "ethereum",crates/evm-coder-macros/Cargo.tomldiffbeforeafterbothno changes
crates/evm-coder-macros/src/lib.rsdiffbeforeafterbothno changes
crates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterbothno changes
crates/evm-coder-macros/src/to_log.rsdiffbeforeafterbothno changes
crates/evm-coder/CHANGELOG.mddiffbeforeafterboth1# Change Log23All notable changes to this project will be documented in this file.45## [0.1.3] - 2022-08-2967### Fixed89 - Parsing simple values.101<!-- bureaucrate goes here -->11<!-- bureaucrate goes here -->12## [v0.1.2] 2022-08-191314### Added1516 - Implementation `AbiWrite` for tuples.1718 ### Fixes1920 - Tuple generation for solidity.212## [v0.1.1] 2022-08-1622## [v0.1.1] 2022-08-163234### Other changes24### Other changes7278- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf828- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf892910- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b30- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b31crates/evm-coder/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "evm-coder"2name = "evm-coder"3version = "0.1.1"3version = "0.1.3"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"667[dependencies]7[dependencies]8# evm-coder reexports those proc-macro8evm-coder-macros = { path = "../evm-coder-macros" }9evm-coder-procedural = { path = "./procedural" }10# Evm uses primitive-types for H160, H256 and others9primitive-types = { version = "0.11.1", default-features = false }11primitive-types = { version = "0.11.1", default-features = false }10hex-literal = "0.3.3"12# Evm doesn't have reexports for log and others11ethereum = { version = "0.12.0", default-features = false }13ethereum = { version = "0.12.0", default-features = false }14sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }15# Error types for execution12evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.27" }16evm-core = { default-features = false , git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.27" }17# We have tuple-heavy code in solidity.rs13impl-trait-for-tuples = "0.2.1"18impl-trait-for-tuples = "0.2.2"141915[dev-dependencies]20[dev-dependencies]21# We want to assert some large binary blobs equality in tests16hex = "0.4.3"22hex = "0.4.3"23hex-literal = "0.3.4"172418[features]25[features]19default = ["std"]26default = ["std"]crates/evm-coder/README.mddiffbeforeafterbothno changes
crates/evm-coder/procedural/Cargo.tomldiffbeforeafterbothno changes
crates/evm-coder/procedural/src/lib.rsdiffbeforeafterbothno changes
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterbothno changes
crates/evm-coder/procedural/src/to_log.rsdiffbeforeafterbothno changes
crates/evm-coder/src/abi.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617//! TODO: I misunterstood therminology, abi IS rlp encoded, so17//! Implementation of EVM RLP reader/writer18//! this module should be replaced with rlp crate191820#![allow(dead_code)]19#![allow(dead_code)]2120323133const ABI_ALIGNMENT: usize = 32;32const ABI_ALIGNMENT: usize = 32;343334trait TypeHelper {35 fn is_dynamic() -> bool;36}3738/// View into RLP data, which provides method to read typed items from it35#[derive(Clone)]39#[derive(Clone)]36pub struct AbiReader<'i> {40pub struct AbiReader<'i> {37 buf: &'i [u8],41 buf: &'i [u8],38 subresult_offset: usize,42 subresult_offset: usize,39 offset: usize,43 offset: usize,40}44}41impl<'i> AbiReader<'i> {45impl<'i> AbiReader<'i> {46 /// Start reading RLP buffer, assuming there is no padding bytes42 pub fn new(buf: &'i [u8]) -> Self {47 pub fn new(buf: &'i [u8]) -> Self {43 Self {48 Self {44 buf,49 buf,45 subresult_offset: 0,50 subresult_offset: 0,46 offset: 0,51 offset: 0,47 }52 }48 }53 }54 /// Start reading RLP buffer, parsing first 4 bytes as selector49 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {55 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {50 if buf.len() < 4 {56 if buf.len() < 4 {51 return Err(Error::Error(ExitError::OutOfOffset));57 return Err(Error::Error(ExitError::OutOfOffset));75 return Err(Error::Error(ExitError::OutOfOffset));81 return Err(Error::Error(ExitError::OutOfOffset));76 }82 }77 let mut block = [0; S];83 let mut block = [0; S];78 // Verify padding is empty79 if !buf[pad_start..pad_size].iter().all(|&v| v == 0) {84 let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);85 if !is_pad_zeroed {80 return Err(Error::Error(ExitError::InvalidRange));86 return Err(Error::Error(ExitError::InvalidRange));81 }87 }82 block.copy_from_slice(&buf[block_start..block_size]);88 block.copy_from_slice(&buf[block_start..block_size]);109 )115 )110 }116 }111117118 /// Read [`H160`] at current position, then advance112 pub fn address(&mut self) -> Result<H160> {119 pub fn address(&mut self) -> Result<H160> {113 Ok(H160(self.read_padleft()?))120 Ok(H160(self.read_padleft()?))114 }121 }115122123 /// Read [`bool`] at current position, then advance116 pub fn bool(&mut self) -> Result<bool> {124 pub fn bool(&mut self) -> Result<bool> {117 let data: [u8; 1] = self.read_padleft()?;125 let data: [u8; 1] = self.read_padleft()?;118 match data[0] {126 match data[0] {122 }130 }123 }131 }124132133 /// Read [`[u8; 4]`] at current position, then advance125 pub fn bytes4(&mut self) -> Result<[u8; 4]> {134 pub fn bytes4(&mut self) -> Result<[u8; 4]> {126 self.read_padright()135 self.read_padright()127 }136 }128137138 /// Read [`Vec<u8>`] at current position, then advance129 pub fn bytes(&mut self) -> Result<Vec<u8>> {139 pub fn bytes(&mut self) -> Result<Vec<u8>> {130 let mut subresult = self.subresult()?;140 let mut subresult = self.subresult(None)?;131 let length = subresult.read_usize()?;141 let length = subresult.uint32()? as usize;132 if subresult.buf.len() < subresult.offset + length {142 if subresult.buf.len() < subresult.offset + length {133 return Err(Error::Error(ExitError::OutOfOffset));143 return Err(Error::Error(ExitError::OutOfOffset));134 }144 }135 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())145 Ok(subresult.buf[subresult.offset..subresult.offset + length].into())136 }146 }147148 /// Read [`string`] at current position, then advance137 pub fn string(&mut self) -> Result<string> {149 pub fn string(&mut self) -> Result<string> {138 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))150 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))139 }151 }140152153 /// Read [`u8`] at current position, then advance141 pub fn uint8(&mut self) -> Result<u8> {154 pub fn uint8(&mut self) -> Result<u8> {142 Ok(self.read_padleft::<1>()?[0])155 Ok(self.read_padleft::<1>()?[0])143 }156 }144157158 /// Read [`u32`] at current position, then advance145 pub fn uint32(&mut self) -> Result<u32> {159 pub fn uint32(&mut self) -> Result<u32> {146 Ok(u32::from_be_bytes(self.read_padleft()?))160 Ok(u32::from_be_bytes(self.read_padleft()?))147 }161 }148162163 /// Read [`u128`] at current position, then advance149 pub fn uint128(&mut self) -> Result<u128> {164 pub fn uint128(&mut self) -> Result<u128> {150 Ok(u128::from_be_bytes(self.read_padleft()?))165 Ok(u128::from_be_bytes(self.read_padleft()?))151 }166 }152167168 /// Read [`U256`] at current position, then advance153 pub fn uint256(&mut self) -> Result<U256> {169 pub fn uint256(&mut self) -> Result<U256> {154 let buf: [u8; 32] = self.read_padleft()?;170 let buf: [u8; 32] = self.read_padleft()?;155 Ok(U256::from_big_endian(&buf))171 Ok(U256::from_big_endian(&buf))156 }172 }157173174 /// Read [`u64`] at current position, then advance158 pub fn uint64(&mut self) -> Result<u64> {175 pub fn uint64(&mut self) -> Result<u64> {159 Ok(u64::from_be_bytes(self.read_padleft()?))176 Ok(u64::from_be_bytes(self.read_padleft()?))160 }177 }161178179 /// Read [`usize`] at current position, then advance180 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]162 pub fn read_usize(&mut self) -> Result<usize> {181 pub fn read_usize(&mut self) -> Result<usize> {163 Ok(usize::from_be_bytes(self.read_padleft()?))182 Ok(usize::from_be_bytes(self.read_padleft()?))164 }183 }165184185 /// Slice recursive buffer, advance one word for buffer offset186 /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].166 fn subresult(&mut self) -> Result<AbiReader<'i>> {187 fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {188 let subresult_offset = self.subresult_offset;167 let offset = self.read_usize()?;189 let offset = if let Some(size) = size {190 self.offset += size;191 self.subresult_offset += size;192 0193 } else {194 self.uint32()? as usize195 };196168 if offset + self.subresult_offset > self.buf.len() {197 if offset + self.subresult_offset > self.buf.len() {169 return Err(Error::Error(ExitError::InvalidRange));198 return Err(Error::Error(ExitError::InvalidRange));170 }199 }200201 let new_offset = offset + subresult_offset;171 Ok(AbiReader {202 Ok(AbiReader {172 buf: self.buf,203 buf: self.buf,173 subresult_offset: offset + self.subresult_offset,204 subresult_offset: new_offset,174 offset: offset + self.subresult_offset,205 offset: new_offset,175 })206 })176 }207 }177208209 /// Is this parser reached end of buffer?178 pub fn is_finished(&self) -> bool {210 pub fn is_finished(&self) -> bool {179 self.buf.len() == self.offset211 self.buf.len() == self.offset180 }212 }181}213}182214215/// Writer for RLP encoded data183#[derive(Default)]216#[derive(Default)]184pub struct AbiWriter {217pub struct AbiWriter {185 static_part: Vec<u8>,218 static_part: Vec<u8>,186 dynamic_part: Vec<(usize, AbiWriter)>,219 dynamic_part: Vec<(usize, AbiWriter)>,187 had_call: bool,220 had_call: bool,188}221}189impl AbiWriter {222impl AbiWriter {223 /// Initialize internal buffers for output data, assuming no padding required190 pub fn new() -> Self {224 pub fn new() -> Self {191 Self::default()225 Self::default()192 }226 }227 /// Initialize internal buffers, inserting method selector at beginning193 pub fn new_call(method_id: u32) -> Self {228 pub fn new_call(method_id: u32) -> Self {194 let mut val = Self::new();229 let mut val = Self::new();195 val.static_part.extend(&method_id.to_be_bytes());230 val.static_part.extend(&method_id.to_be_bytes());211 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);246 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);212 }247 }213248249 /// Write [`H160`] to end of buffer214 pub fn address(&mut self, address: &H160) {250 pub fn address(&mut self, address: &H160) {215 self.write_padleft(&address.0)251 self.write_padleft(&address.0)216 }252 }217253254 /// Write [`bool`] to end of buffer218 pub fn bool(&mut self, value: &bool) {255 pub fn bool(&mut self, value: &bool) {219 self.write_padleft(&[if *value { 1 } else { 0 }])256 self.write_padleft(&[if *value { 1 } else { 0 }])220 }257 }221258259 /// Write [`u8`] to end of buffer222 pub fn uint8(&mut self, value: &u8) {260 pub fn uint8(&mut self, value: &u8) {223 self.write_padleft(&[*value])261 self.write_padleft(&[*value])224 }262 }225263264 /// Write [`u32`] to end of buffer226 pub fn uint32(&mut self, value: &u32) {265 pub fn uint32(&mut self, value: &u32) {227 self.write_padleft(&u32::to_be_bytes(*value))266 self.write_padleft(&u32::to_be_bytes(*value))228 }267 }229268269 /// Write [`u128`] to end of buffer230 pub fn uint128(&mut self, value: &u128) {270 pub fn uint128(&mut self, value: &u128) {231 self.write_padleft(&u128::to_be_bytes(*value))271 self.write_padleft(&u128::to_be_bytes(*value))232 }272 }233273274 /// Write [`U256`] to end of buffer234 pub fn uint256(&mut self, value: &U256) {275 pub fn uint256(&mut self, value: &U256) {235 let mut out = [0; 32];276 let mut out = [0; 32];236 value.to_big_endian(&mut out);277 value.to_big_endian(&mut out);237 self.write_padleft(&out)278 self.write_padleft(&out)238 }279 }239280281 /// Write [`usize`] to end of buffer282 #[deprecated = "dangerous, as usize may have different width in wasm and native execution"]240 pub fn write_usize(&mut self, value: &usize) {283 pub fn write_usize(&mut self, value: &usize) {241 self.write_padleft(&usize::to_be_bytes(*value))284 self.write_padleft(&usize::to_be_bytes(*value))242 }285 }243286287 /// Append recursive data, writing pending offset at end of buffer244 pub fn write_subresult(&mut self, result: Self) {288 pub fn write_subresult(&mut self, result: Self) {245 self.dynamic_part.push((self.static_part.len(), result));289 self.dynamic_part.push((self.static_part.len(), result));246 // Empty block, to be filled later290 // Empty block, to be filled later247 self.write_padleft(&[]);291 self.write_padleft(&[]);248 }292 }249293250 pub fn memory(&mut self, value: &[u8]) {294 fn memory(&mut self, value: &[u8]) {251 let mut sub = Self::new();295 let mut sub = Self::new();252 sub.write_usize(&value.len());296 sub.uint32(&(value.len() as u32));253 for chunk in value.chunks(ABI_ALIGNMENT) {297 for chunk in value.chunks(ABI_ALIGNMENT) {254 sub.write_padright(chunk);298 sub.write_padright(chunk);255 }299 }256 self.write_subresult(sub);300 self.write_subresult(sub);257 }301 }258302303 /// Append recursive [`str`] at end of buffer259 pub fn string(&mut self, value: &str) {304 pub fn string(&mut self, value: &str) {260 self.memory(value.as_bytes())305 self.memory(value.as_bytes())261 }306 }262307308 /// Append recursive [`[u8]`] at end of buffer263 pub fn bytes(&mut self, value: &[u8]) {309 pub fn bytes(&mut self, value: &[u8]) {264 self.memory(value)310 self.memory(value)265 }311 }266312313 /// Finish writer, concatenating all internal buffers267 pub fn finish(mut self) -> Vec<u8> {314 pub fn finish(mut self) -> Vec<u8> {268 for (static_offset, part) in self.dynamic_part {315 for (static_offset, part) in self.dynamic_part {269 let part_offset = self.static_part.len() - self.had_call.then(|| 4).unwrap_or(0);316 let part_offset = self.static_part.len() - self.had_call.then(|| 4).unwrap_or(0);278 }325 }279}326}280327328/// [`AbiReader`] implements reading of many types, but it should329/// be limited to types defined in spec330///331/// As this trait can't be made sealed,332/// instead of having `impl AbiRead for T`, we have `impl AbiRead<T> for AbiReader`281pub trait AbiRead<T> {333pub trait AbiRead<T> {334 /// Read item from current position, advanding decoder282 fn abi_read(&mut self) -> Result<T>;335 fn abi_read(&mut self) -> Result<T>;336337 /// Size for type aligned to [`ABI_ALIGNMENT`].338 fn size() -> usize;283}339}284340285macro_rules! impl_abi_readable {341macro_rules! impl_abi_readable {286 ($ty:ty, $method:ident) => {342 ($ty:ty, $method:ident, $dynamic:literal) => {343 impl TypeHelper for $ty {344 fn is_dynamic() -> bool {345 $dynamic346 }347 }287 impl AbiRead<$ty> for AbiReader<'_> {348 impl AbiRead<$ty> for AbiReader<'_> {288 fn abi_read(&mut self) -> Result<$ty> {349 fn abi_read(&mut self) -> Result<$ty> {289 self.$method()350 self.$method()290 }351 }352353 fn size() -> usize {354 ABI_ALIGNMENT355 }291 }356 }292 };357 };293}358}294359295impl_abi_readable!(u8, uint8);360impl_abi_readable!(u8, uint8, false);296impl_abi_readable!(u32, uint32);361impl_abi_readable!(u32, uint32, false);297impl_abi_readable!(u64, uint64);362impl_abi_readable!(u64, uint64, false);298impl_abi_readable!(u128, uint128);363impl_abi_readable!(u128, uint128, false);299impl_abi_readable!(U256, uint256);364impl_abi_readable!(U256, uint256, false);300impl_abi_readable!([u8; 4], bytes4);365impl_abi_readable!([u8; 4], bytes4, false);301impl_abi_readable!(H160, address);366impl_abi_readable!(H160, address, false);302impl_abi_readable!(Vec<u8>, bytes);367impl_abi_readable!(Vec<u8>, bytes, true);303impl_abi_readable!(bool, bool);368impl_abi_readable!(bool, bool, true);304impl_abi_readable!(string, string);369impl_abi_readable!(string, string, true);305370306mod sealed {371mod sealed {307 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead372 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead317 Self: AbiRead<R>,382 Self: AbiRead<R>,318{383{319 fn abi_read(&mut self) -> Result<Vec<R>> {384 fn abi_read(&mut self) -> Result<Vec<R>> {320 let mut sub = self.subresult()?;385 let mut sub = self.subresult(None)?;321 let size = sub.read_usize()?;386 let size = sub.uint32()? as usize;322 sub.subresult_offset = sub.offset;387 sub.subresult_offset = sub.offset;323 let mut out = Vec::with_capacity(size);388 let mut out = Vec::with_capacity(size);324 for _ in 0..size {389 for _ in 0..size {327 Ok(out)392 Ok(out)328 }393 }394395 fn size() -> usize {396 ABI_ALIGNMENT397 }329}398}330399331macro_rules! impl_tuples {400macro_rules! impl_tuples {332 ($($ident:ident)+) => {401 ($($ident:ident)+) => {402 impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+) {403 fn is_dynamic() -> bool {404 false405 $(406 || <$ident>::is_dynamic()407 )*408 }409 }333 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}410 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}334 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>411 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>335 where412 where336 $(Self: AbiRead<$ident>),+413 $(414 Self: AbiRead<$ident>,415 )+416 ($($ident,)+): TypeHelper,337 {417 {338 fn abi_read(&mut self) -> Result<($($ident,)+)> {418 fn abi_read(&mut self) -> Result<($($ident,)+)> {419 let size = if !<($($ident,)+)>::is_dynamic() { Some(<Self as AbiRead<($($ident,)+)>>::size()) } else { None };339 let mut subresult = self.subresult()?;420 let mut subresult = self.subresult(size)?;340 Ok((421 Ok((341 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+422 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+342 ))423 ))343 }424 }425426 fn size() -> usize {427 0 $(+ <AbiReader<'_> as AbiRead<$ident>>::size())+428 }344 }429 }430 #[allow(non_snake_case)]431 impl<$($ident),+> AbiWrite for &($($ident,)+)432 where433 $($ident: AbiWrite,)+434 {435 fn abi_write(&self, writer: &mut AbiWriter) {436 let ($($ident,)+) = self;437 $($ident.abi_write(writer);)+438 }439 }345 };440 };346}441}347442356impl_tuples! {A B C D E F G H I}451impl_tuples! {A B C D E F G H I}357impl_tuples! {A B C D E F G H I J}452impl_tuples! {A B C D E F G H I J}358453454/// For questions about inability to provide custom implementations,455/// see [`AbiRead`]359pub trait AbiWrite {456pub trait AbiWrite {457 /// Write value to end of specified encoder360 fn abi_write(&self, writer: &mut AbiWriter);458 fn abi_write(&self, writer: &mut AbiWriter);459 /// Specialization for [`crate::solidity_interface`] implementation,460 /// see comment in `impl AbiWrite for ResultWithPostInfo`361 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {461 fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {362 let mut writer = AbiWriter::new();462 let mut writer = AbiWriter::new();363 self.abi_write(&mut writer);463 self.abi_write(&mut writer);364 Ok(writer.into())464 Ok(writer.into())365 }465 }366}466}367467468/// This particular AbiWrite implementation should be split to another trait,469/// which only implements `to_result`, but due to lack of specialization feature470/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`,471/// so here we abusing default trait methods for it368impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {472impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {369 // this particular AbiWrite implementation should be split to another trait,370 // which only implements [`to_result`]371 //372 // But due to lack of specialization feature in stable Rust, we can't have373 // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing374 // default trait methods for it375 fn abi_write(&self, _writer: &mut AbiWriter) {473 fn abi_write(&self, _writer: &mut AbiWriter) {376 debug_assert!(false, "shouldn't be called, see comment")474 debug_assert!(false, "shouldn't be called, see comment")377 }475 }422 fn abi_write(&self, _writer: &mut AbiWriter) {}520 fn abi_write(&self, _writer: &mut AbiWriter) {}423}521}424522523/// Helper macros to parse reader into variables524#[deprecated]425#[macro_export]525#[macro_export]426macro_rules! abi_decode {526macro_rules! abi_decode {427 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {527 ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {431 }531 }432}532}533534/// Helper macros to construct RLP-encoded buffer535#[deprecated]433#[macro_export]536#[macro_export]434macro_rules! abi_encode {537macro_rules! abi_encode {435 ($($typ:ident($value:expr)),* $(,)?) => {{538 ($($typ:ident($value:expr)),* $(,)?) => {{479 assert_eq!(encoded, alternative_encoded);582 assert_eq!(encoded, alternative_encoded);480583481 let mut decoder = AbiReader::new(&encoded);584 let mut decoder = AbiReader::new(&encoded);482 assert_eq!(decoder.bool().unwrap(), true);585 assert!(decoder.bool().unwrap());483 assert_eq!(decoder.string().unwrap(), "test");586 assert_eq!(decoder.string().unwrap(), "test");484 }587 }485588549 );652 );550 }653 }654655 #[test]656 fn parse_vec_with_simple_type() {657 use crate::types::address;658 use primitive_types::{H160, U256};659660 let (call, mut decoder) = AbiReader::new_call(&hex!(661 "662 1ACF2D55663 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]664 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]665666 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address667 000000000000000000000000000000000000000000000000000000000000000A // uint256668669 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address670 0000000000000000000000000000000000000000000000000000000000000014 // uint256671672 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address673 000000000000000000000000000000000000000000000000000000000000001E // uint256674 "675 ))676 .unwrap();677 assert_eq!(call, u32::to_be_bytes(0x1ACF2D55));678 let data =679 <AbiReader<'_> as AbiRead<Vec<(address, uint256)>>>::abi_read(&mut decoder).unwrap();680 assert_eq!(data.len(), 3);681 assert_eq!(682 data,683 vec![684 (685 H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),686 U256([10, 0, 0, 0])687 ),688 (689 H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),690 U256([20, 0, 0, 0])691 ),692 (693 H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),694 U256([30, 0, 0, 0])695 ),696 ]697 );698 }551}699}552700crates/evm-coder/src/events.rsdiffbeforeafterboth191920use crate::types::*;20use crate::types::*;212122/// Implementation of this trait should not be written manually,23/// instead use [`crate::ToLog`] proc macros.24///25/// See also [`evm_coder_procedural::ToLog`], [solidity docs on events](https://docs.soliditylang.org/en/develop/contracts.html#events)22pub trait ToLog {26pub trait ToLog {27 /// Convert event to [`ethereum::Log`].28 /// Because event by itself doesn't contains current contract29 /// address, it should be specified manually.23 fn to_log(&self, contract: H160) -> Log;30 fn to_log(&self, contract: H160) -> Log;24}31}253233/// Only items implementing `ToTopic` may be used as `#[indexed]` field34/// in [`crate::ToLog`] macro usage.35///36/// See also (solidity docs on events)[<https://docs.soliditylang.org/en/develop/contracts.html#events>]26pub trait ToTopic {37pub trait ToTopic {38 /// Convert value to topic to be used in [`ethereum::Log`]27 fn to_topic(&self) -> H256;39 fn to_topic(&self) -> H256;28}40}2941crates/evm-coder/src/execution.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Contract execution related types161817#[cfg(not(feature = "std"))]19#[cfg(not(feature = "std"))]18use alloc::string::{String, ToString};20use alloc::string::{String, ToString};222423use crate::Weight;25use crate::Weight;242627/// Execution error, should be convertible between EVM and Substrate.25#[derive(Debug, Clone)]28#[derive(Debug, Clone)]26pub enum Error {29pub enum Error {30 /// Non-fatal contract error occured27 Revert(String),31 Revert(String),32 /// EVM fatal error28 Fatal(ExitFatal),33 Fatal(ExitFatal),34 /// EVM normal error29 Error(ExitError),35 Error(ExitError),30}36}313738 }44 }39}45}404647/// To be used in [`crate::solidity_interface`] implementation.41pub type Result<T> = core::result::Result<T, Error>;48pub type Result<T> = core::result::Result<T, Error>;424950/// Static information collected from [`crate::weight`].43pub struct DispatchInfo {51pub struct DispatchInfo {52 /// Statically predicted call weight44 pub weight: Weight,53 pub weight: Weight,45}54}465555 }64 }56}65}576667/// Weight information that is only available post dispatch.68/// Note: This can only be used to reduce the weight or fee, not increase it.58#[derive(Default, Clone)]69#[derive(Default, Clone)]59pub struct PostDispatchInfo {70pub struct PostDispatchInfo {71 /// Actual weight consumed by call60 actual_weight: Option<Weight>,72 actual_weight: Option<Weight>,61}73}627463impl PostDispatchInfo {75impl PostDispatchInfo {76 /// Calculate amount to be returned back to user64 pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {77 pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {65 info.weight - self.calc_actual_weight(info)78 info.weight - self.calc_actual_weight(info)66 }79 }678081 /// Calculate actual consumed weight, saturating to weight reported82 /// pre-dispatch68 pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {83 pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {69 if let Some(actual_weight) = self.actual_weight {84 if let Some(actual_weight) = self.actual_weight {70 actual_weight.min(info.weight)85 actual_weight.min(info.weight)74 }89 }75}90}769192/// Wrapper for PostDispatchInfo and any user-provided data77#[derive(Clone)]93#[derive(Clone)]78pub struct WithPostDispatchInfo<T> {94pub struct WithPostDispatchInfo<T> {95 /// User provided data79 pub data: T,96 pub data: T,97 /// Info known after dispatch80 pub post_info: PostDispatchInfo,98 pub post_info: PostDispatchInfo,81}99}8210089 }107 }90}108}91109110/// Return type of items in [`crate::solidity_interface`] definition92pub type ResultWithPostInfo<T> =111pub type ResultWithPostInfo<T> =93 core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;112 core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;94113crates/evm-coder/src/lib.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617#![doc = include_str!("../README.md")]18#![deny(missing_docs)]17#![cfg_attr(not(feature = "std"), no_std)]19#![cfg_attr(not(feature = "std"), no_std)]18#[cfg(not(feature = "std"))]20#[cfg(not(feature = "std"))]19extern crate alloc;21extern crate alloc;202221use abi::{AbiRead, AbiReader, AbiWriter};23use abi::{AbiRead, AbiReader, AbiWriter};22pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, weight, ToLog};24pub use evm_coder_procedural::{event_topic, fn_selector};23pub mod abi;25pub mod abi;24pub mod events;25pub use events::ToLog;26pub use events::{ToLog, ToTopic};26use execution::DispatchInfo;27use execution::DispatchInfo;27pub mod execution;28pub mod execution;2930/// Derives call enum implementing [`crate::Callable`], [`crate::Weighted`]31/// and [`crate::Call`] from impl block.32///33/// ## Macro syntax34///35/// `#[solidity_interface(name, is, inline_is, events)]`36/// - *name* - used in generated code, and for Call enum name37/// - *is* - used to provide inheritance in Solidity38/// - *inline_is* - same as `is`, but ERC165::SupportsInterface will work differently: For `is` SupportsInterface(A) will return true39/// if A is one of the interfaces the contract is inherited from (e.g. B is created as `is(A)`). If B is created as `inline_is(A)`40/// SupportsInterface(A) will internally create a new interface that combines all methods of A and B, so SupportsInterface(A) will return41/// false.42///43/// `#[weight(value)]`44/// Can be added to every method of impl block, used for deriving [`crate::Weighted`], which45/// is used by substrate bridge.46/// - *value*: expression, which evaluates to weight required to call this method.47/// This expression can use call arguments to calculate non-constant execution time.48/// This expression should evaluate faster than actual execution does, and may provide worse case49/// than one is called.50///51/// `#[solidity_interface(rename_selector)]`52/// - *rename_selector* - by default, selector name will be generated by transforming method name53/// from snake_case to camelCase. Use this option, if other naming convention is required.54/// I.e: method `token_uri` will be automatically renamed to `tokenUri` in selector, but name55/// required by ERC721 standard is `tokenURI`, thus we need to specify `rename_selector = "tokenURI"`56/// explicitly.57///58/// Both contract and contract methods may have doccomments, which will end up in a generated59/// solidity interface file, thus you should use [solidity syntax](https://docs.soliditylang.org/en/latest/natspec-format.html) for writing documentation in this macro60///61/// ## Example62///63/// ```ignore64/// struct SuperContract;65/// struct InlineContract;66/// struct Contract;67///68/// #[derive(ToLog)]69/// enum ContractEvents {70/// Event(#[indexed] uint32),71/// }72///73/// /// @dev This contract provides function to multiply two numbers74/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))]75/// impl Contract {76/// /// Multiply two numbers77/// /// @param a First number78/// /// @param b Second number79/// /// @return uint32 Product of two passed numbers80/// /// @dev This function returns error in case of overflow81/// #[weight(200 + a + b)]82/// #[solidity_interface(rename_selector = "mul")]83/// fn mul(&mut self, a: uint32, b: uint32) -> Result<uint32> {84/// Ok(a.checked_mul(b).ok_or("overflow")?)85/// }86/// }87/// ```88pub use evm_coder_procedural::solidity_interface;89/// See [`solidity_interface`]90pub use evm_coder_procedural::solidity;91/// See [`solidity_interface`]92pub use evm_coder_procedural::weight;9394/// Derives [`ToLog`] for enum95///96/// Selectors will be derived from variant names, there is currently no way to have custom naming97/// for them98///99/// `#[indexed]`100/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data101pub use evm_coder_procedural::ToLog;102103// Api of those modules shouldn't be consumed directly, it is only exported for usage in proc macros104#[doc(hidden)]105pub mod events;106#[doc(hidden)]28pub mod solidity;107pub mod solidity;2910830/// Solidity type definitions109/// Solidity type definitions (aliases from solidity name to rust type)110/// To be used in [`solidity_interface`] definitions, to make sure there is no111/// type conflict between Rust code and generated definitions31pub mod types {112pub mod types {32 #![allow(non_camel_case_types)]113 #![allow(non_camel_case_types, missing_docs)]3311434 #[cfg(not(feature = "std"))]115 #[cfg(not(feature = "std"))]35 use alloc::{vec::Vec};116 use alloc::{vec::Vec};54 pub type string = ::std::string::String;135 pub type string = ::std::string::String;55 pub type bytes = Vec<u8>;136 pub type bytes = Vec<u8>;56137138 /// Solidity doesn't have `void` type, however we have special implementation139 /// for empty tuple return type57 pub type void = ();140 pub type void = ();5814159 //#region Special types142 //#region Special types63 pub type caller = address;146 pub type caller = address;64 //#endregion147 //#endregion65148149 /// Ethereum typed call message, similar to solidity150 /// `msg` object.66 pub struct Msg<C> {151 pub struct Msg<C> {67 pub call: C,152 pub call: C,153 /// Address of user, which called this contract.68 pub caller: H160,154 pub caller: H160,155 /// Payment amount to contract.156 /// Contract should reject payment, if target call is not payable,157 /// and there is no `receiver()` function defined.69 pub value: U256,158 pub value: U256,70 }159 }71}160}72161162/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro73pub trait Call: Sized {163pub trait Call: Sized {164 /// Parse call buffer into typed call enum74 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;165 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;75}166}76167168/// Intended to be used as `#[weight]` output type169/// Should be same between evm-coder and substrate to avoid confusion170///171/// Isn't same thing as gas, some mapping is required between those types77pub type Weight = u64;172pub type Weight = u64;78173174/// In substrate, we have benchmarking, which allows175/// us to not rely on gas metering, but instead predict amount of gas to execute call79pub trait Weighted: Call {176pub trait Weighted: Call {177 /// Predict weight of this call80 fn weight(&self) -> DispatchInfo;178 fn weight(&self) -> DispatchInfo;81}179}82180181/// Type callable with ethereum message, may be implemented by [`solidity_interface`] macro182/// on interface implementation, or for externally-owned real EVM contract83pub trait Callable<C: Call> {183pub trait Callable<C: Call> {184 /// Call contract using specified call data84 fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;185 fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;85}186}8618787/// Implementation is implicitly provided for all interfaces188/// Implementation of ERC165 is implicitly generated for all interfaces in [`solidity_interface`],189/// this structure holds parsed data for ERC165Call subvariant88///190///89/// Note: no Callable implementation is provided191/// Note: no [`Callable`] implementation is provided, call implementation is inlined into every192/// implementing contract193///194/// See <https://eips.ethereum.org/EIPS/eip-165>90#[derive(Debug)]195#[derive(Debug)]91pub enum ERC165Call {196pub enum ERC165Call {197 /// ERC165 provides single method, which returns true, if contract198 /// implements specified interface92 SupportsInterface { interface_id: types::bytes4 },199 SupportsInterface {200 /// Requested interface201 interface_id: types::bytes4,202 },93}203}9420495impl ERC165Call {205impl ERC165Call {206 /// ERC165 selector is provided by standard96 pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);207 pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);97}208}98209crates/evm-coder/src/solidity.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation detail of [`crate::solidity_interface`] macro code-generation.18//! You should not rely on any public item from this module, as it is only intended to be used19//! by procedural macro, API and output format may be changed at any time.20//!21//! Purpose of this module is to receive solidity contract definition in module-specified22//! format, and then output string, representing interface of this contract in solidity language162317#[cfg(not(feature = "std"))]24#[cfg(not(feature = "std"))]18use alloc::{25use alloc::{string::String, vec::Vec, collections::BTreeMap, format};19 string::String,20 vec::Vec,21 collections::{BTreeSet, BTreeMap},22 format,23};24#[cfg(feature = "std")]26#[cfg(feature = "std")]25use std::collections::{BTreeSet, BTreeMap};27use std::collections::BTreeMap;26use core::{28use core::{27 fmt::{self, Write},29 fmt::{self, Write},28 marker::PhantomData,30 marker::PhantomData,29 cell::{Cell, RefCell},31 cell::{Cell, RefCell},32 cmp::Reverse,30};33};31use impl_trait_for_tuples::impl_for_tuples;34use impl_trait_for_tuples::impl_for_tuples;32use crate::types::*;35use crate::types::*;333634#[derive(Default)]37#[derive(Default)]35pub struct TypeCollector {38pub struct TypeCollector {39 /// Code => id40 /// id ordering is required to perform topo-sort on the resulting data36 structs: RefCell<BTreeSet<string>>,41 structs: RefCell<BTreeMap<string, usize>>,37 anonymous: RefCell<BTreeMap<Vec<string>, usize>>,42 anonymous: RefCell<BTreeMap<Vec<string>, usize>>,38 id: Cell<usize>,43 id: Cell<usize>,39}44}42 Self::default()47 Self::default()43 }48 }44 pub fn collect(&self, item: string) {49 pub fn collect(&self, item: string) {50 let id = self.next_id();45 self.structs.borrow_mut().insert(item);51 self.structs.borrow_mut().insert(item, id);46 }52 }47 pub fn next_id(&self) -> usize {53 pub fn next_id(&self) -> usize {48 let v = self.id.get();54 let v = self.id.get();56 }62 }57 let id = self.next_id();63 let id = self.next_id();58 let mut str = String::new();64 let mut str = String::new();59 writeln!(str, "// Anonymous struct").unwrap();65 writeln!(str, "/// @dev anonymous struct").unwrap();60 writeln!(str, "struct Tuple{} {{", id).unwrap();66 writeln!(str, "struct Tuple{} {{", id).unwrap();61 for (i, name) in names.iter().enumerate() {67 for (i, name) in names.iter().enumerate() {62 writeln!(str, "\t{} field_{};", name, i).unwrap();68 writeln!(str, "\t{} field_{};", name, i).unwrap();66 self.anonymous.borrow_mut().insert(names, id);72 self.anonymous.borrow_mut().insert(names, id);67 format!("Tuple{}", id)73 format!("Tuple{}", id)68 }74 }69 pub fn finish(self) -> BTreeSet<string> {75 pub fn finish(self) -> Vec<string> {70 self.structs.into_inner()76 let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();77 data.sort_by_key(|(_, id)| Reverse(*id));78 data.into_iter().map(|(code, _)| code).collect()71 }79 }72}80}738174pub trait SolidityTypeName: 'static {82pub trait SolidityTypeName: 'static {75 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;83 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;84 /// "simple" types are stored inline, no `memory` modifier should be used in solidity76 fn is_simple() -> bool;85 fn is_simple() -> bool;77 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;86 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;87 /// Specialization78 fn is_void() -> bool {88 fn is_void() -> bool {79 false89 false80 }90 }125}135}126136127mod sealed {137mod sealed {138 /// Not every type should be directly placed in vec.139 /// Vec encoding is not memory efficient, as every item will be padded140 /// to 32 bytes.141 /// Instead you should use specialized types (`bytes` in case of `Vec<u8>`)128 pub trait CanBePlacedInVec {}142 pub trait CanBePlacedInVec {}129}143}130144180 fn is_simple() -> bool {194 fn is_simple() -> bool {181 false195 false182 }196 }197 #[allow(unused_assignments)]183 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {198 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {184 write!(writer, "{}(", tc.collect_tuple::<Self>())?;199 write!(writer, "{}(", tc.collect_tuple::<Self>())?;200 let mut first = true;185 $(201 $(202 if !first {203 write!(writer, ",")?;204 } else {205 first = false;206 }186 <$ident>::solidity_default(writer, tc)?;207 <$ident>::solidity_default(writer, tc)?;187 )*208 )*188 write!(writer, ")")209 write!(writer, ")")395}416}396pub struct SolidityFunction<A, R> {417pub struct SolidityFunction<A, R> {397 pub docs: &'static [&'static str],418 pub docs: &'static [&'static str],398 pub selector: &'static str,419 pub selector_str: &'static str,420 pub selector: u32,399 pub name: &'static str,421 pub name: &'static str,400 pub args: A,422 pub args: A,401 pub result: R,423 pub result: R,409 tc: &TypeCollector,431 tc: &TypeCollector,410 ) -> fmt::Result {432 ) -> fmt::Result {411 for doc in self.docs {433 for doc in self.docs {412 writeln!(writer, "\t//{}", doc)?;434 writeln!(writer, "\t///{}", doc)?;413 }435 }414 if !self.docs.is_empty() {415 writeln!(writer, "\t//")?;436 writeln!(416 }437 writer,438 "\t/// @dev EVM selector for this function is: 0x{:0>8x},",439 self.selector440 )?;417 writeln!(writer, "\t// Selector: {}", self.selector)?;441 writeln!(writer, "\t/// or in textual repr: {}", self.selector_str)?;418 write!(writer, "\tfunction {}(", self.name)?;442 write!(writer, "\tfunction {}(", self.name)?;419 self.args.solidity_name(writer, tc)?;443 self.args.solidity_name(writer, tc)?;420 write!(writer, ")")?;444 write!(writer, ")")?;455 }479 }456}480}457481458#[impl_for_tuples(0, 24)]482#[impl_for_tuples(0, 48)]459impl SolidityFunctions for Tuple {483impl SolidityFunctions for Tuple {460 for_tuples!( where #( Tuple: SolidityFunctions ),* );484 for_tuples!( where #( Tuple: SolidityFunctions ),* );461485474}498}475499476pub struct SolidityInterface<F: SolidityFunctions> {500pub struct SolidityInterface<F: SolidityFunctions> {501 pub docs: &'static [&'static str],477 pub selector: bytes4,502 pub selector: bytes4,478 pub name: &'static str,503 pub name: &'static str,479 pub is: &'static [&'static str],504 pub is: &'static [&'static str],488 tc: &TypeCollector,513 tc: &TypeCollector,489 ) -> fmt::Result {514 ) -> fmt::Result {490 const ZERO_BYTES: [u8; 4] = [0; 4];515 const ZERO_BYTES: [u8; 4] = [0; 4];516 for doc in self.docs {517 writeln!(out, "///{}", doc)?;518 }491 if self.selector != ZERO_BYTES {519 if self.selector != ZERO_BYTES {492 writeln!(520 writeln!(493 out,521 out,494 "// Selector: {:0>8x}",522 "/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",495 u32::from_be_bytes(self.selector)523 u32::from_be_bytes(self.selector)496 )?;524 )?;497 }525 }crates/evm-coder/tests/generics.rsdiffbeforeafterboth191920struct Generic<T>(PhantomData<T>);20struct Generic<T>(PhantomData<T>);212122#[solidity_interface(name = "GenericIs")]22#[solidity_interface(name = GenericIs)]23impl<T> Generic<T> {23impl<T> Generic<T> {24 fn test_1(&self) -> Result<uint256> {24 fn test_1(&self) -> Result<uint256> {25 unreachable!()25 unreachable!()26 }26 }27}27}282829#[solidity_interface(name = "Generic", is(GenericIs))]29#[solidity_interface(name = Generic, is(GenericIs))]30impl<T: Into<u32>> Generic<T> {30impl<T: Into<u32>> Generic<T> {31 fn test_2(&self) -> Result<uint256> {31 fn test_2(&self) -> Result<uint256> {32 unreachable!()32 unreachable!()353536generate_stubgen!(gen_iface, GenericCall<()>, false);36generate_stubgen!(gen_iface, GenericCall<()>, false);373738#[solidity_interface(name = "GenericWhere")]38#[solidity_interface(name = GenericWhere)]39impl<T> Generic<T>39impl<T> Generic<T>40where40where41 T: core::fmt::Debug,41 T: core::fmt::Debug,crates/evm-coder/tests/random.rsdiffbeforeafterboth161617#![allow(dead_code)] // This test only checks that macros is not panicking17#![allow(dead_code)] // This test only checks that macros is not panicking181819use evm_coder::{ToLog, execution::Result, solidity_interface, types::*};19use evm_coder::{ToLog, execution::Result, solidity_interface, types::*, solidity, weight};20use evm_coder_macros::{solidity, weight};212022struct Impls;21struct Impls;232224#[solidity_interface(name = "OurInterface")]23#[solidity_interface(name = OurInterface)]25impl Impls {24impl Impls {26 fn fn_a(&self, _input: uint256) -> Result<bool> {25 fn fn_a(&self, _input: uint256) -> Result<bool> {27 unreachable!()26 unreachable!()28 }27 }29}28}302931#[solidity_interface(name = "OurInterface1")]30#[solidity_interface(name = OurInterface1)]32impl Impls {31impl Impls {33 fn fn_b(&self, _input: uint128) -> Result<uint32> {32 fn fn_b(&self, _input: uint128) -> Result<uint32> {34 unreachable!()33 unreachable!()48}47}494850#[solidity_interface(49#[solidity_interface(51 name = "OurInterface2",50 name = OurInterface2,52 is(OurInterface),51 is(OurInterface),53 inline_is(OurInterface1),52 inline_is(OurInterface1),54 events(OurEvents)53 events(OurEvents)80 }79 }81}80}8182#[solidity_interface(83 name = ValidSelector,84 expect_selector = 0x00000000,85)]86impl Impls {}8287crates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth181819struct ERC20;19struct ERC20;202021#[solidity_interface(name = "ERC20")]21#[solidity_interface(name = ERC20)]22impl ERC20 {22impl ERC20 {23 fn decimals(&self) -> Result<uint8> {23 fn decimals(&self) -> Result<uint8> {24 unreachable!()24 unreachable!()node/cli/src/chain_spec.rsdiffbeforeafterboth123 .public()123 .public()124}124}125125126/// The extensions for the [`ChainSpec`].126/// The extensions for the [`DefaultChainSpec`].127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]128#[serde(deny_unknown_fields)]128#[serde(deny_unknown_fields)]129pub struct Extensions {129pub struct Extensions {pallets/common/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [0.1.8] - 2022-08-2467## Added8 - Eth methods for collection9 + set_collection_sponsor_substrate10 + has_collection_pending_sponsor11 + remove_collection_sponsor12 + get_collection_sponsor13- Add convert function from `uint256` to `CrossAccountId`.1415## [0.1.7] - 2022-08-191617### Added1819 - Add convert funtion from `CrossAccountId` to eth `uint256`.2021 22## [0.1.6] - 2022-08-162324### Added25- New Ethereum API methods: changeOwner, changeOwner(Substrate) and verifyOwnerOrAdmin(Substrate).265<!-- bureaucrate goes here -->27<!-- bureaucrate goes here -->6## [v0.1.5] 2022-08-1628## [v0.1.5] 2022-08-16729pallets/common/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-common"2name = "pallet-common"3version = "0.1.5"3version = "0.1.8"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/common/src/erc.rsdiffbeforeafterboth26use sp_std::vec::Vec;26use sp_std::vec::Vec;27use up_data_structs::{27use up_data_structs::{28 AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,28 AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,29 SponsoringRateLimit,29 SponsoringRateLimit, SponsorshipState,30};30};31use alloc::format;31use alloc::format;323233use crate::{Pallet, CollectionHandle, Config, CollectionProperties};33use crate::{34 Pallet, CollectionHandle, Config, CollectionProperties,35 eth::{convert_cross_account_to_uint256, convert_uint256_to_cross_account},36};343735/// Events for ethereum collection helper.38/// Events for ethereum collection helper.36#[derive(ToLog)]39#[derive(ToLog)]57}60}586159/// @title A contract that allows you to work with collections.62/// @title A contract that allows you to work with collections.60#[solidity_interface(name = "Collection")]63#[solidity_interface(name = Collection)]61impl<T: Config> CollectionHandle<T>64impl<T: Config> CollectionHandle<T>62where65where63 T::AccountId: From<[u8; 32]>,66 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,64{67{65 /// Set collection property.68 /// Set collection property.66 ///69 ///125 save(self)128 save(self)126 }129 }127130131 /// Set the substrate sponsor of the collection.132 ///133 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.134 ///135 /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.136 fn set_collection_sponsor_substrate(137 &mut self,138 caller: caller,139 sponsor: uint256,140 ) -> Result<void> {141 check_is_owner_or_admin(caller, self)?;142143 let sponsor = convert_uint256_to_cross_account::<T>(sponsor);144 self.set_sponsor(sponsor.as_sub().clone())145 .map_err(dispatch_to_evm::<T>)?;146 save(self)147 }148149 // /// Whether there is a pending sponsor.150 fn has_collection_pending_sponsor(&self) -> Result<bool> {151 Ok(matches!(152 self.collection.sponsorship,153 SponsorshipState::Unconfirmed(_)154 ))155 }156128 /// Collection sponsorship confirmation.157 /// Collection sponsorship confirmation.129 ///158 ///130 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.159 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.139 save(self)168 save(self)140 }169 }141170171 /// Remove collection sponsor.172 fn remove_collection_sponsor(&mut self, caller: caller) -> Result<void> {173 check_is_owner_or_admin(caller, self)?;174 self.remove_sponsor().map_err(dispatch_to_evm::<T>)?;175 save(self)176 }177178 /// Get current sponsor.179 ///180 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.181 fn get_collection_sponsor(&self) -> Result<(address, uint256)> {182 let sponsor = match self.collection.sponsorship.sponsor() {183 Some(sponsor) => sponsor,184 None => return Ok(Default::default()),185 };186 let sponsor = T::CrossAccountId::from_sub(sponsor.clone());187 let result: (address, uint256) = if sponsor.is_canonical_substrate() {188 let sponsor = convert_cross_account_to_uint256::<T>(&sponsor);189 (Default::default(), sponsor)190 } else {191 let sponsor = *sponsor.as_eth();192 (sponsor, Default::default())193 };194 Ok(result)195 }196142 /// Set limits for the collection.197 /// Set limits for the collection.143 /// @dev Throws error if limit not found.198 /// @dev Throws error if limit not found.144 /// @param limit Name of the limit. Valid names:199 /// @param limit Name of the limit. Valid names:225 }280 }226281227 /// Add collection admin by substrate address.282 /// Add collection admin by substrate address.228 /// @param new_admin Substrate administrator address.283 /// @param newAdmin Substrate administrator address.229 fn add_collection_admin_substrate(284 fn add_collection_admin_substrate(230 &mut self,285 &mut self,231 caller: caller,286 caller: caller,232 new_admin: uint256,287 new_admin: uint256,233 ) -> Result<void> {288 ) -> Result<void> {234 let caller = T::CrossAccountId::from_eth(caller);289 let caller = T::CrossAccountId::from_eth(caller);235 let mut new_admin_arr: [u8; 32] = Default::default();290 let new_admin = convert_uint256_to_cross_account::<T>(new_admin);236 new_admin.to_big_endian(&mut new_admin_arr);237 let account_id = T::AccountId::from(new_admin_arr);238 let new_admin = T::CrossAccountId::from_sub(account_id);239 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;291 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;240 Ok(())292 Ok(())241 }293 }248 admin: uint256,300 admin: uint256,249 ) -> Result<void> {301 ) -> Result<void> {250 let caller = T::CrossAccountId::from_eth(caller);302 let caller = T::CrossAccountId::from_eth(caller);251 let mut admin_arr: [u8; 32] = Default::default();303 let admin = convert_uint256_to_cross_account::<T>(admin);252 admin.to_big_endian(&mut admin_arr);253 let account_id = T::AccountId::from(admin_arr);254 let admin = T::CrossAccountId::from_sub(account_id);255 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;304 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;256 Ok(())305 Ok(())257 }306 }258307259 /// Add collection admin.308 /// Add collection admin.260 /// @param new_admin Address of the added administrator.309 /// @param newAdmin Address of the added administrator.261 fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result<void> {310 fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result<void> {262 let caller = T::CrossAccountId::from_eth(caller);311 let caller = T::CrossAccountId::from_eth(caller);263 let new_admin = T::CrossAccountId::from_eth(new_admin);312 let new_admin = T::CrossAccountId::from_eth(new_admin);267316268 /// Remove collection admin.317 /// Remove collection admin.269 ///318 ///270 /// @param new_admin Address of the removed administrator.319 /// @param admin Address of the removed administrator.271 fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result<void> {320 fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result<void> {272 let caller = T::CrossAccountId::from_eth(caller);321 let caller = T::CrossAccountId::from_eth(caller);273 let admin = T::CrossAccountId::from_eth(admin);322 let admin = T::CrossAccountId::from_eth(admin);414 ///463 ///415 /// @param user account to verify464 /// @param user account to verify416 /// @return "true" if account is the owner or admin465 /// @return "true" if account is the owner or admin417 fn verify_owner_or_admin(&self, user: address) -> Result<bool> {466 #[solidity(rename_selector = "isOwnerOrAdmin")]467 fn is_owner_or_admin_eth(&self, user: address) -> Result<bool> {418 Ok(check_is_owner_or_admin(user, self)468 let user = T::CrossAccountId::from_eth(user);419 .map(|_| true)469 Ok(self.is_owner_or_admin(&user))420 .unwrap_or(false))421 }470 }422471472 /// Check that substrate account is the owner or admin of the collection473 ///474 /// @param user account to verify475 /// @return "true" if account is the owner or admin476 fn is_owner_or_admin_substrate(&self, user: uint256) -> Result<bool> {477 let user = convert_uint256_to_cross_account::<T>(user);478 Ok(self.is_owner_or_admin(&user))479 }480423 /// Returns collection type481 /// Returns collection type424 ///482 ///425 /// @return `Fungible` or `NFT` or `ReFungible`483 /// @return `Fungible` or `NFT` or `ReFungible`431 };489 };432 Ok(mode.into())490 Ok(mode.into())433 }491 }492493 /// Changes collection owner to another account494 ///495 /// @dev Owner can be changed only by current owner496 /// @param newOwner new owner account497 fn set_owner(&mut self, caller: caller, new_owner: address) -> Result<void> {498 let caller = T::CrossAccountId::from_eth(caller);499 let new_owner = T::CrossAccountId::from_eth(new_owner);500 self.set_owner_internal(caller, new_owner)501 .map_err(dispatch_to_evm::<T>)502 }503504 /// Changes collection owner to another substrate account505 ///506 /// @dev Owner can be changed only by current owner507 /// @param newOwner new owner substrate account508 fn set_owner_substrate(&mut self, caller: caller, new_owner: uint256) -> Result<void> {509 let caller = T::CrossAccountId::from_eth(caller);510 let new_owner = convert_uint256_to_cross_account::<T>(new_owner);511 self.set_owner_internal(caller, new_owner)512 .map_err(dispatch_to_evm::<T>)513 }434}514}435515436fn check_is_owner_or_admin<T: Config>(516fn check_is_owner_or_admin<T: Config>(440 let caller = T::CrossAccountId::from_eth(caller);520 let caller = T::CrossAccountId::from_eth(caller);441 collection521 collection442 .check_is_owner_or_admin(&caller)522 .check_is_owner_or_admin(&caller)443 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;523 .map_err(dispatch_to_evm::<T>)?;444 Ok(caller)524 Ok(caller)445}525}446526447fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {527fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {448 // TODO possibly delete for the lack of transaction528 // TODO possibly delete for the lack of transaction529 collection.consume_store_writes(1)?;449 collection530 collection450 .check_is_internal()531 .check_is_internal()451 .map_err(dispatch_to_evm::<T>)?;532 .map_err(dispatch_to_evm::<T>)?;452 <crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());533 collection.save().map_err(dispatch_to_evm::<T>)?;453 Ok(())534 Ok(())454}535}455536pallets/common/src/eth.rsdiffbeforeafterboth161617//! The module contains a number of functions for converting and checking ethereum identifiers.17//! The module contains a number of functions for converting and checking ethereum identifiers.181819use up_data_structs::CollectionId;19use evm_coder::types::uint256;20pub use pallet_evm::account::{Config, CrossAccountId};20use sp_core::H160;21use sp_core::H160;22use up_data_structs::CollectionId;212322// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 124// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 123// TODO: Unhardcode prefix25// TODO: Unhardcode prefix48 address[0..16] == ETH_COLLECTION_PREFIX50 address[0..16] == ETH_COLLECTION_PREFIX49}51}5253/// Convert `CrossAccountId` to `uint256`.54pub fn convert_cross_account_to_uint256<T: Config>(from: &T::CrossAccountId) -> uint25655where56 T::AccountId: AsRef<[u8; 32]>,57{58 let slice = from.as_sub().as_ref();59 uint256::from_big_endian(slice)60}6162/// Convert `uint256` to `CrossAccountId`.63pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId64where65 T::AccountId: From<[u8; 32]>,66{67 let mut new_admin_arr = [0_u8; 32];68 from.to_big_endian(&mut new_admin_arr);69 let account_id = T::AccountId::from(new_admin_arr);70 T::CrossAccountId::from_sub(account_id)71}5072pallets/common/src/lib.rsdiffbeforeafterboth203 }203 }204204205 /// Save collection to storage.205 /// Save collection to storage.206 pub fn save(self) -> DispatchResult {206 pub fn save(&self) -> DispatchResult {207 <CollectionById<T>>::insert(self.id, self.collection);207 <CollectionById<T>>::insert(self.id, &self.collection);208 Ok(())208 Ok(())209 }209 }210210231 Ok(true)231 Ok(true)232 }232 }233234 /// Remove collection sponsor.235 pub fn remove_sponsor(&mut self) -> DispatchResult {236 self.collection.sponsorship = SponsorshipState::Disabled;237 Ok(())238 }233239234 /// Checks that the collection was created with, and must be operated upon through **Unique API**.240 /// Checks that the collection was created with, and must be operated upon through **Unique API**.235 /// Now check only the `external_collection` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.241 /// Now check only the `external_collection` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.303 Ok(())309 Ok(())304 }310 }311312 /// Changes collection owner to another account313 fn set_owner_internal(314 &mut self,315 caller: T::CrossAccountId,316 new_owner: T::CrossAccountId,317 ) -> DispatchResult {318 self.check_is_owner(&caller)?;319 self.collection.owner = new_owner.as_sub().clone();320 self.save()321 }305}322}306323307#[frame_support::pallet]324#[frame_support::pallet]721738722 /// Get the effective limits for the collection.739 /// Get the effective limits for the collection.723 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {740 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {724 let collection = <CollectionById<T>>::get(collection);741 let collection = <CollectionById<T>>::get(collection)?;725 if collection.is_none() {726 return None;727 }728729 let collection = collection.unwrap();730 let limits = collection.limits;742 let limits = collection.limits;731 let effective_limits = CollectionLimits {743 let effective_limits = CollectionLimits {732 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),744 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),pallets/evm-contract-helpers/CHANGELOG.mddiffbeforeafterboth1# Change Log23All notable changes to this project will be documented in this file.41<!-- bureaucrate goes here -->5## [v0.2.0] - 2022-08-1967### Added89 - Set arbitrary evm address as contract sponsor.10 - Ability to remove current sponsor.1112### Removed13 - Remove methods14 + sponsoring_enabled15 + toggle_sponsoring1617 ### Changed1819 - Change `toggle_sponsoring` to `self_sponsored_enable`.20212## [v0.1.2] 2022-08-1622## [v0.1.2] 2022-08-16323pallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-evm-contract-helpers"2name = "pallet-evm-contract-helpers"3version = "0.1.2"3version = "0.2.0"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/evm-contract-helpers/README.mddiffbeforeafterbothno changes
pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of magic contract161817use core::marker::PhantomData;19use core::marker::PhantomData;18use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};20use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};19use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};21use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder, dispatch_to_evm};20use pallet_evm::{22use pallet_evm::{21 ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,23 ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle,22 account::CrossAccountId,24 account::CrossAccountId,23};25};24use sp_core::H160;26use sp_core::H160;27use up_data_structs::SponsorshipState;25use crate::{28use crate::{26 AllowlistEnabled, Config, Owner, Pallet, SponsorBasket, SponsoringRateLimit, SponsoringModeT,29 AllowlistEnabled, Config, Owner, Pallet, SponsorBasket, SponsoringRateLimit, SponsoringModeT,30 Sponsoring,27};31};28use frame_support::traits::Get;32use frame_support::traits::Get;29use up_sponsorship::SponsorshipHandler;33use up_sponsorship::SponsorshipHandler;30use sp_std::vec::Vec;34use sp_std::vec::Vec;313536/// See [`ContractHelpersCall`]32struct ContractHelpers<T: Config>(SubstrateRecorder<T>);37pub struct ContractHelpers<T: Config>(SubstrateRecorder<T>);33impl<T: Config> WithRecorder<T> for ContractHelpers<T> {38impl<T: Config> WithRecorder<T> for ContractHelpers<T> {34 fn recorder(&self) -> &SubstrateRecorder<T> {39 fn recorder(&self) -> &SubstrateRecorder<T> {35 &self.040 &self.040 }45 }41}46}424748/// @title Magic contract, which allows users to reconfigure other contracts43#[solidity_interface(name = "ContractHelpers")]49#[solidity_interface(name = ContractHelpers)]44impl<T: Config> ContractHelpers<T> {50impl<T: Config> ContractHelpers<T>51where52 T::AccountId: AsRef<[u8; 32]>,53{54 /// Get user, which deployed specified contract55 /// @dev May return zero address in case if contract is deployed56 /// using uniquenetwork evm-migration pallet, or using other terms not57 /// intended by pallet-evm58 /// @dev Returns zero address if contract does not exists59 /// @param contractAddress Contract to get owner of60 /// @return address Owner of contract45 fn contract_owner(&self, contract_address: address) -> Result<address> {61 fn contract_owner(&self, contract_address: address) -> Result<address> {46 Ok(<Owner<T>>::get(contract_address))62 Ok(<Owner<T>>::get(contract_address))47 }63 }486465 /// Set sponsor.66 /// @param contractAddress Contract for which a sponsor is being established.67 /// @param sponsor User address who set as pending sponsor.49 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {68 fn set_sponsor(69 &mut self,70 caller: caller,71 contract_address: address,72 sponsor: address,73 ) -> Result<void> {74 self.recorder().consume_sload()?;75 self.recorder().consume_sstore()?;7650 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)77 Pallet::<T>::set_sponsor(78 &T::CrossAccountId::from_eth(caller),79 contract_address,80 &T::CrossAccountId::from_eth(sponsor),81 )82 .map_err(dispatch_to_evm::<T>)?;8384 Ok(())51 }85 }528653 /// Deprecated87 /// Set contract as self sponsored.88 ///89 /// @param contractAddress Contract for which a self sponsoring is being enabled.54 fn toggle_sponsoring(90 fn self_sponsored_enable(&mut self, caller: caller, contract_address: address) -> Result<void> {55 &mut self,56 caller: caller,57 contract_address: address,58 enabled: bool,59 ) -> Result<void> {60 <Pallet<T>>::ensure_owner(contract_address, caller)?;91 self.recorder().consume_sload()?;92 self.recorder().consume_sstore()?;9361 <Pallet<T>>::toggle_sponsoring(contract_address, enabled);94 Pallet::<T>::self_sponsored_enable(&T::CrossAccountId::from_eth(caller), contract_address)95 .map_err(dispatch_to_evm::<T>)?;9662 Ok(())97 Ok(())63 }98 }6499100 /// Remove sponsor.101 ///102 /// @param contractAddress Contract for which a sponsorship is being removed.65 fn set_sponsoring_mode(103 fn remove_sponsor(&mut self, caller: caller, contract_address: address) -> Result<void> {66 &mut self,104 self.recorder().consume_sload()?;67 caller: caller,105 self.recorder().consume_sstore()?;106107 Pallet::<T>::remove_sponsor(&T::CrossAccountId::from_eth(caller), contract_address)108 .map_err(dispatch_to_evm::<T>)?;109110 Ok(())111 }112113 /// Confirm sponsorship.114 ///115 /// @dev Caller must be same that set via [`setSponsor`].116 ///117 /// @param contractAddress Сontract for which need to confirm sponsorship.68 contract_address: address,118 fn confirm_sponsorship(&mut self, caller: caller, contract_address: address) -> Result<void> {69 mode: uint8,70 ) -> Result<void> {71 <Pallet<T>>::ensure_owner(contract_address, caller)?;119 self.recorder().consume_sload()?;72 let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?;120 self.recorder().consume_sstore()?;12173 <Pallet<T>>::set_sponsoring_mode(contract_address, mode);122 Pallet::<T>::confirm_sponsorship(&T::CrossAccountId::from_eth(caller), contract_address)123 .map_err(dispatch_to_evm::<T>)?;12474 Ok(())125 Ok(())75 }126 }127128 /// Get current sponsor.129 ///130 /// @param contractAddress The contract for which a sponsor is requested.131 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.132 fn get_sponsor(&self, contract_address: address) -> Result<(address, uint256)> {133 let sponsor =134 Pallet::<T>::get_sponsor(contract_address).ok_or("Contract has no sponsor")?;135 let result: (address, uint256) = if sponsor.is_canonical_substrate() {136 let sponsor = pallet_common::eth::convert_cross_account_to_uint256::<T>(&sponsor);137 (Default::default(), sponsor)138 } else {139 let sponsor = *sponsor.as_eth();140 (sponsor, Default::default())141 };142 Ok(result)143 }144145 /// Check tat contract has confirmed sponsor.146 ///147 /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.148 /// @return **true** if contract has confirmed sponsor.149 fn has_sponsor(&self, contract_address: address) -> Result<bool> {150 Ok(Pallet::<T>::get_sponsor(contract_address).is_some())151 }152153 /// Check tat contract has pending sponsor.154 ///155 /// @param contractAddress The contract for which the presence of a pending sponsor is checked.156 /// @return **true** if contract has pending sponsor.157 fn has_pending_sponsor(&self, contract_address: address) -> Result<bool> {158 Ok(match Sponsoring::<T>::get(contract_address) {159 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => false,160 SponsorshipState::Unconfirmed(_) => true,161 })162 }7616377 fn sponsoring_mode(&self, contract_address: address) -> Result<uint8> {164 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {78 Ok(<Pallet<T>>::sponsoring_mode(contract_address).to_eth())165 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)79 }166 }8016781 fn set_sponsoring_rate_limit(168 fn set_sponsoring_mode(82 &mut self,169 &mut self,83 caller: caller,170 caller: caller,84 contract_address: address,171 contract_address: address,172 // TODO: implement support for enums in evm-coder85 rate_limit: uint32,173 mode: uint8,86 ) -> Result<void> {174 ) -> Result<void> {175 self.recorder().consume_sload()?;176 self.recorder().consume_sstore()?;17787 <Pallet<T>>::ensure_owner(contract_address, caller)?;178 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;179 let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?;88 <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());180 <Pallet<T>>::set_sponsoring_mode(contract_address, mode);18189 Ok(())182 Ok(())90 }183 }91184185 /// Get current contract sponsoring rate limit186 /// @param contractAddress Contract to get sponsoring mode of187 /// @return uint32 Amount of blocks between two sponsored transactions92 fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {188 fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {93 Ok(<SponsoringRateLimit<T>>::get(contract_address)189 Ok(<SponsoringRateLimit<T>>::get(contract_address)94 .try_into()190 .try_into()95 .map_err(|_| "rate limit > u32::MAX")?)191 .map_err(|_| "rate limit > u32::MAX")?)96 }192 }97193194 /// Set contract sponsoring rate limit195 /// @dev Sponsoring rate limit - is a minimum amount of blocks that should196 /// pass between two sponsored transactions197 /// @param contractAddress Contract to change sponsoring rate limit of198 /// @param rateLimit Target rate limit199 /// @dev Only contract owner can change this setting98 fn allowed(&self, contract_address: address, user: address) -> Result<bool> {200 fn set_sponsoring_rate_limit(201 &mut self,202 caller: caller,203 contract_address: address,204 rate_limit: uint32,205 ) -> Result<void> {99 self.0.consume_sload()?;206 self.recorder().consume_sload()?;207 self.recorder().consume_sstore()?;208209 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;100 Ok(<Pallet<T>>::allowed(contract_address, user))210 <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());211 Ok(())101 }212 }102213214 /// Is specified user present in contract allow list215 /// @dev Contract owner always implicitly included216 /// @param contractAddress Contract to check allowlist of217 /// @param user User to check218 /// @return bool Is specified users exists in contract allowlist103 fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {219 fn allowed(&self, contract_address: address, user: address) -> Result<bool> {220 self.0.consume_sload()?;104 Ok(<AllowlistEnabled<T>>::get(contract_address))221 Ok(<Pallet<T>>::allowed(contract_address, user))105 }222 }106223224 /// Toggle user presence in contract allowlist225 /// @param contractAddress Contract to change allowlist of226 /// @param user Which user presence should be toggled227 /// @param isAllowed `true` if user should be allowed to be sponsored228 /// or call this contract, `false` otherwise229 /// @dev Only contract owner can change this setting107 fn toggle_allowlist(230 fn toggle_allowed(108 &mut self,231 &mut self,109 caller: caller,232 caller: caller,110 contract_address: address,233 contract_address: address,234 user: address,111 enabled: bool,235 is_allowed: bool,112 ) -> Result<void> {236 ) -> Result<void> {237 self.recorder().consume_sload()?;238 self.recorder().consume_sstore()?;239113 <Pallet<T>>::ensure_owner(contract_address, caller)?;240 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;114 <Pallet<T>>::toggle_allowlist(contract_address, enabled);241 <Pallet<T>>::toggle_allowed(contract_address, user, is_allowed);242115 Ok(())243 Ok(())116 }244 }117245246 /// Is this contract has allowlist access enabled247 /// @dev Allowlist always can have users, and it is used for two purposes:248 /// in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist249 /// in case of allowlist access enabled, only users from allowlist may call this contract250 /// @param contractAddress Contract to get allowlist access of251 /// @return bool Is specified contract has allowlist access enabled252 fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {253 Ok(<AllowlistEnabled<T>>::get(contract_address))254 }255256 /// Toggle contract allowlist access257 /// @param contractAddress Contract to change allowlist access of258 /// @param enabled Should allowlist access to be enabled?118 fn toggle_allowed(259 fn toggle_allowlist(119 &mut self,260 &mut self,120 caller: caller,261 caller: caller,121 contract_address: address,262 contract_address: address,122 user: address,123 allowed: bool,263 enabled: bool,124 ) -> Result<void> {264 ) -> Result<void> {265 self.recorder().consume_sload()?;266 self.recorder().consume_sstore()?;267125 <Pallet<T>>::ensure_owner(contract_address, caller)?;268 <Pallet<T>>::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::<T>)?;126 <Pallet<T>>::toggle_allowed(contract_address, user, allowed);269 <Pallet<T>>::toggle_allowlist(contract_address, enabled);127 Ok(())270 Ok(())128 }271 }129}272}130273274/// Implements [`OnMethodCall`], which delegates call to [`ContractHelpers`]131pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);275pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);132impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T> {276impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T>277where278 T::AccountId: AsRef<[u8; 32]>,279{133 fn is_reserved(contract: &sp_core::H160) -> bool {280 fn is_reserved(contract: &sp_core::H160) -> bool {134 contract == &T::ContractAddress::get()281 contract == &T::ContractAddress::get()167 }314 }168}315}169316317/// Hooks into contract creation, storing owner of newly deployed contract170pub struct HelpersOnCreate<T: Config>(PhantomData<*const T>);318pub struct HelpersOnCreate<T: Config>(PhantomData<*const T>);171impl<T: Config> OnCreate<T> for HelpersOnCreate<T> {319impl<T: Config> OnCreate<T> for HelpersOnCreate<T> {172 fn on_create(owner: H160, contract: H160) {320 fn on_create(owner: H160, contract: H160) {173 <Owner<T>>::insert(contract, owner);321 <Owner<T>>::insert(contract, owner);174 }322 }175}323}176324325/// Bridge to pallet-sponsoring177pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);326pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);178impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)>327impl<T: Config> SponsorshipHandler<T::CrossAccountId, (H160, Vec<u8>)>179 for HelpersContractSponsoring<T>328 for HelpersContractSponsoring<T>180{329{181 fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {330 fn get_sponsor(who: &T::CrossAccountId, call: &(H160, Vec<u8>)) -> Option<T::CrossAccountId> {331 let (contract_address, _) = call;182 let mode = <Pallet<T>>::sponsoring_mode(call.0);332 let mode = <Pallet<T>>::sponsoring_mode(*contract_address);183 if mode == SponsoringModeT::Disabled {333 if mode == SponsoringModeT::Disabled {184 return None;334 return None;185 }335 }336337 let sponsor = match <Pallet<T>>::get_sponsor(*contract_address) {338 Some(sponsor) => sponsor,339 None => return None,340 };186341187 if mode == SponsoringModeT::Allowlisted && !<Pallet<T>>::allowed(call.0, *who.as_eth()) {342 if mode == SponsoringModeT::Allowlisted343 && !<Pallet<T>>::allowed(*contract_address, *who.as_eth())344 {188 return None;345 return None;189 }346 }190 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;347 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;191348192 if let Some(last_tx_block) = <SponsorBasket<T>>::get(&call.0, who.as_eth()) {349 if let Some(last_tx_block) = <SponsorBasket<T>>::get(contract_address, who.as_eth()) {193 let limit = <SponsoringRateLimit<T>>::get(&call.0);350 let limit = <SponsoringRateLimit<T>>::get(contract_address);194351195 let timeout = last_tx_block + limit;352 let timeout = last_tx_block + limit;196 if block_number < timeout {353 if block_number < timeout {197 return None;354 return None;198 }355 }199 }356 }200357201 <SponsorBasket<T>>::insert(&call.0, who.as_eth(), block_number);358 <SponsorBasket<T>>::insert(contract_address, who.as_eth(), block_number);202359203 let sponsor = T::CrossAccountId::from_eth(call.0);204 Some(sponsor)360 Some(sponsor)205 }361 }206}362}pallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617#![doc = include_str!("../README.md")]17#![cfg_attr(not(feature = "std"), no_std)]18#![cfg_attr(not(feature = "std"), no_std)]19#![deny(missing_docs)]182019use codec::{Decode, Encode, MaxEncodedLen};21use codec::{Decode, Encode, MaxEncodedLen};20pub use pallet::*;22pub use pallet::*;25#[frame_support::pallet]27#[frame_support::pallet]26pub mod pallet {28pub mod pallet {27 pub use super::*;29 pub use super::*;28 use evm_coder::execution::Result;30 use frame_support::pallet_prelude::*;29 use frame_support::pallet_prelude::*;31 use pallet_evm_coder_substrate::DispatchResult;30 use sp_core::H160;32 use sp_core::H160;33 use pallet_evm::account::CrossAccountId;34 use up_data_structs::SponsorshipState;313532 #[pallet::config]36 #[pallet::config]33 pub trait Config:37 pub trait Config:34 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config38 frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config35 {39 {40 /// Address, under which magic contract will be available36 type ContractAddress: Get<H160>;41 type ContractAddress: Get<H160>;42 /// In case of enabled sponsoring, but no sponsoring rate limit set,43 /// this value will be used implicitly37 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;44 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;38 }45 }394640 #[pallet::error]47 #[pallet::error]41 pub enum Error<T> {48 pub enum Error<T> {42 /// This method is only executable by owner49 /// This method is only executable by contract owner43 NoPermission,50 NoPermission,5152 /// No pending sponsor for contract.53 NoPendingSponsor,44 }54 }455546 #[pallet::pallet]56 #[pallet::pallet]47 #[pallet::generate_store(pub(super) trait Store)]57 #[pallet::generate_store(pub(super) trait Store)]48 pub struct Pallet<T>(_);58 pub struct Pallet<T>(_);495960 /// Store owner for contract.61 ///62 /// * **Key** - contract address.63 /// * **Value** - owner for contract.50 #[pallet::storage]64 #[pallet::storage]51 pub(super) type Owner<T: Config> =65 pub(super) type Owner<T: Config> =52 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;66 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;56 pub(super) type SelfSponsoring<T: Config> =70 pub(super) type SelfSponsoring<T: Config> =57 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;71 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;587273 /// Store for contract sponsorship state.74 ///75 /// * **Key** - contract address.76 /// * **Value** - sponsorship state.77 #[pallet::storage]78 pub(super) type Sponsoring<T: Config> = StorageMap<79 Hasher = Twox64Concat,80 Key = H160,81 Value = SponsorshipState<T::CrossAccountId>,82 QueryKind = ValueQuery,83 >;8485 /// Store for sponsoring mode.86 ///87 /// ### Usage88 /// Prefer to delete collection from storage if mode chaged to [`Disabled`](SponsoringModeT::Disabled).89 ///90 /// * **Key** - contract address.91 /// * **Value** - [`sponsoring mode`](SponsoringModeT).59 #[pallet::storage]92 #[pallet::storage]60 pub(super) type SponsoringMode<T: Config> =93 pub(super) type SponsoringMode<T: Config> =61 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;94 StorageMap<Hasher = Twox128, Key = H160, Value = SponsoringModeT, QueryKind = OptionQuery>;629596 /// Storage for sponsoring rate limit in blocks.97 ///98 /// * **Key** - contract address.99 /// * **Value** - amount of sponsored blocks.63 #[pallet::storage]100 #[pallet::storage]64 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<101 pub(super) type SponsoringRateLimit<T: Config> = StorageMap<65 Hasher = Twox128,102 Hasher = Twox128,69 OnEmpty = T::DefaultSponsoringRateLimit,106 OnEmpty = T::DefaultSponsoringRateLimit,70 >;107 >;71108109 /// Storage for last sponsored block.110 ///111 /// * **Key1** - contract address.112 /// * **Key2** - sponsored user address.113 /// * **Value** - last sponsored block number.72 #[pallet::storage]114 #[pallet::storage]73 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<115 pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<74 Hasher1 = Twox128,116 Hasher1 = Twox128,79 QueryKind = OptionQuery,121 QueryKind = OptionQuery,80 >;122 >;81123124 /// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.125 ///126 /// ### Usage127 /// Prefer to delete collection from storage if mode chaged to non `Allowlisted`, than set **Value** to **false**.128 ///129 /// * **Key** - contract address.130 /// * **Value** - is contract in [`Allowlisted`](SponsoringModeT::Allowlisted) mode.82 #[pallet::storage]131 #[pallet::storage]83 pub(super) type AllowlistEnabled<T: Config> =132 pub(super) type AllowlistEnabled<T: Config> =84 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;133 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;85134135 /// Storage for users that allowed for sponsorship.136 ///137 /// ### Usage138 /// Prefer to delete record from storage if user no more allowed for sponsorship.139 ///140 /// * **Key1** - contract address.141 /// * **Key2** - user that allowed for sponsorship.142 /// * **Value** - allowance for sponsorship.86 #[pallet::storage]143 #[pallet::storage]87 pub(super) type Allowlist<T: Config> = StorageDoubleMap<144 pub(super) type Allowlist<T: Config> = StorageDoubleMap<88 Hasher1 = Twox128,145 Hasher1 = Twox128,94 >;151 >;9515296 impl<T: Config> Pallet<T> {153 impl<T: Config> Pallet<T> {154 /// Get contract owner.155 pub fn contract_owner(contract: H160) -> H160 {156 <Owner<T>>::get(contract)157 }158159 /// Set `sponsor` for `contract`.160 ///161 /// `sender` must be owner of contract.162 pub fn set_sponsor(163 sender: &T::CrossAccountId,164 contract: H160,165 sponsor: &T::CrossAccountId,166 ) -> DispatchResult {167 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;168 Sponsoring::<T>::insert(169 contract,170 SponsorshipState::<T::CrossAccountId>::Unconfirmed(sponsor.clone()),171 );172 Ok(())173 }174175 /// Set `contract` as self sponsored.176 ///177 /// `sender` must be owner of contract.178 pub fn self_sponsored_enable(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {179 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;180 Sponsoring::<T>::insert(181 contract,182 SponsorshipState::<T::CrossAccountId>::Confirmed(T::CrossAccountId::from_eth(183 contract,184 )),185 );186 Ok(())187 }188189 /// Remove sponsor for `contract`.190 ///191 /// `sender` must be owner of contract.192 pub fn remove_sponsor(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {193 Pallet::<T>::ensure_owner(contract, *sender.as_eth())?;194 Sponsoring::<T>::remove(contract);195 Ok(())196 }197198 /// Confirm sponsorship.199 ///200 /// `sender` must be same that set via [`set_sponsor`].201 pub fn confirm_sponsorship(sender: &T::CrossAccountId, contract: H160) -> DispatchResult {202 match Sponsoring::<T>::get(contract) {203 SponsorshipState::Unconfirmed(sponsor) => {204 ensure!(sponsor == *sender, Error::<T>::NoPermission);205 Sponsoring::<T>::insert(206 contract,207 SponsorshipState::<T::CrossAccountId>::Confirmed(sponsor),208 );209 Ok(())210 }211 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => {212 Err(Error::<T>::NoPendingSponsor.into())213 }214 }215 }216217 /// Get sponsor.218 pub fn get_sponsor(contract: H160) -> Option<T::CrossAccountId> {219 match Sponsoring::<T>::get(contract) {220 SponsorshipState::Disabled | SponsorshipState::Unconfirmed(_) => None,221 SponsorshipState::Confirmed(sponsor) => Some(sponsor),222 }223 }224225 /// Get current sponsoring mode, performing lazy migration from legacy storage97 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {226 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {98 <SponsoringMode<T>>::get(contract)227 <SponsoringMode<T>>::get(contract)99 .or_else(|| {228 .or_else(|| {102 .unwrap_or_default()231 .unwrap_or_default()103 }232 }233234 /// Reconfigure contract sponsoring mode104 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {235 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {105 if mode == SponsoringModeT::Disabled {236 if mode == SponsoringModeT::Disabled {106 <SponsoringMode<T>>::remove(contract);237 <SponsoringMode<T>>::remove(contract);110 <SelfSponsoring<T>>::remove(contract)241 <SelfSponsoring<T>>::remove(contract)111 }242 }112243113 pub fn toggle_sponsoring(contract: H160, enabled: bool) {244 /// Set duration between two sponsored contract calls114 Self::set_sponsoring_mode(115 contract,116 if enabled {117 SponsoringModeT::Allowlisted118 } else {119 SponsoringModeT::Disabled120 },121 )122 }123124 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {245 pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {125 <SponsoringRateLimit<T>>::insert(contract, rate_limit);246 <SponsoringRateLimit<T>>::insert(contract, rate_limit);126 }247 }127248249 /// Is user added to allowlist, or he is owner of specified contract128 pub fn allowed(contract: H160, user: H160) -> bool {250 pub fn allowed(contract: H160, user: H160) -> bool {129 <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user251 <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user130 }252 }131253254 /// Toggle contract allowlist access132 pub fn toggle_allowlist(contract: H160, enabled: bool) {255 pub fn toggle_allowlist(contract: H160, enabled: bool) {133 <AllowlistEnabled<T>>::insert(contract, enabled)256 <AllowlistEnabled<T>>::insert(contract, enabled)134 }257 }135258259 /// Toggle user presence in contract's allowlist136 pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {260 pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {137 <Allowlist<T>>::insert(contract, user, allowed);261 <Allowlist<T>>::insert(contract, user, allowed);138 }262 }139263264 /// Throw error if user is not allowed to reconfigure target contract140 pub fn ensure_owner(contract: H160, user: H160) -> Result<()> {265 pub fn ensure_owner(contract: H160, user: H160) -> DispatchResult {141 ensure!(<Owner<T>>::get(&contract) == user, "no permission");266 ensure!(<Owner<T>>::get(&contract) == user, Error::<T>::NoPermission);142 Ok(())267 Ok(())143 }268 }144 }269 }145}270}146271272/// Available contract sponsoring modes147#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]273#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]148pub enum SponsoringModeT {274pub enum SponsoringModeT {275 /// Sponsoring is disabled276 #[default]149 Disabled,277 Disabled,278 /// Only users from allowlist will be sponsored150 Allowlisted,279 Allowlisted,280 /// All users will be sponsored151 Generous,281 Generous,152}282}153283169 }299 }170}300}171172impl Default for SponsoringModeT {173 fn default() -> Self {174 Self::Disabled175 }176}177301pallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7contract Dummy {7contract Dummy {8 uint8 dummy;8 uint8 dummy;9 string stub_error = "this contract is implemented in native";9 string stub_error = "this contract is implemented in native";21 }21 }22}22}232324// Selector: 7b4866f924/// @title Magic contract, which allows users to reconfigure other contracts25/// @dev the ERC-165 identifier for this interface is 0xd77fab7025contract ContractHelpers is Dummy, ERC165 {26contract ContractHelpers is Dummy, ERC165 {26 // Selector: contractOwner(address) 5152b14c27 /// Get user, which deployed specified contract28 /// @dev May return zero address in case if contract is deployed29 /// using uniquenetwork evm-migration pallet, or using other terms not30 /// intended by pallet-evm31 /// @dev Returns zero address if contract does not exists32 /// @param contractAddress Contract to get owner of33 /// @return address Owner of contract34 /// @dev EVM selector for this function is: 0x5152b14c,35 /// or in textual repr: contractOwner(address)27 function contractOwner(address contractAddress)36 function contractOwner(address contractAddress)28 public37 public29 view38 view35 return 0x0000000000000000000000000000000000000000;44 return 0x0000000000000000000000000000000000000000;36 }45 }374638 // Selector: sponsoringEnabled(address) 6027dc6147 /// Set sponsor.48 /// @param contractAddress Contract for which a sponsor is being established.49 /// @param sponsor User address who set as pending sponsor.50 /// @dev EVM selector for this function is: 0xf01fba93,51 /// or in textual repr: setSponsor(address,address)39 function sponsoringEnabled(address contractAddress)52 function setSponsor(address contractAddress, address sponsor) public {40 public41 view42 returns (bool)43 {44 require(false, stub_error);53 require(false, stub_error);45 contractAddress;54 contractAddress;46 dummy;55 sponsor;47 return false;56 dummy = 0;48 }57 }495850 // Deprecated59 /// Set contract as self sponsored.51 //60 ///52 // Selector: toggleSponsoring(address,bool) fcac6d8661 /// @param contractAddress Contract for which a self sponsoring is being enabled.62 /// @dev EVM selector for this function is: 0x89f7d9ae,63 /// or in textual repr: selfSponsoredEnable(address)64 function selfSponsoredEnable(address contractAddress) public {65 require(false, stub_error);66 contractAddress;67 dummy = 0;68 }6970 /// Remove sponsor.71 ///72 /// @param contractAddress Contract for which a sponsorship is being removed.73 /// @dev EVM selector for this function is: 0xef784250,74 /// or in textual repr: removeSponsor(address)53 function toggleSponsoring(address contractAddress, bool enabled) public {75 function removeSponsor(address contractAddress) public {54 require(false, stub_error);76 require(false, stub_error);55 contractAddress;77 contractAddress;56 enabled;57 dummy = 0;78 dummy = 0;58 }79 }598060 // Selector: setSponsoringMode(address,uint8) fde8a56081 /// Confirm sponsorship.82 ///83 /// @dev Caller must be same that set via [`setSponsor`].84 ///85 /// @param contractAddress Сontract for which need to confirm sponsorship.86 /// @dev EVM selector for this function is: 0xabc00001,87 /// or in textual repr: confirmSponsorship(address)61 function setSponsoringMode(address contractAddress, uint8 mode) public {88 function confirmSponsorship(address contractAddress) public {62 require(false, stub_error);89 require(false, stub_error);63 contractAddress;90 contractAddress;64 mode;65 dummy = 0;91 dummy = 0;66 }92 }679368 // Selector: sponsoringMode(address) b70c726794 /// Get current sponsor.95 ///96 /// @param contractAddress The contract for which a sponsor is requested.97 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.98 /// @dev EVM selector for this function is: 0x743fc745,99 /// or in textual repr: getSponsor(address)69 function sponsoringMode(address contractAddress)100 function getSponsor(address contractAddress)70 public101 public71 view102 view72 returns (uint8)103 returns (Tuple0 memory)73 {104 {74 require(false, stub_error);105 require(false, stub_error);75 contractAddress;106 contractAddress;76 dummy;107 dummy;77 return 0;108 return Tuple0(0x0000000000000000000000000000000000000000, 0);78 }109 }7911080 // Selector: setSponsoringRateLimit(address,uint32) 77b6c908111 /// Check tat contract has confirmed sponsor.112 ///113 /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.114 /// @return **true** if contract has confirmed sponsor.115 /// @dev EVM selector for this function is: 0x97418603,116 /// or in textual repr: hasSponsor(address)117 function hasSponsor(address contractAddress) public view returns (bool) {118 require(false, stub_error);119 contractAddress;120 dummy;121 return false;122 }123124 /// Check tat contract has pending sponsor.125 ///126 /// @param contractAddress The contract for which the presence of a pending sponsor is checked.127 /// @return **true** if contract has pending sponsor.128 /// @dev EVM selector for this function is: 0x39b9b242,129 /// or in textual repr: hasPendingSponsor(address)130 function hasPendingSponsor(address contractAddress)131 public132 view133 returns (bool)134 {135 require(false, stub_error);136 contractAddress;137 dummy;138 return false;139 }140141 /// @dev EVM selector for this function is: 0x6027dc61,142 /// or in textual repr: sponsoringEnabled(address)143 function sponsoringEnabled(address contractAddress)144 public145 view146 returns (bool)147 {148 require(false, stub_error);149 contractAddress;150 dummy;151 return false;152 }153154 /// @dev EVM selector for this function is: 0xfde8a560,155 /// or in textual repr: setSponsoringMode(address,uint8)81 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)156 function setSponsoringMode(address contractAddress, uint8 mode) public {82 public83 {84 require(false, stub_error);157 require(false, stub_error);85 contractAddress;158 contractAddress;86 rateLimit;159 mode;87 dummy = 0;160 dummy = 0;88 }161 }89162163 /// Get current contract sponsoring rate limit164 /// @param contractAddress Contract to get sponsoring mode of165 /// @return uint32 Amount of blocks between two sponsored transactions166 /// @dev EVM selector for this function is: 0x610cfabd,90 // Selector: getSponsoringRateLimit(address) 610cfabd167 /// or in textual repr: getSponsoringRateLimit(address)91 function getSponsoringRateLimit(address contractAddress)168 function getSponsoringRateLimit(address contractAddress)92 public169 public93 view170 view99 return 0;176 return 0;100 }177 }101178102 // Selector: allowed(address,address) 5c658165179 /// Set contract sponsoring rate limit180 /// @dev Sponsoring rate limit - is a minimum amount of blocks that should181 /// pass between two sponsored transactions182 /// @param contractAddress Contract to change sponsoring rate limit of183 /// @param rateLimit Target rate limit184 /// @dev Only contract owner can change this setting185 /// @dev EVM selector for this function is: 0x77b6c908,186 /// or in textual repr: setSponsoringRateLimit(address,uint32)103 function allowed(address contractAddress, address user)187 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)104 public188 public105 view106 returns (bool)107 {189 {108 require(false, stub_error);190 require(false, stub_error);109 contractAddress;191 contractAddress;110 user;192 rateLimit;111 dummy;193 dummy = 0;112 return false;113 }194 }114195115 // Selector: allowlistEnabled(address) c772ef6c196 /// Is specified user present in contract allow list197 /// @dev Contract owner always implicitly included198 /// @param contractAddress Contract to check allowlist of199 /// @param user User to check200 /// @return bool Is specified users exists in contract allowlist201 /// @dev EVM selector for this function is: 0x5c658165,202 /// or in textual repr: allowed(address,address)116 function allowlistEnabled(address contractAddress)203 function allowed(address contractAddress, address user)117 public204 public118 view205 view119 returns (bool)206 returns (bool)120 {207 {121 require(false, stub_error);208 require(false, stub_error);122 contractAddress;209 contractAddress;210 user;123 dummy;211 dummy;124 return false;212 return false;125 }213 }126214127 // Selector: toggleAllowlist(address,bool) 36de20f5215 /// Toggle user presence in contract allowlist216 /// @param contractAddress Contract to change allowlist of217 /// @param user Which user presence should be toggled218 /// @param isAllowed `true` if user should be allowed to be sponsored219 /// or call this contract, `false` otherwise220 /// @dev Only contract owner can change this setting221 /// @dev EVM selector for this function is: 0x4706cc1c,222 /// or in textual repr: toggleAllowed(address,address,bool)128 function toggleAllowlist(address contractAddress, bool enabled) public {223 function toggleAllowed(224 address contractAddress,225 address user,226 bool isAllowed227 ) public {129 require(false, stub_error);228 require(false, stub_error);130 contractAddress;229 contractAddress;131 enabled;230 user;231 isAllowed;132 dummy = 0;232 dummy = 0;133 }233 }134234135 // Selector: toggleAllowed(address,address,bool) 4706cc1c235 /// Is this contract has allowlist access enabled236 /// @dev Allowlist always can have users, and it is used for two purposes:237 /// in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist238 /// in case of allowlist access enabled, only users from allowlist may call this contract239 /// @param contractAddress Contract to get allowlist access of240 /// @return bool Is specified contract has allowlist access enabled241 /// @dev EVM selector for this function is: 0xc772ef6c,242 /// or in textual repr: allowlistEnabled(address)136 function toggleAllowed(243 function allowlistEnabled(address contractAddress)244 public245 view246 returns (bool)247 {137 address contractAddress,248 require(false, stub_error);249 contractAddress;250 dummy;251 return false;252 }253254 /// Toggle contract allowlist access255 /// @param contractAddress Contract to change allowlist access of256 /// @param enabled Should allowlist access to be enabled?257 /// @dev EVM selector for this function is: 0x36de20f5,258 /// or in textual repr: toggleAllowlist(address,bool)138 address user,259 function toggleAllowlist(address contractAddress, bool enabled) public {139 bool allowed140 ) public {141 require(false, stub_error);260 require(false, stub_error);142 contractAddress;261 contractAddress;143 user;262 enabled;144 allowed;145 dummy = 0;263 dummy = 0;146 }264 }147}265}266267/// @dev anonymous struct268struct Tuple0 {269 address field_0;270 uint256 field_1;271}148272pallets/evm-migration/README.mddiffbeforeafterbothno changes
pallets/evm-migration/src/benchmarking.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![allow(missing_docs)]161817use super::{Call, Config, Pallet};19use super::{Call, Config, Pallet};18use frame_benchmarking::benchmarks;20use frame_benchmarking::benchmarks;pallets/evm-migration/src/lib.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617#![doc = include_str!("../README.md")]17#![cfg_attr(not(feature = "std"), no_std)]18#![cfg_attr(not(feature = "std"), no_std)]19#![deny(missing_docs)]182019pub use pallet::*;21pub use pallet::*;20#[cfg(feature = "runtime-benchmarks")]22#[cfg(feature = "runtime-benchmarks")]323433 #[pallet::config]35 #[pallet::config]34 pub trait Config: frame_system::Config + pallet_evm::Config {36 pub trait Config: frame_system::Config + pallet_evm::Config {37 /// Weights35 type WeightInfo: WeightInfo;38 type WeightInfo: WeightInfo;36 }39 }3740434644 #[pallet::error]47 #[pallet::error]45 pub enum Error<T> {48 pub enum Error<T> {49 /// Can only migrate to empty address.46 AccountNotEmpty,50 AccountNotEmpty,51 /// Migration of this account is not yet started, or already finished.47 AccountIsNotMigrating,52 AccountIsNotMigrating,48 }53 }4954535854 #[pallet::call]59 #[pallet::call]55 impl<T: Config> Pallet<T> {60 impl<T: Config> Pallet<T> {61 /// Start contract migration, inserts contract stub at target address,62 /// and marks account as pending, allowing to insert storage56 #[pallet::weight(<SelfWeightOf<T>>::begin())]63 #[pallet::weight(<SelfWeightOf<T>>::begin())]57 pub fn begin(origin: OriginFor<T>, address: H160) -> DispatchResult {64 pub fn begin(origin: OriginFor<T>, address: H160) -> DispatchResult {58 ensure_root(origin)?;65 ensure_root(origin)?;65 Ok(())72 Ok(())66 }73 }677475 /// Insert items into contract storage, this method can be called76 /// multiple times68 #[pallet::weight(<SelfWeightOf<T>>::set_data(data.len() as u32))]77 #[pallet::weight(<SelfWeightOf<T>>::set_data(data.len() as u32))]69 pub fn set_data(78 pub fn set_data(70 origin: OriginFor<T>,79 origin: OriginFor<T>,83 Ok(())92 Ok(())84 }93 }859495 /// Finish contract migration, allows it to be called.96 /// It is not possible to alter contract storage via [`Self::set_data`]97 /// after this call.86 #[pallet::weight(<SelfWeightOf<T>>::finish(code.len() as u32))]98 #[pallet::weight(<SelfWeightOf<T>>::finish(code.len() as u32))]87 pub fn finish(origin: OriginFor<T>, address: H160, code: Vec<u8>) -> DispatchResult {99 pub fn finish(origin: OriginFor<T>, address: H160, code: Vec<u8>) -> DispatchResult {88 ensure_root(origin)?;100 ensure_root(origin)?;97 }109 }98 }110 }99111112 /// Implements [`pallet_evm::OnMethodCall`], which reserves accounts with pending migration100 pub struct OnMethodCall<T>(PhantomData<T>);113 pub struct OnMethodCall<T>(PhantomData<T>);101 impl<T: Config> pallet_evm::OnMethodCall<T> for OnMethodCall<T> {114 impl<T: Config> pallet_evm::OnMethodCall<T> for OnMethodCall<T> {102 fn is_reserved(contract: &H160) -> bool {115 fn is_reserved(contract: &H160) -> bool {pallets/evm-migration/src/weights.rsdiffbeforeafterboth26#![cfg_attr(rustfmt, rustfmt_skip)]26#![cfg_attr(rustfmt, rustfmt_skip)]27#![allow(unused_parens)]27#![allow(unused_parens)]28#![allow(unused_imports)]28#![allow(unused_imports)]29#![allow(missing_docs)]29#![allow(clippy::unnecessary_cast)]30#![allow(clippy::unnecessary_cast)]303131use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};32use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};pallets/evm-transaction-payment/README.mddiffbeforeafterbothno changes
pallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617#![doc = include_str!("../README.md")]17#![cfg_attr(not(feature = "std"), no_std)]18#![cfg_attr(not(feature = "std"), no_std)]19#![deny(missing_docs)]182019use core::marker::PhantomData;21use core::marker::PhantomData;20use fp_evm::WithdrawReason;22use fp_evm::WithdrawReason;29pub mod pallet {31pub mod pallet {30 use super::*;32 use super::*;313332 use frame_support::traits::Currency;33 use sp_std::vec::Vec;34 use sp_std::vec::Vec;343535 #[pallet::config]36 #[pallet::config]36 pub trait Config: frame_system::Config + pallet_evm::account::Config {37 pub trait Config: frame_system::Config + pallet_evm::account::Config {38 /// Loosly-coupled handlers for evm call sponsoring37 type EvmSponsorshipHandler: SponsorshipHandler<Self::CrossAccountId, (H160, Vec<u8>)>;39 type EvmSponsorshipHandler: SponsorshipHandler<Self::CrossAccountId, (H160, Vec<u8>)>;38 type Currency: Currency<Self::AccountId>;39 }40 }404141 #[pallet::pallet]42 #[pallet::pallet]42 #[pallet::generate_store(pub(super) trait Store)]43 #[pallet::generate_store(pub(super) trait Store)]43 pub struct Pallet<T>(_);44 pub struct Pallet<T>(_);44}45}454647/// Implements [`fp_evm::TransactionValidityHack`], which provides sponsor address to pallet-evm46pub struct TransactionValidityHack<T: Config>(PhantomData<*const T>);48pub struct TransactionValidityHack<T: Config>(PhantomData<*const T>);47impl<T: Config> fp_evm::TransactionValidityHack<T::CrossAccountId> for TransactionValidityHack<T> {49impl<T: Config> fp_evm::TransactionValidityHack<T::CrossAccountId> for TransactionValidityHack<T> {48 fn who_pays_fee(origin: H160, reason: &WithdrawReason) -> Option<T::CrossAccountId> {50 fn who_pays_fee(origin: H160, reason: &WithdrawReason) -> Option<T::CrossAccountId> {pallets/fungible/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.4456## [0.1.5] - 2022-08-2978### Added910 - Implementation of `mint` and `mint_bulk` methods for ERC20 API.1112## [v0.1.4] - 2022-08-241314### Change15 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.165<!-- bureaucrate goes here -->17<!-- bureaucrate goes here -->6## [v0.1.3] 2022-08-1618## [v0.1.3] 2022-08-16719pallets/fungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-fungible"2name = "pallet-fungible"3version = "0.1.3"3version = "0.1.5"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/fungible/src/erc.rsdiffbeforeafterboth50 },50 },51}51}525253#[solidity_interface(name = "ERC20", events(ERC20Events))]53#[solidity_interface(name = ERC20, events(ERC20Events))]54impl<T: Config> FungibleHandle<T> {54impl<T: Config> FungibleHandle<T> {55 fn name(&self) -> Result<string> {55 fn name(&self) -> Result<string> {56 Ok(decode_utf16(self.name.iter().copied())56 Ok(decode_utf16(self.name.iter().copied())129 }129 }130}130}131132#[solidity_interface(name = ERC20Mintable)]133impl<T: Config> FungibleHandle<T> {134 /// Mint tokens for `to` account.135 /// @param to account that will receive minted tokens136 /// @param amount amount of tokens to mint137 #[weight(<SelfWeightOf<T>>::create_item())]138 fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {139 let caller = T::CrossAccountId::from_eth(caller);140 let to = T::CrossAccountId::from_eth(to);141 let amount = amount.try_into().map_err(|_| "amount overflow")?;142 let budget = self143 .recorder144 .weight_calls_budget(<StructureWeight<T>>::find_parent());145 <Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)146 .map_err(dispatch_to_evm::<T>)?;147 Ok(true)148 }149}131150132#[solidity_interface(name = "ERC20UniqueExtensions")]151#[solidity_interface(name = ERC20UniqueExtensions)]133impl<T: Config> FungibleHandle<T> {152impl<T: Config> FungibleHandle<T> {153 /// Burn tokens from account154 /// @dev Function that burns an `amount` of the tokens of a given account,155 /// deducting from the sender's allowance for said account.156 /// @param from The account whose tokens will be burnt.157 /// @param amount The amount that will be burnt.134 #[weight(<SelfWeightOf<T>>::burn_from())]158 #[weight(<SelfWeightOf<T>>::burn_from())]135 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {159 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {136 let caller = T::CrossAccountId::from_eth(caller);160 let caller = T::CrossAccountId::from_eth(caller);145 Ok(true)169 Ok(true)146 }170 }171172 /// Mint tokens for multiple accounts.173 /// @param amounts array of pairs of account address and amount174 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]175 fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {176 let caller = T::CrossAccountId::from_eth(caller);177 let budget = self178 .recorder179 .weight_calls_budget(<StructureWeight<T>>::find_parent());180 let amounts = amounts181 .into_iter()182 .map(|(to, amount)| {183 Ok((184 T::CrossAccountId::from_eth(to),185 amount.try_into().map_err(|_| "amount overflow")?,186 ))187 })188 .collect::<Result<_>>()?;189190 <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)191 .map_err(dispatch_to_evm::<T>)?;192 Ok(true)193 }147}194}148195149#[solidity_interface(196#[solidity_interface(150 name = "UniqueFungible",197 name = UniqueFungible,151 is(198 is(152 ERC20,199 ERC20,200 ERC20Mintable,153 ERC20UniqueExtensions,201 ERC20UniqueExtensions,154 via("CollectionHandle<T>", common_mut, Collection)202 Collection(common_mut, CollectionHandle<T>),155 )203 )156)]204)]157impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> {}205impl<T: Config> FungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}158206159generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);207generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);160generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);208generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);161209162impl<T: Config> CommonEvmHandler for FungibleHandle<T>210impl<T: Config> CommonEvmHandler for FungibleHandle<T>163where211where164 T::AccountId: From<[u8; 32]>,212 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,165{213{166 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");214 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");167215pallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7contract Dummy {7contract Dummy {8 uint8 dummy;8 uint8 dummy;9 string stub_error = "this contract is implemented in native";9 string stub_error = "this contract is implemented in native";21 }21 }22}22}232324// Inline24/// @title A contract that allows you to work with collections.25/// @dev the ERC-165 identifier for this interface is 0xe54be64026contract Collection is Dummy, ERC165 {27 /// Set collection property.28 ///29 /// @param key Property key.30 /// @param value Propery value.31 /// @dev EVM selector for this function is: 0x2f073f66,32 /// or in textual repr: setCollectionProperty(string,bytes)33 function setCollectionProperty(string memory key, bytes memory value)34 public35 {36 require(false, stub_error);37 key;38 value;39 dummy = 0;40 }4142 /// Delete collection property.43 ///44 /// @param key Property key.45 /// @dev EVM selector for this function is: 0x7b7debce,46 /// or in textual repr: deleteCollectionProperty(string)47 function deleteCollectionProperty(string memory key) public {48 require(false, stub_error);49 key;50 dummy = 0;51 }5253 /// Get collection property.54 ///55 /// @dev Throws error if key not found.56 ///57 /// @param key Property key.58 /// @return bytes The property corresponding to the key.59 /// @dev EVM selector for this function is: 0xcf24fd6d,60 /// or in textual repr: collectionProperty(string)61 function collectionProperty(string memory key)62 public63 view64 returns (bytes memory)65 {66 require(false, stub_error);67 key;68 dummy;69 return hex"";70 }7172 /// Set the sponsor of the collection.73 ///74 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.75 ///76 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.77 /// @dev EVM selector for this function is: 0x7623402e,78 /// or in textual repr: setCollectionSponsor(address)79 function setCollectionSponsor(address sponsor) public {80 require(false, stub_error);81 sponsor;82 dummy = 0;83 }8485 /// Set the substrate sponsor of the collection.86 ///87 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.88 ///89 /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.90 /// @dev EVM selector for this function is: 0xc74d6751,91 /// or in textual repr: setCollectionSponsorSubstrate(uint256)92 function setCollectionSponsorSubstrate(uint256 sponsor) public {93 require(false, stub_error);94 sponsor;95 dummy = 0;96 }9798 /// @dev EVM selector for this function is: 0x058ac185,99 /// or in textual repr: hasCollectionPendingSponsor()100 function hasCollectionPendingSponsor() public view returns (bool) {101 require(false, stub_error);102 dummy;103 return false;104 }105106 /// Collection sponsorship confirmation.107 ///108 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.109 /// @dev EVM selector for this function is: 0x3c50e97a,110 /// or in textual repr: confirmCollectionSponsorship()111 function confirmCollectionSponsorship() public {112 require(false, stub_error);113 dummy = 0;114 }115116 /// Remove collection sponsor.117 /// @dev EVM selector for this function is: 0x6e0326a3,118 /// or in textual repr: removeCollectionSponsor()119 function removeCollectionSponsor() public {120 require(false, stub_error);121 dummy = 0;122 }123124 /// Get current sponsor.125 ///126 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.127 /// @dev EVM selector for this function is: 0xb66bbc14,128 /// or in textual repr: getCollectionSponsor()129 function getCollectionSponsor() public view returns (Tuple6 memory) {130 require(false, stub_error);131 dummy;132 return Tuple6(0x0000000000000000000000000000000000000000, 0);133 }134135 /// Set limits for the collection.136 /// @dev Throws error if limit not found.137 /// @param limit Name of the limit. Valid names:138 /// "accountTokenOwnershipLimit",139 /// "sponsoredDataSize",140 /// "sponsoredDataRateLimit",141 /// "tokenLimit",142 /// "sponsorTransferTimeout",143 /// "sponsorApproveTimeout"144 /// @param value Value of the limit.145 /// @dev EVM selector for this function is: 0x6a3841db,146 /// or in textual repr: setCollectionLimit(string,uint32)147 function setCollectionLimit(string memory limit, uint32 value) public {148 require(false, stub_error);149 limit;150 value;151 dummy = 0;152 }153154 /// Set limits for the collection.155 /// @dev Throws error if limit not found.156 /// @param limit Name of the limit. Valid names:157 /// "ownerCanTransfer",158 /// "ownerCanDestroy",159 /// "transfersEnabled"160 /// @param value Value of the limit.161 /// @dev EVM selector for this function is: 0x993b7fba,162 /// or in textual repr: setCollectionLimit(string,bool)163 function setCollectionLimit(string memory limit, bool value) public {164 require(false, stub_error);165 limit;166 value;167 dummy = 0;168 }169170 /// Get contract address.171 /// @dev EVM selector for this function is: 0xf6b4dfb4,172 /// or in textual repr: contractAddress()173 function contractAddress() public view returns (address) {174 require(false, stub_error);175 dummy;176 return 0x0000000000000000000000000000000000000000;177 }178179 /// Add collection admin by substrate address.180 /// @param newAdmin Substrate administrator address.181 /// @dev EVM selector for this function is: 0x5730062b,182 /// or in textual repr: addCollectionAdminSubstrate(uint256)183 function addCollectionAdminSubstrate(uint256 newAdmin) public {184 require(false, stub_error);185 newAdmin;186 dummy = 0;187 }188189 /// Remove collection admin by substrate address.190 /// @param admin Substrate administrator address.191 /// @dev EVM selector for this function is: 0x4048fcf9,192 /// or in textual repr: removeCollectionAdminSubstrate(uint256)193 function removeCollectionAdminSubstrate(uint256 admin) public {194 require(false, stub_error);195 admin;196 dummy = 0;197 }198199 /// Add collection admin.200 /// @param newAdmin Address of the added administrator.201 /// @dev EVM selector for this function is: 0x92e462c7,202 /// or in textual repr: addCollectionAdmin(address)203 function addCollectionAdmin(address newAdmin) public {204 require(false, stub_error);205 newAdmin;206 dummy = 0;207 }208209 /// Remove collection admin.210 ///211 /// @param admin Address of the removed administrator.212 /// @dev EVM selector for this function is: 0xfafd7b42,213 /// or in textual repr: removeCollectionAdmin(address)214 function removeCollectionAdmin(address admin) public {215 require(false, stub_error);216 admin;217 dummy = 0;218 }219220 /// Toggle accessibility of collection nesting.221 ///222 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'223 /// @dev EVM selector for this function is: 0x112d4586,224 /// or in textual repr: setCollectionNesting(bool)225 function setCollectionNesting(bool enable) public {226 require(false, stub_error);227 enable;228 dummy = 0;229 }230231 /// Toggle accessibility of collection nesting.232 ///233 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'234 /// @param collections Addresses of collections that will be available for nesting.235 /// @dev EVM selector for this function is: 0x64872396,236 /// or in textual repr: setCollectionNesting(bool,address[])237 function setCollectionNesting(bool enable, address[] memory collections)238 public239 {240 require(false, stub_error);241 enable;242 collections;243 dummy = 0;244 }245246 /// Set the collection access method.247 /// @param mode Access mode248 /// 0 for Normal249 /// 1 for AllowList250 /// @dev EVM selector for this function is: 0x41835d4c,251 /// or in textual repr: setCollectionAccess(uint8)252 function setCollectionAccess(uint8 mode) public {253 require(false, stub_error);254 mode;255 dummy = 0;256 }257258 /// Add the user to the allowed list.259 ///260 /// @param user Address of a trusted user.261 /// @dev EVM selector for this function is: 0x67844fe6,262 /// or in textual repr: addToCollectionAllowList(address)263 function addToCollectionAllowList(address user) public {264 require(false, stub_error);265 user;266 dummy = 0;267 }268269 /// Remove the user from the allowed list.270 ///271 /// @param user Address of a removed user.272 /// @dev EVM selector for this function is: 0x85c51acb,273 /// or in textual repr: removeFromCollectionAllowList(address)274 function removeFromCollectionAllowList(address user) public {275 require(false, stub_error);276 user;277 dummy = 0;278 }279280 /// Switch permission for minting.281 ///282 /// @param mode Enable if "true".283 /// @dev EVM selector for this function is: 0x00018e84,284 /// or in textual repr: setCollectionMintMode(bool)285 function setCollectionMintMode(bool mode) public {286 require(false, stub_error);287 mode;288 dummy = 0;289 }290291 /// Check that account is the owner or admin of the collection292 ///293 /// @param user account to verify294 /// @return "true" if account is the owner or admin295 /// @dev EVM selector for this function is: 0x9811b0c7,296 /// or in textual repr: isOwnerOrAdmin(address)297 function isOwnerOrAdmin(address user) public view returns (bool) {298 require(false, stub_error);299 user;300 dummy;301 return false;302 }303304 /// Check that substrate account is the owner or admin of the collection305 ///306 /// @param user account to verify307 /// @return "true" if account is the owner or admin308 /// @dev EVM selector for this function is: 0x68910e00,309 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)310 function isOwnerOrAdminSubstrate(uint256 user) public view returns (bool) {311 require(false, stub_error);312 user;313 dummy;314 return false;315 }316317 /// Returns collection type318 ///319 /// @return `Fungible` or `NFT` or `ReFungible`320 /// @dev EVM selector for this function is: 0xd34b55b8,321 /// or in textual repr: uniqueCollectionType()322 function uniqueCollectionType() public returns (string memory) {323 require(false, stub_error);324 dummy = 0;325 return "";326 }327328 /// Changes collection owner to another account329 ///330 /// @dev Owner can be changed only by current owner331 /// @param newOwner new owner account332 /// @dev EVM selector for this function is: 0x13af4035,333 /// or in textual repr: setOwner(address)334 function setOwner(address newOwner) public {335 require(false, stub_error);336 newOwner;337 dummy = 0;338 }339340 /// Changes collection owner to another substrate account341 ///342 /// @dev Owner can be changed only by current owner343 /// @param newOwner new owner substrate account344 /// @dev EVM selector for this function is: 0xb212138f,345 /// or in textual repr: setOwnerSubstrate(uint256)346 function setOwnerSubstrate(uint256 newOwner) public {347 require(false, stub_error);348 newOwner;349 dummy = 0;350 }351}352353/// @dev the ERC-165 identifier for this interface is 0x63034ac5354contract ERC20UniqueExtensions is Dummy, ERC165 {355 /// Burn tokens from account356 /// @dev Function that burns an `amount` of the tokens of a given account,357 /// deducting from the sender's allowance for said account.358 /// @param from The account whose tokens will be burnt.359 /// @param amount The amount that will be burnt.360 /// @dev EVM selector for this function is: 0x79cc6790,361 /// or in textual repr: burnFrom(address,uint256)362 function burnFrom(address from, uint256 amount) public returns (bool) {363 require(false, stub_error);364 from;365 amount;366 dummy = 0;367 return false;368 }369370 /// Mint tokens for multiple accounts.371 /// @param amounts array of pairs of account address and amount372 /// @dev EVM selector for this function is: 0x1acf2d55,373 /// or in textual repr: mintBulk((address,uint256)[])374 function mintBulk(Tuple6[] memory amounts) public returns (bool) {375 require(false, stub_error);376 amounts;377 dummy = 0;378 return false;379 }380}381382/// @dev anonymous struct383struct Tuple6 {384 address field_0;385 uint256 field_1;386}387388/// @dev the ERC-165 identifier for this interface is 0x40c10f19389contract ERC20Mintable is Dummy, ERC165 {390 /// Mint tokens for `to` account.391 /// @param to account that will receive minted tokens392 /// @param amount amount of tokens to mint393 /// @dev EVM selector for this function is: 0x40c10f19,394 /// or in textual repr: mint(address,uint256)395 function mint(address to, uint256 amount) public returns (bool) {396 require(false, stub_error);397 to;398 amount;399 dummy = 0;400 return false;401 }402}403404/// @dev inlined interface25contract ERC20Events {405contract ERC20Events {26 event Transfer(address indexed from, address indexed to, uint256 value);406 event Transfer(address indexed from, address indexed to, uint256 value);27 event Approval(407 event Approval(31 );411 );32}412}3341334// Selector: 6cf113cd414/// @dev the ERC-165 identifier for this interface is 0x942e8b2235contract Collection is Dummy, ERC165 {36 // Set collection property.37 //38 // @param key Property key.39 // @param value Propery value.40 //41 // Selector: setCollectionProperty(string,bytes) 2f073f6642 function setCollectionProperty(string memory key, bytes memory value)43 public44 {45 require(false, stub_error);46 key;47 value;48 dummy = 0;49 }5051 // Delete collection property.52 //53 // @param key Property key.54 //55 // Selector: deleteCollectionProperty(string) 7b7debce56 function deleteCollectionProperty(string memory key) public {57 require(false, stub_error);58 key;59 dummy = 0;60 }6162 // Get collection property.63 //64 // @dev Throws error if key not found.65 //66 // @param key Property key.67 // @return bytes The property corresponding to the key.68 //69 // Selector: collectionProperty(string) cf24fd6d70 function collectionProperty(string memory key)71 public72 view73 returns (bytes memory)74 {75 require(false, stub_error);76 key;77 dummy;78 return hex"";79 }8081 // Set the sponsor of the collection.82 //83 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.84 //85 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.86 //87 // Selector: setCollectionSponsor(address) 7623402e88 function setCollectionSponsor(address sponsor) public {89 require(false, stub_error);90 sponsor;91 dummy = 0;92 }9394 // Collection sponsorship confirmation.95 //96 // @dev After setting the sponsor for the collection, it must be confirmed with this function.97 //98 // Selector: confirmCollectionSponsorship() 3c50e97a99 function confirmCollectionSponsorship() public {100 require(false, stub_error);101 dummy = 0;102 }103104 // Set limits for the collection.105 // @dev Throws error if limit not found.106 // @param limit Name of the limit. Valid names:107 // "accountTokenOwnershipLimit",108 // "sponsoredDataSize",109 // "sponsoredDataRateLimit",110 // "tokenLimit",111 // "sponsorTransferTimeout",112 // "sponsorApproveTimeout"113 // @param value Value of the limit.114 //115 // Selector: setCollectionLimit(string,uint32) 6a3841db116 function setCollectionLimit(string memory limit, uint32 value) public {117 require(false, stub_error);118 limit;119 value;120 dummy = 0;121 }122123 // Set limits for the collection.124 // @dev Throws error if limit not found.125 // @param limit Name of the limit. Valid names:126 // "ownerCanTransfer",127 // "ownerCanDestroy",128 // "transfersEnabled"129 // @param value Value of the limit.130 //131 // Selector: setCollectionLimit(string,bool) 993b7fba132 function setCollectionLimit(string memory limit, bool value) public {133 require(false, stub_error);134 limit;135 value;136 dummy = 0;137 }138139 // Get contract address.140 //141 // Selector: contractAddress() f6b4dfb4142 function contractAddress() public view returns (address) {143 require(false, stub_error);144 dummy;145 return 0x0000000000000000000000000000000000000000;146 }147148 // Add collection admin by substrate address.149 // @param new_admin Substrate administrator address.150 //151 // Selector: addCollectionAdminSubstrate(uint256) 5730062b152 function addCollectionAdminSubstrate(uint256 newAdmin) public {153 require(false, stub_error);154 newAdmin;155 dummy = 0;156 }157158 // Remove collection admin by substrate address.159 // @param admin Substrate administrator address.160 //161 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9162 function removeCollectionAdminSubstrate(uint256 admin) public {163 require(false, stub_error);164 admin;165 dummy = 0;166 }167168 // Add collection admin.169 // @param new_admin Address of the added administrator.170 //171 // Selector: addCollectionAdmin(address) 92e462c7172 function addCollectionAdmin(address newAdmin) public {173 require(false, stub_error);174 newAdmin;175 dummy = 0;176 }177178 // Remove collection admin.179 //180 // @param new_admin Address of the removed administrator.181 //182 // Selector: removeCollectionAdmin(address) fafd7b42183 function removeCollectionAdmin(address admin) public {184 require(false, stub_error);185 admin;186 dummy = 0;187 }188189 // Toggle accessibility of collection nesting.190 //191 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'192 //193 // Selector: setCollectionNesting(bool) 112d4586194 function setCollectionNesting(bool enable) public {195 require(false, stub_error);196 enable;197 dummy = 0;198 }199200 // Toggle accessibility of collection nesting.201 //202 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'203 // @param collections Addresses of collections that will be available for nesting.204 //205 // Selector: setCollectionNesting(bool,address[]) 64872396206 function setCollectionNesting(bool enable, address[] memory collections)207 public208 {209 require(false, stub_error);210 enable;211 collections;212 dummy = 0;213 }214215 // Set the collection access method.216 // @param mode Access mode217 // 0 for Normal218 // 1 for AllowList219 //220 // Selector: setCollectionAccess(uint8) 41835d4c221 function setCollectionAccess(uint8 mode) public {222 require(false, stub_error);223 mode;224 dummy = 0;225 }226227 // Add the user to the allowed list.228 //229 // @param user Address of a trusted user.230 //231 // Selector: addToCollectionAllowList(address) 67844fe6232 function addToCollectionAllowList(address user) public {233 require(false, stub_error);234 user;235 dummy = 0;236 }237238 // Remove the user from the allowed list.239 //240 // @param user Address of a removed user.241 //242 // Selector: removeFromCollectionAllowList(address) 85c51acb243 function removeFromCollectionAllowList(address user) public {244 require(false, stub_error);245 user;246 dummy = 0;247 }248249 // Switch permission for minting.250 //251 // @param mode Enable if "true".252 //253 // Selector: setCollectionMintMode(bool) 00018e84254 function setCollectionMintMode(bool mode) public {255 require(false, stub_error);256 mode;257 dummy = 0;258 }259260 // Check that account is the owner or admin of the collection261 //262 // @param user account to verify263 // @return "true" if account is the owner or admin264 //265 // Selector: verifyOwnerOrAdmin(address) c2282493266 function verifyOwnerOrAdmin(address user) public view returns (bool) {267 require(false, stub_error);268 user;269 dummy;270 return false;271 }272273 // Returns collection type274 //275 // @return `Fungible` or `NFT` or `ReFungible`276 //277 // Selector: uniqueCollectionType() d34b55b8278 function uniqueCollectionType() public returns (string memory) {279 require(false, stub_error);280 dummy = 0;281 return "";282 }283}284285// Selector: 79cc6790286contract ERC20UniqueExtensions is Dummy, ERC165 {287 // Selector: burnFrom(address,uint256) 79cc6790288 function burnFrom(address from, uint256 amount) public returns (bool) {289 require(false, stub_error);290 from;291 amount;292 dummy = 0;293 return false;294 }295}296297// Selector: 942e8b22298contract ERC20 is Dummy, ERC165, ERC20Events {415contract ERC20 is Dummy, ERC165, ERC20Events {299 // Selector: name() 06fdde03416 /// @dev EVM selector for this function is: 0x06fdde03,417 /// or in textual repr: name()300 function name() public view returns (string memory) {418 function name() public view returns (string memory) {301 require(false, stub_error);419 require(false, stub_error);302 dummy;420 dummy;303 return "";421 return "";304 }422 }305423306 // Selector: symbol() 95d89b41424 /// @dev EVM selector for this function is: 0x95d89b41,425 /// or in textual repr: symbol()307 function symbol() public view returns (string memory) {426 function symbol() public view returns (string memory) {308 require(false, stub_error);427 require(false, stub_error);309 dummy;428 dummy;310 return "";429 return "";311 }430 }312431313 // Selector: totalSupply() 18160ddd432 /// @dev EVM selector for this function is: 0x18160ddd,433 /// or in textual repr: totalSupply()314 function totalSupply() public view returns (uint256) {434 function totalSupply() public view returns (uint256) {315 require(false, stub_error);435 require(false, stub_error);316 dummy;436 dummy;317 return 0;437 return 0;318 }438 }319439320 // Selector: decimals() 313ce567440 /// @dev EVM selector for this function is: 0x313ce567,441 /// or in textual repr: decimals()321 function decimals() public view returns (uint8) {442 function decimals() public view returns (uint8) {322 require(false, stub_error);443 require(false, stub_error);323 dummy;444 dummy;324 return 0;445 return 0;325 }446 }326447448 /// @dev EVM selector for this function is: 0x70a08231,327 // Selector: balanceOf(address) 70a08231449 /// or in textual repr: balanceOf(address)328 function balanceOf(address owner) public view returns (uint256) {450 function balanceOf(address owner) public view returns (uint256) {329 require(false, stub_error);451 require(false, stub_error);330 owner;452 owner;331 dummy;453 dummy;332 return 0;454 return 0;333 }455 }334456457 /// @dev EVM selector for this function is: 0xa9059cbb,335 // Selector: transfer(address,uint256) a9059cbb458 /// or in textual repr: transfer(address,uint256)336 function transfer(address to, uint256 amount) public returns (bool) {459 function transfer(address to, uint256 amount) public returns (bool) {337 require(false, stub_error);460 require(false, stub_error);338 to;461 to;341 return false;464 return false;342 }465 }343466467 /// @dev EVM selector for this function is: 0x23b872dd,344 // Selector: transferFrom(address,address,uint256) 23b872dd468 /// or in textual repr: transferFrom(address,address,uint256)345 function transferFrom(469 function transferFrom(346 address from,470 address from,347 address to,471 address to,355 return false;479 return false;356 }480 }357481482 /// @dev EVM selector for this function is: 0x095ea7b3,358 // Selector: approve(address,uint256) 095ea7b3483 /// or in textual repr: approve(address,uint256)359 function approve(address spender, uint256 amount) public returns (bool) {484 function approve(address spender, uint256 amount) public returns (bool) {360 require(false, stub_error);485 require(false, stub_error);361 spender;486 spender;364 return false;489 return false;365 }490 }366491492 /// @dev EVM selector for this function is: 0xdd62ed3e,367 // Selector: allowance(address,address) dd62ed3e493 /// or in textual repr: allowance(address,address)368 function allowance(address owner, address spender)494 function allowance(address owner, address spender)369 public495 public370 view496 view382 Dummy,508 Dummy,383 ERC165,509 ERC165,384 ERC20,510 ERC20,511 ERC20Mintable,385 ERC20UniqueExtensions,512 ERC20UniqueExtensions,386 Collection513 Collection387{}514{}pallets/nonfungible/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [v0.1.5] - 2022-08-2467### Change8 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.95<!-- bureaucrate goes here -->10<!-- bureaucrate goes here -->6## [v0.1.4] 2022-08-1611## [v0.1.4] 2022-08-16712pallets/nonfungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-nonfungible"2name = "pallet-nonfungible"3version = "0.1.4"3version = "0.1.5"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/nonfungible/src/erc.rsdiffbeforeafterboth50};50};515152/// @title A contract that allows to set and delete token properties and change token property permissions.52/// @title A contract that allows to set and delete token properties and change token property permissions.53#[solidity_interface(name = "TokenProperties")]53#[solidity_interface(name = TokenProperties)]54impl<T: Config> NonfungibleHandle<T> {54impl<T: Config> NonfungibleHandle<T> {55 /// @notice Set permissions for token property.55 /// @notice Set permissions for token property.56 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.56 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.57 /// @param key Property key.57 /// @param key Property key.58 /// @param is_mutable Permission to mutate property.58 /// @param isMutable Permission to mutate property.59 /// @param collection_admin Permission to mutate property by collection admin if property is mutable.59 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.60 /// @param token_owner Permission to mutate property by token owner if property is mutable.60 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.61 fn set_token_property_permission(61 fn set_token_property_permission(62 &mut self,62 &mut self,63 caller: caller,63 caller: caller,201201202/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension202/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension203/// @dev See https://eips.ethereum.org/EIPS/eip-721203/// @dev See https://eips.ethereum.org/EIPS/eip-721204#[solidity_interface(name = "ERC721Metadata")]204#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]205impl<T: Config> NonfungibleHandle<T> {205impl<T: Config> NonfungibleHandle<T> {206 /// @notice A descriptive name for a collection of NFTs in this contract206 /// @notice A descriptive name for a collection of NFTs in this contract207 fn name(&self) -> Result<string> {207 fn name(&self) -> Result<string> {262262263/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension263/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension264/// @dev See https://eips.ethereum.org/EIPS/eip-721264/// @dev See https://eips.ethereum.org/EIPS/eip-721265#[solidity_interface(name = "ERC721Enumerable")]265#[solidity_interface(name = ERC721Enumerable, expect_selector = 0x780e9d63)]266impl<T: Config> NonfungibleHandle<T> {266impl<T: Config> NonfungibleHandle<T> {267 /// @notice Enumerate valid NFTs267 /// @notice Enumerate valid NFTs268 /// @param index A counter less than `totalSupply()`268 /// @param index A counter less than `totalSupply()`289289290/// @title ERC-721 Non-Fungible Token Standard290/// @title ERC-721 Non-Fungible Token Standard291/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md291/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md292#[solidity_interface(name = "ERC721", events(ERC721Events))]292#[solidity_interface(name = ERC721, events(ERC721Events), expect_selector = 0x80ac58cd)]293impl<T: Config> NonfungibleHandle<T> {293impl<T: Config> NonfungibleHandle<T> {294 /// @notice Count all NFTs assigned to an owner294 /// @notice Count all NFTs assigned to an owner295 /// @dev NFTs assigned to the zero address are considered invalid, and this295 /// @dev NFTs assigned to the zero address are considered invalid, and this316 .as_eth())316 .as_eth())317 }317 }318 /// @dev Not implemented318 /// @dev Not implemented319 #[solidity(rename_selector = "safeTransferFrom")]319 fn safe_transfer_from_with_data(320 fn safe_transfer_from_with_data(320 &mut self,321 &mut self,321 _from: address,322 _from: address,322 _to: address,323 _to: address,323 _token_id: uint256,324 _token_id: uint256,324 _data: bytes,325 _data: bytes,325 _value: value,326 ) -> Result<void> {326 ) -> Result<void> {327 // TODO: Not implemetable327 // TODO: Not implemetable328 Err("not implemented".into())328 Err("not implemented".into())333 _from: address,333 _from: address,334 _to: address,334 _to: address,335 _token_id: uint256,335 _token_id: uint256,336 _value: value,337 ) -> Result<void> {336 ) -> Result<void> {338 // TODO: Not implemetable337 // TODO: Not implemetable339 Err("not implemented".into())338 Err("not implemented".into())348 /// @param from The current owner of the NFT347 /// @param from The current owner of the NFT349 /// @param to The new owner348 /// @param to The new owner350 /// @param tokenId The NFT to transfer349 /// @param tokenId The NFT to transfer351 /// @param _value Not used for an NFT352 #[weight(<SelfWeightOf<T>>::transfer_from())]350 #[weight(<SelfWeightOf<T>>::transfer_from())]353 fn transfer_from(351 fn transfer_from(354 &mut self,352 &mut self,355 caller: caller,353 caller: caller,356 from: address,354 from: address,357 to: address,355 to: address,358 token_id: uint256,356 token_id: uint256,359 _value: value,360 ) -> Result<void> {357 ) -> Result<void> {361 let caller = T::CrossAccountId::from_eth(caller);358 let caller = T::CrossAccountId::from_eth(caller);362 let from = T::CrossAccountId::from_eth(from);359 let from = T::CrossAccountId::from_eth(from);382 &mut self,383 caller: caller,384 approved: address,385 token_id: uint256,386 _value: value,387 ) -> Result<void> {388 let caller = T::CrossAccountId::from_eth(caller);379 let caller = T::CrossAccountId::from_eth(caller);389 let approved = T::CrossAccountId::from_eth(approved);380 let approved = T::CrossAccountId::from_eth(approved);419}410}420411421/// @title ERC721 Token that can be irreversibly burned (destroyed).412/// @title ERC721 Token that can be irreversibly burned (destroyed).422#[solidity_interface(name = "ERC721Burnable")]413#[solidity_interface(name = ERC721Burnable)]423impl<T: Config> NonfungibleHandle<T> {414impl<T: Config> NonfungibleHandle<T> {424 /// @notice Burns a specific ERC721 token.415 /// @notice Burns a specific ERC721 token.425 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized416 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized436}427}437428438/// @title ERC721 minting logic.429/// @title ERC721 minting logic.439#[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]430#[solidity_interface(name = ERC721Mintable, events(ERC721MintableEvents))]440impl<T: Config> NonfungibleHandle<T> {431impl<T: Config> NonfungibleHandle<T> {441 fn minting_finished(&self) -> Result<bool> {432 fn minting_finished(&self) -> Result<bool> {442 Ok(false)433 Ok(false)597}588}598589599/// @title Unique extensions for ERC721.590/// @title Unique extensions for ERC721.600#[solidity_interface(name = "ERC721UniqueExtensions")]591#[solidity_interface(name = ERC721UniqueExtensions)]601impl<T: Config> NonfungibleHandle<T> {592impl<T: Config> NonfungibleHandle<T> {602 /// @notice Transfer ownership of an NFT593 /// @notice Transfer ownership of an NFT603 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`594 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`604 /// is the zero address. Throws if `tokenId` is not a valid NFT.595 /// is the zero address. Throws if `tokenId` is not a valid NFT.605 /// @param to The new owner596 /// @param to The new owner606 /// @param tokenId The NFT to transfer597 /// @param tokenId The NFT to transfer607 /// @param _value Not used for an NFT608 #[weight(<SelfWeightOf<T>>::transfer())]598 #[weight(<SelfWeightOf<T>>::transfer())]609 fn transfer(599 fn transfer(&mut self, caller: caller, to: address, token_id: uint256) -> Result<void> {610 &mut self,611 caller: caller,612 to: address,613 token_id: uint256,614 _value: value,615 ) -> Result<void> {616 let caller = T::CrossAccountId::from_eth(caller);600 let caller = T::CrossAccountId::from_eth(caller);617 let to = T::CrossAccountId::from_eth(to);601 let to = T::CrossAccountId::from_eth(to);630 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.614 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.631 /// @param from The current owner of the NFT615 /// @param from The current owner of the NFT632 /// @param tokenId The NFT to transfer616 /// @param tokenId The NFT to transfer633 /// @param _value Not used for an NFT634 #[weight(<SelfWeightOf<T>>::burn_from())]617 #[weight(<SelfWeightOf<T>>::burn_from())]635 fn burn_from(618 fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result<void> {636 &mut self,637 caller: caller,638 from: address,639 token_id: uint256,640 _value: value,641 ) -> Result<void> {642 let caller = T::CrossAccountId::from_eth(caller);619 let caller = T::CrossAccountId::from_eth(caller);643 let from = T::CrossAccountId::from_eth(from);620 let from = T::CrossAccountId::from_eth(from);751}728}752729753#[solidity_interface(730#[solidity_interface(754 name = "UniqueNFT",731 name = UniqueNFT,755 is(732 is(756 ERC721,733 ERC721,757 ERC721Metadata,734 ERC721Metadata,758 ERC721Enumerable,735 ERC721Enumerable,759 ERC721UniqueExtensions,736 ERC721UniqueExtensions,760 ERC721Mintable,737 ERC721Mintable,761 ERC721Burnable,738 ERC721Burnable,762 via("CollectionHandle<T>", common_mut, Collection),739 Collection(common_mut, CollectionHandle<T>),763 TokenProperties,740 TokenProperties,764 )741 )765)]742)]766impl<T: Config> NonfungibleHandle<T> where T::AccountId: From<[u8; 32]> {}743impl<T: Config> NonfungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}767744768// Not a tests, but code generators745// Not a tests, but code generators769generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);746generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);770generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);747generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);771748772impl<T: Config> CommonEvmHandler for NonfungibleHandle<T>749impl<T: Config> CommonEvmHandler for NonfungibleHandle<T>773where750where774 T::AccountId: From<[u8; 32]>,751 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,775{752{776 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");753 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");777754pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 uint256 field_0;9 string field_1;10}11512// Common stubs holder6/// @dev common stubs holder13contract Dummy {7contract Dummy {14 uint8 dummy;8 uint8 dummy;15 string stub_error = "this contract is implemented in native";9 string stub_error = "this contract is implemented in native";27 }21 }28}22}292330// Inline24/// @title A contract that allows to set and delete token properties and change token property permissions.25/// @dev the ERC-165 identifier for this interface is 0x4136937726contract TokenProperties is Dummy, ERC165 {27 /// @notice Set permissions for token property.28 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.29 /// @param key Property key.30 /// @param isMutable Permission to mutate property.31 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.32 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.33 /// @dev EVM selector for this function is: 0x222d97fa,34 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)35 function setTokenPropertyPermission(36 string memory key,37 bool isMutable,38 bool collectionAdmin,39 bool tokenOwner40 ) public {41 require(false, stub_error);42 key;43 isMutable;44 collectionAdmin;45 tokenOwner;46 dummy = 0;47 }4849 /// @notice Set token property value.50 /// @dev Throws error if `msg.sender` has no permission to edit the property.51 /// @param tokenId ID of the token.52 /// @param key Property key.53 /// @param value Property value.54 /// @dev EVM selector for this function is: 0x1752d67b,55 /// or in textual repr: setProperty(uint256,string,bytes)56 function setProperty(57 uint256 tokenId,58 string memory key,59 bytes memory value60 ) public {61 require(false, stub_error);62 tokenId;63 key;64 value;65 dummy = 0;66 }6768 /// @notice Delete token property value.69 /// @dev Throws error if `msg.sender` has no permission to edit the property.70 /// @param tokenId ID of the token.71 /// @param key Property key.72 /// @dev EVM selector for this function is: 0x066111d1,73 /// or in textual repr: deleteProperty(uint256,string)74 function deleteProperty(uint256 tokenId, string memory key) public {75 require(false, stub_error);76 tokenId;77 key;78 dummy = 0;79 }8081 /// @notice Get token property value.82 /// @dev Throws error if key not found83 /// @param tokenId ID of the token.84 /// @param key Property key.85 /// @return Property value bytes86 /// @dev EVM selector for this function is: 0x7228c327,87 /// or in textual repr: property(uint256,string)88 function property(uint256 tokenId, string memory key)89 public90 view91 returns (bytes memory)92 {93 require(false, stub_error);94 tokenId;95 key;96 dummy;97 return hex"";98 }99}100101/// @title A contract that allows you to work with collections.102/// @dev the ERC-165 identifier for this interface is 0xe54be640103contract Collection is Dummy, ERC165 {104 /// Set collection property.105 ///106 /// @param key Property key.107 /// @param value Propery value.108 /// @dev EVM selector for this function is: 0x2f073f66,109 /// or in textual repr: setCollectionProperty(string,bytes)110 function setCollectionProperty(string memory key, bytes memory value)111 public112 {113 require(false, stub_error);114 key;115 value;116 dummy = 0;117 }118119 /// Delete collection property.120 ///121 /// @param key Property key.122 /// @dev EVM selector for this function is: 0x7b7debce,123 /// or in textual repr: deleteCollectionProperty(string)124 function deleteCollectionProperty(string memory key) public {125 require(false, stub_error);126 key;127 dummy = 0;128 }129130 /// Get collection property.131 ///132 /// @dev Throws error if key not found.133 ///134 /// @param key Property key.135 /// @return bytes The property corresponding to the key.136 /// @dev EVM selector for this function is: 0xcf24fd6d,137 /// or in textual repr: collectionProperty(string)138 function collectionProperty(string memory key)139 public140 view141 returns (bytes memory)142 {143 require(false, stub_error);144 key;145 dummy;146 return hex"";147 }148149 /// Set the sponsor of the collection.150 ///151 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.152 ///153 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.154 /// @dev EVM selector for this function is: 0x7623402e,155 /// or in textual repr: setCollectionSponsor(address)156 function setCollectionSponsor(address sponsor) public {157 require(false, stub_error);158 sponsor;159 dummy = 0;160 }161162 /// Set the substrate sponsor of the collection.163 ///164 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.165 ///166 /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.167 /// @dev EVM selector for this function is: 0xc74d6751,168 /// or in textual repr: setCollectionSponsorSubstrate(uint256)169 function setCollectionSponsorSubstrate(uint256 sponsor) public {170 require(false, stub_error);171 sponsor;172 dummy = 0;173 }174175 /// @dev EVM selector for this function is: 0x058ac185,176 /// or in textual repr: hasCollectionPendingSponsor()177 function hasCollectionPendingSponsor() public view returns (bool) {178 require(false, stub_error);179 dummy;180 return false;181 }182183 /// Collection sponsorship confirmation.184 ///185 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.186 /// @dev EVM selector for this function is: 0x3c50e97a,187 /// or in textual repr: confirmCollectionSponsorship()188 function confirmCollectionSponsorship() public {189 require(false, stub_error);190 dummy = 0;191 }192193 /// Remove collection sponsor.194 /// @dev EVM selector for this function is: 0x6e0326a3,195 /// or in textual repr: removeCollectionSponsor()196 function removeCollectionSponsor() public {197 require(false, stub_error);198 dummy = 0;199 }200201 /// Get current sponsor.202 ///203 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.204 /// @dev EVM selector for this function is: 0xb66bbc14,205 /// or in textual repr: getCollectionSponsor()206 function getCollectionSponsor() public view returns (Tuple17 memory) {207 require(false, stub_error);208 dummy;209 return Tuple17(0x0000000000000000000000000000000000000000, 0);210 }211212 /// Set limits for the collection.213 /// @dev Throws error if limit not found.214 /// @param limit Name of the limit. Valid names:215 /// "accountTokenOwnershipLimit",216 /// "sponsoredDataSize",217 /// "sponsoredDataRateLimit",218 /// "tokenLimit",219 /// "sponsorTransferTimeout",220 /// "sponsorApproveTimeout"221 /// @param value Value of the limit.222 /// @dev EVM selector for this function is: 0x6a3841db,223 /// or in textual repr: setCollectionLimit(string,uint32)224 function setCollectionLimit(string memory limit, uint32 value) public {225 require(false, stub_error);226 limit;227 value;228 dummy = 0;229 }230231 /// Set limits for the collection.232 /// @dev Throws error if limit not found.233 /// @param limit Name of the limit. Valid names:234 /// "ownerCanTransfer",235 /// "ownerCanDestroy",236 /// "transfersEnabled"237 /// @param value Value of the limit.238 /// @dev EVM selector for this function is: 0x993b7fba,239 /// or in textual repr: setCollectionLimit(string,bool)240 function setCollectionLimit(string memory limit, bool value) public {241 require(false, stub_error);242 limit;243 value;244 dummy = 0;245 }246247 /// Get contract address.248 /// @dev EVM selector for this function is: 0xf6b4dfb4,249 /// or in textual repr: contractAddress()250 function contractAddress() public view returns (address) {251 require(false, stub_error);252 dummy;253 return 0x0000000000000000000000000000000000000000;254 }255256 /// Add collection admin by substrate address.257 /// @param newAdmin Substrate administrator address.258 /// @dev EVM selector for this function is: 0x5730062b,259 /// or in textual repr: addCollectionAdminSubstrate(uint256)260 function addCollectionAdminSubstrate(uint256 newAdmin) public {261 require(false, stub_error);262 newAdmin;263 dummy = 0;264 }265266 /// Remove collection admin by substrate address.267 /// @param admin Substrate administrator address.268 /// @dev EVM selector for this function is: 0x4048fcf9,269 /// or in textual repr: removeCollectionAdminSubstrate(uint256)270 function removeCollectionAdminSubstrate(uint256 admin) public {271 require(false, stub_error);272 admin;273 dummy = 0;274 }275276 /// Add collection admin.277 /// @param newAdmin Address of the added administrator.278 /// @dev EVM selector for this function is: 0x92e462c7,279 /// or in textual repr: addCollectionAdmin(address)280 function addCollectionAdmin(address newAdmin) public {281 require(false, stub_error);282 newAdmin;283 dummy = 0;284 }285286 /// Remove collection admin.287 ///288 /// @param admin Address of the removed administrator.289 /// @dev EVM selector for this function is: 0xfafd7b42,290 /// or in textual repr: removeCollectionAdmin(address)291 function removeCollectionAdmin(address admin) public {292 require(false, stub_error);293 admin;294 dummy = 0;295 }296297 /// Toggle accessibility of collection nesting.298 ///299 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'300 /// @dev EVM selector for this function is: 0x112d4586,301 /// or in textual repr: setCollectionNesting(bool)302 function setCollectionNesting(bool enable) public {303 require(false, stub_error);304 enable;305 dummy = 0;306 }307308 /// Toggle accessibility of collection nesting.309 ///310 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'311 /// @param collections Addresses of collections that will be available for nesting.312 /// @dev EVM selector for this function is: 0x64872396,313 /// or in textual repr: setCollectionNesting(bool,address[])314 function setCollectionNesting(bool enable, address[] memory collections)315 public316 {317 require(false, stub_error);318 enable;319 collections;320 dummy = 0;321 }322323 /// Set the collection access method.324 /// @param mode Access mode325 /// 0 for Normal326 /// 1 for AllowList327 /// @dev EVM selector for this function is: 0x41835d4c,328 /// or in textual repr: setCollectionAccess(uint8)329 function setCollectionAccess(uint8 mode) public {330 require(false, stub_error);331 mode;332 dummy = 0;333 }334335 /// Add the user to the allowed list.336 ///337 /// @param user Address of a trusted user.338 /// @dev EVM selector for this function is: 0x67844fe6,339 /// or in textual repr: addToCollectionAllowList(address)340 function addToCollectionAllowList(address user) public {341 require(false, stub_error);342 user;343 dummy = 0;344 }345346 /// Remove the user from the allowed list.347 ///348 /// @param user Address of a removed user.349 /// @dev EVM selector for this function is: 0x85c51acb,350 /// or in textual repr: removeFromCollectionAllowList(address)351 function removeFromCollectionAllowList(address user) public {352 require(false, stub_error);353 user;354 dummy = 0;355 }356357 /// Switch permission for minting.358 ///359 /// @param mode Enable if "true".360 /// @dev EVM selector for this function is: 0x00018e84,361 /// or in textual repr: setCollectionMintMode(bool)362 function setCollectionMintMode(bool mode) public {363 require(false, stub_error);364 mode;365 dummy = 0;366 }367368 /// Check that account is the owner or admin of the collection369 ///370 /// @param user account to verify371 /// @return "true" if account is the owner or admin372 /// @dev EVM selector for this function is: 0x9811b0c7,373 /// or in textual repr: isOwnerOrAdmin(address)374 function isOwnerOrAdmin(address user) public view returns (bool) {375 require(false, stub_error);376 user;377 dummy;378 return false;379 }380381 /// Check that substrate account is the owner or admin of the collection382 ///383 /// @param user account to verify384 /// @return "true" if account is the owner or admin385 /// @dev EVM selector for this function is: 0x68910e00,386 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)387 function isOwnerOrAdminSubstrate(uint256 user) public view returns (bool) {388 require(false, stub_error);389 user;390 dummy;391 return false;392 }393394 /// Returns collection type395 ///396 /// @return `Fungible` or `NFT` or `ReFungible`397 /// @dev EVM selector for this function is: 0xd34b55b8,398 /// or in textual repr: uniqueCollectionType()399 function uniqueCollectionType() public returns (string memory) {400 require(false, stub_error);401 dummy = 0;402 return "";403 }404405 /// Changes collection owner to another account406 ///407 /// @dev Owner can be changed only by current owner408 /// @param newOwner new owner account409 /// @dev EVM selector for this function is: 0x13af4035,410 /// or in textual repr: setOwner(address)411 function setOwner(address newOwner) public {412 require(false, stub_error);413 newOwner;414 dummy = 0;415 }416417 /// Changes collection owner to another substrate account418 ///419 /// @dev Owner can be changed only by current owner420 /// @param newOwner new owner substrate account421 /// @dev EVM selector for this function is: 0xb212138f,422 /// or in textual repr: setOwnerSubstrate(uint256)423 function setOwnerSubstrate(uint256 newOwner) public {424 require(false, stub_error);425 newOwner;426 dummy = 0;427 }428}429430/// @dev anonymous struct431struct Tuple17 {432 address field_0;433 uint256 field_1;434}435436/// @title ERC721 Token that can be irreversibly burned (destroyed).437/// @dev the ERC-165 identifier for this interface is 0x42966c68438contract ERC721Burnable is Dummy, ERC165 {439 /// @notice Burns a specific ERC721 token.440 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized441 /// operator of the current owner.442 /// @param tokenId The NFT to approve443 /// @dev EVM selector for this function is: 0x42966c68,444 /// or in textual repr: burn(uint256)445 function burn(uint256 tokenId) public {446 require(false, stub_error);447 tokenId;448 dummy = 0;449 }450}451452/// @dev inlined interface453contract ERC721MintableEvents {454 event MintingFinished();455}456457/// @title ERC721 minting logic.458/// @dev the ERC-165 identifier for this interface is 0x68ccfe89459contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {460 /// @dev EVM selector for this function is: 0x05d2035b,461 /// or in textual repr: mintingFinished()462 function mintingFinished() public view returns (bool) {463 require(false, stub_error);464 dummy;465 return false;466 }467468 /// @notice Function to mint token.469 /// @dev `tokenId` should be obtained with `nextTokenId` method,470 /// unlike standard, you can't specify it manually471 /// @param to The new owner472 /// @param tokenId ID of the minted NFT473 /// @dev EVM selector for this function is: 0x40c10f19,474 /// or in textual repr: mint(address,uint256)475 function mint(address to, uint256 tokenId) public returns (bool) {476 require(false, stub_error);477 to;478 tokenId;479 dummy = 0;480 return false;481 }482483 /// @notice Function to mint token with the given tokenUri.484 /// @dev `tokenId` should be obtained with `nextTokenId` method,485 /// unlike standard, you can't specify it manually486 /// @param to The new owner487 /// @param tokenId ID of the minted NFT488 /// @param tokenUri Token URI that would be stored in the NFT properties489 /// @dev EVM selector for this function is: 0x50bb4e7f,490 /// or in textual repr: mintWithTokenURI(address,uint256,string)491 function mintWithTokenURI(492 address to,493 uint256 tokenId,494 string memory tokenUri495 ) public returns (bool) {496 require(false, stub_error);497 to;498 tokenId;499 tokenUri;500 dummy = 0;501 return false;502 }503504 /// @dev Not implemented505 /// @dev EVM selector for this function is: 0x7d64bcb4,506 /// or in textual repr: finishMinting()507 function finishMinting() public returns (bool) {508 require(false, stub_error);509 dummy = 0;510 return false;511 }512}513514/// @title Unique extensions for ERC721.515/// @dev the ERC-165 identifier for this interface is 0xd74d154f516contract ERC721UniqueExtensions is Dummy, ERC165 {517 /// @notice Transfer ownership of an NFT518 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`519 /// is the zero address. Throws if `tokenId` is not a valid NFT.520 /// @param to The new owner521 /// @param tokenId The NFT to transfer522 /// @dev EVM selector for this function is: 0xa9059cbb,523 /// or in textual repr: transfer(address,uint256)524 function transfer(address to, uint256 tokenId) public {525 require(false, stub_error);526 to;527 tokenId;528 dummy = 0;529 }530531 /// @notice Burns a specific ERC721 token.532 /// @dev Throws unless `msg.sender` is the current owner or an authorized533 /// operator for this NFT. Throws if `from` is not the current owner. Throws534 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.535 /// @param from The current owner of the NFT536 /// @param tokenId The NFT to transfer537 /// @dev EVM selector for this function is: 0x79cc6790,538 /// or in textual repr: burnFrom(address,uint256)539 function burnFrom(address from, uint256 tokenId) public {540 require(false, stub_error);541 from;542 tokenId;543 dummy = 0;544 }545546 /// @notice Returns next free NFT ID.547 /// @dev EVM selector for this function is: 0x75794a3c,548 /// or in textual repr: nextTokenId()549 function nextTokenId() public view returns (uint256) {550 require(false, stub_error);551 dummy;552 return 0;553 }554555 /// @notice Function to mint multiple tokens.556 /// @dev `tokenIds` should be an array of consecutive numbers and first number557 /// should be obtained with `nextTokenId` method558 /// @param to The new owner559 /// @param tokenIds IDs of the minted NFTs560 /// @dev EVM selector for this function is: 0x44a9945e,561 /// or in textual repr: mintBulk(address,uint256[])562 function mintBulk(address to, uint256[] memory tokenIds)563 public564 returns (bool)565 {566 require(false, stub_error);567 to;568 tokenIds;569 dummy = 0;570 return false;571 }572573 /// @notice Function to mint multiple tokens with the given tokenUris.574 /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive575 /// numbers and first number should be obtained with `nextTokenId` method576 /// @param to The new owner577 /// @param tokens array of pairs of token ID and token URI for minted tokens578 /// @dev EVM selector for this function is: 0x36543006,579 /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])580 function mintBulkWithTokenURI(address to, Tuple8[] memory tokens)581 public582 returns (bool)583 {584 require(false, stub_error);585 to;586 tokens;587 dummy = 0;588 return false;589 }590}591592/// @dev anonymous struct593struct Tuple8 {594 uint256 field_0;595 string field_1;596}597598/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension599/// @dev See https://eips.ethereum.org/EIPS/eip-721600/// @dev the ERC-165 identifier for this interface is 0x780e9d63601contract ERC721Enumerable is Dummy, ERC165 {602 /// @notice Enumerate valid NFTs603 /// @param index A counter less than `totalSupply()`604 /// @return The token identifier for the `index`th NFT,605 /// (sort order not specified)606 /// @dev EVM selector for this function is: 0x4f6ccce7,607 /// or in textual repr: tokenByIndex(uint256)608 function tokenByIndex(uint256 index) public view returns (uint256) {609 require(false, stub_error);610 index;611 dummy;612 return 0;613 }614615 /// @dev Not implemented616 /// @dev EVM selector for this function is: 0x2f745c59,617 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)618 function tokenOfOwnerByIndex(address owner, uint256 index)619 public620 view621 returns (uint256)622 {623 require(false, stub_error);624 owner;625 index;626 dummy;627 return 0;628 }629630 /// @notice Count NFTs tracked by this contract631 /// @return A count of valid NFTs tracked by this contract, where each one of632 /// them has an assigned and queryable owner not equal to the zero address633 /// @dev EVM selector for this function is: 0x18160ddd,634 /// or in textual repr: totalSupply()635 function totalSupply() public view returns (uint256) {636 require(false, stub_error);637 dummy;638 return 0;639 }640}641642/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension643/// @dev See https://eips.ethereum.org/EIPS/eip-721644/// @dev the ERC-165 identifier for this interface is 0x5b5e139f645contract ERC721Metadata is Dummy, ERC165 {646 /// @notice A descriptive name for a collection of NFTs in this contract647 /// @dev EVM selector for this function is: 0x06fdde03,648 /// or in textual repr: name()649 function name() public view returns (string memory) {650 require(false, stub_error);651 dummy;652 return "";653 }654655 /// @notice An abbreviated name for NFTs in this contract656 /// @dev EVM selector for this function is: 0x95d89b41,657 /// or in textual repr: symbol()658 function symbol() public view returns (string memory) {659 require(false, stub_error);660 dummy;661 return "";662 }663664 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.665 ///666 /// @dev If the token has a `url` property and it is not empty, it is returned.667 /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.668 /// If the collection property `baseURI` is empty or absent, return "" (empty string)669 /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix670 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).671 ///672 /// @return token's const_metadata673 /// @dev EVM selector for this function is: 0xc87b56dd,674 /// or in textual repr: tokenURI(uint256)675 function tokenURI(uint256 tokenId) public view returns (string memory) {676 require(false, stub_error);677 tokenId;678 dummy;679 return "";680 }681}682683/// @dev inlined interface31contract ERC721Events {684contract ERC721Events {32 event Transfer(685 event Transfer(33 address indexed from,686 address indexed from,46 );699 );47}700}4870149// Inline702/// @title ERC-721 Non-Fungible Token Standard50contract ERC721MintableEvents {703/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md51 event MintingFinished();704/// @dev the ERC-165 identifier for this interface is 0x80ac58cd52}5354// Selector: 4136937755contract TokenProperties is Dummy, ERC165 {56 // @notice Set permissions for token property.57 // @dev Throws error if `msg.sender` is not admin or owner of the collection.58 // @param key Property key.59 // @param is_mutable Permission to mutate property.60 // @param collection_admin Permission to mutate property by collection admin if property is mutable.61 // @param token_owner Permission to mutate property by token owner if property is mutable.62 //63 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa64 function setTokenPropertyPermission(65 string memory key,66 bool isMutable,67 bool collectionAdmin,68 bool tokenOwner69 ) public {70 require(false, stub_error);71 key;72 isMutable;73 collectionAdmin;74 tokenOwner;75 dummy = 0;76 }7778 // @notice Set token property value.79 // @dev Throws error if `msg.sender` has no permission to edit the property.80 // @param tokenId ID of the token.81 // @param key Property key.82 // @param value Property value.83 //84 // Selector: setProperty(uint256,string,bytes) 1752d67b85 function setProperty(86 uint256 tokenId,87 string memory key,88 bytes memory value89 ) public {90 require(false, stub_error);91 tokenId;92 key;93 value;94 dummy = 0;95 }9697 // @notice Delete token property value.98 // @dev Throws error if `msg.sender` has no permission to edit the property.99 // @param tokenId ID of the token.100 // @param key Property key.101 //102 // Selector: deleteProperty(uint256,string) 066111d1103 function deleteProperty(uint256 tokenId, string memory key) public {104 require(false, stub_error);105 tokenId;106 key;107 dummy = 0;108 }109110 // @notice Get token property value.111 // @dev Throws error if key not found112 // @param tokenId ID of the token.113 // @param key Property key.114 // @return Property value bytes115 //116 // Selector: property(uint256,string) 7228c327117 function property(uint256 tokenId, string memory key)118 public119 view120 returns (bytes memory)121 {122 require(false, stub_error);123 tokenId;124 key;125 dummy;126 return hex"";127 }128}129130// Selector: 42966c68131contract ERC721Burnable is Dummy, ERC165 {132 // @notice Burns a specific ERC721 token.133 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized134 // operator of the current owner.135 // @param tokenId The NFT to approve136 //137 // Selector: burn(uint256) 42966c68138 function burn(uint256 tokenId) public {139 require(false, stub_error);140 tokenId;141 dummy = 0;142 }143}144145// Selector: 58800161146contract ERC721 is Dummy, ERC165, ERC721Events {705contract ERC721 is Dummy, ERC165, ERC721Events {147 // @notice Count all NFTs assigned to an owner706 /// @notice Count all NFTs assigned to an owner148 // @dev NFTs assigned to the zero address are considered invalid, and this707 /// @dev NFTs assigned to the zero address are considered invalid, and this149 // function throws for queries about the zero address.708 /// function throws for queries about the zero address.150 // @param owner An address for whom to query the balance709 /// @param owner An address for whom to query the balance151 // @return The number of NFTs owned by `owner`, possibly zero710 /// @return The number of NFTs owned by `owner`, possibly zero152 //711 /// @dev EVM selector for this function is: 0x70a08231,153 // Selector: balanceOf(address) 70a08231712 /// or in textual repr: balanceOf(address)154 function balanceOf(address owner) public view returns (uint256) {713 function balanceOf(address owner) public view returns (uint256) {155 require(false, stub_error);714 require(false, stub_error);156 owner;715 owner;157 dummy;716 dummy;158 return 0;717 return 0;159 }718 }160719161 // @notice Find the owner of an NFT720 /// @notice Find the owner of an NFT162 // @dev NFTs assigned to zero address are considered invalid, and queries721 /// @dev NFTs assigned to zero address are considered invalid, and queries163 // about them do throw.722 /// about them do throw.164 // @param tokenId The identifier for an NFT723 /// @param tokenId The identifier for an NFT165 // @return The address of the owner of the NFT724 /// @return The address of the owner of the NFT166 //725 /// @dev EVM selector for this function is: 0x6352211e,167 // Selector: ownerOf(uint256) 6352211e726 /// or in textual repr: ownerOf(uint256)168 function ownerOf(uint256 tokenId) public view returns (address) {727 function ownerOf(uint256 tokenId) public view returns (address) {169 require(false, stub_error);728 require(false, stub_error);170 tokenId;729 tokenId;171 dummy;730 dummy;172 return 0x0000000000000000000000000000000000000000;731 return 0x0000000000000000000000000000000000000000;173 }732 }174733175 // @dev Not implemented734 /// @dev Not implemented176 //735 /// @dev EVM selector for this function is: 0xb88d4fde,177 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672736 /// or in textual repr: safeTransferFrom(address,address,uint256,bytes)178 function safeTransferFromWithData(737 function safeTransferFrom(179 address from,738 address from,180 address to,739 address to,181 uint256 tokenId,740 uint256 tokenId,189 dummy = 0;748 dummy = 0;190 }749 }191750192 // @dev Not implemented751 /// @dev Not implemented193 //752 /// @dev EVM selector for this function is: 0x42842e0e,194 // Selector: safeTransferFrom(address,address,uint256) 42842e0e753 /// or in textual repr: safeTransferFrom(address,address,uint256)195 function safeTransferFrom(754 function safeTransferFrom(196 address from,755 address from,197 address to,756 address to,204 dummy = 0;763 dummy = 0;205 }764 }206765207 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE766 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE208 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE767 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE209 // THEY MAY BE PERMANENTLY LOST768 /// THEY MAY BE PERMANENTLY LOST210 // @dev Throws unless `msg.sender` is the current owner or an authorized769 /// @dev Throws unless `msg.sender` is the current owner or an authorized211 // operator for this NFT. Throws if `from` is not the current owner. Throws770 /// operator for this NFT. Throws if `from` is not the current owner. Throws212 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.771 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.213 // @param from The current owner of the NFT772 /// @param from The current owner of the NFT214 // @param to The new owner773 /// @param to The new owner215 // @param tokenId The NFT to transfer774 /// @param tokenId The NFT to transfer216 // @param _value Not used for an NFT775 /// @dev EVM selector for this function is: 0x23b872dd,217 //218 // Selector: transferFrom(address,address,uint256) 23b872dd776 /// or in textual repr: transferFrom(address,address,uint256)219 function transferFrom(777 function transferFrom(220 address from,778 address from,221 address to,779 address to,228 dummy = 0;786 dummy = 0;229 }787 }230788231 // @notice Set or reaffirm the approved address for an NFT789 /// @notice Set or reaffirm the approved address for an NFT232 // @dev The zero address indicates there is no approved address.790 /// @dev The zero address indicates there is no approved address.233 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized791 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized234 // operator of the current owner.792 /// operator of the current owner.235 // @param approved The new approved NFT controller793 /// @param approved The new approved NFT controller236 // @param tokenId The NFT to approve794 /// @param tokenId The NFT to approve237 //795 /// @dev EVM selector for this function is: 0x095ea7b3,238 // Selector: approve(address,uint256) 095ea7b3796 /// or in textual repr: approve(address,uint256)239 function approve(address approved, uint256 tokenId) public {797 function approve(address approved, uint256 tokenId) public {240 require(false, stub_error);798 require(false, stub_error);241 approved;799 approved;242 tokenId;800 tokenId;243 dummy = 0;801 dummy = 0;244 }802 }245803246 // @dev Not implemented804 /// @dev Not implemented247 //805 /// @dev EVM selector for this function is: 0xa22cb465,248 // Selector: setApprovalForAll(address,bool) a22cb465806 /// or in textual repr: setApprovalForAll(address,bool)249 function setApprovalForAll(address operator, bool approved) public {807 function setApprovalForAll(address operator, bool approved) public {250 require(false, stub_error);808 require(false, stub_error);251 operator;809 operator;252 approved;810 approved;253 dummy = 0;811 dummy = 0;254 }812 }255813256 // @dev Not implemented814 /// @dev Not implemented257 //815 /// @dev EVM selector for this function is: 0x081812fc,258 // Selector: getApproved(uint256) 081812fc816 /// or in textual repr: getApproved(uint256)259 function getApproved(uint256 tokenId) public view returns (address) {817 function getApproved(uint256 tokenId) public view returns (address) {260 require(false, stub_error);818 require(false, stub_error);261 tokenId;819 tokenId;262 dummy;820 dummy;263 return 0x0000000000000000000000000000000000000000;821 return 0x0000000000000000000000000000000000000000;264 }822 }265823266 // @dev Not implemented824 /// @dev Not implemented267 //825 /// @dev EVM selector for this function is: 0xe985e9c5,268 // Selector: isApprovedForAll(address,address) e985e9c5826 /// or in textual repr: isApprovedForAll(address,address)269 function isApprovedForAll(address owner, address operator)827 function isApprovedForAll(address owner, address operator)270 public828 public271 view829 view279 }837 }280}838}281282// Selector: 5b5e139f283contract ERC721Metadata is Dummy, ERC165 {284 // @notice A descriptive name for a collection of NFTs in this contract285 //286 // Selector: name() 06fdde03287 function name() public view returns (string memory) {288 require(false, stub_error);289 dummy;290 return "";291 }292293 // @notice An abbreviated name for NFTs in this contract294 //295 // Selector: symbol() 95d89b41296 function symbol() public view returns (string memory) {297 require(false, stub_error);298 dummy;299 return "";300 }301302 // @notice A distinct Uniform Resource Identifier (URI) for a given asset.303 //304 // @dev If the token has a `url` property and it is not empty, it is returned.305 // Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.306 // If the collection property `baseURI` is empty or absent, return "" (empty string)307 // otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix308 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).309 //310 // @return token's const_metadata311 //312 // Selector: tokenURI(uint256) c87b56dd313 function tokenURI(uint256 tokenId) public view returns (string memory) {314 require(false, stub_error);315 tokenId;316 dummy;317 return "";318 }319}320321// Selector: 68ccfe89322contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {323 // Selector: mintingFinished() 05d2035b324 function mintingFinished() public view returns (bool) {325 require(false, stub_error);326 dummy;327 return false;328 }329330 // @notice Function to mint token.331 // @dev `tokenId` should be obtained with `nextTokenId` method,332 // unlike standard, you can't specify it manually333 // @param to The new owner334 // @param tokenId ID of the minted NFT335 //336 // Selector: mint(address,uint256) 40c10f19337 function mint(address to, uint256 tokenId) public returns (bool) {338 require(false, stub_error);339 to;340 tokenId;341 dummy = 0;342 return false;343 }344345 // @notice Function to mint token with the given tokenUri.346 // @dev `tokenId` should be obtained with `nextTokenId` method,347 // unlike standard, you can't specify it manually348 // @param to The new owner349 // @param tokenId ID of the minted NFT350 // @param tokenUri Token URI that would be stored in the NFT properties351 //352 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f353 function mintWithTokenURI(354 address to,355 uint256 tokenId,356 string memory tokenUri357 ) public returns (bool) {358 require(false, stub_error);359 to;360 tokenId;361 tokenUri;362 dummy = 0;363 return false;364 }365366 // @dev Not implemented367 //368 // Selector: finishMinting() 7d64bcb4369 function finishMinting() public returns (bool) {370 require(false, stub_error);371 dummy = 0;372 return false;373 }374}375376// Selector: 6cf113cd377contract Collection is Dummy, ERC165 {378 // Set collection property.379 //380 // @param key Property key.381 // @param value Propery value.382 //383 // Selector: setCollectionProperty(string,bytes) 2f073f66384 function setCollectionProperty(string memory key, bytes memory value)385 public386 {387 require(false, stub_error);388 key;389 value;390 dummy = 0;391 }392393 // Delete collection property.394 //395 // @param key Property key.396 //397 // Selector: deleteCollectionProperty(string) 7b7debce398 function deleteCollectionProperty(string memory key) public {399 require(false, stub_error);400 key;401 dummy = 0;402 }403404 // Get collection property.405 //406 // @dev Throws error if key not found.407 //408 // @param key Property key.409 // @return bytes The property corresponding to the key.410 //411 // Selector: collectionProperty(string) cf24fd6d412 function collectionProperty(string memory key)413 public414 view415 returns (bytes memory)416 {417 require(false, stub_error);418 key;419 dummy;420 return hex"";421 }422423 // Set the sponsor of the collection.424 //425 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.426 //427 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.428 //429 // Selector: setCollectionSponsor(address) 7623402e430 function setCollectionSponsor(address sponsor) public {431 require(false, stub_error);432 sponsor;433 dummy = 0;434 }435436 // Collection sponsorship confirmation.437 //438 // @dev After setting the sponsor for the collection, it must be confirmed with this function.439 //440 // Selector: confirmCollectionSponsorship() 3c50e97a441 function confirmCollectionSponsorship() public {442 require(false, stub_error);443 dummy = 0;444 }445446 // Set limits for the collection.447 // @dev Throws error if limit not found.448 // @param limit Name of the limit. Valid names:449 // "accountTokenOwnershipLimit",450 // "sponsoredDataSize",451 // "sponsoredDataRateLimit",452 // "tokenLimit",453 // "sponsorTransferTimeout",454 // "sponsorApproveTimeout"455 // @param value Value of the limit.456 //457 // Selector: setCollectionLimit(string,uint32) 6a3841db458 function setCollectionLimit(string memory limit, uint32 value) public {459 require(false, stub_error);460 limit;461 value;462 dummy = 0;463 }464465 // Set limits for the collection.466 // @dev Throws error if limit not found.467 // @param limit Name of the limit. Valid names:468 // "ownerCanTransfer",469 // "ownerCanDestroy",470 // "transfersEnabled"471 // @param value Value of the limit.472 //473 // Selector: setCollectionLimit(string,bool) 993b7fba474 function setCollectionLimit(string memory limit, bool value) public {475 require(false, stub_error);476 limit;477 value;478 dummy = 0;479 }480481 // Get contract address.482 //483 // Selector: contractAddress() f6b4dfb4484 function contractAddress() public view returns (address) {485 require(false, stub_error);486 dummy;487 return 0x0000000000000000000000000000000000000000;488 }489490 // Add collection admin by substrate address.491 // @param new_admin Substrate administrator address.492 //493 // Selector: addCollectionAdminSubstrate(uint256) 5730062b494 function addCollectionAdminSubstrate(uint256 newAdmin) public {495 require(false, stub_error);496 newAdmin;497 dummy = 0;498 }499500 // Remove collection admin by substrate address.501 // @param admin Substrate administrator address.502 //503 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9504 function removeCollectionAdminSubstrate(uint256 admin) public {505 require(false, stub_error);506 admin;507 dummy = 0;508 }509510 // Add collection admin.511 // @param new_admin Address of the added administrator.512 //513 // Selector: addCollectionAdmin(address) 92e462c7514 function addCollectionAdmin(address newAdmin) public {515 require(false, stub_error);516 newAdmin;517 dummy = 0;518 }519520 // Remove collection admin.521 //522 // @param new_admin Address of the removed administrator.523 //524 // Selector: removeCollectionAdmin(address) fafd7b42525 function removeCollectionAdmin(address admin) public {526 require(false, stub_error);527 admin;528 dummy = 0;529 }530531 // Toggle accessibility of collection nesting.532 //533 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'534 //535 // Selector: setCollectionNesting(bool) 112d4586536 function setCollectionNesting(bool enable) public {537 require(false, stub_error);538 enable;539 dummy = 0;540 }541542 // Toggle accessibility of collection nesting.543 //544 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'545 // @param collections Addresses of collections that will be available for nesting.546 //547 // Selector: setCollectionNesting(bool,address[]) 64872396548 function setCollectionNesting(bool enable, address[] memory collections)549 public550 {551 require(false, stub_error);552 enable;553 collections;554 dummy = 0;555 }556557 // Set the collection access method.558 // @param mode Access mode559 // 0 for Normal560 // 1 for AllowList561 //562 // Selector: setCollectionAccess(uint8) 41835d4c563 function setCollectionAccess(uint8 mode) public {564 require(false, stub_error);565 mode;566 dummy = 0;567 }568569 // Add the user to the allowed list.570 //571 // @param user Address of a trusted user.572 //573 // Selector: addToCollectionAllowList(address) 67844fe6574 function addToCollectionAllowList(address user) public {575 require(false, stub_error);576 user;577 dummy = 0;578 }579580 // Remove the user from the allowed list.581 //582 // @param user Address of a removed user.583 //584 // Selector: removeFromCollectionAllowList(address) 85c51acb585 function removeFromCollectionAllowList(address user) public {586 require(false, stub_error);587 user;588 dummy = 0;589 }590591 // Switch permission for minting.592 //593 // @param mode Enable if "true".594 //595 // Selector: setCollectionMintMode(bool) 00018e84596 function setCollectionMintMode(bool mode) public {597 require(false, stub_error);598 mode;599 dummy = 0;600 }601602 // Check that account is the owner or admin of the collection603 //604 // @param user account to verify605 // @return "true" if account is the owner or admin606 //607 // Selector: verifyOwnerOrAdmin(address) c2282493608 function verifyOwnerOrAdmin(address user) public view returns (bool) {609 require(false, stub_error);610 user;611 dummy;612 return false;613 }614615 // Returns collection type616 //617 // @return `Fungible` or `NFT` or `ReFungible`618 //619 // Selector: uniqueCollectionType() d34b55b8620 function uniqueCollectionType() public returns (string memory) {621 require(false, stub_error);622 dummy = 0;623 return "";624 }625}626627// Selector: 780e9d63628contract ERC721Enumerable is Dummy, ERC165 {629 // @notice Enumerate valid NFTs630 // @param index A counter less than `totalSupply()`631 // @return The token identifier for the `index`th NFT,632 // (sort order not specified)633 //634 // Selector: tokenByIndex(uint256) 4f6ccce7635 function tokenByIndex(uint256 index) public view returns (uint256) {636 require(false, stub_error);637 index;638 dummy;639 return 0;640 }641642 // @dev Not implemented643 //644 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59645 function tokenOfOwnerByIndex(address owner, uint256 index)646 public647 view648 returns (uint256)649 {650 require(false, stub_error);651 owner;652 index;653 dummy;654 return 0;655 }656657 // @notice Count NFTs tracked by this contract658 // @return A count of valid NFTs tracked by this contract, where each one of659 // them has an assigned and queryable owner not equal to the zero address660 //661 // Selector: totalSupply() 18160ddd662 function totalSupply() public view returns (uint256) {663 require(false, stub_error);664 dummy;665 return 0;666 }667}668669// Selector: d74d154f670contract ERC721UniqueExtensions is Dummy, ERC165 {671 // @notice Transfer ownership of an NFT672 // @dev Throws unless `msg.sender` is the current owner. Throws if `to`673 // is the zero address. Throws if `tokenId` is not a valid NFT.674 // @param to The new owner675 // @param tokenId The NFT to transfer676 // @param _value Not used for an NFT677 //678 // Selector: transfer(address,uint256) a9059cbb679 function transfer(address to, uint256 tokenId) public {680 require(false, stub_error);681 to;682 tokenId;683 dummy = 0;684 }685686 // @notice Burns a specific ERC721 token.687 // @dev Throws unless `msg.sender` is the current owner or an authorized688 // operator for this NFT. Throws if `from` is not the current owner. Throws689 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.690 // @param from The current owner of the NFT691 // @param tokenId The NFT to transfer692 // @param _value Not used for an NFT693 //694 // Selector: burnFrom(address,uint256) 79cc6790695 function burnFrom(address from, uint256 tokenId) public {696 require(false, stub_error);697 from;698 tokenId;699 dummy = 0;700 }701702 // @notice Returns next free NFT ID.703 //704 // Selector: nextTokenId() 75794a3c705 function nextTokenId() public view returns (uint256) {706 require(false, stub_error);707 dummy;708 return 0;709 }710711 // @notice Function to mint multiple tokens.712 // @dev `tokenIds` should be an array of consecutive numbers and first number713 // should be obtained with `nextTokenId` method714 // @param to The new owner715 // @param tokenIds IDs of the minted NFTs716 //717 // Selector: mintBulk(address,uint256[]) 44a9945e718 function mintBulk(address to, uint256[] memory tokenIds)719 public720 returns (bool)721 {722 require(false, stub_error);723 to;724 tokenIds;725 dummy = 0;726 return false;727 }728729 // @notice Function to mint multiple tokens with the given tokenUris.730 // @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive731 // numbers and first number should be obtained with `nextTokenId` method732 // @param to The new owner733 // @param tokens array of pairs of token ID and token URI for minted tokens734 //735 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006736 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)737 public738 returns (bool)739 {740 require(false, stub_error);741 to;742 tokens;743 dummy = 0;744 return false;745 }746}747839748contract UniqueNFT is840contract UniqueNFT is749 Dummy,841 Dummy,pallets/refungible/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [v0.2.4] - 2022-08-2467### Change8 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.95<!-- bureaucrate goes here -->10<!-- bureaucrate goes here -->6## [v0.2.3] 2022-08-1611## [v0.2.3] 2022-08-16712pallets/refungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-refungible"2name = "pallet-refungible"3version = "0.2.3"3version = "0.2.4"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/refungible/src/benchmarking.rsdiffbeforeafterboth281 let item = create_max_item(&collection, &sender, [(owner.clone(), 100)])?;281 let item = create_max_item(&collection, &sender, [(owner.clone(), 100)])?;282 }: {<Pallet<T>>::repartition(&collection, &owner, item, 200)?}282 }: {<Pallet<T>>::repartition(&collection, &owner, item, 200)?}283284 set_parent_nft_unchecked {285 bench_init!{286 owner: sub; collection: collection(owner);287 sender: cross_from_sub(owner); owner: cross_sub;288 };289 let item = create_max_item(&collection, &sender, [(owner.clone(), 100)])?;290291 }: {<Pallet<T>>::set_parent_nft_unchecked(&collection, item, owner, T::CrossAccountId::from_eth(H160::default()))?}292283293 token_owner {284 token_owner {294 bench_init!{285 bench_init!{pallets/refungible/src/erc.rsdiffbeforeafterboth53pub const ADDRESS_FOR_PARTIALLY_OWNED_TOKENS: H160 = H160::repeat_byte(0xff);53pub const ADDRESS_FOR_PARTIALLY_OWNED_TOKENS: H160 = H160::repeat_byte(0xff);545455/// @title A contract that allows to set and delete token properties and change token property permissions.55/// @title A contract that allows to set and delete token properties and change token property permissions.56#[solidity_interface(name = "TokenProperties")]56#[solidity_interface(name = TokenProperties)]57impl<T: Config> RefungibleHandle<T> {57impl<T: Config> RefungibleHandle<T> {58 /// @notice Set permissions for token property.58 /// @notice Set permissions for token property.59 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.59 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.60 /// @param key Property key.60 /// @param key Property key.61 /// @param is_mutable Permission to mutate property.61 /// @param isMutable Permission to mutate property.62 /// @param collection_admin Permission to mutate property by collection admin if property is mutable.62 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.63 /// @param token_owner Permission to mutate property by token owner if property is mutable.63 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.64 fn set_token_property_permission(64 fn set_token_property_permission(65 &mut self,65 &mut self,66 caller: caller,66 caller: caller,197 MintingFinished {},197 MintingFinished {},198}198}199199200#[solidity_interface(name = "ERC721Metadata")]200#[solidity_interface(name = ERC721Metadata)]201impl<T: Config> RefungibleHandle<T> {201impl<T: Config> RefungibleHandle<T> {202 /// @notice A descriptive name for a collection of RFTs in this contract202 /// @notice A descriptive name for a collection of RFTs in this contract203 fn name(&self) -> Result<string> {203 fn name(&self) -> Result<string> {258258259/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension259/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension260/// @dev See https://eips.ethereum.org/EIPS/eip-721260/// @dev See https://eips.ethereum.org/EIPS/eip-721261#[solidity_interface(name = "ERC721Enumerable")]261#[solidity_interface(name = ERC721Enumerable)]262impl<T: Config> RefungibleHandle<T> {262impl<T: Config> RefungibleHandle<T> {263 /// @notice Enumerate valid RFTs263 /// @notice Enumerate valid RFTs264 /// @param index A counter less than `totalSupply()`264 /// @param index A counter less than `totalSupply()`285285286/// @title ERC-721 Non-Fungible Token Standard286/// @title ERC-721 Non-Fungible Token Standard287/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md287/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md288#[solidity_interface(name = "ERC721", events(ERC721Events))]288#[solidity_interface(name = ERC721, events(ERC721Events))]289impl<T: Config> RefungibleHandle<T> {289impl<T: Config> RefungibleHandle<T> {290 /// @notice Count all RFTs assigned to an owner290 /// @notice Count all RFTs assigned to an owner291 /// @dev RFTs assigned to the zero address are considered invalid, and this291 /// @dev RFTs assigned to the zero address are considered invalid, and this322 _to: address,322 _to: address,323 _token_id: uint256,323 _token_id: uint256,324 _data: bytes,324 _data: bytes,325 _value: value,326 ) -> Result<void> {325 ) -> Result<void> {327 // TODO: Not implemetable326 // TODO: Not implemetable328 Err("not implemented".into())327 Err("not implemented".into())334 _from: address,333 _from: address,335 _to: address,334 _to: address,336 _token_id: uint256,335 _token_id: uint256,337 _value: value,338 ) -> Result<void> {336 ) -> Result<void> {339 // TODO: Not implemetable337 // TODO: Not implemetable340 Err("not implemented".into())338 Err("not implemented".into())350 /// @param from The current owner of the NFT348 /// @param from The current owner of the NFT351 /// @param to The new owner349 /// @param to The new owner352 /// @param tokenId The NFT to transfer350 /// @param tokenId The NFT to transfer353 /// @param _value Not used for an NFT354 #[weight(<SelfWeightOf<T>>::transfer_from_creating_removing())]351 #[weight(<SelfWeightOf<T>>::transfer_from_creating_removing())]355 fn transfer_from(352 fn transfer_from(356 &mut self,353 &mut self,357 caller: caller,354 caller: caller,358 from: address,355 from: address,359 to: address,356 to: address,360 token_id: uint256,357 token_id: uint256,361 _value: value,362 ) -> Result<void> {358 ) -> Result<void> {363 let caller = T::CrossAccountId::from_eth(caller);359 let caller = T::CrossAccountId::from_eth(caller);364 let from = T::CrossAccountId::from_eth(from);360 let from = T::CrossAccountId::from_eth(from);382 &mut self,383 _caller: caller,384 _approved: address,385 _token_id: uint256,386 _value: value,387 ) -> Result<void> {388 Err("not implemented".into())378 Err("not implemented".into())389 }379 }438}428}439429440/// @title ERC721 Token that can be irreversibly burned (destroyed).430/// @title ERC721 Token that can be irreversibly burned (destroyed).441#[solidity_interface(name = "ERC721Burnable")]431#[solidity_interface(name = ERC721Burnable)]442impl<T: Config> RefungibleHandle<T> {432impl<T: Config> RefungibleHandle<T> {443 /// @notice Burns a specific ERC721 token.433 /// @notice Burns a specific ERC721 token.444 /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized434 /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized458}448}459449460/// @title ERC721 minting logic.450/// @title ERC721 minting logic.461#[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]451#[solidity_interface(name = ERC721Mintable, events(ERC721MintableEvents))]462impl<T: Config> RefungibleHandle<T> {452impl<T: Config> RefungibleHandle<T> {463 fn minting_finished(&self) -> Result<bool> {453 fn minting_finished(&self) -> Result<bool> {464 Ok(false)454 Ok(false)616}606}617607618/// @title Unique extensions for ERC721.608/// @title Unique extensions for ERC721.619#[solidity_interface(name = "ERC721UniqueExtensions")]609#[solidity_interface(name = ERC721UniqueExtensions)]620impl<T: Config> RefungibleHandle<T> {610impl<T: Config> RefungibleHandle<T> {621 /// @notice Transfer ownership of an RFT611 /// @notice Transfer ownership of an RFT622 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`612 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`623 /// is the zero address. Throws if `tokenId` is not a valid RFT.613 /// is the zero address. Throws if `tokenId` is not a valid RFT.624 /// Throws if RFT pieces have multiple owners.614 /// Throws if RFT pieces have multiple owners.625 /// @param to The new owner615 /// @param to The new owner626 /// @param tokenId The RFT to transfer616 /// @param tokenId The RFT to transfer627 /// @param _value Not used for an RFT628 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]617 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]629 fn transfer(618 fn transfer(&mut self, caller: caller, to: address, token_id: uint256) -> Result<void> {630 &mut self,631 caller: caller,632 to: address,633 token_id: uint256,634 _value: value,635 ) -> Result<void> {636 let caller = T::CrossAccountId::from_eth(caller);619 let caller = T::CrossAccountId::from_eth(caller);637 let to = T::CrossAccountId::from_eth(to);620 let to = T::CrossAccountId::from_eth(to);655 /// Throws if RFT pieces have multiple owners.638 /// Throws if RFT pieces have multiple owners.656 /// @param from The current owner of the RFT639 /// @param from The current owner of the RFT657 /// @param tokenId The RFT to transfer640 /// @param tokenId The RFT to transfer658 /// @param _value Not used for an RFT659 #[weight(<SelfWeightOf<T>>::burn_from())]641 #[weight(<SelfWeightOf<T>>::burn_from())]660 fn burn_from(642 fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result<void> {661 &mut self,662 caller: caller,663 from: address,664 token_id: uint256,665 _value: value,666 ) -> Result<void> {667 let caller = T::CrossAccountId::from_eth(caller);643 let caller = T::CrossAccountId::from_eth(caller);668 let from = T::CrossAccountId::from_eth(from);644 let from = T::CrossAccountId::from_eth(from);801}777}802778803#[solidity_interface(779#[solidity_interface(804 name = "UniqueRefungible",780 name = UniqueRefungible,805 is(781 is(806 ERC721,782 ERC721,807 ERC721Metadata,783 ERC721Metadata,808 ERC721Enumerable,784 ERC721Enumerable,809 ERC721UniqueExtensions,785 ERC721UniqueExtensions,810 ERC721Mintable,786 ERC721Mintable,811 ERC721Burnable,787 ERC721Burnable,812 via("CollectionHandle<T>", common_mut, Collection),788 Collection(common_mut, CollectionHandle<T>),813 TokenProperties,789 TokenProperties,814 )790 )815)]791)]816impl<T: Config> RefungibleHandle<T> where T::AccountId: From<[u8; 32]> {}792impl<T: Config> RefungibleHandle<T> where T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]> {}817793818// Not a tests, but code generators794// Not a tests, but code generators819generate_stubgen!(gen_impl, UniqueRefungibleCall<()>, true);795generate_stubgen!(gen_impl, UniqueRefungibleCall<()>, true);820generate_stubgen!(gen_iface, UniqueRefungibleCall<()>, false);796generate_stubgen!(gen_iface, UniqueRefungibleCall<()>, false);821797822impl<T: Config> CommonEvmHandler for RefungibleHandle<T>798impl<T: Config> CommonEvmHandler for RefungibleHandle<T>823where799where824 T::AccountId: From<[u8; 32]>,800 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,825{801{826 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungible.raw");802 const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungible.raw");827 fn call(803 fn call(pallets/refungible/src/erc_token.rsdiffbeforeafterboth29 convert::TryInto,29 convert::TryInto,30 ops::Deref,30 ops::Deref,31};31};32use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};32use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};33use pallet_common::{33use pallet_common::{34 CommonWeightInfo,34 CommonWeightInfo,35 erc::{CommonEvmHandler, PrecompileResult, static_property::key},35 erc::{CommonEvmHandler, PrecompileResult},36 eth::map_eth_to_id,36 eth::collection_id_to_address,37};37};38use pallet_evm::{account::CrossAccountId, PrecompileHandle};38use pallet_evm::{account::CrossAccountId, PrecompileHandle};39use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};39use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};40use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};40use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};41use sp_core::H160;42use sp_std::vec::Vec;41use sp_std::vec::Vec;43use up_data_structs::{mapping::TokenAddressMapping, PropertyScope, TokenId};42use up_data_structs::TokenId;444345use crate::{44use crate::{46 Allowance, Balance, common::CommonWeights, Config, Pallet, RefungibleHandle, SelfWeightOf,45 Allowance, Balance, common::CommonWeights, Config, Pallet, RefungibleHandle, SelfWeightOf,47 TokenProperties, TotalSupply, weights::WeightInfo,46 TotalSupply, weights::WeightInfo,48};47};494850pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);49pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);515052#[solidity_interface(name = "ERC1633")]51#[solidity_interface(name = ERC1633)]53impl<T: Config> RefungibleTokenHandle<T> {52impl<T: Config> RefungibleTokenHandle<T> {54 fn parent_token(&self) -> Result<address> {53 fn parent_token(&self) -> Result<address> {55 self.consume_store_reads(2)?;56 let props = <TokenProperties<T>>::get((self.id, self.1));57 let key = key::parent_nft();5859 let key_scoped = PropertyScope::Eth60 .apply(key)61 .expect("property key shouldn't exceed length limit");62 if let Some(value) = props.get(&key_scoped) {63 Ok(H160::from_slice(value.as_slice()))54 Ok(collection_id_to_address(self.id))64 } else {65 Ok(*T::CrossTokenAddressMapping::token_to_address(self.id, self.1).as_eth())66 }67 }55 }685669 fn parent_token_id(&self) -> Result<uint256> {57 fn parent_token_id(&self) -> Result<uint256> {70 self.consume_store_reads(2)?;71 let props = <TokenProperties<T>>::get((self.id, self.1));72 let key = key::parent_nft();7374 let key_scoped = PropertyScope::Eth75 .apply(key)76 .expect("property key shouldn't exceed length limit");77 if let Some(value) = props.get(&key_scoped) {78 let nft_token_address = H160::from_slice(value.as_slice());79 let nft_token_account = T::CrossAccountId::from_eth(nft_token_address);80 let (_, token_id) = T::CrossTokenAddressMapping::address_to_token(&nft_token_account)81 .ok_or("parent NFT should contain NFT token address")?;8283 Ok(token_id.into())84 } else {85 Ok(self.1.into())58 Ok(self.1.into())86 }87 }59 }88}60}8990#[solidity_interface(name = "ERC1633UniqueExtensions")]91impl<T: Config> RefungibleTokenHandle<T> {92 #[solidity(rename_selector = "setParentNFT")]93 #[weight(<CommonWeights<T>>::token_owner() + <SelfWeightOf<T>>::set_parent_nft_unchecked())]94 fn set_parent_nft(95 &mut self,96 caller: caller,97 collection: address,98 nft_id: uint256,99 ) -> Result<bool> {100 self.consume_store_reads(1)?;101 let caller = T::CrossAccountId::from_eth(caller);102 let nft_collection = map_eth_to_id(&collection).ok_or("collection not found")?;103 let nft_token = nft_id.try_into()?;104105 <Pallet<T>>::set_parent_nft(&self.0, self.1, caller, nft_collection, nft_token)106 .map_err(dispatch_to_evm::<T>)?;107108 Ok(true)109 }110}11161112#[derive(ToLog)]62#[derive(ToLog)]113pub enum ERC20Events {63pub enum ERC20Events {137///87///138/// @dev Implementation of the basic standard token.88/// @dev Implementation of the basic standard token.139/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md89/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md140#[solidity_interface(name = "ERC20", events(ERC20Events))]90#[solidity_interface(name = ERC20, events(ERC20Events))]141impl<T: Config> RefungibleTokenHandle<T> {91impl<T: Config> RefungibleTokenHandle<T> {142 /// @return the name of the token.92 /// @return the name of the token.143 fn name(&self) -> Result<string> {93 fn name(&self) -> Result<string> {246 }196 }247}197}248198249#[solidity_interface(name = "ERC20UniqueExtensions")]199#[solidity_interface(name = ERC20UniqueExtensions)]250impl<T: Config> RefungibleTokenHandle<T> {200impl<T: Config> RefungibleTokenHandle<T> {251 /// @dev Function that burns an amount of the token of a given account,201 /// @dev Function that burns an amount of the token of a given account,252 /// deducting from the sender's allowance for said account.202 /// deducting from the sender's allowance for said account.306}256}307257308#[solidity_interface(258#[solidity_interface(309 name = "UniqueRefungibleToken",259 name = UniqueRefungibleToken,310 is(ERC20, ERC20UniqueExtensions, ERC1633, ERC1633UniqueExtensions)260 is(ERC20, ERC20UniqueExtensions, ERC1633)311)]261)]312impl<T: Config> RefungibleTokenHandle<T> where T::AccountId: From<[u8; 32]> {}262impl<T: Config> RefungibleTokenHandle<T> where T::AccountId: From<[u8; 32]> {}313263pallets/refungible/src/lib.rsdiffbeforeafterboth1380 }1380 }1381 }1381 }13821383 /// Sets the NFT token as a parent for the RFT token1384 ///1385 /// Throws if `sender` is not the owner of the NFT token.1386 /// Throws if `sender` is not the owner of all of the RFT token pieces.1387 pub fn set_parent_nft(1388 collection: &RefungibleHandle<T>,1389 rft_token_id: TokenId,1390 sender: T::CrossAccountId,1391 nft_collection: CollectionId,1392 nft_token: TokenId,1393 ) -> DispatchResult {1394 let handle = <CollectionHandle<T>>::try_get(nft_collection)?;1395 if handle.mode != CollectionMode::NFT {1396 return Err("Only NFT token could be parent to RFT".into());1397 }1398 let dispatch = T::CollectionDispatch::dispatch(handle);1399 let dispatch = dispatch.as_dyn();14001401 let owner = dispatch.token_owner(nft_token).ok_or("owner not found")?;1402 if owner != sender {1403 return Err("Only owned token could be set as parent".into());1404 }14051406 let nft_token_address =1407 T::CrossTokenAddressMapping::token_to_address(nft_collection, nft_token);14081409 Self::set_parent_nft_unchecked(collection, rft_token_id, sender, nft_token_address)1410 }14111412 /// Sets the NFT token as a parent for the RFT token1413 ///1414 /// `sender` should be the owner of the NFT token.1415 /// Throws if `sender` is not the owner of all of the RFT token pieces.1416 pub fn set_parent_nft_unchecked(1417 collection: &RefungibleHandle<T>,1418 rft_token_id: TokenId,1419 sender: T::CrossAccountId,1420 nft_token_address: T::CrossAccountId,1421 ) -> DispatchResult {1422 let owner_balance = <Balance<T>>::get((collection.id, rft_token_id, &sender));1423 let total_supply = <TotalSupply<T>>::get((collection.id, rft_token_id));1424 if total_supply != owner_balance {1425 return Err("token has multiple owners".into());1426 }14271428 let parent_nft_property_key = key::parent_nft();14291430 let parent_nft_property_value =1431 property_value_from_bytes(&nft_token_address.as_eth().to_fixed_bytes())1432 .expect("address should fit in value length limit");14331434 <Pallet<T>>::set_scoped_token_property(1435 collection.id,1436 rft_token_id,1437 PropertyScope::Eth,1438 Property {1439 key: parent_nft_property_key,1440 value: parent_nft_property_value,1441 },1442 )?;14431444 Ok(())1445 }1446}1382}14471383pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 uint256 field_0;9 string field_1;10}11512// Common stubs holder6/// @dev common stubs holder13contract Dummy {7contract Dummy {14 uint8 dummy;8 uint8 dummy;15 string stub_error = "this contract is implemented in native";9 string stub_error = "this contract is implemented in native";27 }21 }28}22}292330// Inline24/// @title A contract that allows to set and delete token properties and change token property permissions.25/// @dev the ERC-165 identifier for this interface is 0x4136937726contract TokenProperties is Dummy, ERC165 {27 /// @notice Set permissions for token property.28 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.29 /// @param key Property key.30 /// @param isMutable Permission to mutate property.31 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.32 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.33 /// @dev EVM selector for this function is: 0x222d97fa,34 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)35 function setTokenPropertyPermission(36 string memory key,37 bool isMutable,38 bool collectionAdmin,39 bool tokenOwner40 ) public {41 require(false, stub_error);42 key;43 isMutable;44 collectionAdmin;45 tokenOwner;46 dummy = 0;47 }4849 /// @notice Set token property value.50 /// @dev Throws error if `msg.sender` has no permission to edit the property.51 /// @param tokenId ID of the token.52 /// @param key Property key.53 /// @param value Property value.54 /// @dev EVM selector for this function is: 0x1752d67b,55 /// or in textual repr: setProperty(uint256,string,bytes)56 function setProperty(57 uint256 tokenId,58 string memory key,59 bytes memory value60 ) public {61 require(false, stub_error);62 tokenId;63 key;64 value;65 dummy = 0;66 }6768 /// @notice Delete token property value.69 /// @dev Throws error if `msg.sender` has no permission to edit the property.70 /// @param tokenId ID of the token.71 /// @param key Property key.72 /// @dev EVM selector for this function is: 0x066111d1,73 /// or in textual repr: deleteProperty(uint256,string)74 function deleteProperty(uint256 tokenId, string memory key) public {75 require(false, stub_error);76 tokenId;77 key;78 dummy = 0;79 }8081 /// @notice Get token property value.82 /// @dev Throws error if key not found83 /// @param tokenId ID of the token.84 /// @param key Property key.85 /// @return Property value bytes86 /// @dev EVM selector for this function is: 0x7228c327,87 /// or in textual repr: property(uint256,string)88 function property(uint256 tokenId, string memory key)89 public90 view91 returns (bytes memory)92 {93 require(false, stub_error);94 tokenId;95 key;96 dummy;97 return hex"";98 }99}100101/// @title A contract that allows you to work with collections.102/// @dev the ERC-165 identifier for this interface is 0xe54be640103contract Collection is Dummy, ERC165 {104 /// Set collection property.105 ///106 /// @param key Property key.107 /// @param value Propery value.108 /// @dev EVM selector for this function is: 0x2f073f66,109 /// or in textual repr: setCollectionProperty(string,bytes)110 function setCollectionProperty(string memory key, bytes memory value)111 public112 {113 require(false, stub_error);114 key;115 value;116 dummy = 0;117 }118119 /// Delete collection property.120 ///121 /// @param key Property key.122 /// @dev EVM selector for this function is: 0x7b7debce,123 /// or in textual repr: deleteCollectionProperty(string)124 function deleteCollectionProperty(string memory key) public {125 require(false, stub_error);126 key;127 dummy = 0;128 }129130 /// Get collection property.131 ///132 /// @dev Throws error if key not found.133 ///134 /// @param key Property key.135 /// @return bytes The property corresponding to the key.136 /// @dev EVM selector for this function is: 0xcf24fd6d,137 /// or in textual repr: collectionProperty(string)138 function collectionProperty(string memory key)139 public140 view141 returns (bytes memory)142 {143 require(false, stub_error);144 key;145 dummy;146 return hex"";147 }148149 /// Set the sponsor of the collection.150 ///151 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.152 ///153 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.154 /// @dev EVM selector for this function is: 0x7623402e,155 /// or in textual repr: setCollectionSponsor(address)156 function setCollectionSponsor(address sponsor) public {157 require(false, stub_error);158 sponsor;159 dummy = 0;160 }161162 /// Set the substrate sponsor of the collection.163 ///164 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.165 ///166 /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.167 /// @dev EVM selector for this function is: 0xc74d6751,168 /// or in textual repr: setCollectionSponsorSubstrate(uint256)169 function setCollectionSponsorSubstrate(uint256 sponsor) public {170 require(false, stub_error);171 sponsor;172 dummy = 0;173 }174175 /// @dev EVM selector for this function is: 0x058ac185,176 /// or in textual repr: hasCollectionPendingSponsor()177 function hasCollectionPendingSponsor() public view returns (bool) {178 require(false, stub_error);179 dummy;180 return false;181 }182183 /// Collection sponsorship confirmation.184 ///185 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.186 /// @dev EVM selector for this function is: 0x3c50e97a,187 /// or in textual repr: confirmCollectionSponsorship()188 function confirmCollectionSponsorship() public {189 require(false, stub_error);190 dummy = 0;191 }192193 /// Remove collection sponsor.194 /// @dev EVM selector for this function is: 0x6e0326a3,195 /// or in textual repr: removeCollectionSponsor()196 function removeCollectionSponsor() public {197 require(false, stub_error);198 dummy = 0;199 }200201 /// Get current sponsor.202 ///203 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.204 /// @dev EVM selector for this function is: 0xb66bbc14,205 /// or in textual repr: getCollectionSponsor()206 function getCollectionSponsor() public view returns (Tuple17 memory) {207 require(false, stub_error);208 dummy;209 return Tuple17(0x0000000000000000000000000000000000000000, 0);210 }211212 /// Set limits for the collection.213 /// @dev Throws error if limit not found.214 /// @param limit Name of the limit. Valid names:215 /// "accountTokenOwnershipLimit",216 /// "sponsoredDataSize",217 /// "sponsoredDataRateLimit",218 /// "tokenLimit",219 /// "sponsorTransferTimeout",220 /// "sponsorApproveTimeout"221 /// @param value Value of the limit.222 /// @dev EVM selector for this function is: 0x6a3841db,223 /// or in textual repr: setCollectionLimit(string,uint32)224 function setCollectionLimit(string memory limit, uint32 value) public {225 require(false, stub_error);226 limit;227 value;228 dummy = 0;229 }230231 /// Set limits for the collection.232 /// @dev Throws error if limit not found.233 /// @param limit Name of the limit. Valid names:234 /// "ownerCanTransfer",235 /// "ownerCanDestroy",236 /// "transfersEnabled"237 /// @param value Value of the limit.238 /// @dev EVM selector for this function is: 0x993b7fba,239 /// or in textual repr: setCollectionLimit(string,bool)240 function setCollectionLimit(string memory limit, bool value) public {241 require(false, stub_error);242 limit;243 value;244 dummy = 0;245 }246247 /// Get contract address.248 /// @dev EVM selector for this function is: 0xf6b4dfb4,249 /// or in textual repr: contractAddress()250 function contractAddress() public view returns (address) {251 require(false, stub_error);252 dummy;253 return 0x0000000000000000000000000000000000000000;254 }255256 /// Add collection admin by substrate address.257 /// @param newAdmin Substrate administrator address.258 /// @dev EVM selector for this function is: 0x5730062b,259 /// or in textual repr: addCollectionAdminSubstrate(uint256)260 function addCollectionAdminSubstrate(uint256 newAdmin) public {261 require(false, stub_error);262 newAdmin;263 dummy = 0;264 }265266 /// Remove collection admin by substrate address.267 /// @param admin Substrate administrator address.268 /// @dev EVM selector for this function is: 0x4048fcf9,269 /// or in textual repr: removeCollectionAdminSubstrate(uint256)270 function removeCollectionAdminSubstrate(uint256 admin) public {271 require(false, stub_error);272 admin;273 dummy = 0;274 }275276 /// Add collection admin.277 /// @param newAdmin Address of the added administrator.278 /// @dev EVM selector for this function is: 0x92e462c7,279 /// or in textual repr: addCollectionAdmin(address)280 function addCollectionAdmin(address newAdmin) public {281 require(false, stub_error);282 newAdmin;283 dummy = 0;284 }285286 /// Remove collection admin.287 ///288 /// @param admin Address of the removed administrator.289 /// @dev EVM selector for this function is: 0xfafd7b42,290 /// or in textual repr: removeCollectionAdmin(address)291 function removeCollectionAdmin(address admin) public {292 require(false, stub_error);293 admin;294 dummy = 0;295 }296297 /// Toggle accessibility of collection nesting.298 ///299 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'300 /// @dev EVM selector for this function is: 0x112d4586,301 /// or in textual repr: setCollectionNesting(bool)302 function setCollectionNesting(bool enable) public {303 require(false, stub_error);304 enable;305 dummy = 0;306 }307308 /// Toggle accessibility of collection nesting.309 ///310 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'311 /// @param collections Addresses of collections that will be available for nesting.312 /// @dev EVM selector for this function is: 0x64872396,313 /// or in textual repr: setCollectionNesting(bool,address[])314 function setCollectionNesting(bool enable, address[] memory collections)315 public316 {317 require(false, stub_error);318 enable;319 collections;320 dummy = 0;321 }322323 /// Set the collection access method.324 /// @param mode Access mode325 /// 0 for Normal326 /// 1 for AllowList327 /// @dev EVM selector for this function is: 0x41835d4c,328 /// or in textual repr: setCollectionAccess(uint8)329 function setCollectionAccess(uint8 mode) public {330 require(false, stub_error);331 mode;332 dummy = 0;333 }334335 /// Add the user to the allowed list.336 ///337 /// @param user Address of a trusted user.338 /// @dev EVM selector for this function is: 0x67844fe6,339 /// or in textual repr: addToCollectionAllowList(address)340 function addToCollectionAllowList(address user) public {341 require(false, stub_error);342 user;343 dummy = 0;344 }345346 /// Remove the user from the allowed list.347 ///348 /// @param user Address of a removed user.349 /// @dev EVM selector for this function is: 0x85c51acb,350 /// or in textual repr: removeFromCollectionAllowList(address)351 function removeFromCollectionAllowList(address user) public {352 require(false, stub_error);353 user;354 dummy = 0;355 }356357 /// Switch permission for minting.358 ///359 /// @param mode Enable if "true".360 /// @dev EVM selector for this function is: 0x00018e84,361 /// or in textual repr: setCollectionMintMode(bool)362 function setCollectionMintMode(bool mode) public {363 require(false, stub_error);364 mode;365 dummy = 0;366 }367368 /// Check that account is the owner or admin of the collection369 ///370 /// @param user account to verify371 /// @return "true" if account is the owner or admin372 /// @dev EVM selector for this function is: 0x9811b0c7,373 /// or in textual repr: isOwnerOrAdmin(address)374 function isOwnerOrAdmin(address user) public view returns (bool) {375 require(false, stub_error);376 user;377 dummy;378 return false;379 }380381 /// Check that substrate account is the owner or admin of the collection382 ///383 /// @param user account to verify384 /// @return "true" if account is the owner or admin385 /// @dev EVM selector for this function is: 0x68910e00,386 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)387 function isOwnerOrAdminSubstrate(uint256 user) public view returns (bool) {388 require(false, stub_error);389 user;390 dummy;391 return false;392 }393394 /// Returns collection type395 ///396 /// @return `Fungible` or `NFT` or `ReFungible`397 /// @dev EVM selector for this function is: 0xd34b55b8,398 /// or in textual repr: uniqueCollectionType()399 function uniqueCollectionType() public returns (string memory) {400 require(false, stub_error);401 dummy = 0;402 return "";403 }404405 /// Changes collection owner to another account406 ///407 /// @dev Owner can be changed only by current owner408 /// @param newOwner new owner account409 /// @dev EVM selector for this function is: 0x13af4035,410 /// or in textual repr: setOwner(address)411 function setOwner(address newOwner) public {412 require(false, stub_error);413 newOwner;414 dummy = 0;415 }416417 /// Changes collection owner to another substrate account418 ///419 /// @dev Owner can be changed only by current owner420 /// @param newOwner new owner substrate account421 /// @dev EVM selector for this function is: 0xb212138f,422 /// or in textual repr: setOwnerSubstrate(uint256)423 function setOwnerSubstrate(uint256 newOwner) public {424 require(false, stub_error);425 newOwner;426 dummy = 0;427 }428}429430/// @dev anonymous struct431struct Tuple17 {432 address field_0;433 uint256 field_1;434}435436/// @title ERC721 Token that can be irreversibly burned (destroyed).437/// @dev the ERC-165 identifier for this interface is 0x42966c68438contract ERC721Burnable is Dummy, ERC165 {439 /// @notice Burns a specific ERC721 token.440 /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized441 /// operator of the current owner.442 /// @param tokenId The RFT to approve443 /// @dev EVM selector for this function is: 0x42966c68,444 /// or in textual repr: burn(uint256)445 function burn(uint256 tokenId) public {446 require(false, stub_error);447 tokenId;448 dummy = 0;449 }450}451452/// @dev inlined interface453contract ERC721MintableEvents {454 event MintingFinished();455}456457/// @title ERC721 minting logic.458/// @dev the ERC-165 identifier for this interface is 0x68ccfe89459contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {460 /// @dev EVM selector for this function is: 0x05d2035b,461 /// or in textual repr: mintingFinished()462 function mintingFinished() public view returns (bool) {463 require(false, stub_error);464 dummy;465 return false;466 }467468 /// @notice Function to mint token.469 /// @dev `tokenId` should be obtained with `nextTokenId` method,470 /// unlike standard, you can't specify it manually471 /// @param to The new owner472 /// @param tokenId ID of the minted RFT473 /// @dev EVM selector for this function is: 0x40c10f19,474 /// or in textual repr: mint(address,uint256)475 function mint(address to, uint256 tokenId) public returns (bool) {476 require(false, stub_error);477 to;478 tokenId;479 dummy = 0;480 return false;481 }482483 /// @notice Function to mint token with the given tokenUri.484 /// @dev `tokenId` should be obtained with `nextTokenId` method,485 /// unlike standard, you can't specify it manually486 /// @param to The new owner487 /// @param tokenId ID of the minted RFT488 /// @param tokenUri Token URI that would be stored in the RFT properties489 /// @dev EVM selector for this function is: 0x50bb4e7f,490 /// or in textual repr: mintWithTokenURI(address,uint256,string)491 function mintWithTokenURI(492 address to,493 uint256 tokenId,494 string memory tokenUri495 ) public returns (bool) {496 require(false, stub_error);497 to;498 tokenId;499 tokenUri;500 dummy = 0;501 return false;502 }503504 /// @dev Not implemented505 /// @dev EVM selector for this function is: 0x7d64bcb4,506 /// or in textual repr: finishMinting()507 function finishMinting() public returns (bool) {508 require(false, stub_error);509 dummy = 0;510 return false;511 }512}513514/// @title Unique extensions for ERC721.515/// @dev the ERC-165 identifier for this interface is 0x7c3bef89516contract ERC721UniqueExtensions is Dummy, ERC165 {517 /// @notice Transfer ownership of an RFT518 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`519 /// is the zero address. Throws if `tokenId` is not a valid RFT.520 /// Throws if RFT pieces have multiple owners.521 /// @param to The new owner522 /// @param tokenId The RFT to transfer523 /// @dev EVM selector for this function is: 0xa9059cbb,524 /// or in textual repr: transfer(address,uint256)525 function transfer(address to, uint256 tokenId) public {526 require(false, stub_error);527 to;528 tokenId;529 dummy = 0;530 }531532 /// @notice Burns a specific ERC721 token.533 /// @dev Throws unless `msg.sender` is the current owner or an authorized534 /// operator for this RFT. Throws if `from` is not the current owner. Throws535 /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.536 /// Throws if RFT pieces have multiple owners.537 /// @param from The current owner of the RFT538 /// @param tokenId The RFT to transfer539 /// @dev EVM selector for this function is: 0x79cc6790,540 /// or in textual repr: burnFrom(address,uint256)541 function burnFrom(address from, uint256 tokenId) public {542 require(false, stub_error);543 from;544 tokenId;545 dummy = 0;546 }547548 /// @notice Returns next free RFT ID.549 /// @dev EVM selector for this function is: 0x75794a3c,550 /// or in textual repr: nextTokenId()551 function nextTokenId() public view returns (uint256) {552 require(false, stub_error);553 dummy;554 return 0;555 }556557 /// @notice Function to mint multiple tokens.558 /// @dev `tokenIds` should be an array of consecutive numbers and first number559 /// should be obtained with `nextTokenId` method560 /// @param to The new owner561 /// @param tokenIds IDs of the minted RFTs562 /// @dev EVM selector for this function is: 0x44a9945e,563 /// or in textual repr: mintBulk(address,uint256[])564 function mintBulk(address to, uint256[] memory tokenIds)565 public566 returns (bool)567 {568 require(false, stub_error);569 to;570 tokenIds;571 dummy = 0;572 return false;573 }574575 /// @notice Function to mint multiple tokens with the given tokenUris.576 /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive577 /// numbers and first number should be obtained with `nextTokenId` method578 /// @param to The new owner579 /// @param tokens array of pairs of token ID and token URI for minted tokens580 /// @dev EVM selector for this function is: 0x36543006,581 /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])582 function mintBulkWithTokenURI(address to, Tuple8[] memory tokens)583 public584 returns (bool)585 {586 require(false, stub_error);587 to;588 tokens;589 dummy = 0;590 return false;591 }592593 /// Returns EVM address for refungible token594 ///595 /// @param token ID of the token596 /// @dev EVM selector for this function is: 0xab76fac6,597 /// or in textual repr: tokenContractAddress(uint256)598 function tokenContractAddress(uint256 token) public view returns (address) {599 require(false, stub_error);600 token;601 dummy;602 return 0x0000000000000000000000000000000000000000;603 }604}605606/// @dev anonymous struct607struct Tuple8 {608 uint256 field_0;609 string field_1;610}611612/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension613/// @dev See https://eips.ethereum.org/EIPS/eip-721614/// @dev the ERC-165 identifier for this interface is 0x780e9d63615contract ERC721Enumerable is Dummy, ERC165 {616 /// @notice Enumerate valid RFTs617 /// @param index A counter less than `totalSupply()`618 /// @return The token identifier for the `index`th NFT,619 /// (sort order not specified)620 /// @dev EVM selector for this function is: 0x4f6ccce7,621 /// or in textual repr: tokenByIndex(uint256)622 function tokenByIndex(uint256 index) public view returns (uint256) {623 require(false, stub_error);624 index;625 dummy;626 return 0;627 }628629 /// Not implemented630 /// @dev EVM selector for this function is: 0x2f745c59,631 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)632 function tokenOfOwnerByIndex(address owner, uint256 index)633 public634 view635 returns (uint256)636 {637 require(false, stub_error);638 owner;639 index;640 dummy;641 return 0;642 }643644 /// @notice Count RFTs tracked by this contract645 /// @return A count of valid RFTs tracked by this contract, where each one of646 /// them has an assigned and queryable owner not equal to the zero address647 /// @dev EVM selector for this function is: 0x18160ddd,648 /// or in textual repr: totalSupply()649 function totalSupply() public view returns (uint256) {650 require(false, stub_error);651 dummy;652 return 0;653 }654}655656/// @dev the ERC-165 identifier for this interface is 0x5b5e139f657contract ERC721Metadata is Dummy, ERC165 {658 /// @notice A descriptive name for a collection of RFTs in this contract659 /// @dev EVM selector for this function is: 0x06fdde03,660 /// or in textual repr: name()661 function name() public view returns (string memory) {662 require(false, stub_error);663 dummy;664 return "";665 }666667 /// @notice An abbreviated name for RFTs in this contract668 /// @dev EVM selector for this function is: 0x95d89b41,669 /// or in textual repr: symbol()670 function symbol() public view returns (string memory) {671 require(false, stub_error);672 dummy;673 return "";674 }675676 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.677 ///678 /// @dev If the token has a `url` property and it is not empty, it is returned.679 /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.680 /// If the collection property `baseURI` is empty or absent, return "" (empty string)681 /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix682 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).683 ///684 /// @return token's const_metadata685 /// @dev EVM selector for this function is: 0xc87b56dd,686 /// or in textual repr: tokenURI(uint256)687 function tokenURI(uint256 tokenId) public view returns (string memory) {688 require(false, stub_error);689 tokenId;690 dummy;691 return "";692 }693}694695/// @dev inlined interface31contract ERC721Events {696contract ERC721Events {32 event Transfer(697 event Transfer(33 address indexed from,698 address indexed from,46 );711 );47}712}4871349// Inline714/// @title ERC-721 Non-Fungible Token Standard50contract ERC721MintableEvents {715/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md51 event MintingFinished();716/// @dev the ERC-165 identifier for this interface is 0x5880016152}5354// Selector: 4136937755contract TokenProperties is Dummy, ERC165 {56 // @notice Set permissions for token property.57 // @dev Throws error if `msg.sender` is not admin or owner of the collection.58 // @param key Property key.59 // @param is_mutable Permission to mutate property.60 // @param collection_admin Permission to mutate property by collection admin if property is mutable.61 // @param token_owner Permission to mutate property by token owner if property is mutable.62 //63 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa64 function setTokenPropertyPermission(65 string memory key,66 bool isMutable,67 bool collectionAdmin,68 bool tokenOwner69 ) public {70 require(false, stub_error);71 key;72 isMutable;73 collectionAdmin;74 tokenOwner;75 dummy = 0;76 }7778 // @notice Set token property value.79 // @dev Throws error if `msg.sender` has no permission to edit the property.80 // @param tokenId ID of the token.81 // @param key Property key.82 // @param value Property value.83 //84 // Selector: setProperty(uint256,string,bytes) 1752d67b85 function setProperty(86 uint256 tokenId,87 string memory key,88 bytes memory value89 ) public {90 require(false, stub_error);91 tokenId;92 key;93 value;94 dummy = 0;95 }9697 // @notice Delete token property value.98 // @dev Throws error if `msg.sender` has no permission to edit the property.99 // @param tokenId ID of the token.100 // @param key Property key.101 //102 // Selector: deleteProperty(uint256,string) 066111d1103 function deleteProperty(uint256 tokenId, string memory key) public {104 require(false, stub_error);105 tokenId;106 key;107 dummy = 0;108 }109110 // @notice Get token property value.111 // @dev Throws error if key not found112 // @param tokenId ID of the token.113 // @param key Property key.114 // @return Property value bytes115 //116 // Selector: property(uint256,string) 7228c327117 function property(uint256 tokenId, string memory key)118 public119 view120 returns (bytes memory)121 {122 require(false, stub_error);123 tokenId;124 key;125 dummy;126 return hex"";127 }128}129130// Selector: 42966c68131contract ERC721Burnable is Dummy, ERC165 {132 // @notice Burns a specific ERC721 token.133 // @dev Throws unless `msg.sender` is the current RFT owner, or an authorized134 // operator of the current owner.135 // @param tokenId The RFT to approve136 //137 // Selector: burn(uint256) 42966c68138 function burn(uint256 tokenId) public {139 require(false, stub_error);140 tokenId;141 dummy = 0;142 }143}144145// Selector: 58800161146contract ERC721 is Dummy, ERC165, ERC721Events {717contract ERC721 is Dummy, ERC165, ERC721Events {147 // @notice Count all RFTs assigned to an owner718 /// @notice Count all RFTs assigned to an owner148 // @dev RFTs assigned to the zero address are considered invalid, and this719 /// @dev RFTs assigned to the zero address are considered invalid, and this149 // function throws for queries about the zero address.720 /// function throws for queries about the zero address.150 // @param owner An address for whom to query the balance721 /// @param owner An address for whom to query the balance151 // @return The number of RFTs owned by `owner`, possibly zero722 /// @return The number of RFTs owned by `owner`, possibly zero152 //723 /// @dev EVM selector for this function is: 0x70a08231,153 // Selector: balanceOf(address) 70a08231724 /// or in textual repr: balanceOf(address)154 function balanceOf(address owner) public view returns (uint256) {725 function balanceOf(address owner) public view returns (uint256) {155 require(false, stub_error);726 require(false, stub_error);156 owner;727 owner;157 dummy;728 dummy;158 return 0;729 return 0;159 }730 }160731161 // @notice Find the owner of an RFT732 /// @notice Find the owner of an RFT162 // @dev RFTs assigned to zero address are considered invalid, and queries733 /// @dev RFTs assigned to zero address are considered invalid, and queries163 // about them do throw.734 /// about them do throw.164 // Returns special 0xffffffffffffffffffffffffffffffffffffffff address for735 /// Returns special 0xffffffffffffffffffffffffffffffffffffffff address for165 // the tokens that are partially owned.736 /// the tokens that are partially owned.166 // @param tokenId The identifier for an RFT737 /// @param tokenId The identifier for an RFT167 // @return The address of the owner of the RFT738 /// @return The address of the owner of the RFT168 //739 /// @dev EVM selector for this function is: 0x6352211e,169 // Selector: ownerOf(uint256) 6352211e740 /// or in textual repr: ownerOf(uint256)170 function ownerOf(uint256 tokenId) public view returns (address) {741 function ownerOf(uint256 tokenId) public view returns (address) {171 require(false, stub_error);742 require(false, stub_error);172 tokenId;743 tokenId;173 dummy;744 dummy;174 return 0x0000000000000000000000000000000000000000;745 return 0x0000000000000000000000000000000000000000;175 }746 }176747177 // @dev Not implemented748 /// @dev Not implemented178 //749 /// @dev EVM selector for this function is: 0x60a11672,179 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672750 /// or in textual repr: safeTransferFromWithData(address,address,uint256,bytes)180 function safeTransferFromWithData(751 function safeTransferFromWithData(181 address from,752 address from,182 address to,753 address to,191 dummy = 0;762 dummy = 0;192 }763 }193764194 // @dev Not implemented765 /// @dev Not implemented195 //766 /// @dev EVM selector for this function is: 0x42842e0e,196 // Selector: safeTransferFrom(address,address,uint256) 42842e0e767 /// or in textual repr: safeTransferFrom(address,address,uint256)197 function safeTransferFrom(768 function safeTransferFrom(198 address from,769 address from,199 address to,770 address to,206 dummy = 0;777 dummy = 0;207 }778 }208779209 // @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE780 /// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE210 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE781 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE211 // THEY MAY BE PERMANENTLY LOST782 /// THEY MAY BE PERMANENTLY LOST212 // @dev Throws unless `msg.sender` is the current owner or an authorized783 /// @dev Throws unless `msg.sender` is the current owner or an authorized213 // operator for this RFT. Throws if `from` is not the current owner. Throws784 /// operator for this RFT. Throws if `from` is not the current owner. Throws214 // if `to` is the zero address. Throws if `tokenId` is not a valid RFT.785 /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.215 // Throws if RFT pieces have multiple owners.786 /// Throws if RFT pieces have multiple owners.216 // @param from The current owner of the NFT787 /// @param from The current owner of the NFT217 // @param to The new owner788 /// @param to The new owner218 // @param tokenId The NFT to transfer789 /// @param tokenId The NFT to transfer219 // @param _value Not used for an NFT790 /// @dev EVM selector for this function is: 0x23b872dd,220 //221 // Selector: transferFrom(address,address,uint256) 23b872dd791 /// or in textual repr: transferFrom(address,address,uint256)222 function transferFrom(792 function transferFrom(223 address from,793 address from,224 address to,794 address to,231 dummy = 0;801 dummy = 0;232 }802 }233803234 // @dev Not implemented804 /// @dev Not implemented235 //805 /// @dev EVM selector for this function is: 0x095ea7b3,236 // Selector: approve(address,uint256) 095ea7b3806 /// or in textual repr: approve(address,uint256)237 function approve(address approved, uint256 tokenId) public {807 function approve(address approved, uint256 tokenId) public {238 require(false, stub_error);808 require(false, stub_error);239 approved;809 approved;240 tokenId;810 tokenId;241 dummy = 0;811 dummy = 0;242 }812 }243813244 // @dev Not implemented814 /// @dev Not implemented245 //815 /// @dev EVM selector for this function is: 0xa22cb465,246 // Selector: setApprovalForAll(address,bool) a22cb465816 /// or in textual repr: setApprovalForAll(address,bool)247 function setApprovalForAll(address operator, bool approved) public {817 function setApprovalForAll(address operator, bool approved) public {248 require(false, stub_error);818 require(false, stub_error);249 operator;819 operator;250 approved;820 approved;251 dummy = 0;821 dummy = 0;252 }822 }253823254 // @dev Not implemented824 /// @dev Not implemented255 //825 /// @dev EVM selector for this function is: 0x081812fc,256 // Selector: getApproved(uint256) 081812fc826 /// or in textual repr: getApproved(uint256)257 function getApproved(uint256 tokenId) public view returns (address) {827 function getApproved(uint256 tokenId) public view returns (address) {258 require(false, stub_error);828 require(false, stub_error);259 tokenId;829 tokenId;260 dummy;830 dummy;261 return 0x0000000000000000000000000000000000000000;831 return 0x0000000000000000000000000000000000000000;262 }832 }263833264 // @dev Not implemented834 /// @dev Not implemented265 //835 /// @dev EVM selector for this function is: 0xe985e9c5,266 // Selector: isApprovedForAll(address,address) e985e9c5836 /// or in textual repr: isApprovedForAll(address,address)267 function isApprovedForAll(address owner, address operator)837 function isApprovedForAll(address owner, address operator)268 public838 public269 view839 view277 }847 }278}848}279280// Selector: 5b5e139f281contract ERC721Metadata is Dummy, ERC165 {282 // @notice A descriptive name for a collection of RFTs in this contract283 //284 // Selector: name() 06fdde03285 function name() public view returns (string memory) {286 require(false, stub_error);287 dummy;288 return "";289 }290291 // @notice An abbreviated name for RFTs in this contract292 //293 // Selector: symbol() 95d89b41294 function symbol() public view returns (string memory) {295 require(false, stub_error);296 dummy;297 return "";298 }299300 // @notice A distinct Uniform Resource Identifier (URI) for a given asset.301 //302 // @dev If the token has a `url` property and it is not empty, it is returned.303 // Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.304 // If the collection property `baseURI` is empty or absent, return "" (empty string)305 // otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix306 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).307 //308 // @return token's const_metadata309 //310 // Selector: tokenURI(uint256) c87b56dd311 function tokenURI(uint256 tokenId) public view returns (string memory) {312 require(false, stub_error);313 tokenId;314 dummy;315 return "";316 }317}318319// Selector: 68ccfe89320contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {321 // Selector: mintingFinished() 05d2035b322 function mintingFinished() public view returns (bool) {323 require(false, stub_error);324 dummy;325 return false;326 }327328 // @notice Function to mint token.329 // @dev `tokenId` should be obtained with `nextTokenId` method,330 // unlike standard, you can't specify it manually331 // @param to The new owner332 // @param tokenId ID of the minted RFT333 //334 // Selector: mint(address,uint256) 40c10f19335 function mint(address to, uint256 tokenId) public returns (bool) {336 require(false, stub_error);337 to;338 tokenId;339 dummy = 0;340 return false;341 }342343 // @notice Function to mint token with the given tokenUri.344 // @dev `tokenId` should be obtained with `nextTokenId` method,345 // unlike standard, you can't specify it manually346 // @param to The new owner347 // @param tokenId ID of the minted RFT348 // @param tokenUri Token URI that would be stored in the RFT properties349 //350 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f351 function mintWithTokenURI(352 address to,353 uint256 tokenId,354 string memory tokenUri355 ) public returns (bool) {356 require(false, stub_error);357 to;358 tokenId;359 tokenUri;360 dummy = 0;361 return false;362 }363364 // @dev Not implemented365 //366 // Selector: finishMinting() 7d64bcb4367 function finishMinting() public returns (bool) {368 require(false, stub_error);369 dummy = 0;370 return false;371 }372}373374// Selector: 6cf113cd375contract Collection is Dummy, ERC165 {376 // Set collection property.377 //378 // @param key Property key.379 // @param value Propery value.380 //381 // Selector: setCollectionProperty(string,bytes) 2f073f66382 function setCollectionProperty(string memory key, bytes memory value)383 public384 {385 require(false, stub_error);386 key;387 value;388 dummy = 0;389 }390391 // Delete collection property.392 //393 // @param key Property key.394 //395 // Selector: deleteCollectionProperty(string) 7b7debce396 function deleteCollectionProperty(string memory key) public {397 require(false, stub_error);398 key;399 dummy = 0;400 }401402 // Get collection property.403 //404 // @dev Throws error if key not found.405 //406 // @param key Property key.407 // @return bytes The property corresponding to the key.408 //409 // Selector: collectionProperty(string) cf24fd6d410 function collectionProperty(string memory key)411 public412 view413 returns (bytes memory)414 {415 require(false, stub_error);416 key;417 dummy;418 return hex"";419 }420421 // Set the sponsor of the collection.422 //423 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.424 //425 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.426 //427 // Selector: setCollectionSponsor(address) 7623402e428 function setCollectionSponsor(address sponsor) public {429 require(false, stub_error);430 sponsor;431 dummy = 0;432 }433434 // Collection sponsorship confirmation.435 //436 // @dev After setting the sponsor for the collection, it must be confirmed with this function.437 //438 // Selector: confirmCollectionSponsorship() 3c50e97a439 function confirmCollectionSponsorship() public {440 require(false, stub_error);441 dummy = 0;442 }443444 // Set limits for the collection.445 // @dev Throws error if limit not found.446 // @param limit Name of the limit. Valid names:447 // "accountTokenOwnershipLimit",448 // "sponsoredDataSize",449 // "sponsoredDataRateLimit",450 // "tokenLimit",451 // "sponsorTransferTimeout",452 // "sponsorApproveTimeout"453 // @param value Value of the limit.454 //455 // Selector: setCollectionLimit(string,uint32) 6a3841db456 function setCollectionLimit(string memory limit, uint32 value) public {457 require(false, stub_error);458 limit;459 value;460 dummy = 0;461 }462463 // Set limits for the collection.464 // @dev Throws error if limit not found.465 // @param limit Name of the limit. Valid names:466 // "ownerCanTransfer",467 // "ownerCanDestroy",468 // "transfersEnabled"469 // @param value Value of the limit.470 //471 // Selector: setCollectionLimit(string,bool) 993b7fba472 function setCollectionLimit(string memory limit, bool value) public {473 require(false, stub_error);474 limit;475 value;476 dummy = 0;477 }478479 // Get contract address.480 //481 // Selector: contractAddress() f6b4dfb4482 function contractAddress() public view returns (address) {483 require(false, stub_error);484 dummy;485 return 0x0000000000000000000000000000000000000000;486 }487488 // Add collection admin by substrate address.489 // @param new_admin Substrate administrator address.490 //491 // Selector: addCollectionAdminSubstrate(uint256) 5730062b492 function addCollectionAdminSubstrate(uint256 newAdmin) public {493 require(false, stub_error);494 newAdmin;495 dummy = 0;496 }497498 // Remove collection admin by substrate address.499 // @param admin Substrate administrator address.500 //501 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9502 function removeCollectionAdminSubstrate(uint256 admin) public {503 require(false, stub_error);504 admin;505 dummy = 0;506 }507508 // Add collection admin.509 // @param new_admin Address of the added administrator.510 //511 // Selector: addCollectionAdmin(address) 92e462c7512 function addCollectionAdmin(address newAdmin) public {513 require(false, stub_error);514 newAdmin;515 dummy = 0;516 }517518 // Remove collection admin.519 //520 // @param new_admin Address of the removed administrator.521 //522 // Selector: removeCollectionAdmin(address) fafd7b42523 function removeCollectionAdmin(address admin) public {524 require(false, stub_error);525 admin;526 dummy = 0;527 }528529 // Toggle accessibility of collection nesting.530 //531 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'532 //533 // Selector: setCollectionNesting(bool) 112d4586534 function setCollectionNesting(bool enable) public {535 require(false, stub_error);536 enable;537 dummy = 0;538 }539540 // Toggle accessibility of collection nesting.541 //542 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'543 // @param collections Addresses of collections that will be available for nesting.544 //545 // Selector: setCollectionNesting(bool,address[]) 64872396546 function setCollectionNesting(bool enable, address[] memory collections)547 public548 {549 require(false, stub_error);550 enable;551 collections;552 dummy = 0;553 }554555 // Set the collection access method.556 // @param mode Access mode557 // 0 for Normal558 // 1 for AllowList559 //560 // Selector: setCollectionAccess(uint8) 41835d4c561 function setCollectionAccess(uint8 mode) public {562 require(false, stub_error);563 mode;564 dummy = 0;565 }566567 // Add the user to the allowed list.568 //569 // @param user Address of a trusted user.570 //571 // Selector: addToCollectionAllowList(address) 67844fe6572 function addToCollectionAllowList(address user) public {573 require(false, stub_error);574 user;575 dummy = 0;576 }577578 // Remove the user from the allowed list.579 //580 // @param user Address of a removed user.581 //582 // Selector: removeFromCollectionAllowList(address) 85c51acb583 function removeFromCollectionAllowList(address user) public {584 require(false, stub_error);585 user;586 dummy = 0;587 }588589 // Switch permission for minting.590 //591 // @param mode Enable if "true".592 //593 // Selector: setCollectionMintMode(bool) 00018e84594 function setCollectionMintMode(bool mode) public {595 require(false, stub_error);596 mode;597 dummy = 0;598 }599600 // Check that account is the owner or admin of the collection601 //602 // @param user account to verify603 // @return "true" if account is the owner or admin604 //605 // Selector: verifyOwnerOrAdmin(address) c2282493606 function verifyOwnerOrAdmin(address user) public view returns (bool) {607 require(false, stub_error);608 user;609 dummy;610 return false;611 }612613 // Returns collection type614 //615 // @return `Fungible` or `NFT` or `ReFungible`616 //617 // Selector: uniqueCollectionType() d34b55b8618 function uniqueCollectionType() public returns (string memory) {619 require(false, stub_error);620 dummy = 0;621 return "";622 }623}624625// Selector: 780e9d63626contract ERC721Enumerable is Dummy, ERC165 {627 // @notice Enumerate valid RFTs628 // @param index A counter less than `totalSupply()`629 // @return The token identifier for the `index`th NFT,630 // (sort order not specified)631 //632 // Selector: tokenByIndex(uint256) 4f6ccce7633 function tokenByIndex(uint256 index) public view returns (uint256) {634 require(false, stub_error);635 index;636 dummy;637 return 0;638 }639640 // Not implemented641 //642 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59643 function tokenOfOwnerByIndex(address owner, uint256 index)644 public645 view646 returns (uint256)647 {648 require(false, stub_error);649 owner;650 index;651 dummy;652 return 0;653 }654655 // @notice Count RFTs tracked by this contract656 // @return A count of valid RFTs tracked by this contract, where each one of657 // them has an assigned and queryable owner not equal to the zero address658 //659 // Selector: totalSupply() 18160ddd660 function totalSupply() public view returns (uint256) {661 require(false, stub_error);662 dummy;663 return 0;664 }665}666667// Selector: 7c3bef89668contract ERC721UniqueExtensions is Dummy, ERC165 {669 // @notice Transfer ownership of an RFT670 // @dev Throws unless `msg.sender` is the current owner. Throws if `to`671 // is the zero address. Throws if `tokenId` is not a valid RFT.672 // Throws if RFT pieces have multiple owners.673 // @param to The new owner674 // @param tokenId The RFT to transfer675 // @param _value Not used for an RFT676 //677 // Selector: transfer(address,uint256) a9059cbb678 function transfer(address to, uint256 tokenId) public {679 require(false, stub_error);680 to;681 tokenId;682 dummy = 0;683 }684685 // @notice Burns a specific ERC721 token.686 // @dev Throws unless `msg.sender` is the current owner or an authorized687 // operator for this RFT. Throws if `from` is not the current owner. Throws688 // if `to` is the zero address. Throws if `tokenId` is not a valid RFT.689 // Throws if RFT pieces have multiple owners.690 // @param from The current owner of the RFT691 // @param tokenId The RFT to transfer692 // @param _value Not used for an RFT693 //694 // Selector: burnFrom(address,uint256) 79cc6790695 function burnFrom(address from, uint256 tokenId) public {696 require(false, stub_error);697 from;698 tokenId;699 dummy = 0;700 }701702 // @notice Returns next free RFT ID.703 //704 // Selector: nextTokenId() 75794a3c705 function nextTokenId() public view returns (uint256) {706 require(false, stub_error);707 dummy;708 return 0;709 }710711 // @notice Function to mint multiple tokens.712 // @dev `tokenIds` should be an array of consecutive numbers and first number713 // should be obtained with `nextTokenId` method714 // @param to The new owner715 // @param tokenIds IDs of the minted RFTs716 //717 // Selector: mintBulk(address,uint256[]) 44a9945e718 function mintBulk(address to, uint256[] memory tokenIds)719 public720 returns (bool)721 {722 require(false, stub_error);723 to;724 tokenIds;725 dummy = 0;726 return false;727 }728729 // @notice Function to mint multiple tokens with the given tokenUris.730 // @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive731 // numbers and first number should be obtained with `nextTokenId` method732 // @param to The new owner733 // @param tokens array of pairs of token ID and token URI for minted tokens734 //735 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006736 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)737 public738 returns (bool)739 {740 require(false, stub_error);741 to;742 tokens;743 dummy = 0;744 return false;745 }746747 // Returns EVM address for refungible token748 //749 // @param token ID of the token750 //751 // Selector: tokenContractAddress(uint256) ab76fac6752 function tokenContractAddress(uint256 token) public view returns (address) {753 require(false, stub_error);754 token;755 dummy;756 return 0x0000000000000000000000000000000000000000;757 }758}759849760contract UniqueRefungible is850contract UniqueRefungible is761 Dummy,851 Dummy,pallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7contract Dummy {7contract Dummy {8 uint8 dummy;8 uint8 dummy;9 string stub_error = "this contract is implemented in native";9 string stub_error = "this contract is implemented in native";21 }21 }22}22}232324// Inline24/// @dev the ERC-165 identifier for this interface is 0x5755c3f225contract ERC1633 is Dummy, ERC165 {26 /// @dev EVM selector for this function is: 0x80a54001,27 /// or in textual repr: parentToken()28 function parentToken() public view returns (address) {29 require(false, stub_error);30 dummy;31 return 0x0000000000000000000000000000000000000000;32 }3334 /// @dev EVM selector for this function is: 0xd7f083f3,35 /// or in textual repr: parentTokenId()36 function parentTokenId() public view returns (uint256) {37 require(false, stub_error);38 dummy;39 return 0;40 }41}4243/// @dev the ERC-165 identifier for this interface is 0xab8deb3744contract ERC20UniqueExtensions is Dummy, ERC165 {45 /// @dev Function that burns an amount of the token of a given account,46 /// deducting from the sender's allowance for said account.47 /// @param from The account whose tokens will be burnt.48 /// @param amount The amount that will be burnt.49 /// @dev EVM selector for this function is: 0x79cc6790,50 /// or in textual repr: burnFrom(address,uint256)51 function burnFrom(address from, uint256 amount) public returns (bool) {52 require(false, stub_error);53 from;54 amount;55 dummy = 0;56 return false;57 }5859 /// @dev Function that changes total amount of the tokens.60 /// Throws if `msg.sender` doesn't owns all of the tokens.61 /// @param amount New total amount of the tokens.62 /// @dev EVM selector for this function is: 0xd2418ca7,63 /// or in textual repr: repartition(uint256)64 function repartition(uint256 amount) public returns (bool) {65 require(false, stub_error);66 amount;67 dummy = 0;68 return false;69 }70}7172/// @dev inlined interface25contract ERC20Events {73contract ERC20Events {26 event Transfer(address indexed from, address indexed to, uint256 value);74 event Transfer(address indexed from, address indexed to, uint256 value);27 event Approval(75 event Approval(31 );79 );32}80}338134// Selector: 042f110682/// @title Standard ERC20 token35contract ERC1633UniqueExtensions is Dummy, ERC165 {83///36 // Selector: setParentNFT(address,uint256) 042f110684/// @dev Implementation of the basic standard token.37 function setParentNFT(address collection, uint256 nftId)85/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md38 public86/// @dev the ERC-165 identifier for this interface is 0x942e8b2239 returns (bool)40 {41 require(false, stub_error);42 collection;43 nftId;44 dummy = 0;45 return false;46 }47}4849// Selector: 5755c3f250contract ERC1633 is Dummy, ERC165 {51 // Selector: parentToken() 80a5400152 function parentToken() public view returns (address) {53 require(false, stub_error);54 dummy;55 return 0x0000000000000000000000000000000000000000;56 }5758 // Selector: parentTokenId() d7f083f359 function parentTokenId() public view returns (uint256) {60 require(false, stub_error);61 dummy;62 return 0;63 }64}6566// Selector: 942e8b2267contract ERC20 is Dummy, ERC165, ERC20Events {87contract ERC20 is Dummy, ERC165, ERC20Events {68 // @return the name of the token.88 /// @return the name of the token.69 //89 /// @dev EVM selector for this function is: 0x06fdde03,70 // Selector: name() 06fdde0390 /// or in textual repr: name()71 function name() public view returns (string memory) {91 function name() public view returns (string memory) {72 require(false, stub_error);92 require(false, stub_error);73 dummy;93 dummy;74 return "";94 return "";75 }95 }769677 // @return the symbol of the token.97 /// @return the symbol of the token.78 //98 /// @dev EVM selector for this function is: 0x95d89b41,79 // Selector: symbol() 95d89b4199 /// or in textual repr: symbol()80 function symbol() public view returns (string memory) {100 function symbol() public view returns (string memory) {81 require(false, stub_error);101 require(false, stub_error);82 dummy;102 dummy;83 return "";103 return "";84 }104 }8510586 // @dev Total number of tokens in existence106 /// @dev Total number of tokens in existence87 //107 /// @dev EVM selector for this function is: 0x18160ddd,88 // Selector: totalSupply() 18160ddd108 /// or in textual repr: totalSupply()89 function totalSupply() public view returns (uint256) {109 function totalSupply() public view returns (uint256) {90 require(false, stub_error);110 require(false, stub_error);91 dummy;111 dummy;92 return 0;112 return 0;93 }113 }9411495 // @dev Not supported115 /// @dev Not supported96 //116 /// @dev EVM selector for this function is: 0x313ce567,97 // Selector: decimals() 313ce567117 /// or in textual repr: decimals()98 function decimals() public view returns (uint8) {118 function decimals() public view returns (uint8) {99 require(false, stub_error);119 require(false, stub_error);100 dummy;120 dummy;101 return 0;121 return 0;102 }122 }103123104 // @dev Gets the balance of the specified address.124 /// @dev Gets the balance of the specified address.105 // @param owner The address to query the balance of.125 /// @param owner The address to query the balance of.106 // @return An uint256 representing the amount owned by the passed address.126 /// @return An uint256 representing the amount owned by the passed address.107 //127 /// @dev EVM selector for this function is: 0x70a08231,108 // Selector: balanceOf(address) 70a08231128 /// or in textual repr: balanceOf(address)109 function balanceOf(address owner) public view returns (uint256) {129 function balanceOf(address owner) public view returns (uint256) {110 require(false, stub_error);130 require(false, stub_error);111 owner;131 owner;112 dummy;132 dummy;113 return 0;133 return 0;114 }134 }115135116 // @dev Transfer token for a specified address136 /// @dev Transfer token for a specified address117 // @param to The address to transfer to.137 /// @param to The address to transfer to.118 // @param amount The amount to be transferred.138 /// @param amount The amount to be transferred.119 //139 /// @dev EVM selector for this function is: 0xa9059cbb,120 // Selector: transfer(address,uint256) a9059cbb140 /// or in textual repr: transfer(address,uint256)121 function transfer(address to, uint256 amount) public returns (bool) {141 function transfer(address to, uint256 amount) public returns (bool) {122 require(false, stub_error);142 require(false, stub_error);123 to;143 to;126 return false;146 return false;127 }147 }128148129 // @dev Transfer tokens from one address to another149 /// @dev Transfer tokens from one address to another130 // @param from address The address which you want to send tokens from150 /// @param from address The address which you want to send tokens from131 // @param to address The address which you want to transfer to151 /// @param to address The address which you want to transfer to132 // @param amount uint256 the amount of tokens to be transferred152 /// @param amount uint256 the amount of tokens to be transferred133 //153 /// @dev EVM selector for this function is: 0x23b872dd,134 // Selector: transferFrom(address,address,uint256) 23b872dd154 /// or in textual repr: transferFrom(address,address,uint256)135 function transferFrom(155 function transferFrom(136 address from,156 address from,137 address to,157 address to,145 return false;165 return false;146 }166 }147167148 // @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.168 /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.149 // Beware that changing an allowance with this method brings the risk that someone may use both the old169 /// Beware that changing an allowance with this method brings the risk that someone may use both the old150 // and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this170 /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this151 // race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:171 /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:152 // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729172 /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729153 // @param spender The address which will spend the funds.173 /// @param spender The address which will spend the funds.154 // @param amount The amount of tokens to be spent.174 /// @param amount The amount of tokens to be spent.155 //175 /// @dev EVM selector for this function is: 0x095ea7b3,156 // Selector: approve(address,uint256) 095ea7b3176 /// or in textual repr: approve(address,uint256)157 function approve(address spender, uint256 amount) public returns (bool) {177 function approve(address spender, uint256 amount) public returns (bool) {158 require(false, stub_error);178 require(false, stub_error);159 spender;179 spender;162 return false;182 return false;163 }183 }164184165 // @dev Function to check the amount of tokens that an owner allowed to a spender.185 /// @dev Function to check the amount of tokens that an owner allowed to a spender.166 // @param owner address The address which owns the funds.186 /// @param owner address The address which owns the funds.167 // @param spender address The address which will spend the funds.187 /// @param spender address The address which will spend the funds.168 // @return A uint256 specifying the amount of tokens still available for the spender.188 /// @return A uint256 specifying the amount of tokens still available for the spender.169 //189 /// @dev EVM selector for this function is: 0xdd62ed3e,170 // Selector: allowance(address,address) dd62ed3e190 /// or in textual repr: allowance(address,address)171 function allowance(address owner, address spender)191 function allowance(address owner, address spender)172 public192 public173 view193 view181 }201 }182}202}183184// Selector: ab8deb37185contract ERC20UniqueExtensions is Dummy, ERC165 {186 // @dev Function that burns an amount of the token of a given account,187 // deducting from the sender's allowance for said account.188 // @param from The account whose tokens will be burnt.189 // @param amount The amount that will be burnt.190 //191 // Selector: burnFrom(address,uint256) 79cc6790192 function burnFrom(address from, uint256 amount) public returns (bool) {193 require(false, stub_error);194 from;195 amount;196 dummy = 0;197 return false;198 }199200 // @dev Function that changes total amount of the tokens.201 // Throws if `msg.sender` doesn't owns all of the tokens.202 // @param amount New total amount of the tokens.203 //204 // Selector: repartition(uint256) d2418ca7205 function repartition(uint256 amount) public returns (bool) {206 require(false, stub_error);207 amount;208 dummy = 0;209 return false;210 }211}212203213contract UniqueRefungibleToken is204contract UniqueRefungibleToken is214 Dummy,205 Dummy,215 ERC165,206 ERC165,216 ERC20,207 ERC20,217 ERC20UniqueExtensions,208 ERC20UniqueExtensions,218 ERC1633,209 ERC1633219 ERC1633UniqueExtensions220{}210{}221211pallets/refungible/src/weights.rsdiffbeforeafterboth53 fn set_token_properties(b: u32, ) -> Weight;53 fn set_token_properties(b: u32, ) -> Weight;54 fn delete_token_properties(b: u32, ) -> Weight;54 fn delete_token_properties(b: u32, ) -> Weight;55 fn repartition_item() -> Weight;55 fn repartition_item() -> Weight;56 fn set_parent_nft_unchecked() -> Weight;57 fn token_owner() -> Weight;56 fn token_owner() -> Weight;58}57}5958255 .saturating_add(T::DbWeight::get().reads(2 as Weight))254 .saturating_add(T::DbWeight::get().reads(2 as Weight))256 .saturating_add(T::DbWeight::get().writes(2 as Weight))255 .saturating_add(T::DbWeight::get().writes(2 as Weight))257 }256 }258 // Storage: Refungible Balance (r:1 w:0)259 // Storage: Refungible TotalSupply (r:1 w:0)260 // Storage: Refungible TokenProperties (r:1 w:1)261 fn set_parent_nft_unchecked() -> Weight {262 (12_015_000 as Weight)263 .saturating_add(T::DbWeight::get().reads(3 as Weight))264 .saturating_add(T::DbWeight::get().writes(1 as Weight))265 }266 // Storage: Refungible Balance (r:2 w:0)257 // Storage: Refungible Balance (r:2 w:0)267 fn token_owner() -> Weight {258 fn token_owner() -> Weight {268 (9_431_000 as Weight)259 (9_431_000 as Weight)467 .saturating_add(RocksDbWeight::get().reads(2 as Weight))458 .saturating_add(RocksDbWeight::get().reads(2 as Weight))468 .saturating_add(RocksDbWeight::get().writes(2 as Weight))459 .saturating_add(RocksDbWeight::get().writes(2 as Weight))469 }460 }470 // Storage: Refungible Balance (r:1 w:0)471 // Storage: Refungible TotalSupply (r:1 w:0)472 // Storage: Refungible TokenProperties (r:1 w:1)473 fn set_parent_nft_unchecked() -> Weight {474 (12_015_000 as Weight)475 .saturating_add(RocksDbWeight::get().reads(3 as Weight))476 .saturating_add(RocksDbWeight::get().writes(1 as Weight))477 }478 // Storage: Refungible Balance (r:2 w:0)461 // Storage: Refungible Balance (r:2 w:0)479 fn token_owner() -> Weight {462 fn token_owner() -> Weight {480 (9_431_000 as Weight)463 (9_431_000 as Weight)pallets/unique/src/eth/mod.rsdiffbeforeafterboth154 Ok(data)154 Ok(data)155}155}156157fn parent_nft_property_permissions() -> PropertyKeyPermission {158 PropertyKeyPermission {159 key: key::parent_nft(),160 permission: PropertyPermission {161 mutable: false,162 collection_admin: false,163 token_owner: true,164 },165 }166}167156168fn create_refungible_collection_internal<157fn create_refungible_collection_internal<169 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,158 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,189 let collection_id = T::CollectionDispatch::create(caller.clone(), data)178 let collection_id = T::CollectionDispatch::create(caller.clone(), data)190 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;179 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;191192 let handle = <CollectionHandle<T>>::try_get(collection_id).map_err(dispatch_to_evm::<T>)?;193 <PalletCommon<T>>::set_scoped_token_property_permissions(194 &handle,195 &caller,196 PropertyScope::Eth,197 vec![parent_nft_property_permissions()],198 )199 .map_err(dispatch_to_evm::<T>)?;200201 let address = pallet_common::eth::collection_id_to_address(collection_id);180 let address = pallet_common::eth::collection_id_to_address(collection_id);202 Ok(address)181 Ok(address)203}182}204183205/// @title Contract, which allows users to operate with collections184/// @title Contract, which allows users to operate with collections206#[solidity_interface(name = "CollectionHelpers", events(CollectionHelpersEvents))]185#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]207impl<T> EvmCollectionHelpers<T>186impl<T> EvmCollectionHelpers<T>208where187where209 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,188 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,210{189{211 /// Create an NFT collection190 /// Create an NFT collection212 /// @param name Name of the collection191 /// @param name Name of the collection213 /// @param description Informative description of the collection192 /// @param description Informative description of the collection214 /// @param token_prefix Token prefix to represent the collection tokens in UI and user applications193 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications215 /// @return address Address of the newly created collection194 /// @return address Address of the newly created collection216 #[weight(<SelfWeightOf<T>>::create_collection())]195 #[weight(<SelfWeightOf<T>>::create_collection())]217 fn create_nonfungible_collection(196 fn create_nonfungible_collection(304 }283 }305284306 /// Check if a collection exists285 /// Check if a collection exists307 /// @param collection_address Address of the collection in question286 /// @param collectionAddress Address of the collection in question308 /// @return bool Does the collection exist?287 /// @return bool Does the collection exist?309 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {288 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {310 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {289 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7contract Dummy {7contract Dummy {8 uint8 dummy;8 uint8 dummy;9 string stub_error = "this contract is implemented in native";9 string stub_error = "this contract is implemented in native";21 }21 }22}22}232324// Inline24/// @dev inlined interface25contract CollectionHelpersEvents {25contract CollectionHelpersEvents {26 event CollectionCreated(26 event CollectionCreated(27 address indexed owner,27 address indexed owner,28 address indexed collectionId28 address indexed collectionId29 );29 );30}30}313132// Selector: 675f307432/// @title Contract, which allows users to operate with collections33/// @dev the ERC-165 identifier for this interface is 0x675f307433contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {34contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {34 // Create an NFT collection35 /// Create an NFT collection35 // @param name Name of the collection36 /// @param name Name of the collection36 // @param description Informative description of the collection37 /// @param description Informative description of the collection37 // @param token_prefix Token prefix to represent the collection tokens in UI and user applications38 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications38 // @return address Address of the newly created collection39 /// @return address Address of the newly created collection39 //40 /// @dev EVM selector for this function is: 0xe34a6844,40 // Selector: createNonfungibleCollection(string,string,string) e34a684441 /// or in textual repr: createNonfungibleCollection(string,string,string)41 function createNonfungibleCollection(42 function createNonfungibleCollection(42 string memory name,43 string memory name,43 string memory description,44 string memory description,51 return 0x0000000000000000000000000000000000000000;52 return 0x0000000000000000000000000000000000000000;52 }53 }535455 /// @dev EVM selector for this function is: 0xa634a5f9,54 // Selector: createERC721MetadataCompatibleCollection(string,string,string,string) a634a5f956 /// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string)55 function createERC721MetadataCompatibleCollection(57 function createERC721MetadataCompatibleCollection(56 string memory name,58 string memory name,57 string memory description,59 string memory description,67 return 0x0000000000000000000000000000000000000000;69 return 0x0000000000000000000000000000000000000000;68 }70 }697172 /// @dev EVM selector for this function is: 0x44a68ad5,70 // Selector: createRefungibleCollection(string,string,string) 44a68ad573 /// or in textual repr: createRefungibleCollection(string,string,string)71 function createRefungibleCollection(74 function createRefungibleCollection(72 string memory name,75 string memory name,73 string memory description,76 string memory description,81 return 0x0000000000000000000000000000000000000000;84 return 0x0000000000000000000000000000000000000000;82 }85 }838687 /// @dev EVM selector for this function is: 0xa5596388,84 // Selector: createERC721MetadataCompatibleRFTCollection(string,string,string,string) a559638888 /// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string)85 function createERC721MetadataCompatibleRFTCollection(89 function createERC721MetadataCompatibleRFTCollection(86 string memory name,90 string memory name,87 string memory description,91 string memory description,97 return 0x0000000000000000000000000000000000000000;101 return 0x0000000000000000000000000000000000000000;98 }102 }99103100 // Check if a collection exists104 /// Check if a collection exists101 // @param collection_address Address of the collection in question105 /// @param collectionAddress Address of the collection in question102 // @return bool Does the collection exist?106 /// @return bool Does the collection exist?103 //107 /// @dev EVM selector for this function is: 0xc3de1494,104 // Selector: isCollectionExist(address) c3de1494108 /// or in textual repr: isCollectionExist(address)105 function isCollectionExist(address collectionAddress)109 function isCollectionExist(address collectionAddress)106 public110 public107 view111 viewprimitives/data-structs/src/lib.rsdiffbeforeafterboth1050pub enum PropertyScope {1050pub enum PropertyScope {1051 None,1051 None,1052 Rmrk,1052 Rmrk,1053 Eth,1054}1053}105510541056impl PropertyScope {1055impl PropertyScope {1059 let scope_str: &[u8] = match self {1058 let scope_str: &[u8] = match self {1060 Self::None => return Ok(key),1059 Self::None => return Ok(key),1061 Self::Rmrk => b"rmrk",1060 Self::Rmrk => b"rmrk",1062 Self::Eth => b"eth",1063 };1061 };106410621065 [scope_str, b":", key.as_slice()]1063 [scope_str, b":", key.as_slice()]runtime/common/config/ethereum.rsdiffbeforeafterboth120120121impl pallet_evm_transaction_payment::Config for Runtime {121impl pallet_evm_transaction_payment::Config for Runtime {122 type EvmSponsorshipHandler = EvmSponsorshipHandler;122 type EvmSponsorshipHandler = EvmSponsorshipHandler;123 type Currency = Balances;124}123}125124runtime/common/dispatch.rsdiffbeforeafterboth124 + pallet_fungible::Config124 + pallet_fungible::Config125 + pallet_nonfungible::Config125 + pallet_nonfungible::Config126 + pallet_refungible::Config,126 + pallet_refungible::Config,127 T::AccountId: From<[u8; 32]>,127 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,128{128{129 fn is_reserved(target: &H160) -> bool {129 fn is_reserved(target: &H160) -> bool {130 map_eth_to_id(target).is_some()130 map_eth_to_id(target).is_some()runtime/tests/src/lib.rsdiffbeforeafterboth167}167}168168169#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, TypeInfo, MaxEncodedLen)]169#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, TypeInfo, MaxEncodedLen)]170pub struct TestCrossAccountId(u64, sp_core::H160);170pub struct TestCrossAccountId(u64, sp_core::H160, bool);171impl CrossAccountId<u64> for TestCrossAccountId {171impl CrossAccountId<u64> for TestCrossAccountId {172 fn as_sub(&self) -> &u64 {172 fn as_sub(&self) -> &u64 {173 &self.0173 &self.0178 fn from_sub(sub: u64) -> Self {178 fn from_sub(sub: u64) -> Self {179 let mut eth = [0; 20];179 let mut eth = [0; 20];180 eth[12..20].copy_from_slice(&sub.to_be_bytes());180 eth[12..20].copy_from_slice(&sub.to_be_bytes());181 Self(sub, sp_core::H160(eth))181 Self(sub, sp_core::H160(eth), true)182 }182 }183 fn from_eth(eth: sp_core::H160) -> Self {183 fn from_eth(eth: sp_core::H160) -> Self {184 let mut sub_raw = [0; 8];184 let mut sub_raw = [0; 8];185 sub_raw.copy_from_slice(ð.0[0..8]);185 sub_raw.copy_from_slice(ð.0[0..8]);186 let sub = u64::from_be_bytes(sub_raw);186 let sub = u64::from_be_bytes(sub_raw);187 Self(sub, eth)187 Self(sub, eth, false)188 }188 }189 fn conv_eq(&self, other: &Self) -> bool {189 fn conv_eq(&self, other: &Self) -> bool {190 self.as_sub() == other.as_sub()190 self.as_sub() == other.as_sub()191 }191 }192 fn is_canonical_substrate(&self) -> bool {193 self.2194 }192}195}193196194impl Default for TestCrossAccountId {197impl Default for TestCrossAccountId {tests/src/addCollectionAdmin.test.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {ApiPromise} from '@polkadot/api';17import {IKeyringPair} from '@polkadot/types/types';18import chai from 'chai';18import chai from 'chai';19import chaiAsPromised from 'chai-as-promised';19import chaiAsPromised from 'chai-as-promised';20import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';21import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, destroyCollectionExpectSuccess, getAdminList, normalizeAccountId, queryCollectionExpectSuccess} from './util/helpers';20import {usingPlaygrounds} from './util/playgrounds';222123chai.use(chaiAsPromised);22chai.use(chaiAsPromised);24const expect = chai.expect;23const expect = chai.expect;2425let donor: IKeyringPair;2627before(async () => {28 await usingPlaygrounds(async (_, privateKeyWrapper) => {29 donor = privateKeyWrapper('//Alice');30 });31});253226describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {33describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {27 it('Add collection admin.', async () => {34 it('Add collection admin.', async () => {28 await usingApi(async (api, privateKeyWrapper) => {35 await usingPlaygrounds(async (helper) => {29 const collectionId = await createCollectionExpectSuccess();36 const [alice, bob] = await helper.arrange.creteAccounts([10n, 10n], donor);30 const alice = privateKeyWrapper('//Alice');37 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});31 const bob = privateKeyWrapper('//Bob');323833 const collection = await queryCollectionExpectSuccess(api, collectionId);39 const collection = await helper.collection.getData(collectionId);34 expect(collection.owner.toString()).to.be.equal(alice.address);40 expect(collection!.normalizedOwner!).to.be.equal(alice.address);354136 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));42 await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address});37 await submitTransactionAsync(alice, changeAdminTx);384339 const adminListAfterAddAdmin = await getAdminList(api, collectionId);44 const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId);40 expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address));45 expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});41 });46 });42 });47 });43});48});444945describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {50describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {46 it("Not owner can't add collection admin.", async () => {51 it("Not owner can't add collection admin.", async () => {47 await usingApi(async (api, privateKeyWrapper) => {52 await usingPlaygrounds(async (helper) => {48 const collectionId = await createCollectionExpectSuccess();53 const [alice, bob, charlie] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor);49 const alice = privateKeyWrapper('//Alice');50 const bob = privateKeyWrapper('//Bob');51 const charlie = privateKeyWrapper('//CHARLIE');54 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});525553 const collection = await queryCollectionExpectSuccess(api, collectionId);56 const collection = await helper.collection.getData(collectionId);54 expect(collection.owner.toString()).to.be.equal(alice.address);57 expect(collection?.normalizedOwner).to.be.equal(alice.address);555856 const adminListAfterAddAdmin = await getAdminList(api, collectionId);59 const changeAdminTxBob = async () => helper.collection.addAdmin(bob, collectionId, {Substrate: bob.address});57 expect(adminListAfterAddAdmin).to.be.not.deep.contains(normalizeAccountId(bob.address));5859 const changeAdminTxCharlie = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address));60 const changeAdminTxCharlie = async () => helper.collection.addAdmin(bob, collectionId, {Substrate: charlie.address});60 await expect(submitTransactionAsync(bob, changeAdminTxCharlie)).to.be.rejected;61 await expect(changeAdminTxCharlie()).to.be.rejected;61 62 await expect(changeAdminTxBob()).to.be.rejected;6362 const adminListAfterAddNewAdmin = await getAdminList(api, collectionId);64 const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId);63 expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(bob.address));65 expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: charlie.address});64 expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(charlie.address));66 expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: bob.address});65 });67 });66 });68 });676968 it("Admin can't add collection admin.", async () => {70 it("Admin can't add collection admin.", async () => {69 await usingApi(async (api, privateKeyWrapper) => {71 await usingPlaygrounds(async (helper) => {70 const collectionId = await createCollectionExpectSuccess();72 const [alice, bob, charlie] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor);71 const alice = privateKeyWrapper('//Alice');72 const bob = privateKeyWrapper('//Bob');73 const charlie = privateKeyWrapper('//CHARLIE');7475 const collection = await queryCollectionExpectSuccess(api, collectionId);73 const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});76 expect(collection.owner.toString()).to.be.equal(alice.address);777478 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));75 await collection.addAdmin(alice, {Substrate: bob.address});79 await submitTransactionAsync(alice, changeAdminTx);807681 const adminListAfterAddAdmin = await getAdminList(api, collectionId);77 const adminListAfterAddAdmin = await collection.getAdmins();82 expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address));78 expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address});837984 const changeAdminTxCharlie = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address));80 const changeAdminTxCharlie = async () => collection.addAdmin(bob, {Substrate: charlie.address});85 await expect(submitTransactionAsync(bob, changeAdminTxCharlie)).to.be.rejected;81 await expect(changeAdminTxCharlie()).to.be.rejected;86 8287 const adminListAfterAddNewAdmin = await getAdminList(api, collectionId);83 const adminListAfterAddNewAdmin = await collection.getAdmins();88 expect(adminListAfterAddNewAdmin).to.be.deep.contains(normalizeAccountId(bob.address));84 expect(adminListAfterAddNewAdmin).to.be.deep.contains({Substrate: bob.address});89 expect(adminListAfterAddNewAdmin).to.be.not.deep.contains(normalizeAccountId(charlie.address));85 expect(adminListAfterAddNewAdmin).to.be.not.deep.contains({Substrate: charlie.address});90 });86 });91 });87 });928893 it("Can't add collection admin of not existing collection.", async () => {89 it("Can't add collection admin of not existing collection.", async () => {94 await usingApi(async (api, privateKeyWrapper) => {90 await usingPlaygrounds(async (helper) => {91 const [alice, bob] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor);95 // tslint:disable-next-line: no-bitwise92 // tslint:disable-next-line: no-bitwise96 const collectionId = (1 << 32) - 1;93 const collectionId = (1 << 32) - 1;97 const alice = privateKeyWrapper('//Alice');98 const bob = privateKeyWrapper('//Bob');9994100 const changeOwnerTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));95 const addAdminTx = async () => helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});101 await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected;96 await expect(addAdminTx()).to.be.rejected;10297103 // Verifying that nothing bad happened (network is live, new collections can be created, etc.)98 // Verifying that nothing bad happened (network is live, new collections can be created, etc.)104 await createCollectionExpectSuccess();99 await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});105 });100 });106 });101 });107102108 it("Can't add an admin to a destroyed collection.", async () => {103 it("Can't add an admin to a destroyed collection.", async () => {109 await usingApi(async (api, privateKeyWrapper) => {104 await usingPlaygrounds(async (helper) => {110 const collectionId = await createCollectionExpectSuccess();105 const [alice, bob] = await helper.arrange.creteAccounts([10n, 10n, 10n], donor);111 const alice = privateKeyWrapper('//Alice');106 const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});112 const bob = privateKeyWrapper('//Bob');107113 await destroyCollectionExpectSuccess(collectionId);108 await collection.burn(alice);114 const changeOwnerTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));109 const addAdminTx = async () => collection.addAdmin(alice, {Substrate: bob.address});115 await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected;110 await expect(addAdminTx()).to.be.rejected;116111117 // Verifying that nothing bad happened (network is live, new collections can be created, etc.)112 // Verifying that nothing bad happened (network is live, new collections can be created, etc.)118 await createCollectionExpectSuccess();113 await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});119 });114 });120 });115 });121116122 it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {117 it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {123 await usingApi(async (api: ApiPromise, privateKeyWrapper) => {118 await usingPlaygrounds(async (helper) => {124 const alice = privateKeyWrapper('//Alice');125 const accounts = [119 const [alice, ...accounts] = await helper.arrange.creteAccounts([10n, 0n, 0n, 0n, 0n, 0n, 0n, 0n], donor);126 privateKeyWrapper('//AdminTest/1').address,127 privateKeyWrapper('//AdminTest/2').address,128 privateKeyWrapper('//AdminTest/3').address,129 privateKeyWrapper('//AdminTest/4').address,130 privateKeyWrapper('//AdminTest/5').address,131 privateKeyWrapper('//AdminTest/6').address,132 privateKeyWrapper('//AdminTest/7').address,133 ];134 const collectionId = await createCollectionExpectSuccess();120 const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'});135121136 const chainAdminLimit = (api.consts.common.collectionAdminsLimit as any).toNumber();122 const chainAdminLimit = (helper.api!.consts.common.collectionAdminsLimit as any).toNumber();137 expect(chainAdminLimit).to.be.equal(5);123 expect(chainAdminLimit).to.be.equal(5);138124139 for (let i = 0; i < chainAdminLimit; i++) {125 for (let i = 0; i < chainAdminLimit; i++) {140 await addCollectionAdminExpectSuccess(alice, collectionId, accounts[i]);126 await collection.addAdmin(alice, {Substrate: accounts[i].address});141 const adminListAfterAddAdmin = await getAdminList(api, collectionId);127 const adminListAfterAddAdmin = await collection.getAdmins();142 expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(accounts[i]));128 expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: accounts[i].address});143 }129 }144130145 const tx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(accounts[chainAdminLimit]));131 const addExtraAdminTx = async () => collection.addAdmin(alice, {Substrate: accounts[chainAdminLimit].address});146 await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;132 await expect(addExtraAdminTx()).to.be.rejected;147 });133 });148 });134 });149});135});tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7interface Dummy {7interface Dummy {889}9}12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);13}13}141415// Inline15/// @dev inlined interface16interface CollectionHelpersEvents {16interface CollectionHelpersEvents {17 event CollectionCreated(17 event CollectionCreated(18 address indexed owner,18 address indexed owner,19 address indexed collectionId19 address indexed collectionId20 );20 );21}21}222223// Selector: 675f307423/// @title Contract, which allows users to operate with collections24/// @dev the ERC-165 identifier for this interface is 0x675f307424interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {25interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {25 // Create an NFT collection26 /// Create an NFT collection26 // @param name Name of the collection27 /// @param name Name of the collection27 // @param description Informative description of the collection28 /// @param description Informative description of the collection28 // @param token_prefix Token prefix to represent the collection tokens in UI and user applications29 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications29 // @return address Address of the newly created collection30 /// @return address Address of the newly created collection30 //31 /// @dev EVM selector for this function is: 0xe34a6844,31 // Selector: createNonfungibleCollection(string,string,string) e34a684432 /// or in textual repr: createNonfungibleCollection(string,string,string)32 function createNonfungibleCollection(33 function createNonfungibleCollection(33 string memory name,34 string memory name,34 string memory description,35 string memory description,35 string memory tokenPrefix36 string memory tokenPrefix36 ) external returns (address);37 ) external returns (address);373839 /// @dev EVM selector for this function is: 0xa634a5f9,38 // Selector: createERC721MetadataCompatibleCollection(string,string,string,string) a634a5f940 /// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string)39 function createERC721MetadataCompatibleCollection(41 function createERC721MetadataCompatibleCollection(40 string memory name,42 string memory name,41 string memory description,43 string memory description,42 string memory tokenPrefix,44 string memory tokenPrefix,43 string memory baseUri45 string memory baseUri44 ) external returns (address);46 ) external returns (address);454748 /// @dev EVM selector for this function is: 0x44a68ad5,46 // Selector: createRefungibleCollection(string,string,string) 44a68ad549 /// or in textual repr: createRefungibleCollection(string,string,string)47 function createRefungibleCollection(50 function createRefungibleCollection(48 string memory name,51 string memory name,49 string memory description,52 string memory description,50 string memory tokenPrefix53 string memory tokenPrefix51 ) external returns (address);54 ) external returns (address);525556 /// @dev EVM selector for this function is: 0xa5596388,53 // Selector: createERC721MetadataCompatibleRFTCollection(string,string,string,string) a559638857 /// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string)54 function createERC721MetadataCompatibleRFTCollection(58 function createERC721MetadataCompatibleRFTCollection(55 string memory name,59 string memory name,56 string memory description,60 string memory description,57 string memory tokenPrefix,61 string memory tokenPrefix,58 string memory baseUri62 string memory baseUri59 ) external returns (address);63 ) external returns (address);606461 // Check if a collection exists65 /// Check if a collection exists62 // @param collection_address Address of the collection in question66 /// @param collectionAddress Address of the collection in question63 // @return bool Does the collection exist?67 /// @return bool Does the collection exist?64 //68 /// @dev EVM selector for this function is: 0xc3de1494,65 // Selector: isCollectionExist(address) c3de149469 /// or in textual repr: isCollectionExist(address)66 function isCollectionExist(address collectionAddress)70 function isCollectionExist(address collectionAddress)67 external71 external68 view72 viewtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7interface Dummy {7interface Dummy {889}9}12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);13}13}141415// Selector: 7b4866f915/// @title Magic contract, which allows users to reconfigure other contracts16/// @dev the ERC-165 identifier for this interface is 0xd77fab7016interface ContractHelpers is Dummy, ERC165 {17interface ContractHelpers is Dummy, ERC165 {17 // Selector: contractOwner(address) 5152b14c18 /// Get user, which deployed specified contract19 /// @dev May return zero address in case if contract is deployed20 /// using uniquenetwork evm-migration pallet, or using other terms not21 /// intended by pallet-evm22 /// @dev Returns zero address if contract does not exists23 /// @param contractAddress Contract to get owner of24 /// @return address Owner of contract25 /// @dev EVM selector for this function is: 0x5152b14c,26 /// or in textual repr: contractOwner(address)18 function contractOwner(address contractAddress)27 function contractOwner(address contractAddress)19 external28 external20 view29 view21 returns (address);30 returns (address);223123 // Selector: sponsoringEnabled(address) 6027dc6132 /// Set sponsor.33 /// @param contractAddress Contract for which a sponsor is being established.34 /// @param sponsor User address who set as pending sponsor.35 /// @dev EVM selector for this function is: 0xf01fba93,36 /// or in textual repr: setSponsor(address,address)37 function setSponsor(address contractAddress, address sponsor) external;3839 /// Set contract as self sponsored.40 ///41 /// @param contractAddress Contract for which a self sponsoring is being enabled.42 /// @dev EVM selector for this function is: 0x89f7d9ae,43 /// or in textual repr: selfSponsoredEnable(address)44 function selfSponsoredEnable(address contractAddress) external;4546 /// Remove sponsor.47 ///48 /// @param contractAddress Contract for which a sponsorship is being removed.49 /// @dev EVM selector for this function is: 0xef784250,50 /// or in textual repr: removeSponsor(address)51 function removeSponsor(address contractAddress) external;5253 /// Confirm sponsorship.54 ///55 /// @dev Caller must be same that set via [`setSponsor`].56 ///57 /// @param contractAddress Сontract for which need to confirm sponsorship.58 /// @dev EVM selector for this function is: 0xabc00001,59 /// or in textual repr: confirmSponsorship(address)60 function confirmSponsorship(address contractAddress) external;6162 /// Get current sponsor.63 ///64 /// @param contractAddress The contract for which a sponsor is requested.65 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.66 /// @dev EVM selector for this function is: 0x743fc745,67 /// or in textual repr: getSponsor(address)68 function getSponsor(address contractAddress)69 external70 view71 returns (Tuple0 memory);7273 /// Check tat contract has confirmed sponsor.74 ///75 /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.76 /// @return **true** if contract has confirmed sponsor.77 /// @dev EVM selector for this function is: 0x97418603,78 /// or in textual repr: hasSponsor(address)24 function sponsoringEnabled(address contractAddress)79 function hasSponsor(address contractAddress) external view returns (bool);25 external8026 view81 /// Check tat contract has pending sponsor.27 returns (bool);82 ///2883 /// @param contractAddress The contract for which the presence of a pending sponsor is checked.29 // Deprecated84 /// @return **true** if contract has pending sponsor.30 //85 /// @dev EVM selector for this function is: 0x39b9b242,31 // Selector: toggleSponsoring(address,bool) fcac6d8686 /// or in textual repr: hasPendingSponsor(address)32 function toggleSponsoring(address contractAddress, bool enabled) external;87 function hasPendingSponsor(address contractAddress)3388 external89 view90 returns (bool);9192 /// @dev EVM selector for this function is: 0x6027dc61,93 /// or in textual repr: sponsoringEnabled(address)94 function sponsoringEnabled(address contractAddress)95 external96 view97 returns (bool);9899 /// @dev EVM selector for this function is: 0xfde8a560,34 // Selector: setSponsoringMode(address,uint8) fde8a560100 /// or in textual repr: setSponsoringMode(address,uint8)35 function setSponsoringMode(address contractAddress, uint8 mode) external;101 function setSponsoringMode(address contractAddress, uint8 mode) external;3610237 // Selector: sponsoringMode(address) b70c7267103 /// Get current contract sponsoring rate limit104 /// @param contractAddress Contract to get sponsoring mode of105 /// @return uint32 Amount of blocks between two sponsored transactions106 /// @dev EVM selector for this function is: 0x610cfabd,107 /// or in textual repr: getSponsoringRateLimit(address)38 function sponsoringMode(address contractAddress)108 function getSponsoringRateLimit(address contractAddress)39 external109 external40 view110 view41 returns (uint8);111 returns (uint32);42112113 /// Set contract sponsoring rate limit114 /// @dev Sponsoring rate limit - is a minimum amount of blocks that should115 /// pass between two sponsored transactions116 /// @param contractAddress Contract to change sponsoring rate limit of117 /// @param rateLimit Target rate limit118 /// @dev Only contract owner can change this setting119 /// @dev EVM selector for this function is: 0x77b6c908,43 // Selector: setSponsoringRateLimit(address,uint32) 77b6c908120 /// or in textual repr: setSponsoringRateLimit(address,uint32)44 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)121 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)45 external;122 external;4612347 // Selector: getSponsoringRateLimit(address) 610cfabd124 /// Is specified user present in contract allow list125 /// @dev Contract owner always implicitly included126 /// @param contractAddress Contract to check allowlist of127 /// @param user User to check128 /// @return bool Is specified users exists in contract allowlist129 /// @dev EVM selector for this function is: 0x5c658165,130 /// or in textual repr: allowed(address,address)48 function getSponsoringRateLimit(address contractAddress)131 function allowed(address contractAddress, address user)49 external132 external50 view133 view51 returns (uint32);134 returns (bool);5213553 // Selector: allowed(address,address) 5c658165136 /// Toggle user presence in contract allowlist137 /// @param contractAddress Contract to change allowlist of138 /// @param user Which user presence should be toggled139 /// @param isAllowed `true` if user should be allowed to be sponsored140 /// or call this contract, `false` otherwise141 /// @dev Only contract owner can change this setting142 /// @dev EVM selector for this function is: 0x4706cc1c,143 /// or in textual repr: toggleAllowed(address,address,bool)54 function allowed(address contractAddress, address user)144 function toggleAllowed(145 address contractAddress,146 address user,147 bool isAllowed55 external148 ) external;56 view14957 returns (bool);150 /// Is this contract has allowlist access enabled58151 /// @dev Allowlist always can have users, and it is used for two purposes:59 // Selector: allowlistEnabled(address) c772ef6c152 /// in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist153 /// in case of allowlist access enabled, only users from allowlist may call this contract154 /// @param contractAddress Contract to get allowlist access of155 /// @return bool Is specified contract has allowlist access enabled156 /// @dev EVM selector for this function is: 0xc772ef6c,157 /// or in textual repr: allowlistEnabled(address)60 function allowlistEnabled(address contractAddress)158 function allowlistEnabled(address contractAddress)61 external159 external62 view160 view63 returns (bool);161 returns (bool);64162163 /// Toggle contract allowlist access164 /// @param contractAddress Contract to change allowlist access of165 /// @param enabled Should allowlist access to be enabled?166 /// @dev EVM selector for this function is: 0x36de20f5,65 // Selector: toggleAllowlist(address,bool) 36de20f5167 /// or in textual repr: toggleAllowlist(address,bool)66 function toggleAllowlist(address contractAddress, bool enabled) external;168 function toggleAllowlist(address contractAddress, bool enabled) external;6768 // Selector: toggleAllowed(address,address,bool) 4706cc1c69 function toggleAllowed(70 address contractAddress,71 address user,72 bool allowed73 ) external;74}169}170171/// @dev anonymous struct172struct Tuple0 {173 address field_0;174 uint256 field_1;175}75176tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7interface Dummy {7interface Dummy {889}9}12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);13}13}141415// Inline15/// @title A contract that allows you to work with collections.16/// @dev the ERC-165 identifier for this interface is 0xe54be64017interface Collection is Dummy, ERC165 {18 /// Set collection property.19 ///20 /// @param key Property key.21 /// @param value Propery value.22 /// @dev EVM selector for this function is: 0x2f073f66,23 /// or in textual repr: setCollectionProperty(string,bytes)24 function setCollectionProperty(string memory key, bytes memory value)25 external;2627 /// Delete collection property.28 ///29 /// @param key Property key.30 /// @dev EVM selector for this function is: 0x7b7debce,31 /// or in textual repr: deleteCollectionProperty(string)32 function deleteCollectionProperty(string memory key) external;3334 /// Get collection property.35 ///36 /// @dev Throws error if key not found.37 ///38 /// @param key Property key.39 /// @return bytes The property corresponding to the key.40 /// @dev EVM selector for this function is: 0xcf24fd6d,41 /// or in textual repr: collectionProperty(string)42 function collectionProperty(string memory key)43 external44 view45 returns (bytes memory);4647 /// Set the sponsor of the collection.48 ///49 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.50 ///51 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.52 /// @dev EVM selector for this function is: 0x7623402e,53 /// or in textual repr: setCollectionSponsor(address)54 function setCollectionSponsor(address sponsor) external;5556 /// Set the substrate sponsor of the collection.57 ///58 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.59 ///60 /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.61 /// @dev EVM selector for this function is: 0xc74d6751,62 /// or in textual repr: setCollectionSponsorSubstrate(uint256)63 function setCollectionSponsorSubstrate(uint256 sponsor) external;6465 /// @dev EVM selector for this function is: 0x058ac185,66 /// or in textual repr: hasCollectionPendingSponsor()67 function hasCollectionPendingSponsor() external view returns (bool);6869 /// Collection sponsorship confirmation.70 ///71 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.72 /// @dev EVM selector for this function is: 0x3c50e97a,73 /// or in textual repr: confirmCollectionSponsorship()74 function confirmCollectionSponsorship() external;7576 /// Remove collection sponsor.77 /// @dev EVM selector for this function is: 0x6e0326a3,78 /// or in textual repr: removeCollectionSponsor()79 function removeCollectionSponsor() external;8081 /// Get current sponsor.82 ///83 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.84 /// @dev EVM selector for this function is: 0xb66bbc14,85 /// or in textual repr: getCollectionSponsor()86 function getCollectionSponsor() external view returns (Tuple6 memory);8788 /// Set limits for the collection.89 /// @dev Throws error if limit not found.90 /// @param limit Name of the limit. Valid names:91 /// "accountTokenOwnershipLimit",92 /// "sponsoredDataSize",93 /// "sponsoredDataRateLimit",94 /// "tokenLimit",95 /// "sponsorTransferTimeout",96 /// "sponsorApproveTimeout"97 /// @param value Value of the limit.98 /// @dev EVM selector for this function is: 0x6a3841db,99 /// or in textual repr: setCollectionLimit(string,uint32)100 function setCollectionLimit(string memory limit, uint32 value) external;101102 /// Set limits for the collection.103 /// @dev Throws error if limit not found.104 /// @param limit Name of the limit. Valid names:105 /// "ownerCanTransfer",106 /// "ownerCanDestroy",107 /// "transfersEnabled"108 /// @param value Value of the limit.109 /// @dev EVM selector for this function is: 0x993b7fba,110 /// or in textual repr: setCollectionLimit(string,bool)111 function setCollectionLimit(string memory limit, bool value) external;112113 /// Get contract address.114 /// @dev EVM selector for this function is: 0xf6b4dfb4,115 /// or in textual repr: contractAddress()116 function contractAddress() external view returns (address);117118 /// Add collection admin by substrate address.119 /// @param newAdmin Substrate administrator address.120 /// @dev EVM selector for this function is: 0x5730062b,121 /// or in textual repr: addCollectionAdminSubstrate(uint256)122 function addCollectionAdminSubstrate(uint256 newAdmin) external;123124 /// Remove collection admin by substrate address.125 /// @param admin Substrate administrator address.126 /// @dev EVM selector for this function is: 0x4048fcf9,127 /// or in textual repr: removeCollectionAdminSubstrate(uint256)128 function removeCollectionAdminSubstrate(uint256 admin) external;129130 /// Add collection admin.131 /// @param newAdmin Address of the added administrator.132 /// @dev EVM selector for this function is: 0x92e462c7,133 /// or in textual repr: addCollectionAdmin(address)134 function addCollectionAdmin(address newAdmin) external;135136 /// Remove collection admin.137 ///138 /// @param admin Address of the removed administrator.139 /// @dev EVM selector for this function is: 0xfafd7b42,140 /// or in textual repr: removeCollectionAdmin(address)141 function removeCollectionAdmin(address admin) external;142143 /// Toggle accessibility of collection nesting.144 ///145 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'146 /// @dev EVM selector for this function is: 0x112d4586,147 /// or in textual repr: setCollectionNesting(bool)148 function setCollectionNesting(bool enable) external;149150 /// Toggle accessibility of collection nesting.151 ///152 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'153 /// @param collections Addresses of collections that will be available for nesting.154 /// @dev EVM selector for this function is: 0x64872396,155 /// or in textual repr: setCollectionNesting(bool,address[])156 function setCollectionNesting(bool enable, address[] memory collections)157 external;158159 /// Set the collection access method.160 /// @param mode Access mode161 /// 0 for Normal162 /// 1 for AllowList163 /// @dev EVM selector for this function is: 0x41835d4c,164 /// or in textual repr: setCollectionAccess(uint8)165 function setCollectionAccess(uint8 mode) external;166167 /// Add the user to the allowed list.168 ///169 /// @param user Address of a trusted user.170 /// @dev EVM selector for this function is: 0x67844fe6,171 /// or in textual repr: addToCollectionAllowList(address)172 function addToCollectionAllowList(address user) external;173174 /// Remove the user from the allowed list.175 ///176 /// @param user Address of a removed user.177 /// @dev EVM selector for this function is: 0x85c51acb,178 /// or in textual repr: removeFromCollectionAllowList(address)179 function removeFromCollectionAllowList(address user) external;180181 /// Switch permission for minting.182 ///183 /// @param mode Enable if "true".184 /// @dev EVM selector for this function is: 0x00018e84,185 /// or in textual repr: setCollectionMintMode(bool)186 function setCollectionMintMode(bool mode) external;187188 /// Check that account is the owner or admin of the collection189 ///190 /// @param user account to verify191 /// @return "true" if account is the owner or admin192 /// @dev EVM selector for this function is: 0x9811b0c7,193 /// or in textual repr: isOwnerOrAdmin(address)194 function isOwnerOrAdmin(address user) external view returns (bool);195196 /// Check that substrate account is the owner or admin of the collection197 ///198 /// @param user account to verify199 /// @return "true" if account is the owner or admin200 /// @dev EVM selector for this function is: 0x68910e00,201 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)202 function isOwnerOrAdminSubstrate(uint256 user) external view returns (bool);203204 /// Returns collection type205 ///206 /// @return `Fungible` or `NFT` or `ReFungible`207 /// @dev EVM selector for this function is: 0xd34b55b8,208 /// or in textual repr: uniqueCollectionType()209 function uniqueCollectionType() external returns (string memory);210211 /// Changes collection owner to another account212 ///213 /// @dev Owner can be changed only by current owner214 /// @param newOwner new owner account215 /// @dev EVM selector for this function is: 0x13af4035,216 /// or in textual repr: setOwner(address)217 function setOwner(address newOwner) external;218219 /// Changes collection owner to another substrate account220 ///221 /// @dev Owner can be changed only by current owner222 /// @param newOwner new owner substrate account223 /// @dev EVM selector for this function is: 0xb212138f,224 /// or in textual repr: setOwnerSubstrate(uint256)225 function setOwnerSubstrate(uint256 newOwner) external;226}227228/// @dev the ERC-165 identifier for this interface is 0x63034ac5229interface ERC20UniqueExtensions is Dummy, ERC165 {230 /// Burn tokens from account231 /// @dev Function that burns an `amount` of the tokens of a given account,232 /// deducting from the sender's allowance for said account.233 /// @param from The account whose tokens will be burnt.234 /// @param amount The amount that will be burnt.235 /// @dev EVM selector for this function is: 0x79cc6790,236 /// or in textual repr: burnFrom(address,uint256)237 function burnFrom(address from, uint256 amount) external returns (bool);238239 /// Mint tokens for multiple accounts.240 /// @param amounts array of pairs of account address and amount241 /// @dev EVM selector for this function is: 0x1acf2d55,242 /// or in textual repr: mintBulk((address,uint256)[])243 function mintBulk(Tuple6[] memory amounts) external returns (bool);244}245246/// @dev anonymous struct247struct Tuple6 {248 address field_0;249 uint256 field_1;250}251252/// @dev the ERC-165 identifier for this interface is 0x40c10f19253interface ERC20Mintable is Dummy, ERC165 {254 /// Mint tokens for `to` account.255 /// @param to account that will receive minted tokens256 /// @param amount amount of tokens to mint257 /// @dev EVM selector for this function is: 0x40c10f19,258 /// or in textual repr: mint(address,uint256)259 function mint(address to, uint256 amount) external returns (bool);260}261262/// @dev inlined interface16interface ERC20Events {263interface ERC20Events {17 event Transfer(address indexed from, address indexed to, uint256 value);264 event Transfer(address indexed from, address indexed to, uint256 value);18 event Approval(265 event Approval(22 );269 );23}270}2427125// Selector: 6cf113cd272/// @dev the ERC-165 identifier for this interface is 0x942e8b2226interface Collection is Dummy, ERC165 {27 // Set collection property.28 //29 // @param key Property key.30 // @param value Propery value.31 //32 // Selector: setCollectionProperty(string,bytes) 2f073f6633 function setCollectionProperty(string memory key, bytes memory value)34 external;3536 // Delete collection property.37 //38 // @param key Property key.39 //40 // Selector: deleteCollectionProperty(string) 7b7debce41 function deleteCollectionProperty(string memory key) external;4243 // Get collection property.44 //45 // @dev Throws error if key not found.46 //47 // @param key Property key.48 // @return bytes The property corresponding to the key.49 //50 // Selector: collectionProperty(string) cf24fd6d51 function collectionProperty(string memory key)52 external53 view54 returns (bytes memory);5556 // Set the sponsor of the collection.57 //58 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.59 //60 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.61 //62 // Selector: setCollectionSponsor(address) 7623402e63 function setCollectionSponsor(address sponsor) external;6465 // Collection sponsorship confirmation.66 //67 // @dev After setting the sponsor for the collection, it must be confirmed with this function.68 //69 // Selector: confirmCollectionSponsorship() 3c50e97a70 function confirmCollectionSponsorship() external;7172 // Set limits for the collection.73 // @dev Throws error if limit not found.74 // @param limit Name of the limit. Valid names:75 // "accountTokenOwnershipLimit",76 // "sponsoredDataSize",77 // "sponsoredDataRateLimit",78 // "tokenLimit",79 // "sponsorTransferTimeout",80 // "sponsorApproveTimeout"81 // @param value Value of the limit.82 //83 // Selector: setCollectionLimit(string,uint32) 6a3841db84 function setCollectionLimit(string memory limit, uint32 value) external;8586 // Set limits for the collection.87 // @dev Throws error if limit not found.88 // @param limit Name of the limit. Valid names:89 // "ownerCanTransfer",90 // "ownerCanDestroy",91 // "transfersEnabled"92 // @param value Value of the limit.93 //94 // Selector: setCollectionLimit(string,bool) 993b7fba95 function setCollectionLimit(string memory limit, bool value) external;9697 // Get contract address.98 //99 // Selector: contractAddress() f6b4dfb4100 function contractAddress() external view returns (address);101102 // Add collection admin by substrate address.103 // @param new_admin Substrate administrator address.104 //105 // Selector: addCollectionAdminSubstrate(uint256) 5730062b106 function addCollectionAdminSubstrate(uint256 newAdmin) external;107108 // Remove collection admin by substrate address.109 // @param admin Substrate administrator address.110 //111 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9112 function removeCollectionAdminSubstrate(uint256 admin) external;113114 // Add collection admin.115 // @param new_admin Address of the added administrator.116 //117 // Selector: addCollectionAdmin(address) 92e462c7118 function addCollectionAdmin(address newAdmin) external;119120 // Remove collection admin.121 //122 // @param new_admin Address of the removed administrator.123 //124 // Selector: removeCollectionAdmin(address) fafd7b42125 function removeCollectionAdmin(address admin) external;126127 // Toggle accessibility of collection nesting.128 //129 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'130 //131 // Selector: setCollectionNesting(bool) 112d4586132 function setCollectionNesting(bool enable) external;133134 // Toggle accessibility of collection nesting.135 //136 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'137 // @param collections Addresses of collections that will be available for nesting.138 //139 // Selector: setCollectionNesting(bool,address[]) 64872396140 function setCollectionNesting(bool enable, address[] memory collections)141 external;142143 // Set the collection access method.144 // @param mode Access mode145 // 0 for Normal146 // 1 for AllowList147 //148 // Selector: setCollectionAccess(uint8) 41835d4c149 function setCollectionAccess(uint8 mode) external;150151 // Add the user to the allowed list.152 //153 // @param user Address of a trusted user.154 //155 // Selector: addToCollectionAllowList(address) 67844fe6156 function addToCollectionAllowList(address user) external;157158 // Remove the user from the allowed list.159 //160 // @param user Address of a removed user.161 //162 // Selector: removeFromCollectionAllowList(address) 85c51acb163 function removeFromCollectionAllowList(address user) external;164165 // Switch permission for minting.166 //167 // @param mode Enable if "true".168 //169 // Selector: setCollectionMintMode(bool) 00018e84170 function setCollectionMintMode(bool mode) external;171172 // Check that account is the owner or admin of the collection173 //174 // @param user account to verify175 // @return "true" if account is the owner or admin176 //177 // Selector: verifyOwnerOrAdmin(address) c2282493178 function verifyOwnerOrAdmin(address user) external view returns (bool);179180 // Returns collection type181 //182 // @return `Fungible` or `NFT` or `ReFungible`183 //184 // Selector: uniqueCollectionType() d34b55b8185 function uniqueCollectionType() external returns (string memory);186}187188// Selector: 79cc6790189interface ERC20UniqueExtensions is Dummy, ERC165 {190 // Selector: burnFrom(address,uint256) 79cc6790191 function burnFrom(address from, uint256 amount) external returns (bool);192}193194// Selector: 942e8b22195interface ERC20 is Dummy, ERC165, ERC20Events {273interface ERC20 is Dummy, ERC165, ERC20Events {196 // Selector: name() 06fdde03274 /// @dev EVM selector for this function is: 0x06fdde03,275 /// or in textual repr: name()197 function name() external view returns (string memory);276 function name() external view returns (string memory);198277199 // Selector: symbol() 95d89b41278 /// @dev EVM selector for this function is: 0x95d89b41,279 /// or in textual repr: symbol()200 function symbol() external view returns (string memory);280 function symbol() external view returns (string memory);201281202 // Selector: totalSupply() 18160ddd282 /// @dev EVM selector for this function is: 0x18160ddd,283 /// or in textual repr: totalSupply()203 function totalSupply() external view returns (uint256);284 function totalSupply() external view returns (uint256);204285205 // Selector: decimals() 313ce567286 /// @dev EVM selector for this function is: 0x313ce567,287 /// or in textual repr: decimals()206 function decimals() external view returns (uint8);288 function decimals() external view returns (uint8);207289290 /// @dev EVM selector for this function is: 0x70a08231,208 // Selector: balanceOf(address) 70a08231291 /// or in textual repr: balanceOf(address)209 function balanceOf(address owner) external view returns (uint256);292 function balanceOf(address owner) external view returns (uint256);210293294 /// @dev EVM selector for this function is: 0xa9059cbb,211 // Selector: transfer(address,uint256) a9059cbb295 /// or in textual repr: transfer(address,uint256)212 function transfer(address to, uint256 amount) external returns (bool);296 function transfer(address to, uint256 amount) external returns (bool);213297298 /// @dev EVM selector for this function is: 0x23b872dd,214 // Selector: transferFrom(address,address,uint256) 23b872dd299 /// or in textual repr: transferFrom(address,address,uint256)215 function transferFrom(300 function transferFrom(216 address from,301 address from,217 address to,302 address to,218 uint256 amount303 uint256 amount219 ) external returns (bool);304 ) external returns (bool);220305306 /// @dev EVM selector for this function is: 0x095ea7b3,221 // Selector: approve(address,uint256) 095ea7b3307 /// or in textual repr: approve(address,uint256)222 function approve(address spender, uint256 amount) external returns (bool);308 function approve(address spender, uint256 amount) external returns (bool);223309310 /// @dev EVM selector for this function is: 0xdd62ed3e,224 // Selector: allowance(address,address) dd62ed3e311 /// or in textual repr: allowance(address,address)225 function allowance(address owner, address spender)312 function allowance(address owner, address spender)226 external313 external227 view314 view232 Dummy,319 Dummy,233 ERC165,320 ERC165,234 ERC20,321 ERC20,322 ERC20Mintable,235 ERC20UniqueExtensions,323 ERC20UniqueExtensions,236 Collection324 Collection237{}325{}tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 uint256 field_0;9 string field_1;10}11512// Common stubs holder6/// @dev common stubs holder13interface Dummy {7interface Dummy {14815}9}18 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);19}13}201421// Inline15/// @title A contract that allows to set and delete token properties and change token property permissions.16/// @dev the ERC-165 identifier for this interface is 0x4136937717interface TokenProperties is Dummy, ERC165 {18 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 /// @param key Property key.21 /// @param isMutable Permission to mutate property.22 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 /// @dev EVM selector for this function is: 0x222d97fa,25 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)26 function setTokenPropertyPermission(27 string memory key,28 bool isMutable,29 bool collectionAdmin,30 bool tokenOwner31 ) external;3233 /// @notice Set token property value.34 /// @dev Throws error if `msg.sender` has no permission to edit the property.35 /// @param tokenId ID of the token.36 /// @param key Property key.37 /// @param value Property value.38 /// @dev EVM selector for this function is: 0x1752d67b,39 /// or in textual repr: setProperty(uint256,string,bytes)40 function setProperty(41 uint256 tokenId,42 string memory key,43 bytes memory value44 ) external;4546 /// @notice Delete token property value.47 /// @dev Throws error if `msg.sender` has no permission to edit the property.48 /// @param tokenId ID of the token.49 /// @param key Property key.50 /// @dev EVM selector for this function is: 0x066111d1,51 /// or in textual repr: deleteProperty(uint256,string)52 function deleteProperty(uint256 tokenId, string memory key) external;5354 /// @notice Get token property value.55 /// @dev Throws error if key not found56 /// @param tokenId ID of the token.57 /// @param key Property key.58 /// @return Property value bytes59 /// @dev EVM selector for this function is: 0x7228c327,60 /// or in textual repr: property(uint256,string)61 function property(uint256 tokenId, string memory key)62 external63 view64 returns (bytes memory);65}6667/// @title A contract that allows you to work with collections.68/// @dev the ERC-165 identifier for this interface is 0xe54be64069interface Collection is Dummy, ERC165 {70 /// Set collection property.71 ///72 /// @param key Property key.73 /// @param value Propery value.74 /// @dev EVM selector for this function is: 0x2f073f66,75 /// or in textual repr: setCollectionProperty(string,bytes)76 function setCollectionProperty(string memory key, bytes memory value)77 external;7879 /// Delete collection property.80 ///81 /// @param key Property key.82 /// @dev EVM selector for this function is: 0x7b7debce,83 /// or in textual repr: deleteCollectionProperty(string)84 function deleteCollectionProperty(string memory key) external;8586 /// Get collection property.87 ///88 /// @dev Throws error if key not found.89 ///90 /// @param key Property key.91 /// @return bytes The property corresponding to the key.92 /// @dev EVM selector for this function is: 0xcf24fd6d,93 /// or in textual repr: collectionProperty(string)94 function collectionProperty(string memory key)95 external96 view97 returns (bytes memory);9899 /// Set the sponsor of the collection.100 ///101 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.102 ///103 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.104 /// @dev EVM selector for this function is: 0x7623402e,105 /// or in textual repr: setCollectionSponsor(address)106 function setCollectionSponsor(address sponsor) external;107108 /// Set the substrate sponsor of the collection.109 ///110 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.111 ///112 /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.113 /// @dev EVM selector for this function is: 0xc74d6751,114 /// or in textual repr: setCollectionSponsorSubstrate(uint256)115 function setCollectionSponsorSubstrate(uint256 sponsor) external;116117 /// @dev EVM selector for this function is: 0x058ac185,118 /// or in textual repr: hasCollectionPendingSponsor()119 function hasCollectionPendingSponsor() external view returns (bool);120121 /// Collection sponsorship confirmation.122 ///123 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.124 /// @dev EVM selector for this function is: 0x3c50e97a,125 /// or in textual repr: confirmCollectionSponsorship()126 function confirmCollectionSponsorship() external;127128 /// Remove collection sponsor.129 /// @dev EVM selector for this function is: 0x6e0326a3,130 /// or in textual repr: removeCollectionSponsor()131 function removeCollectionSponsor() external;132133 /// Get current sponsor.134 ///135 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.136 /// @dev EVM selector for this function is: 0xb66bbc14,137 /// or in textual repr: getCollectionSponsor()138 function getCollectionSponsor() external view returns (Tuple17 memory);139140 /// Set limits for the collection.141 /// @dev Throws error if limit not found.142 /// @param limit Name of the limit. Valid names:143 /// "accountTokenOwnershipLimit",144 /// "sponsoredDataSize",145 /// "sponsoredDataRateLimit",146 /// "tokenLimit",147 /// "sponsorTransferTimeout",148 /// "sponsorApproveTimeout"149 /// @param value Value of the limit.150 /// @dev EVM selector for this function is: 0x6a3841db,151 /// or in textual repr: setCollectionLimit(string,uint32)152 function setCollectionLimit(string memory limit, uint32 value) external;153154 /// Set limits for the collection.155 /// @dev Throws error if limit not found.156 /// @param limit Name of the limit. Valid names:157 /// "ownerCanTransfer",158 /// "ownerCanDestroy",159 /// "transfersEnabled"160 /// @param value Value of the limit.161 /// @dev EVM selector for this function is: 0x993b7fba,162 /// or in textual repr: setCollectionLimit(string,bool)163 function setCollectionLimit(string memory limit, bool value) external;164165 /// Get contract address.166 /// @dev EVM selector for this function is: 0xf6b4dfb4,167 /// or in textual repr: contractAddress()168 function contractAddress() external view returns (address);169170 /// Add collection admin by substrate address.171 /// @param newAdmin Substrate administrator address.172 /// @dev EVM selector for this function is: 0x5730062b,173 /// or in textual repr: addCollectionAdminSubstrate(uint256)174 function addCollectionAdminSubstrate(uint256 newAdmin) external;175176 /// Remove collection admin by substrate address.177 /// @param admin Substrate administrator address.178 /// @dev EVM selector for this function is: 0x4048fcf9,179 /// or in textual repr: removeCollectionAdminSubstrate(uint256)180 function removeCollectionAdminSubstrate(uint256 admin) external;181182 /// Add collection admin.183 /// @param newAdmin Address of the added administrator.184 /// @dev EVM selector for this function is: 0x92e462c7,185 /// or in textual repr: addCollectionAdmin(address)186 function addCollectionAdmin(address newAdmin) external;187188 /// Remove collection admin.189 ///190 /// @param admin Address of the removed administrator.191 /// @dev EVM selector for this function is: 0xfafd7b42,192 /// or in textual repr: removeCollectionAdmin(address)193 function removeCollectionAdmin(address admin) external;194195 /// Toggle accessibility of collection nesting.196 ///197 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'198 /// @dev EVM selector for this function is: 0x112d4586,199 /// or in textual repr: setCollectionNesting(bool)200 function setCollectionNesting(bool enable) external;201202 /// Toggle accessibility of collection nesting.203 ///204 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'205 /// @param collections Addresses of collections that will be available for nesting.206 /// @dev EVM selector for this function is: 0x64872396,207 /// or in textual repr: setCollectionNesting(bool,address[])208 function setCollectionNesting(bool enable, address[] memory collections)209 external;210211 /// Set the collection access method.212 /// @param mode Access mode213 /// 0 for Normal214 /// 1 for AllowList215 /// @dev EVM selector for this function is: 0x41835d4c,216 /// or in textual repr: setCollectionAccess(uint8)217 function setCollectionAccess(uint8 mode) external;218219 /// Add the user to the allowed list.220 ///221 /// @param user Address of a trusted user.222 /// @dev EVM selector for this function is: 0x67844fe6,223 /// or in textual repr: addToCollectionAllowList(address)224 function addToCollectionAllowList(address user) external;225226 /// Remove the user from the allowed list.227 ///228 /// @param user Address of a removed user.229 /// @dev EVM selector for this function is: 0x85c51acb,230 /// or in textual repr: removeFromCollectionAllowList(address)231 function removeFromCollectionAllowList(address user) external;232233 /// Switch permission for minting.234 ///235 /// @param mode Enable if "true".236 /// @dev EVM selector for this function is: 0x00018e84,237 /// or in textual repr: setCollectionMintMode(bool)238 function setCollectionMintMode(bool mode) external;239240 /// Check that account is the owner or admin of the collection241 ///242 /// @param user account to verify243 /// @return "true" if account is the owner or admin244 /// @dev EVM selector for this function is: 0x9811b0c7,245 /// or in textual repr: isOwnerOrAdmin(address)246 function isOwnerOrAdmin(address user) external view returns (bool);247248 /// Check that substrate account is the owner or admin of the collection249 ///250 /// @param user account to verify251 /// @return "true" if account is the owner or admin252 /// @dev EVM selector for this function is: 0x68910e00,253 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)254 function isOwnerOrAdminSubstrate(uint256 user) external view returns (bool);255256 /// Returns collection type257 ///258 /// @return `Fungible` or `NFT` or `ReFungible`259 /// @dev EVM selector for this function is: 0xd34b55b8,260 /// or in textual repr: uniqueCollectionType()261 function uniqueCollectionType() external returns (string memory);262263 /// Changes collection owner to another account264 ///265 /// @dev Owner can be changed only by current owner266 /// @param newOwner new owner account267 /// @dev EVM selector for this function is: 0x13af4035,268 /// or in textual repr: setOwner(address)269 function setOwner(address newOwner) external;270271 /// Changes collection owner to another substrate account272 ///273 /// @dev Owner can be changed only by current owner274 /// @param newOwner new owner substrate account275 /// @dev EVM selector for this function is: 0xb212138f,276 /// or in textual repr: setOwnerSubstrate(uint256)277 function setOwnerSubstrate(uint256 newOwner) external;278}279280/// @dev anonymous struct281struct Tuple17 {282 address field_0;283 uint256 field_1;284}285286/// @title ERC721 Token that can be irreversibly burned (destroyed).287/// @dev the ERC-165 identifier for this interface is 0x42966c68288interface ERC721Burnable is Dummy, ERC165 {289 /// @notice Burns a specific ERC721 token.290 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized291 /// operator of the current owner.292 /// @param tokenId The NFT to approve293 /// @dev EVM selector for this function is: 0x42966c68,294 /// or in textual repr: burn(uint256)295 function burn(uint256 tokenId) external;296}297298/// @dev inlined interface299interface ERC721MintableEvents {300 event MintingFinished();301}302303/// @title ERC721 minting logic.304/// @dev the ERC-165 identifier for this interface is 0x68ccfe89305interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {306 /// @dev EVM selector for this function is: 0x05d2035b,307 /// or in textual repr: mintingFinished()308 function mintingFinished() external view returns (bool);309310 /// @notice Function to mint token.311 /// @dev `tokenId` should be obtained with `nextTokenId` method,312 /// unlike standard, you can't specify it manually313 /// @param to The new owner314 /// @param tokenId ID of the minted NFT315 /// @dev EVM selector for this function is: 0x40c10f19,316 /// or in textual repr: mint(address,uint256)317 function mint(address to, uint256 tokenId) external returns (bool);318319 /// @notice Function to mint token with the given tokenUri.320 /// @dev `tokenId` should be obtained with `nextTokenId` method,321 /// unlike standard, you can't specify it manually322 /// @param to The new owner323 /// @param tokenId ID of the minted NFT324 /// @param tokenUri Token URI that would be stored in the NFT properties325 /// @dev EVM selector for this function is: 0x50bb4e7f,326 /// or in textual repr: mintWithTokenURI(address,uint256,string)327 function mintWithTokenURI(328 address to,329 uint256 tokenId,330 string memory tokenUri331 ) external returns (bool);332333 /// @dev Not implemented334 /// @dev EVM selector for this function is: 0x7d64bcb4,335 /// or in textual repr: finishMinting()336 function finishMinting() external returns (bool);337}338339/// @title Unique extensions for ERC721.340/// @dev the ERC-165 identifier for this interface is 0xd74d154f341interface ERC721UniqueExtensions is Dummy, ERC165 {342 /// @notice Transfer ownership of an NFT343 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`344 /// is the zero address. Throws if `tokenId` is not a valid NFT.345 /// @param to The new owner346 /// @param tokenId The NFT to transfer347 /// @dev EVM selector for this function is: 0xa9059cbb,348 /// or in textual repr: transfer(address,uint256)349 function transfer(address to, uint256 tokenId) external;350351 /// @notice Burns a specific ERC721 token.352 /// @dev Throws unless `msg.sender` is the current owner or an authorized353 /// operator for this NFT. Throws if `from` is not the current owner. Throws354 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.355 /// @param from The current owner of the NFT356 /// @param tokenId The NFT to transfer357 /// @dev EVM selector for this function is: 0x79cc6790,358 /// or in textual repr: burnFrom(address,uint256)359 function burnFrom(address from, uint256 tokenId) external;360361 /// @notice Returns next free NFT ID.362 /// @dev EVM selector for this function is: 0x75794a3c,363 /// or in textual repr: nextTokenId()364 function nextTokenId() external view returns (uint256);365366 /// @notice Function to mint multiple tokens.367 /// @dev `tokenIds` should be an array of consecutive numbers and first number368 /// should be obtained with `nextTokenId` method369 /// @param to The new owner370 /// @param tokenIds IDs of the minted NFTs371 /// @dev EVM selector for this function is: 0x44a9945e,372 /// or in textual repr: mintBulk(address,uint256[])373 function mintBulk(address to, uint256[] memory tokenIds)374 external375 returns (bool);376377 /// @notice Function to mint multiple tokens with the given tokenUris.378 /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive379 /// numbers and first number should be obtained with `nextTokenId` method380 /// @param to The new owner381 /// @param tokens array of pairs of token ID and token URI for minted tokens382 /// @dev EVM selector for this function is: 0x36543006,383 /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])384 function mintBulkWithTokenURI(address to, Tuple8[] memory tokens)385 external386 returns (bool);387}388389/// @dev anonymous struct390struct Tuple8 {391 uint256 field_0;392 string field_1;393}394395/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension396/// @dev See https://eips.ethereum.org/EIPS/eip-721397/// @dev the ERC-165 identifier for this interface is 0x780e9d63398interface ERC721Enumerable is Dummy, ERC165 {399 /// @notice Enumerate valid NFTs400 /// @param index A counter less than `totalSupply()`401 /// @return The token identifier for the `index`th NFT,402 /// (sort order not specified)403 /// @dev EVM selector for this function is: 0x4f6ccce7,404 /// or in textual repr: tokenByIndex(uint256)405 function tokenByIndex(uint256 index) external view returns (uint256);406407 /// @dev Not implemented408 /// @dev EVM selector for this function is: 0x2f745c59,409 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)410 function tokenOfOwnerByIndex(address owner, uint256 index)411 external412 view413 returns (uint256);414415 /// @notice Count NFTs tracked by this contract416 /// @return A count of valid NFTs tracked by this contract, where each one of417 /// them has an assigned and queryable owner not equal to the zero address418 /// @dev EVM selector for this function is: 0x18160ddd,419 /// or in textual repr: totalSupply()420 function totalSupply() external view returns (uint256);421}422423/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension424/// @dev See https://eips.ethereum.org/EIPS/eip-721425/// @dev the ERC-165 identifier for this interface is 0x5b5e139f426interface ERC721Metadata is Dummy, ERC165 {427 /// @notice A descriptive name for a collection of NFTs in this contract428 /// @dev EVM selector for this function is: 0x06fdde03,429 /// or in textual repr: name()430 function name() external view returns (string memory);431432 /// @notice An abbreviated name for NFTs in this contract433 /// @dev EVM selector for this function is: 0x95d89b41,434 /// or in textual repr: symbol()435 function symbol() external view returns (string memory);436437 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.438 ///439 /// @dev If the token has a `url` property and it is not empty, it is returned.440 /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.441 /// If the collection property `baseURI` is empty or absent, return "" (empty string)442 /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix443 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).444 ///445 /// @return token's const_metadata446 /// @dev EVM selector for this function is: 0xc87b56dd,447 /// or in textual repr: tokenURI(uint256)448 function tokenURI(uint256 tokenId) external view returns (string memory);449}450451/// @dev inlined interface22interface ERC721Events {452interface ERC721Events {23 event Transfer(453 event Transfer(24 address indexed from,454 address indexed from,37 );467 );38}468}3946940// Inline470/// @title ERC-721 Non-Fungible Token Standard41interface ERC721MintableEvents {471/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md42 event MintingFinished();472/// @dev the ERC-165 identifier for this interface is 0x80ac58cd43}4445// Selector: 4136937746interface TokenProperties is Dummy, ERC165 {47 // @notice Set permissions for token property.48 // @dev Throws error if `msg.sender` is not admin or owner of the collection.49 // @param key Property key.50 // @param is_mutable Permission to mutate property.51 // @param collection_admin Permission to mutate property by collection admin if property is mutable.52 // @param token_owner Permission to mutate property by token owner if property is mutable.53 //54 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa55 function setTokenPropertyPermission(56 string memory key,57 bool isMutable,58 bool collectionAdmin,59 bool tokenOwner60 ) external;6162 // @notice Set token property value.63 // @dev Throws error if `msg.sender` has no permission to edit the property.64 // @param tokenId ID of the token.65 // @param key Property key.66 // @param value Property value.67 //68 // Selector: setProperty(uint256,string,bytes) 1752d67b69 function setProperty(70 uint256 tokenId,71 string memory key,72 bytes memory value73 ) external;7475 // @notice Delete token property value.76 // @dev Throws error if `msg.sender` has no permission to edit the property.77 // @param tokenId ID of the token.78 // @param key Property key.79 //80 // Selector: deleteProperty(uint256,string) 066111d181 function deleteProperty(uint256 tokenId, string memory key) external;8283 // @notice Get token property value.84 // @dev Throws error if key not found85 // @param tokenId ID of the token.86 // @param key Property key.87 // @return Property value bytes88 //89 // Selector: property(uint256,string) 7228c32790 function property(uint256 tokenId, string memory key)91 external92 view93 returns (bytes memory);94}9596// Selector: 42966c6897interface ERC721Burnable is Dummy, ERC165 {98 // @notice Burns a specific ERC721 token.99 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized100 // operator of the current owner.101 // @param tokenId The NFT to approve102 //103 // Selector: burn(uint256) 42966c68104 function burn(uint256 tokenId) external;105}106107// Selector: 58800161108interface ERC721 is Dummy, ERC165, ERC721Events {473interface ERC721 is Dummy, ERC165, ERC721Events {109 // @notice Count all NFTs assigned to an owner474 /// @notice Count all NFTs assigned to an owner110 // @dev NFTs assigned to the zero address are considered invalid, and this475 /// @dev NFTs assigned to the zero address are considered invalid, and this111 // function throws for queries about the zero address.476 /// function throws for queries about the zero address.112 // @param owner An address for whom to query the balance477 /// @param owner An address for whom to query the balance113 // @return The number of NFTs owned by `owner`, possibly zero478 /// @return The number of NFTs owned by `owner`, possibly zero114 //479 /// @dev EVM selector for this function is: 0x70a08231,115 // Selector: balanceOf(address) 70a08231480 /// or in textual repr: balanceOf(address)116 function balanceOf(address owner) external view returns (uint256);481 function balanceOf(address owner) external view returns (uint256);117482118 // @notice Find the owner of an NFT483 /// @notice Find the owner of an NFT119 // @dev NFTs assigned to zero address are considered invalid, and queries484 /// @dev NFTs assigned to zero address are considered invalid, and queries120 // about them do throw.485 /// about them do throw.121 // @param tokenId The identifier for an NFT486 /// @param tokenId The identifier for an NFT122 // @return The address of the owner of the NFT487 /// @return The address of the owner of the NFT123 //488 /// @dev EVM selector for this function is: 0x6352211e,124 // Selector: ownerOf(uint256) 6352211e489 /// or in textual repr: ownerOf(uint256)125 function ownerOf(uint256 tokenId) external view returns (address);490 function ownerOf(uint256 tokenId) external view returns (address);126491127 // @dev Not implemented492 /// @dev Not implemented128 //493 /// @dev EVM selector for this function is: 0xb88d4fde,129 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672494 /// or in textual repr: safeTransferFrom(address,address,uint256,bytes)130 function safeTransferFromWithData(495 function safeTransferFrom(131 address from,496 address from,132 address to,497 address to,133 uint256 tokenId,498 uint256 tokenId,134 bytes memory data499 bytes memory data135 ) external;500 ) external;136501137 // @dev Not implemented502 /// @dev Not implemented138 //503 /// @dev EVM selector for this function is: 0x42842e0e,139 // Selector: safeTransferFrom(address,address,uint256) 42842e0e504 /// or in textual repr: safeTransferFrom(address,address,uint256)140 function safeTransferFrom(505 function safeTransferFrom(141 address from,506 address from,142 address to,507 address to,143 uint256 tokenId508 uint256 tokenId144 ) external;509 ) external;145510146 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE511 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE147 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE512 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE148 // THEY MAY BE PERMANENTLY LOST513 /// THEY MAY BE PERMANENTLY LOST149 // @dev Throws unless `msg.sender` is the current owner or an authorized514 /// @dev Throws unless `msg.sender` is the current owner or an authorized150 // operator for this NFT. Throws if `from` is not the current owner. Throws515 /// operator for this NFT. Throws if `from` is not the current owner. Throws151 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.516 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.152 // @param from The current owner of the NFT517 /// @param from The current owner of the NFT153 // @param to The new owner518 /// @param to The new owner154 // @param tokenId The NFT to transfer519 /// @param tokenId The NFT to transfer155 // @param _value Not used for an NFT520 /// @dev EVM selector for this function is: 0x23b872dd,156 //157 // Selector: transferFrom(address,address,uint256) 23b872dd521 /// or in textual repr: transferFrom(address,address,uint256)158 function transferFrom(522 function transferFrom(159 address from,523 address from,160 address to,524 address to,161 uint256 tokenId525 uint256 tokenId162 ) external;526 ) external;163527164 // @notice Set or reaffirm the approved address for an NFT528 /// @notice Set or reaffirm the approved address for an NFT165 // @dev The zero address indicates there is no approved address.529 /// @dev The zero address indicates there is no approved address.166 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized530 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized167 // operator of the current owner.531 /// operator of the current owner.168 // @param approved The new approved NFT controller532 /// @param approved The new approved NFT controller169 // @param tokenId The NFT to approve533 /// @param tokenId The NFT to approve170 //534 /// @dev EVM selector for this function is: 0x095ea7b3,171 // Selector: approve(address,uint256) 095ea7b3535 /// or in textual repr: approve(address,uint256)172 function approve(address approved, uint256 tokenId) external;536 function approve(address approved, uint256 tokenId) external;173537174 // @dev Not implemented538 /// @dev Not implemented175 //539 /// @dev EVM selector for this function is: 0xa22cb465,176 // Selector: setApprovalForAll(address,bool) a22cb465540 /// or in textual repr: setApprovalForAll(address,bool)177 function setApprovalForAll(address operator, bool approved) external;541 function setApprovalForAll(address operator, bool approved) external;178542179 // @dev Not implemented543 /// @dev Not implemented180 //544 /// @dev EVM selector for this function is: 0x081812fc,181 // Selector: getApproved(uint256) 081812fc545 /// or in textual repr: getApproved(uint256)182 function getApproved(uint256 tokenId) external view returns (address);546 function getApproved(uint256 tokenId) external view returns (address);183547184 // @dev Not implemented548 /// @dev Not implemented185 //549 /// @dev EVM selector for this function is: 0xe985e9c5,186 // Selector: isApprovedForAll(address,address) e985e9c5550 /// or in textual repr: isApprovedForAll(address,address)187 function isApprovedForAll(address owner, address operator)551 function isApprovedForAll(address owner, address operator)188 external552 external189 view553 view190 returns (address);554 returns (address);191}555}192193// Selector: 5b5e139f194interface ERC721Metadata is Dummy, ERC165 {195 // @notice A descriptive name for a collection of NFTs in this contract196 //197 // Selector: name() 06fdde03198 function name() external view returns (string memory);199200 // @notice An abbreviated name for NFTs in this contract201 //202 // Selector: symbol() 95d89b41203 function symbol() external view returns (string memory);204205 // @notice A distinct Uniform Resource Identifier (URI) for a given asset.206 //207 // @dev If the token has a `url` property and it is not empty, it is returned.208 // Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.209 // If the collection property `baseURI` is empty or absent, return "" (empty string)210 // otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix211 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).212 //213 // @return token's const_metadata214 //215 // Selector: tokenURI(uint256) c87b56dd216 function tokenURI(uint256 tokenId) external view returns (string memory);217}218219// Selector: 68ccfe89220interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {221 // Selector: mintingFinished() 05d2035b222 function mintingFinished() external view returns (bool);223224 // @notice Function to mint token.225 // @dev `tokenId` should be obtained with `nextTokenId` method,226 // unlike standard, you can't specify it manually227 // @param to The new owner228 // @param tokenId ID of the minted NFT229 //230 // Selector: mint(address,uint256) 40c10f19231 function mint(address to, uint256 tokenId) external returns (bool);232233 // @notice Function to mint token with the given tokenUri.234 // @dev `tokenId` should be obtained with `nextTokenId` method,235 // unlike standard, you can't specify it manually236 // @param to The new owner237 // @param tokenId ID of the minted NFT238 // @param tokenUri Token URI that would be stored in the NFT properties239 //240 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f241 function mintWithTokenURI(242 address to,243 uint256 tokenId,244 string memory tokenUri245 ) external returns (bool);246247 // @dev Not implemented248 //249 // Selector: finishMinting() 7d64bcb4250 function finishMinting() external returns (bool);251}252253// Selector: 6cf113cd254interface Collection is Dummy, ERC165 {255 // Set collection property.256 //257 // @param key Property key.258 // @param value Propery value.259 //260 // Selector: setCollectionProperty(string,bytes) 2f073f66261 function setCollectionProperty(string memory key, bytes memory value)262 external;263264 // Delete collection property.265 //266 // @param key Property key.267 //268 // Selector: deleteCollectionProperty(string) 7b7debce269 function deleteCollectionProperty(string memory key) external;270271 // Get collection property.272 //273 // @dev Throws error if key not found.274 //275 // @param key Property key.276 // @return bytes The property corresponding to the key.277 //278 // Selector: collectionProperty(string) cf24fd6d279 function collectionProperty(string memory key)280 external281 view282 returns (bytes memory);283284 // Set the sponsor of the collection.285 //286 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.287 //288 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.289 //290 // Selector: setCollectionSponsor(address) 7623402e291 function setCollectionSponsor(address sponsor) external;292293 // Collection sponsorship confirmation.294 //295 // @dev After setting the sponsor for the collection, it must be confirmed with this function.296 //297 // Selector: confirmCollectionSponsorship() 3c50e97a298 function confirmCollectionSponsorship() external;299300 // Set limits for the collection.301 // @dev Throws error if limit not found.302 // @param limit Name of the limit. Valid names:303 // "accountTokenOwnershipLimit",304 // "sponsoredDataSize",305 // "sponsoredDataRateLimit",306 // "tokenLimit",307 // "sponsorTransferTimeout",308 // "sponsorApproveTimeout"309 // @param value Value of the limit.310 //311 // Selector: setCollectionLimit(string,uint32) 6a3841db312 function setCollectionLimit(string memory limit, uint32 value) external;313314 // Set limits for the collection.315 // @dev Throws error if limit not found.316 // @param limit Name of the limit. Valid names:317 // "ownerCanTransfer",318 // "ownerCanDestroy",319 // "transfersEnabled"320 // @param value Value of the limit.321 //322 // Selector: setCollectionLimit(string,bool) 993b7fba323 function setCollectionLimit(string memory limit, bool value) external;324325 // Get contract address.326 //327 // Selector: contractAddress() f6b4dfb4328 function contractAddress() external view returns (address);329330 // Add collection admin by substrate address.331 // @param new_admin Substrate administrator address.332 //333 // Selector: addCollectionAdminSubstrate(uint256) 5730062b334 function addCollectionAdminSubstrate(uint256 newAdmin) external;335336 // Remove collection admin by substrate address.337 // @param admin Substrate administrator address.338 //339 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9340 function removeCollectionAdminSubstrate(uint256 admin) external;341342 // Add collection admin.343 // @param new_admin Address of the added administrator.344 //345 // Selector: addCollectionAdmin(address) 92e462c7346 function addCollectionAdmin(address newAdmin) external;347348 // Remove collection admin.349 //350 // @param new_admin Address of the removed administrator.351 //352 // Selector: removeCollectionAdmin(address) fafd7b42353 function removeCollectionAdmin(address admin) external;354355 // Toggle accessibility of collection nesting.356 //357 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'358 //359 // Selector: setCollectionNesting(bool) 112d4586360 function setCollectionNesting(bool enable) external;361362 // Toggle accessibility of collection nesting.363 //364 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'365 // @param collections Addresses of collections that will be available for nesting.366 //367 // Selector: setCollectionNesting(bool,address[]) 64872396368 function setCollectionNesting(bool enable, address[] memory collections)369 external;370371 // Set the collection access method.372 // @param mode Access mode373 // 0 for Normal374 // 1 for AllowList375 //376 // Selector: setCollectionAccess(uint8) 41835d4c377 function setCollectionAccess(uint8 mode) external;378379 // Add the user to the allowed list.380 //381 // @param user Address of a trusted user.382 //383 // Selector: addToCollectionAllowList(address) 67844fe6384 function addToCollectionAllowList(address user) external;385386 // Remove the user from the allowed list.387 //388 // @param user Address of a removed user.389 //390 // Selector: removeFromCollectionAllowList(address) 85c51acb391 function removeFromCollectionAllowList(address user) external;392393 // Switch permission for minting.394 //395 // @param mode Enable if "true".396 //397 // Selector: setCollectionMintMode(bool) 00018e84398 function setCollectionMintMode(bool mode) external;399400 // Check that account is the owner or admin of the collection401 //402 // @param user account to verify403 // @return "true" if account is the owner or admin404 //405 // Selector: verifyOwnerOrAdmin(address) c2282493406 function verifyOwnerOrAdmin(address user) external view returns (bool);407408 // Returns collection type409 //410 // @return `Fungible` or `NFT` or `ReFungible`411 //412 // Selector: uniqueCollectionType() d34b55b8413 function uniqueCollectionType() external returns (string memory);414}415416// Selector: 780e9d63417interface ERC721Enumerable is Dummy, ERC165 {418 // @notice Enumerate valid NFTs419 // @param index A counter less than `totalSupply()`420 // @return The token identifier for the `index`th NFT,421 // (sort order not specified)422 //423 // Selector: tokenByIndex(uint256) 4f6ccce7424 function tokenByIndex(uint256 index) external view returns (uint256);425426 // @dev Not implemented427 //428 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59429 function tokenOfOwnerByIndex(address owner, uint256 index)430 external431 view432 returns (uint256);433434 // @notice Count NFTs tracked by this contract435 // @return A count of valid NFTs tracked by this contract, where each one of436 // them has an assigned and queryable owner not equal to the zero address437 //438 // Selector: totalSupply() 18160ddd439 function totalSupply() external view returns (uint256);440}441442// Selector: d74d154f443interface ERC721UniqueExtensions is Dummy, ERC165 {444 // @notice Transfer ownership of an NFT445 // @dev Throws unless `msg.sender` is the current owner. Throws if `to`446 // is the zero address. Throws if `tokenId` is not a valid NFT.447 // @param to The new owner448 // @param tokenId The NFT to transfer449 // @param _value Not used for an NFT450 //451 // Selector: transfer(address,uint256) a9059cbb452 function transfer(address to, uint256 tokenId) external;453454 // @notice Burns a specific ERC721 token.455 // @dev Throws unless `msg.sender` is the current owner or an authorized456 // operator for this NFT. Throws if `from` is not the current owner. Throws457 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.458 // @param from The current owner of the NFT459 // @param tokenId The NFT to transfer460 // @param _value Not used for an NFT461 //462 // Selector: burnFrom(address,uint256) 79cc6790463 function burnFrom(address from, uint256 tokenId) external;464465 // @notice Returns next free NFT ID.466 //467 // Selector: nextTokenId() 75794a3c468 function nextTokenId() external view returns (uint256);469470 // @notice Function to mint multiple tokens.471 // @dev `tokenIds` should be an array of consecutive numbers and first number472 // should be obtained with `nextTokenId` method473 // @param to The new owner474 // @param tokenIds IDs of the minted NFTs475 //476 // Selector: mintBulk(address,uint256[]) 44a9945e477 function mintBulk(address to, uint256[] memory tokenIds)478 external479 returns (bool);480481 // @notice Function to mint multiple tokens with the given tokenUris.482 // @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive483 // numbers and first number should be obtained with `nextTokenId` method484 // @param to The new owner485 // @param tokens array of pairs of token ID and token URI for minted tokens486 //487 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006488 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)489 external490 returns (bool);491}492556493interface UniqueNFT is557interface UniqueNFT is494 Dummy,558 Dummy,tests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 uint256 field_0;9 string field_1;10}11512// Common stubs holder6/// @dev common stubs holder13interface Dummy {7interface Dummy {14815}9}18 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);19}13}201421// Inline15/// @title A contract that allows to set and delete token properties and change token property permissions.16/// @dev the ERC-165 identifier for this interface is 0x4136937717interface TokenProperties is Dummy, ERC165 {18 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 /// @param key Property key.21 /// @param isMutable Permission to mutate property.22 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 /// @dev EVM selector for this function is: 0x222d97fa,25 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)26 function setTokenPropertyPermission(27 string memory key,28 bool isMutable,29 bool collectionAdmin,30 bool tokenOwner31 ) external;3233 /// @notice Set token property value.34 /// @dev Throws error if `msg.sender` has no permission to edit the property.35 /// @param tokenId ID of the token.36 /// @param key Property key.37 /// @param value Property value.38 /// @dev EVM selector for this function is: 0x1752d67b,39 /// or in textual repr: setProperty(uint256,string,bytes)40 function setProperty(41 uint256 tokenId,42 string memory key,43 bytes memory value44 ) external;4546 /// @notice Delete token property value.47 /// @dev Throws error if `msg.sender` has no permission to edit the property.48 /// @param tokenId ID of the token.49 /// @param key Property key.50 /// @dev EVM selector for this function is: 0x066111d1,51 /// or in textual repr: deleteProperty(uint256,string)52 function deleteProperty(uint256 tokenId, string memory key) external;5354 /// @notice Get token property value.55 /// @dev Throws error if key not found56 /// @param tokenId ID of the token.57 /// @param key Property key.58 /// @return Property value bytes59 /// @dev EVM selector for this function is: 0x7228c327,60 /// or in textual repr: property(uint256,string)61 function property(uint256 tokenId, string memory key)62 external63 view64 returns (bytes memory);65}6667/// @title A contract that allows you to work with collections.68/// @dev the ERC-165 identifier for this interface is 0xe54be64069interface Collection is Dummy, ERC165 {70 /// Set collection property.71 ///72 /// @param key Property key.73 /// @param value Propery value.74 /// @dev EVM selector for this function is: 0x2f073f66,75 /// or in textual repr: setCollectionProperty(string,bytes)76 function setCollectionProperty(string memory key, bytes memory value)77 external;7879 /// Delete collection property.80 ///81 /// @param key Property key.82 /// @dev EVM selector for this function is: 0x7b7debce,83 /// or in textual repr: deleteCollectionProperty(string)84 function deleteCollectionProperty(string memory key) external;8586 /// Get collection property.87 ///88 /// @dev Throws error if key not found.89 ///90 /// @param key Property key.91 /// @return bytes The property corresponding to the key.92 /// @dev EVM selector for this function is: 0xcf24fd6d,93 /// or in textual repr: collectionProperty(string)94 function collectionProperty(string memory key)95 external96 view97 returns (bytes memory);9899 /// Set the sponsor of the collection.100 ///101 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.102 ///103 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.104 /// @dev EVM selector for this function is: 0x7623402e,105 /// or in textual repr: setCollectionSponsor(address)106 function setCollectionSponsor(address sponsor) external;107108 /// Set the substrate sponsor of the collection.109 ///110 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.111 ///112 /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.113 /// @dev EVM selector for this function is: 0xc74d6751,114 /// or in textual repr: setCollectionSponsorSubstrate(uint256)115 function setCollectionSponsorSubstrate(uint256 sponsor) external;116117 /// @dev EVM selector for this function is: 0x058ac185,118 /// or in textual repr: hasCollectionPendingSponsor()119 function hasCollectionPendingSponsor() external view returns (bool);120121 /// Collection sponsorship confirmation.122 ///123 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.124 /// @dev EVM selector for this function is: 0x3c50e97a,125 /// or in textual repr: confirmCollectionSponsorship()126 function confirmCollectionSponsorship() external;127128 /// Remove collection sponsor.129 /// @dev EVM selector for this function is: 0x6e0326a3,130 /// or in textual repr: removeCollectionSponsor()131 function removeCollectionSponsor() external;132133 /// Get current sponsor.134 ///135 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.136 /// @dev EVM selector for this function is: 0xb66bbc14,137 /// or in textual repr: getCollectionSponsor()138 function getCollectionSponsor() external view returns (Tuple17 memory);139140 /// Set limits for the collection.141 /// @dev Throws error if limit not found.142 /// @param limit Name of the limit. Valid names:143 /// "accountTokenOwnershipLimit",144 /// "sponsoredDataSize",145 /// "sponsoredDataRateLimit",146 /// "tokenLimit",147 /// "sponsorTransferTimeout",148 /// "sponsorApproveTimeout"149 /// @param value Value of the limit.150 /// @dev EVM selector for this function is: 0x6a3841db,151 /// or in textual repr: setCollectionLimit(string,uint32)152 function setCollectionLimit(string memory limit, uint32 value) external;153154 /// Set limits for the collection.155 /// @dev Throws error if limit not found.156 /// @param limit Name of the limit. Valid names:157 /// "ownerCanTransfer",158 /// "ownerCanDestroy",159 /// "transfersEnabled"160 /// @param value Value of the limit.161 /// @dev EVM selector for this function is: 0x993b7fba,162 /// or in textual repr: setCollectionLimit(string,bool)163 function setCollectionLimit(string memory limit, bool value) external;164165 /// Get contract address.166 /// @dev EVM selector for this function is: 0xf6b4dfb4,167 /// or in textual repr: contractAddress()168 function contractAddress() external view returns (address);169170 /// Add collection admin by substrate address.171 /// @param newAdmin Substrate administrator address.172 /// @dev EVM selector for this function is: 0x5730062b,173 /// or in textual repr: addCollectionAdminSubstrate(uint256)174 function addCollectionAdminSubstrate(uint256 newAdmin) external;175176 /// Remove collection admin by substrate address.177 /// @param admin Substrate administrator address.178 /// @dev EVM selector for this function is: 0x4048fcf9,179 /// or in textual repr: removeCollectionAdminSubstrate(uint256)180 function removeCollectionAdminSubstrate(uint256 admin) external;181182 /// Add collection admin.183 /// @param newAdmin Address of the added administrator.184 /// @dev EVM selector for this function is: 0x92e462c7,185 /// or in textual repr: addCollectionAdmin(address)186 function addCollectionAdmin(address newAdmin) external;187188 /// Remove collection admin.189 ///190 /// @param admin Address of the removed administrator.191 /// @dev EVM selector for this function is: 0xfafd7b42,192 /// or in textual repr: removeCollectionAdmin(address)193 function removeCollectionAdmin(address admin) external;194195 /// Toggle accessibility of collection nesting.196 ///197 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'198 /// @dev EVM selector for this function is: 0x112d4586,199 /// or in textual repr: setCollectionNesting(bool)200 function setCollectionNesting(bool enable) external;201202 /// Toggle accessibility of collection nesting.203 ///204 /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'205 /// @param collections Addresses of collections that will be available for nesting.206 /// @dev EVM selector for this function is: 0x64872396,207 /// or in textual repr: setCollectionNesting(bool,address[])208 function setCollectionNesting(bool enable, address[] memory collections)209 external;210211 /// Set the collection access method.212 /// @param mode Access mode213 /// 0 for Normal214 /// 1 for AllowList215 /// @dev EVM selector for this function is: 0x41835d4c,216 /// or in textual repr: setCollectionAccess(uint8)217 function setCollectionAccess(uint8 mode) external;218219 /// Add the user to the allowed list.220 ///221 /// @param user Address of a trusted user.222 /// @dev EVM selector for this function is: 0x67844fe6,223 /// or in textual repr: addToCollectionAllowList(address)224 function addToCollectionAllowList(address user) external;225226 /// Remove the user from the allowed list.227 ///228 /// @param user Address of a removed user.229 /// @dev EVM selector for this function is: 0x85c51acb,230 /// or in textual repr: removeFromCollectionAllowList(address)231 function removeFromCollectionAllowList(address user) external;232233 /// Switch permission for minting.234 ///235 /// @param mode Enable if "true".236 /// @dev EVM selector for this function is: 0x00018e84,237 /// or in textual repr: setCollectionMintMode(bool)238 function setCollectionMintMode(bool mode) external;239240 /// Check that account is the owner or admin of the collection241 ///242 /// @param user account to verify243 /// @return "true" if account is the owner or admin244 /// @dev EVM selector for this function is: 0x9811b0c7,245 /// or in textual repr: isOwnerOrAdmin(address)246 function isOwnerOrAdmin(address user) external view returns (bool);247248 /// Check that substrate account is the owner or admin of the collection249 ///250 /// @param user account to verify251 /// @return "true" if account is the owner or admin252 /// @dev EVM selector for this function is: 0x68910e00,253 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)254 function isOwnerOrAdminSubstrate(uint256 user) external view returns (bool);255256 /// Returns collection type257 ///258 /// @return `Fungible` or `NFT` or `ReFungible`259 /// @dev EVM selector for this function is: 0xd34b55b8,260 /// or in textual repr: uniqueCollectionType()261 function uniqueCollectionType() external returns (string memory);262263 /// Changes collection owner to another account264 ///265 /// @dev Owner can be changed only by current owner266 /// @param newOwner new owner account267 /// @dev EVM selector for this function is: 0x13af4035,268 /// or in textual repr: setOwner(address)269 function setOwner(address newOwner) external;270271 /// Changes collection owner to another substrate account272 ///273 /// @dev Owner can be changed only by current owner274 /// @param newOwner new owner substrate account275 /// @dev EVM selector for this function is: 0xb212138f,276 /// or in textual repr: setOwnerSubstrate(uint256)277 function setOwnerSubstrate(uint256 newOwner) external;278}279280/// @dev anonymous struct281struct Tuple17 {282 address field_0;283 uint256 field_1;284}285286/// @title ERC721 Token that can be irreversibly burned (destroyed).287/// @dev the ERC-165 identifier for this interface is 0x42966c68288interface ERC721Burnable is Dummy, ERC165 {289 /// @notice Burns a specific ERC721 token.290 /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized291 /// operator of the current owner.292 /// @param tokenId The RFT to approve293 /// @dev EVM selector for this function is: 0x42966c68,294 /// or in textual repr: burn(uint256)295 function burn(uint256 tokenId) external;296}297298/// @dev inlined interface299interface ERC721MintableEvents {300 event MintingFinished();301}302303/// @title ERC721 minting logic.304/// @dev the ERC-165 identifier for this interface is 0x68ccfe89305interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {306 /// @dev EVM selector for this function is: 0x05d2035b,307 /// or in textual repr: mintingFinished()308 function mintingFinished() external view returns (bool);309310 /// @notice Function to mint token.311 /// @dev `tokenId` should be obtained with `nextTokenId` method,312 /// unlike standard, you can't specify it manually313 /// @param to The new owner314 /// @param tokenId ID of the minted RFT315 /// @dev EVM selector for this function is: 0x40c10f19,316 /// or in textual repr: mint(address,uint256)317 function mint(address to, uint256 tokenId) external returns (bool);318319 /// @notice Function to mint token with the given tokenUri.320 /// @dev `tokenId` should be obtained with `nextTokenId` method,321 /// unlike standard, you can't specify it manually322 /// @param to The new owner323 /// @param tokenId ID of the minted RFT324 /// @param tokenUri Token URI that would be stored in the RFT properties325 /// @dev EVM selector for this function is: 0x50bb4e7f,326 /// or in textual repr: mintWithTokenURI(address,uint256,string)327 function mintWithTokenURI(328 address to,329 uint256 tokenId,330 string memory tokenUri331 ) external returns (bool);332333 /// @dev Not implemented334 /// @dev EVM selector for this function is: 0x7d64bcb4,335 /// or in textual repr: finishMinting()336 function finishMinting() external returns (bool);337}338339/// @title Unique extensions for ERC721.340/// @dev the ERC-165 identifier for this interface is 0x7c3bef89341interface ERC721UniqueExtensions is Dummy, ERC165 {342 /// @notice Transfer ownership of an RFT343 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`344 /// is the zero address. Throws if `tokenId` is not a valid RFT.345 /// Throws if RFT pieces have multiple owners.346 /// @param to The new owner347 /// @param tokenId The RFT to transfer348 /// @dev EVM selector for this function is: 0xa9059cbb,349 /// or in textual repr: transfer(address,uint256)350 function transfer(address to, uint256 tokenId) external;351352 /// @notice Burns a specific ERC721 token.353 /// @dev Throws unless `msg.sender` is the current owner or an authorized354 /// operator for this RFT. Throws if `from` is not the current owner. Throws355 /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.356 /// Throws if RFT pieces have multiple owners.357 /// @param from The current owner of the RFT358 /// @param tokenId The RFT to transfer359 /// @dev EVM selector for this function is: 0x79cc6790,360 /// or in textual repr: burnFrom(address,uint256)361 function burnFrom(address from, uint256 tokenId) external;362363 /// @notice Returns next free RFT ID.364 /// @dev EVM selector for this function is: 0x75794a3c,365 /// or in textual repr: nextTokenId()366 function nextTokenId() external view returns (uint256);367368 /// @notice Function to mint multiple tokens.369 /// @dev `tokenIds` should be an array of consecutive numbers and first number370 /// should be obtained with `nextTokenId` method371 /// @param to The new owner372 /// @param tokenIds IDs of the minted RFTs373 /// @dev EVM selector for this function is: 0x44a9945e,374 /// or in textual repr: mintBulk(address,uint256[])375 function mintBulk(address to, uint256[] memory tokenIds)376 external377 returns (bool);378379 /// @notice Function to mint multiple tokens with the given tokenUris.380 /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive381 /// numbers and first number should be obtained with `nextTokenId` method382 /// @param to The new owner383 /// @param tokens array of pairs of token ID and token URI for minted tokens384 /// @dev EVM selector for this function is: 0x36543006,385 /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])386 function mintBulkWithTokenURI(address to, Tuple8[] memory tokens)387 external388 returns (bool);389390 /// Returns EVM address for refungible token391 ///392 /// @param token ID of the token393 /// @dev EVM selector for this function is: 0xab76fac6,394 /// or in textual repr: tokenContractAddress(uint256)395 function tokenContractAddress(uint256 token)396 external397 view398 returns (address);399}400401/// @dev anonymous struct402struct Tuple8 {403 uint256 field_0;404 string field_1;405}406407/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension408/// @dev See https://eips.ethereum.org/EIPS/eip-721409/// @dev the ERC-165 identifier for this interface is 0x780e9d63410interface ERC721Enumerable is Dummy, ERC165 {411 /// @notice Enumerate valid RFTs412 /// @param index A counter less than `totalSupply()`413 /// @return The token identifier for the `index`th NFT,414 /// (sort order not specified)415 /// @dev EVM selector for this function is: 0x4f6ccce7,416 /// or in textual repr: tokenByIndex(uint256)417 function tokenByIndex(uint256 index) external view returns (uint256);418419 /// Not implemented420 /// @dev EVM selector for this function is: 0x2f745c59,421 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)422 function tokenOfOwnerByIndex(address owner, uint256 index)423 external424 view425 returns (uint256);426427 /// @notice Count RFTs tracked by this contract428 /// @return A count of valid RFTs tracked by this contract, where each one of429 /// them has an assigned and queryable owner not equal to the zero address430 /// @dev EVM selector for this function is: 0x18160ddd,431 /// or in textual repr: totalSupply()432 function totalSupply() external view returns (uint256);433}434435/// @dev the ERC-165 identifier for this interface is 0x5b5e139f436interface ERC721Metadata is Dummy, ERC165 {437 /// @notice A descriptive name for a collection of RFTs in this contract438 /// @dev EVM selector for this function is: 0x06fdde03,439 /// or in textual repr: name()440 function name() external view returns (string memory);441442 /// @notice An abbreviated name for RFTs in this contract443 /// @dev EVM selector for this function is: 0x95d89b41,444 /// or in textual repr: symbol()445 function symbol() external view returns (string memory);446447 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.448 ///449 /// @dev If the token has a `url` property and it is not empty, it is returned.450 /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.451 /// If the collection property `baseURI` is empty or absent, return "" (empty string)452 /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix453 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).454 ///455 /// @return token's const_metadata456 /// @dev EVM selector for this function is: 0xc87b56dd,457 /// or in textual repr: tokenURI(uint256)458 function tokenURI(uint256 tokenId) external view returns (string memory);459}460461/// @dev inlined interface22interface ERC721Events {462interface ERC721Events {23 event Transfer(463 event Transfer(24 address indexed from,464 address indexed from,37 );477 );38}478}3947940// Inline480/// @title ERC-721 Non-Fungible Token Standard41interface ERC721MintableEvents {481/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md42 event MintingFinished();482/// @dev the ERC-165 identifier for this interface is 0x5880016143}4445// Selector: 4136937746interface TokenProperties is Dummy, ERC165 {47 // @notice Set permissions for token property.48 // @dev Throws error if `msg.sender` is not admin or owner of the collection.49 // @param key Property key.50 // @param is_mutable Permission to mutate property.51 // @param collection_admin Permission to mutate property by collection admin if property is mutable.52 // @param token_owner Permission to mutate property by token owner if property is mutable.53 //54 // Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa55 function setTokenPropertyPermission(56 string memory key,57 bool isMutable,58 bool collectionAdmin,59 bool tokenOwner60 ) external;6162 // @notice Set token property value.63 // @dev Throws error if `msg.sender` has no permission to edit the property.64 // @param tokenId ID of the token.65 // @param key Property key.66 // @param value Property value.67 //68 // Selector: setProperty(uint256,string,bytes) 1752d67b69 function setProperty(70 uint256 tokenId,71 string memory key,72 bytes memory value73 ) external;7475 // @notice Delete token property value.76 // @dev Throws error if `msg.sender` has no permission to edit the property.77 // @param tokenId ID of the token.78 // @param key Property key.79 //80 // Selector: deleteProperty(uint256,string) 066111d181 function deleteProperty(uint256 tokenId, string memory key) external;8283 // @notice Get token property value.84 // @dev Throws error if key not found85 // @param tokenId ID of the token.86 // @param key Property key.87 // @return Property value bytes88 //89 // Selector: property(uint256,string) 7228c32790 function property(uint256 tokenId, string memory key)91 external92 view93 returns (bytes memory);94}9596// Selector: 42966c6897interface ERC721Burnable is Dummy, ERC165 {98 // @notice Burns a specific ERC721 token.99 // @dev Throws unless `msg.sender` is the current RFT owner, or an authorized100 // operator of the current owner.101 // @param tokenId The RFT to approve102 //103 // Selector: burn(uint256) 42966c68104 function burn(uint256 tokenId) external;105}106107// Selector: 58800161108interface ERC721 is Dummy, ERC165, ERC721Events {483interface ERC721 is Dummy, ERC165, ERC721Events {109 // @notice Count all RFTs assigned to an owner484 /// @notice Count all RFTs assigned to an owner110 // @dev RFTs assigned to the zero address are considered invalid, and this485 /// @dev RFTs assigned to the zero address are considered invalid, and this111 // function throws for queries about the zero address.486 /// function throws for queries about the zero address.112 // @param owner An address for whom to query the balance487 /// @param owner An address for whom to query the balance113 // @return The number of RFTs owned by `owner`, possibly zero488 /// @return The number of RFTs owned by `owner`, possibly zero114 //489 /// @dev EVM selector for this function is: 0x70a08231,115 // Selector: balanceOf(address) 70a08231490 /// or in textual repr: balanceOf(address)116 function balanceOf(address owner) external view returns (uint256);491 function balanceOf(address owner) external view returns (uint256);117492118 // @notice Find the owner of an RFT493 /// @notice Find the owner of an RFT119 // @dev RFTs assigned to zero address are considered invalid, and queries494 /// @dev RFTs assigned to zero address are considered invalid, and queries120 // about them do throw.495 /// about them do throw.121 // Returns special 0xffffffffffffffffffffffffffffffffffffffff address for496 /// Returns special 0xffffffffffffffffffffffffffffffffffffffff address for122 // the tokens that are partially owned.497 /// the tokens that are partially owned.123 // @param tokenId The identifier for an RFT498 /// @param tokenId The identifier for an RFT124 // @return The address of the owner of the RFT499 /// @return The address of the owner of the RFT125 //500 /// @dev EVM selector for this function is: 0x6352211e,126 // Selector: ownerOf(uint256) 6352211e501 /// or in textual repr: ownerOf(uint256)127 function ownerOf(uint256 tokenId) external view returns (address);502 function ownerOf(uint256 tokenId) external view returns (address);128503129 // @dev Not implemented504 /// @dev Not implemented130 //505 /// @dev EVM selector for this function is: 0x60a11672,131 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672506 /// or in textual repr: safeTransferFromWithData(address,address,uint256,bytes)132 function safeTransferFromWithData(507 function safeTransferFromWithData(133 address from,508 address from,134 address to,509 address to,135 uint256 tokenId,510 uint256 tokenId,136 bytes memory data511 bytes memory data137 ) external;512 ) external;138513139 // @dev Not implemented514 /// @dev Not implemented140 //515 /// @dev EVM selector for this function is: 0x42842e0e,141 // Selector: safeTransferFrom(address,address,uint256) 42842e0e516 /// or in textual repr: safeTransferFrom(address,address,uint256)142 function safeTransferFrom(517 function safeTransferFrom(143 address from,518 address from,144 address to,519 address to,145 uint256 tokenId520 uint256 tokenId146 ) external;521 ) external;147522148 // @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE523 /// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE149 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE524 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE150 // THEY MAY BE PERMANENTLY LOST525 /// THEY MAY BE PERMANENTLY LOST151 // @dev Throws unless `msg.sender` is the current owner or an authorized526 /// @dev Throws unless `msg.sender` is the current owner or an authorized152 // operator for this RFT. Throws if `from` is not the current owner. Throws527 /// operator for this RFT. Throws if `from` is not the current owner. Throws153 // if `to` is the zero address. Throws if `tokenId` is not a valid RFT.528 /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.154 // Throws if RFT pieces have multiple owners.529 /// Throws if RFT pieces have multiple owners.155 // @param from The current owner of the NFT530 /// @param from The current owner of the NFT156 // @param to The new owner531 /// @param to The new owner157 // @param tokenId The NFT to transfer532 /// @param tokenId The NFT to transfer158 // @param _value Not used for an NFT533 /// @dev EVM selector for this function is: 0x23b872dd,159 //160 // Selector: transferFrom(address,address,uint256) 23b872dd534 /// or in textual repr: transferFrom(address,address,uint256)161 function transferFrom(535 function transferFrom(162 address from,536 address from,163 address to,537 address to,164 uint256 tokenId538 uint256 tokenId165 ) external;539 ) external;166540167 // @dev Not implemented541 /// @dev Not implemented168 //542 /// @dev EVM selector for this function is: 0x095ea7b3,169 // Selector: approve(address,uint256) 095ea7b3543 /// or in textual repr: approve(address,uint256)170 function approve(address approved, uint256 tokenId) external;544 function approve(address approved, uint256 tokenId) external;171545172 // @dev Not implemented546 /// @dev Not implemented173 //547 /// @dev EVM selector for this function is: 0xa22cb465,174 // Selector: setApprovalForAll(address,bool) a22cb465548 /// or in textual repr: setApprovalForAll(address,bool)175 function setApprovalForAll(address operator, bool approved) external;549 function setApprovalForAll(address operator, bool approved) external;176550177 // @dev Not implemented551 /// @dev Not implemented178 //552 /// @dev EVM selector for this function is: 0x081812fc,179 // Selector: getApproved(uint256) 081812fc553 /// or in textual repr: getApproved(uint256)180 function getApproved(uint256 tokenId) external view returns (address);554 function getApproved(uint256 tokenId) external view returns (address);181555182 // @dev Not implemented556 /// @dev Not implemented183 //557 /// @dev EVM selector for this function is: 0xe985e9c5,184 // Selector: isApprovedForAll(address,address) e985e9c5558 /// or in textual repr: isApprovedForAll(address,address)185 function isApprovedForAll(address owner, address operator)559 function isApprovedForAll(address owner, address operator)186 external560 external187 view561 view188 returns (address);562 returns (address);189}563}190191// Selector: 5b5e139f192interface ERC721Metadata is Dummy, ERC165 {193 // @notice A descriptive name for a collection of RFTs in this contract194 //195 // Selector: name() 06fdde03196 function name() external view returns (string memory);197198 // @notice An abbreviated name for RFTs in this contract199 //200 // Selector: symbol() 95d89b41201 function symbol() external view returns (string memory);202203 // @notice A distinct Uniform Resource Identifier (URI) for a given asset.204 //205 // @dev If the token has a `url` property and it is not empty, it is returned.206 // Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.207 // If the collection property `baseURI` is empty or absent, return "" (empty string)208 // otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix209 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).210 //211 // @return token's const_metadata212 //213 // Selector: tokenURI(uint256) c87b56dd214 function tokenURI(uint256 tokenId) external view returns (string memory);215}216217// Selector: 68ccfe89218interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {219 // Selector: mintingFinished() 05d2035b220 function mintingFinished() external view returns (bool);221222 // @notice Function to mint token.223 // @dev `tokenId` should be obtained with `nextTokenId` method,224 // unlike standard, you can't specify it manually225 // @param to The new owner226 // @param tokenId ID of the minted RFT227 //228 // Selector: mint(address,uint256) 40c10f19229 function mint(address to, uint256 tokenId) external returns (bool);230231 // @notice Function to mint token with the given tokenUri.232 // @dev `tokenId` should be obtained with `nextTokenId` method,233 // unlike standard, you can't specify it manually234 // @param to The new owner235 // @param tokenId ID of the minted RFT236 // @param tokenUri Token URI that would be stored in the RFT properties237 //238 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f239 function mintWithTokenURI(240 address to,241 uint256 tokenId,242 string memory tokenUri243 ) external returns (bool);244245 // @dev Not implemented246 //247 // Selector: finishMinting() 7d64bcb4248 function finishMinting() external returns (bool);249}250251// Selector: 6cf113cd252interface Collection is Dummy, ERC165 {253 // Set collection property.254 //255 // @param key Property key.256 // @param value Propery value.257 //258 // Selector: setCollectionProperty(string,bytes) 2f073f66259 function setCollectionProperty(string memory key, bytes memory value)260 external;261262 // Delete collection property.263 //264 // @param key Property key.265 //266 // Selector: deleteCollectionProperty(string) 7b7debce267 function deleteCollectionProperty(string memory key) external;268269 // Get collection property.270 //271 // @dev Throws error if key not found.272 //273 // @param key Property key.274 // @return bytes The property corresponding to the key.275 //276 // Selector: collectionProperty(string) cf24fd6d277 function collectionProperty(string memory key)278 external279 view280 returns (bytes memory);281282 // Set the sponsor of the collection.283 //284 // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.285 //286 // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.287 //288 // Selector: setCollectionSponsor(address) 7623402e289 function setCollectionSponsor(address sponsor) external;290291 // Collection sponsorship confirmation.292 //293 // @dev After setting the sponsor for the collection, it must be confirmed with this function.294 //295 // Selector: confirmCollectionSponsorship() 3c50e97a296 function confirmCollectionSponsorship() external;297298 // Set limits for the collection.299 // @dev Throws error if limit not found.300 // @param limit Name of the limit. Valid names:301 // "accountTokenOwnershipLimit",302 // "sponsoredDataSize",303 // "sponsoredDataRateLimit",304 // "tokenLimit",305 // "sponsorTransferTimeout",306 // "sponsorApproveTimeout"307 // @param value Value of the limit.308 //309 // Selector: setCollectionLimit(string,uint32) 6a3841db310 function setCollectionLimit(string memory limit, uint32 value) external;311312 // Set limits for the collection.313 // @dev Throws error if limit not found.314 // @param limit Name of the limit. Valid names:315 // "ownerCanTransfer",316 // "ownerCanDestroy",317 // "transfersEnabled"318 // @param value Value of the limit.319 //320 // Selector: setCollectionLimit(string,bool) 993b7fba321 function setCollectionLimit(string memory limit, bool value) external;322323 // Get contract address.324 //325 // Selector: contractAddress() f6b4dfb4326 function contractAddress() external view returns (address);327328 // Add collection admin by substrate address.329 // @param new_admin Substrate administrator address.330 //331 // Selector: addCollectionAdminSubstrate(uint256) 5730062b332 function addCollectionAdminSubstrate(uint256 newAdmin) external;333334 // Remove collection admin by substrate address.335 // @param admin Substrate administrator address.336 //337 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9338 function removeCollectionAdminSubstrate(uint256 admin) external;339340 // Add collection admin.341 // @param new_admin Address of the added administrator.342 //343 // Selector: addCollectionAdmin(address) 92e462c7344 function addCollectionAdmin(address newAdmin) external;345346 // Remove collection admin.347 //348 // @param new_admin Address of the removed administrator.349 //350 // Selector: removeCollectionAdmin(address) fafd7b42351 function removeCollectionAdmin(address admin) external;352353 // Toggle accessibility of collection nesting.354 //355 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'356 //357 // Selector: setCollectionNesting(bool) 112d4586358 function setCollectionNesting(bool enable) external;359360 // Toggle accessibility of collection nesting.361 //362 // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'363 // @param collections Addresses of collections that will be available for nesting.364 //365 // Selector: setCollectionNesting(bool,address[]) 64872396366 function setCollectionNesting(bool enable, address[] memory collections)367 external;368369 // Set the collection access method.370 // @param mode Access mode371 // 0 for Normal372 // 1 for AllowList373 //374 // Selector: setCollectionAccess(uint8) 41835d4c375 function setCollectionAccess(uint8 mode) external;376377 // Add the user to the allowed list.378 //379 // @param user Address of a trusted user.380 //381 // Selector: addToCollectionAllowList(address) 67844fe6382 function addToCollectionAllowList(address user) external;383384 // Remove the user from the allowed list.385 //386 // @param user Address of a removed user.387 //388 // Selector: removeFromCollectionAllowList(address) 85c51acb389 function removeFromCollectionAllowList(address user) external;390391 // Switch permission for minting.392 //393 // @param mode Enable if "true".394 //395 // Selector: setCollectionMintMode(bool) 00018e84396 function setCollectionMintMode(bool mode) external;397398 // Check that account is the owner or admin of the collection399 //400 // @param user account to verify401 // @return "true" if account is the owner or admin402 //403 // Selector: verifyOwnerOrAdmin(address) c2282493404 function verifyOwnerOrAdmin(address user) external view returns (bool);405406 // Returns collection type407 //408 // @return `Fungible` or `NFT` or `ReFungible`409 //410 // Selector: uniqueCollectionType() d34b55b8411 function uniqueCollectionType() external returns (string memory);412}413414// Selector: 780e9d63415interface ERC721Enumerable is Dummy, ERC165 {416 // @notice Enumerate valid RFTs417 // @param index A counter less than `totalSupply()`418 // @return The token identifier for the `index`th NFT,419 // (sort order not specified)420 //421 // Selector: tokenByIndex(uint256) 4f6ccce7422 function tokenByIndex(uint256 index) external view returns (uint256);423424 // Not implemented425 //426 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59427 function tokenOfOwnerByIndex(address owner, uint256 index)428 external429 view430 returns (uint256);431432 // @notice Count RFTs tracked by this contract433 // @return A count of valid RFTs tracked by this contract, where each one of434 // them has an assigned and queryable owner not equal to the zero address435 //436 // Selector: totalSupply() 18160ddd437 function totalSupply() external view returns (uint256);438}439440// Selector: 7c3bef89441interface ERC721UniqueExtensions is Dummy, ERC165 {442 // @notice Transfer ownership of an RFT443 // @dev Throws unless `msg.sender` is the current owner. Throws if `to`444 // is the zero address. Throws if `tokenId` is not a valid RFT.445 // Throws if RFT pieces have multiple owners.446 // @param to The new owner447 // @param tokenId The RFT to transfer448 // @param _value Not used for an RFT449 //450 // Selector: transfer(address,uint256) a9059cbb451 function transfer(address to, uint256 tokenId) external;452453 // @notice Burns a specific ERC721 token.454 // @dev Throws unless `msg.sender` is the current owner or an authorized455 // operator for this RFT. Throws if `from` is not the current owner. Throws456 // if `to` is the zero address. Throws if `tokenId` is not a valid RFT.457 // Throws if RFT pieces have multiple owners.458 // @param from The current owner of the RFT459 // @param tokenId The RFT to transfer460 // @param _value Not used for an RFT461 //462 // Selector: burnFrom(address,uint256) 79cc6790463 function burnFrom(address from, uint256 tokenId) external;464465 // @notice Returns next free RFT ID.466 //467 // Selector: nextTokenId() 75794a3c468 function nextTokenId() external view returns (uint256);469470 // @notice Function to mint multiple tokens.471 // @dev `tokenIds` should be an array of consecutive numbers and first number472 // should be obtained with `nextTokenId` method473 // @param to The new owner474 // @param tokenIds IDs of the minted RFTs475 //476 // Selector: mintBulk(address,uint256[]) 44a9945e477 function mintBulk(address to, uint256[] memory tokenIds)478 external479 returns (bool);480481 // @notice Function to mint multiple tokens with the given tokenUris.482 // @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive483 // numbers and first number should be obtained with `nextTokenId` method484 // @param to The new owner485 // @param tokens array of pairs of token ID and token URI for minted tokens486 //487 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006488 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)489 external490 returns (bool);491492 // Returns EVM address for refungible token493 //494 // @param token ID of the token495 //496 // Selector: tokenContractAddress(uint256) ab76fac6497 function tokenContractAddress(uint256 token)498 external499 view500 returns (address);501}502564503interface UniqueRefungible is565interface UniqueRefungible is504 Dummy,566 Dummy,tests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;556// Common stubs holder6/// @dev common stubs holder7interface Dummy {7interface Dummy {889}9}12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);13}13}141415// Inline15/// @dev the ERC-165 identifier for this interface is 0x5755c3f216interface ERC1633 is Dummy, ERC165 {17 /// @dev EVM selector for this function is: 0x80a54001,18 /// or in textual repr: parentToken()19 function parentToken() external view returns (address);2021 /// @dev EVM selector for this function is: 0xd7f083f3,22 /// or in textual repr: parentTokenId()23 function parentTokenId() external view returns (uint256);24}2526/// @dev the ERC-165 identifier for this interface is 0xab8deb3727interface ERC20UniqueExtensions is Dummy, ERC165 {28 /// @dev Function that burns an amount of the token of a given account,29 /// deducting from the sender's allowance for said account.30 /// @param from The account whose tokens will be burnt.31 /// @param amount The amount that will be burnt.32 /// @dev EVM selector for this function is: 0x79cc6790,33 /// or in textual repr: burnFrom(address,uint256)34 function burnFrom(address from, uint256 amount) external returns (bool);3536 /// @dev Function that changes total amount of the tokens.37 /// Throws if `msg.sender` doesn't owns all of the tokens.38 /// @param amount New total amount of the tokens.39 /// @dev EVM selector for this function is: 0xd2418ca7,40 /// or in textual repr: repartition(uint256)41 function repartition(uint256 amount) external returns (bool);42}4344/// @dev inlined interface16interface ERC20Events {45interface ERC20Events {17 event Transfer(address indexed from, address indexed to, uint256 value);46 event Transfer(address indexed from, address indexed to, uint256 value);18 event Approval(47 event Approval(22 );51 );23}52}245325// Selector: 042f110654/// @title Standard ERC20 token26interface ERC1633UniqueExtensions is Dummy, ERC165 {55///27 // Selector: setParentNFT(address,uint256) 042f110656/// @dev Implementation of the basic standard token.28 function setParentNFT(address collection, uint256 nftId)57/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md29 external58/// @dev the ERC-165 identifier for this interface is 0x942e8b2230 returns (bool);31}3233// Selector: 5755c3f234interface ERC1633 is Dummy, ERC165 {35 // Selector: parentToken() 80a5400136 function parentToken() external view returns (address);3738 // Selector: parentTokenId() d7f083f339 function parentTokenId() external view returns (uint256);40}4142// Selector: 942e8b2243interface ERC20 is Dummy, ERC165, ERC20Events {59interface ERC20 is Dummy, ERC165, ERC20Events {44 // @return the name of the token.60 /// @return the name of the token.45 //61 /// @dev EVM selector for this function is: 0x06fdde03,46 // Selector: name() 06fdde0362 /// or in textual repr: name()47 function name() external view returns (string memory);63 function name() external view returns (string memory);486449 // @return the symbol of the token.65 /// @return the symbol of the token.50 //66 /// @dev EVM selector for this function is: 0x95d89b41,51 // Selector: symbol() 95d89b4167 /// or in textual repr: symbol()52 function symbol() external view returns (string memory);68 function symbol() external view returns (string memory);536954 // @dev Total number of tokens in existence70 /// @dev Total number of tokens in existence55 //71 /// @dev EVM selector for this function is: 0x18160ddd,56 // Selector: totalSupply() 18160ddd72 /// or in textual repr: totalSupply()57 function totalSupply() external view returns (uint256);73 function totalSupply() external view returns (uint256);587459 // @dev Not supported75 /// @dev Not supported60 //76 /// @dev EVM selector for this function is: 0x313ce567,61 // Selector: decimals() 313ce56777 /// or in textual repr: decimals()62 function decimals() external view returns (uint8);78 function decimals() external view returns (uint8);637964 // @dev Gets the balance of the specified address.80 /// @dev Gets the balance of the specified address.65 // @param owner The address to query the balance of.81 /// @param owner The address to query the balance of.66 // @return An uint256 representing the amount owned by the passed address.82 /// @return An uint256 representing the amount owned by the passed address.67 //83 /// @dev EVM selector for this function is: 0x70a08231,68 // Selector: balanceOf(address) 70a0823184 /// or in textual repr: balanceOf(address)69 function balanceOf(address owner) external view returns (uint256);85 function balanceOf(address owner) external view returns (uint256);708671 // @dev Transfer token for a specified address87 /// @dev Transfer token for a specified address72 // @param to The address to transfer to.88 /// @param to The address to transfer to.73 // @param amount The amount to be transferred.89 /// @param amount The amount to be transferred.74 //90 /// @dev EVM selector for this function is: 0xa9059cbb,75 // Selector: transfer(address,uint256) a9059cbb91 /// or in textual repr: transfer(address,uint256)76 function transfer(address to, uint256 amount) external returns (bool);92 function transfer(address to, uint256 amount) external returns (bool);779378 // @dev Transfer tokens from one address to another94 /// @dev Transfer tokens from one address to another79 // @param from address The address which you want to send tokens from95 /// @param from address The address which you want to send tokens from80 // @param to address The address which you want to transfer to96 /// @param to address The address which you want to transfer to81 // @param amount uint256 the amount of tokens to be transferred97 /// @param amount uint256 the amount of tokens to be transferred82 //98 /// @dev EVM selector for this function is: 0x23b872dd,83 // Selector: transferFrom(address,address,uint256) 23b872dd99 /// or in textual repr: transferFrom(address,address,uint256)84 function transferFrom(100 function transferFrom(85 address from,101 address from,86 address to,102 address to,87 uint256 amount103 uint256 amount88 ) external returns (bool);104 ) external returns (bool);8910590 // @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.106 /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.91 // Beware that changing an allowance with this method brings the risk that someone may use both the old107 /// Beware that changing an allowance with this method brings the risk that someone may use both the old92 // and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this108 /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this93 // race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:109 /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:94 // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729110 /// https://github.com/ethereum/EIPs/issues/20#issuecomment-26352472995 // @param spender The address which will spend the funds.111 /// @param spender The address which will spend the funds.96 // @param amount The amount of tokens to be spent.112 /// @param amount The amount of tokens to be spent.97 //113 /// @dev EVM selector for this function is: 0x095ea7b3,98 // Selector: approve(address,uint256) 095ea7b3114 /// or in textual repr: approve(address,uint256)99 function approve(address spender, uint256 amount) external returns (bool);115 function approve(address spender, uint256 amount) external returns (bool);100116101 // @dev Function to check the amount of tokens that an owner allowed to a spender.117 /// @dev Function to check the amount of tokens that an owner allowed to a spender.102 // @param owner address The address which owns the funds.118 /// @param owner address The address which owns the funds.103 // @param spender address The address which will spend the funds.119 /// @param spender address The address which will spend the funds.104 // @return A uint256 specifying the amount of tokens still available for the spender.120 /// @return A uint256 specifying the amount of tokens still available for the spender.105 //121 /// @dev EVM selector for this function is: 0xdd62ed3e,106 // Selector: allowance(address,address) dd62ed3e122 /// or in textual repr: allowance(address,address)107 function allowance(address owner, address spender)123 function allowance(address owner, address spender)108 external124 external109 view125 view110 returns (uint256);126 returns (uint256);111}127}112113// Selector: ab8deb37114interface ERC20UniqueExtensions is Dummy, ERC165 {115 // @dev Function that burns an amount of the token of a given account,116 // deducting from the sender's allowance for said account.117 // @param from The account whose tokens will be burnt.118 // @param amount The amount that will be burnt.119 //120 // Selector: burnFrom(address,uint256) 79cc6790121 function burnFrom(address from, uint256 amount) external returns (bool);122123 // @dev Function that changes total amount of the tokens.124 // Throws if `msg.sender` doesn't owns all of the tokens.125 // @param amount New total amount of the tokens.126 //127 // Selector: repartition(uint256) d2418ca7128 function repartition(uint256 amount) external returns (bool);129}130128131interface UniqueRefungibleToken is129interface UniqueRefungibleToken is132 Dummy,130 Dummy,133 ERC165,131 ERC165,134 ERC20,132 ERC20,135 ERC20UniqueExtensions,133 ERC20UniqueExtensions,136 ERC1633,134 ERC1633137 ERC1633UniqueExtensions138{}135{}139136tests/src/eth/base.test.tsdiffbeforeafterboth94 });94 });959596 itWeb3('ERC721 support', async ({web3}) => {96 itWeb3('ERC721 support', async ({web3}) => {97 expect(await contract(web3).methods.supportsInterface('0x58800161').call()).to.be.true;97 expect(await contract(web3).methods.supportsInterface('0x780e9d63').call()).to.be.true;98 });98 });9999100 itWeb3('ERC721Metadata support', async ({web3}) => {100 itWeb3('ERC721Metadata support', async ({web3}) => {tests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth151516import {expect} from 'chai';16import {expect} from 'chai';17import privateKey from '../substrate/privateKey';17import privateKey from '../substrate/privateKey';18import { UNIQUE } from '../util/helpers';18import {19import {19 createEthAccount,20 createEthAccount,20 createEthAccountWithBalance, 21 createEthAccountWithBalance, 21 evmCollection, 22 evmCollection, 22 evmCollectionHelpers, 23 evmCollectionHelpers, 23 getCollectionAddressFromResult, 24 getCollectionAddressFromResult, 24 itWeb3,25 itWeb3,26 recordEthFee,27 subToEth,25} from './util/helpers';28} from './util/helpers';262927describe('Add collection admins', () => {30describe('Add collection admins', () => {717472 const newAdmin = createEthAccount(web3);75 const newAdmin = createEthAccount(web3);73 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);76 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);74 expect(await collectionEvm.methods.verifyOwnerOrAdmin(newAdmin).call()).to.be.false;77 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.false;75 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();78 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();76 expect(await collectionEvm.methods.verifyOwnerOrAdmin(newAdmin).call()).to.be.true;79 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.true;77 });80 });788179 itWeb3('(!negative tests!) Add admin by ADMIN is not allowed', async ({api, web3, privateKeyWrapper}) => {82 itWeb3('(!negative tests!) Add admin by ADMIN is not allowed', async ({api, web3, privateKeyWrapper}) => {311 });314 });312});315});316317describe('Change owner tests', () => {318 itWeb3('Change owner', async ({api, web3, privateKeyWrapper}) => {319 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);320 const newOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);321 const collectionHelper = evmCollectionHelpers(web3, owner);322 const result = await collectionHelper.methods323 .createNonfungibleCollection('A', 'B', 'C')324 .send();325 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);326 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);327 328 await collectionEvm.methods.setOwner(newOwner).send();329 330 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;331 expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.true;332 });333334 itWeb3('change owner call fee', async ({web3, api, privateKeyWrapper}) => {335 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);336 const newOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);337 const collectionHelper = evmCollectionHelpers(web3, owner);338 const result = await collectionHelper.methods339 .createNonfungibleCollection('A', 'B', 'C')340 .send();341 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);342 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);343344 const cost = await recordEthFee(api, owner, () => collectionEvm.methods.setOwner(newOwner).send());345 expect(cost < BigInt(0.2 * Number(UNIQUE)));346 expect(cost > 0);347 });348349 itWeb3('(!negative tests!) call setOwner by non owner', async ({api, web3, privateKeyWrapper}) => {350 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);351 const newOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);352 const collectionHelper = evmCollectionHelpers(web3, owner);353 const result = await collectionHelper.methods354 .createNonfungibleCollection('A', 'B', 'C')355 .send();356 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);357 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);358 359 await expect(collectionEvm.methods.setOwner(newOwner).send({from: newOwner})).to.be.rejected;360 expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.false;361 });362});363364describe('Change substrate owner tests', () => {365 itWeb3('Change owner', async ({api, web3, privateKeyWrapper}) => {366 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);367 const newOwner = privateKeyWrapper('//Alice');368 const collectionHelper = evmCollectionHelpers(web3, owner);369 const result = await collectionHelper.methods370 .createNonfungibleCollection('A', 'B', 'C')371 .send();372 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);373 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);374 375 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.true;376 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false;377 378 await collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send();379 380 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;381 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.true;382 });383384 itWeb3('change owner call fee', async ({web3, api, privateKeyWrapper}) => {385 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);386 const newOwner = privateKeyWrapper('//Alice');387 const collectionHelper = evmCollectionHelpers(web3, owner);388 const result = await collectionHelper.methods389 .createNonfungibleCollection('A', 'B', 'C')390 .send();391 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);392 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);393394 const cost = await recordEthFee(api, owner, () => collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send());395 expect(cost < BigInt(0.2 * Number(UNIQUE)));396 expect(cost > 0);397 });398399 itWeb3('(!negative tests!) call setOwner by non owner', async ({api, web3, privateKeyWrapper}) => {400 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);401 const otherReceiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);402 const newOwner = privateKeyWrapper('//Alice');403 const collectionHelper = evmCollectionHelpers(web3, owner);404 const result = await collectionHelper.methods405 .createNonfungibleCollection('A', 'B', 'C')406 .send();407 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);408 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);409 410 await expect(collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send({from: otherReceiver})).to.be.rejected;411 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false;412 });413});tests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth1import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, setCollectionSponsorExpectSuccess} from '../util/helpers';1import {addToAllowListExpectSuccess, bigIntToSub, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers';2import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents} from './util/helpers';2import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub, subToEth} from './util/helpers';3import nonFungibleAbi from './nonFungibleAbi.json';3import nonFungibleAbi from './nonFungibleAbi.json';4import {expect} from 'chai';4import {expect} from 'chai';5import {evmToAddress} from '@polkadot/util-crypto';6import {submitTransactionAsync} from '../substrate/substrate-api';7import getBalance from '../substrate/get-balance';586describe('evm collection sponsoring', () => {9describe('evm collection sponsoring', () => {7 itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => {10 itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => {37 ]);40 ]);38 });41 });4243 itWeb3('Set substrate sponsor', async ({api, web3, privateKeyWrapper}) => {44 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);45 const collectionHelpers = evmCollectionHelpers(web3, owner);46 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();47 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);48 const sponsor = privateKeyWrapper('//Alice');49 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);5051 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;52 result = await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});53 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;54 55 const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);56 await submitTransactionAsync(sponsor, confirmTx);57 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;58 59 const sponsorTuple = await collectionEvm.methods.getCollectionSponsor().call({from: owner});60 expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);61 });6263 itWeb3('Remove sponsor', async ({api, web3, privateKeyWrapper}) => {64 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);65 const collectionHelpers = evmCollectionHelpers(web3, owner);66 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();67 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);68 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);69 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);7071 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;72 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});73 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;74 75 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});76 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;77 78 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});79 80 const sponsorTuple = await collectionEvm.methods.getCollectionSponsor().call({from: owner});81 expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');82 });8384 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {85 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);86 const collectionHelpers = evmCollectionHelpers(web3, owner);87 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();88 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);89 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);90 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);91 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});92 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;93 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;94 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;95 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));96 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');9798 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});99 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;100 expect(collectionSub.sponsorship.isConfirmed).to.be.true;101 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));102103 const user = createEthAccount(web3);104 const nextTokenId = await collectionEvm.methods.nextTokenId().call();105 expect(nextTokenId).to.be.equal('1');106107 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();108 expect(oldPermissions.mintMode).to.be.false;109 expect(oldPermissions.access).to.be.equal('Normal');110111 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});112 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});113 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});114115 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();116 expect(newPermissions.mintMode).to.be.true;117 expect(newPermissions.access).to.be.equal('AllowList');118119 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);120 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);121122 {123 const nextTokenId = await collectionEvm.methods.nextTokenId().call();124 expect(nextTokenId).to.be.equal('1');125 const result = await collectionEvm.methods.mintWithTokenURI(126 user,127 nextTokenId,128 'Test URI',129 ).send({from: user});130 const events = normalizeEvents(result.events);131132 expect(events).to.be.deep.equal([133 {134 address: collectionIdAddress,135 event: 'Transfer',136 args: {137 from: '0x0000000000000000000000000000000000000000',138 to: user,139 tokenId: nextTokenId,140 },141 },142 ]);143144 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);145 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);146147 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');148 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);149 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;150 }151 });152153 itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => {154 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);155 const collectionHelpers = evmCollectionHelpers(web3, owner);156 const result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();157 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);158 const sponsor = privateKeyWrapper('//Alice');159 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);160161 await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});162 163 const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);164 await submitTransactionAsync(sponsor, confirmTx);165 166 const user = createEthAccount(web3);167 const nextTokenId = await collectionEvm.methods.nextTokenId().call();168 expect(nextTokenId).to.be.equal('1');169170 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});171 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});172 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});173174 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);175 const sponsorBalanceBefore = (await getBalance(api, [sponsor.address]))[0];176177 {178 const nextTokenId = await collectionEvm.methods.nextTokenId().call();179 expect(nextTokenId).to.be.equal('1');180 const result = await collectionEvm.methods.mintWithTokenURI(181 user,182 nextTokenId,183 'Test URI',184 ).send({from: user});185 const events = normalizeEvents(result.events);186187 expect(events).to.be.deep.equal([188 {189 address: collectionIdAddress,190 event: 'Transfer',191 args: {192 from: '0x0000000000000000000000000000000000000000',193 to: user,194 tokenId: nextTokenId,195 },196 },197 ]);198199 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);200 const sponsorBalanceAfter = (await getBalance(api, [sponsor.address]))[0];201202 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');203 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);204 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;205 }206 });207208 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {209 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);210 const collectionHelpers = evmCollectionHelpers(web3, owner);211 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();212 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);213 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);214 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);215 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();216 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;217 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;218 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;219 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));220 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');221 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);222 await sponsorCollection.methods.confirmCollectionSponsorship().send();223 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;224 expect(collectionSub.sponsorship.isConfirmed).to.be.true;225 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));226227 const user = createEthAccount(web3);228 await collectionEvm.methods.addCollectionAdmin(user).send();229 230 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);231 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);232 233 234 const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);235 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();236 expect(nextTokenId).to.be.equal('1');237 result = await userCollectionEvm.methods.mintWithTokenURI(238 user,239 nextTokenId,240 'Test URI',241 ).send();242243 const events = normalizeEvents(result.events);244 const address = collectionIdToAddress(collectionId);245246 expect(events).to.be.deep.equal([247 {248 address,249 event: 'Transfer',250 args: {251 from: '0x0000000000000000000000000000000000000000',252 to: user,253 tokenId: nextTokenId,254 },255 },256 ]);257 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');258 259 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);260 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);261 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);262 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;263 });39});264});40265tests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth23 itWeb3,23 itWeb3,24 SponsoringMode,24 SponsoringMode,25 createEthAccount,25 createEthAccount,26 collectionIdToAddress,27 GAS_ARGS,28 normalizeEvents,29 subToEth,30 executeEthTxOnSub,31 evmCollectionHelpers,32 getCollectionAddressFromResult,33 evmCollection,34 ethBalanceViaSub,26 ethBalanceViaSub,35} from './util/helpers';27} from './util/helpers';36import {37 addCollectionAdminExpectSuccess,38 createCollectionExpectSuccess,39 getDetailedCollectionInfo,40 transferBalanceTo,41} from '../util/helpers';42import nonFungibleAbi from './nonFungibleAbi.json';43import getBalance from '../substrate/get-balance';44import {evmToAddress} from '@polkadot/util-crypto';452846describe('Sponsoring EVM contracts', () => {29describe('Sponsoring EVM contracts', () => {30 itWeb3('Self sponsored can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {31 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);32 const flipper = await deployFlipper(web3, owner);33 const helpers = contractHelpers(web3, owner);34 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;35 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;36 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;37 });3839 itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {40 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);41 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);42 const flipper = await deployFlipper(web3, owner);43 const helpers = contractHelpers(web3, owner);44 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;45 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');46 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;47 });4847 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => {49 itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => {48 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);50 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);49 const flipper = await deployFlipper(web3, owner);51 const flipper = await deployFlipper(web3, owner);50 const helpers = contractHelpers(web3, owner);52 const helpers = contractHelpers(web3, owner);51 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;53 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;52 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});54 await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected;53 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;55 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;54 });56 });555759 const flipper = await deployFlipper(web3, owner);61 const flipper = await deployFlipper(web3, owner);60 const helpers = contractHelpers(web3, owner);62 const helpers = contractHelpers(web3, owner);61 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;63 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;62 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;64 await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission');63 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;65 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;64 });66 });67 68 itWeb3('Sponsor can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {69 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);70 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);71 const flipper = await deployFlipper(web3, owner);72 const helpers = contractHelpers(web3, owner);73 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;74 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;75 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;76 });77 78 itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {79 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);80 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);81 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);82 const flipper = await deployFlipper(web3, owner);83 const helpers = contractHelpers(web3, owner);84 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;85 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission');86 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;87 });658889 itWeb3('Sponsorship can be confirmed by the address that pending as sponsor', async ({api, web3, privateKeyWrapper}) => {90 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);91 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);92 const flipper = await deployFlipper(web3, owner);93 const helpers = contractHelpers(web3, owner);94 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;95 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;96 await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected;97 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;98 });99100 itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => {101 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);102 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);103 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const flipper = await deployFlipper(web3, owner);105 const helpers = contractHelpers(web3, owner);106 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;107 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;108 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission');109 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;110 });111112 itWeb3('Sponsorship can not be confirmed by the address that not set as sponsor', async ({api, web3, privateKeyWrapper}) => {113 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);114 const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);115 const flipper = await deployFlipper(web3, owner);116 const helpers = contractHelpers(web3, owner);117 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;118 await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor');119 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;120 });121122 itWeb3('Get self sponsored sponsor', async ({api, web3, privateKeyWrapper}) => {123 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);124 const flipper = await deployFlipper(web3, owner);125 const helpers = contractHelpers(web3, owner);126 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();127 128 const result = await helpers.methods.getSponsor(flipper.options.address).call();129130 expect(result[0]).to.be.eq(flipper.options.address);131 expect(result[1]).to.be.eq('0');132 });133134 itWeb3('Get confirmed sponsor', async ({api, web3, privateKeyWrapper}) => {135 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);136 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);137 const flipper = await deployFlipper(web3, owner);138 const helpers = contractHelpers(web3, owner);139 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();140 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});141 142 const result = await helpers.methods.getSponsor(flipper.options.address).call();143144 expect(result[0]).to.be.eq(sponsor);145 expect(result[1]).to.be.eq('0');146 });147148 itWeb3('Sponsor can be removed by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => {149 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);150 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);151 const flipper = await deployFlipper(web3, owner);152 const helpers = contractHelpers(web3, owner);153154 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;155 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();156 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});157 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;158 159 await helpers.methods.removeSponsor(flipper.options.address).send();160 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;161 });162163 itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => {164 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);165 const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);166 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);167 const flipper = await deployFlipper(web3, owner);168 const helpers = contractHelpers(web3, owner);169170 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;171 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();172 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});173 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;174 175 await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');176 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;177 });17866 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {179 itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {180 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);181 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);182 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);183184 const flipper = await deployFlipper(web3, owner);185186 const helpers = contractHelpers(web3, owner);187188 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();189 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});190191 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});192 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});193194 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);195 const callerBalanceBefore = await ethBalanceViaSub(api, caller);196197 await flipper.methods.flip().send({from: caller});198 expect(await flipper.methods.getValue().call()).to.be.true;199200 // Balance should be taken from sponsor instead of caller201 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);202 const callerBalanceAfter = await ethBalanceViaSub(api, caller);203 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;204 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);205 });206207 itWeb3('In generous mode, non-allowlisted user transaction will be self sponsored', async ({api, web3, privateKeyWrapper}) => {67 const alice = privateKeyWrapper('//Alice');208 const alice = privateKeyWrapper('//Alice');6820969 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);210 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);7321474 const helpers = contractHelpers(web3, owner);215 const helpers = contractHelpers(web3, owner);7521676 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;217 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();21877 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});219 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});78 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});220 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});79 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;8022181 await transferBalanceToEth(api, alice, flipper.options.address);222 await transferBalanceToEth(api, alice, flipper.options.address);8222383 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);224 const contractBalanceBefore = await ethBalanceViaSub(api, flipper.options.address);84 expect(originalFlipperBalance).to.be.not.equal('0');225 const callerBalanceBefore = await ethBalanceViaSub(api, caller);8522686 await flipper.methods.flip().send({from: caller});227 await flipper.methods.flip().send({from: caller});87 expect(await flipper.methods.getValue().call()).to.be.true;228 expect(await flipper.methods.getValue().call()).to.be.true;8822989 // Balance should be taken from flipper instead of caller230 // Balance should be taken from sponsor instead of caller90 const balanceAfter = await web3.eth.getBalance(flipper.options.address);231 const contractBalanceAfter = await ethBalanceViaSub(api, flipper.options.address);232 const callerBalanceAfter = await ethBalanceViaSub(api, caller);233 expect(contractBalanceAfter < contractBalanceBefore).to.be.true;91 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);234 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);92 });235 });9323694 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({api, web3, privateKeyWrapper}) => {237 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({api, web3, privateKeyWrapper}) => {95 const alice = privateKeyWrapper('//Alice');9697 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);238 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);239 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);98 const caller = createEthAccount(web3);240 const caller = createEthAccount(web3);99241100 const flipper = await deployFlipper(web3, owner);242 const flipper = await deployFlipper(web3, owner);103 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});245 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});104 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});246 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});105247106 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;107 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});248 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});108 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});249 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});109 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;110250111 await transferBalanceToEth(api, alice, flipper.options.address);251 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();252 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});112253113 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);254 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);114 expect(originalFlipperBalance).to.be.not.equal('0');255 expect(sponsorBalanceBefore).to.be.not.equal('0');115256116 await flipper.methods.flip().send({from: caller});257 await flipper.methods.flip().send({from: caller});117 expect(await flipper.methods.getValue().call()).to.be.true;258 expect(await flipper.methods.getValue().call()).to.be.true;118259119 // Balance should be taken from flipper instead of caller260 // Balance should be taken from flipper instead of caller120 const balanceAfter = await web3.eth.getBalance(flipper.options.address);261 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);121 expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);262 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;122 });263 });123264124 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({api, web3, privateKeyWrapper}) => {265 itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({api, web3, privateKeyWrapper}) => {131272132 const helpers = contractHelpers(web3, owner);273 const helpers = contractHelpers(web3, owner);133274134 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;135 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});275 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});136 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});276 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});137 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;138277139 await transferBalanceToEth(api, alice, flipper.options.address);278 await transferBalanceToEth(api, alice, flipper.options.address);140279150 });289 });151290152 itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3, privateKeyWrapper}) => {291 itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3, privateKeyWrapper}) => {153 const alice = privateKeyWrapper('//Alice');154155 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);292 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);293 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);156 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);294 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);157 const originalCallerBalance = await web3.eth.getBalance(caller);158295159 const flipper = await deployFlipper(web3, owner);296 const flipper = await deployFlipper(web3, owner);160297161 const helpers = contractHelpers(web3, owner);298 const helpers = contractHelpers(web3, owner);162 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});299 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});163 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});300 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});164301165 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;166 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});302 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});167 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});303 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});168 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;169304170 await transferBalanceToEth(api, alice, flipper.options.address);305 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();306 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});171307172 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);308 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);173 expect(originalFlipperBalance).to.be.not.equal('0');309 const callerBalanceBefore = await ethBalanceViaSub(api, caller);174310175 await flipper.methods.flip().send({from: caller});311 await flipper.methods.flip().send({from: caller});176 expect(await flipper.methods.getValue().call()).to.be.true;312 expect(await flipper.methods.getValue().call()).to.be.true;177313178 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);314 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);315 const callerBalanceAfter = await ethBalanceViaSub(api, caller);316 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;317 expect(callerBalanceAfter).to.be.equals(callerBalanceBefore);179 });318 });180319181 itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3, privateKeyWrapper}) => {320 itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3, privateKeyWrapper}) => {182 const alice = privateKeyWrapper('//Alice');183184 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);321 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);322 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);185 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);323 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);186 const originalCallerBalance = await web3.eth.getBalance(caller);324 const originalCallerBalance = await web3.eth.getBalance(caller);187325191 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});329 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});192 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});330 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});193331194 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;195 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});332 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});196 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});333 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});197 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;198334199 await transferBalanceToEth(api, alice, flipper.options.address);335 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();336 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});200337201 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);338 const originalFlipperBalance = await web3.eth.getBalance(sponsor);202 expect(originalFlipperBalance).to.be.not.equal('0');339 expect(originalFlipperBalance).to.be.not.equal('0');203340204 await flipper.methods.flip().send({from: caller});341 await flipper.methods.flip().send({from: caller});205 expect(await flipper.methods.getValue().call()).to.be.true;342 expect(await flipper.methods.getValue().call()).to.be.true;206 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);343 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);207344208 const newFlipperBalance = await web3.eth.getBalance(flipper.options.address);345 const newFlipperBalance = await web3.eth.getBalance(sponsor);209 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);346 expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);210347211 await flipper.methods.flip().send({from: caller});348 await flipper.methods.flip().send({from: caller});212 expect(await web3.eth.getBalance(flipper.options.address)).to.be.equal(newFlipperBalance);349 expect(await web3.eth.getBalance(sponsor)).to.be.equal(newFlipperBalance);213 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);350 expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);214 });351 });215352219 const flipper = await deployFlipper(web3, owner);356 const flipper = await deployFlipper(web3, owner);220 const helpers = contractHelpers(web3, owner);357 const helpers = contractHelpers(web3, owner);221 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');358 expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');222 });223224 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {225 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);226 const collectionHelpers = evmCollectionHelpers(web3, owner);227 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();228 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);229 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);230 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);231 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});232 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;233 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;234 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;235 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));236 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');237238 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});239 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;240 expect(collectionSub.sponsorship.isConfirmed).to.be.true;241 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));242243 const user = createEthAccount(web3);244 const nextTokenId = await collectionEvm.methods.nextTokenId().call();245 expect(nextTokenId).to.be.equal('1');246247 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();248 expect(oldPermissions.mintMode).to.be.false;249 expect(oldPermissions.access).to.be.equal('Normal');250251 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});252 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});253 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});254255 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();256 expect(newPermissions.mintMode).to.be.true;257 expect(newPermissions.access).to.be.equal('AllowList');258259 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);260 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);261262 {263 const nextTokenId = await collectionEvm.methods.nextTokenId().call();264 expect(nextTokenId).to.be.equal('1');265 const result = await collectionEvm.methods.mintWithTokenURI(266 user,267 nextTokenId,268 'Test URI',269 ).send({from: user});270 const events = normalizeEvents(result.events);271272 expect(events).to.be.deep.equal([273 {274 address: collectionIdAddress,275 event: 'Transfer',276 args: {277 from: '0x0000000000000000000000000000000000000000',278 to: user,279 tokenId: nextTokenId,280 },281 },282 ]);283284 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);285 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);286287 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');288 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);289 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;290 }291 });292293 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {294 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);295 const collectionHelpers = evmCollectionHelpers(web3, owner);296 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();297 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);298 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);299 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);300 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();301 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;302 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;303 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;304 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));305 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');306 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);307 await sponsorCollection.methods.confirmCollectionSponsorship().send();308 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;309 expect(collectionSub.sponsorship.isConfirmed).to.be.true;310 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));311312 const user = createEthAccount(web3);313 await collectionEvm.methods.addCollectionAdmin(user).send();314 315 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);316 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);317 318 319 const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);320 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();321 expect(nextTokenId).to.be.equal('1');322 result = await userCollectionEvm.methods.mintWithTokenURI(323 user,324 nextTokenId,325 'Test URI',326 ).send();327328 const events = normalizeEvents(result.events);329 const address = collectionIdToAddress(collectionId);330331 expect(events).to.be.deep.equal([332 {333 address,334 event: 'Transfer',335 args: {336 from: '0x0000000000000000000000000000000000000000',337 to: user,338 tokenId: nextTokenId,339 },340 },341 ]);342 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');343 344 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);345 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);346 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);347 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;348 });359 });349});360});350361tests/src/eth/fractionalizer/Fractionalizer.bindiffbeforeafterbothno changes
tests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth16 }16 }17 address rftCollection;17 address rftCollection;18 mapping(address => bool) nftCollectionAllowList;18 mapping(address => bool) nftCollectionAllowList;19 mapping(address => mapping(uint256 => uint256)) nft2rftMapping;19 mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;20 mapping(address => Token) rft2nftMapping;20 mapping(address => Token) public rft2nftMapping;21 bytes32 refungibleCollectionType = keccak256(bytes("ReFungible"));21 bytes32 refungibleCollectionType = keccak256(bytes("ReFungible"));222223 receive() external payable onlyOwner {}23 receive() external payable onlyOwner {}64 "Wrong collection type. Collection is not refungible."64 "Wrong collection type. Collection is not refungible."65 );65 );66 require(66 require(67 refungibleContract.verifyOwnerOrAdmin(address(this)),67 refungibleContract.isOwnerOrAdmin(address(this)),68 "Fractionalizer contract should be an admin of the collection"68 "Fractionalizer contract should be an admin of the collection"69 );69 );70 rftCollection = _collection;70 rftCollection = _collection;137 rft2nftMapping[rftTokenAddress] = Token(_collection, _token);137 rft2nftMapping[rftTokenAddress] = Token(_collection, _token);138138139 rftTokenContract = UniqueRefungibleToken(rftTokenAddress);139 rftTokenContract = UniqueRefungibleToken(rftTokenAddress);140 rftTokenContract.setParentNFT(_collection, _token);141 } else {140 } else {142 rftTokenId = nft2rftMapping[_collection][_token];141 rftTokenId = nft2rftMapping[_collection][_token];143 rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId);142 rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId);tests/src/eth/fractionalizer/FractionalizerAbi.jsondiffbeforeafterbothno changes
tests/src/eth/fractionalizer/fractionalizer.test.tsdiffbeforeafterboth224 });224 });225 });225 });226227 itWeb3('Test fractionalizer NFT <-> RFT mapping ', async ({api, web3, privateKeyWrapper}) => {228 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);229230 const {fractionalizer, rftCollectionAddress} = await initFractionalizer(api, web3, privateKeyWrapper, owner);231 const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await createRFTToken(api, web3, owner, fractionalizer, 100n);232233 const {collectionId, tokenId} = tokenIdFromAddress(rftTokenAddress);234 const refungibleAddress = collectionIdToAddress(collectionId);235 expect(rftCollectionAddress).to.be.equal(refungibleAddress);236 const refungibleTokenContract = uniqueRefungibleToken(web3, rftTokenAddress, owner);237 await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send();238239 const rft2nft = await fractionalizer.methods.rft2nftMapping(rftTokenAddress).call();240 expect(rft2nft).to.be.like({241 _collection: nftCollectionAddress,242 _tokenId: nftTokenId,243 });244245 const nft2rft = await fractionalizer.methods.nft2rftMapping(nftCollectionAddress, nftTokenId).call();246 expect(nft2rft).to.be.eq(tokenId.toString());247 });226});248});227249228250tests/src/eth/fungible.test.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {approveExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';17import {approveExpectSuccess, createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';19import fungibleAbi from './fungibleAbi.json';19import fungibleAbi from './fungibleAbi.json';20import {expect} from 'chai';20import {expect} from 'chai';21import {submitTransactionAsync} from '../substrate/substrate-api';212222describe('Fungible: Information getting', () => {23describe('Fungible: Information getting', () => {23 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {24 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {58});59});596060describe('Fungible: Plain calls', () => {61describe('Fungible: Plain calls', () => {62 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {63 const alice = privateKeyWrapper('//Alice');64 const collection = await createCollection(api, alice, {65 name: 'token name',66 mode: {type: 'Fungible', decimalPoints: 0},67 });6869 const receiver = createEthAccount(web3);7071 const collectionIdAddress = collectionIdToAddress(collection.collectionId);72 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);73 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});74 await submitTransactionAsync(alice, changeAdminTx);7576 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});77 const result = await collectionContract.methods.mint(receiver, 100).send();78 const events = normalizeEvents(result.events);79 80 expect(events).to.be.deep.equal([81 {82 address: collectionIdAddress,83 event: 'Transfer',84 args: {85 from: '0x0000000000000000000000000000000000000000',86 to: receiver,87 value: '100',88 },89 },90 ]);91 });9293 itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {94 const alice = privateKeyWrapper('//Alice');95 const collection = await createCollection(api, alice, {96 name: 'token name',97 mode: {type: 'Fungible', decimalPoints: 0},98 });99100 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);101 const receiver1 = createEthAccount(web3);102 const receiver2 = createEthAccount(web3);103 const receiver3 = createEthAccount(web3);104105 const collectionIdAddress = collectionIdToAddress(collection.collectionId);106 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});107 await submitTransactionAsync(alice, changeAdminTx);108109 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});110 const result = await collectionContract.methods.mintBulk([111 [receiver1, 10],112 [receiver2, 20],113 [receiver3, 30],114 ]).send();115 const events = normalizeEvents(result.events);116117 expect(events).to.be.deep.contain({118 address:collectionIdAddress,119 event: 'Transfer',120 args: {121 from: '0x0000000000000000000000000000000000000000',122 to: receiver1,123 value: '10',124 },125 });126 127 expect(events).to.be.deep.contain({128 address:collectionIdAddress,129 event: 'Transfer',130 args: {131 from: '0x0000000000000000000000000000000000000000',132 to: receiver2,133 value: '20',134 },135 });136 137 expect(events).to.be.deep.contain({138 address:collectionIdAddress,139 event: 'Transfer',140 args: {141 from: '0x0000000000000000000000000000000000000000',142 to: receiver3,143 value: '30',144 },145 });146 });147148 itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {149 const alice = privateKeyWrapper('//Alice');150 const collection = await createCollection(api, alice, {151 name: 'token name',152 mode: {type: 'Fungible', decimalPoints: 0},153 });154155 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);156 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});157 await submitTransactionAsync(alice, changeAdminTx);158 const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);159160 const collectionIdAddress = collectionIdToAddress(collection.collectionId);161 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});162 await collectionContract.methods.mint(receiver, 100).send();163164 const result = await collectionContract.methods.burnFrom(receiver, 49).send({from: receiver});165 166 const events = normalizeEvents(result.events);167168 expect(events).to.be.deep.equal([169 {170 address: collectionIdAddress,171 event: 'Transfer',172 args: {173 from: receiver,174 to: '0x0000000000000000000000000000000000000000',175 value: '49',176 },177 },178 ]);179180 const balance = await collectionContract.methods.balanceOf(receiver).call();181 expect(balance).to.equal('51');182 });18361 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {184 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {62 const collection = await createCollectionExpectSuccess({185 const collection = await createCollectionExpectSuccess({tests/src/eth/fungibleAbi.jsondiffbeforeafterboth150 "stateMutability": "nonpayable",150 "stateMutability": "nonpayable",151 "type": "function"151 "type": "function"152 },152 },153 {154 "inputs": [],155 "name": "getCollectionSponsor",156 "outputs": [157 {158 "components": [159 { "internalType": "address", "name": "field_0", "type": "address" },160 { "internalType": "uint256", "name": "field_1", "type": "uint256" }161 ],162 "internalType": "struct Tuple6",163 "name": "",164 "type": "tuple"165 }166 ],167 "stateMutability": "view",168 "type": "function"169 },170 {171 "inputs": [],172 "name": "hasCollectionPendingSponsor",173 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],174 "stateMutability": "view",175 "type": "function"176 },177 {178 "inputs": [179 { "internalType": "address", "name": "user", "type": "address" }180 ],181 "name": "isOwnerOrAdmin",182 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],183 "stateMutability": "view",184 "type": "function"185 },186 {187 "inputs": [188 { "internalType": "uint256", "name": "user", "type": "uint256" }189 ],190 "name": "isOwnerOrAdminSubstrate",191 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],192 "stateMutability": "view",193 "type": "function"194 },195 {196 "inputs": [197 { "internalType": "address", "name": "to", "type": "address" },198 { "internalType": "uint256", "name": "amount", "type": "uint256" }199 ],200 "name": "mint",201 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],202 "stateMutability": "nonpayable",203 "type": "function"204 },205 {206 "inputs": [207 {208 "components": [209 { "internalType": "address", "name": "field_0", "type": "address" },210 { "internalType": "uint256", "name": "field_1", "type": "uint256" }211 ],212 "internalType": "struct Tuple6[]",213 "name": "amounts",214 "type": "tuple[]"215 }216 ],217 "name": "mintBulk",218 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],219 "stateMutability": "nonpayable",220 "type": "function"221 },153 {222 {154 "inputs": [],223 "inputs": [],155 "name": "name",224 "name": "name",175 "stateMutability": "nonpayable",244 "stateMutability": "nonpayable",176 "type": "function"245 "type": "function"177 },246 },247 {248 "inputs": [],249 "name": "removeCollectionSponsor",250 "outputs": [],251 "stateMutability": "nonpayable",252 "type": "function"253 },178 {254 {179 "inputs": [255 "inputs": [180 { "internalType": "address", "name": "user", "type": "address" }256 { "internalType": "address", "name": "user", "type": "address" }258 "stateMutability": "nonpayable",334 "stateMutability": "nonpayable",259 "type": "function"335 "type": "function"260 },336 },337 {338 "inputs": [339 { "internalType": "uint256", "name": "sponsor", "type": "uint256" }340 ],341 "name": "setCollectionSponsorSubstrate",342 "outputs": [],343 "stateMutability": "nonpayable",344 "type": "function"345 },346 {347 "inputs": [348 { "internalType": "address", "name": "newOwner", "type": "address" }349 ],350 "name": "setOwner",351 "outputs": [],352 "stateMutability": "nonpayable",353 "type": "function"354 },355 {356 "inputs": [357 { "internalType": "uint256", "name": "newOwner", "type": "uint256" }358 ],359 "name": "setOwnerSubstrate",360 "outputs": [],361 "stateMutability": "nonpayable",362 "type": "function"363 },261 {364 {262 "inputs": [365 "inputs": [263 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }366 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }308 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],411 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],309 "stateMutability": "nonpayable",412 "stateMutability": "nonpayable",310 "type": "function"413 "type": "function"311 },414 }312 {313 "inputs": [314 { "internalType": "address", "name": "user", "type": "address" }315 ],316 "name": "verifyOwnerOrAdmin",317 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],318 "stateMutability": "view",319 "type": "function"320 }321]415]322416tests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth39describe('Matcher contract usage', () => {39describe('Matcher contract usage', () => {40 itWeb3('With UNQ', async ({api, web3, privateKeyWrapper}) => {40 itWeb3('With UNQ', async ({api, web3, privateKeyWrapper}) => {41 const alice = privateKeyWrapper('//Alice');41 const alice = privateKeyWrapper('//Alice');42 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);42 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {44 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {44 from: matcherOwner,45 from: matcherOwner,49 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});50 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});50 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});51 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});52 51 await transferBalanceToEth(api, alice, matcher.options.address);53 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});54 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});525553 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});56 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});54 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});57 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});100103101 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {104 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {102 const alice = privateKeyWrapper('//Alice');105 const alice = privateKeyWrapper('//Alice');106 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);103 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);107 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const escrow = await createEthAccountWithBalance(api, web3, privateKeyWrapper);108 const escrow = await createEthAccountWithBalance(api, web3, privateKeyWrapper);105 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {109 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {112 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});116 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});113 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});117 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});118 114 await transferBalanceToEth(api, alice, matcher.options.address);119 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});120 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});115121116 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});122 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});117 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});123 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth199 "stateMutability": "view",199 "stateMutability": "view",200 "type": "function"200 "type": "function"201 },201 },202 {203 "inputs": [],204 "name": "getCollectionSponsor",205 "outputs": [206 {207 "components": [208 { "internalType": "address", "name": "field_0", "type": "address" },209 { "internalType": "uint256", "name": "field_1", "type": "uint256" }210 ],211 "internalType": "struct Tuple17",212 "name": "",213 "type": "tuple"214 }215 ],216 "stateMutability": "view",217 "type": "function"218 },219 {220 "inputs": [],221 "name": "hasCollectionPendingSponsor",222 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],223 "stateMutability": "view",224 "type": "function"225 },202 {226 {203 "inputs": [227 "inputs": [204 { "internalType": "address", "name": "owner", "type": "address" },228 { "internalType": "address", "name": "owner", "type": "address" },209 "stateMutability": "view",233 "stateMutability": "view",210 "type": "function"234 "type": "function"211 },235 },236 {237 "inputs": [238 { "internalType": "address", "name": "user", "type": "address" }239 ],240 "name": "isOwnerOrAdmin",241 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],242 "stateMutability": "view",243 "type": "function"244 },245 {246 "inputs": [247 { "internalType": "uint256", "name": "user", "type": "uint256" }248 ],249 "name": "isOwnerOrAdminSubstrate",250 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],251 "stateMutability": "view",252 "type": "function"253 },212 {254 {213 "inputs": [255 "inputs": [214 { "internalType": "address", "name": "to", "type": "address" },256 { "internalType": "address", "name": "to", "type": "address" },237 { "internalType": "uint256", "name": "field_0", "type": "uint256" },279 { "internalType": "uint256", "name": "field_0", "type": "uint256" },238 { "internalType": "string", "name": "field_1", "type": "string" }280 { "internalType": "string", "name": "field_1", "type": "string" }239 ],281 ],240 "internalType": "struct Tuple0[]",282 "internalType": "struct Tuple8[]",241 "name": "tokens",283 "name": "tokens",242 "type": "tuple[]"284 "type": "tuple[]"243 }285 }316 "stateMutability": "nonpayable",358 "stateMutability": "nonpayable",317 "type": "function"359 "type": "function"318 },360 },361 {362 "inputs": [],363 "name": "removeCollectionSponsor",364 "outputs": [],365 "stateMutability": "nonpayable",366 "type": "function"367 },319 {368 {320 "inputs": [369 "inputs": [321 { "internalType": "address", "name": "user", "type": "address" }370 { "internalType": "address", "name": "user", "type": "address" }343 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },392 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },344 { "internalType": "bytes", "name": "data", "type": "bytes" }393 { "internalType": "bytes", "name": "data", "type": "bytes" }345 ],394 ],346 "name": "safeTransferFromWithData",395 "name": "safeTransferFrom",347 "outputs": [],396 "outputs": [],348 "stateMutability": "nonpayable",397 "stateMutability": "nonpayable",349 "type": "function"398 "type": "function"432 "stateMutability": "nonpayable",481 "stateMutability": "nonpayable",433 "type": "function"482 "type": "function"434 },483 },484 {485 "inputs": [486 { "internalType": "uint256", "name": "sponsor", "type": "uint256" }487 ],488 "name": "setCollectionSponsorSubstrate",489 "outputs": [],490 "stateMutability": "nonpayable",491 "type": "function"492 },493 {494 "inputs": [495 { "internalType": "address", "name": "newOwner", "type": "address" }496 ],497 "name": "setOwner",498 "outputs": [],499 "stateMutability": "nonpayable",500 "type": "function"501 },502 {503 "inputs": [504 { "internalType": "uint256", "name": "newOwner", "type": "uint256" }505 ],506 "name": "setOwnerSubstrate",507 "outputs": [],508 "stateMutability": "nonpayable",509 "type": "function"510 },435 {511 {436 "inputs": [512 "inputs": [437 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },513 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },533 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],609 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],534 "stateMutability": "nonpayable",610 "stateMutability": "nonpayable",535 "type": "function"611 "type": "function"536 },612 }537 {538 "inputs": [539 { "internalType": "address", "name": "user", "type": "address" }540 ],541 "name": "verifyOwnerOrAdmin",542 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],543 "stateMutability": "view",544 "type": "function"545 }546]613]547614tests/src/eth/reFungibleAbi.jsondiffbeforeafterboth199 "stateMutability": "view",199 "stateMutability": "view",200 "type": "function"200 "type": "function"201 },201 },202 {203 "inputs": [],204 "name": "getCollectionSponsor",205 "outputs": [206 {207 "components": [208 { "internalType": "address", "name": "field_0", "type": "address" },209 { "internalType": "uint256", "name": "field_1", "type": "uint256" }210 ],211 "internalType": "struct Tuple17",212 "name": "",213 "type": "tuple"214 }215 ],216 "stateMutability": "view",217 "type": "function"218 },219 {220 "inputs": [],221 "name": "hasCollectionPendingSponsor",222 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],223 "stateMutability": "view",224 "type": "function"225 },202 {226 {203 "inputs": [227 "inputs": [204 { "internalType": "address", "name": "owner", "type": "address" },228 { "internalType": "address", "name": "owner", "type": "address" },209 "stateMutability": "view",233 "stateMutability": "view",210 "type": "function"234 "type": "function"211 },235 },236 {237 "inputs": [238 { "internalType": "address", "name": "user", "type": "address" }239 ],240 "name": "isOwnerOrAdmin",241 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],242 "stateMutability": "view",243 "type": "function"244 },245 {246 "inputs": [247 { "internalType": "uint256", "name": "user", "type": "uint256" }248 ],249 "name": "isOwnerOrAdminSubstrate",250 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],251 "stateMutability": "view",252 "type": "function"253 },212 {254 {213 "inputs": [255 "inputs": [214 { "internalType": "address", "name": "to", "type": "address" },256 { "internalType": "address", "name": "to", "type": "address" },237 { "internalType": "uint256", "name": "field_0", "type": "uint256" },279 { "internalType": "uint256", "name": "field_0", "type": "uint256" },238 { "internalType": "string", "name": "field_1", "type": "string" }280 { "internalType": "string", "name": "field_1", "type": "string" }239 ],281 ],240 "internalType": "struct Tuple0[]",282 "internalType": "struct Tuple8[]",241 "name": "tokens",283 "name": "tokens",242 "type": "tuple[]"284 "type": "tuple[]"243 }285 }316 "stateMutability": "nonpayable",358 "stateMutability": "nonpayable",317 "type": "function"359 "type": "function"318 },360 },361 {362 "inputs": [],363 "name": "removeCollectionSponsor",364 "outputs": [],365 "stateMutability": "nonpayable",366 "type": "function"367 },319 {368 {320 "inputs": [369 "inputs": [321 { "internalType": "address", "name": "user", "type": "address" }370 { "internalType": "address", "name": "user", "type": "address" }432 "stateMutability": "nonpayable",481 "stateMutability": "nonpayable",433 "type": "function"482 "type": "function"434 },483 },484 {485 "inputs": [486 { "internalType": "uint256", "name": "sponsor", "type": "uint256" }487 ],488 "name": "setCollectionSponsorSubstrate",489 "outputs": [],490 "stateMutability": "nonpayable",491 "type": "function"492 },493 {494 "inputs": [495 { "internalType": "address", "name": "newOwner", "type": "address" }496 ],497 "name": "setOwner",498 "outputs": [],499 "stateMutability": "nonpayable",500 "type": "function"501 },502 {503 "inputs": [504 { "internalType": "uint256", "name": "newOwner", "type": "uint256" }505 ],506 "name": "setOwnerSubstrate",507 "outputs": [],508 "stateMutability": "nonpayable",509 "type": "function"510 },435 {511 {436 "inputs": [512 "inputs": [437 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },513 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },542 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],618 "outputs": [{ "internalType": "string", "name": "", "type": "string" }],543 "stateMutability": "nonpayable",619 "stateMutability": "nonpayable",544 "type": "function"620 "type": "function"545 },621 }546 {547 "inputs": [548 { "internalType": "address", "name": "user", "type": "address" }549 ],550 "name": "verifyOwnerOrAdmin",551 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],552 "stateMutability": "view",553 "type": "function"554 }555]622]556623tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth655 await requirePallets(this, [Pallets.ReFungible]);655 await requirePallets(this, [Pallets.ReFungible]);656 });656 });657658 itWeb3('Parent NFT token address and id', async ({api, web3, privateKeyWrapper}) => {659 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);660661 const {collectionIdAddress: nftCollectionAddress} = await createNonfungibleCollection(api, web3, owner);662 const nftContract = uniqueNFT(web3, nftCollectionAddress, owner);663 const nftTokenId = await nftContract.methods.nextTokenId().call();664 await nftContract.methods.mint(owner, nftTokenId).send();665 const nftCollectionId = collectionIdFromAddress(nftCollectionAddress);666667 const {collectionIdAddress, collectionId} = await createRefungibleCollection(api, web3, owner);668 const refungibleContract = uniqueRefungible(web3, collectionIdAddress, owner);669 const refungibleTokenId = await refungibleContract.methods.nextTokenId().call();670 await refungibleContract.methods.mint(owner, refungibleTokenId).send();671672 const rftTokenAddress = tokenIdToAddress(collectionId, refungibleTokenId);673 const refungibleTokenContract = uniqueRefungibleToken(web3, rftTokenAddress, owner);674 await refungibleTokenContract.methods.setParentNFT(nftCollectionAddress, nftTokenId).send();675676 const tokenAddress = await refungibleTokenContract.methods.parentToken().call();677 const tokenId = await refungibleTokenContract.methods.parentTokenId().call();678 const nftTokenAddress = tokenIdToAddress(nftCollectionId, nftTokenId);679 expect(tokenAddress).to.be.equal(nftTokenAddress);680 expect(tokenId).to.be.equal(nftTokenId);681 });682657683 itWeb3('Default parent token address and id', async ({api, web3, privateKeyWrapper}) => {658 itWeb3('Default parent token address and id', async ({api, web3, privateKeyWrapper}) => {684 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);659 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);693668694 const tokenAddress = await refungibleTokenContract.methods.parentToken().call();669 const tokenAddress = await refungibleTokenContract.methods.parentToken().call();695 const tokenId = await refungibleTokenContract.methods.parentTokenId().call();670 const tokenId = await refungibleTokenContract.methods.parentTokenId().call();696 expect(tokenAddress).to.be.equal(rftTokenAddress);671 expect(tokenAddress).to.be.equal(collectionIdAddress);697 expect(tokenId).to.be.equal(refungibleTokenId);672 expect(tokenId).to.be.equal(refungibleTokenId);698 });673 });699});674});tests/src/eth/reFungibleTokenAbi.jsondiffbeforeafterboth125 "stateMutability": "nonpayable",125 "stateMutability": "nonpayable",126 "type": "function"126 "type": "function"127 },127 },128 {129 "inputs": [130 { "internalType": "address", "name": "collection", "type": "address" },131 { "internalType": "uint256", "name": "nftId", "type": "uint256" }132 ],133 "name": "setParentNFT",134 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],135 "stateMutability": "nonpayable",136 "type": "function"137 },138 {128 {139 "inputs": [129 "inputs": [140 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }130 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }tests/src/eth/refungibleAbi.jsondiffbeforeafterbothno changes
tests/src/eth/sponsoring.test.tsdiffbeforeafterboth15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {expect} from 'chai';17import {expect} from 'chai';18import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, SponsoringMode, transferBalanceToEth} from './util/helpers';18import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, SponsoringMode} from './util/helpers';191920describe('EVM sponsoring', () => {20describe('EVM sponsoring', () => {21 itWeb3('Fee is deducted from contract if sponsoring is enabled', async ({api, web3, privateKeyWrapper}) => {21 itWeb3('Fee is deducted from contract if sponsoring is enabled', async ({api, web3, privateKeyWrapper}) => {22 const alice = privateKeyWrapper('//Alice');22 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);2324 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);23 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);25 const caller = createEthAccount(web3);24 const caller = createEthAccount(web3);26 const originalCallerBalance = await web3.eth.getBalance(caller);25 const originalCallerBalance = await web3.eth.getBalance(caller);27 expect(originalCallerBalance).to.be.equal('0');26 expect(originalCallerBalance).to.be.equal('0');32 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});31 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});33 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});32 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});33 34 await helpers.methods.setSponsor(flipper.options.address, sponsor).send({from: owner});35 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});343635 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;37 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;36 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});38 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});37 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});39 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});38 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;40 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;3940 await transferBalanceToEth(api, alice, flipper.options.address);414142 const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);42 const originalSponsorBalance = await web3.eth.getBalance(sponsor);43 expect(originalFlipperBalance).to.be.not.equal('0');43 expect(originalSponsorBalance).to.be.not.equal('0');444445 await flipper.methods.flip().send({from: caller});45 await flipper.methods.flip().send({from: caller});46 expect(await flipper.methods.getValue().call()).to.be.true;46 expect(await flipper.methods.getValue().call()).to.be.true;474748 // Balance should be taken from flipper instead of caller48 // Balance should be taken from flipper instead of caller49 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);49 expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);50 expect(await web3.eth.getBalance(flipper.options.address)).to.be.not.equals(originalFlipperBalance);50 expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance);51 });51 });5252 itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => {53 itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => {53 const alice = privateKeyWrapper('//Alice');54 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);5455 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);55 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);56 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);56 const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);57 const originalCallerBalance = await web3.eth.getBalance(caller);57 const originalCallerBalance = await web3.eth.getBalance(caller);58 expect(originalCallerBalance).to.be.not.equal('0');58 expect(originalCallerBalance).to.be.not.equal('0');68 await helpers.methods.setSponsoringRateLimit(collector.options.address, 0).send({from: owner});68 await helpers.methods.setSponsoringRateLimit(collector.options.address, 0).send({from: owner});69 expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.true;69 expect(await helpers.methods.sponsoringEnabled(collector.options.address).call()).to.be.true;707071 await transferBalanceToEth(api, alice, collector.options.address);71 await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});7273 const originalCollectorBalance = await web3.eth.getBalance(collector.options.address);72 await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});7374 const originalSponsorBalance = await web3.eth.getBalance(sponsor);74 expect(originalCollectorBalance).to.be.not.equal('0');75 expect(originalSponsorBalance).to.be.not.equal('0');757676 await collector.methods.giveMoney().send({from: caller, value: '10000'});77 await collector.methods.giveMoney().send({from: caller, value: '10000'});777878 // Balance will be taken from both caller (value) and from collector (fee)79 // Balance will be taken from both caller (value) and from collector (fee)79 expect(await web3.eth.getBalance(caller)).to.be.equals((BigInt(originalCallerBalance) - 10000n).toString());80 expect(await web3.eth.getBalance(caller)).to.be.equals((BigInt(originalCallerBalance) - 10000n).toString());80 expect(await web3.eth.getBalance(collector.options.address)).to.be.not.equals(originalCollectorBalance);81 expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance);81 expect(await collector.methods.getCollected().call()).to.be.equal('10000');82 expect(await collector.methods.getCollected().call()).to.be.equal('10000');82 });83 });83});84});tests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth26 "stateMutability": "view",26 "stateMutability": "view",27 "type": "function"27 "type": "function"28 },28 },29 {30 "inputs": [31 {32 "internalType": "address",33 "name": "contractAddress",34 "type": "address"35 }36 ],37 "name": "confirmSponsorship",38 "outputs": [],39 "stateMutability": "nonpayable",40 "type": "function"41 },29 {42 {30 "inputs": [43 "inputs": [31 {44 {39 "stateMutability": "view",52 "stateMutability": "view",40 "type": "function"53 "type": "function"41 },54 },55 {56 "inputs": [57 {58 "internalType": "address",59 "name": "contractAddress",60 "type": "address"61 }62 ],63 "name": "getSponsor",64 "outputs": [65 {66 "components": [67 { "internalType": "address", "name": "field_0", "type": "address" },68 { "internalType": "uint256", "name": "field_1", "type": "uint256" }69 ],70 "internalType": "struct Tuple0",71 "name": "",72 "type": "tuple"73 }74 ],75 "stateMutability": "view",76 "type": "function"77 },42 {78 {43 "inputs": [79 "inputs": [44 {80 {52 "stateMutability": "view",88 "stateMutability": "view",53 "type": "function"89 "type": "function"54 },90 },91 {92 "inputs": [93 {94 "internalType": "address",95 "name": "contractAddress",96 "type": "address"97 }98 ],99 "name": "hasPendingSponsor",100 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],101 "stateMutability": "view",102 "type": "function"103 },104 {105 "inputs": [106 {107 "internalType": "address",108 "name": "contractAddress",109 "type": "address"110 }111 ],112 "name": "hasSponsor",113 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],114 "stateMutability": "view",115 "type": "function"116 },117 {118 "inputs": [119 {120 "internalType": "address",121 "name": "contractAddress",122 "type": "address"123 }124 ],125 "name": "removeSponsor",126 "outputs": [],127 "stateMutability": "nonpayable",128 "type": "function"129 },130 {131 "inputs": [132 {133 "internalType": "address",134 "name": "contractAddress",135 "type": "address"136 }137 ],138 "name": "selfSponsoredEnable",139 "outputs": [],140 "stateMutability": "nonpayable",141 "type": "function"142 },143 {144 "inputs": [145 {146 "internalType": "address",147 "name": "contractAddress",148 "type": "address"149 },150 { "internalType": "address", "name": "sponsor", "type": "address" }151 ],152 "name": "setSponsor",153 "outputs": [],154 "stateMutability": "nonpayable",155 "type": "function"156 },55 {157 {56 "inputs": [158 "inputs": [57 {159 {93 "stateMutability": "view",195 "stateMutability": "view",94 "type": "function"196 "type": "function"95 },197 },96 {97 "inputs": [98 {99 "internalType": "address",100 "name": "contractAddress",101 "type": "address"102 }103 ],104 "name": "sponsoringMode",105 "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],106 "stateMutability": "view",107 "type": "function"108 },109 {198 {110 "inputs": [199 "inputs": [111 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }200 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }123 "type": "address"212 "type": "address"124 },213 },125 { "internalType": "address", "name": "user", "type": "address" },214 { "internalType": "address", "name": "user", "type": "address" },126 { "internalType": "bool", "name": "allowed", "type": "bool" }215 { "internalType": "bool", "name": "isAllowed", "type": "bool" }127 ],216 ],128 "name": "toggleAllowed",217 "name": "toggleAllowed",129 "outputs": [],218 "outputs": [],143 "outputs": [],232 "outputs": [],144 "stateMutability": "nonpayable",233 "stateMutability": "nonpayable",145 "type": "function"234 "type": "function"146 },235 }147 {148 "inputs": [149 {150 "internalType": "address",151 "name": "contractAddress",152 "type": "address"153 },154 { "internalType": "bool", "name": "enabled", "type": "bool" }155 ],156 "name": "toggleSponsoring",157 "outputs": [],158 "stateMutability": "nonpayable",159 "type": "function"160 }161]236]162237tests/src/util/helpers.tsdiffbeforeafterboth99 }99 }100}100}101102export function bigIntToSub(api: ApiPromise, number: bigint) {103 return api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();104}101105102export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {106export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {103 if (typeof input === 'string') {107 if (typeof input === 'string') {tests/src/util/playgrounds/index.tsdiffbeforeafterboth2// SPDX-License-Identifier: Apache-2.02// SPDX-License-Identifier: Apache-2.0334import {IKeyringPair} from '@polkadot/types/types';4import {IKeyringPair} from '@polkadot/types/types';5import {UniqueHelper} from './unique';6import config from '../../config';5import config from '../../config';7import '../../interfaces/augment-api-events';6import '../../interfaces/augment-api-events';8import * as defs from '../../interfaces/definitions';9import {ApiPromise, WsProvider} from '@polkadot/api';7import {DevUniqueHelper} from './unique.dev';1011812class SilentLogger {9class SilentLogger {19}16}202122class DevUniqueHelper extends UniqueHelper {23 async connect(wsEndpoint: string, listeners?: any): Promise<void> {24 const wsProvider = new WsProvider(wsEndpoint);25 this.api = new ApiPromise({26 provider: wsProvider, 27 signedExtensions: {28 ContractHelpers: {29 extrinsic: {},30 payload: {},31 },32 FakeTransactionFinalizer: {33 extrinsic: {},34 payload: {},35 },36 },37 rpc: {38 unique: defs.unique.rpc,39 rmrk: defs.rmrk.rpc,40 eth: {41 feeHistory: {42 description: 'Dummy',43 params: [],44 type: 'u8',45 },46 maxPriorityFeePerGas: {47 description: 'Dummy',48 params: [],49 type: 'u8',50 },51 },52 },53 });54 await this.api.isReadyOrError;55 this.network = await UniqueHelper.detectNetwork(this.api);56 }57}581759export const usingPlaygrounds = async (code: (helper: UniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise<void>) => {18export const usingPlaygrounds = async (code: (helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise<void>) => {60 // TODO: Remove, this is temporary: Filter unneeded API output19 // TODO: Remove, this is temporary: Filter unneeded API output61 // (Jaco promised it will be removed in the next version)20 // (Jaco promised it will be removed in the next version)62 const consoleErr = console.error;21 const consoleErr = console.error;tests/src/util/playgrounds/types.tsdiffbeforeafterbothno changes
tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterbothno changes
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth778import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';8import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import {ApiInterfaceEvents} from '@polkadot/api/types';9import {ApiInterfaceEvents} from '@polkadot/api/types';10import {IKeyringPair} from '@polkadot/types/types';11import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';1211import {IKeyringPair} from '@polkadot/types/types';12import {IApiListeners, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';131314const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {14const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {15 const address = {} as ICrossAccountId;15 const address = {} as ICrossAccountId;45};45};464748interface IChainEvent {49 data: any;50 method: string;51 section: string;52}5354interface ITransactionResult {55 status: 'Fail' | 'Success';56 result: {57 events: {58 event: IChainEvent59 }[];60 },61 moduleError?: string;62}6364interface ILogger {65 log: (msg: any, level?: string) => void;66 level: {67 ERROR: 'ERROR';68 WARNING: 'WARNING';69 INFO: 'INFO';70 [key: string]: string;71 }72}7374interface IUniqueHelperLog {75 executedAt: number;76 executionTime: number;77 type: 'extrinsic' | 'rpc';78 status: 'Fail' | 'Success';79 call: string;80 params: any[];81 moduleError?: string;82 events?: any;83}8485interface IApiListeners {86 connected?: (...args: any[]) => any;87 disconnected?: (...args: any[]) => any;88 error?: (...args: any[]) => any;89 ready?: (...args: any[]) => any; 90 decorated?: (...args: any[]) => any;91}9293interface ICrossAccountId {94 Substrate?: TSubstrateAccount;95 Ethereum?: TEthereumAccount;96}9798interface ICrossAccountIdLower {99 substrate?: TSubstrateAccount;100 ethereum?: TEthereumAccount;101}102103interface ICollectionLimits {104 accountTokenOwnershipLimit?: number | null;105 sponsoredDataSize?: number | null;106 sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;107 tokenLimit?: number | null;108 sponsorTransferTimeout?: number | null;109 sponsorApproveTimeout?: number | null;110 ownerCanTransfer?: boolean | null;111 ownerCanDestroy?: boolean | null;112 transfersEnabled?: boolean | null;113}114115interface INestingPermissions {116 tokenOwner?: boolean;117 collectionAdmin?: boolean;118 restricted?: number[] | null;119}120121interface ICollectionPermissions {122 access?: 'Normal' | 'AllowList';123 mintMode?: boolean;124 nesting?: INestingPermissions;125}126127interface IProperty {128 key: string;129 value: string;130}131132interface ITokenPropertyPermission {133 key: string;134 permission: {135 mutable: boolean;136 tokenOwner: boolean;137 collectionAdmin: boolean;138 }139}140141interface IToken {142 collectionId: number;143 tokenId: number;144}145146interface ICollectionCreationOptions {147 name: string | number[];148 description: string | number[];149 tokenPrefix: string | number[];150 mode?: {151 nft?: null;152 refungible?: null;153 fungible?: number;154 }155 permissions?: ICollectionPermissions;156 properties?: IProperty[];157 tokenPropertyPermissions?: ITokenPropertyPermission[];158 limits?: ICollectionLimits;159 pendingSponsor?: TSubstrateAccount;160}161162interface IChainProperties {163 ss58Format: number;164 tokenDecimals: number[];165 tokenSymbol: string[]166}167168type TSubstrateAccount = string;169type TEthereumAccount = string;170type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';171type TUniqueNetworks = 'opal' | 'quartz' | 'unique';172type TSigner = IKeyringPair; // | 'string'17346174class UniqueUtil {47class UniqueUtil {175 static transactionStatus = {48 static transactionStatus = {439 return this.transactionStatus.FAIL;312 return this.transactionStatus.FAIL;440 }313 }441314442 signTransaction(sender: TSigner, transaction: any, label = 'transaction', options = null) {315 signTransaction(sender: TSigner, transaction: any, label = 'transaction', options: any = null) {443 const sign = (callback: any) => {316 const sign = (callback: any) => {444 if(options !== null) return transaction.signAndSend(sender, options, callback);317 if(options !== null) return transaction.signAndSend(sender, options, callback);445 return transaction.signAndSend(sender, callback);318 return transaction.signAndSend(sender, callback);651 return normalized;524 return normalized;652 }525 }526527 /**528 * Get the normalized addresses added to the collection allow-list.529 * @param collectionId ID of collection530 * @example await getAllowList(1)531 * @returns array of allow-listed addresses532 */533 async getAllowList(collectionId: number): Promise<ICrossAccountId[]> {534 const normalized = [];535 const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();536 for (const address of allowListed) {537 if (address.Substrate) normalized.push({Substrate: this.helper.address.normalizeSubstrate(address.Substrate)});538 else normalized.push(address);539 }540 return normalized;541 }653542654 /**543 /**655 * Get the effective limits of the collection instead of null for default values544 * Get the effective limits of the collection instead of null for default values794 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded', label);683 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded', label);795 }684 }685686 /**687 * Adds an address to allow list 688 * @param signer keyring of signer689 * @param collectionId ID of collection690 * @param addressObj address to add to the allow list691 * @param label extra label for log692 * @returns ```true``` if extrinsic success, otherwise ```false```693 */694 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId, label?: string): Promise<boolean> {695 if(typeof label === 'undefined') label = `collection #${collectionId}`;696 const result = await this.helper.executeExtrinsic(697 signer,698 'api.tx.unique.addToAllowList', [collectionId, addressObj],699 true, `Unable to add address to allow list for ${label}`,700 );701702 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');703 }796704797 /**705 /**798 * Removes a collection administrator.706 * Removes a collection administrator.2119 return await this.helper.collection.getAdmins(this.collectionId);2027 return await this.helper.collection.getAdmins(this.collectionId);2120 }2028 }20292030 async getAllowList() {2031 return await this.helper.collection.getAllowList(this.collectionId);2032 }212120332122 async getEffectiveLimits() {2034 async getEffectiveLimits() {2123 return await this.helper.collection.getEffectiveLimits(this.collectionId);2035 return await this.helper.collection.getEffectiveLimits(this.collectionId);2143 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj, label);2055 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj, label);2144 }2056 }20572058 async addToAllowList(signer: TSigner, addressObj: ICrossAccountId, label?: string) {2059 return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj, label);2060 }214520612146 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) {2062 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) {2147 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj, label);2063 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj, label);