git.delta.rocks / unique-network / refs/commits / 97d7053c9b0e

difftreelog

Merge branch 'develop' into feature/contract-sponsoring-modes

Igor Kozyrev2022-02-17parents: #e7ebf1d #71137c9.patch.diff
in: master

34 files changed

modifiedCargo.lockdiffbeforeafterboth
382382
383[[package]]383[[package]]
384name = "autocfg"384name = "autocfg"
385version = "1.0.1"385version = "1.1.0"
386source = "registry+https://github.com/rust-lang/crates.io-index"386source = "registry+https://github.com/rust-lang/crates.io-index"
387checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"387checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
388388
389[[package]]389[[package]]
390name = "backtrace"390name = "backtrace"
634634
635[[package]]635[[package]]
636name = "block-buffer"636name = "block-buffer"
637version = "0.10.1"637version = "0.10.2"
638source = "registry+https://github.com/rust-lang/crates.io-index"638source = "registry+https://github.com/rust-lang/crates.io-index"
639checksum = "03588e54c62ae6d763e2a80090d50353b785795361b4ff5b3bf0a5097fc31c0b"639checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
640dependencies = [640dependencies = [
641 "generic-array 0.14.5",641 "generic-array 0.14.5",
642]642]
10971097
1098[[package]]1098[[package]]
1099name = "core-foundation"1099name = "core-foundation"
1100version = "0.9.2"1100version = "0.9.3"
1101source = "registry+https://github.com/rust-lang/crates.io-index"1101source = "registry+https://github.com/rust-lang/crates.io-index"
1102checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"1102checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
1103dependencies = [1103dependencies = [
1104 "core-foundation-sys",1104 "core-foundation-sys",
1105 "libc",1105 "libc",
12291229
1230[[package]]1230[[package]]
1231name = "crc32fast"1231name = "crc32fast"
1232version = "1.3.1"1232version = "1.3.2"
1233source = "registry+https://github.com/rust-lang/crates.io-index"1233source = "registry+https://github.com/rust-lang/crates.io-index"
1234checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3"1234checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
1235dependencies = [1235dependencies = [
1236 "cfg-if 1.0.0",1236 "cfg-if 1.0.0",
1237]1237]
12881288
1289[[package]]1289[[package]]
1290name = "crypto-common"1290name = "crypto-common"
1291version = "0.1.1"1291version = "0.1.2"
1292source = "registry+https://github.com/rust-lang/crates.io-index"1292source = "registry+https://github.com/rust-lang/crates.io-index"
1293checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0"1293checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06"
1294dependencies = [1294dependencies = [
1295 "generic-array 0.14.5",1295 "generic-array 0.14.5",
1296]1296]
18981898
1899[[package]]1899[[package]]
1900name = "digest"1900name = "digest"
1901version = "0.10.1"1901version = "0.10.2"
1902source = "registry+https://github.com/rust-lang/crates.io-index"1902source = "registry+https://github.com/rust-lang/crates.io-index"
1903checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"1903checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837"
1904dependencies = [1904dependencies = [
1905 "block-buffer 0.10.1",1905 "block-buffer 0.10.2",
1906 "crypto-common",1906 "crypto-common",
1907 "generic-array 0.14.5",
1908]1907]
19091908
1910[[package]]1909[[package]]
32413240
3242[[package]]3241[[package]]
3243name = "httparse"3242name = "httparse"
3244version = "1.5.1"3243version = "1.6.0"
3245source = "registry+https://github.com/rust-lang/crates.io-index"3244source = "registry+https://github.com/rust-lang/crates.io-index"
3246checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"3245checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
32473246
3248[[package]]3247[[package]]
3249name = "httpdate"3248name = "httpdate"
46644663
4665[[package]]4664[[package]]
4666name = "memmap2"4665name = "memmap2"
4667version = "0.5.2"4666version = "0.5.3"
4668source = "registry+https://github.com/rust-lang/crates.io-index"4667source = "registry+https://github.com/rust-lang/crates.io-index"
4669checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d"4668checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f"
4670dependencies = [4669dependencies = [
4671 "libc",4670 "libc",
4672]4671]
8805source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.16#4aeb95f7f38fcd519e2628f32f79044a8fef99d5"8804source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.16#4aeb95f7f38fcd519e2628f32f79044a8fef99d5"
8806dependencies = [8805dependencies = [
8807 "impl-trait-for-tuples",8806 "impl-trait-for-tuples",
8808 "memmap2 0.5.2",8807 "memmap2 0.5.3",
8809 "parity-scale-codec",8808 "parity-scale-codec",
8810 "sc-chain-spec-derive",8809 "sc-chain-spec-derive",
8811 "sc-network",8810 "sc-network",
9912dependencies = [9911dependencies = [
9913 "cfg-if 1.0.0",9912 "cfg-if 1.0.0",
9914 "cpufeatures 0.2.1",9913 "cpufeatures 0.2.1",
9915 "digest 0.10.1",9914 "digest 0.10.2",
9916]9915]
99179916
9918[[package]]9917[[package]]
1164411643
11645[[package]]11644[[package]]
11646name = "unique-node"11645name = "unique-node"
11647version = "0.9.14"11646version = "0.9.16"
11648dependencies = [11647dependencies = [
11649 "cumulus-client-cli",11648 "cumulus-client-cli",
11650 "cumulus-client-collator",11649 "cumulus-client-collator",
modifiedDockerfile-parachaindiffbeforeafterboth
90 nvm install v15.5.0 && \90 nvm install v15.5.0 && \
91 nvm use v15.5.091 nvm use v15.5.0
9292
93RUN git clone https://github.com/PureStake/polkadot-launch -b jlm-use-para-id-in-specs93RUN git clone https://github.com/paritytech/polkadot-launch
9494
95RUN export NVM_DIR="$HOME/.nvm" && \95RUN export NVM_DIR="$HOME/.nvm" && \
96 [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \96 [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \
modifiedREADME.mddiffbeforeafterboth
2929
30Please see our [walk-thorugh instructions](doc/hackusama_walk_through.md) to try everything out!30Please see our [walk-thorugh instructions](doc/hackusama_walk_through.md) to try everything out!
3131
32## Hackusama Update
33
34During the Kusama Hackaphon the following changes were made:
35
36- Enabled Smart Contracts Pallet
37- Enabled integration between Smart Contracts and Unique Pallet (required special edition of RC4 Substrate version)
38- Fixed misc. bugs in Unique Pallet
39- Deployed Unique TestNet. Public node available at wss://unique.usetech.com, custom UI types - see below in this README.
40- New Features:
41 - Re-Fungible Token Mode
42 - Off-Chain Schema to store token image URLs
43 - Alternative economic model
44 - Allow Lists and Public Mint Permission
45- Use example: [SubstraPunks Game](https://github.com/usetech-llc/substrapunks), fully hosted on IPFS and Unique Testnet
46 Blockchain.
47
48## Application Development32## Application Development
4933
50If you are building an application that operates NFT tokens, use [this document](doc/application_development.md).34If you are building an application that operates NFT tokens, use [this document](doc/application_development.md).
5135
36
52## Building37## Building
5338
54Building Unique chain requires special versions of Rust and toolchain. We don't use the most recent versions of everything39Building Unique chain requires special versions of Rust and toolchain. We don't use the most recent versions of everything
571. Install Rust:421. Install Rust:
5843
59```bash44```bash
45sudo apt-get install git curl libssl-dev llvm pkg-config libclang-dev clang
60curl https://sh.rustup.rs -sSf | sh46curl https://sh.rustup.rs -sSf | sh
61sudo apt-get install libssl-dev pkg-config libclang-dev clang
62```47```
6348
642. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall <toolchain>`.492. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall <toolchain>`.
86cargo build --release71cargo build --release
87```72```
8873
89## Run74## Building as Parachain locally
9075
91You can start a development chain with:76Note: checkout this project and all related projects (see below) in the sibling folders (both under the same folder)
9277
93```bash
94cargo run -- --dev78### Polkadot launch utility
95```
9679
97Detailed logs may be shown by running the node with the following environment variables set:
98`RUST_LOG=debug RUST_BACKTRACE=1 cargo run -- --dev`.
99
100If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two
101validator nodes for Alice and Bob, who are the initial authorities of the genesis chain that have been endowed with
102testnet units. Give each node a name and expose them so they are listed on the Polkadot
103[telemetry site](https://telemetry.polkadot.io/#/Local%20Testnet). You'll need two terminal windows open.
104
105We'll start Alice's substrate node first on default TCP port 30333 with her chain database stored locally at
106`/tmp/alice`. The bootnode ID of her node is `QmQZ8TjTqeDj3ciwr93EJ95hxfDsb9pEYDizUAbWpigtQN`, which is generated from
107the `--node-key` value that we specify below:
108
109```bash
110cargo run -- \
111 --base-path /tmp/alice \
112 --chain=local \
113 --alice \
114 --node-key 0000000000000000000000000000000000000000000000000000000000000001 \
115 --telemetry-url ws://telemetry.polkadot.io:1024 \
116 --validator
117```80```
118
119In the second terminal, we'll start Bob's substrate node on a different TCP port of 30334, and with his chain database81git clone https://github.com/paritytech/polkadot-launch
120stored locally at `/tmp/bob`. We'll specify a value for the `--bootnodes` option that will connect his node to Alice's
121bootnode ID on TCP port 30333:
122
123```bash
124cargo run -- \
125 --base-path /tmp/bob \
126 --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/QmQZ8TjTqeDj3ciwr93EJ95hxfDsb9pEYDizUAbWpigtQN \
127 --chain=local \
128 --bob \
129 --port 30334 \
130 --telemetry-url ws://telemetry.polkadot.io:1024 \
131 --validator
132```82```
13383
134Additional CLI usage options are available and may be shown by running `cargo run -- --help`.
135
136## Building and Running as Parachain locally
137
138Rust toolchain: nightly-2021-11-11
139Note: checkout this project and polkadot project (see below) in the sibling folders (both under the same folder)
140
141### Build relay84### Build relay
14285
143```86```
144git clone https://github.com/paritytech/polkadot.git87git clone https://github.com/paritytech/polkadot.git
145cd polkadot88cd polkadot
146git checkout release-v0.9.989git checkout release-v0.9.16
147cargo build --release90cargo build --release
148```91```
14992
150### Build parachain93### Build Unique parachain
15194
152Run in the root of this project:95Run in the root of this project:
153```96```
154cargo --build97cargo build --release
155```98```
15699
157### Run 4-node Relay100### Build Acala parachain (optional, full config only)
158101
1591. Download `rococo-custom-4.json` chain spec here: https://substrate.dev/cumulus-workshop/shared/chainspecs/rococo-custom-4.json
1602. Use these instructions to launch 4 nodes: https://substrate.dev/cumulus-workshop/#/en/2-relay-chain/1-launch
161
162Example (Run in polkadot folder. Replace `12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on` with output from Alice node):
163```102```
164./target/release/polkadot --alice --validator --base-path ./cumulus_relay0 --chain rococo-custom-4.json --port 50555 --ws-port 9944103git clone https://github.com/AcalaNetwork/Acala
165./target/release/polkadot --bob --validator --base-path ./cumulus_relay1 --chain rococo-custom-4.json --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on --port 50556 --ws-port 9945104cd Acala
166./target/release/polkadot --charlie --validator --base-path ./cumulus_relay1 --chain rococo-custom-4.json --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on --port 50557 --ws-port 9946105git checkout 54db3acd409a0b787f116f20e163a3b24101ce38
167./target/release/polkadot --dave --validator --base-path ./cumulus_relay1 --chain rococo-custom-4.json --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWNLAmKcyee3oqSgTMthaQVXaAcXeo8RrGCzMfMVA3B5on --port 50558 --ws-port 9947106make build-release
168
169```107```
170108
1713. Export genesis state and runtime wasm from Unique parachain:109## Running as Parachain locally
172110
173Run from this project root:
174```111```
175./target/release/unique-collator export-genesis-state --parachain-id 2000 > ./resources/para-2000-genesis112./launch-testnet.sh
176./target/release/unique-collator export-genesis-wasm > ./resources/para-2000-wasm
177```113```
178114
1794. Run two parachain nodes:115Optional, full setup with Acala and Statemint
180
181Replace `12D3KooWN1ah2bFQSysEFnwZqcmcVpDDR8UedXyo6xfzV1zDNMNg` with Alice or Bob relay ID
182
183Run from this project root:
184```116```
185./target/release/unique-collator --alice --collator --force-authoring --base-path ./tmp/parachain-alice --parachain-id 2000 --port 40333 --ws-port 9844 -- --execution wasm --chain ../polkadot/rococo-custom-4.json --port 30343 --ws-port 9977117./launch-testnet-full.sh
186./target/release/unique-collator --bob --collator --force-authoring --parachain-id 2000 --base-path ./tmp/parachain/bob --port 40334 --ws-port 9845 -- --execution wasm --chain ../polkadot/rococo-custom-4.json --port 30344 --ws-port 9978 --bootnodes /ip4/127.0.0.1/tcp/50556/p2p/12D3KooWN1ah2bFQSysEFnwZqcmcVpDDR8UedXyo6xfzV1zDNMNg
187```118```
188119
1894. Reserve parachain ID as described here: https://substrate.dev/cumulus-workshop/#/en/2-relay-chain/2-reserve
190
1915. Register parachain in relay as described here: https://substrate.dev/cumulus-workshop/#/en/3-parachains/2-register
192
193
194## Run Integration Tests120## Run Integration Tests
195121
1961. Install all needed dependecies1221. Install all needed dependecies
204yarn test130yarn test
205```131```
206132
207## Benchmarks
208133
209First of all, add rust toolchain and make it default.
210```bash
211rustup target add wasm32-unknown-unknown --toolchain nightly-2021-11-11
212```
213
214Then in "/node/src" run build command below
215```bash
216cargo +nightly-2021-11-11 build --release --features runtime-benchmarks
217```
218
219Run benchmark
220```bash
221target/release/unique-collator benchmark --chain dev --pallet "pallet_unique" --extrinsic "*" --repeat 1
222```
223
224## UI custom types
225
226Moved to [runtime_types.json](./runtime_types.json).
227
228## Running Integration Tests
229
230See [tests/README.md](./tests/README.md).
231
232## Code Formatting134## Code Formatting
233135
234### Get formatter and linter settings into your branch (if you forked before they were introduced)
235```bash
236git cherry-pick -n 8ff77c21b0d30b2a4648fa35dbf61dfa9d3948a7
237```
238
239### Apply formatting and clippy fixes136### Apply formatting and clippy fixes
240```bash137```bash
241cargo clippy138cargo clippy
252cd tests && yarn eslint --ext .ts,.js src/149cd tests && yarn eslint --ext .ts,.js src/
253```150```
254151
255## Re-Enabling Ink! Contracts
256152
257Uncomment following lies:
2581. In node/rpc/Cargo.toml
259```
260# pallet-contracts-rpc = { version = "3.0", git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.9' }153## Karura token transfer
261```
262154
2632. In node/rpc/src/lib.rs155To get started, you need to open inbound and outbound hrmp channels.
264```
265// C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>,
266...
267// use pallet_contracts_rpc::{Contracts, ContractsApi};
268...
269// io.extend_with(ContractsApi::to_delegate(Contracts::new(client.clone())));
270156
157### Next, we need to register our asset at Karura.
271```158```
159assetRegistry -> registerForeignAsset(location, metadata)
160location:
161 V0(X2(Parent, Parachain(PARA_ID)))
162metadata:
163 name OPL
164 symbol OPL
165 decimals 18
166minimalBalance 1
167```
272168
2733. In runtime/Cargo.toml169### Next, we can send tokens from Opal to Karura:
274```170```
275 # 'pallet-contracts/std',171polkadotXcm -> reserveTransferAssets
276 # 'pallet-contracts-primitives/std',172dest:
277 # 'pallet-contracts-rpc-runtime-api/std',
278 # 'pallet-contract-helpers/std',173 V0(X2(Parent, Parachain(<KARURA_PARA_ID>)))
279...174beneficiary:
280 # [dependencies.pallet-contracts]175 X1(AccountId(Any, <ACCOUNT>))
281 # git = 'https://github.com/paritytech/substrate.git'176assets:
282 # default-features = false177 V1(Concrete(0,Here), Fungible(<AMOUNT>))
283 # branch = 'polkadot-v0.9.9'178feeAssetItem:
284 # version = '3.0.0'179 0
180weightLimit:
181 <LIMIT>
182```
285183
286 # [dependencies.pallet-contracts-primitives]184The result will be displayed in ChainState
287 # git = 'https://github.com/paritytech/substrate.git'
288 # default-features = false185tokens -> accounts
289 # branch = 'polkadot-v0.9.9'
290 # version = '3.0.0'
291186
292 # [dependencies.pallet-contracts-rpc-runtime-api]187### To send tokens from Karura to Opal:
293 # git = 'https://github.com/paritytech/substrate.git'
294 # default-features = false
295 # branch = 'polkadot-v0.9.9'
296 # version = '3.0.0'
297...
298 # pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' }
299```188```
189xtokens -> transfer
300190
3014. runtime/src/lib.rs
302```
303// use pallet_contracts::weights::WeightInfo;191currencyId:
304...
305// pub use pallet_timestamp::Call as TimestampCall;
306...
307// mod chain_extension;
308// use crate::chain_extension::{NFTExtension, Imbalance};
309...
310/*
311parameter_types! {
312 pub TombstoneDeposit: Balance = deposit(192 ForeingAsset
313 ...
314}
315*/
316...
317//pallet_contract_helpers::ContractSponsorshipHandler<Runtime>,
318...
319// impl pallet_contract_helpers::Config for Runtime {}
320...
321// Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>},
322...
323// ContractHelpers: pallet_contract_helpers::{Pallet, Call, Storage},
324...
325//pallet_contract_helpers::ContractHelpersExtension<Runtime>,
326...
327/*
328 impl pallet_contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash>193 <TOKEN_ID>
329 for Runtime
330 {
331 ...
332 }
333*/
334194
195amount:
196 <AMOUNT>
197dest:
198 V1
199 (
200 Parents:1,
201 X2(Parachain(<KARURA_PARA_ID>), AccountId(Any, <ACCOUNT>)
202 )
203destWeight:
204 <WEIGHT>
335```205```
336
modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
4use jsonrpc_core::{Error as RpcError, ErrorCode, Result};4use jsonrpc_core::{Error as RpcError, ErrorCode, Result};
5use jsonrpc_derive::rpc;5use jsonrpc_derive::rpc;
6use up_data_structs::{Collection, CollectionId, CollectionStats, TokenId};6use up_data_structs::{Collection, CollectionId, CollectionStats, TokenId};
7use sp_api::{BlockId, BlockT, ProvideRuntimeApi};7use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};
8use sp_blockchain::HeaderBackend;8use sp_blockchain::HeaderBackend;
9use up_rpc::UniqueApi as UniqueRuntimeApi;9use up_rpc::UniqueApi as UniqueRuntimeApi;
1010
134macro_rules! pass_method {134macro_rules! pass_method {
135 ($method_name:ident($($name:ident: $ty:ty),* $(,)?) -> $result:ty $(=> $mapper:expr)?) => {135 (
136 $method_name:ident($($name:ident: $ty:ty),* $(,)?) -> $result:ty $(=> $mapper:expr)?
137 $(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*
138 ) => {
136 fn $method_name(139 fn $method_name(
137 &self,140 &self,
142 ) -> Result<$result> {145 ) -> Result<$result> {
143 let api = self.client.runtime_api();146 let api = self.client.runtime_api();
144 let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));147 let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));
148 let _api_version = if let Ok(Some(api_version)) =
149 api.api_version::<dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>>(&at)
150 {
151 api_version
152 } else {
153 // unreachable for our runtime
154 return Err(RpcError {
155 code: ErrorCode::InvalidParams,
156 message: "Api is not available".into(),
157 data: None,
158 })
159 };
145160
146 let result = api.$method_name(&at, $($name),*).map_err(|e| RpcError {161 let result = $(if _api_version < $ver {
162 api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))
163 } else)*
164 { api.$method_name(&at, $($name),*) };
165
166 let result = result.map_err(|e| RpcError {
147 code: ErrorCode::ServerError(Error::RuntimeError.into()),167 code: ErrorCode::ServerError(Error::RuntimeError.into()),
148 message: "Unable to query".into(),168 message: "Unable to query".into(),
149 data: Some(format!("{:?}", e).into()),169 data: Some(format!("{:?}", e).into()),
169 pass_method!(account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>);189 pass_method!(account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>);
170 pass_method!(token_exists(collection: CollectionId, token: TokenId) -> bool);190 pass_method!(token_exists(collection: CollectionId, token: TokenId) -> bool);
171 pass_method!(token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>);191 pass_method!(
192 token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>;
193 changed_in 2, token_owner_before_version_2(collection, token) => |u| Some(u)
194 );
172 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);195 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);
173 pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);196 pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);
addeddoc/hackusama_update.mddiffbeforeafterboth

no changes

addeddoc/re-enable_ink_contracts.mddiffbeforeafterboth

no changes

addedlaunch-config-full.jsondiffbeforeafterboth

no changes

deletedlaunch-config-westend.jsondiffbeforeafterboth

no changes

modifiedlaunch-config.jsondiffbeforeafterboth
9 "rpcPort": 9843,9 "rpcPort": 9843,
10 "port": 30444,10 "port": 30444,
11 "flags": [11 "flags": [
12 "-lparachain::candidate_validation=debug"12 "-lparachain::candidate_validation=debug",
13 "-lxcm=trace"
13 ]14 ]
14 },15 },
15 {16 {
18 "rpcPort": 9854,19 "rpcPort": 9854,
19 "port": 30555,20 "port": 30555,
20 "flags": [21 "flags": [
21 "-lparachain::candidate_validation=debug"22 "-lparachain::candidate_validation=debug",
23 "-lxcm=trace"
22 ]24 ]
23 },25 },
24 {26 {
38 "flags": [40 "flags": [
39 "-lparachain::candidate_validation=debug"41 "-lparachain::candidate_validation=debug"
40 ]42 ]
41 }43 },
44 {
45 "name": "eve",
46 "wsPort": 9888,
47 "rpcPort": 9887,
48 "port": 30888,
49 "flags": [
50 "-lparachain::candidate_validation=debug"
51 ]
52 }
42 ],53 ],
43 "genesis": {54 "genesis": {
44 "runtime": {55 "runtime": {
67 "flags": [78 "flags": [
68 "--rpc-cors=all",79 "--rpc-cors=all",
69 "--unsafe-rpc-external",80 "--unsafe-rpc-external",
70 "--unsafe-ws-external"81 "--unsafe-ws-external",
82 "-lxcm=trace"
71 ]83 ]
72 },84 },
73 {85 {
78 "flags": [90 "flags": [
79 "--rpc-cors=all",91 "--rpc-cors=all",
80 "--unsafe-rpc-external",92 "--unsafe-rpc-external",
81 "--unsafe-ws-external"93 "--unsafe-ws-external",
94 "-lxcm=trace"
82 ]95 ]
83 }96 }
84 ]97 ]
deletedlaunch-test-env.shdiffbeforeafterboth

no changes

addedlaunch-testnet-full.shdiffbeforeafterboth

no changes

addedlaunch-testnet.shdiffbeforeafterboth

no changes

modifiednode/cli/Cargo.tomldiffbeforeafterboth
257license = 'All Rights Reserved'257license = 'All Rights Reserved'
258name = 'unique-node'258name = 'unique-node'
259repository = 'https://github.com/UniqueNetwork/unique-chain'259repository = 'https://github.com/UniqueNetwork/unique-chain'
260version = '0.9.14'260version = '0.9.16'
261261
262[[bin]]262[[bin]]
263name = 'unique-collator'263name = 'unique-collator'
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
14use up_data_structs::{14use up_data_structs::{
15 COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,15 COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,
16 MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, Pays, PostDispatchInfo,16 MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, Pays, PostDispatchInfo,
17 TokenId, Weight, WithdrawReasons, CollectionStats, CustomDataLimit,17 TokenId, Weight, WithdrawReasons, CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode,
18 NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
19 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT, CUSTOM_DATA_LIMIT, CollectionLimits,
20 CustomDataLimit, CreateCollectionData, SponsorshipState,
18};21};
19pub use pallet::*;22pub use pallet::*;
20use sp_core::H160;23use sp_core::H160;
285 TokenVariableDataLimitExceeded,288 TokenVariableDataLimitExceeded,
286 /// Exceeded max admin count289 /// Exceeded max admin count
287 CollectionAdminCountExceeded,290 CollectionAdminCountExceeded,
291 /// Collection limit bounds per collection exceeded
292 CollectionLimitBoundsExceeded,
293 /// Tried to enable permissions which are only permitted to be disabled
294 OwnerPermissionsCantBeReverted,
288295
289 /// Collection settings not allowing items transferring296 /// Collection settings not allowing items transferring
290 TransferNotAllowed,297 TransferNotAllowed,
300 /// Item balance not enough.307 /// Item balance not enough.
301 TokenValueTooLow,308 TokenValueTooLow,
302 /// Requested value more than approved.309 /// Requested value more than approved.
303 TokenValueNotEnough,310 ApprovedValueTooLow,
304 /// Tried to approve more than owned311 /// Tried to approve more than owned
305 CantApproveMoreThanOwned,312 CantApproveMoreThanOwned,
306313
395}402}
396403
397impl<T: Config> Pallet<T> {404impl<T: Config> Pallet<T> {
398 pub fn init_collection(data: Collection<T::AccountId>) -> Result<CollectionId, DispatchError> {405 pub fn init_collection(
406 owner: T::AccountId,
407 data: CreateCollectionData<T::AccountId>,
408 ) -> Result<CollectionId, DispatchError> {
399 {409 {
400 ensure!(410 ensure!(
418428
419 // =========429 // =========
430
431 let collection = Collection {
432 owner: owner.clone(),
433 name: data.name,
434 mode: data.mode.clone(),
435 mint_mode: false,
436 access: data.access.unwrap_or_default(),
437 description: data.description,
438 token_prefix: data.token_prefix,
439 offchain_schema: data.offchain_schema,
440 schema_version: data.schema_version.unwrap_or_default(),
441 sponsorship: data
442 .pending_sponsor
443 .map(SponsorshipState::Unconfirmed)
444 .unwrap_or_default(),
445 variable_on_chain_schema: data.variable_on_chain_schema,
446 const_on_chain_schema: data.const_on_chain_schema,
447 limits: data
448 .limits
449 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))
450 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,
451 meta_update_permission: data.meta_update_permission.unwrap_or_default(),
452 };
420453
421 // Take a (non-refundable) deposit of collection creation454 // Take a (non-refundable) deposit of collection creation
422 {455 {
429 ),462 ),
430 );463 );
431 <T as Config>::Currency::settle(464 <T as Config>::Currency::settle(
432 &data.owner,465 &owner,
433 imbalance,466 imbalance,
434 WithdrawReasons::TRANSFER,467 WithdrawReasons::TRANSFER,
435 ExistenceRequirement::KeepAlive,468 ExistenceRequirement::KeepAlive,
441 <Pallet<T>>::deposit_event(Event::CollectionCreated(474 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));
442 id,
443 data.mode.id(),
444 data.owner.clone(),
445 ));
446 <CollectionById<T>>::insert(id, data);475 <CollectionById<T>>::insert(id, collection);
447 Ok(id)476 Ok(id)
448 }477 }
449478
528 Ok(())557 Ok(())
529 }558 }
559
560 pub fn clamp_limits(
561 mode: CollectionMode,
562 old_limit: &CollectionLimits,
563 mut new_limit: CollectionLimits,
564 ) -> Result<CollectionLimits, DispatchError> {
565 macro_rules! limit_default {
566 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{
567 $(
568 if let Some($new) = $new.$field {
569 let $old = $old.$field($($arg)?);
570 let _ = $new;
571 let _ = $old;
572 $check
573 } else {
574 $new.$field = $old.$field
575 }
576 )*
577 }};
578 }
579
580 limit_default!(old_limit, new_limit,
581 account_token_ownership_limit => ensure!(
582 new_limit <= MAX_TOKEN_OWNERSHIP,
583 <Error<T>>::CollectionLimitBoundsExceeded,
584 ),
585 sponsor_transfer_timeout(match mode {
586 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
587 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
588 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
589 }) => ensure!(
590 new_limit <= MAX_SPONSOR_TIMEOUT,
591 <Error<T>>::CollectionLimitBoundsExceeded,
592 ),
593 sponsored_data_size => ensure!(
594 new_limit <= CUSTOM_DATA_LIMIT,
595 <Error<T>>::CollectionLimitBoundsExceeded,
596 ),
597 token_limit => ensure!(
598 old_limit >= new_limit && new_limit > 0,
599 <Error<T>>::CollectionTokenLimitExceeded
600 ),
601 owner_can_transfer => ensure!(
602 old_limit || !new_limit,
603 <Error<T>>::OwnerPermissionsCantBeReverted,
604 ),
605 owner_can_destroy => ensure!(
606 old_limit || !new_limit,
607 <Error<T>>::OwnerPermissionsCantBeReverted,
608 ),
609 sponsored_data_rate_limit => {},
610 transfers_enabled => {},
611 );
612 Ok(new_limit)
613 }
530}614}
531615
532#[macro_export]616#[macro_export]
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
22
3use core::ops::Deref;3use core::ops::Deref;
4use frame_support::{ensure};4use frame_support::{ensure};
5use up_data_structs::{AccessMode, Collection, CollectionId, TokenId};5use up_data_structs::{AccessMode, CollectionId, TokenId, CreateCollectionData};
6use pallet_common::{6use pallet_common::{
7 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,7 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,
8};8};
100}100}
101101
102impl<T: Config> Pallet<T> {102impl<T: Config> Pallet<T> {
103 pub fn init_collection(data: Collection<T::AccountId>) -> Result<CollectionId, DispatchError> {103 pub fn init_collection(
104 owner: T::AccountId,
105 data: CreateCollectionData<T::AccountId>,
106 ) -> Result<CollectionId, DispatchError> {
104 <PalletCommon<T>>::init_collection(data)107 <PalletCommon<T>>::init_collection(owner, data)
105 }108 }
106 pub fn destroy_collection(109 pub fn destroy_collection(
107 collection: FungibleHandle<T>,110 collection: FungibleHandle<T>,
343 if allowance.is_none() {346 if allowance.is_none() {
344 ensure!(347 ensure!(
345 collection.ignores_allowance(spender),348 collection.ignores_allowance(spender),
346 <CommonError<T>>::TokenValueNotEnough349 <CommonError<T>>::ApprovedValueTooLow
347 );350 );
348 }351 }
349352
374 if allowance.is_none() {377 if allowance.is_none() {
375 ensure!(378 ensure!(
376 collection.ignores_allowance(spender),379 collection.ignores_allowance(spender),
377 <CommonError<T>>::TokenValueNotEnough380 <CommonError<T>>::ApprovedValueTooLow
378 );381 );
379 }382 }
380383
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
22
3use erc::ERC721Events;3use erc::ERC721Events;
4use frame_support::{BoundedVec, ensure};4use frame_support::{BoundedVec, ensure};
5use up_data_structs::{AccessMode, Collection, CollectionId, CustomDataLimit, TokenId};5use up_data_structs::{AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData};
6use pallet_common::{6use pallet_common::{
7 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,7 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,
8};8};
140140
141// unchecked calls skips any permission checks141// unchecked calls skips any permission checks
142impl<T: Config> Pallet<T> {142impl<T: Config> Pallet<T> {
143 pub fn init_collection(data: Collection<T::AccountId>) -> Result<CollectionId, DispatchError> {143 pub fn init_collection(
144 owner: T::AccountId,
145 data: CreateCollectionData<T::AccountId>,
146 ) -> Result<CollectionId, DispatchError> {
144 <PalletCommon<T>>::init_collection(data)147 <PalletCommon<T>>::init_collection(owner, data)
145 }148 }
146 pub fn destroy_collection(149 pub fn destroy_collection(
147 collection: NonfungibleHandle<T>,150 collection: NonfungibleHandle<T>,
492 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {495 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
493 ensure!(496 ensure!(
494 collection.ignores_allowance(spender),497 collection.ignores_allowance(spender),
495 <CommonError<T>>::TokenValueNotEnough498 <CommonError<T>>::ApprovedValueTooLow
496 );499 );
497 }500 }
498501
520 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {523 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
521 ensure!(524 ensure!(
522 collection.ignores_allowance(spender),525 collection.ignores_allowance(spender),
523 <CommonError<T>>::TokenValueNotEnough526 <CommonError<T>>::ApprovedValueTooLow
524 );527 );
525 }528 }
526529
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
22
3use frame_support::{ensure, BoundedVec};3use frame_support::{ensure, BoundedVec};
4use up_data_structs::{4use up_data_structs::{
5 AccessMode, Collection, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId,5 AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId, CreateCollectionData,
6};6};
7use pallet_common::{7use pallet_common::{
8 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,8 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,
155155
156// unchecked calls skips any permission checks156// unchecked calls skips any permission checks
157impl<T: Config> Pallet<T> {157impl<T: Config> Pallet<T> {
158 pub fn init_collection(data: Collection<T::AccountId>) -> Result<CollectionId, DispatchError> {158 pub fn init_collection(
159 owner: T::AccountId,
160 data: CreateCollectionData<T::AccountId>,
161 ) -> Result<CollectionId, DispatchError> {
159 <PalletCommon<T>>::init_collection(data)162 <PalletCommon<T>>::init_collection(owner, data)
160 }163 }
161 pub fn destroy_collection(164 pub fn destroy_collection(
162 collection: RefungibleHandle<T>,165 collection: RefungibleHandle<T>,
528 if allowance.is_none() {531 if allowance.is_none() {
529 ensure!(532 ensure!(
530 collection.ignores_allowance(spender),533 collection.ignores_allowance(spender),
531 <CommonError<T>>::TokenValueNotEnough534 <CommonError<T>>::ApprovedValueTooLow
532 );535 );
533 }536 }
534537
561 if allowance.is_none() {564 if allowance.is_none() {
562 ensure!(565 ensure!(
563 collection.ignores_allowance(spender),566 collection.ignores_allowance(spender),
564 <CommonError<T>>::TokenValueNotEnough567 <CommonError<T>>::ApprovedValueTooLow
565 );568 );
566 }569 }
567570
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
36use frame_system::{self as system, ensure_signed};36use frame_system::{self as system, ensure_signed};
37use sp_runtime::{sp_std::prelude::Vec};37use sp_runtime::{sp_std::prelude::Vec};
38use up_data_structs::{38use up_data_structs::{
39 MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, CUSTOM_DATA_LIMIT,39 MAX_DECIMAL_POINTS, VARIABLE_ON_CHAIN_SCHEMA_LIMIT, CONST_ON_CHAIN_SCHEMA_LIMIT,
40 VARIABLE_ON_CHAIN_SCHEMA_LIMIT, CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,40 OFFCHAIN_SCHEMA_LIMIT, MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH,
41 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
42 NFT_SPONSOR_TRANSFER_TIMEOUT, MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH,
43 MAX_TOKEN_PREFIX_LENGTH, AccessMode, Collection, CreateItemData, CollectionLimits,41 MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData, CollectionLimits, CollectionId,
44 CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState, MetaUpdatePermission,42 CollectionMode, TokenId, SchemaVersion, SponsorshipState, MetaUpdatePermission,
45 CustomDataLimit,43 CreateCollectionData, CustomDataLimit,
46};44};
47use pallet_common::{45use pallet_common::{
48 account::CrossAccountId, CollectionHandle, Pallet as PalletCommon, Error as CommonError,46 account::CrossAccountId, CollectionHandle, Pallet as PalletCommon, Error as CommonError,
84 ConfirmUnsetSponsorFail,82 ConfirmUnsetSponsorFail,
85 /// Length of items properties must be greater than 0.83 /// Length of items properties must be greater than 0.
86 EmptyArgument,84 EmptyArgument,
87 /// Collection limit bounds per collection exceeded
88 CollectionLimitBoundsExceeded,
89 /// Tried to enable permissions which are only permitted to be disabled
90 OwnerPermissionsCantBeReverted,
91 }85 }
92}86}
9387
321 // returns collection ID315 // returns collection ID
322 #[weight = <SelfWeightOf<T>>::create_collection()]316 #[weight = <SelfWeightOf<T>>::create_collection()]
323 #[transactional]317 #[transactional]
318 #[deprecated]
324 pub fn create_collection(origin,319 pub fn create_collection(origin,
325 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,320 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
326 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,321 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
327 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,322 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,
328 mode: CollectionMode) -> DispatchResult {323 mode: CollectionMode) -> DispatchResult {
329
330 // Anyone can create a collection
331 let who = ensure_signed(origin)?;324 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {
332
333 // Create new collection
334 let new_collection = Collection {
335 owner: who,
336 name: collection_name,325 name: collection_name,
337 mode: mode.clone(),
338 mint_mode: false,
339 access: AccessMode::Normal,
340 description: collection_description,326 description: collection_description,
341 token_prefix,327 token_prefix,
342 offchain_schema: BoundedVec::default(),328 mode,
343 schema_version: SchemaVersion::ImageURL,
344 sponsorship: SponsorshipState::Disabled,
345 variable_on_chain_schema: BoundedVec::default(),329 ..Default::default()
330 };
346 const_on_chain_schema: BoundedVec::default(),331 Self::create_collection_ex(origin, data)
332 }
333
334 /// This method creates a collection
335 ///
336 /// Prefer it to deprecated [`created_collection`] method
347 limits: Default::default(),337 #[weight = <SelfWeightOf<T>>::create_collection()]
338 #[transactional]
348 meta_update_permission: Default::default(),339 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {
349 };340 let owner = ensure_signed(origin)?;
350341
351 let _id = match mode {342 let _id = match data.mode {
352 CollectionMode::NFT => {<PalletNonfungible<T>>::init_collection(new_collection)?},343 CollectionMode::NFT => {<PalletNonfungible<T>>::init_collection(owner, data)?},
353 CollectionMode::Fungible(decimal_points) => {344 CollectionMode::Fungible(decimal_points) => {
354 // check params345 // check params
355 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);346 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);
356 <PalletFungible<T>>::init_collection(new_collection)?347 <PalletFungible<T>>::init_collection(owner, data)?
357 }348 }
358 CollectionMode::ReFungible => {349 CollectionMode::ReFungible => {
359 <PalletRefungible<T>>::init_collection(new_collection)?350 <PalletRefungible<T>>::init_collection(owner, data)?
360 }351 }
361 };352 };
362353
363 Ok(())354 Ok(())
364 }355 }
365356
366 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.357 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.
367 ///358 ///
1093 collection_id: CollectionId,1084 collection_id: CollectionId,
1094 new_limit: CollectionLimits,1085 new_limit: CollectionLimits,
1095 ) -> DispatchResult {1086 ) -> DispatchResult {
1096 let mut new_limit = new_limit;
1097 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1087 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
1098 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1088 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
1099 target_collection.check_is_owner(&sender)?;1089 target_collection.check_is_owner(&sender)?;
1100 let old_limit = &target_collection.limits;1090 let old_limit = &target_collection.limits;
11011091
1102 macro_rules! limit_default {
1103 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{
1104 $(
1105 if let Some($new) = $new.$field {1092 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;
1106 let $old = $old.$field($($arg)?);
1107 let _ = $new;
1108 let _ = $old;
1109 $check
1110 } else {
1111 $new.$field = $old.$field
1112 }
1113 )*
1114 }};
1115 }
1116
1117 limit_default!(old_limit, new_limit,
1118 account_token_ownership_limit => ensure!(
1119 new_limit <= MAX_TOKEN_OWNERSHIP,
1120 <Error<T>>::CollectionLimitBoundsExceeded,
1121 ),
1122 sponsor_transfer_timeout(match target_collection.mode {
1123 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
1124 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
1125 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
1126 }) => ensure!(
1127 new_limit <= MAX_SPONSOR_TIMEOUT,
1128 <Error<T>>::CollectionLimitBoundsExceeded,
1129 ),
1130 sponsored_data_size => ensure!(
1131 new_limit <= CUSTOM_DATA_LIMIT,
1132 <Error<T>>::CollectionLimitBoundsExceeded,
1133 ),
1134 token_limit => ensure!(
1135 old_limit >= new_limit && new_limit > 0,
1136 <CommonError<T>>::CollectionTokenLimitExceeded
1137 ),
1138 owner_can_transfer => ensure!(
1139 old_limit || !new_limit,
1140 <Error<T>>::OwnerPermissionsCantBeReverted,
1141 ),
1142 owner_can_destroy => ensure!(
1143 old_limit || !new_limit,
1144 <Error<T>>::OwnerPermissionsCantBeReverted,
1145 ),
1146 sponsored_data_rate_limit => {},
1147 transfers_enabled => {},
1148 );
1149
1150 target_collection.limits = new_limit;
11511093
1152 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(1094 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(
1153 collection_id1095 collection_id
modifiedpallets/unique/src/tests.rsdiffbeforeafterboth
5use up_data_structs::{5use up_data_structs::{
6 COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,6 COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,
7 CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,7 CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,
8 TokenId,8 TokenId, MAX_TOKEN_OWNERSHIP,
9};9};
10use frame_support::{assert_noop, assert_ok};10use frame_support::{assert_noop, assert_ok};
11use sp_std::convert::TryInto;11use sp_std::convert::TryInto;
601 1601 1
602 )602 )
603 .map_err(|e| e.error),603 .map_err(|e| e.error),
604 CommonError::<Test>::TokenValueNotEnough604 CommonError::<Test>::ApprovedValueTooLow
605 );605 );
606606
607 // do approve607 // do approve
916 4916 4
917 )917 )
918 .map_err(|e| e.error),918 .map_err(|e| e.error),
919 CommonError::<Test>::TokenValueNotEnough919 CommonError::<Test>::ApprovedValueTooLow
920 );920 );
921 });921 });
922}922}
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
263 pub meta_update_permission: MetaUpdatePermission,263 pub meta_update_permission: MetaUpdatePermission,
264}264}
265
266#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Debug, Derivative, MaxEncodedLen)]
267#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
268#[derivative(Default(bound = ""))]
269pub struct CreateCollectionData<AccountId> {
270 #[derivative(Default(value = "CollectionMode::NFT"))]
271 pub mode: CollectionMode,
272 pub access: Option<AccessMode>,
273 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
274 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
275 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
276 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
277 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
278 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,
279 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
280 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,
281 pub schema_version: Option<SchemaVersion>,
282 pub pending_sponsor: Option<AccountId>,
283 pub limits: Option<CollectionLimits>,
284 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
285 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,
286 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
287 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,
288 pub meta_update_permission: Option<MetaUpdatePermission>,
289}
265290
266#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]291#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]
267#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]292#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
9type Result<T> = core::result::Result<T, DispatchError>;9type Result<T> = core::result::Result<T, DispatchError>;
1010
11sp_api::decl_runtime_apis! {11sp_api::decl_runtime_apis! {
12 #[api_version(2)]
12 pub trait UniqueApi<CrossAccountId, AccountId> where13 pub trait UniqueApi<CrossAccountId, AccountId> where
13 AccountId: Decode,14 AccountId: Decode,
14 CrossAccountId: pallet_common::account::CrossAccountId<AccountId>,15 CrossAccountId: pallet_common::account::CrossAccountId<AccountId>,
15 {16 {
17 #[changed_in(2)]
18 fn token_owner(collection: CollectionId, token: TokenId) -> Result<CrossAccountId>;
19
16 fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>>;20 fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>>;
17 fn token_exists(collection: CollectionId, token: TokenId) -> Result<bool>;21 fn token_exists(collection: CollectionId, token: TokenId) -> Result<bool>;
modifiedruntime/src/lib.rsdiffbeforeafterboth
24 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,24 Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
25 traits::{25 traits::{
26 AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify, AccountIdConversion,26 AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify,
27 AccountIdConversion, Zero,
27 },28 },
28 transaction_validity::{TransactionSource, TransactionValidity},29 transaction_validity::{TransactionSource, TransactionValidity},
29 ApplyExtrinsicResult, MultiSignature, RuntimeAppPublic,30 ApplyExtrinsicResult, MultiSignature, RuntimeAppPublic,
45 dispatch::DispatchResult,46 dispatch::DispatchResult,
46 PalletId, parameter_types, StorageValue, ConsensusEngineId,47 PalletId, parameter_types, StorageValue, ConsensusEngineId,
47 traits::{48 traits::{
48 Everything, Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem,49 tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT, Everything,
49 LockIdentifier, OnUnbalanced, Randomness, FindAuthor,50 Currency, ExistenceRequirement, Get, IsInVec, KeyOwnerProofSystem, LockIdentifier,
51 OnUnbalanced, Randomness, FindAuthor,
50 },52 },
69use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall};71use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall};
70use fp_rpc::TransactionStatus;72use fp_rpc::TransactionStatus;
71use sp_runtime::{73use sp_runtime::{
72 traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf},74 traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf, Saturating},
73 transaction_validity::TransactionValidityError,75 transaction_validity::TransactionValidityError,
76 SaturatedConversion,
74};77};
7578
76// pub use pallet_timestamp::Call as TimestampCall;79// pub use pallet_timestamp::Call as TimestampCall;
82use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};85use xcm::v1::{BodyId, Junction::*, MultiLocation, NetworkId, Junctions::*};
83use xcm_builder::{86use xcm_builder::{
84 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,87 AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter,
85 EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset,88 EnsureXcmOrigin, FixedWeightBounds, LocationInverter, NativeAsset, ParentAsSuperuser,
86 ParentAsSuperuser, ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative,89 ParentIsDefault, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
87 SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,90 SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
88 SovereignSignedViaLocation, TakeWeightCredit, UsingComponents,
89};91};
90use xcm_executor::{Config, XcmExecutor};92use xcm_executor::{Config, XcmExecutor, Assets};
93use sp_std::{marker::PhantomData};
94
95use xcm::latest::{
96 // Xcm,
97 AssetId::{Concrete},
98 Fungibility::Fungible as XcmFungible,
99 MultiAsset,
100 Error as XcmError,
101};
102use xcm_executor::traits::{MatchesFungible, WeightTrader};
103//use xcm_executor::traits::MatchesFungible;
104use sp_runtime::traits::CheckedConversion;
91105
92// mod chain_extension;106// mod chain_extension;
93// use crate::chain_extension::{NFTExtension, Imbalance};107// use crate::chain_extension::{NFTExtension, Imbalance};
146 spec_name: create_runtime_str!("opal"),160 spec_name: create_runtime_str!("opal"),
147 impl_name: create_runtime_str!("opal"),161 impl_name: create_runtime_str!("opal"),
148 authoring_version: 1,162 authoring_version: 1,
149 spec_version: 914000,163 spec_version: 916001,
150 impl_version: 1,164 impl_version: 0,
151 apis: RUNTIME_API_VERSIONS,165 apis: RUNTIME_API_VERSIONS,
152 transaction_version: 0,166 transaction_version: 1,
153 state_version: 0,167 state_version: 0,
154};168};
155169
616 AccountId32Aliases<RelayNetwork, AccountId>,630 AccountId32Aliases<RelayNetwork, AccountId>,
617);631);
632
633pub struct OnlySelfCurrency;
634impl<B: TryFrom<u128>> MatchesFungible<B> for OnlySelfCurrency {
635 fn matches_fungible(a: &MultiAsset) -> Option<B> {
636 match (&a.id, &a.fun) {
637 (Concrete(_), XcmFungible(ref amount)) => CheckedConversion::checked_from(*amount),
638 _ => None,
639 }
640 }
641}
618642
619/// Means for transacting assets on this chain.643/// Means for transacting assets on this chain.
620pub type LocalAssetTransactor = CurrencyAdapter<644pub type LocalAssetTransactor = CurrencyAdapter<
621 // Use this currency:645 // Use this currency:
622 Balances,646 Balances,
623 // Use this currency when it is a fungible asset matching the given location or name:647 // Use this currency when it is a fungible asset matching the given location or name:
624 IsConcrete<RelayLocation>,648 OnlySelfCurrency,
625 // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:649 // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID:
626 LocationToAccountId,650 LocationToAccountId,
627 // Our chain's account ID type (we can't get away without mentioning it explicitly):651 // Our chain's account ID type (we can't get away without mentioning it explicitly):
677 // ^^^ Parent & its unit plurality gets free execution701 // ^^^ Parent & its unit plurality gets free execution
678);702);
703
704pub struct UsingOnlySelfCurrencyComponents<
705 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
706 AssetId: Get<MultiLocation>,
707 AccountId,
708 Currency: CurrencyT<AccountId>,
709 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
710>(
711 Weight,
712 Currency::Balance,
713 PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,
714);
715impl<
716 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
717 AssetId: Get<MultiLocation>,
718 AccountId,
719 Currency: CurrencyT<AccountId>,
720 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
721 > WeightTrader
722 for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
723{
724 fn new() -> Self {
725 Self(0, Zero::zero(), PhantomData)
726 }
727
728 fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {
729 let amount = WeightToFee::calc(&weight);
730 let u128_amount: u128 = amount.try_into().map_err(|_| XcmError::Overflow)?;
731
732 // location to this parachain through relay chain
733 let option1: xcm::v1::AssetId = Concrete(MultiLocation {
734 parents: 1,
735 interior: X1(Parachain(ParachainInfo::parachain_id().into())),
736 });
737 // direct location
738 let option2: xcm::v1::AssetId = Concrete(MultiLocation {
739 parents: 0,
740 interior: Here,
741 });
742
743 let required = if payment.fungible.contains_key(&option1) {
744 (option1, u128_amount).into()
745 } else if payment.fungible.contains_key(&option2) {
746 (option2, u128_amount).into()
747 } else {
748 (Concrete(MultiLocation::default()), u128_amount).into()
749 };
750
751 let unused = payment
752 .checked_sub(required)
753 .map_err(|_| XcmError::TooExpensive)?;
754 self.0 = self.0.saturating_add(weight);
755 self.1 = self.1.saturating_add(amount);
756 Ok(unused)
757 }
758
759 fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
760 let weight = weight.min(self.0);
761 let amount = WeightToFee::calc(&weight);
762 self.0 -= weight;
763 self.1 = self.1.saturating_sub(amount);
764 let amount: u128 = amount.saturated_into();
765 if amount > 0 {
766 Some((AssetId::get(), amount).into())
767 } else {
768 None
769 }
770 }
771}
772impl<
773 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,
774 AssetId: Get<MultiLocation>,
775 AccountId,
776 Currency: CurrencyT<AccountId>,
777 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
778 > Drop
779 for UsingOnlySelfCurrencyComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>
780{
781 fn drop(&mut self) {
782 OnUnbalanced::on_unbalanced(Currency::issue(self.1));
783 }
784}
679785
680pub struct XcmConfig;786pub struct XcmConfig;
681impl Config for XcmConfig {787impl Config for XcmConfig {
689 type LocationInverter = LocationInverter<Ancestry>;795 type LocationInverter = LocationInverter<Ancestry>;
690 type Barrier = Barrier;796 type Barrier = Barrier;
691 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;797 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
692 type Trader = UsingComponents<IdentityFee<Balance>, RelayLocation, AccountId, Balances, ()>;798 type Trader = UsingOnlySelfCurrencyComponents<
799 IdentityFee<Balance>,
800 RelayLocation,
801 AccountId,
802 Balances,
803 (),
804 >;
693 type ResponseHandler = (); // Don't handle responses for now.805 type ResponseHandler = (); // Don't handle responses for now.
694 type SubscriptionService = PolkadotXcm;806 type SubscriptionService = PolkadotXcm;
modifiedtests/package.jsondiffbeforeafterboth
64 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",64 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
65 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",65 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",
66 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",66 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
67 "testXcmTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/xcmTransfer.test.ts",
67 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",68 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",
68 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",69 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
69 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",70 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",
71 "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
70 "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --input src/interfaces/ --package .",72 "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --input src/interfaces/ --package .",
71 "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint ws://localhost:9944 --output src/interfaces/ --package .",73 "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",
72 "polkadot-types": "yarn polkadot-types-from-defs && yarn polkadot-types-from-chain"74 "polkadot-types": "yarn polkadot-types-fetch-metadata && yarn polkadot-types-from-defs && yarn polkadot-types-from-chain"
73 },75 },
74 "author": "",76 "author": "",
75 "license": "SEE LICENSE IN ../LICENSE",77 "license": "SEE LICENSE IN ../LICENSE",
modifiedtests/src/check-event/createCollectionEvent.test.tsdiffbeforeafterboth
27 });27 });
28 it('Check event from createCollection(): ', async () => {28 it('Check event from createCollection(): ', async () => {
29 await usingApi(async (api: ApiPromise) => {29 await usingApi(async (api: ApiPromise) => {
30 const tx = api.tx.unique.createCollection([0x31], [0x32], '0x33', 'NFT');30 const tx = api.tx.unique.createCollectionEx({name: [0x31], description: [0x32], tokenPrefix: '0x33', mode: 'NFT'});
31 const events = await submitTransactionAsync(alice, tx);31 const events = await submitTransactionAsync(alice, tx);
32 const msg = JSON.stringify(uniqueEventMessage(events));32 const msg = JSON.stringify(uniqueEventMessage(events));
33 expect(msg).to.be.contain(checkSection);33 expect(msg).to.be.contain(checkSection);
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.
4//4//
55
6import chai from 'chai';6import {expect} from 'chai';
7import chaiAsPromised from 'chai-as-promised';7import privateKey from './substrate/privateKey';
8import usingApi, {executeTransaction, submitTransactionAsync} from './substrate/substrate-api';
8import {createCollectionExpectFailure, createCollectionExpectSuccess} from './util/helpers';9import {createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo} from './util/helpers';
9
10chai.use(chaiAsPromised);
1110
12describe('integration test: ext. createCollection():', () => {11describe('integration test: ext. createCollection():', () => {
13 it('Create new NFT collection', async () => {12 it('Create new NFT collection', async () => {
28 it('Create new ReFungible collection', async () => {27 it('Create new ReFungible collection', async () => {
29 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});28 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
30 });29 });
30 it('Create new collection with extra fields', async () => {
31 await usingApi(async api => {
32 const alice = privateKey('//Alice');
33 const bob = privateKey('//Bob');
34 const tx = api.tx.unique.createCollectionEx({
35 mode: {Fungible: 8},
36 access: 'AllowList',
37 name: [1],
38 description: [2],
39 tokenPrefix: '0x000000',
40 offchainSchema: '0x111111',
41 schemaVersion: 'Unique',
42 pendingSponsor: bob.address,
43 limits: {
44 accountTokenOwnershipLimit: 3,
45 },
46 variableOnChainSchema: '0x222222',
47 constOnChainSchema: '0x333333',
48 metaUpdatePermission: 'Admin',
49 });
50 const events = await submitTransactionAsync(alice, tx);
51 const result = getCreateCollectionResult(events);
52
53 const collection = (await getDetailedCollectionInfo(api, result.collectionId))!;
54 expect(collection.owner.toString()).to.equal(alice.address);
55 expect(collection.mode.asFungible.toNumber()).to.equal(8);
56 expect(collection.access.isAllowList).to.be.true;
57 expect(collection.name.map(v => v.toNumber())).to.deep.equal([1]);
58 expect(collection.description.map(v => v.toNumber())).to.deep.equal([2]);
59 expect(collection.tokenPrefix.toString()).to.equal('0x000000');
60 expect(collection.offchainSchema.toString()).to.equal('0x111111');
61 expect(collection.schemaVersion.isUnique).to.be.true;
62 expect(collection.sponsorship.asUnconfirmed.toString()).to.equal(bob.address);
63 expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.equal(3);
64 expect(collection.variableOnChainSchema.toString()).to.equal('0x222222');
65 expect(collection.constOnChainSchema.toString()).to.equal('0x333333');
66 expect(collection.metaUpdatePermission.isAdmin).to.be.true;
67 });
68 });
31});69});
3270
33describe('(!negative test!) integration test: ext. createCollection():', () => {71describe('(!negative test!) integration test: ext. createCollection():', () => {
40 it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => {78 it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => {
41 await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17), mode: {type: 'NFT'}});79 await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17), mode: {type: 'NFT'}});
42 });80 });
81 it('fails when bad limits are set', async () => {
82 await usingApi(async api => {
83 const alice = privateKey('//Alice');
84 const tx = api.tx.unique.createCollectionEx({mode: 'NFT', limits: {tokenLimit: 0}});
85 await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/^common.CollectionTokenLimitExceeded$/);
86 });
87 });
43});88});
4489
addedtests/src/interfaces/.gitignorediffbeforeafterboth

no changes

modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
68 * Collection description can not be longer than 255 char.68 * Collection description can not be longer than 255 char.
69 **/69 **/
70 CollectionDescriptionLimitExceeded: AugmentedError<ApiType>;70 CollectionDescriptionLimitExceeded: AugmentedError<ApiType>;
71 /**
72 * Collection limit bounds per collection exceeded
73 **/
74 CollectionLimitBoundsExceeded: AugmentedError<ApiType>;
71 /**75 /**
72 * Collection name can not be longer than 63 char.76 * Collection name can not be longer than 63 char.
73 **/77 **/
96 * No permission to perform action100 * No permission to perform action
97 **/101 **/
98 NoPermission: AugmentedError<ApiType>;102 NoPermission: AugmentedError<ApiType>;
103 /**
104 * Tried to enable permissions which are only permitted to be disabled
105 **/
106 OwnerPermissionsCantBeReverted: AugmentedError<ApiType>;
99 /**107 /**
100 * Collection is not in mint mode.108 * Collection is not in mint mode.
101 **/109 **/
107 /**115 /**
108 * Requested value more than approved.116 * Requested value more than approved.
109 **/117 **/
110 TokenValueNotEnough: AugmentedError<ApiType>;118 ApprovedValueTooLow: AugmentedError<ApiType>;
111 /**119 /**
112 * Item balance not enough.120 * Item balance not enough.
113 **/121 **/
436 * Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.444 * Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.
437 **/445 **/
438 CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;446 CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;
439 /**
440 * Collection limit bounds per collection exceeded
441 **/
442 CollectionLimitBoundsExceeded: AugmentedError<ApiType>;
443 /**447 /**
444 * This address is not set as sponsor, use setCollectionSponsor first.448 * This address is not set as sponsor, use setCollectionSponsor first.
445 **/449 **/
448 * Length of items properties must be greater than 0.452 * Length of items properties must be greater than 0.
449 **/453 **/
450 EmptyArgument: AugmentedError<ApiType>;454 EmptyArgument: AugmentedError<ApiType>;
451 /**
452 * Tried to enable permissions which are only permitted to be disabled
453 **/
454 OwnerPermissionsCantBeReverted: AugmentedError<ApiType>;
455 /**455 /**
456 * Generic error456 * Generic error
457 **/457 **/
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
2/* eslint-disable */2/* eslint-disable */
33
4import type { CumulusPrimitivesParachainInherentParachainInherentData } from './polkadot';4import type { CumulusPrimitivesParachainInherentParachainInherentData } from './polkadot';
5import type { PalletCommonAccountBasicCrossAccountIdRepr, UpDataStructsAccessMode, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCreateItemData, UpDataStructsMetaUpdatePermission, UpDataStructsSchemaVersion } from './unique';5import type { PalletCommonAccountBasicCrossAccountIdRepr, UpDataStructsAccessMode, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsMetaUpdatePermission, UpDataStructsSchemaVersion } from './unique';
6import type { ApiTypes, SubmittableExtrinsic } from '@polkadot/api/types';6import type { ApiTypes, SubmittableExtrinsic } from '@polkadot/api/types';
7import type { Bytes, Compact, Option, U256, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types';7import type { Bytes, Compact, Option, U256, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types';
8import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';8import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
670 * * mode: [CollectionMode] collection type and type dependent data.670 * * mode: [CollectionMode] collection type and type dependent data.
671 **/671 **/
672 createCollection: AugmentedSubmittable<(collectionName: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], collectionDescription: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], tokenPrefix: Bytes | string | Uint8Array, mode: UpDataStructsCollectionMode | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<u16>, Vec<u16>, Bytes, UpDataStructsCollectionMode]>;672 createCollection: AugmentedSubmittable<(collectionName: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], collectionDescription: Vec<u16> | (u16 | AnyNumber | Uint8Array)[], tokenPrefix: Bytes | string | Uint8Array, mode: UpDataStructsCollectionMode | { NFT: any } | { Fungible: any } | { ReFungible: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Vec<u16>, Vec<u16>, Bytes, UpDataStructsCollectionMode]>;
673 /**
674 * This method creates a collection
675 *
676 * Prefer it to deprecated [`created_collection`] method
677 **/
678 createCollectionEx: AugmentedSubmittable<(data: UpDataStructsCreateCollectionData | { mode?: any; access?: any; name?: any; description?: any; tokenPrefix?: any; offchainSchema?: any; schemaVersion?: any; pendingSponsor?: any; limits?: any; variableOnChainSchema?: any; constOnChainSchema?: any; metaUpdatePermission?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [UpDataStructsCreateCollectionData]>;
673 /**679 /**
674 * This method creates a concrete instance of NFT Collection created with CreateCollection method.680 * This method creates a concrete instance of NFT Collection created with CreateCollection method.
675 * 681 *
modifiedtests/src/interfaces/augment-types.tsdiffbeforeafterboth
33
4import type { EthereumBlock, EthereumLog, EthereumReceipt, EthereumTransactionLegacyTransaction, EvmCoreErrorExitReason, FpRpcTransactionStatus } from './ethereum';4import type { EthereumBlock, EthereumLog, EthereumReceipt, EthereumTransactionLegacyTransaction, EvmCoreErrorExitReason, FpRpcTransactionStatus } from './ethereum';
5import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundStatus, CumulusPalletXcmpQueueOutboundStatus, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1PersistedValidationData } from './polkadot';5import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundStatus, CumulusPalletXcmpQueueOutboundStatus, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1PersistedValidationData } from './polkadot';
6import type { PalletCommonAccountBasicCrossAccountIdRepr, PalletNonfungibleItemData, PalletRefungibleItemData, PalletUnqSchedulerCallSpec, PalletUnqSchedulerReleases, PalletUnqSchedulerScheduledV2, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionId, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateItemData, UpDataStructsMetaUpdatePermission, UpDataStructsSchemaVersion, UpDataStructsSponsorshipState, UpDataStructsTokenId } from './unique';6import type { PalletCommonAccountBasicCrossAccountIdRepr, PalletNonfungibleItemData, PalletRefungibleItemData, PalletUnqSchedulerCallSpec, PalletUnqSchedulerReleases, PalletUnqSchedulerScheduledV2, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionId, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsMetaUpdatePermission, UpDataStructsSchemaVersion, UpDataStructsSponsorshipState, UpDataStructsTokenId } from './unique';
7import type { BitVec, Bool, Bytes, Data, I128, I16, I256, I32, I64, I8, Json, Null, Raw, StorageKey, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types';7import type { BitVec, Bool, Bytes, Data, I128, I16, I256, I32, I64, I8, Json, Null, Raw, StorageKey, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types';
8import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets';8import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets';
9import type { BlockAttestations, IncludedBlocks, MoreAttestations } from '@polkadot/types/interfaces/attestations';9import type { BlockAttestations, IncludedBlocks, MoreAttestations } from '@polkadot/types/interfaces/attestations';
1021 UpDataStructsCollectionLimits: UpDataStructsCollectionLimits;1021 UpDataStructsCollectionLimits: UpDataStructsCollectionLimits;
1022 UpDataStructsCollectionMode: UpDataStructsCollectionMode;1022 UpDataStructsCollectionMode: UpDataStructsCollectionMode;
1023 UpDataStructsCollectionStats: UpDataStructsCollectionStats;1023 UpDataStructsCollectionStats: UpDataStructsCollectionStats;
1024 UpDataStructsCreateCollectionData: UpDataStructsCreateCollectionData;
1024 UpDataStructsCreateItemData: UpDataStructsCreateItemData;1025 UpDataStructsCreateItemData: UpDataStructsCreateItemData;
1025 UpDataStructsMetaUpdatePermission: UpDataStructsMetaUpdatePermission;1026 UpDataStructsMetaUpdatePermission: UpDataStructsMetaUpdatePermission;
1026 UpDataStructsSchemaVersion: UpDataStructsSchemaVersion;1027 UpDataStructsSchemaVersion: UpDataStructsSchemaVersion;
modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth
67 constOnChainSchema: 'Vec<u8>',67 constOnChainSchema: 'Vec<u8>',
68 metaUpdatePermission: 'UpDataStructsMetaUpdatePermission',68 metaUpdatePermission: 'UpDataStructsMetaUpdatePermission',
69 },69 },
70 UpDataStructsCreateCollectionData: {
71 mode: 'UpDataStructsCollectionMode',
72 access: 'Option<UpDataStructsAccessMode>',
73 name: 'Vec<u16>',
74 description: 'Vec<u16>',
75 tokenPrefix: 'Vec<u8>',
76 offchainSchema: 'Vec<u8>',
77 schemaVersion: 'Option<UpDataStructsSchemaVersion>',
78 pendingSponsor: 'Option<AccountId>',
79 limits: 'Option<UpDataStructsCollectionLimits>',
80 variableOnChainSchema: 'Vec<u8>',
81 constOnChainSchema: 'Vec<u8>',
82 metaUpdatePermission: 'Option<UpDataStructsMetaUpdatePermission>',
83 },
70 UpDataStructsCollectionStats: {84 UpDataStructsCollectionStats: {
71 created: 'u32',85 created: 'u32',
72 destroyed: 'u32',86 destroyed: 'u32',
76 UpDataStructsTokenId: 'u32',90 UpDataStructsTokenId: 'u32',
77 PalletNonfungibleItemData: mkDummy('NftItemData'),91 PalletNonfungibleItemData: mkDummy('NftItemData'),
78 PalletRefungibleItemData: mkDummy('RftItemData'),92 PalletRefungibleItemData: mkDummy('RftItemData'),
79 UpDataStructsCollectionMode: mkDummy('CollectionMode'),93 UpDataStructsCollectionMode: {
94 _enum: {
95 NFT: null,
96 Fungible: 'u32',
97 ReFungible: null,
98 },
99 },
80 UpDataStructsCreateItemData: mkDummy('CreateItemData'),100 UpDataStructsCreateItemData: mkDummy('CreateItemData'),
81 UpDataStructsCollectionLimits: {101 UpDataStructsCollectionLimits: {
82 accountTokenOwnershipLimit: 'Option<u32>',102 accountTokenOwnershipLimit: 'Option<u32>',
101 UpDataStructsAccessMode: {121 UpDataStructsAccessMode: {
102 _enum: ['Normal', 'AllowList'],122 _enum: ['Normal', 'AllowList'],
103 },123 },
104 UpDataStructsSchemaVersion: mkDummy('SchemaVersion'),124 UpDataStructsSchemaVersion: {
125 _enum: ['ImageURL', 'Unique'],
126 },
105127
106 PalletUnqSchedulerScheduledV2: mkDummy('ScheduledV2'),128 PalletUnqSchedulerScheduledV2: mkDummy('ScheduledV2'),
107 PalletUnqSchedulerCallSpec: mkDummy('CallSpec'),129 PalletUnqSchedulerCallSpec: mkDummy('CallSpec'),
modifiedtests/src/interfaces/unique/types.tsdiffbeforeafterboth
77}77}
7878
79/** @name UpDataStructsCollectionMode */79/** @name UpDataStructsCollectionMode */
80export interface UpDataStructsCollectionMode extends Struct {80export interface UpDataStructsCollectionMode extends Enum {
81 readonly isNft: boolean;
82 readonly isFungible: boolean;
81 readonly dummyCollectionMode: u32;83 readonly asFungible: u32;
84 readonly isReFungible: boolean;
82}85}
8386
84/** @name UpDataStructsCollectionStats */87/** @name UpDataStructsCollectionStats */
88 readonly alive: u32;91 readonly alive: u32;
89}92}
93
94/** @name UpDataStructsCreateCollectionData */
95export interface UpDataStructsCreateCollectionData extends Struct {
96 readonly mode: UpDataStructsCollectionMode;
97 readonly access: Option<UpDataStructsAccessMode>;
98 readonly name: Vec<u16>;
99 readonly description: Vec<u16>;
100 readonly tokenPrefix: Bytes;
101 readonly offchainSchema: Bytes;
102 readonly schemaVersion: Option<UpDataStructsSchemaVersion>;
103 readonly pendingSponsor: Option<AccountId>;
104 readonly limits: Option<UpDataStructsCollectionLimits>;
105 readonly variableOnChainSchema: Bytes;
106 readonly constOnChainSchema: Bytes;
107 readonly metaUpdatePermission: Option<UpDataStructsMetaUpdatePermission>;
108}
90109
91/** @name UpDataStructsCreateItemData */110/** @name UpDataStructsCreateItemData */
92export interface UpDataStructsCreateItemData extends Struct {111export interface UpDataStructsCreateItemData extends Struct {
101}120}
102121
103/** @name UpDataStructsSchemaVersion */122/** @name UpDataStructsSchemaVersion */
104export interface UpDataStructsSchemaVersion extends Struct {123export interface UpDataStructsSchemaVersion extends Enum {
105 readonly dummySchemaVersion: u32;124 readonly isImageUrl: boolean;
125 readonly isUnique: boolean;
106}126}
107127
108/** @name UpDataStructsSponsorshipState */128/** @name UpDataStructsSponsorshipState */
modifiedtests/src/substrate/substrate-api.tsdiffbeforeafterboth
95 return TransactionStatus.Fail;95 return TransactionStatus.Fail;
96}96}
97
98export function executeTransaction(api: ApiPromise, sender: IKeyringPair, transaction: SubmittableExtrinsic<'promise'>): Promise<EventRecord[]> {
99 return new Promise(async (res, rej) => {
100 try {
101 await transaction.signAndSend(sender, ({events, status}) => {
102 if (!status.isInBlock && !status.isFinalized) return;
103 for (const {event} of events) {
104 if (api.events.system.ExtrinsicSuccess.is(event)) {
105 res(events);
106 } else if (api.events.system.ExtrinsicFailed.is(event)) {
107 const {data: [error]} = event;
108 if (error.isModule) {
109 const decoded = api.registry.findMetaError(error.asModule);
110 const {method, section} = decoded;
111 rej(new Error(`${section}.${method}`));
112 } else {
113 rej(new Error(error.toString()));
114 }
115 }
116 }
117 });
118 } catch (e) {
119 rej(e);
120 }
121 });
122}
97123
98export function124export function
99submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {125submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
283 modeprm = {refungible: null};283 modeprm = {refungible: null};
284 }284 }
285285
286 const tx = api.tx.unique.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm as any);286 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any});
287 const events = await submitTransactionAsync(alicePrivateKey, tx);287 const events = await submitTransactionAsync(alicePrivateKey, tx);
288 const result = getCreateCollectionResult(events);288 const result = getCreateCollectionResult(events);
289289
329329
330 // Run the CreateCollection transaction330 // Run the CreateCollection transaction
331 const alicePrivateKey = privateKey('//Alice');331 const alicePrivateKey = privateKey('//Alice');
332 const tx = api.tx.unique.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm as any);332 const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any});
333 const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;333 const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;
334 const result = getCreateCollectionResult(events);334 const result = getCreateCollectionResult(events);
335335
addedtests/src/xcmTransfer.test.tsdiffbeforeafterboth

no changes