git.delta.rocks / unique-network / refs/commits / a238bf32070a

difftreelog

Merge branch 'develop' into feature/multi-assets-redone

Daniel Shiposha2022-08-30parents: #8afee35 #bb78c7a.patch.diff
in: master

108 files changed

modified.docker/Dockerfile-chain-dev-unitdiffbeforeafterboth
2323
24WORKDIR /dev_chain24WORKDIR /dev_chain
2525
26RUN cargo test --features=limit-testing26CMD cargo test --features=limit-testing
2727
added.docker/Dockerfile-parachain-node-onlydiffbeforeafterboth

no changes

added.docker/docker-compose.tmp-node.j2diffbeforeafterboth

no changes

modified.docker/forkless-config/launch-config-forkless-data.j2diffbeforeafterboth
86 },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",
modified.docker/forkless-config/launch-config-forkless-nodata.j2diffbeforeafterboth
101 "--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 ]
deleted.github/workflows/build-test-master.ymldiffbeforeafterboth

no changes

modified.github/workflows/codestyle.ymldiffbeforeafterboth
49 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 state
51 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."
5353
5454
55 clippy:55 clippy:
modified.github/workflows/dev-build-tests.ymldiffbeforeafterboth
125 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" down
126
127
128 dev_build_unit_test:
129 # The type of runner that the job will run on
130 runs-on: [self-hosted-ci,medium]
131 timeout-minutes: 1380
132
133 name: unit tests
134
135
136 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.
137
138
139 steps:
140 - name: Skip if pull request is in Draft
141 # `if: github.event.pull_request.draft == true` should be kept here, at
142 # the step level, rather than at the job level. The latter is not
143 # recommended because when the PR is moved from "Draft" to "Ready to
144 # 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 for
146 # the workflow to start. This is also disclosed in:
147 # https://github.community/t/dont-run-actions-on-draft-pull-requests/16817/17
148 # That scenario would open an opportunity for the check to be bypassed:
149 # 1. Get your PR approved
150 # 2. Move it to Draft
151 # 3. Push whatever commits you want
152 # 4. Move it to "Ready for review"; now the workflow is passing (it was
153 # skipped) and "Check reviews" is also passing (it won't be updated
154 # until the workflow is finished)
155 if: github.event.pull_request.draft == true
156 run: exit 1
157
158 - name: Clean Workspace
159 uses: AutoModality/action-clean@v1.1.0
160
161 # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
162 - uses: actions/checkout@v3
163 with:
164 ref: ${{ github.head_ref }} #Checking out head commit
165
166 - name: Read .env file
167 uses: xom9ikk/dotenv@v1.0.2
168
169 - name: Generate ENV related extend file for docker-compose
170 uses: cuchi/jinja2-action@v1.2.0
171 with:
172 template: .docker/docker-compose.tmp-unit.j2
173 output_file: .docker/docker-compose.unit.yml
174 variables: |
175 RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}
176 FEATURE=${{ matrix.features }}
177
178
179 - name: Show build configuration
180 run: cat .docker/docker-compose.unit.yml
181
182 - name: Build the stack
183 run: docker-compose -f ".docker/docker-compose-dev.yaml" -f ".docker/docker-compose.unit.yml" up -d --build --remove-orphans
184
185
186 - name: Stop running containers
187 if: always() # run this step always
188 run: docker-compose -f ".docker/docker-compose-dev.yaml" -f ".docker/docker-compose.unit.yml" down
189126
added.github/workflows/nodes-only-update.ymldiffbeforeafterboth

no changes

added.github/workflows/unit-test.ymldiffbeforeafterboth

no changes

modified.maintain/frame-weight-template.hbsdiffbeforeafterboth
14#![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)]
1819
19use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};20use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
modifiedCargo.lockdiffbeforeafterboth
1771 "zeroize",1771 "zeroize",
1772]1772]
1773
1774[[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]
1783
1784[[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]
1797
1798[[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]
18081773
1809[[package]]1774[[package]]
1810name = "data-encoding"1775name = "data-encoding"
22042169
2205[[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]
22172183
2218[[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]
22302195
2345[[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]
3430
3431[[package]]
3432name = "ident_case"
3433version = "1.0.1"
3434source = "registry+https://github.com/rust-lang/crates.io-index"
3435checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
34363395
3437[[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",
56385597
5639[[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",
58195778
5820[[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",
59035862
5904[[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",
61456104
6146[[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",
62676226
6268[[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",
deletedcrates/evm-coder-macros/Cargo.tomldiffbeforeafterboth

no changes

deletedcrates/evm-coder-macros/src/lib.rsdiffbeforeafterboth

no changes

deletedcrates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth

no changes

deletedcrates/evm-coder-macros/src/to_log.rsdiffbeforeafterboth

no changes

modifiedcrates/evm-coder/CHANGELOG.mddiffbeforeafterboth
1# Change Log
2
3All notable changes to this project will be documented in this file.
4
5## [0.1.3] - 2022-08-29
6
7### Fixed
8
9 - Parsing simple values.
10
1<!-- bureaucrate goes here -->11<!-- bureaucrate goes here -->
12## [v0.1.2] 2022-08-19
13
14### Added
15
16 - Implementation `AbiWrite` for tuples.
17
18 ### Fixes
19
20 - Tuple generation for solidity.
21
2## [v0.1.1] 2022-08-1622## [v0.1.1] 2022-08-16
323
4### Other changes24### Other changes
727
8- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf828- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8
929
10- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b30- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b
31
modifiedcrates/evm-coder/Cargo.tomldiffbeforeafterboth
1[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"
66
7[dependencies]7[dependencies]
8# evm-coder reexports those proc-macro
8evm-coder-macros = { path = "../evm-coder-macros" }9evm-coder-procedural = { path = "./procedural" }
10# Evm uses primitive-types for H160, H256 and others
9primitive-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 others
11ethereum = { 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 execution
12evm-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.rs
13impl-trait-for-tuples = "0.2.1"18impl-trait-for-tuples = "0.2.2"
1419
15[dev-dependencies]20[dev-dependencies]
21# We want to assert some large binary blobs equality in tests
16hex = "0.4.3"22hex = "0.4.3"
23hex-literal = "0.3.4"
1724
18[features]25[features]
19default = ["std"]26default = ["std"]
addedcrates/evm-coder/README.mddiffbeforeafterboth

no changes

addedcrates/evm-coder/procedural/Cargo.tomldiffbeforeafterboth

no changes

addedcrates/evm-coder/procedural/src/lib.rsdiffbeforeafterboth

no changes

addedcrates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth

no changes

addedcrates/evm-coder/procedural/src/to_log.rsdiffbeforeafterboth

no changes

modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17//! TODO: I misunterstood therminology, abi IS rlp encoded, so17//! Implementation of EVM RLP reader/writer
18//! this module should be replaced with rlp crate
1918
20#![allow(dead_code)]19#![allow(dead_code)]
2120
3231
33const ABI_ALIGNMENT: usize = 32;32const ABI_ALIGNMENT: usize = 32;
3433
34trait TypeHelper {
35 fn is_dynamic() -> bool;
36}
37
38/// View into RLP data, which provides method to read typed items from it
35#[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 bytes
42 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 selector
49 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 empty
79 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 }
111117
118 /// Read [`H160`] at current position, then advance
112 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 }
115122
123 /// Read [`bool`] at current position, then advance
116 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 }
124132
133 /// Read [`[u8; 4]`] at current position, then advance
125 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 }
128137
138 /// Read [`Vec<u8>`] at current position, then advance
129 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 }
147
148 /// Read [`string`] at current position, then advance
137 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 }
140152
153 /// Read [`u8`] at current position, then advance
141 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 }
144157
158 /// Read [`u32`] at current position, then advance
145 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 }
148162
163 /// Read [`u128`] at current position, then advance
149 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 }
152167
168 /// Read [`U256`] at current position, then advance
153 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 }
157173
174 /// Read [`u64`] at current position, then advance
158 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 }
161178
179 /// Read [`usize`] at current position, then advance
180 #[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 }
165184
185 /// Slice recursive buffer, advance one word for buffer offset
186 /// 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 0
193 } else {
194 self.uint32()? as usize
195 };
196
168 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 }
200
201 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 }
177208
209 /// 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.offset
180 }212 }
181}213}
182214
215/// Writer for RLP encoded data
183#[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 required
190 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 beginning
193 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 }
213248
249 /// Write [`H160`] to end of buffer
214 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 }
217253
254 /// Write [`bool`] to end of buffer
218 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 }
221258
259 /// Write [`u8`] to end of buffer
222 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 }
225263
264 /// Write [`u32`] to end of buffer
226 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 }
229268
269 /// Write [`u128`] to end of buffer
230 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 }
233273
274 /// Write [`U256`] to end of buffer
234 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 }
239280
281 /// Write [`usize`] to end of buffer
282 #[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 }
243286
287 /// Append recursive data, writing pending offset at end of buffer
244 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 later
247 self.write_padleft(&[]);291 self.write_padleft(&[]);
248 }292 }
249293
250 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 }
258302
303 /// Append recursive [`str`] at end of buffer
259 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 }
262307
308 /// Append recursive [`[u8]`] at end of buffer
263 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 }
266312
313 /// Finish writer, concatenating all internal buffers
267 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}
280327
328/// [`AbiReader`] implements reading of many types, but it should
329/// be limited to types defined in spec
330///
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 decoder
282 fn abi_read(&mut self) -> Result<T>;335 fn abi_read(&mut self) -> Result<T>;
336
337 /// Size for type aligned to [`ABI_ALIGNMENT`].
338 fn size() -> usize;
283}339}
284340
285macro_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 $dynamic
346 }
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 }
352
353 fn size() -> usize {
354 ABI_ALIGNMENT
355 }
291 }356 }
292 };357 };
293}358}
294359
295impl_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);
305370
306mod 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 instead
317 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 }
394
395 fn size() -> usize {
396 ABI_ALIGNMENT
397 }
329}398}
330399
331macro_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 false
405 $(
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 where
336 $(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 }
425
426 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 where
433 $($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}
347442
356impl_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}
358453
454/// For questions about inability to provide custom implementations,
455/// see [`AbiRead`]
359pub trait AbiWrite {456pub trait AbiWrite {
457 /// Write value to end of specified encoder
360 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}
367467
468/// This particular AbiWrite implementation should be split to another trait,
469/// which only implements `to_result`, but due to lack of specialization feature
470/// 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 it
368impl<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 have
373 // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing
374 // default trait methods for it
375 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}
424522
523/// Helper macros to parse reader into variables
524#[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}
533
534/// Helper macros to construct RLP-encoded buffer
535#[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);
480583
481 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 }
485588
549 );652 );
550 }653 }
654
655 #[test]
656 fn parse_vec_with_simple_type() {
657 use crate::types::address;
658 use primitive_types::{H160, U256};
659
660 let (call, mut decoder) = AbiReader::new_call(&hex!(
661 "
662 1ACF2D55
663 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]
664 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]
665
666 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address
667 000000000000000000000000000000000000000000000000000000000000000A // uint256
668
669 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address
670 0000000000000000000000000000000000000000000000000000000000000014 // uint256
671
672 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address
673 000000000000000000000000000000000000000000000000000000000000001E // uint256
674 "
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}
552700
modifiedcrates/evm-coder/src/events.rsdiffbeforeafterboth
1919
20use crate::types::*;20use crate::types::*;
2121
22/// 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 contract
29 /// address, it should be specified manually.
23 fn to_log(&self, contract: H160) -> Log;30 fn to_log(&self, contract: H160) -> Log;
24}31}
2532
33/// Only items implementing `ToTopic` may be used as `#[indexed]` field
34/// 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}
2941
modifiedcrates/evm-coder/src/execution.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
16
17//! Contract execution related types
1618
17#[cfg(not(feature = "std"))]19#[cfg(not(feature = "std"))]
18use alloc::string::{String, ToString};20use alloc::string::{String, ToString};
2224
23use crate::Weight;25use crate::Weight;
2426
27/// 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 occured
27 Revert(String),31 Revert(String),
32 /// EVM fatal error
28 Fatal(ExitFatal),33 Fatal(ExitFatal),
34 /// EVM normal error
29 Error(ExitError),35 Error(ExitError),
30}36}
3137
38 }44 }
39}45}
4046
47/// 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>;
4249
50/// Static information collected from [`crate::weight`].
43pub struct DispatchInfo {51pub struct DispatchInfo {
52 /// Statically predicted call weight
44 pub weight: Weight,53 pub weight: Weight,
45}54}
4655
55 }64 }
56}65}
5766
67/// 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 call
60 actual_weight: Option<Weight>,72 actual_weight: Option<Weight>,
61}73}
6274
63impl PostDispatchInfo {75impl PostDispatchInfo {
76 /// Calculate amount to be returned back to user
64 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 }
6780
81 /// Calculate actual consumed weight, saturating to weight reported
82 /// pre-dispatch
68 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}
7691
92/// Wrapper for PostDispatchInfo and any user-provided data
77#[derive(Clone)]93#[derive(Clone)]
78pub struct WithPostDispatchInfo<T> {94pub struct WithPostDispatchInfo<T> {
95 /// User provided data
79 pub data: T,96 pub data: T,
97 /// Info known after dispatch
80 pub post_info: PostDispatchInfo,98 pub post_info: PostDispatchInfo,
81}99}
82100
89 }107 }
90}108}
91109
110/// Return type of items in [`crate::solidity_interface`] definition
92pub type ResultWithPostInfo<T> =111pub type ResultWithPostInfo<T> =
93 core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;112 core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;
94113
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17#![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;
2022
21use 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;
29
30/// Derives call enum implementing [`crate::Callable`], [`crate::Weighted`]
31/// and [`crate::Call`] from impl block.
32///
33/// ## Macro syntax
34///
35/// `#[solidity_interface(name, is, inline_is, events)]`
36/// - *name* - used in generated code, and for Call enum name
37/// - *is* - used to provide inheritance in Solidity
38/// - *inline_is* - same as `is`, but ERC165::SupportsInterface will work differently: For `is` SupportsInterface(A) will return true
39/// 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 return
41/// false.
42///
43/// `#[weight(value)]`
44/// Can be added to every method of impl block, used for deriving [`crate::Weighted`], which
45/// 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 case
49/// than one is called.
50///
51/// `#[solidity_interface(rename_selector)]`
52/// - *rename_selector* - by default, selector name will be generated by transforming method name
53/// 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 name
55/// 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 generated
59/// solidity interface file, thus you should use [solidity syntax](https://docs.soliditylang.org/en/latest/natspec-format.html) for writing documentation in this macro
60///
61/// ## Example
62///
63/// ```ignore
64/// 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 numbers
74/// #[solidity_interface(name = MyContract, is(SuperContract), inline_is(InlineContract))]
75/// impl Contract {
76/// /// Multiply two numbers
77/// /// @param a First number
78/// /// @param b Second number
79/// /// @return uint32 Product of two passed numbers
80/// /// @dev This function returns error in case of overflow
81/// #[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;
93
94/// Derives [`ToLog`] for enum
95///
96/// Selectors will be derived from variant names, there is currently no way to have custom naming
97/// for them
98///
99/// `#[indexed]`
100/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data
101pub use evm_coder_procedural::ToLog;
102
103// Api of those modules shouldn't be consumed directly, it is only exported for usage in proc macros
104#[doc(hidden)]
105pub mod events;
106#[doc(hidden)]
28pub mod solidity;107pub mod solidity;
29108
30/// 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 no
111/// type conflict between Rust code and generated definitions
31pub mod types {112pub mod types {
32 #![allow(non_camel_case_types)]113 #![allow(non_camel_case_types, missing_docs)]
33114
34 #[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>;
56137
138 /// Solidity doesn't have `void` type, however we have special implementation
139 /// for empty tuple return type
57 pub type void = ();140 pub type void = ();
58141
59 //#region Special types142 //#region Special types
63 pub type caller = address;146 pub type caller = address;
64 //#endregion147 //#endregion
65148
149 /// Ethereum typed call message, similar to solidity
150 /// `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}
72161
162/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro
73pub trait Call: Sized {163pub trait Call: Sized {
164 /// Parse call buffer into typed call enum
74 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}
76167
168/// Intended to be used as `#[weight]` output type
169/// Should be same between evm-coder and substrate to avoid confusion
170///
171/// Isn't same thing as gas, some mapping is required between those types
77pub type Weight = u64;172pub type Weight = u64;
78173
174/// In substrate, we have benchmarking, which allows
175/// us to not rely on gas metering, but instead predict amount of gas to execute call
79pub trait Weighted: Call {176pub trait Weighted: Call {
177 /// Predict weight of this call
80 fn weight(&self) -> DispatchInfo;178 fn weight(&self) -> DispatchInfo;
81}179}
82180
181/// Type callable with ethereum message, may be implemented by [`solidity_interface`] macro
182/// on interface implementation, or for externally-owned real EVM contract
83pub trait Callable<C: Call> {183pub trait Callable<C: Call> {
184 /// Call contract using specified call data
84 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}
86187
87/// 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 subvariant
88///190///
89/// Note: no Callable implementation is provided191/// Note: no [`Callable`] implementation is provided, call implementation is inlined into every
192/// implementing contract
193///
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 contract
198 /// implements specified interface
92 SupportsInterface { interface_id: types::bytes4 },199 SupportsInterface {
200 /// Requested interface
201 interface_id: types::bytes4,
202 },
93}203}
94204
95impl ERC165Call {205impl ERC165Call {
206 /// ERC165 selector is provided by standard
96 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}
98209
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
16
17//! 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 used
19//! 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-specified
22//! format, and then output string, representing interface of this contract in solidity language
1623
17#[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::*;
3336
34#[derive(Default)]37#[derive(Default)]
35pub struct TypeCollector {38pub struct TypeCollector {
39 /// Code => id
40 /// id ordering is required to perform topo-sort on the resulting data
36 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}
7381
74pub 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 solidity
76 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 /// Specialization
78 fn is_void() -> bool {88 fn is_void() -> bool {
79 false89 false
80 }90 }
125}135}
126136
127mod 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 padded
140 /// 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}
130144
180 fn is_simple() -> bool {194 fn is_simple() -> bool {
181 false195 false
182 }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.selector
440 )?;
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}
457481
458#[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 ),* );
461485
474}498}
475499
476pub 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 }
modifiedcrates/evm-coder/tests/generics.rsdiffbeforeafterboth
1919
20struct Generic<T>(PhantomData<T>);20struct Generic<T>(PhantomData<T>);
2121
22#[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}
2828
29#[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!()
3535
36generate_stubgen!(gen_iface, GenericCall<()>, false);36generate_stubgen!(gen_iface, GenericCall<()>, false);
3737
38#[solidity_interface(name = "GenericWhere")]38#[solidity_interface(name = GenericWhere)]
39impl<T> Generic<T>39impl<T> Generic<T>
40where40where
41 T: core::fmt::Debug,41 T: core::fmt::Debug,
modifiedcrates/evm-coder/tests/random.rsdiffbeforeafterboth
1616
17#![allow(dead_code)] // This test only checks that macros is not panicking17#![allow(dead_code)] // This test only checks that macros is not panicking
1818
19use 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};
2120
22struct Impls;21struct Impls;
2322
24#[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}
3029
31#[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}
4948
50#[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}
81
82#[solidity_interface(
83 name = ValidSelector,
84 expect_selector = 0x00000000,
85)]
86impl Impls {}
8287
modifiedcrates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth
1818
19struct ERC20;19struct ERC20;
2020
21#[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!()
modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
123 .public()123 .public()
124}124}
125125
126/// 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 {
modifiedpallets/common/CHANGELOG.mddiffbeforeafterboth
22
3All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.
44
5## [0.1.8] - 2022-08-24
6
7## Added
8 - Eth methods for collection
9 + set_collection_sponsor_substrate
10 + has_collection_pending_sponsor
11 + remove_collection_sponsor
12 + get_collection_sponsor
13- Add convert function from `uint256` to `CrossAccountId`.
14
15## [0.1.7] - 2022-08-19
16
17### Added
18
19 - Add convert funtion from `CrossAccountId` to eth `uint256`.
20
21
22## [0.1.6] - 2022-08-16
23
24### Added
25- New Ethereum API methods: changeOwner, changeOwner(Substrate) and verifyOwnerOrAdmin(Substrate).
26
5<!-- bureaucrate goes here -->27<!-- bureaucrate goes here -->
6## [v0.1.5] 2022-08-1628## [v0.1.5] 2022-08-16
729
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
1[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"
66
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
26use 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;
3232
33use 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};
3437
35/// Events for ethereum collection helper.38/// Events for ethereum collection helper.
36#[derive(ToLog)]39#[derive(ToLog)]
57}60}
5861
59/// @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>
62where65where
63 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 }
127130
131 /// 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)?;
142
143 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 }
148
149 // /// 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 }
156
128 /// 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 }
141170
171 /// 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 }
177
178 /// 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 }
196
142 /// 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 }
226281
227 /// 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 }
258307
259 /// 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);
267316
268 /// 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 verify
416 /// @return "true" if account is the owner or admin465 /// @return "true" if account is the owner or admin
417 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 }
422471
472 /// Check that substrate account is the owner or admin of the collection
473 ///
474 /// @param user account to verify
475 /// @return "true" if account is the owner or admin
476 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 }
480
423 /// Returns collection type481 /// Returns collection type
424 ///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 }
492
493 /// Changes collection owner to another account
494 ///
495 /// @dev Owner can be changed only by current owner
496 /// @param newOwner new owner account
497 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 }
503
504 /// Changes collection owner to another substrate account
505 ///
506 /// @dev Owner can be changed only by current owner
507 /// @param newOwner new owner substrate account
508 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}
435515
436fn 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 collection
442 .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}
446526
447fn 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 transaction
529 collection.consume_store_writes(1)?;
449 collection530 collection
450 .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}
455536
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
1616
17//! 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.
1818
19use 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;
2123
22// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 124// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 1
23// TODO: Unhardcode prefix25// TODO: Unhardcode prefix
48 address[0..16] == ETH_COLLECTION_PREFIX50 address[0..16] == ETH_COLLECTION_PREFIX
49}51}
52
53/// Convert `CrossAccountId` to `uint256`.
54pub fn convert_cross_account_to_uint256<T: Config>(from: &T::CrossAccountId) -> uint256
55where
56 T::AccountId: AsRef<[u8; 32]>,
57{
58 let slice = from.as_sub().as_ref();
59 uint256::from_big_endian(slice)
60}
61
62/// Convert `uint256` to `CrossAccountId`.
63pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId
64where
65 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}
5072
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
203 }203 }
204204
205 /// 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 }
210210
231 Ok(true)231 Ok(true)
232 }232 }
233
234 /// Remove collection sponsor.
235 pub fn remove_sponsor(&mut self) -> DispatchResult {
236 self.collection.sponsorship = SponsorshipState::Disabled;
237 Ok(())
238 }
233239
234 /// 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 }
311
312 /// Changes collection owner to another account
313 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}
306323
307#[frame_support::pallet]324#[frame_support::pallet]
721738
722 /// 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 }
728
729 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()),
modifiedpallets/evm-contract-helpers/CHANGELOG.mddiffbeforeafterboth
1# Change Log
2
3All notable changes to this project will be documented in this file.
4
1<!-- bureaucrate goes here -->5## [v0.2.0] - 2022-08-19
6
7### Added
8
9 - Set arbitrary evm address as contract sponsor.
10 - Ability to remove current sponsor.
11
12### Removed
13 - Remove methods
14 + sponsoring_enabled
15 + toggle_sponsoring
16
17 ### Changed
18
19 - Change `toggle_sponsoring` to `self_sponsored_enable`.
20
21
2## [v0.1.2] 2022-08-1622## [v0.1.2] 2022-08-16
323
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
1[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"
66
addedpallets/evm-contract-helpers/README.mddiffbeforeafterboth

no changes

modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
16
17//! Implementation of magic contract
1618
17use 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;
3135
36/// 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.0
40 }45 }
41}46}
4247
48/// @title Magic contract, which allows users to reconfigure other contracts
43#[solidity_interface(name = "ContractHelpers")]49#[solidity_interface(name = ContractHelpers)]
44impl<T: Config> ContractHelpers<T> {50impl<T: Config> ContractHelpers<T>
51where
52 T::AccountId: AsRef<[u8; 32]>,
53{
54 /// Get user, which deployed specified contract
55 /// @dev May return zero address in case if contract is deployed
56 /// using uniquenetwork evm-migration pallet, or using other terms not
57 /// intended by pallet-evm
58 /// @dev Returns zero address if contract does not exists
59 /// @param contractAddress Contract to get owner of
60 /// @return address Owner of contract
45 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 }
4864
65 /// 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()?;
76
50 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>)?;
83
84 Ok(())
51 }85 }
5286
53 /// 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()?;
93
61 <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>)?;
96
62 Ok(())97 Ok(())
63 }98 }
6499
100 /// 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()?;
106
107 Pallet::<T>::remove_sponsor(&T::CrossAccountId::from_eth(caller), contract_address)
108 .map_err(dispatch_to_evm::<T>)?;
109
110 Ok(())
111 }
112
113 /// 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()?;
121
73 <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>)?;
124
74 Ok(())125 Ok(())
75 }126 }
127
128 /// 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 }
144
145 /// 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 }
152
153 /// 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 }
76163
77 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 }
80167
81 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-coder
85 rate_limit: uint32,173 mode: uint8,
86 ) -> Result<void> {174 ) -> Result<void> {
175 self.recorder().consume_sload()?;
176 self.recorder().consume_sstore()?;
177
87 <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);
181
89 Ok(())182 Ok(())
90 }183 }
91184
185 /// Get current contract sponsoring rate limit
186 /// @param contractAddress Contract to get sponsoring mode of
187 /// @return uint32 Amount of blocks between two sponsored transactions
92 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 }
97193
194 /// Set contract sponsoring rate limit
195 /// @dev Sponsoring rate limit - is a minimum amount of blocks that should
196 /// pass between two sponsored transactions
197 /// @param contractAddress Contract to change sponsoring rate limit of
198 /// @param rateLimit Target rate limit
199 /// @dev Only contract owner can change this setting
98 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()?;
208
209 <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 }
102213
214 /// Is specified user present in contract allow list
215 /// @dev Contract owner always implicitly included
216 /// @param contractAddress Contract to check allowlist of
217 /// @param user User to check
218 /// @return bool Is specified users exists in contract allowlist
103 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 }
106223
224 /// Toggle user presence in contract allowlist
225 /// @param contractAddress Contract to change allowlist of
226 /// @param user Which user presence should be toggled
227 /// @param isAllowed `true` if user should be allowed to be sponsored
228 /// or call this contract, `false` otherwise
229 /// @dev Only contract owner can change this setting
107 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()?;
239
113 <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);
242
115 Ok(())243 Ok(())
116 }244 }
117245
246 /// Is this contract has allowlist access enabled
247 /// @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 allowlist
249 /// in case of allowlist access enabled, only users from allowlist may call this contract
250 /// @param contractAddress Contract to get allowlist access of
251 /// @return bool Is specified contract has allowlist access enabled
252 fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
253 Ok(<AllowlistEnabled<T>>::get(contract_address))
254 }
255
256 /// Toggle contract allowlist access
257 /// @param contractAddress Contract to change allowlist access of
258 /// @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()?;
267
125 <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}
130273
274/// 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>
277where
278 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}
169316
317/// Hooks into contract creation, storing owner of newly deployed contract
170pub 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}
176324
325/// Bridge to pallet-sponsoring
177pub 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 }
336
337 let sponsor = match <Pallet<T>>::get_sponsor(*contract_address) {
338 Some(sponsor) => sponsor,
339 None => return None,
340 };
186341
187 if mode == SponsoringModeT::Allowlisted && !<Pallet<T>>::allowed(call.0, *who.as_eth()) {342 if mode == SponsoringModeT::Allowlisted
343 && !<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;
191348
192 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);
194351
195 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 }
200357
201 <SponsorBasket<T>>::insert(&call.0, who.as_eth(), block_number);358 <SponsorBasket<T>>::insert(contract_address, who.as_eth(), block_number);
202359
203 let sponsor = T::CrossAccountId::from_eth(call.0);
204 Some(sponsor)360 Some(sponsor)
205 }361 }
206}362}
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17#![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)]
1820
19use 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;
3135
32 #[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::Config
35 {39 {
40 /// Address, under which magic contract will be available
36 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 implicitly
37 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;44 type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;
38 }45 }
3946
40 #[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 owner
43 NoPermission,50 NoPermission,
51
52 /// No pending sponsor for contract.
53 NoPendingSponsor,
44 }54 }
4555
46 #[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>(_);
4959
60 /// 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>;
5872
73 /// 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 >;
84
85 /// Store for sponsoring mode.
86 ///
87 /// ### Usage
88 /// 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>;
6295
96 /// 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 >;
71108
109 /// 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 >;
81123
124 /// Storege for contracts with [`Allowlisted`](SponsoringModeT::Allowlisted) sponsoring mode.
125 ///
126 /// ### Usage
127 /// 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>;
85134
135 /// Storage for users that allowed for sponsorship.
136 ///
137 /// ### Usage
138 /// 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 >;
95152
96 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 }
158
159 /// 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 }
174
175 /// 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 }
188
189 /// 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 }
197
198 /// 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 }
216
217 /// 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 }
224
225 /// Get current sponsoring mode, performing lazy migration from legacy storage
97 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 }
233
234 /// Reconfigure contract sponsoring mode
104 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 }
112243
113 pub fn toggle_sponsoring(contract: H160, enabled: bool) {244 /// Set duration between two sponsored contract calls
114 Self::set_sponsoring_mode(
115 contract,
116 if enabled {
117 SponsoringModeT::Allowlisted
118 } else {
119 SponsoringModeT::Disabled
120 },
121 )
122 }
123
124 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 }
127248
249 /// Is user added to allowlist, or he is owner of specified contract
128 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) == user
130 }252 }
131253
254 /// Toggle contract allowlist access
132 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 }
135258
259 /// Toggle user presence in contract's allowlist
136 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 }
139263
264 /// Throw error if user is not allowed to reconfigure target contract
140 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}
146271
272/// Available contract sponsoring modes
147#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen)]273#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)]
148pub enum SponsoringModeT {274pub enum SponsoringModeT {
275 /// Sponsoring is disabled
276 #[default]
149 Disabled,277 Disabled,
278 /// Only users from allowlist will be sponsored
150 Allowlisted,279 Allowlisted,
280 /// All users will be sponsored
151 Generous,281 Generous,
152}282}
153283
169 }299 }
170}300}
171
172impl Default for SponsoringModeT {
173 fn default() -> Self {
174 Self::Disabled
175 }
176}
177301
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7contract 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}
2323
24// Selector: 7b4866f924/// @title Magic contract, which allows users to reconfigure other contracts
25/// @dev the ERC-165 identifier for this interface is 0xd77fab70
25contract ContractHelpers is Dummy, ERC165 {26contract ContractHelpers is Dummy, ERC165 {
26 // Selector: contractOwner(address) 5152b14c27 /// Get user, which deployed specified contract
28 /// @dev May return zero address in case if contract is deployed
29 /// using uniquenetwork evm-migration pallet, or using other terms not
30 /// intended by pallet-evm
31 /// @dev Returns zero address if contract does not exists
32 /// @param contractAddress Contract to get owner of
33 /// @return address Owner of contract
34 /// @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 public
29 view38 view
35 return 0x0000000000000000000000000000000000000000;44 return 0x0000000000000000000000000000000000000000;
36 }45 }
3746
38 // 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 public
41 view
42 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 }
4958
50 // 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 }
69
70 /// 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 }
5980
60 // 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 }
6793
68 // 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 public
71 view102 view
72 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 }
79110
80 // 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 }
123
124 /// 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 public
132 view
133 returns (bool)
134 {
135 require(false, stub_error);
136 contractAddress;
137 dummy;
138 return false;
139 }
140
141 /// @dev EVM selector for this function is: 0x6027dc61,
142 /// or in textual repr: sponsoringEnabled(address)
143 function sponsoringEnabled(address contractAddress)
144 public
145 view
146 returns (bool)
147 {
148 require(false, stub_error);
149 contractAddress;
150 dummy;
151 return false;
152 }
153
154 /// @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 public
83 {
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 }
89162
163 /// Get current contract sponsoring rate limit
164 /// @param contractAddress Contract to get sponsoring mode of
165 /// @return uint32 Amount of blocks between two sponsored transactions
166 /// @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 public
93 view170 view
99 return 0;176 return 0;
100 }177 }
101178
102 // Selector: allowed(address,address) 5c658165179 /// Set contract sponsoring rate limit
180 /// @dev Sponsoring rate limit - is a minimum amount of blocks that should
181 /// pass between two sponsored transactions
182 /// @param contractAddress Contract to change sponsoring rate limit of
183 /// @param rateLimit Target rate limit
184 /// @dev Only contract owner can change this setting
185 /// @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 public
105 view
106 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 }
114195
115 // Selector: allowlistEnabled(address) c772ef6c196 /// Is specified user present in contract allow list
197 /// @dev Contract owner always implicitly included
198 /// @param contractAddress Contract to check allowlist of
199 /// @param user User to check
200 /// @return bool Is specified users exists in contract allowlist
201 /// @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 public
118 view205 view
119 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 }
126214
127 // Selector: toggleAllowlist(address,bool) 36de20f5215 /// Toggle user presence in contract allowlist
216 /// @param contractAddress Contract to change allowlist of
217 /// @param user Which user presence should be toggled
218 /// @param isAllowed `true` if user should be allowed to be sponsored
219 /// or call this contract, `false` otherwise
220 /// @dev Only contract owner can change this setting
221 /// @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 isAllowed
227 ) 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 }
134234
135 // Selector: toggleAllowed(address,address,bool) 4706cc1c235 /// Is this contract has allowlist access enabled
236 /// @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 allowlist
238 /// in case of allowlist access enabled, only users from allowlist may call this contract
239 /// @param contractAddress Contract to get allowlist access of
240 /// @return bool Is specified contract has allowlist access enabled
241 /// @dev EVM selector for this function is: 0xc772ef6c,
242 /// or in textual repr: allowlistEnabled(address)
136 function toggleAllowed(243 function allowlistEnabled(address contractAddress)
244 public
245 view
246 returns (bool)
247 {
137 address contractAddress,248 require(false, stub_error);
249 contractAddress;
250 dummy;
251 return false;
252 }
253
254 /// Toggle contract allowlist access
255 /// @param contractAddress Contract to change allowlist access of
256 /// @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 allowed
140 ) 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}
266
267/// @dev anonymous struct
268struct Tuple0 {
269 address field_0;
270 uint256 field_1;
271}
148272
addedpallets/evm-migration/README.mddiffbeforeafterboth

no changes

modifiedpallets/evm-migration/src/benchmarking.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
16
17#![allow(missing_docs)]
1618
17use super::{Call, Config, Pallet};19use super::{Call, Config, Pallet};
18use frame_benchmarking::benchmarks;20use frame_benchmarking::benchmarks;
modifiedpallets/evm-migration/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17#![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)]
1820
19pub use pallet::*;21pub use pallet::*;
20#[cfg(feature = "runtime-benchmarks")]22#[cfg(feature = "runtime-benchmarks")]
3234
33 #[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 /// Weights
35 type WeightInfo: WeightInfo;38 type WeightInfo: WeightInfo;
36 }39 }
3740
4346
44 #[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 }
4954
5358
54 #[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 storage
56 #[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 }
6774
75 /// Insert items into contract storage, this method can be called
76 /// multiple times
68 #[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 }
8594
95 /// 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 }
99111
112 /// Implements [`pallet_evm::OnMethodCall`], which reserves accounts with pending migration
100 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 {
modifiedpallets/evm-migration/src/weights.rsdiffbeforeafterboth
26#![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)]
3031
31use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};32use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
addedpallets/evm-transaction-payment/README.mddiffbeforeafterboth

no changes

modifiedpallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17#![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)]
1820
19use 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::*;
3133
32 use frame_support::traits::Currency;
33 use sp_std::vec::Vec;34 use sp_std::vec::Vec;
3435
35 #[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 sponsoring
37 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 }
4041
41 #[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}
4546
47/// Implements [`fp_evm::TransactionValidityHack`], which provides sponsor address to pallet-evm
46pub 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> {
modifiedpallets/fungible/CHANGELOG.mddiffbeforeafterboth
22
3All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.
44
5
6## [0.1.5] - 2022-08-29
7
8### Added
9
10 - Implementation of `mint` and `mint_bulk` methods for ERC20 API.
11
12## [v0.1.4] - 2022-08-24
13
14### Change
15 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.
16
5<!-- bureaucrate goes here -->17<!-- bureaucrate goes here -->
6## [v0.1.3] 2022-08-1618## [v0.1.3] 2022-08-16
719
modifiedpallets/fungible/Cargo.tomldiffbeforeafterboth
1[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"
66
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
50 },50 },
51}51}
5252
53#[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}
131
132#[solidity_interface(name = ERC20Mintable)]
133impl<T: Config> FungibleHandle<T> {
134 /// Mint tokens for `to` account.
135 /// @param to account that will receive minted tokens
136 /// @param amount amount of tokens to mint
137 #[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 = self
143 .recorder
144 .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}
131150
132#[solidity_interface(name = "ERC20UniqueExtensions")]151#[solidity_interface(name = ERC20UniqueExtensions)]
133impl<T: Config> FungibleHandle<T> {152impl<T: Config> FungibleHandle<T> {
153 /// Burn tokens from account
154 /// @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 }
171
172 /// Mint tokens for multiple accounts.
173 /// @param amounts array of pairs of account address and amount
174 #[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 = self
178 .recorder
179 .weight_calls_budget(<StructureWeight<T>>::find_parent());
180 let amounts = amounts
181 .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<_>>()?;
189
190 <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)
191 .map_err(dispatch_to_evm::<T>)?;
192 Ok(true)
193 }
147}194}
148195
149#[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]> {}
158206
159generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);207generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);
160generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);208generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);
161209
162impl<T: Config> CommonEvmHandler for FungibleHandle<T>210impl<T: Config> CommonEvmHandler for FungibleHandle<T>
163where211where
164 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");
167215
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7contract 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}
2323
24// Inline24/// @title A contract that allows you to work with collections.
25/// @dev the ERC-165 identifier for this interface is 0xe54be640
26contract 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 public
35 {
36 require(false, stub_error);
37 key;
38 value;
39 dummy = 0;
40 }
41
42 /// 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 }
52
53 /// 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 public
63 view
64 returns (bytes memory)
65 {
66 require(false, stub_error);
67 key;
68 dummy;
69 return hex"";
70 }
71
72 /// 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 }
84
85 /// 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 }
97
98 /// @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 }
105
106 /// 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 }
115
116 /// 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 }
123
124 /// 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 }
134
135 /// 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 }
153
154 /// 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 }
169
170 /// 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 }
178
179 /// 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 }
188
189 /// 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 }
198
199 /// 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 }
208
209 /// 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 }
219
220 /// 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 }
230
231 /// 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 public
239 {
240 require(false, stub_error);
241 enable;
242 collections;
243 dummy = 0;
244 }
245
246 /// Set the collection access method.
247 /// @param mode Access mode
248 /// 0 for Normal
249 /// 1 for AllowList
250 /// @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 }
257
258 /// 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 }
268
269 /// 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 }
279
280 /// 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 }
290
291 /// Check that account is the owner or admin of the collection
292 ///
293 /// @param user account to verify
294 /// @return "true" if account is the owner or admin
295 /// @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 }
303
304 /// Check that substrate account is the owner or admin of the collection
305 ///
306 /// @param user account to verify
307 /// @return "true" if account is the owner or admin
308 /// @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 }
316
317 /// Returns collection type
318 ///
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 }
327
328 /// Changes collection owner to another account
329 ///
330 /// @dev Owner can be changed only by current owner
331 /// @param newOwner new owner account
332 /// @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 }
339
340 /// Changes collection owner to another substrate account
341 ///
342 /// @dev Owner can be changed only by current owner
343 /// @param newOwner new owner substrate account
344 /// @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}
352
353/// @dev the ERC-165 identifier for this interface is 0x63034ac5
354contract ERC20UniqueExtensions is Dummy, ERC165 {
355 /// Burn tokens from account
356 /// @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 }
369
370 /// Mint tokens for multiple accounts.
371 /// @param amounts array of pairs of account address and amount
372 /// @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}
381
382/// @dev anonymous struct
383struct Tuple6 {
384 address field_0;
385 uint256 field_1;
386}
387
388/// @dev the ERC-165 identifier for this interface is 0x40c10f19
389contract ERC20Mintable is Dummy, ERC165 {
390 /// Mint tokens for `to` account.
391 /// @param to account that will receive minted tokens
392 /// @param amount amount of tokens to mint
393 /// @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}
403
404/// @dev inlined interface
25contract 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}
33413
34// Selector: 6cf113cd414/// @dev the ERC-165 identifier for this interface is 0x942e8b22
35contract 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) 2f073f66
42 function setCollectionProperty(string memory key, bytes memory value)
43 public
44 {
45 require(false, stub_error);
46 key;
47 value;
48 dummy = 0;
49 }
50
51 // Delete collection property.
52 //
53 // @param key Property key.
54 //
55 // Selector: deleteCollectionProperty(string) 7b7debce
56 function deleteCollectionProperty(string memory key) public {
57 require(false, stub_error);
58 key;
59 dummy = 0;
60 }
61
62 // 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) cf24fd6d
70 function collectionProperty(string memory key)
71 public
72 view
73 returns (bytes memory)
74 {
75 require(false, stub_error);
76 key;
77 dummy;
78 return hex"";
79 }
80
81 // 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) 7623402e
88 function setCollectionSponsor(address sponsor) public {
89 require(false, stub_error);
90 sponsor;
91 dummy = 0;
92 }
93
94 // Collection sponsorship confirmation.
95 //
96 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
97 //
98 // Selector: confirmCollectionSponsorship() 3c50e97a
99 function confirmCollectionSponsorship() public {
100 require(false, stub_error);
101 dummy = 0;
102 }
103
104 // 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) 6a3841db
116 function setCollectionLimit(string memory limit, uint32 value) public {
117 require(false, stub_error);
118 limit;
119 value;
120 dummy = 0;
121 }
122
123 // 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) 993b7fba
132 function setCollectionLimit(string memory limit, bool value) public {
133 require(false, stub_error);
134 limit;
135 value;
136 dummy = 0;
137 }
138
139 // Get contract address.
140 //
141 // Selector: contractAddress() f6b4dfb4
142 function contractAddress() public view returns (address) {
143 require(false, stub_error);
144 dummy;
145 return 0x0000000000000000000000000000000000000000;
146 }
147
148 // Add collection admin by substrate address.
149 // @param new_admin Substrate administrator address.
150 //
151 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
152 function addCollectionAdminSubstrate(uint256 newAdmin) public {
153 require(false, stub_error);
154 newAdmin;
155 dummy = 0;
156 }
157
158 // Remove collection admin by substrate address.
159 // @param admin Substrate administrator address.
160 //
161 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
162 function removeCollectionAdminSubstrate(uint256 admin) public {
163 require(false, stub_error);
164 admin;
165 dummy = 0;
166 }
167
168 // Add collection admin.
169 // @param new_admin Address of the added administrator.
170 //
171 // Selector: addCollectionAdmin(address) 92e462c7
172 function addCollectionAdmin(address newAdmin) public {
173 require(false, stub_error);
174 newAdmin;
175 dummy = 0;
176 }
177
178 // Remove collection admin.
179 //
180 // @param new_admin Address of the removed administrator.
181 //
182 // Selector: removeCollectionAdmin(address) fafd7b42
183 function removeCollectionAdmin(address admin) public {
184 require(false, stub_error);
185 admin;
186 dummy = 0;
187 }
188
189 // Toggle accessibility of collection nesting.
190 //
191 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
192 //
193 // Selector: setCollectionNesting(bool) 112d4586
194 function setCollectionNesting(bool enable) public {
195 require(false, stub_error);
196 enable;
197 dummy = 0;
198 }
199
200 // 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[]) 64872396
206 function setCollectionNesting(bool enable, address[] memory collections)
207 public
208 {
209 require(false, stub_error);
210 enable;
211 collections;
212 dummy = 0;
213 }
214
215 // Set the collection access method.
216 // @param mode Access mode
217 // 0 for Normal
218 // 1 for AllowList
219 //
220 // Selector: setCollectionAccess(uint8) 41835d4c
221 function setCollectionAccess(uint8 mode) public {
222 require(false, stub_error);
223 mode;
224 dummy = 0;
225 }
226
227 // Add the user to the allowed list.
228 //
229 // @param user Address of a trusted user.
230 //
231 // Selector: addToCollectionAllowList(address) 67844fe6
232 function addToCollectionAllowList(address user) public {
233 require(false, stub_error);
234 user;
235 dummy = 0;
236 }
237
238 // Remove the user from the allowed list.
239 //
240 // @param user Address of a removed user.
241 //
242 // Selector: removeFromCollectionAllowList(address) 85c51acb
243 function removeFromCollectionAllowList(address user) public {
244 require(false, stub_error);
245 user;
246 dummy = 0;
247 }
248
249 // Switch permission for minting.
250 //
251 // @param mode Enable if "true".
252 //
253 // Selector: setCollectionMintMode(bool) 00018e84
254 function setCollectionMintMode(bool mode) public {
255 require(false, stub_error);
256 mode;
257 dummy = 0;
258 }
259
260 // Check that account is the owner or admin of the collection
261 //
262 // @param user account to verify
263 // @return "true" if account is the owner or admin
264 //
265 // Selector: verifyOwnerOrAdmin(address) c2282493
266 function verifyOwnerOrAdmin(address user) public view returns (bool) {
267 require(false, stub_error);
268 user;
269 dummy;
270 return false;
271 }
272
273 // Returns collection type
274 //
275 // @return `Fungible` or `NFT` or `ReFungible`
276 //
277 // Selector: uniqueCollectionType() d34b55b8
278 function uniqueCollectionType() public returns (string memory) {
279 require(false, stub_error);
280 dummy = 0;
281 return "";
282 }
283}
284
285// Selector: 79cc6790
286contract ERC20UniqueExtensions is Dummy, ERC165 {
287 // Selector: burnFrom(address,uint256) 79cc6790
288 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}
296
297// Selector: 942e8b22
298contract 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 }
305423
306 // 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 }
312431
313 // 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 }
319439
320 // 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 }
326447
448 /// @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 }
334456
457 /// @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 }
343466
467 /// @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 }
357481
482 /// @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 }
366491
492 /// @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 public
370 view496 view
382 Dummy,508 Dummy,
383 ERC165,509 ERC165,
384 ERC20,510 ERC20,
511 ERC20Mintable,
385 ERC20UniqueExtensions,512 ERC20UniqueExtensions,
386 Collection513 Collection
387{}514{}
modifiedpallets/nonfungible/CHANGELOG.mddiffbeforeafterboth
22
3All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.
44
5## [v0.1.5] - 2022-08-24
6
7### Change
8 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.
9
5<!-- bureaucrate goes here -->10<!-- bureaucrate goes here -->
6## [v0.1.4] 2022-08-1611## [v0.1.4] 2022-08-16
712
modifiedpallets/nonfungible/Cargo.tomldiffbeforeafterboth
1[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"
66
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
50};50};
5151
52/// @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,
201201
202/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension202/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
203/// @dev See https://eips.ethereum.org/EIPS/eip-721203/// @dev See https://eips.ethereum.org/EIPS/eip-721
204#[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 contract
207 fn name(&self) -> Result<string> {207 fn name(&self) -> Result<string> {
262262
263/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension263/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
264/// @dev See https://eips.ethereum.org/EIPS/eip-721264/// @dev See https://eips.ethereum.org/EIPS/eip-721
265#[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 NFTs
268 /// @param index A counter less than `totalSupply()`268 /// @param index A counter less than `totalSupply()`
289289
290/// @title ERC-721 Non-Fungible Token Standard290/// @title ERC-721 Non-Fungible Token Standard
291/// @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.md
292#[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 owner
295 /// @dev NFTs assigned to the zero address are considered invalid, and this295 /// @dev NFTs assigned to the zero address are considered invalid, and this
316 .as_eth())316 .as_eth())
317 }317 }
318 /// @dev Not implemented318 /// @dev Not implemented
319 #[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 implemetable
328 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 implemetable
339 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 NFT
349 /// @param to The new owner348 /// @param to The new owner
350 /// @param tokenId The NFT to transfer349 /// @param tokenId The NFT to transfer
351 /// @param _value Not used for an NFT
352 #[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}
420411
421/// @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 authorized
436}427}
437428
438/// @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}
598589
599/// @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 NFT
603 /// @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 owner
606 /// @param tokenId The NFT to transfer597 /// @param tokenId The NFT to transfer
607 /// @param _value Not used for an NFT
608 #[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 NFT
632 /// @param tokenId The NFT to transfer616 /// @param tokenId The NFT to transfer
633 /// @param _value Not used for an NFT
634 #[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}
752729
753#[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]> {}
767744
768// Not a tests, but code generators745// Not a tests, but code generators
769generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);746generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);
770generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);747generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);
771748
772impl<T: Config> CommonEvmHandler for NonfungibleHandle<T>749impl<T: Config> CommonEvmHandler for NonfungibleHandle<T>
773where750where
774 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");
777754
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
5
6// Anonymous struct
7struct Tuple0 {
8 uint256 field_0;
9 string field_1;
10}
115
12// Common stubs holder6/// @dev common stubs holder
13contract 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}
2923
30// 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 0x41369377
26contract 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 tokenOwner
40 ) public {
41 require(false, stub_error);
42 key;
43 isMutable;
44 collectionAdmin;
45 tokenOwner;
46 dummy = 0;
47 }
48
49 /// @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 value
60 ) public {
61 require(false, stub_error);
62 tokenId;
63 key;
64 value;
65 dummy = 0;
66 }
67
68 /// @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 }
80
81 /// @notice Get token property value.
82 /// @dev Throws error if key not found
83 /// @param tokenId ID of the token.
84 /// @param key Property key.
85 /// @return Property value bytes
86 /// @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 public
90 view
91 returns (bytes memory)
92 {
93 require(false, stub_error);
94 tokenId;
95 key;
96 dummy;
97 return hex"";
98 }
99}
100
101/// @title A contract that allows you to work with collections.
102/// @dev the ERC-165 identifier for this interface is 0xe54be640
103contract 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 public
112 {
113 require(false, stub_error);
114 key;
115 value;
116 dummy = 0;
117 }
118
119 /// 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 }
129
130 /// 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 public
140 view
141 returns (bytes memory)
142 {
143 require(false, stub_error);
144 key;
145 dummy;
146 return hex"";
147 }
148
149 /// 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 }
161
162 /// 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 }
174
175 /// @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 }
182
183 /// 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 }
192
193 /// 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 }
200
201 /// 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 }
211
212 /// 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 }
230
231 /// 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 }
246
247 /// 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 }
255
256 /// 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 }
265
266 /// 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 }
275
276 /// 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 }
285
286 /// 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 }
296
297 /// 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 }
307
308 /// 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 public
316 {
317 require(false, stub_error);
318 enable;
319 collections;
320 dummy = 0;
321 }
322
323 /// Set the collection access method.
324 /// @param mode Access mode
325 /// 0 for Normal
326 /// 1 for AllowList
327 /// @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 }
334
335 /// 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 }
345
346 /// 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 }
356
357 /// 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 }
367
368 /// Check that account is the owner or admin of the collection
369 ///
370 /// @param user account to verify
371 /// @return "true" if account is the owner or admin
372 /// @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 }
380
381 /// Check that substrate account is the owner or admin of the collection
382 ///
383 /// @param user account to verify
384 /// @return "true" if account is the owner or admin
385 /// @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 }
393
394 /// Returns collection type
395 ///
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 }
404
405 /// Changes collection owner to another account
406 ///
407 /// @dev Owner can be changed only by current owner
408 /// @param newOwner new owner account
409 /// @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 }
416
417 /// Changes collection owner to another substrate account
418 ///
419 /// @dev Owner can be changed only by current owner
420 /// @param newOwner new owner substrate account
421 /// @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}
429
430/// @dev anonymous struct
431struct Tuple17 {
432 address field_0;
433 uint256 field_1;
434}
435
436/// @title ERC721 Token that can be irreversibly burned (destroyed).
437/// @dev the ERC-165 identifier for this interface is 0x42966c68
438contract ERC721Burnable is Dummy, ERC165 {
439 /// @notice Burns a specific ERC721 token.
440 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
441 /// operator of the current owner.
442 /// @param tokenId The NFT to approve
443 /// @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}
451
452/// @dev inlined interface
453contract ERC721MintableEvents {
454 event MintingFinished();
455}
456
457/// @title ERC721 minting logic.
458/// @dev the ERC-165 identifier for this interface is 0x68ccfe89
459contract 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 }
467
468 /// @notice Function to mint token.
469 /// @dev `tokenId` should be obtained with `nextTokenId` method,
470 /// unlike standard, you can't specify it manually
471 /// @param to The new owner
472 /// @param tokenId ID of the minted NFT
473 /// @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 }
482
483 /// @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 manually
486 /// @param to The new owner
487 /// @param tokenId ID of the minted NFT
488 /// @param tokenUri Token URI that would be stored in the NFT properties
489 /// @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 tokenUri
495 ) public returns (bool) {
496 require(false, stub_error);
497 to;
498 tokenId;
499 tokenUri;
500 dummy = 0;
501 return false;
502 }
503
504 /// @dev Not implemented
505 /// @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}
513
514/// @title Unique extensions for ERC721.
515/// @dev the ERC-165 identifier for this interface is 0xd74d154f
516contract ERC721UniqueExtensions is Dummy, ERC165 {
517 /// @notice Transfer ownership of an NFT
518 /// @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 owner
521 /// @param tokenId The NFT to transfer
522 /// @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 }
530
531 /// @notice Burns a specific ERC721 token.
532 /// @dev Throws unless `msg.sender` is the current owner or an authorized
533 /// operator for this NFT. Throws if `from` is not the current owner. Throws
534 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
535 /// @param from The current owner of the NFT
536 /// @param tokenId The NFT to transfer
537 /// @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 }
545
546 /// @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 }
554
555 /// @notice Function to mint multiple tokens.
556 /// @dev `tokenIds` should be an array of consecutive numbers and first number
557 /// should be obtained with `nextTokenId` method
558 /// @param to The new owner
559 /// @param tokenIds IDs of the minted NFTs
560 /// @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 public
564 returns (bool)
565 {
566 require(false, stub_error);
567 to;
568 tokenIds;
569 dummy = 0;
570 return false;
571 }
572
573 /// @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 consecutive
575 /// numbers and first number should be obtained with `nextTokenId` method
576 /// @param to The new owner
577 /// @param tokens array of pairs of token ID and token URI for minted tokens
578 /// @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 public
582 returns (bool)
583 {
584 require(false, stub_error);
585 to;
586 tokens;
587 dummy = 0;
588 return false;
589 }
590}
591
592/// @dev anonymous struct
593struct Tuple8 {
594 uint256 field_0;
595 string field_1;
596}
597
598/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
599/// @dev See https://eips.ethereum.org/EIPS/eip-721
600/// @dev the ERC-165 identifier for this interface is 0x780e9d63
601contract ERC721Enumerable is Dummy, ERC165 {
602 /// @notice Enumerate valid NFTs
603 /// @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 }
614
615 /// @dev Not implemented
616 /// @dev EVM selector for this function is: 0x2f745c59,
617 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
618 function tokenOfOwnerByIndex(address owner, uint256 index)
619 public
620 view
621 returns (uint256)
622 {
623 require(false, stub_error);
624 owner;
625 index;
626 dummy;
627 return 0;
628 }
629
630 /// @notice Count NFTs tracked by this contract
631 /// @return A count of valid NFTs tracked by this contract, where each one of
632 /// them has an assigned and queryable owner not equal to the zero address
633 /// @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}
641
642/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
643/// @dev See https://eips.ethereum.org/EIPS/eip-721
644/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
645contract ERC721Metadata is Dummy, ERC165 {
646 /// @notice A descriptive name for a collection of NFTs in this contract
647 /// @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 }
654
655 /// @notice An abbreviated name for NFTs in this contract
656 /// @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 }
663
664 /// @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 suffix
670 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
671 ///
672 /// @return token's const_metadata
673 /// @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}
682
683/// @dev inlined interface
31contract ERC721Events {684contract ERC721Events {
32 event Transfer(685 event Transfer(
33 address indexed from,686 address indexed from,
46 );699 );
47}700}
48701
49// Inline702/// @title ERC-721 Non-Fungible Token Standard
50contract ERC721MintableEvents {703/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
51 event MintingFinished();704/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
52}
53
54// Selector: 41369377
55contract 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) 222d97fa
64 function setTokenPropertyPermission(
65 string memory key,
66 bool isMutable,
67 bool collectionAdmin,
68 bool tokenOwner
69 ) public {
70 require(false, stub_error);
71 key;
72 isMutable;
73 collectionAdmin;
74 tokenOwner;
75 dummy = 0;
76 }
77
78 // @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) 1752d67b
85 function setProperty(
86 uint256 tokenId,
87 string memory key,
88 bytes memory value
89 ) public {
90 require(false, stub_error);
91 tokenId;
92 key;
93 value;
94 dummy = 0;
95 }
96
97 // @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) 066111d1
103 function deleteProperty(uint256 tokenId, string memory key) public {
104 require(false, stub_error);
105 tokenId;
106 key;
107 dummy = 0;
108 }
109
110 // @notice Get token property value.
111 // @dev Throws error if key not found
112 // @param tokenId ID of the token.
113 // @param key Property key.
114 // @return Property value bytes
115 //
116 // Selector: property(uint256,string) 7228c327
117 function property(uint256 tokenId, string memory key)
118 public
119 view
120 returns (bytes memory)
121 {
122 require(false, stub_error);
123 tokenId;
124 key;
125 dummy;
126 return hex"";
127 }
128}
129
130// Selector: 42966c68
131contract ERC721Burnable is Dummy, ERC165 {
132 // @notice Burns a specific ERC721 token.
133 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
134 // operator of the current owner.
135 // @param tokenId The NFT to approve
136 //
137 // Selector: burn(uint256) 42966c68
138 function burn(uint256 tokenId) public {
139 require(false, stub_error);
140 tokenId;
141 dummy = 0;
142 }
143}
144
145// Selector: 58800161
146contract 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 owner
148 // @dev NFTs assigned to the zero address are considered invalid, and this707 /// @dev NFTs assigned to the zero address are considered invalid, and this
149 // 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 balance
151 // @return The number of NFTs owned by `owner`, possibly zero710 /// @return The number of NFTs owned by `owner`, possibly zero
152 //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 }
160719
161 // @notice Find the owner of an NFT720 /// @notice Find the owner of an NFT
162 // @dev NFTs assigned to zero address are considered invalid, and queries721 /// @dev NFTs assigned to zero address are considered invalid, and queries
163 // about them do throw.722 /// about them do throw.
164 // @param tokenId The identifier for an NFT723 /// @param tokenId The identifier for an NFT
165 // @return The address of the owner of the NFT724 /// @return The address of the owner of the NFT
166 //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 }
174733
175 // @dev Not implemented734 /// @dev Not implemented
176 //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 }
191750
192 // @dev Not implemented751 /// @dev Not implemented
193 //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 }
206765
207 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE766 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
208 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE767 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
209 // THEY MAY BE PERMANENTLY LOST768 /// THEY MAY BE PERMANENTLY LOST
210 // @dev Throws unless `msg.sender` is the current owner or an authorized769 /// @dev Throws unless `msg.sender` is the current owner or an authorized
211 // 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. Throws
212 // 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 NFT
214 // @param to The new owner773 /// @param to The new owner
215 // @param tokenId The NFT to transfer774 /// @param tokenId The NFT to transfer
216 // @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 }
230788
231 // @notice Set or reaffirm the approved address for an NFT789 /// @notice Set or reaffirm the approved address for an NFT
232 // @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 authorized
234 // 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 controller
236 // @param tokenId The NFT to approve794 /// @param tokenId The NFT to approve
237 //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 }
245803
246 // @dev Not implemented804 /// @dev Not implemented
247 //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 }
255813
256 // @dev Not implemented814 /// @dev Not implemented
257 //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 }
265823
266 // @dev Not implemented824 /// @dev Not implemented
267 //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 public
271 view829 view
279 }837 }
280}838}
281
282// Selector: 5b5e139f
283contract ERC721Metadata is Dummy, ERC165 {
284 // @notice A descriptive name for a collection of NFTs in this contract
285 //
286 // Selector: name() 06fdde03
287 function name() public view returns (string memory) {
288 require(false, stub_error);
289 dummy;
290 return "";
291 }
292
293 // @notice An abbreviated name for NFTs in this contract
294 //
295 // Selector: symbol() 95d89b41
296 function symbol() public view returns (string memory) {
297 require(false, stub_error);
298 dummy;
299 return "";
300 }
301
302 // @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 suffix
308 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
309 //
310 // @return token's const_metadata
311 //
312 // Selector: tokenURI(uint256) c87b56dd
313 function tokenURI(uint256 tokenId) public view returns (string memory) {
314 require(false, stub_error);
315 tokenId;
316 dummy;
317 return "";
318 }
319}
320
321// Selector: 68ccfe89
322contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
323 // Selector: mintingFinished() 05d2035b
324 function mintingFinished() public view returns (bool) {
325 require(false, stub_error);
326 dummy;
327 return false;
328 }
329
330 // @notice Function to mint token.
331 // @dev `tokenId` should be obtained with `nextTokenId` method,
332 // unlike standard, you can't specify it manually
333 // @param to The new owner
334 // @param tokenId ID of the minted NFT
335 //
336 // Selector: mint(address,uint256) 40c10f19
337 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 }
344
345 // @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 manually
348 // @param to The new owner
349 // @param tokenId ID of the minted NFT
350 // @param tokenUri Token URI that would be stored in the NFT properties
351 //
352 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
353 function mintWithTokenURI(
354 address to,
355 uint256 tokenId,
356 string memory tokenUri
357 ) public returns (bool) {
358 require(false, stub_error);
359 to;
360 tokenId;
361 tokenUri;
362 dummy = 0;
363 return false;
364 }
365
366 // @dev Not implemented
367 //
368 // Selector: finishMinting() 7d64bcb4
369 function finishMinting() public returns (bool) {
370 require(false, stub_error);
371 dummy = 0;
372 return false;
373 }
374}
375
376// Selector: 6cf113cd
377contract 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) 2f073f66
384 function setCollectionProperty(string memory key, bytes memory value)
385 public
386 {
387 require(false, stub_error);
388 key;
389 value;
390 dummy = 0;
391 }
392
393 // Delete collection property.
394 //
395 // @param key Property key.
396 //
397 // Selector: deleteCollectionProperty(string) 7b7debce
398 function deleteCollectionProperty(string memory key) public {
399 require(false, stub_error);
400 key;
401 dummy = 0;
402 }
403
404 // 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) cf24fd6d
412 function collectionProperty(string memory key)
413 public
414 view
415 returns (bytes memory)
416 {
417 require(false, stub_error);
418 key;
419 dummy;
420 return hex"";
421 }
422
423 // 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) 7623402e
430 function setCollectionSponsor(address sponsor) public {
431 require(false, stub_error);
432 sponsor;
433 dummy = 0;
434 }
435
436 // Collection sponsorship confirmation.
437 //
438 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
439 //
440 // Selector: confirmCollectionSponsorship() 3c50e97a
441 function confirmCollectionSponsorship() public {
442 require(false, stub_error);
443 dummy = 0;
444 }
445
446 // 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) 6a3841db
458 function setCollectionLimit(string memory limit, uint32 value) public {
459 require(false, stub_error);
460 limit;
461 value;
462 dummy = 0;
463 }
464
465 // 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) 993b7fba
474 function setCollectionLimit(string memory limit, bool value) public {
475 require(false, stub_error);
476 limit;
477 value;
478 dummy = 0;
479 }
480
481 // Get contract address.
482 //
483 // Selector: contractAddress() f6b4dfb4
484 function contractAddress() public view returns (address) {
485 require(false, stub_error);
486 dummy;
487 return 0x0000000000000000000000000000000000000000;
488 }
489
490 // Add collection admin by substrate address.
491 // @param new_admin Substrate administrator address.
492 //
493 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
494 function addCollectionAdminSubstrate(uint256 newAdmin) public {
495 require(false, stub_error);
496 newAdmin;
497 dummy = 0;
498 }
499
500 // Remove collection admin by substrate address.
501 // @param admin Substrate administrator address.
502 //
503 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
504 function removeCollectionAdminSubstrate(uint256 admin) public {
505 require(false, stub_error);
506 admin;
507 dummy = 0;
508 }
509
510 // Add collection admin.
511 // @param new_admin Address of the added administrator.
512 //
513 // Selector: addCollectionAdmin(address) 92e462c7
514 function addCollectionAdmin(address newAdmin) public {
515 require(false, stub_error);
516 newAdmin;
517 dummy = 0;
518 }
519
520 // Remove collection admin.
521 //
522 // @param new_admin Address of the removed administrator.
523 //
524 // Selector: removeCollectionAdmin(address) fafd7b42
525 function removeCollectionAdmin(address admin) public {
526 require(false, stub_error);
527 admin;
528 dummy = 0;
529 }
530
531 // Toggle accessibility of collection nesting.
532 //
533 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
534 //
535 // Selector: setCollectionNesting(bool) 112d4586
536 function setCollectionNesting(bool enable) public {
537 require(false, stub_error);
538 enable;
539 dummy = 0;
540 }
541
542 // 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[]) 64872396
548 function setCollectionNesting(bool enable, address[] memory collections)
549 public
550 {
551 require(false, stub_error);
552 enable;
553 collections;
554 dummy = 0;
555 }
556
557 // Set the collection access method.
558 // @param mode Access mode
559 // 0 for Normal
560 // 1 for AllowList
561 //
562 // Selector: setCollectionAccess(uint8) 41835d4c
563 function setCollectionAccess(uint8 mode) public {
564 require(false, stub_error);
565 mode;
566 dummy = 0;
567 }
568
569 // Add the user to the allowed list.
570 //
571 // @param user Address of a trusted user.
572 //
573 // Selector: addToCollectionAllowList(address) 67844fe6
574 function addToCollectionAllowList(address user) public {
575 require(false, stub_error);
576 user;
577 dummy = 0;
578 }
579
580 // Remove the user from the allowed list.
581 //
582 // @param user Address of a removed user.
583 //
584 // Selector: removeFromCollectionAllowList(address) 85c51acb
585 function removeFromCollectionAllowList(address user) public {
586 require(false, stub_error);
587 user;
588 dummy = 0;
589 }
590
591 // Switch permission for minting.
592 //
593 // @param mode Enable if "true".
594 //
595 // Selector: setCollectionMintMode(bool) 00018e84
596 function setCollectionMintMode(bool mode) public {
597 require(false, stub_error);
598 mode;
599 dummy = 0;
600 }
601
602 // Check that account is the owner or admin of the collection
603 //
604 // @param user account to verify
605 // @return "true" if account is the owner or admin
606 //
607 // Selector: verifyOwnerOrAdmin(address) c2282493
608 function verifyOwnerOrAdmin(address user) public view returns (bool) {
609 require(false, stub_error);
610 user;
611 dummy;
612 return false;
613 }
614
615 // Returns collection type
616 //
617 // @return `Fungible` or `NFT` or `ReFungible`
618 //
619 // Selector: uniqueCollectionType() d34b55b8
620 function uniqueCollectionType() public returns (string memory) {
621 require(false, stub_error);
622 dummy = 0;
623 return "";
624 }
625}
626
627// Selector: 780e9d63
628contract ERC721Enumerable is Dummy, ERC165 {
629 // @notice Enumerate valid NFTs
630 // @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) 4f6ccce7
635 function tokenByIndex(uint256 index) public view returns (uint256) {
636 require(false, stub_error);
637 index;
638 dummy;
639 return 0;
640 }
641
642 // @dev Not implemented
643 //
644 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
645 function tokenOfOwnerByIndex(address owner, uint256 index)
646 public
647 view
648 returns (uint256)
649 {
650 require(false, stub_error);
651 owner;
652 index;
653 dummy;
654 return 0;
655 }
656
657 // @notice Count NFTs tracked by this contract
658 // @return A count of valid NFTs tracked by this contract, where each one of
659 // them has an assigned and queryable owner not equal to the zero address
660 //
661 // Selector: totalSupply() 18160ddd
662 function totalSupply() public view returns (uint256) {
663 require(false, stub_error);
664 dummy;
665 return 0;
666 }
667}
668
669// Selector: d74d154f
670contract ERC721UniqueExtensions is Dummy, ERC165 {
671 // @notice Transfer ownership of an NFT
672 // @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 owner
675 // @param tokenId The NFT to transfer
676 // @param _value Not used for an NFT
677 //
678 // Selector: transfer(address,uint256) a9059cbb
679 function transfer(address to, uint256 tokenId) public {
680 require(false, stub_error);
681 to;
682 tokenId;
683 dummy = 0;
684 }
685
686 // @notice Burns a specific ERC721 token.
687 // @dev Throws unless `msg.sender` is the current owner or an authorized
688 // operator for this NFT. Throws if `from` is not the current owner. Throws
689 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
690 // @param from The current owner of the NFT
691 // @param tokenId The NFT to transfer
692 // @param _value Not used for an NFT
693 //
694 // Selector: burnFrom(address,uint256) 79cc6790
695 function burnFrom(address from, uint256 tokenId) public {
696 require(false, stub_error);
697 from;
698 tokenId;
699 dummy = 0;
700 }
701
702 // @notice Returns next free NFT ID.
703 //
704 // Selector: nextTokenId() 75794a3c
705 function nextTokenId() public view returns (uint256) {
706 require(false, stub_error);
707 dummy;
708 return 0;
709 }
710
711 // @notice Function to mint multiple tokens.
712 // @dev `tokenIds` should be an array of consecutive numbers and first number
713 // should be obtained with `nextTokenId` method
714 // @param to The new owner
715 // @param tokenIds IDs of the minted NFTs
716 //
717 // Selector: mintBulk(address,uint256[]) 44a9945e
718 function mintBulk(address to, uint256[] memory tokenIds)
719 public
720 returns (bool)
721 {
722 require(false, stub_error);
723 to;
724 tokenIds;
725 dummy = 0;
726 return false;
727 }
728
729 // @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 consecutive
731 // numbers and first number should be obtained with `nextTokenId` method
732 // @param to The new owner
733 // @param tokens array of pairs of token ID and token URI for minted tokens
734 //
735 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
736 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
737 public
738 returns (bool)
739 {
740 require(false, stub_error);
741 to;
742 tokens;
743 dummy = 0;
744 return false;
745 }
746}
747839
748contract UniqueNFT is840contract UniqueNFT is
749 Dummy,841 Dummy,
modifiedpallets/refungible/CHANGELOG.mddiffbeforeafterboth
22
3All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.
44
5## [v0.2.4] - 2022-08-24
6
7### Change
8 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.
9
5<!-- bureaucrate goes here -->10<!-- bureaucrate goes here -->
6## [v0.2.3] 2022-08-1611## [v0.2.3] 2022-08-16
712
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
1[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"
66
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
281 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)?}
283
284 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)])?;
290
291 }: {<Pallet<T>>::set_parent_nft_unchecked(&collection, item, owner, T::CrossAccountId::from_eth(H160::default()))?}
292283
293 token_owner {284 token_owner {
294 bench_init!{285 bench_init!{
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
53pub const ADDRESS_FOR_PARTIALLY_OWNED_TOKENS: H160 = H160::repeat_byte(0xff);53pub const ADDRESS_FOR_PARTIALLY_OWNED_TOKENS: H160 = H160::repeat_byte(0xff);
5454
55/// @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}
199199
200#[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 contract
203 fn name(&self) -> Result<string> {203 fn name(&self) -> Result<string> {
258258
259/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension259/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
260/// @dev See https://eips.ethereum.org/EIPS/eip-721260/// @dev See https://eips.ethereum.org/EIPS/eip-721
261#[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 RFTs
264 /// @param index A counter less than `totalSupply()`264 /// @param index A counter less than `totalSupply()`
285285
286/// @title ERC-721 Non-Fungible Token Standard286/// @title ERC-721 Non-Fungible Token Standard
287/// @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.md
288#[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 owner
291 /// @dev RFTs assigned to the zero address are considered invalid, and this291 /// @dev RFTs assigned to the zero address are considered invalid, and this
322 _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 implemetable
328 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 implemetable
340 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 NFT
351 /// @param to The new owner349 /// @param to The new owner
352 /// @param tokenId The NFT to transfer350 /// @param tokenId The NFT to transfer
353 /// @param _value Not used for an NFT
354 #[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}
439429
440/// @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 authorized
458}448}
459449
460/// @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}
617607
618/// @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 RFT
622 /// @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 owner
626 /// @param tokenId The RFT to transfer616 /// @param tokenId The RFT to transfer
627 /// @param _value Not used for an RFT
628 #[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 RFT
657 /// @param tokenId The RFT to transfer640 /// @param tokenId The RFT to transfer
658 /// @param _value Not used for an RFT
659 #[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}
802778
803#[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]> {}
817793
818// Not a tests, but code generators794// Not a tests, but code generators
819generate_stubgen!(gen_impl, UniqueRefungibleCall<()>, true);795generate_stubgen!(gen_impl, UniqueRefungibleCall<()>, true);
820generate_stubgen!(gen_iface, UniqueRefungibleCall<()>, false);796generate_stubgen!(gen_iface, UniqueRefungibleCall<()>, false);
821797
822impl<T: Config> CommonEvmHandler for RefungibleHandle<T>798impl<T: Config> CommonEvmHandler for RefungibleHandle<T>
823where799where
824 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(
modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
29 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;
4443
45use 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};
4948
50pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);49pub struct RefungibleTokenHandle<T: Config>(pub RefungibleHandle<T>, pub TokenId);
5150
52#[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();
58
59 let key_scoped = PropertyScope::Eth
60 .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 }
6856
69 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();
73
74 let key_scoped = PropertyScope::Eth
75 .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")?;
82
83 Ok(token_id.into())
84 } else {
85 Ok(self.1.into())58 Ok(self.1.into())
86 }
87 }59 }
88}60}
89
90#[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()?;
104
105 <Pallet<T>>::set_parent_nft(&self.0, self.1, caller, nft_collection, nft_token)
106 .map_err(dispatch_to_evm::<T>)?;
107
108 Ok(true)
109 }
110}
11161
112#[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.md
140#[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}
248198
249#[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}
307257
308#[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]> {}
313263
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
1380 }1380 }
1381 }1381 }
1382
1383 /// Sets the NFT token as a parent for the RFT token
1384 ///
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();
1400
1401 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 }
1405
1406 let nft_token_address =
1407 T::CrossTokenAddressMapping::token_to_address(nft_collection, nft_token);
1408
1409 Self::set_parent_nft_unchecked(collection, rft_token_id, sender, nft_token_address)
1410 }
1411
1412 /// Sets the NFT token as a parent for the RFT token
1413 ///
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 }
1427
1428 let parent_nft_property_key = key::parent_nft();
1429
1430 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");
1433
1434 <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 )?;
1443
1444 Ok(())
1445 }
1446}1382}
14471383
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
5
6// Anonymous struct
7struct Tuple0 {
8 uint256 field_0;
9 string field_1;
10}
115
12// Common stubs holder6/// @dev common stubs holder
13contract 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}
2923
30// 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 0x41369377
26contract 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 tokenOwner
40 ) public {
41 require(false, stub_error);
42 key;
43 isMutable;
44 collectionAdmin;
45 tokenOwner;
46 dummy = 0;
47 }
48
49 /// @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 value
60 ) public {
61 require(false, stub_error);
62 tokenId;
63 key;
64 value;
65 dummy = 0;
66 }
67
68 /// @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 }
80
81 /// @notice Get token property value.
82 /// @dev Throws error if key not found
83 /// @param tokenId ID of the token.
84 /// @param key Property key.
85 /// @return Property value bytes
86 /// @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 public
90 view
91 returns (bytes memory)
92 {
93 require(false, stub_error);
94 tokenId;
95 key;
96 dummy;
97 return hex"";
98 }
99}
100
101/// @title A contract that allows you to work with collections.
102/// @dev the ERC-165 identifier for this interface is 0xe54be640
103contract 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 public
112 {
113 require(false, stub_error);
114 key;
115 value;
116 dummy = 0;
117 }
118
119 /// 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 }
129
130 /// 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 public
140 view
141 returns (bytes memory)
142 {
143 require(false, stub_error);
144 key;
145 dummy;
146 return hex"";
147 }
148
149 /// 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 }
161
162 /// 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 }
174
175 /// @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 }
182
183 /// 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 }
192
193 /// 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 }
200
201 /// 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 }
211
212 /// 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 }
230
231 /// 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 }
246
247 /// 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 }
255
256 /// 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 }
265
266 /// 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 }
275
276 /// 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 }
285
286 /// 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 }
296
297 /// 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 }
307
308 /// 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 public
316 {
317 require(false, stub_error);
318 enable;
319 collections;
320 dummy = 0;
321 }
322
323 /// Set the collection access method.
324 /// @param mode Access mode
325 /// 0 for Normal
326 /// 1 for AllowList
327 /// @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 }
334
335 /// 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 }
345
346 /// 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 }
356
357 /// 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 }
367
368 /// Check that account is the owner or admin of the collection
369 ///
370 /// @param user account to verify
371 /// @return "true" if account is the owner or admin
372 /// @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 }
380
381 /// Check that substrate account is the owner or admin of the collection
382 ///
383 /// @param user account to verify
384 /// @return "true" if account is the owner or admin
385 /// @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 }
393
394 /// Returns collection type
395 ///
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 }
404
405 /// Changes collection owner to another account
406 ///
407 /// @dev Owner can be changed only by current owner
408 /// @param newOwner new owner account
409 /// @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 }
416
417 /// Changes collection owner to another substrate account
418 ///
419 /// @dev Owner can be changed only by current owner
420 /// @param newOwner new owner substrate account
421 /// @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}
429
430/// @dev anonymous struct
431struct Tuple17 {
432 address field_0;
433 uint256 field_1;
434}
435
436/// @title ERC721 Token that can be irreversibly burned (destroyed).
437/// @dev the ERC-165 identifier for this interface is 0x42966c68
438contract ERC721Burnable is Dummy, ERC165 {
439 /// @notice Burns a specific ERC721 token.
440 /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
441 /// operator of the current owner.
442 /// @param tokenId The RFT to approve
443 /// @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}
451
452/// @dev inlined interface
453contract ERC721MintableEvents {
454 event MintingFinished();
455}
456
457/// @title ERC721 minting logic.
458/// @dev the ERC-165 identifier for this interface is 0x68ccfe89
459contract 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 }
467
468 /// @notice Function to mint token.
469 /// @dev `tokenId` should be obtained with `nextTokenId` method,
470 /// unlike standard, you can't specify it manually
471 /// @param to The new owner
472 /// @param tokenId ID of the minted RFT
473 /// @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 }
482
483 /// @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 manually
486 /// @param to The new owner
487 /// @param tokenId ID of the minted RFT
488 /// @param tokenUri Token URI that would be stored in the RFT properties
489 /// @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 tokenUri
495 ) public returns (bool) {
496 require(false, stub_error);
497 to;
498 tokenId;
499 tokenUri;
500 dummy = 0;
501 return false;
502 }
503
504 /// @dev Not implemented
505 /// @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}
513
514/// @title Unique extensions for ERC721.
515/// @dev the ERC-165 identifier for this interface is 0x7c3bef89
516contract ERC721UniqueExtensions is Dummy, ERC165 {
517 /// @notice Transfer ownership of an RFT
518 /// @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 owner
522 /// @param tokenId The RFT to transfer
523 /// @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 }
531
532 /// @notice Burns a specific ERC721 token.
533 /// @dev Throws unless `msg.sender` is the current owner or an authorized
534 /// operator for this RFT. Throws if `from` is not the current owner. Throws
535 /// 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 RFT
538 /// @param tokenId The RFT to transfer
539 /// @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 }
547
548 /// @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 }
556
557 /// @notice Function to mint multiple tokens.
558 /// @dev `tokenIds` should be an array of consecutive numbers and first number
559 /// should be obtained with `nextTokenId` method
560 /// @param to The new owner
561 /// @param tokenIds IDs of the minted RFTs
562 /// @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 public
566 returns (bool)
567 {
568 require(false, stub_error);
569 to;
570 tokenIds;
571 dummy = 0;
572 return false;
573 }
574
575 /// @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 consecutive
577 /// numbers and first number should be obtained with `nextTokenId` method
578 /// @param to The new owner
579 /// @param tokens array of pairs of token ID and token URI for minted tokens
580 /// @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 public
584 returns (bool)
585 {
586 require(false, stub_error);
587 to;
588 tokens;
589 dummy = 0;
590 return false;
591 }
592
593 /// Returns EVM address for refungible token
594 ///
595 /// @param token ID of the token
596 /// @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}
605
606/// @dev anonymous struct
607struct Tuple8 {
608 uint256 field_0;
609 string field_1;
610}
611
612/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
613/// @dev See https://eips.ethereum.org/EIPS/eip-721
614/// @dev the ERC-165 identifier for this interface is 0x780e9d63
615contract ERC721Enumerable is Dummy, ERC165 {
616 /// @notice Enumerate valid RFTs
617 /// @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 }
628
629 /// Not implemented
630 /// @dev EVM selector for this function is: 0x2f745c59,
631 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
632 function tokenOfOwnerByIndex(address owner, uint256 index)
633 public
634 view
635 returns (uint256)
636 {
637 require(false, stub_error);
638 owner;
639 index;
640 dummy;
641 return 0;
642 }
643
644 /// @notice Count RFTs tracked by this contract
645 /// @return A count of valid RFTs tracked by this contract, where each one of
646 /// them has an assigned and queryable owner not equal to the zero address
647 /// @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}
655
656/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
657contract ERC721Metadata is Dummy, ERC165 {
658 /// @notice A descriptive name for a collection of RFTs in this contract
659 /// @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 }
666
667 /// @notice An abbreviated name for RFTs in this contract
668 /// @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 }
675
676 /// @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 suffix
682 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
683 ///
684 /// @return token's const_metadata
685 /// @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}
694
695/// @dev inlined interface
31contract ERC721Events {696contract ERC721Events {
32 event Transfer(697 event Transfer(
33 address indexed from,698 address indexed from,
46 );711 );
47}712}
48713
49// Inline714/// @title ERC-721 Non-Fungible Token Standard
50contract ERC721MintableEvents {715/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
51 event MintingFinished();716/// @dev the ERC-165 identifier for this interface is 0x58800161
52}
53
54// Selector: 41369377
55contract 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) 222d97fa
64 function setTokenPropertyPermission(
65 string memory key,
66 bool isMutable,
67 bool collectionAdmin,
68 bool tokenOwner
69 ) public {
70 require(false, stub_error);
71 key;
72 isMutable;
73 collectionAdmin;
74 tokenOwner;
75 dummy = 0;
76 }
77
78 // @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) 1752d67b
85 function setProperty(
86 uint256 tokenId,
87 string memory key,
88 bytes memory value
89 ) public {
90 require(false, stub_error);
91 tokenId;
92 key;
93 value;
94 dummy = 0;
95 }
96
97 // @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) 066111d1
103 function deleteProperty(uint256 tokenId, string memory key) public {
104 require(false, stub_error);
105 tokenId;
106 key;
107 dummy = 0;
108 }
109
110 // @notice Get token property value.
111 // @dev Throws error if key not found
112 // @param tokenId ID of the token.
113 // @param key Property key.
114 // @return Property value bytes
115 //
116 // Selector: property(uint256,string) 7228c327
117 function property(uint256 tokenId, string memory key)
118 public
119 view
120 returns (bytes memory)
121 {
122 require(false, stub_error);
123 tokenId;
124 key;
125 dummy;
126 return hex"";
127 }
128}
129
130// Selector: 42966c68
131contract ERC721Burnable is Dummy, ERC165 {
132 // @notice Burns a specific ERC721 token.
133 // @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
134 // operator of the current owner.
135 // @param tokenId The RFT to approve
136 //
137 // Selector: burn(uint256) 42966c68
138 function burn(uint256 tokenId) public {
139 require(false, stub_error);
140 tokenId;
141 dummy = 0;
142 }
143}
144
145// Selector: 58800161
146contract 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 owner
148 // @dev RFTs assigned to the zero address are considered invalid, and this719 /// @dev RFTs assigned to the zero address are considered invalid, and this
149 // 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 balance
151 // @return The number of RFTs owned by `owner`, possibly zero722 /// @return The number of RFTs owned by `owner`, possibly zero
152 //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 }
160731
161 // @notice Find the owner of an RFT732 /// @notice Find the owner of an RFT
162 // @dev RFTs assigned to zero address are considered invalid, and queries733 /// @dev RFTs assigned to zero address are considered invalid, and queries
163 // about them do throw.734 /// about them do throw.
164 // Returns special 0xffffffffffffffffffffffffffffffffffffffff address for735 /// Returns special 0xffffffffffffffffffffffffffffffffffffffff address for
165 // 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 RFT
167 // @return The address of the owner of the RFT738 /// @return The address of the owner of the RFT
168 //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 }
176747
177 // @dev Not implemented748 /// @dev Not implemented
178 //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 }
193764
194 // @dev Not implemented765 /// @dev Not implemented
195 //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 }
208779
209 // @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE780 /// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE
210 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE781 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
211 // THEY MAY BE PERMANENTLY LOST782 /// THEY MAY BE PERMANENTLY LOST
212 // @dev Throws unless `msg.sender` is the current owner or an authorized783 /// @dev Throws unless `msg.sender` is the current owner or an authorized
213 // 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. Throws
214 // 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 NFT
217 // @param to The new owner788 /// @param to The new owner
218 // @param tokenId The NFT to transfer789 /// @param tokenId The NFT to transfer
219 // @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 }
233803
234 // @dev Not implemented804 /// @dev Not implemented
235 //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 }
243813
244 // @dev Not implemented814 /// @dev Not implemented
245 //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 }
253823
254 // @dev Not implemented824 /// @dev Not implemented
255 //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 }
263833
264 // @dev Not implemented834 /// @dev Not implemented
265 //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 public
269 view839 view
277 }847 }
278}848}
279
280// Selector: 5b5e139f
281contract ERC721Metadata is Dummy, ERC165 {
282 // @notice A descriptive name for a collection of RFTs in this contract
283 //
284 // Selector: name() 06fdde03
285 function name() public view returns (string memory) {
286 require(false, stub_error);
287 dummy;
288 return "";
289 }
290
291 // @notice An abbreviated name for RFTs in this contract
292 //
293 // Selector: symbol() 95d89b41
294 function symbol() public view returns (string memory) {
295 require(false, stub_error);
296 dummy;
297 return "";
298 }
299
300 // @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 suffix
306 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
307 //
308 // @return token's const_metadata
309 //
310 // Selector: tokenURI(uint256) c87b56dd
311 function tokenURI(uint256 tokenId) public view returns (string memory) {
312 require(false, stub_error);
313 tokenId;
314 dummy;
315 return "";
316 }
317}
318
319// Selector: 68ccfe89
320contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
321 // Selector: mintingFinished() 05d2035b
322 function mintingFinished() public view returns (bool) {
323 require(false, stub_error);
324 dummy;
325 return false;
326 }
327
328 // @notice Function to mint token.
329 // @dev `tokenId` should be obtained with `nextTokenId` method,
330 // unlike standard, you can't specify it manually
331 // @param to The new owner
332 // @param tokenId ID of the minted RFT
333 //
334 // Selector: mint(address,uint256) 40c10f19
335 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 }
342
343 // @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 manually
346 // @param to The new owner
347 // @param tokenId ID of the minted RFT
348 // @param tokenUri Token URI that would be stored in the RFT properties
349 //
350 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
351 function mintWithTokenURI(
352 address to,
353 uint256 tokenId,
354 string memory tokenUri
355 ) public returns (bool) {
356 require(false, stub_error);
357 to;
358 tokenId;
359 tokenUri;
360 dummy = 0;
361 return false;
362 }
363
364 // @dev Not implemented
365 //
366 // Selector: finishMinting() 7d64bcb4
367 function finishMinting() public returns (bool) {
368 require(false, stub_error);
369 dummy = 0;
370 return false;
371 }
372}
373
374// Selector: 6cf113cd
375contract 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) 2f073f66
382 function setCollectionProperty(string memory key, bytes memory value)
383 public
384 {
385 require(false, stub_error);
386 key;
387 value;
388 dummy = 0;
389 }
390
391 // Delete collection property.
392 //
393 // @param key Property key.
394 //
395 // Selector: deleteCollectionProperty(string) 7b7debce
396 function deleteCollectionProperty(string memory key) public {
397 require(false, stub_error);
398 key;
399 dummy = 0;
400 }
401
402 // 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) cf24fd6d
410 function collectionProperty(string memory key)
411 public
412 view
413 returns (bytes memory)
414 {
415 require(false, stub_error);
416 key;
417 dummy;
418 return hex"";
419 }
420
421 // 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) 7623402e
428 function setCollectionSponsor(address sponsor) public {
429 require(false, stub_error);
430 sponsor;
431 dummy = 0;
432 }
433
434 // Collection sponsorship confirmation.
435 //
436 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
437 //
438 // Selector: confirmCollectionSponsorship() 3c50e97a
439 function confirmCollectionSponsorship() public {
440 require(false, stub_error);
441 dummy = 0;
442 }
443
444 // 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) 6a3841db
456 function setCollectionLimit(string memory limit, uint32 value) public {
457 require(false, stub_error);
458 limit;
459 value;
460 dummy = 0;
461 }
462
463 // 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) 993b7fba
472 function setCollectionLimit(string memory limit, bool value) public {
473 require(false, stub_error);
474 limit;
475 value;
476 dummy = 0;
477 }
478
479 // Get contract address.
480 //
481 // Selector: contractAddress() f6b4dfb4
482 function contractAddress() public view returns (address) {
483 require(false, stub_error);
484 dummy;
485 return 0x0000000000000000000000000000000000000000;
486 }
487
488 // Add collection admin by substrate address.
489 // @param new_admin Substrate administrator address.
490 //
491 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
492 function addCollectionAdminSubstrate(uint256 newAdmin) public {
493 require(false, stub_error);
494 newAdmin;
495 dummy = 0;
496 }
497
498 // Remove collection admin by substrate address.
499 // @param admin Substrate administrator address.
500 //
501 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
502 function removeCollectionAdminSubstrate(uint256 admin) public {
503 require(false, stub_error);
504 admin;
505 dummy = 0;
506 }
507
508 // Add collection admin.
509 // @param new_admin Address of the added administrator.
510 //
511 // Selector: addCollectionAdmin(address) 92e462c7
512 function addCollectionAdmin(address newAdmin) public {
513 require(false, stub_error);
514 newAdmin;
515 dummy = 0;
516 }
517
518 // Remove collection admin.
519 //
520 // @param new_admin Address of the removed administrator.
521 //
522 // Selector: removeCollectionAdmin(address) fafd7b42
523 function removeCollectionAdmin(address admin) public {
524 require(false, stub_error);
525 admin;
526 dummy = 0;
527 }
528
529 // Toggle accessibility of collection nesting.
530 //
531 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
532 //
533 // Selector: setCollectionNesting(bool) 112d4586
534 function setCollectionNesting(bool enable) public {
535 require(false, stub_error);
536 enable;
537 dummy = 0;
538 }
539
540 // 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[]) 64872396
546 function setCollectionNesting(bool enable, address[] memory collections)
547 public
548 {
549 require(false, stub_error);
550 enable;
551 collections;
552 dummy = 0;
553 }
554
555 // Set the collection access method.
556 // @param mode Access mode
557 // 0 for Normal
558 // 1 for AllowList
559 //
560 // Selector: setCollectionAccess(uint8) 41835d4c
561 function setCollectionAccess(uint8 mode) public {
562 require(false, stub_error);
563 mode;
564 dummy = 0;
565 }
566
567 // Add the user to the allowed list.
568 //
569 // @param user Address of a trusted user.
570 //
571 // Selector: addToCollectionAllowList(address) 67844fe6
572 function addToCollectionAllowList(address user) public {
573 require(false, stub_error);
574 user;
575 dummy = 0;
576 }
577
578 // Remove the user from the allowed list.
579 //
580 // @param user Address of a removed user.
581 //
582 // Selector: removeFromCollectionAllowList(address) 85c51acb
583 function removeFromCollectionAllowList(address user) public {
584 require(false, stub_error);
585 user;
586 dummy = 0;
587 }
588
589 // Switch permission for minting.
590 //
591 // @param mode Enable if "true".
592 //
593 // Selector: setCollectionMintMode(bool) 00018e84
594 function setCollectionMintMode(bool mode) public {
595 require(false, stub_error);
596 mode;
597 dummy = 0;
598 }
599
600 // Check that account is the owner or admin of the collection
601 //
602 // @param user account to verify
603 // @return "true" if account is the owner or admin
604 //
605 // Selector: verifyOwnerOrAdmin(address) c2282493
606 function verifyOwnerOrAdmin(address user) public view returns (bool) {
607 require(false, stub_error);
608 user;
609 dummy;
610 return false;
611 }
612
613 // Returns collection type
614 //
615 // @return `Fungible` or `NFT` or `ReFungible`
616 //
617 // Selector: uniqueCollectionType() d34b55b8
618 function uniqueCollectionType() public returns (string memory) {
619 require(false, stub_error);
620 dummy = 0;
621 return "";
622 }
623}
624
625// Selector: 780e9d63
626contract ERC721Enumerable is Dummy, ERC165 {
627 // @notice Enumerate valid RFTs
628 // @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) 4f6ccce7
633 function tokenByIndex(uint256 index) public view returns (uint256) {
634 require(false, stub_error);
635 index;
636 dummy;
637 return 0;
638 }
639
640 // Not implemented
641 //
642 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
643 function tokenOfOwnerByIndex(address owner, uint256 index)
644 public
645 view
646 returns (uint256)
647 {
648 require(false, stub_error);
649 owner;
650 index;
651 dummy;
652 return 0;
653 }
654
655 // @notice Count RFTs tracked by this contract
656 // @return A count of valid RFTs tracked by this contract, where each one of
657 // them has an assigned and queryable owner not equal to the zero address
658 //
659 // Selector: totalSupply() 18160ddd
660 function totalSupply() public view returns (uint256) {
661 require(false, stub_error);
662 dummy;
663 return 0;
664 }
665}
666
667// Selector: 7c3bef89
668contract ERC721UniqueExtensions is Dummy, ERC165 {
669 // @notice Transfer ownership of an RFT
670 // @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 owner
674 // @param tokenId The RFT to transfer
675 // @param _value Not used for an RFT
676 //
677 // Selector: transfer(address,uint256) a9059cbb
678 function transfer(address to, uint256 tokenId) public {
679 require(false, stub_error);
680 to;
681 tokenId;
682 dummy = 0;
683 }
684
685 // @notice Burns a specific ERC721 token.
686 // @dev Throws unless `msg.sender` is the current owner or an authorized
687 // operator for this RFT. Throws if `from` is not the current owner. Throws
688 // 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 RFT
691 // @param tokenId The RFT to transfer
692 // @param _value Not used for an RFT
693 //
694 // Selector: burnFrom(address,uint256) 79cc6790
695 function burnFrom(address from, uint256 tokenId) public {
696 require(false, stub_error);
697 from;
698 tokenId;
699 dummy = 0;
700 }
701
702 // @notice Returns next free RFT ID.
703 //
704 // Selector: nextTokenId() 75794a3c
705 function nextTokenId() public view returns (uint256) {
706 require(false, stub_error);
707 dummy;
708 return 0;
709 }
710
711 // @notice Function to mint multiple tokens.
712 // @dev `tokenIds` should be an array of consecutive numbers and first number
713 // should be obtained with `nextTokenId` method
714 // @param to The new owner
715 // @param tokenIds IDs of the minted RFTs
716 //
717 // Selector: mintBulk(address,uint256[]) 44a9945e
718 function mintBulk(address to, uint256[] memory tokenIds)
719 public
720 returns (bool)
721 {
722 require(false, stub_error);
723 to;
724 tokenIds;
725 dummy = 0;
726 return false;
727 }
728
729 // @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 consecutive
731 // numbers and first number should be obtained with `nextTokenId` method
732 // @param to The new owner
733 // @param tokens array of pairs of token ID and token URI for minted tokens
734 //
735 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
736 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
737 public
738 returns (bool)
739 {
740 require(false, stub_error);
741 to;
742 tokens;
743 dummy = 0;
744 return false;
745 }
746
747 // Returns EVM address for refungible token
748 //
749 // @param token ID of the token
750 //
751 // Selector: tokenContractAddress(uint256) ab76fac6
752 function tokenContractAddress(uint256 token) public view returns (address) {
753 require(false, stub_error);
754 token;
755 dummy;
756 return 0x0000000000000000000000000000000000000000;
757 }
758}
759849
760contract UniqueRefungible is850contract UniqueRefungible is
761 Dummy,851 Dummy,
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7contract 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}
2323
24// Inline24/// @dev the ERC-165 identifier for this interface is 0x5755c3f2
25contract 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 }
33
34 /// @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}
42
43/// @dev the ERC-165 identifier for this interface is 0xab8deb37
44contract 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 }
58
59 /// @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}
71
72/// @dev inlined interface
25contract 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}
3381
34// Selector: 042f110682/// @title Standard ERC20 token
35contract 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.md
38 public86/// @dev the ERC-165 identifier for this interface is 0x942e8b22
39 returns (bool)
40 {
41 require(false, stub_error);
42 collection;
43 nftId;
44 dummy = 0;
45 return false;
46 }
47}
48
49// Selector: 5755c3f2
50contract ERC1633 is Dummy, ERC165 {
51 // Selector: parentToken() 80a54001
52 function parentToken() public view returns (address) {
53 require(false, stub_error);
54 dummy;
55 return 0x0000000000000000000000000000000000000000;
56 }
57
58 // Selector: parentTokenId() d7f083f3
59 function parentTokenId() public view returns (uint256) {
60 require(false, stub_error);
61 dummy;
62 return 0;
63 }
64}
65
66// Selector: 942e8b22
67contract 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 }
7696
77 // @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 }
85105
86 // @dev Total number of tokens in existence106 /// @dev Total number of tokens in existence
87 //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 }
94114
95 // @dev Not supported115 /// @dev Not supported
96 //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 }
103123
104 // @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 }
115135
116 // @dev Transfer token for a specified address136 /// @dev Transfer token for a specified address
117 // @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 }
128148
129 // @dev Transfer tokens from one address to another149 /// @dev Transfer tokens from one address to another
130 // @param from address The address which you want to send tokens from150 /// @param from address The address which you want to send tokens from
131 // @param to address The address which you want to transfer to151 /// @param to address The address which you want to transfer to
132 // @param amount uint256 the amount of tokens to be transferred152 /// @param amount uint256 the amount of tokens to be transferred
133 //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 }
147167
148 // @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 old
150 // 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 this
151 // 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-263524729
153 // @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 }
164184
165 // @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 public
173 view193 view
181 }201 }
182}202}
183
184// Selector: ab8deb37
185contract 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) 79cc6790
192 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 }
199
200 // @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) d2418ca7
205 function repartition(uint256 amount) public returns (bool) {
206 require(false, stub_error);
207 amount;
208 dummy = 0;
209 return false;
210 }
211}
212203
213contract UniqueRefungibleToken is204contract UniqueRefungibleToken is
214 Dummy,205 Dummy,
215 ERC165,206 ERC165,
216 ERC20,207 ERC20,
217 ERC20UniqueExtensions,208 ERC20UniqueExtensions,
218 ERC1633,209 ERC1633
219 ERC1633UniqueExtensions
220{}210{}
221211
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
53 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}
5958
255 .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)
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
154 Ok(data)154 Ok(data)
155}155}
156
157fn 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}
167156
168fn 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>)?;
191
192 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>)?;
200
201 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}
204183
205/// @title Contract, which allows users to operate with collections184/// @title Contract, which allows users to operate with collections
206#[solidity_interface(name = "CollectionHelpers", events(CollectionHelpersEvents))]185#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]
207impl<T> EvmCollectionHelpers<T>186impl<T> EvmCollectionHelpers<T>
208where187where
209 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 collection
212 /// @param name Name of the collection191 /// @param name Name of the collection
213 /// @param description Informative description of the collection192 /// @param description Informative description of the collection
214 /// @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 applications
215 /// @return address Address of the newly created collection194 /// @return address Address of the newly created collection
216 #[weight(<SelfWeightOf<T>>::create_collection())]195 #[weight(<SelfWeightOf<T>>::create_collection())]
217 fn create_nonfungible_collection(196 fn create_nonfungible_collection(
304 }283 }
305284
306 /// Check if a collection exists285 /// Check if a collection exists
307 /// @param collection_address Address of the collection in question286 /// @param collectionAddress Address of the collection in question
308 /// @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) {
modifiedpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7contract 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}
2323
24// Inline24/// @dev inlined interface
25contract CollectionHelpersEvents {25contract CollectionHelpersEvents {
26 event CollectionCreated(26 event CollectionCreated(
27 address indexed owner,27 address indexed owner,
28 address indexed collectionId28 address indexed collectionId
29 );29 );
30}30}
3131
32// Selector: 675f307432/// @title Contract, which allows users to operate with collections
33/// @dev the ERC-165 identifier for this interface is 0x675f3074
33contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {34contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
34 // Create an NFT collection35 /// Create an NFT collection
35 // @param name Name of the collection36 /// @param name Name of the collection
36 // @param description Informative description of the collection37 /// @param description Informative description of the collection
37 // @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 applications
38 // @return address Address of the newly created collection39 /// @return address Address of the newly created collection
39 //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 }
5354
55 /// @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 }
6971
72 /// @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 }
8386
87 /// @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 }
99103
100 // Check if a collection exists104 /// Check if a collection exists
101 // @param collection_address Address of the collection in question105 /// @param collectionAddress Address of the collection in question
102 // @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 public
107 view111 view
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
1050pub enum PropertyScope {1050pub enum PropertyScope {
1051 None,1051 None,
1052 Rmrk,1052 Rmrk,
1053 Eth,
1054}1053}
10551054
1056impl 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 };
10641062
1065 [scope_str, b":", key.as_slice()]1063 [scope_str, b":", key.as_slice()]
modifiedruntime/common/config/ethereum.rsdiffbeforeafterboth
120120
121impl 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}
125124
modifiedruntime/common/dispatch.rsdiffbeforeafterboth
124 + pallet_fungible::Config124 + pallet_fungible::Config
125 + pallet_nonfungible::Config125 + pallet_nonfungible::Config
126 + 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()
modifiedruntime/tests/src/lib.rsdiffbeforeafterboth
167}167}
168168
169#[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.0
178 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(&eth.0[0..8]);185 sub_raw.copy_from_slice(&eth.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.2
194 }
192}195}
193196
194impl Default for TestCrossAccountId {197impl Default for TestCrossAccountId {
modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17import {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';
2221
23chai.use(chaiAsPromised);22chai.use(chaiAsPromised);
24const expect = chai.expect;23const expect = chai.expect;
24
25let donor: IKeyringPair;
26
27before(async () => {
28 await usingPlaygrounds(async (_, privateKeyWrapper) => {
29 donor = privateKeyWrapper('//Alice');
30 });
31});
2532
26describe('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');
3238
33 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);
3541
36 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);
3843
39 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});
4449
45describe('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'});
5255
53 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);
5558
56 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));
58
59 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;
63
62 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 });
6769
68 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');
74
75 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);
7774
78 const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));75 await collection.addAdmin(alice, {Substrate: bob.address});
79 await submitTransactionAsync(alice, changeAdminTx);
8076
81 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});
8379
84 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 82
87 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 });
9288
93 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-bitwise
96 const collectionId = (1 << 32) - 1;93 const collectionId = (1 << 32) - 1;
97 const alice = privateKeyWrapper('//Alice');
98 const bob = privateKeyWrapper('//Bob');
9994
100 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;
10297
103 // 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 });
107102
108 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');107
113 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;
116111
117 // 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 });
121116
122 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'});
135121
136 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);
138124
139 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 }
144130
145 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});
modifiedtests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7interface Dummy {7interface Dummy {
88
9}9}
12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
13}13}
1414
15// Inline15/// @dev inlined interface
16interface CollectionHelpersEvents {16interface CollectionHelpersEvents {
17 event CollectionCreated(17 event CollectionCreated(
18 address indexed owner,18 address indexed owner,
19 address indexed collectionId19 address indexed collectionId
20 );20 );
21}21}
2222
23// Selector: 675f307423/// @title Contract, which allows users to operate with collections
24/// @dev the ERC-165 identifier for this interface is 0x675f3074
24interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {25interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
25 // Create an NFT collection26 /// Create an NFT collection
26 // @param name Name of the collection27 /// @param name Name of the collection
27 // @param description Informative description of the collection28 /// @param description Informative description of the collection
28 // @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 applications
29 // @return address Address of the newly created collection30 /// @return address Address of the newly created collection
30 //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 tokenPrefix
36 ) external returns (address);37 ) external returns (address);
3738
39 /// @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 baseUri
44 ) external returns (address);46 ) external returns (address);
4547
48 /// @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 tokenPrefix
51 ) external returns (address);54 ) external returns (address);
5255
56 /// @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 baseUri
59 ) external returns (address);63 ) external returns (address);
6064
61 // Check if a collection exists65 /// Check if a collection exists
62 // @param collection_address Address of the collection in question66 /// @param collectionAddress Address of the collection in question
63 // @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 external
68 view72 view
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7interface Dummy {7interface Dummy {
88
9}9}
12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
13}13}
1414
15// Selector: 7b4866f915/// @title Magic contract, which allows users to reconfigure other contracts
16/// @dev the ERC-165 identifier for this interface is 0xd77fab70
16interface ContractHelpers is Dummy, ERC165 {17interface ContractHelpers is Dummy, ERC165 {
17 // Selector: contractOwner(address) 5152b14c18 /// Get user, which deployed specified contract
19 /// @dev May return zero address in case if contract is deployed
20 /// using uniquenetwork evm-migration pallet, or using other terms not
21 /// intended by pallet-evm
22 /// @dev Returns zero address if contract does not exists
23 /// @param contractAddress Contract to get owner of
24 /// @return address Owner of contract
25 /// @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 external
20 view29 view
21 returns (address);30 returns (address);
2231
23 // 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;
38
39 /// 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;
45
46 /// 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;
52
53 /// 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;
61
62 /// 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 external
70 view
71 returns (Tuple0 memory);
72
73 /// 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 external80
26 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 external
89 view
90 returns (bool);
91
92 /// @dev EVM selector for this function is: 0x6027dc61,
93 /// or in textual repr: sponsoringEnabled(address)
94 function sponsoringEnabled(address contractAddress)
95 external
96 view
97 returns (bool);
98
99 /// @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;
36102
37 // Selector: sponsoringMode(address) b70c7267103 /// Get current contract sponsoring rate limit
104 /// @param contractAddress Contract to get sponsoring mode of
105 /// @return uint32 Amount of blocks between two sponsored transactions
106 /// @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 external
40 view110 view
41 returns (uint8);111 returns (uint32);
42112
113 /// Set contract sponsoring rate limit
114 /// @dev Sponsoring rate limit - is a minimum amount of blocks that should
115 /// pass between two sponsored transactions
116 /// @param contractAddress Contract to change sponsoring rate limit of
117 /// @param rateLimit Target rate limit
118 /// @dev Only contract owner can change this setting
119 /// @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;
46123
47 // Selector: getSponsoringRateLimit(address) 610cfabd124 /// Is specified user present in contract allow list
125 /// @dev Contract owner always implicitly included
126 /// @param contractAddress Contract to check allowlist of
127 /// @param user User to check
128 /// @return bool Is specified users exists in contract allowlist
129 /// @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 external
50 view133 view
51 returns (uint32);134 returns (bool);
52135
53 // Selector: allowed(address,address) 5c658165136 /// Toggle user presence in contract allowlist
137 /// @param contractAddress Contract to change allowlist of
138 /// @param user Which user presence should be toggled
139 /// @param isAllowed `true` if user should be allowed to be sponsored
140 /// or call this contract, `false` otherwise
141 /// @dev Only contract owner can change this setting
142 /// @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 isAllowed
55 external148 ) external;
56 view149
57 returns (bool);150 /// Is this contract has allowlist access enabled
58151 /// @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 allowlist
153 /// in case of allowlist access enabled, only users from allowlist may call this contract
154 /// @param contractAddress Contract to get allowlist access of
155 /// @return bool Is specified contract has allowlist access enabled
156 /// @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 external
62 view160 view
63 returns (bool);161 returns (bool);
64162
163 /// Toggle contract allowlist access
164 /// @param contractAddress Contract to change allowlist access of
165 /// @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;
67
68 // Selector: toggleAllowed(address,address,bool) 4706cc1c
69 function toggleAllowed(
70 address contractAddress,
71 address user,
72 bool allowed
73 ) external;
74}169}
170
171/// @dev anonymous struct
172struct Tuple0 {
173 address field_0;
174 uint256 field_1;
175}
75176
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7interface Dummy {7interface Dummy {
88
9}9}
12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
13}13}
1414
15// Inline15/// @title A contract that allows you to work with collections.
16/// @dev the ERC-165 identifier for this interface is 0xe54be640
17interface 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;
26
27 /// 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;
33
34 /// 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 external
44 view
45 returns (bytes memory);
46
47 /// 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;
55
56 /// 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;
64
65 /// @dev EVM selector for this function is: 0x058ac185,
66 /// or in textual repr: hasCollectionPendingSponsor()
67 function hasCollectionPendingSponsor() external view returns (bool);
68
69 /// 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;
75
76 /// Remove collection sponsor.
77 /// @dev EVM selector for this function is: 0x6e0326a3,
78 /// or in textual repr: removeCollectionSponsor()
79 function removeCollectionSponsor() external;
80
81 /// 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);
87
88 /// 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;
101
102 /// 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;
112
113 /// 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);
117
118 /// 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;
123
124 /// 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;
129
130 /// 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;
135
136 /// 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;
142
143 /// 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;
149
150 /// 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;
158
159 /// Set the collection access method.
160 /// @param mode Access mode
161 /// 0 for Normal
162 /// 1 for AllowList
163 /// @dev EVM selector for this function is: 0x41835d4c,
164 /// or in textual repr: setCollectionAccess(uint8)
165 function setCollectionAccess(uint8 mode) external;
166
167 /// 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;
173
174 /// 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;
180
181 /// 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;
187
188 /// Check that account is the owner or admin of the collection
189 ///
190 /// @param user account to verify
191 /// @return "true" if account is the owner or admin
192 /// @dev EVM selector for this function is: 0x9811b0c7,
193 /// or in textual repr: isOwnerOrAdmin(address)
194 function isOwnerOrAdmin(address user) external view returns (bool);
195
196 /// Check that substrate account is the owner or admin of the collection
197 ///
198 /// @param user account to verify
199 /// @return "true" if account is the owner or admin
200 /// @dev EVM selector for this function is: 0x68910e00,
201 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)
202 function isOwnerOrAdminSubstrate(uint256 user) external view returns (bool);
203
204 /// Returns collection type
205 ///
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);
210
211 /// Changes collection owner to another account
212 ///
213 /// @dev Owner can be changed only by current owner
214 /// @param newOwner new owner account
215 /// @dev EVM selector for this function is: 0x13af4035,
216 /// or in textual repr: setOwner(address)
217 function setOwner(address newOwner) external;
218
219 /// Changes collection owner to another substrate account
220 ///
221 /// @dev Owner can be changed only by current owner
222 /// @param newOwner new owner substrate account
223 /// @dev EVM selector for this function is: 0xb212138f,
224 /// or in textual repr: setOwnerSubstrate(uint256)
225 function setOwnerSubstrate(uint256 newOwner) external;
226}
227
228/// @dev the ERC-165 identifier for this interface is 0x63034ac5
229interface ERC20UniqueExtensions is Dummy, ERC165 {
230 /// Burn tokens from account
231 /// @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);
238
239 /// Mint tokens for multiple accounts.
240 /// @param amounts array of pairs of account address and amount
241 /// @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}
245
246/// @dev anonymous struct
247struct Tuple6 {
248 address field_0;
249 uint256 field_1;
250}
251
252/// @dev the ERC-165 identifier for this interface is 0x40c10f19
253interface ERC20Mintable is Dummy, ERC165 {
254 /// Mint tokens for `to` account.
255 /// @param to account that will receive minted tokens
256 /// @param amount amount of tokens to mint
257 /// @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}
261
262/// @dev inlined interface
16interface 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}
24271
25// Selector: 6cf113cd272/// @dev the ERC-165 identifier for this interface is 0x942e8b22
26interface 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) 2f073f66
33 function setCollectionProperty(string memory key, bytes memory value)
34 external;
35
36 // Delete collection property.
37 //
38 // @param key Property key.
39 //
40 // Selector: deleteCollectionProperty(string) 7b7debce
41 function deleteCollectionProperty(string memory key) external;
42
43 // 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) cf24fd6d
51 function collectionProperty(string memory key)
52 external
53 view
54 returns (bytes memory);
55
56 // 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) 7623402e
63 function setCollectionSponsor(address sponsor) external;
64
65 // Collection sponsorship confirmation.
66 //
67 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
68 //
69 // Selector: confirmCollectionSponsorship() 3c50e97a
70 function confirmCollectionSponsorship() external;
71
72 // 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) 6a3841db
84 function setCollectionLimit(string memory limit, uint32 value) external;
85
86 // 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) 993b7fba
95 function setCollectionLimit(string memory limit, bool value) external;
96
97 // Get contract address.
98 //
99 // Selector: contractAddress() f6b4dfb4
100 function contractAddress() external view returns (address);
101
102 // Add collection admin by substrate address.
103 // @param new_admin Substrate administrator address.
104 //
105 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
106 function addCollectionAdminSubstrate(uint256 newAdmin) external;
107
108 // Remove collection admin by substrate address.
109 // @param admin Substrate administrator address.
110 //
111 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
112 function removeCollectionAdminSubstrate(uint256 admin) external;
113
114 // Add collection admin.
115 // @param new_admin Address of the added administrator.
116 //
117 // Selector: addCollectionAdmin(address) 92e462c7
118 function addCollectionAdmin(address newAdmin) external;
119
120 // Remove collection admin.
121 //
122 // @param new_admin Address of the removed administrator.
123 //
124 // Selector: removeCollectionAdmin(address) fafd7b42
125 function removeCollectionAdmin(address admin) external;
126
127 // Toggle accessibility of collection nesting.
128 //
129 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
130 //
131 // Selector: setCollectionNesting(bool) 112d4586
132 function setCollectionNesting(bool enable) external;
133
134 // 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[]) 64872396
140 function setCollectionNesting(bool enable, address[] memory collections)
141 external;
142
143 // Set the collection access method.
144 // @param mode Access mode
145 // 0 for Normal
146 // 1 for AllowList
147 //
148 // Selector: setCollectionAccess(uint8) 41835d4c
149 function setCollectionAccess(uint8 mode) external;
150
151 // Add the user to the allowed list.
152 //
153 // @param user Address of a trusted user.
154 //
155 // Selector: addToCollectionAllowList(address) 67844fe6
156 function addToCollectionAllowList(address user) external;
157
158 // Remove the user from the allowed list.
159 //
160 // @param user Address of a removed user.
161 //
162 // Selector: removeFromCollectionAllowList(address) 85c51acb
163 function removeFromCollectionAllowList(address user) external;
164
165 // Switch permission for minting.
166 //
167 // @param mode Enable if "true".
168 //
169 // Selector: setCollectionMintMode(bool) 00018e84
170 function setCollectionMintMode(bool mode) external;
171
172 // Check that account is the owner or admin of the collection
173 //
174 // @param user account to verify
175 // @return "true" if account is the owner or admin
176 //
177 // Selector: verifyOwnerOrAdmin(address) c2282493
178 function verifyOwnerOrAdmin(address user) external view returns (bool);
179
180 // Returns collection type
181 //
182 // @return `Fungible` or `NFT` or `ReFungible`
183 //
184 // Selector: uniqueCollectionType() d34b55b8
185 function uniqueCollectionType() external returns (string memory);
186}
187
188// Selector: 79cc6790
189interface ERC20UniqueExtensions is Dummy, ERC165 {
190 // Selector: burnFrom(address,uint256) 79cc6790
191 function burnFrom(address from, uint256 amount) external returns (bool);
192}
193
194// Selector: 942e8b22
195interface 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);
198277
199 // 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);
201281
202 // 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);
204285
205 // 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);
207289
290 /// @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);
210293
294 /// @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);
213297
298 /// @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 amount
219 ) external returns (bool);304 ) external returns (bool);
220305
306 /// @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);
223309
310 /// @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 external
227 view314 view
232 Dummy,319 Dummy,
233 ERC165,320 ERC165,
234 ERC20,321 ERC20,
322 ERC20Mintable,
235 ERC20UniqueExtensions,323 ERC20UniqueExtensions,
236 Collection324 Collection
237{}325{}
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
5
6// Anonymous struct
7struct Tuple0 {
8 uint256 field_0;
9 string field_1;
10}
115
12// Common stubs holder6/// @dev common stubs holder
13interface Dummy {7interface Dummy {
148
15}9}
18 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
19}13}
2014
21// 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 0x41369377
17interface 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 tokenOwner
31 ) external;
32
33 /// @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 value
44 ) external;
45
46 /// @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;
53
54 /// @notice Get token property value.
55 /// @dev Throws error if key not found
56 /// @param tokenId ID of the token.
57 /// @param key Property key.
58 /// @return Property value bytes
59 /// @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 external
63 view
64 returns (bytes memory);
65}
66
67/// @title A contract that allows you to work with collections.
68/// @dev the ERC-165 identifier for this interface is 0xe54be640
69interface 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;
78
79 /// 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;
85
86 /// 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 external
96 view
97 returns (bytes memory);
98
99 /// 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;
107
108 /// 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;
116
117 /// @dev EVM selector for this function is: 0x058ac185,
118 /// or in textual repr: hasCollectionPendingSponsor()
119 function hasCollectionPendingSponsor() external view returns (bool);
120
121 /// 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;
127
128 /// Remove collection sponsor.
129 /// @dev EVM selector for this function is: 0x6e0326a3,
130 /// or in textual repr: removeCollectionSponsor()
131 function removeCollectionSponsor() external;
132
133 /// 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);
139
140 /// 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;
153
154 /// 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;
164
165 /// 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);
169
170 /// 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;
175
176 /// 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;
181
182 /// 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;
187
188 /// 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;
194
195 /// 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;
201
202 /// 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;
210
211 /// Set the collection access method.
212 /// @param mode Access mode
213 /// 0 for Normal
214 /// 1 for AllowList
215 /// @dev EVM selector for this function is: 0x41835d4c,
216 /// or in textual repr: setCollectionAccess(uint8)
217 function setCollectionAccess(uint8 mode) external;
218
219 /// 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;
225
226 /// 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;
232
233 /// 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;
239
240 /// Check that account is the owner or admin of the collection
241 ///
242 /// @param user account to verify
243 /// @return "true" if account is the owner or admin
244 /// @dev EVM selector for this function is: 0x9811b0c7,
245 /// or in textual repr: isOwnerOrAdmin(address)
246 function isOwnerOrAdmin(address user) external view returns (bool);
247
248 /// Check that substrate account is the owner or admin of the collection
249 ///
250 /// @param user account to verify
251 /// @return "true" if account is the owner or admin
252 /// @dev EVM selector for this function is: 0x68910e00,
253 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)
254 function isOwnerOrAdminSubstrate(uint256 user) external view returns (bool);
255
256 /// Returns collection type
257 ///
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);
262
263 /// Changes collection owner to another account
264 ///
265 /// @dev Owner can be changed only by current owner
266 /// @param newOwner new owner account
267 /// @dev EVM selector for this function is: 0x13af4035,
268 /// or in textual repr: setOwner(address)
269 function setOwner(address newOwner) external;
270
271 /// Changes collection owner to another substrate account
272 ///
273 /// @dev Owner can be changed only by current owner
274 /// @param newOwner new owner substrate account
275 /// @dev EVM selector for this function is: 0xb212138f,
276 /// or in textual repr: setOwnerSubstrate(uint256)
277 function setOwnerSubstrate(uint256 newOwner) external;
278}
279
280/// @dev anonymous struct
281struct Tuple17 {
282 address field_0;
283 uint256 field_1;
284}
285
286/// @title ERC721 Token that can be irreversibly burned (destroyed).
287/// @dev the ERC-165 identifier for this interface is 0x42966c68
288interface ERC721Burnable is Dummy, ERC165 {
289 /// @notice Burns a specific ERC721 token.
290 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
291 /// operator of the current owner.
292 /// @param tokenId The NFT to approve
293 /// @dev EVM selector for this function is: 0x42966c68,
294 /// or in textual repr: burn(uint256)
295 function burn(uint256 tokenId) external;
296}
297
298/// @dev inlined interface
299interface ERC721MintableEvents {
300 event MintingFinished();
301}
302
303/// @title ERC721 minting logic.
304/// @dev the ERC-165 identifier for this interface is 0x68ccfe89
305interface 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);
309
310 /// @notice Function to mint token.
311 /// @dev `tokenId` should be obtained with `nextTokenId` method,
312 /// unlike standard, you can't specify it manually
313 /// @param to The new owner
314 /// @param tokenId ID of the minted NFT
315 /// @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);
318
319 /// @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 manually
322 /// @param to The new owner
323 /// @param tokenId ID of the minted NFT
324 /// @param tokenUri Token URI that would be stored in the NFT properties
325 /// @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 tokenUri
331 ) external returns (bool);
332
333 /// @dev Not implemented
334 /// @dev EVM selector for this function is: 0x7d64bcb4,
335 /// or in textual repr: finishMinting()
336 function finishMinting() external returns (bool);
337}
338
339/// @title Unique extensions for ERC721.
340/// @dev the ERC-165 identifier for this interface is 0xd74d154f
341interface ERC721UniqueExtensions is Dummy, ERC165 {
342 /// @notice Transfer ownership of an NFT
343 /// @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 owner
346 /// @param tokenId The NFT to transfer
347 /// @dev EVM selector for this function is: 0xa9059cbb,
348 /// or in textual repr: transfer(address,uint256)
349 function transfer(address to, uint256 tokenId) external;
350
351 /// @notice Burns a specific ERC721 token.
352 /// @dev Throws unless `msg.sender` is the current owner or an authorized
353 /// operator for this NFT. Throws if `from` is not the current owner. Throws
354 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
355 /// @param from The current owner of the NFT
356 /// @param tokenId The NFT to transfer
357 /// @dev EVM selector for this function is: 0x79cc6790,
358 /// or in textual repr: burnFrom(address,uint256)
359 function burnFrom(address from, uint256 tokenId) external;
360
361 /// @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);
365
366 /// @notice Function to mint multiple tokens.
367 /// @dev `tokenIds` should be an array of consecutive numbers and first number
368 /// should be obtained with `nextTokenId` method
369 /// @param to The new owner
370 /// @param tokenIds IDs of the minted NFTs
371 /// @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 external
375 returns (bool);
376
377 /// @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 consecutive
379 /// numbers and first number should be obtained with `nextTokenId` method
380 /// @param to The new owner
381 /// @param tokens array of pairs of token ID and token URI for minted tokens
382 /// @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 external
386 returns (bool);
387}
388
389/// @dev anonymous struct
390struct Tuple8 {
391 uint256 field_0;
392 string field_1;
393}
394
395/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
396/// @dev See https://eips.ethereum.org/EIPS/eip-721
397/// @dev the ERC-165 identifier for this interface is 0x780e9d63
398interface ERC721Enumerable is Dummy, ERC165 {
399 /// @notice Enumerate valid NFTs
400 /// @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);
406
407 /// @dev Not implemented
408 /// @dev EVM selector for this function is: 0x2f745c59,
409 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
410 function tokenOfOwnerByIndex(address owner, uint256 index)
411 external
412 view
413 returns (uint256);
414
415 /// @notice Count NFTs tracked by this contract
416 /// @return A count of valid NFTs tracked by this contract, where each one of
417 /// them has an assigned and queryable owner not equal to the zero address
418 /// @dev EVM selector for this function is: 0x18160ddd,
419 /// or in textual repr: totalSupply()
420 function totalSupply() external view returns (uint256);
421}
422
423/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
424/// @dev See https://eips.ethereum.org/EIPS/eip-721
425/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
426interface ERC721Metadata is Dummy, ERC165 {
427 /// @notice A descriptive name for a collection of NFTs in this contract
428 /// @dev EVM selector for this function is: 0x06fdde03,
429 /// or in textual repr: name()
430 function name() external view returns (string memory);
431
432 /// @notice An abbreviated name for NFTs in this contract
433 /// @dev EVM selector for this function is: 0x95d89b41,
434 /// or in textual repr: symbol()
435 function symbol() external view returns (string memory);
436
437 /// @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 suffix
443 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
444 ///
445 /// @return token's const_metadata
446 /// @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}
450
451/// @dev inlined interface
22interface ERC721Events {452interface ERC721Events {
23 event Transfer(453 event Transfer(
24 address indexed from,454 address indexed from,
37 );467 );
38}468}
39469
40// Inline470/// @title ERC-721 Non-Fungible Token Standard
41interface ERC721MintableEvents {471/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
42 event MintingFinished();472/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
43}
44
45// Selector: 41369377
46interface 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) 222d97fa
55 function setTokenPropertyPermission(
56 string memory key,
57 bool isMutable,
58 bool collectionAdmin,
59 bool tokenOwner
60 ) external;
61
62 // @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) 1752d67b
69 function setProperty(
70 uint256 tokenId,
71 string memory key,
72 bytes memory value
73 ) external;
74
75 // @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) 066111d1
81 function deleteProperty(uint256 tokenId, string memory key) external;
82
83 // @notice Get token property value.
84 // @dev Throws error if key not found
85 // @param tokenId ID of the token.
86 // @param key Property key.
87 // @return Property value bytes
88 //
89 // Selector: property(uint256,string) 7228c327
90 function property(uint256 tokenId, string memory key)
91 external
92 view
93 returns (bytes memory);
94}
95
96// Selector: 42966c68
97interface ERC721Burnable is Dummy, ERC165 {
98 // @notice Burns a specific ERC721 token.
99 // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
100 // operator of the current owner.
101 // @param tokenId The NFT to approve
102 //
103 // Selector: burn(uint256) 42966c68
104 function burn(uint256 tokenId) external;
105}
106
107// Selector: 58800161
108interface 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 owner
110 // @dev NFTs assigned to the zero address are considered invalid, and this475 /// @dev NFTs assigned to the zero address are considered invalid, and this
111 // 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 balance
113 // @return The number of NFTs owned by `owner`, possibly zero478 /// @return The number of NFTs owned by `owner`, possibly zero
114 //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);
117482
118 // @notice Find the owner of an NFT483 /// @notice Find the owner of an NFT
119 // @dev NFTs assigned to zero address are considered invalid, and queries484 /// @dev NFTs assigned to zero address are considered invalid, and queries
120 // about them do throw.485 /// about them do throw.
121 // @param tokenId The identifier for an NFT486 /// @param tokenId The identifier for an NFT
122 // @return The address of the owner of the NFT487 /// @return The address of the owner of the NFT
123 //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);
126491
127 // @dev Not implemented492 /// @dev Not implemented
128 //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 data
135 ) external;500 ) external;
136501
137 // @dev Not implemented502 /// @dev Not implemented
138 //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 tokenId
144 ) external;509 ) external;
145510
146 // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE511 /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
147 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE512 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
148 // THEY MAY BE PERMANENTLY LOST513 /// THEY MAY BE PERMANENTLY LOST
149 // @dev Throws unless `msg.sender` is the current owner or an authorized514 /// @dev Throws unless `msg.sender` is the current owner or an authorized
150 // 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. Throws
151 // 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 NFT
153 // @param to The new owner518 /// @param to The new owner
154 // @param tokenId The NFT to transfer519 /// @param tokenId The NFT to transfer
155 // @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 tokenId
162 ) external;526 ) external;
163527
164 // @notice Set or reaffirm the approved address for an NFT528 /// @notice Set or reaffirm the approved address for an NFT
165 // @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 authorized
167 // 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 controller
169 // @param tokenId The NFT to approve533 /// @param tokenId The NFT to approve
170 //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;
173537
174 // @dev Not implemented538 /// @dev Not implemented
175 //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;
178542
179 // @dev Not implemented543 /// @dev Not implemented
180 //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);
183547
184 // @dev Not implemented548 /// @dev Not implemented
185 //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 external
189 view553 view
190 returns (address);554 returns (address);
191}555}
192
193// Selector: 5b5e139f
194interface ERC721Metadata is Dummy, ERC165 {
195 // @notice A descriptive name for a collection of NFTs in this contract
196 //
197 // Selector: name() 06fdde03
198 function name() external view returns (string memory);
199
200 // @notice An abbreviated name for NFTs in this contract
201 //
202 // Selector: symbol() 95d89b41
203 function symbol() external view returns (string memory);
204
205 // @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 suffix
211 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
212 //
213 // @return token's const_metadata
214 //
215 // Selector: tokenURI(uint256) c87b56dd
216 function tokenURI(uint256 tokenId) external view returns (string memory);
217}
218
219// Selector: 68ccfe89
220interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
221 // Selector: mintingFinished() 05d2035b
222 function mintingFinished() external view returns (bool);
223
224 // @notice Function to mint token.
225 // @dev `tokenId` should be obtained with `nextTokenId` method,
226 // unlike standard, you can't specify it manually
227 // @param to The new owner
228 // @param tokenId ID of the minted NFT
229 //
230 // Selector: mint(address,uint256) 40c10f19
231 function mint(address to, uint256 tokenId) external returns (bool);
232
233 // @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 manually
236 // @param to The new owner
237 // @param tokenId ID of the minted NFT
238 // @param tokenUri Token URI that would be stored in the NFT properties
239 //
240 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
241 function mintWithTokenURI(
242 address to,
243 uint256 tokenId,
244 string memory tokenUri
245 ) external returns (bool);
246
247 // @dev Not implemented
248 //
249 // Selector: finishMinting() 7d64bcb4
250 function finishMinting() external returns (bool);
251}
252
253// Selector: 6cf113cd
254interface 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) 2f073f66
261 function setCollectionProperty(string memory key, bytes memory value)
262 external;
263
264 // Delete collection property.
265 //
266 // @param key Property key.
267 //
268 // Selector: deleteCollectionProperty(string) 7b7debce
269 function deleteCollectionProperty(string memory key) external;
270
271 // 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) cf24fd6d
279 function collectionProperty(string memory key)
280 external
281 view
282 returns (bytes memory);
283
284 // 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) 7623402e
291 function setCollectionSponsor(address sponsor) external;
292
293 // Collection sponsorship confirmation.
294 //
295 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
296 //
297 // Selector: confirmCollectionSponsorship() 3c50e97a
298 function confirmCollectionSponsorship() external;
299
300 // 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) 6a3841db
312 function setCollectionLimit(string memory limit, uint32 value) external;
313
314 // 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) 993b7fba
323 function setCollectionLimit(string memory limit, bool value) external;
324
325 // Get contract address.
326 //
327 // Selector: contractAddress() f6b4dfb4
328 function contractAddress() external view returns (address);
329
330 // Add collection admin by substrate address.
331 // @param new_admin Substrate administrator address.
332 //
333 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
334 function addCollectionAdminSubstrate(uint256 newAdmin) external;
335
336 // Remove collection admin by substrate address.
337 // @param admin Substrate administrator address.
338 //
339 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
340 function removeCollectionAdminSubstrate(uint256 admin) external;
341
342 // Add collection admin.
343 // @param new_admin Address of the added administrator.
344 //
345 // Selector: addCollectionAdmin(address) 92e462c7
346 function addCollectionAdmin(address newAdmin) external;
347
348 // Remove collection admin.
349 //
350 // @param new_admin Address of the removed administrator.
351 //
352 // Selector: removeCollectionAdmin(address) fafd7b42
353 function removeCollectionAdmin(address admin) external;
354
355 // Toggle accessibility of collection nesting.
356 //
357 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
358 //
359 // Selector: setCollectionNesting(bool) 112d4586
360 function setCollectionNesting(bool enable) external;
361
362 // 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[]) 64872396
368 function setCollectionNesting(bool enable, address[] memory collections)
369 external;
370
371 // Set the collection access method.
372 // @param mode Access mode
373 // 0 for Normal
374 // 1 for AllowList
375 //
376 // Selector: setCollectionAccess(uint8) 41835d4c
377 function setCollectionAccess(uint8 mode) external;
378
379 // Add the user to the allowed list.
380 //
381 // @param user Address of a trusted user.
382 //
383 // Selector: addToCollectionAllowList(address) 67844fe6
384 function addToCollectionAllowList(address user) external;
385
386 // Remove the user from the allowed list.
387 //
388 // @param user Address of a removed user.
389 //
390 // Selector: removeFromCollectionAllowList(address) 85c51acb
391 function removeFromCollectionAllowList(address user) external;
392
393 // Switch permission for minting.
394 //
395 // @param mode Enable if "true".
396 //
397 // Selector: setCollectionMintMode(bool) 00018e84
398 function setCollectionMintMode(bool mode) external;
399
400 // Check that account is the owner or admin of the collection
401 //
402 // @param user account to verify
403 // @return "true" if account is the owner or admin
404 //
405 // Selector: verifyOwnerOrAdmin(address) c2282493
406 function verifyOwnerOrAdmin(address user) external view returns (bool);
407
408 // Returns collection type
409 //
410 // @return `Fungible` or `NFT` or `ReFungible`
411 //
412 // Selector: uniqueCollectionType() d34b55b8
413 function uniqueCollectionType() external returns (string memory);
414}
415
416// Selector: 780e9d63
417interface ERC721Enumerable is Dummy, ERC165 {
418 // @notice Enumerate valid NFTs
419 // @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) 4f6ccce7
424 function tokenByIndex(uint256 index) external view returns (uint256);
425
426 // @dev Not implemented
427 //
428 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
429 function tokenOfOwnerByIndex(address owner, uint256 index)
430 external
431 view
432 returns (uint256);
433
434 // @notice Count NFTs tracked by this contract
435 // @return A count of valid NFTs tracked by this contract, where each one of
436 // them has an assigned and queryable owner not equal to the zero address
437 //
438 // Selector: totalSupply() 18160ddd
439 function totalSupply() external view returns (uint256);
440}
441
442// Selector: d74d154f
443interface ERC721UniqueExtensions is Dummy, ERC165 {
444 // @notice Transfer ownership of an NFT
445 // @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 owner
448 // @param tokenId The NFT to transfer
449 // @param _value Not used for an NFT
450 //
451 // Selector: transfer(address,uint256) a9059cbb
452 function transfer(address to, uint256 tokenId) external;
453
454 // @notice Burns a specific ERC721 token.
455 // @dev Throws unless `msg.sender` is the current owner or an authorized
456 // operator for this NFT. Throws if `from` is not the current owner. Throws
457 // if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
458 // @param from The current owner of the NFT
459 // @param tokenId The NFT to transfer
460 // @param _value Not used for an NFT
461 //
462 // Selector: burnFrom(address,uint256) 79cc6790
463 function burnFrom(address from, uint256 tokenId) external;
464
465 // @notice Returns next free NFT ID.
466 //
467 // Selector: nextTokenId() 75794a3c
468 function nextTokenId() external view returns (uint256);
469
470 // @notice Function to mint multiple tokens.
471 // @dev `tokenIds` should be an array of consecutive numbers and first number
472 // should be obtained with `nextTokenId` method
473 // @param to The new owner
474 // @param tokenIds IDs of the minted NFTs
475 //
476 // Selector: mintBulk(address,uint256[]) 44a9945e
477 function mintBulk(address to, uint256[] memory tokenIds)
478 external
479 returns (bool);
480
481 // @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 consecutive
483 // numbers and first number should be obtained with `nextTokenId` method
484 // @param to The new owner
485 // @param tokens array of pairs of token ID and token URI for minted tokens
486 //
487 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
488 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
489 external
490 returns (bool);
491}
492556
493interface UniqueNFT is557interface UniqueNFT is
494 Dummy,558 Dummy,
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
5
6// Anonymous struct
7struct Tuple0 {
8 uint256 field_0;
9 string field_1;
10}
115
12// Common stubs holder6/// @dev common stubs holder
13interface Dummy {7interface Dummy {
148
15}9}
18 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
19}13}
2014
21// 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 0x41369377
17interface 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 tokenOwner
31 ) external;
32
33 /// @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 value
44 ) external;
45
46 /// @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;
53
54 /// @notice Get token property value.
55 /// @dev Throws error if key not found
56 /// @param tokenId ID of the token.
57 /// @param key Property key.
58 /// @return Property value bytes
59 /// @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 external
63 view
64 returns (bytes memory);
65}
66
67/// @title A contract that allows you to work with collections.
68/// @dev the ERC-165 identifier for this interface is 0xe54be640
69interface 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;
78
79 /// 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;
85
86 /// 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 external
96 view
97 returns (bytes memory);
98
99 /// 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;
107
108 /// 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;
116
117 /// @dev EVM selector for this function is: 0x058ac185,
118 /// or in textual repr: hasCollectionPendingSponsor()
119 function hasCollectionPendingSponsor() external view returns (bool);
120
121 /// 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;
127
128 /// Remove collection sponsor.
129 /// @dev EVM selector for this function is: 0x6e0326a3,
130 /// or in textual repr: removeCollectionSponsor()
131 function removeCollectionSponsor() external;
132
133 /// 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);
139
140 /// 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;
153
154 /// 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;
164
165 /// 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);
169
170 /// 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;
175
176 /// 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;
181
182 /// 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;
187
188 /// 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;
194
195 /// 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;
201
202 /// 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;
210
211 /// Set the collection access method.
212 /// @param mode Access mode
213 /// 0 for Normal
214 /// 1 for AllowList
215 /// @dev EVM selector for this function is: 0x41835d4c,
216 /// or in textual repr: setCollectionAccess(uint8)
217 function setCollectionAccess(uint8 mode) external;
218
219 /// 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;
225
226 /// 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;
232
233 /// 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;
239
240 /// Check that account is the owner or admin of the collection
241 ///
242 /// @param user account to verify
243 /// @return "true" if account is the owner or admin
244 /// @dev EVM selector for this function is: 0x9811b0c7,
245 /// or in textual repr: isOwnerOrAdmin(address)
246 function isOwnerOrAdmin(address user) external view returns (bool);
247
248 /// Check that substrate account is the owner or admin of the collection
249 ///
250 /// @param user account to verify
251 /// @return "true" if account is the owner or admin
252 /// @dev EVM selector for this function is: 0x68910e00,
253 /// or in textual repr: isOwnerOrAdminSubstrate(uint256)
254 function isOwnerOrAdminSubstrate(uint256 user) external view returns (bool);
255
256 /// Returns collection type
257 ///
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);
262
263 /// Changes collection owner to another account
264 ///
265 /// @dev Owner can be changed only by current owner
266 /// @param newOwner new owner account
267 /// @dev EVM selector for this function is: 0x13af4035,
268 /// or in textual repr: setOwner(address)
269 function setOwner(address newOwner) external;
270
271 /// Changes collection owner to another substrate account
272 ///
273 /// @dev Owner can be changed only by current owner
274 /// @param newOwner new owner substrate account
275 /// @dev EVM selector for this function is: 0xb212138f,
276 /// or in textual repr: setOwnerSubstrate(uint256)
277 function setOwnerSubstrate(uint256 newOwner) external;
278}
279
280/// @dev anonymous struct
281struct Tuple17 {
282 address field_0;
283 uint256 field_1;
284}
285
286/// @title ERC721 Token that can be irreversibly burned (destroyed).
287/// @dev the ERC-165 identifier for this interface is 0x42966c68
288interface ERC721Burnable is Dummy, ERC165 {
289 /// @notice Burns a specific ERC721 token.
290 /// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
291 /// operator of the current owner.
292 /// @param tokenId The RFT to approve
293 /// @dev EVM selector for this function is: 0x42966c68,
294 /// or in textual repr: burn(uint256)
295 function burn(uint256 tokenId) external;
296}
297
298/// @dev inlined interface
299interface ERC721MintableEvents {
300 event MintingFinished();
301}
302
303/// @title ERC721 minting logic.
304/// @dev the ERC-165 identifier for this interface is 0x68ccfe89
305interface 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);
309
310 /// @notice Function to mint token.
311 /// @dev `tokenId` should be obtained with `nextTokenId` method,
312 /// unlike standard, you can't specify it manually
313 /// @param to The new owner
314 /// @param tokenId ID of the minted RFT
315 /// @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);
318
319 /// @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 manually
322 /// @param to The new owner
323 /// @param tokenId ID of the minted RFT
324 /// @param tokenUri Token URI that would be stored in the RFT properties
325 /// @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 tokenUri
331 ) external returns (bool);
332
333 /// @dev Not implemented
334 /// @dev EVM selector for this function is: 0x7d64bcb4,
335 /// or in textual repr: finishMinting()
336 function finishMinting() external returns (bool);
337}
338
339/// @title Unique extensions for ERC721.
340/// @dev the ERC-165 identifier for this interface is 0x7c3bef89
341interface ERC721UniqueExtensions is Dummy, ERC165 {
342 /// @notice Transfer ownership of an RFT
343 /// @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 owner
347 /// @param tokenId The RFT to transfer
348 /// @dev EVM selector for this function is: 0xa9059cbb,
349 /// or in textual repr: transfer(address,uint256)
350 function transfer(address to, uint256 tokenId) external;
351
352 /// @notice Burns a specific ERC721 token.
353 /// @dev Throws unless `msg.sender` is the current owner or an authorized
354 /// operator for this RFT. Throws if `from` is not the current owner. Throws
355 /// 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 RFT
358 /// @param tokenId The RFT to transfer
359 /// @dev EVM selector for this function is: 0x79cc6790,
360 /// or in textual repr: burnFrom(address,uint256)
361 function burnFrom(address from, uint256 tokenId) external;
362
363 /// @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);
367
368 /// @notice Function to mint multiple tokens.
369 /// @dev `tokenIds` should be an array of consecutive numbers and first number
370 /// should be obtained with `nextTokenId` method
371 /// @param to The new owner
372 /// @param tokenIds IDs of the minted RFTs
373 /// @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 external
377 returns (bool);
378
379 /// @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 consecutive
381 /// numbers and first number should be obtained with `nextTokenId` method
382 /// @param to The new owner
383 /// @param tokens array of pairs of token ID and token URI for minted tokens
384 /// @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 external
388 returns (bool);
389
390 /// Returns EVM address for refungible token
391 ///
392 /// @param token ID of the token
393 /// @dev EVM selector for this function is: 0xab76fac6,
394 /// or in textual repr: tokenContractAddress(uint256)
395 function tokenContractAddress(uint256 token)
396 external
397 view
398 returns (address);
399}
400
401/// @dev anonymous struct
402struct Tuple8 {
403 uint256 field_0;
404 string field_1;
405}
406
407/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
408/// @dev See https://eips.ethereum.org/EIPS/eip-721
409/// @dev the ERC-165 identifier for this interface is 0x780e9d63
410interface ERC721Enumerable is Dummy, ERC165 {
411 /// @notice Enumerate valid RFTs
412 /// @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);
418
419 /// Not implemented
420 /// @dev EVM selector for this function is: 0x2f745c59,
421 /// or in textual repr: tokenOfOwnerByIndex(address,uint256)
422 function tokenOfOwnerByIndex(address owner, uint256 index)
423 external
424 view
425 returns (uint256);
426
427 /// @notice Count RFTs tracked by this contract
428 /// @return A count of valid RFTs tracked by this contract, where each one of
429 /// them has an assigned and queryable owner not equal to the zero address
430 /// @dev EVM selector for this function is: 0x18160ddd,
431 /// or in textual repr: totalSupply()
432 function totalSupply() external view returns (uint256);
433}
434
435/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
436interface ERC721Metadata is Dummy, ERC165 {
437 /// @notice A descriptive name for a collection of RFTs in this contract
438 /// @dev EVM selector for this function is: 0x06fdde03,
439 /// or in textual repr: name()
440 function name() external view returns (string memory);
441
442 /// @notice An abbreviated name for RFTs in this contract
443 /// @dev EVM selector for this function is: 0x95d89b41,
444 /// or in textual repr: symbol()
445 function symbol() external view returns (string memory);
446
447 /// @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 suffix
453 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
454 ///
455 /// @return token's const_metadata
456 /// @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}
460
461/// @dev inlined interface
22interface ERC721Events {462interface ERC721Events {
23 event Transfer(463 event Transfer(
24 address indexed from,464 address indexed from,
37 );477 );
38}478}
39479
40// Inline480/// @title ERC-721 Non-Fungible Token Standard
41interface ERC721MintableEvents {481/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
42 event MintingFinished();482/// @dev the ERC-165 identifier for this interface is 0x58800161
43}
44
45// Selector: 41369377
46interface 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) 222d97fa
55 function setTokenPropertyPermission(
56 string memory key,
57 bool isMutable,
58 bool collectionAdmin,
59 bool tokenOwner
60 ) external;
61
62 // @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) 1752d67b
69 function setProperty(
70 uint256 tokenId,
71 string memory key,
72 bytes memory value
73 ) external;
74
75 // @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) 066111d1
81 function deleteProperty(uint256 tokenId, string memory key) external;
82
83 // @notice Get token property value.
84 // @dev Throws error if key not found
85 // @param tokenId ID of the token.
86 // @param key Property key.
87 // @return Property value bytes
88 //
89 // Selector: property(uint256,string) 7228c327
90 function property(uint256 tokenId, string memory key)
91 external
92 view
93 returns (bytes memory);
94}
95
96// Selector: 42966c68
97interface ERC721Burnable is Dummy, ERC165 {
98 // @notice Burns a specific ERC721 token.
99 // @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
100 // operator of the current owner.
101 // @param tokenId The RFT to approve
102 //
103 // Selector: burn(uint256) 42966c68
104 function burn(uint256 tokenId) external;
105}
106
107// Selector: 58800161
108interface 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 owner
110 // @dev RFTs assigned to the zero address are considered invalid, and this485 /// @dev RFTs assigned to the zero address are considered invalid, and this
111 // 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 balance
113 // @return The number of RFTs owned by `owner`, possibly zero488 /// @return The number of RFTs owned by `owner`, possibly zero
114 //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);
117492
118 // @notice Find the owner of an RFT493 /// @notice Find the owner of an RFT
119 // @dev RFTs assigned to zero address are considered invalid, and queries494 /// @dev RFTs assigned to zero address are considered invalid, and queries
120 // about them do throw.495 /// about them do throw.
121 // Returns special 0xffffffffffffffffffffffffffffffffffffffff address for496 /// Returns special 0xffffffffffffffffffffffffffffffffffffffff address for
122 // 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 RFT
124 // @return The address of the owner of the RFT499 /// @return The address of the owner of the RFT
125 //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);
128503
129 // @dev Not implemented504 /// @dev Not implemented
130 //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 data
137 ) external;512 ) external;
138513
139 // @dev Not implemented514 /// @dev Not implemented
140 //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 tokenId
146 ) external;521 ) external;
147522
148 // @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE523 /// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE
149 // TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE524 /// TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
150 // THEY MAY BE PERMANENTLY LOST525 /// THEY MAY BE PERMANENTLY LOST
151 // @dev Throws unless `msg.sender` is the current owner or an authorized526 /// @dev Throws unless `msg.sender` is the current owner or an authorized
152 // 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. Throws
153 // 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 NFT
156 // @param to The new owner531 /// @param to The new owner
157 // @param tokenId The NFT to transfer532 /// @param tokenId The NFT to transfer
158 // @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 tokenId
165 ) external;539 ) external;
166540
167 // @dev Not implemented541 /// @dev Not implemented
168 //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;
171545
172 // @dev Not implemented546 /// @dev Not implemented
173 //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;
176550
177 // @dev Not implemented551 /// @dev Not implemented
178 //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);
181555
182 // @dev Not implemented556 /// @dev Not implemented
183 //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 external
187 view561 view
188 returns (address);562 returns (address);
189}563}
190
191// Selector: 5b5e139f
192interface ERC721Metadata is Dummy, ERC165 {
193 // @notice A descriptive name for a collection of RFTs in this contract
194 //
195 // Selector: name() 06fdde03
196 function name() external view returns (string memory);
197
198 // @notice An abbreviated name for RFTs in this contract
199 //
200 // Selector: symbol() 95d89b41
201 function symbol() external view returns (string memory);
202
203 // @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 suffix
209 // otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
210 //
211 // @return token's const_metadata
212 //
213 // Selector: tokenURI(uint256) c87b56dd
214 function tokenURI(uint256 tokenId) external view returns (string memory);
215}
216
217// Selector: 68ccfe89
218interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
219 // Selector: mintingFinished() 05d2035b
220 function mintingFinished() external view returns (bool);
221
222 // @notice Function to mint token.
223 // @dev `tokenId` should be obtained with `nextTokenId` method,
224 // unlike standard, you can't specify it manually
225 // @param to The new owner
226 // @param tokenId ID of the minted RFT
227 //
228 // Selector: mint(address,uint256) 40c10f19
229 function mint(address to, uint256 tokenId) external returns (bool);
230
231 // @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 manually
234 // @param to The new owner
235 // @param tokenId ID of the minted RFT
236 // @param tokenUri Token URI that would be stored in the RFT properties
237 //
238 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
239 function mintWithTokenURI(
240 address to,
241 uint256 tokenId,
242 string memory tokenUri
243 ) external returns (bool);
244
245 // @dev Not implemented
246 //
247 // Selector: finishMinting() 7d64bcb4
248 function finishMinting() external returns (bool);
249}
250
251// Selector: 6cf113cd
252interface 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) 2f073f66
259 function setCollectionProperty(string memory key, bytes memory value)
260 external;
261
262 // Delete collection property.
263 //
264 // @param key Property key.
265 //
266 // Selector: deleteCollectionProperty(string) 7b7debce
267 function deleteCollectionProperty(string memory key) external;
268
269 // 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) cf24fd6d
277 function collectionProperty(string memory key)
278 external
279 view
280 returns (bytes memory);
281
282 // 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) 7623402e
289 function setCollectionSponsor(address sponsor) external;
290
291 // Collection sponsorship confirmation.
292 //
293 // @dev After setting the sponsor for the collection, it must be confirmed with this function.
294 //
295 // Selector: confirmCollectionSponsorship() 3c50e97a
296 function confirmCollectionSponsorship() external;
297
298 // 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) 6a3841db
310 function setCollectionLimit(string memory limit, uint32 value) external;
311
312 // 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) 993b7fba
321 function setCollectionLimit(string memory limit, bool value) external;
322
323 // Get contract address.
324 //
325 // Selector: contractAddress() f6b4dfb4
326 function contractAddress() external view returns (address);
327
328 // Add collection admin by substrate address.
329 // @param new_admin Substrate administrator address.
330 //
331 // Selector: addCollectionAdminSubstrate(uint256) 5730062b
332 function addCollectionAdminSubstrate(uint256 newAdmin) external;
333
334 // Remove collection admin by substrate address.
335 // @param admin Substrate administrator address.
336 //
337 // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9
338 function removeCollectionAdminSubstrate(uint256 admin) external;
339
340 // Add collection admin.
341 // @param new_admin Address of the added administrator.
342 //
343 // Selector: addCollectionAdmin(address) 92e462c7
344 function addCollectionAdmin(address newAdmin) external;
345
346 // Remove collection admin.
347 //
348 // @param new_admin Address of the removed administrator.
349 //
350 // Selector: removeCollectionAdmin(address) fafd7b42
351 function removeCollectionAdmin(address admin) external;
352
353 // Toggle accessibility of collection nesting.
354 //
355 // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
356 //
357 // Selector: setCollectionNesting(bool) 112d4586
358 function setCollectionNesting(bool enable) external;
359
360 // 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[]) 64872396
366 function setCollectionNesting(bool enable, address[] memory collections)
367 external;
368
369 // Set the collection access method.
370 // @param mode Access mode
371 // 0 for Normal
372 // 1 for AllowList
373 //
374 // Selector: setCollectionAccess(uint8) 41835d4c
375 function setCollectionAccess(uint8 mode) external;
376
377 // Add the user to the allowed list.
378 //
379 // @param user Address of a trusted user.
380 //
381 // Selector: addToCollectionAllowList(address) 67844fe6
382 function addToCollectionAllowList(address user) external;
383
384 // Remove the user from the allowed list.
385 //
386 // @param user Address of a removed user.
387 //
388 // Selector: removeFromCollectionAllowList(address) 85c51acb
389 function removeFromCollectionAllowList(address user) external;
390
391 // Switch permission for minting.
392 //
393 // @param mode Enable if "true".
394 //
395 // Selector: setCollectionMintMode(bool) 00018e84
396 function setCollectionMintMode(bool mode) external;
397
398 // Check that account is the owner or admin of the collection
399 //
400 // @param user account to verify
401 // @return "true" if account is the owner or admin
402 //
403 // Selector: verifyOwnerOrAdmin(address) c2282493
404 function verifyOwnerOrAdmin(address user) external view returns (bool);
405
406 // Returns collection type
407 //
408 // @return `Fungible` or `NFT` or `ReFungible`
409 //
410 // Selector: uniqueCollectionType() d34b55b8
411 function uniqueCollectionType() external returns (string memory);
412}
413
414// Selector: 780e9d63
415interface ERC721Enumerable is Dummy, ERC165 {
416 // @notice Enumerate valid RFTs
417 // @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) 4f6ccce7
422 function tokenByIndex(uint256 index) external view returns (uint256);
423
424 // Not implemented
425 //
426 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
427 function tokenOfOwnerByIndex(address owner, uint256 index)
428 external
429 view
430 returns (uint256);
431
432 // @notice Count RFTs tracked by this contract
433 // @return A count of valid RFTs tracked by this contract, where each one of
434 // them has an assigned and queryable owner not equal to the zero address
435 //
436 // Selector: totalSupply() 18160ddd
437 function totalSupply() external view returns (uint256);
438}
439
440// Selector: 7c3bef89
441interface ERC721UniqueExtensions is Dummy, ERC165 {
442 // @notice Transfer ownership of an RFT
443 // @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 owner
447 // @param tokenId The RFT to transfer
448 // @param _value Not used for an RFT
449 //
450 // Selector: transfer(address,uint256) a9059cbb
451 function transfer(address to, uint256 tokenId) external;
452
453 // @notice Burns a specific ERC721 token.
454 // @dev Throws unless `msg.sender` is the current owner or an authorized
455 // operator for this RFT. Throws if `from` is not the current owner. Throws
456 // 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 RFT
459 // @param tokenId The RFT to transfer
460 // @param _value Not used for an RFT
461 //
462 // Selector: burnFrom(address,uint256) 79cc6790
463 function burnFrom(address from, uint256 tokenId) external;
464
465 // @notice Returns next free RFT ID.
466 //
467 // Selector: nextTokenId() 75794a3c
468 function nextTokenId() external view returns (uint256);
469
470 // @notice Function to mint multiple tokens.
471 // @dev `tokenIds` should be an array of consecutive numbers and first number
472 // should be obtained with `nextTokenId` method
473 // @param to The new owner
474 // @param tokenIds IDs of the minted RFTs
475 //
476 // Selector: mintBulk(address,uint256[]) 44a9945e
477 function mintBulk(address to, uint256[] memory tokenIds)
478 external
479 returns (bool);
480
481 // @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 consecutive
483 // numbers and first number should be obtained with `nextTokenId` method
484 // @param to The new owner
485 // @param tokens array of pairs of token ID and token URI for minted tokens
486 //
487 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
488 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
489 external
490 returns (bool);
491
492 // Returns EVM address for refungible token
493 //
494 // @param token ID of the token
495 //
496 // Selector: tokenContractAddress(uint256) ab76fac6
497 function tokenContractAddress(uint256 token)
498 external
499 view
500 returns (address);
501}
502564
503interface UniqueRefungible is565interface UniqueRefungible is
504 Dummy,566 Dummy,
modifiedtests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
33
4pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;
55
6// Common stubs holder6/// @dev common stubs holder
7interface Dummy {7interface Dummy {
88
9}9}
12 function supportsInterface(bytes4 interfaceID) external view returns (bool);12 function supportsInterface(bytes4 interfaceID) external view returns (bool);
13}13}
1414
15// Inline15/// @dev the ERC-165 identifier for this interface is 0x5755c3f2
16interface 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);
20
21 /// @dev EVM selector for this function is: 0xd7f083f3,
22 /// or in textual repr: parentTokenId()
23 function parentTokenId() external view returns (uint256);
24}
25
26/// @dev the ERC-165 identifier for this interface is 0xab8deb37
27interface 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);
35
36 /// @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}
43
44/// @dev inlined interface
16interface 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}
2453
25// Selector: 042f110654/// @title Standard ERC20 token
26interface 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.md
29 external58/// @dev the ERC-165 identifier for this interface is 0x942e8b22
30 returns (bool);
31}
32
33// Selector: 5755c3f2
34interface ERC1633 is Dummy, ERC165 {
35 // Selector: parentToken() 80a54001
36 function parentToken() external view returns (address);
37
38 // Selector: parentTokenId() d7f083f3
39 function parentTokenId() external view returns (uint256);
40}
41
42// Selector: 942e8b22
43interface 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);
4864
49 // @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);
5369
54 // @dev Total number of tokens in existence70 /// @dev Total number of tokens in existence
55 //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);
5874
59 // @dev Not supported75 /// @dev Not supported
60 //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);
6379
64 // @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);
7086
71 // @dev Transfer token for a specified address87 /// @dev Transfer token for a specified address
72 // @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);
7793
78 // @dev Transfer tokens from one address to another94 /// @dev Transfer tokens from one address to another
79 // @param from address The address which you want to send tokens from95 /// @param from address The address which you want to send tokens from
80 // @param to address The address which you want to transfer to96 /// @param to address The address which you want to transfer to
81 // @param amount uint256 the amount of tokens to be transferred97 /// @param amount uint256 the amount of tokens to be transferred
82 //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 amount
88 ) external returns (bool);104 ) external returns (bool);
89105
90 // @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 old
92 // 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 this
93 // 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-263524729
95 // @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);
100116
101 // @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 external
109 view125 view
110 returns (uint256);126 returns (uint256);
111}127}
112
113// Selector: ab8deb37
114interface 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) 79cc6790
121 function burnFrom(address from, uint256 amount) external returns (bool);
122
123 // @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) d2418ca7
128 function repartition(uint256 amount) external returns (bool);
129}
130128
131interface UniqueRefungibleToken is129interface UniqueRefungibleToken is
132 Dummy,130 Dummy,
133 ERC165,131 ERC165,
134 ERC20,132 ERC20,
135 ERC20UniqueExtensions,133 ERC20UniqueExtensions,
136 ERC1633,134 ERC1633
137 ERC1633UniqueExtensions
138{}135{}
139136
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
94 });94 });
9595
96 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 });
9999
100 itWeb3('ERC721Metadata support', async ({web3}) => {100 itWeb3('ERC721Metadata support', async ({web3}) => {
modifiedtests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth
1515
16import {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';
2629
27describe('Add collection admins', () => {30describe('Add collection admins', () => {
7174
72 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 });
7881
79 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});
316
317describe('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.methods
323 .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 });
333
334 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.methods
339 .createNonfungibleCollection('A', 'B', 'C')
340 .send();
341 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
342 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
343
344 const cost = await recordEthFee(api, owner, () => collectionEvm.methods.setOwner(newOwner).send());
345 expect(cost < BigInt(0.2 * Number(UNIQUE)));
346 expect(cost > 0);
347 });
348
349 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.methods
354 .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});
363
364describe('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.methods
370 .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 });
383
384 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.methods
389 .createNonfungibleCollection('A', 'B', 'C')
390 .send();
391 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
392 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
393
394 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 });
398
399 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.methods
405 .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});
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
1import {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';
58
6describe('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 });
42
43 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);
50
51 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 });
62
63 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);
70
71 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 });
83
84 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');
97
98 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)));
102
103 const user = createEthAccount(web3);
104 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
105 expect(nextTokenId).to.be.equal('1');
106
107 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
108 expect(oldPermissions.mintMode).to.be.false;
109 expect(oldPermissions.access).to.be.equal('Normal');
110
111 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});
114
115 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
116 expect(newPermissions.mintMode).to.be.true;
117 expect(newPermissions.access).to.be.equal('AllowList');
118
119 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
120 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
121
122 {
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);
131
132 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 ]);
143
144 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
145 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);
146
147 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 });
152
153 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);
160
161 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');
169
170 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});
173
174 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
175 const sponsorBalanceBefore = (await getBalance(api, [sponsor.address]))[0];
176
177 {
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);
186
187 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 ]);
198
199 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
200 const sponsorBalanceAfter = (await getBalance(api, [sponsor.address]))[0];
201
202 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 });
207
208 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)));
226
227 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();
242
243 const events = normalizeEvents(result.events);
244 const address = collectionIdToAddress(collectionId);
245
246 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});
40265
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
23 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';
4528
46describe('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 });
38
39 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 });
48
47 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 });
5557
59 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 });
6588
89 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 });
99
100 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 });
111
112 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 });
121
122 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();
129
130 expect(result[0]).to.be.eq(flipper.options.address);
131 expect(result[1]).to.be.eq('0');
132 });
133
134 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();
143
144 expect(result[0]).to.be.eq(sponsor);
145 expect(result[1]).to.be.eq('0');
146 });
147
148 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);
153
154 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 });
162
163 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);
169
170 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 });
178
66 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);
183
184 const flipper = await deployFlipper(web3, owner);
185
186 const helpers = contractHelpers(web3, owner);
187
188 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();
189 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});
190
191 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});
192 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});
193
194 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
195 const callerBalanceBefore = await ethBalanceViaSub(api, caller);
196
197 await flipper.methods.flip().send({from: caller});
198 expect(await flipper.methods.getValue().call()).to.be.true;
199
200 // Balance should be taken from sponsor instead of caller
201 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 });
206
207 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');
68209
69 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);210 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
73214
74 const helpers = contractHelpers(web3, owner);215 const helpers = contractHelpers(web3, owner);
75216
76 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;217 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();
218
77 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;
80221
81 await transferBalanceToEth(api, alice, flipper.options.address);222 await transferBalanceToEth(api, alice, flipper.options.address);
82223
83 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);
85226
86 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;
88229
89 // Balance should be taken from flipper instead of caller230 // Balance should be taken from sponsor instead of caller
90 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 });
93236
94 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');
96
97 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);
99241
100 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});
105247
106 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;
110250
111 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});
112253
113 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');
115256
116 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;
118259
119 // Balance should be taken from flipper instead of caller260 // Balance should be taken from flipper instead of caller
120 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 });
123264
124 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}) => {
131272
132 const helpers = contractHelpers(web3, owner);273 const helpers = contractHelpers(web3, owner);
133274
134 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;
138277
139 await transferBalanceToEth(api, alice, flipper.options.address);278 await transferBalanceToEth(api, alice, flipper.options.address);
140279
150 });289 });
151290
152 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');
154
155 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);
158295
159 const flipper = await deployFlipper(web3, owner);296 const flipper = await deployFlipper(web3, owner);
160297
161 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});
164301
165 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;
169304
170 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});
171307
172 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);
174310
175 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;
177313
178 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 });
180319
181 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');
183
184 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);
187325
191 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});
193331
194 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;
198334
199 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});
200337
201 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');
203340
204 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);
207344
208 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);
210347
211 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 });
215352
219 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 });
223
224 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');
237
238 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)));
242
243 const user = createEthAccount(web3);
244 const nextTokenId = await collectionEvm.methods.nextTokenId().call();
245 expect(nextTokenId).to.be.equal('1');
246
247 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
248 expect(oldPermissions.mintMode).to.be.false;
249 expect(oldPermissions.access).to.be.equal('Normal');
250
251 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});
254
255 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
256 expect(newPermissions.mintMode).to.be.true;
257 expect(newPermissions.access).to.be.equal('AllowList');
258
259 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);
260 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);
261
262 {
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);
271
272 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 ]);
283
284 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);
285 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);
286
287 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 });
292
293 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)));
311
312 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();
327
328 const events = normalizeEvents(result.events);
329 const address = collectionIdToAddress(collectionId);
330
331 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});
350361
deletedtests/src/eth/fractionalizer/Fractionalizer.bindiffbeforeafterboth

no changes

modifiedtests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth
16 }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"));
2222
23 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);
138138
139 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);
deletedtests/src/eth/fractionalizer/FractionalizerAbi.jsondiffbeforeafterboth

no changes

modifiedtests/src/eth/fractionalizer/fractionalizer.test.tsdiffbeforeafterboth
224 });224 });
225 });225 });
226
227 itWeb3('Test fractionalizer NFT <-> RFT mapping ', async ({api, web3, privateKeyWrapper}) => {
228 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
229
230 const {fractionalizer, rftCollectionAddress} = await initFractionalizer(api, web3, privateKeyWrapper, owner);
231 const {rftTokenAddress, nftCollectionAddress, nftTokenId} = await createRFTToken(api, web3, owner, fractionalizer, 100n);
232
233 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();
238
239 const rft2nft = await fractionalizer.methods.rft2nftMapping(rftTokenAddress).call();
240 expect(rft2nft).to.be.like({
241 _collection: nftCollectionAddress,
242 _tokenId: nftTokenId,
243 });
244
245 const nft2rft = await fractionalizer.methods.nft2rftMapping(nftCollectionAddress, nftTokenId).call();
246 expect(nft2rft).to.be.eq(tokenId.toString());
247 });
226});248});
227249
228250
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License
15// 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/>.
1616
17import {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';
2122
22describe('Fungible: Information getting', () => {23describe('Fungible: Information getting', () => {
23 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {24 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {
58});59});
5960
60describe('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 });
68
69 const receiver = createEthAccount(web3);
70
71 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);
75
76 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 });
92
93 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 });
99
100 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
101 const receiver1 = createEthAccount(web3);
102 const receiver2 = createEthAccount(web3);
103 const receiver3 = createEthAccount(web3);
104
105 const collectionIdAddress = collectionIdToAddress(collection.collectionId);
106 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});
107 await submitTransactionAsync(alice, changeAdminTx);
108
109 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);
116
117 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 });
147
148 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 });
154
155 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);
159
160 const collectionIdAddress = collectionIdToAddress(collection.collectionId);
161 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});
162 await collectionContract.methods.mint(receiver, 100).send();
163
164 const result = await collectionContract.methods.burnFrom(receiver, 49).send({from: receiver});
165
166 const events = normalizeEvents(result.events);
167
168 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 ]);
179
180 const balance = await collectionContract.methods.balanceOf(receiver).call();
181 expect(balance).to.equal('51');
182 });
183
61 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({
modifiedtests/src/eth/fungibleAbi.jsondiffbeforeafterboth
150 "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]
322416
modifiedtests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth
39describe('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});
5255
53 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});
100103
101 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});
115121
116 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});
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
199 "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]
547614
modifiedtests/src/eth/reFungibleAbi.jsondiffbeforeafterboth
199 "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]
556623
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
655 await requirePallets(this, [Pallets.ReFungible]);655 await requirePallets(this, [Pallets.ReFungible]);
656 });656 });
657
658 itWeb3('Parent NFT token address and id', async ({api, web3, privateKeyWrapper}) => {
659 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
660
661 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);
666
667 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();
671
672 const rftTokenAddress = tokenIdToAddress(collectionId, refungibleTokenId);
673 const refungibleTokenContract = uniqueRefungibleToken(web3, rftTokenAddress, owner);
674 await refungibleTokenContract.methods.setParentNFT(nftCollectionAddress, nftTokenId).send();
675
676 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 });
682657
683 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);
693668
694 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});
modifiedtests/src/eth/reFungibleTokenAbi.jsondiffbeforeafterboth
125 "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" }
deletedtests/src/eth/refungibleAbi.jsondiffbeforeafterboth

no changes

modifiedtests/src/eth/sponsoring.test.tsdiffbeforeafterboth
15// 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/>.
1616
17import {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';
1919
20describe('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);
23
24 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});
3436
35 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;
39
40 await transferBalanceToEth(api, alice, flipper.options.address);
4141
42 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');
4444
45 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;
4747
48 // Balance should be taken from flipper instead of caller48 // Balance should be taken from flipper instead of caller
49 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 });
52
52 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);
54
55 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;
7070
71 await transferBalanceToEth(api, alice, collector.options.address);71 await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner});
72
73 const originalCollectorBalance = await web3.eth.getBalance(collector.options.address);72 await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor});
73
74 const originalSponsorBalance = await web3.eth.getBalance(sponsor);
74 expect(originalCollectorBalance).to.be.not.equal('0');75 expect(originalSponsorBalance).to.be.not.equal('0');
7576
76 await collector.methods.giveMoney().send({from: caller, value: '10000'});77 await collector.methods.giveMoney().send({from: caller, value: '10000'});
7778
78 // 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});
modifiedtests/src/eth/util/contractHelpersAbi.jsondiffbeforeafterboth
26 "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]
162237
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
99 }99 }
100}100}
101
102export function bigIntToSub(api: ApiPromise, number: bigint) {
103 return api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();
104}
101105
102export 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') {
modifiedtests/src/util/playgrounds/index.tsdiffbeforeafterboth
2// SPDX-License-Identifier: Apache-2.02// SPDX-License-Identifier: Apache-2.0
33
4import {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';
10
118
12class SilentLogger {9class SilentLogger {
19}16}
20
21
22class 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}
5817
59export 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 output
61 // (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;
addedtests/src/util/playgrounds/types.tsdiffbeforeafterboth

no changes

addedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth

no changes

modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
77
8import {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';
1313
14const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {14const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
15 const address = {} as ICrossAccountId;15 const address = {} as ICrossAccountId;
45};45};
46
47
48interface IChainEvent {
49 data: any;
50 method: string;
51 section: string;
52}
53
54interface ITransactionResult {
55 status: 'Fail' | 'Success';
56 result: {
57 events: {
58 event: IChainEvent
59 }[];
60 },
61 moduleError?: string;
62}
63
64interface 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}
73
74interface 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}
84
85interface 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}
92
93interface ICrossAccountId {
94 Substrate?: TSubstrateAccount;
95 Ethereum?: TEthereumAccount;
96}
97
98interface ICrossAccountIdLower {
99 substrate?: TSubstrateAccount;
100 ethereum?: TEthereumAccount;
101}
102
103interface 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}
114
115interface INestingPermissions {
116 tokenOwner?: boolean;
117 collectionAdmin?: boolean;
118 restricted?: number[] | null;
119}
120
121interface ICollectionPermissions {
122 access?: 'Normal' | 'AllowList';
123 mintMode?: boolean;
124 nesting?: INestingPermissions;
125}
126
127interface IProperty {
128 key: string;
129 value: string;
130}
131
132interface ITokenPropertyPermission {
133 key: string;
134 permission: {
135 mutable: boolean;
136 tokenOwner: boolean;
137 collectionAdmin: boolean;
138 }
139}
140
141interface IToken {
142 collectionId: number;
143 tokenId: number;
144}
145
146interface 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}
161
162interface IChainProperties {
163 ss58Format: number;
164 tokenDecimals: number[];
165 tokenSymbol: string[]
166}
167
168type TSubstrateAccount = string;
169type TEthereumAccount = string;
170type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';
171type TUniqueNetworks = 'opal' | 'quartz' | 'unique';
172type TSigner = IKeyringPair; // | 'string'
17346
174class UniqueUtil {47class UniqueUtil {
175 static transactionStatus = {48 static transactionStatus = {
439 return this.transactionStatus.FAIL;312 return this.transactionStatus.FAIL;
440 }313 }
441314
442 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 }
526
527 /**
528 * Get the normalized addresses added to the collection allow-list.
529 * @param collectionId ID of collection
530 * @example await getAllowList(1)
531 * @returns array of allow-listed addresses
532 */
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 }
653542
654 /**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 values
794 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 }
685
686 /**
687 * Adds an address to allow list
688 * @param signer keyring of signer
689 * @param collectionId ID of collection
690 * @param addressObj address to add to the allow list
691 * @param label extra label for log
692 * @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 );
701
702 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');
703 }
796704
797 /**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 }
2029
2030 async getAllowList() {
2031 return await this.helper.collection.getAllowList(this.collectionId);
2032 }
21212033
2122 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 }
2057
2058 async addToAllowList(signer: TSigner, addressObj: ICrossAccountId, label?: string) {
2059 return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj, label);
2060 }
21452061
2146 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);