difftreelog
Merge branch 'develop' into tests/require-await
in: master
91 files changed
Cargo.lockdiffbeforeafterboth746source = "registry+https://github.com/rust-lang/crates.io-index"746source = "registry+https://github.com/rust-lang/crates.io-index"747checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"747checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"748dependencies = [748dependencies = [749 "lazy_static",749 "memchr",750 "memchr",751 "regex-automata",750]752]751753752[[package]]754[[package]]1054 "unicode-width",1056 "unicode-width",1055]1057]10581059[[package]]1060name = "concat-idents"1061version = "1.1.3"1062source = "registry+https://github.com/rust-lang/crates.io-index"1063checksum = "4b6f90860248d75014b7b103db8fee4f291c07bfb41306cdf77a0a5ab7a10d2f"1064dependencies = [1065 "quote",1066 "syn",1067]105610681057[[package]]1069[[package]]1058name = "concurrent-queue"1070name = "concurrent-queue"1063 "cache-padded",1075 "cache-padded",1064]1076]10771078[[package]]1079name = "console"1080version = "0.15.2"1081source = "registry+https://github.com/rust-lang/crates.io-index"1082checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"1083dependencies = [1084 "encode_unicode",1085 "lazy_static",1086 "libc",1087 "terminal_size",1088 "winapi",1089]106510901066[[package]]1091[[package]]1067name = "const-oid"1092name = "const-oid"184618711847[[package]]1872[[package]]1848name = "cxx"1873name = "cxx"1849version = "1.0.79"1874version = "1.0.78"1850source = "registry+https://github.com/rust-lang/crates.io-index"1875source = "registry+https://github.com/rust-lang/crates.io-index"1851checksum = "3f83d0ebf42c6eafb8d7c52f7e5f2d3003b89c7aa4fd2b79229209459a849af8"1876checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4"1852dependencies = [1877dependencies = [1853 "cc",1878 "cc",1854 "cxxbridge-flags",1879 "cxxbridge-flags",185818831859[[package]]1884[[package]]1860name = "cxx-build"1885name = "cxx-build"1861version = "1.0.79"1886version = "1.0.78"1862source = "registry+https://github.com/rust-lang/crates.io-index"1887source = "registry+https://github.com/rust-lang/crates.io-index"1863checksum = "07d050484b55975889284352b0ffc2ecbda25c0c55978017c132b29ba0818a86"1888checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199"1864dependencies = [1889dependencies = [1865 "cc",1890 "cc",1866 "codespan-reporting",1891 "codespan-reporting",187318981874[[package]]1899[[package]]1875name = "cxxbridge-flags"1900name = "cxxbridge-flags"1876version = "1.0.79"1901version = "1.0.78"1877source = "registry+https://github.com/rust-lang/crates.io-index"1902source = "registry+https://github.com/rust-lang/crates.io-index"1878checksum = "99d2199b00553eda8012dfec8d3b1c75fce747cf27c169a270b3b99e3448ab78"1903checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c"187919041880[[package]]1905[[package]]1881name = "cxxbridge-macro"1906name = "cxxbridge-macro"1882version = "1.0.79"1907version = "1.0.78"1883source = "registry+https://github.com/rust-lang/crates.io-index"1908source = "registry+https://github.com/rust-lang/crates.io-index"1884checksum = "dcb67a6de1f602736dd7eaead0080cf3435df806c61b24b13328db128c58868f"1909checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea"1885dependencies = [1910dependencies = [1886 "proc-macro2",1911 "proc-macro2",1887 "quote",1912 "quote",2139 "zeroize",2164 "zeroize",2140]2165]21662167[[package]]2168name = "encode_unicode"2169version = "0.3.6"2170source = "registry+https://github.com/rust-lang/crates.io-index"2171checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"214121722142[[package]]2173[[package]]2143name = "enum-as-inner"2174name = "enum-as-inner"2302name = "evm-coder"2333name = "evm-coder"2303version = "0.1.3"2334version = "0.1.3"2304dependencies = [2335dependencies = [2336 "concat-idents",2305 "ethereum",2337 "ethereum",2306 "evm-coder-procedural",2338 "evm-coder-procedural",2307 "evm-core",2339 "evm-core",2310 "hex-literal",2342 "hex-literal",2311 "impl-trait-for-tuples",2343 "impl-trait-for-tuples",2312 "primitive-types",2344 "primitive-types",2345 "similar-asserts",2313 "sp-std",2346 "sp-std",2314]2347]23152348352835613529[[package]]3562[[package]]3530name = "iana-time-zone-haiku"3563name = "iana-time-zone-haiku"3531version = "0.1.1"3564version = "0.1.0"3532source = "registry+https://github.com/rust-lang/crates.io-index"3565source = "registry+https://github.com/rust-lang/crates.io-index"3533checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"3566checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa"3534dependencies = [3567dependencies = [3535 "cxx",3568 "cxx",3536 "cxx-build",3569 "cxx-build",5345 "pallet-structure",5378 "pallet-structure",5346 "pallet-sudo",5379 "pallet-sudo",5347 "pallet-template-transaction-payment",5380 "pallet-template-transaction-payment",5381 "pallet-test-utils",5348 "pallet-timestamp",5382 "pallet-timestamp",5349 "pallet-transaction-payment",5383 "pallet-transaction-payment",5350 "pallet-transaction-payment-rpc-runtime-api",5384 "pallet-transaction-payment-rpc-runtime-api",5351 "pallet-treasury",5385 "pallet-treasury",5352 "pallet-unique",5386 "pallet-unique",5353 "pallet-unique-scheduler",5387 "pallet-unique-scheduler",5388 "pallet-unique-scheduler-v2",5354 "pallet-xcm",5389 "pallet-xcm",5355 "parachain-info",5390 "parachain-info",5356 "parity-scale-codec 3.2.1",5391 "parity-scale-codec 3.2.1",579258275793[[package]]5828[[package]]5794name = "pallet-common"5829name = "pallet-common"5795version = "0.1.8"5830version = "0.1.9"5796dependencies = [5831dependencies = [5797 "ethereum",5832 "ethereum",5798 "evm-coder",5833 "evm-coder",632563606326[[package]]6361[[package]]6327name = "pallet-nonfungible"6362name = "pallet-nonfungible"6328version = "0.1.5"6363version = "0.1.6"6329dependencies = [6364dependencies = [6330 "ethereum",6365 "ethereum",6331 "evm-coder",6366 "evm-coder",644764826448[[package]]6483[[package]]6449name = "pallet-refungible"6484name = "pallet-refungible"6450version = "0.2.4"6485version = "0.2.5"6451dependencies = [6486dependencies = [6452 "derivative",6487 "derivative",6453 "ethereum",6488 "ethereum",6668 "up-sponsorship",6703 "up-sponsorship",6669]6704]67056706[[package]]6707name = "pallet-test-utils"6708version = "0.1.0"6709dependencies = [6710 "frame-support",6711 "frame-system",6712 "pallet-unique-scheduler-v2",6713 "parity-scale-codec 3.2.1",6714 "scale-info",6715]667067166671[[package]]6717[[package]]6672name = "pallet-timestamp"6718name = "pallet-timestamp"676668126767[[package]]6813[[package]]6768name = "pallet-unique"6814name = "pallet-unique"6769version = "0.2.0"6815version = "0.2.1"6770dependencies = [6816dependencies = [6771 "ethereum",6817 "ethereum",6772 "evm-coder",6818 "evm-coder",6807 "up-sponsorship",6853 "up-sponsorship",6808]6854]68556856[[package]]6857name = "pallet-unique-scheduler-v2"6858version = "0.1.0"6859dependencies = [6860 "frame-benchmarking",6861 "frame-support",6862 "frame-system",6863 "log",6864 "pallet-preimage",6865 "parity-scale-codec 3.2.1",6866 "scale-info",6867 "sp-core",6868 "sp-io",6869 "sp-runtime",6870 "sp-std",6871 "substrate-test-utils",6872]680968736810[[package]]6874[[package]]6811name = "pallet-utility"6875name = "pallet-utility"107411080510742[[package]]10806[[package]]10743name = "serde_json"10807name = "serde_json"10744version = "1.0.87"10808version = "1.0.86"10745source = "registry+https://github.com/rust-lang/crates.io-index"10809source = "registry+https://github.com/rust-lang/crates.io-index"10746checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"10810checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"10747dependencies = [10811dependencies = [10748 "itoa",10812 "itoa",10749 "ryu",10813 "ryu",10885 "paste",10949 "paste",10886]10950]1095110952[[package]]10953name = "similar"10954version = "2.2.0"10955source = "registry+https://github.com/rust-lang/crates.io-index"10956checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803"10957dependencies = [10958 "bstr",10959 "unicode-segmentation",10960]1096110962[[package]]10963name = "similar-asserts"10964version = "1.4.2"10965source = "registry+https://github.com/rust-lang/crates.io-index"10966checksum = "bbf644ad016b75129f01a34a355dcb8d66a5bc803e417c7a77cc5d5ee9fa0f18"10967dependencies = [10968 "console",10969 "similar",10970]108871097110888[[package]]10972[[package]]10889name = "slab"10973name = "slab"120021208612003[[package]]12087[[package]]12004name = "syn"12088name = "syn"12005version = "1.0.103"12089version = "1.0.102"12006source = "registry+https://github.com/rust-lang/crates.io-index"12090source = "registry+https://github.com/rust-lang/crates.io-index"12007checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"12091checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"12008dependencies = [12092dependencies = [12009 "proc-macro2",12093 "proc-macro2",12010 "quote",12094 "quote",12079 "winapi-util",12163 "winapi-util",12080]12164]1216512166[[package]]12167name = "terminal_size"12168version = "0.1.17"12169source = "registry+https://github.com/rust-lang/crates.io-index"12170checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"12171dependencies = [12172 "libc",12173 "winapi",12174]120811217512082[[package]]12176[[package]]12083name = "test-runtime-constants"12177name = "test-runtime-constants"12659 "tinyvec",12753 "tinyvec",12660]12754]1275512756[[package]]12757name = "unicode-segmentation"12758version = "1.10.0"12759source = "registry+https://github.com/rust-lang/crates.io-index"12760checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"126611276112662[[package]]12762[[package]]12663name = "unicode-width"12763name = "unicode-width"Cargo.tomldiffbeforeafterbothno syntactic changes
client/rpc/src/lib.rsdiffbeforeafterboth558 pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);558 pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);559 pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);559 pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);560 pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);560 pass_method!(561 collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api;562 changed_in 3, collection_by_id_before_version_3(collection) => |value| value.map(|coll| coll.into())563 );561 pass_method!(collection_stats() -> CollectionStats, unique_api);564 pass_method!(collection_stats() -> CollectionStats, unique_api);562 pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);565 pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);crates/evm-coder/Cargo.tomldiffbeforeafterboth22# We want to assert some large binary blobs equality in tests22# We want to assert some large binary blobs equality in tests23hex = "0.4.3"23hex = "0.4.3"24hex-literal = "0.3.4"24hex-literal = "0.3.4"25similar-asserts = "1.4.2"26concat-idents = "1.1.3"252726[features]28[features]27default = ["std"]29default = ["std"]crates/evm-coder/src/abi.rsdiffbeforeafterboth252526use crate::{26use crate::{27 execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},27 execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},28 types::{string, self},28 types::*,29};29};30use crate::execution::Result;30use crate::execution::Result;313132const ABI_ALIGNMENT: usize = 32;32const ABI_ALIGNMENT: usize = 32;333334trait TypeHelper {34trait TypeHelper {35 /// Is type dynamic sized.35 fn is_dynamic() -> bool;36 fn is_dynamic() -> bool;3738 /// Size for type aligned to [`ABI_ALIGNMENT`].39 fn size() -> usize;36}40}374138/// View into RLP data, which provides method to read typed items from it42/// View into RLP data, which provides method to read typed items from it52 }56 }53 }57 }54 /// Start reading RLP buffer, parsing first 4 bytes as selector58 /// Start reading RLP buffer, parsing first 4 bytes as selector55 pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> {59 pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {56 if buf.len() < 4 {60 if buf.len() < 4 {57 return Err(Error::Error(ExitError::OutOfOffset));61 return Err(Error::Error(ExitError::OutOfOffset));58 }62 }218 static_part: Vec<u8>,222 static_part: Vec<u8>,219 dynamic_part: Vec<(usize, AbiWriter)>,223 dynamic_part: Vec<(usize, AbiWriter)>,220 had_call: bool,224 had_call: bool,225 is_dynamic: bool,221}226}222impl AbiWriter {227impl AbiWriter {223 /// Initialize internal buffers for output data, assuming no padding required228 /// Initialize internal buffers for output data, assuming no padding required224 pub fn new() -> Self {229 pub fn new() -> Self {225 Self::default()230 Self::default()226 }231 }232233 /// Initialize internal buffers with data size234 pub fn new_dynamic(is_dynamic: bool) -> Self {235 Self {236 is_dynamic,237 ..Default::default()238 }239 }227 /// Initialize internal buffers, inserting method selector at beginning240 /// Initialize internal buffers, inserting method selector at beginning228 pub fn new_call(method_id: u32) -> Self {241 pub fn new_call(method_id: u32) -> Self {229 let mut val = Self::new();242 let mut val = Self::new();239 self.static_part.extend(block);252 self.static_part.extend(block);240 }253 }241254242 fn write_padright(&mut self, bytes: &[u8]) {255 fn write_padright(&mut self, block: &[u8]) {243 assert!(bytes.len() <= ABI_ALIGNMENT);256 assert!(block.len() <= ABI_ALIGNMENT);244 self.static_part.extend(bytes);257 self.static_part.extend(block);245 self.static_part258 self.static_part246 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);259 .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);247 }260 }248261249 /// Write [`H160`] to end of buffer262 /// Write [`H160`] to end of buffer315 for (static_offset, part) in self.dynamic_part {328 for (static_offset, part) in self.dynamic_part {316 let part_offset = self.static_part.len() - if self.had_call { 4 } else { 0 };329 let part_offset = self.static_part.len()330 - if self.had_call { 4 } else { 0 }331 - if self.is_dynamic { ABI_ALIGNMENT } else { 0 };317332318 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);333 let encoded_dynamic_offset = usize::to_be_bytes(part_offset);334 let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len();335 let stop = static_offset + ABI_ALIGNMENT;319 self.static_part[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len()336 self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset);320 ..static_offset + ABI_ALIGNMENT]321 .copy_from_slice(&encoded_dynamic_offset);322 self.static_part.extend(part.finish())337 self.static_part.extend(part.finish())323 }338 }334 /// Read item from current position, advanding decoder349 /// Read item from current position, advanding decoder335 fn abi_read(&mut self) -> Result<T>;350 fn abi_read(&mut self) -> Result<T>;336337 /// Size for type aligned to [`ABI_ALIGNMENT`].338 fn size() -> usize;339}351}340352341macro_rules! impl_abi_readable {353macro_rules! impl_abi_readable {345 $dynamic357 $dynamic346 }358 }359360 fn size() -> usize {361 ABI_ALIGNMENT362 }347 }363 }348 impl AbiRead<$ty> for AbiReader<'_> {364 impl AbiRead<$ty> for AbiReader<'_> {349 fn abi_read(&mut self) -> Result<$ty> {365 fn abi_read(&mut self) -> Result<$ty> {350 self.$method()366 self.$method()351 }367 }352353 fn size() -> usize {354 ABI_ALIGNMENT355 }356 }368 }357 };369 };358}370}359371372impl_abi_readable!(bool, bool, false);360impl_abi_readable!(u8, uint8, false);373impl_abi_readable!(uint8, uint8, false);361impl_abi_readable!(u32, uint32, false);374impl_abi_readable!(uint32, uint32, false);362impl_abi_readable!(u64, uint64, false);375impl_abi_readable!(uint64, uint64, false);363impl_abi_readable!(u128, uint128, false);376impl_abi_readable!(uint128, uint128, false);364impl_abi_readable!(U256, uint256, false);377impl_abi_readable!(uint256, uint256, false);365impl_abi_readable!([u8; 4], bytes4, false);378impl_abi_readable!(bytes4, bytes4, false);366impl_abi_readable!(H160, address, false);379impl_abi_readable!(address, address, false);367impl_abi_readable!(Vec<u8>, bytes, true);368impl_abi_readable!(bool, bool, true);369impl_abi_readable!(string, string, true);380impl_abi_readable!(string, string, true);381// impl_abi_readable!(bytes, bytes, true);382383impl TypeHelper for bytes {384 fn is_dynamic() -> bool {385 true386 }387 fn size() -> usize {388 ABI_ALIGNMENT389 }390}391impl AbiRead<bytes> for AbiReader<'_> {392 fn abi_read(&mut self) -> Result<bytes> {393 Ok(bytes(self.bytes()?))394 }395}370396371mod sealed {397mod sealed {372 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead398 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead392 Ok(out)418 Ok(out)393 }419 }394395 fn size() -> usize {396 ABI_ALIGNMENT397 }398}420}399421400macro_rules! impl_tuples {422macro_rules! impl_tuples {401 ($($ident:ident)+) => {423 ($($ident:ident)+) => {402 impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+) {424 impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+)425 where426 $(427 $ident: TypeHelper,428 )+429 {403 fn is_dynamic() -> bool {430 fn is_dynamic() -> bool {404 false431 false407 )*434 )*408 }435 }436437 fn size() -> usize {438 0 $(+ <$ident>::size())+439 }409 }440 }410 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}441 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}411 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>442 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>416 ($($ident,)+): TypeHelper,447 ($($ident,)+): TypeHelper,417 {448 {418 fn abi_read(&mut self) -> Result<($($ident,)+)> {449 fn abi_read(&mut self) -> Result<($($ident,)+)> {419 let size = if !<($($ident,)+)>::is_dynamic() { Some(<Self as AbiRead<($($ident,)+)>>::size()) } else { None };450 let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };420 let mut subresult = self.subresult(size)?;451 let mut subresult = self.subresult(size)?;421 Ok((452 Ok((422 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+453 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+423 ))454 ))424 }455 }425426 fn size() -> usize {427 0 $(+ <AbiReader<'_> as AbiRead<$ident>>::size())+428 }429 }456 }430 #[allow(non_snake_case)]457 #[allow(non_snake_case)]431 impl<$($ident),+> AbiWrite for &($($ident,)+)458 impl<$($ident),+> AbiWrite for ($($ident,)+)432 where459 where433 $($ident: AbiWrite,)+460 $($ident: AbiWrite,)+434 {461 {435 fn abi_write(&self, writer: &mut AbiWriter) {462 fn abi_write(&self, writer: &mut AbiWriter) {436 let ($($ident,)+) = self;463 let ($($ident,)+) = self;464 if writer.is_dynamic {465 let mut sub = AbiWriter::new();466 $($ident.abi_write(&mut sub);)+467 writer.write_subresult(sub);468 } else {437 $($ident.abi_write(writer);)+469 $($ident.abi_write(writer);)+470 }438 }471 }439 }472 }440 };473 };506impl_abi_writeable!(bool, bool);539impl_abi_writeable!(bool, bool);507impl_abi_writeable!(&str, string);540impl_abi_writeable!(&str, string);541508impl AbiWrite for &string {542impl AbiWrite for string {509 fn abi_write(&self, writer: &mut AbiWriter) {543 fn abi_write(&self, writer: &mut AbiWriter) {510 writer.string(self)544 writer.string(self)511 }545 }512}546}547548impl AbiWrite for bytes {549 fn abi_write(&self, writer: &mut AbiWriter) {550 writer.bytes(self.0.as_slice())551 }552}553513impl AbiWrite for &Vec<u8> {554impl<T: AbiWrite + TypeHelper> AbiWrite for Vec<T> {514 fn abi_write(&self, writer: &mut AbiWriter) {555 fn abi_write(&self, writer: &mut AbiWriter) {556 let is_dynamic = T::is_dynamic();557 let mut sub = if is_dynamic {558 AbiWriter::new_dynamic(is_dynamic)559 } else {560 AbiWriter::new()561 };562563 // Write items count564 (self.len() as u32).abi_write(&mut sub);565566 for item in self {567 item.abi_write(&mut sub);568 }515 writer.bytes(self)569 writer.write_subresult(sub);516 }570 }517}571}518572556#[cfg(test)]610#[cfg(test)]557pub mod test {611pub mod test {558 use crate::{612 use crate::{559 abi::AbiRead,613 abi::{AbiRead, AbiWrite},560 types::{string, uint256},614 types::*,561 };615 };562616563 use super::{AbiReader, AbiWriter};617 use super::{AbiReader, AbiWriter};564 use hex_literal::hex;618 use hex_literal::hex;619 use primitive_types::{H160, U256};620 use concat_idents::concat_idents;621622 macro_rules! test_impl {623 ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {624 concat_idents!(test_name = encode_decode_, $name {625 #[test]626 fn test_name() {627 let function_identifier: u32 = $function_identifier;628 let decoded_data = $decoded_data;629 let encoded_data = $encoded_data;630631 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();632 assert_eq!(call, u32::to_be_bytes(function_identifier));633 let data = <AbiReader<'_> as AbiRead<$type>>::abi_read(&mut decoder).unwrap();634 assert_eq!(data, decoded_data);635636 let mut writer = AbiWriter::new_call(function_identifier);637 decoded_data.abi_write(&mut writer);638 let ed = writer.finish();639 similar_asserts::assert_eq!(encoded_data, ed.as_slice());640 }641 });642 };643 }644645 macro_rules! test_impl_uint {646 ($type:ident) => {647 test_impl!(648 $type,649 $type,650 0xdeadbeef,651 255 as $type,652 &hex!(653 "654 deadbeef655 00000000000000000000000000000000000000000000000000000000000000ff656 "657 )658 );659 };660 }661662 test_impl_uint!(uint8);663 test_impl_uint!(uint32);664 test_impl_uint!(uint128);665666 test_impl!(667 uint256,668 uint256,669 0xdeadbeef,670 U256([255, 0, 0, 0]),671 &hex!(672 "673 deadbeef674 00000000000000000000000000000000000000000000000000000000000000ff675 "676 )677 );678679 test_impl!(680 vec_tuple_address_uint256,681 Vec<(address, uint256)>,682 0x1ACF2D55,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 &hex!(698 "699 1ACF2D55700 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]701 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]702 703 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address704 000000000000000000000000000000000000000000000000000000000000000A // uint256705 706 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address707 0000000000000000000000000000000000000000000000000000000000000014 // uint256708 709 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address710 000000000000000000000000000000000000000000000000000000000000001E // uint256711 "712 )713 );714715 test_impl!(716 vec_tuple_uint256_string,717 Vec<(uint256, string)>,718 0xdeadbeef,719 vec![720 (1.into(), "Test URI 0".to_string()),721 (11.into(), "Test URI 1".to_string()),722 (12.into(), "Test URI 2".to_string()),723 ],724 &hex!(725 "726 deadbeef727 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]728 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]729730 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem731 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem732 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem733734 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60735 0000000000000000000000000000000000000000000000000000000000000040 // offset of string736 000000000000000000000000000000000000000000000000000000000000000a // size of string737 5465737420555249203000000000000000000000000000000000000000000000 // string738739 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0740 0000000000000000000000000000000000000000000000000000000000000040 // offset of string741 000000000000000000000000000000000000000000000000000000000000000a // size of string742 5465737420555249203100000000000000000000000000000000000000000000 // string743744 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160745 0000000000000000000000000000000000000000000000000000000000000040 // offset of string746 000000000000000000000000000000000000000000000000000000000000000a // size of string747 5465737420555249203200000000000000000000000000000000000000000000 // string748 "749 )750 );565751566 #[test]752 #[test]567 fn dynamic_after_static() {753 fn dynamic_after_static() {609 }795 }610796611 #[test]797 #[test]612 fn mint_bulk() {798 fn parse_vec_with_dynamic_type() {799 let decoded_data = (800 0x36543006,801 vec![802 (1.into(), "Test URI 0".to_string()),803 (11.into(), "Test URI 1".to_string()),804 (12.into(), "Test URI 2".to_string()),805 ],806 );807808 let encoded_data = &hex!(809 "810 36543006811 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address812 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]813 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]814815 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem816 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem817 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem818819 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60820 0000000000000000000000000000000000000000000000000000000000000040 // offset of string821 000000000000000000000000000000000000000000000000000000000000000a // size of string822 5465737420555249203000000000000000000000000000000000000000000000 // string823824 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0825 0000000000000000000000000000000000000000000000000000000000000040 // offset of string826 000000000000000000000000000000000000000000000000000000000000000a // size of string827 5465737420555249203100000000000000000000000000000000000000000000 // string828829 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160830 0000000000000000000000000000000000000000000000000000000000000040 // offset of string831 000000000000000000000000000000000000000000000000000000000000000a // size of string832 5465737420555249203200000000000000000000000000000000000000000000 // string833 "834 );835613 let (call, mut decoder) = AbiReader::new_call(&hex!(836 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();614 "615 36543006616 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address617 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]618 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]619620 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem621 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem622 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem623624 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60625 0000000000000000000000000000000000000000000000000000000000000040 // offset of string626 000000000000000000000000000000000000000000000000000000000000000a // size of string627 5465737420555249203000000000000000000000000000000000000000000000 // string628629 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0630 0000000000000000000000000000000000000000000000000000000000000040 // offset of string631 000000000000000000000000000000000000000000000000000000000000000a // size of string632 5465737420555249203100000000000000000000000000000000000000000000 // string633634 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160635 0000000000000000000000000000000000000000000000000000000000000040 // offset of string636 000000000000000000000000000000000000000000000000000000000000000a // size of string637 5465737420555249203200000000000000000000000000000000000000000000 // string638 "639 ))640 .unwrap();641 assert_eq!(call, u32::to_be_bytes(0x36543006));837 assert_eq!(call, u32::to_be_bytes(decoded_data.0));642 let _ = decoder.address().unwrap();838 let address = decoder.address().unwrap();643 let data =839 let data =644 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();840 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();645 assert_eq!(841 assert_eq!(data, decoded_data.1);646 data,842647 vec![843 let mut writer = AbiWriter::new_call(decoded_data.0);648 (1.into(), "Test URI 0".to_string()),844 address.abi_write(&mut writer);649 (11.into(), "Test URI 1".to_string()),845 decoded_data.1.abi_write(&mut writer);650 (12.into(), "Test URI 2".to_string())846 let ed = writer.finish();651 ]847 similar_asserts::assert_eq!(encoded_data, ed.as_slice());652 );653 }848 }654655 #[test]656 fn parse_vec_with_simple_type() {657 use crate::types::address;658 use primitive_types::{H160, U256};659660 let (call, mut decoder) = AbiReader::new_call(&hex!(661 "662 1ACF2D55663 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]664 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]665666 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address667 000000000000000000000000000000000000000000000000000000000000000A // uint256668669 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address670 0000000000000000000000000000000000000000000000000000000000000014 // uint256671672 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address673 000000000000000000000000000000000000000000000000000000000000001E // uint256674 "675 ))676 .unwrap();677 assert_eq!(call, u32::to_be_bytes(0x1ACF2D55));678 let data =679 <AbiReader<'_> as AbiRead<Vec<(address, uint256)>>>::abi_read(&mut decoder).unwrap();680 assert_eq!(data.len(), 3);681 assert_eq!(682 data,683 vec![684 (685 H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),686 U256([10, 0, 0, 0])687 ),688 (689 H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),690 U256([20, 0, 0, 0])691 ),692 (693 H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),694 U256([30, 0, 0, 0])695 ),696 ]697 );698 }699}849}700850crates/evm-coder/src/lib.rsdiffbeforeafterboth134 #[cfg(feature = "std")]134 #[cfg(feature = "std")]135 pub type string = ::std::string::String;135 pub type string = ::std::string::String;136137 #[derive(Default, Debug)]136 pub type bytes = Vec<u8>;138 pub struct bytes(pub Vec<u8>);137139138 /// Solidity doesn't have `void` type, however we have special implementation140 /// Solidity doesn't have `void` type, however we have special implementation139 /// for empty tuple return type141 /// for empty tuple return type158 pub value: U256,160 pub value: U256,159 }161 }162163 impl From<Vec<u8>> for bytes {164 fn from(src: Vec<u8>) -> Self {165 Self(src)166 }167 }168169 impl Into<Vec<u8>> for bytes {170 fn into(self) -> Vec<u8> {171 self.0172 }173 }174175 impl bytes {176 #[must_use]177 pub fn len(&self) -> usize {178 self.0.len()179 }180181 #[must_use]182 pub fn is_empty(&self) -> bool {183 self.len() == 0184 }185 }160}186}161187162/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro188/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macrocrates/evm-coder/src/solidity.rsdiffbeforeafterboth154 fn is_simple() -> bool {154 fn is_simple() -> bool {155 false155 false156 }156 }157 fn solidity_default(writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {157 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {158 write!(writer, "new ")?;159 T::solidity_name(writer, tc)?;158 write!(writer, "[]")160 write!(writer, "[](0)")159 }161 }160}162}161163node/cli/src/command.rsdiffbeforeafterboth343435use crate::{35use crate::{36 chain_spec::{36 chain_spec::{self, RuntimeId, RuntimeIdentification, ServiceId, ServiceIdentification},37 self, RuntimeId, RuntimeIdentification, ServiceId, ServiceIdentification, default_runtime,38 },39 cli::{Cli, RelayChainCli, Subcommand},37 cli::{Cli, RelayChainCli, Subcommand},40 service::{new_partial, start_node, start_dev_node},38 service::{new_partial, start_node, start_dev_node},41};39};40#[cfg(feature = "runtime-benchmarks")]41use crate::chain_spec::default_runtime;424243#[cfg(feature = "unique-runtime")]43#[cfg(feature = "unique-runtime")]44use crate::service::UniqueRuntimeExecutor;44use crate::service::UniqueRuntimeExecutor;454546#[cfg(feature = "quartz-runtime")]46#[cfg(feature = "quartz-runtime")]47use crate::service::QuartzRuntimeExecutor;47use crate::service::QuartzRuntimeExecutor;484849use crate::service::{OpalRuntimeExecutor, DefaultRuntimeExecutor};49use crate::service::OpalRuntimeExecutor;5051#[cfg(feature = "runtime-benchmarks")]52use crate::service::DefaultRuntimeExecutor;505351use codec::Encode;54use codec::Encode;52use cumulus_primitives_core::ParaId;55use cumulus_primitives_core::ParaId;node/cli/src/service.rsdiffbeforeafterboth46use cumulus_relay_chain_rpc_interface::{RelayChainRpcInterface, create_client_and_start_worker};46use cumulus_relay_chain_rpc_interface::{RelayChainRpcInterface, create_client_and_start_worker};474748// Substrate Imports48// Substrate Imports49use sc_client_api::ExecutorProvider;50use sc_executor::NativeElseWasmExecutor;49use sc_executor::NativeElseWasmExecutor;51use sc_executor::NativeExecutionDispatch;50use sc_executor::NativeExecutionDispatch;52use sc_network::{NetworkService, NetworkBlock};51use sc_network::{NetworkService, NetworkBlock};84/// Opal native executor instance.83/// Opal native executor instance.85pub struct OpalRuntimeExecutor;84pub struct OpalRuntimeExecutor;868587#[cfg(feature = "unique-runtime")]86#[cfg(all(feature = "unique-runtime", feature = "runtime-benchmarks"))]88pub type DefaultRuntimeExecutor = UniqueRuntimeExecutor;87pub type DefaultRuntimeExecutor = UniqueRuntimeExecutor;898890#[cfg(all(not(feature = "unique-runtime"), feature = "quartz-runtime"))]89#[cfg(all(90 not(feature = "unique-runtime"),91 feature = "quartz-runtime",92 feature = "runtime-benchmarks"93))]91pub type DefaultRuntimeExecutor = QuartzRuntimeExecutor;94pub type DefaultRuntimeExecutor = QuartzRuntimeExecutor;929593#[cfg(all(not(feature = "unique-runtime"), not(feature = "quartz-runtime")))]96#[cfg(all(97 not(feature = "unique-runtime"),98 not(feature = "quartz-runtime"),99 feature = "runtime-benchmarks"100))]94pub type DefaultRuntimeExecutor = OpalRuntimeExecutor;101pub type DefaultRuntimeExecutor = OpalRuntimeExecutor;95102pallets/common/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [0.1.9] - 2022-10-1367## Added89- EVM event for `destroy_collection`.105## [0.1.8] - 2022-08-2411## [0.1.8] - 2022-08-246127## Added13## Added148 - Eth methods for collection15- Eth methods for collection9 + set_collection_sponsor_substrate16 - set_collection_sponsor_substrate10 + has_collection_pending_sponsor17 - has_collection_pending_sponsor11 + remove_collection_sponsor18 - remove_collection_sponsor12 + get_collection_sponsor19 - get_collection_sponsor13- Add convert function from `uint256` to `CrossAccountId`.20- Add convert function from `uint256` to `CrossAccountId`.142115## [0.1.7] - 2022-08-1922## [0.1.7] - 2022-08-19162317### Added24### Added182519 - Add convert funtion from `CrossAccountId` to eth `uint256`.26- Add convert funtion from `CrossAccountId` to eth `uint256`.202721 22## [0.1.6] - 2022-08-1628## [0.1.6] - 2022-08-16232924### Added30### Added25- New Ethereum API methods: changeOwner, changeOwner(Substrate) and verifyOwnerOrAdmin(Substrate).263132- New Ethereum API methods: changeOwner, changeOwner(Substrate) and verifyOwnerOrAdmin(Substrate).3327<!-- bureaucrate goes here -->34<!-- bureaucrate goes here -->3528## [v0.1.5] 2022-08-1636## [v0.1.5] 2022-08-16293730### Other changes38### Other changes45- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b53- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b465447## [0.1.3] - 2022-07-2555## [0.1.3] - 2022-07-255648### Add57### Add5849- Some static property keys and values.59- Some static property keys and values.506051## [0.1.2] - 2022-07-2061## [0.1.2] - 2022-07-20526253### Fixed63### Fixed546455- Some methods in `#[solidity_interface]` for `CollectionHandle` had invalid65- Some methods in `#[solidity_interface]` for `CollectionHandle` had invalid56 mutability modifiers, causing invalid stub/abi generation.66 mutability modifiers, causing invalid stub/abi generation.576758## [0.1.1] - 2022-07-1468## [0.1.1] - 2022-07-14596960### Added70### Added617162 - Implementation of RPC method `token_owners` returning 10 owners in no particular order.72- Implementation of RPC method `token_owners` returning 10 owners in no particular order.63 This was an internal request to improve the web interface and support fractionalization event.73 This was an internal request to improve the web interface and support fractionalization event.6474pallets/common/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-common"2name = "pallet-common"3version = "0.1.8"3version = "0.1.9"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/common/src/erc.rsdiffbeforeafterboth34use crate::{34use crate::{35 Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf,35 Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf,36 eth::{36 eth::{37 convert_cross_account_to_uint256, convert_uint256_to_cross_account,37 convert_cross_account_to_uint256, convert_cross_account_to_tuple,38 convert_cross_account_to_tuple,38 convert_tuple_to_cross_account,39 },39 },40 weights::WeightInfo,40 weights::WeightInfo,41};41};53 #[indexed]53 #[indexed]54 collection_id: address,54 collection_id: address,55 },55 },56 /// The collection has been destroyed.57 CollectionDestroyed {58 /// Collection ID.59 #[indexed]60 collection_id: address,61 },56}62}576358/// Does not always represent a full collection, for RFT it is either64/// Does not always represent a full collection, for RFT it is either85 let key = <Vec<u8>>::from(key)91 let key = <Vec<u8>>::from(key)86 .try_into()92 .try_into()87 .map_err(|_| "key too large")?;93 .map_err(|_| "key too large")?;88 let value = value.try_into().map_err(|_| "value too large")?;94 let value = value.0.try_into().map_err(|_| "value too large")?;899590 <Pallet<T>>::set_collection_property(self, &caller, Property { key, value })96 <Pallet<T>>::set_collection_property(self, &caller, Property { key, value })91 .map_err(dispatch_to_evm::<T>)97 .map_err(dispatch_to_evm::<T>)92 }98 }99100 /// Set collection properties.101 ///102 /// @param properties Vector of properties key/value pair.103 #[weight(<SelfWeightOf<T>>::set_collection_properties(properties.len() as u32))]104 fn set_collection_properties(105 &mut self,106 caller: caller,107 properties: Vec<(string, bytes)>,108 ) -> Result<void> {109 let caller = T::CrossAccountId::from_eth(caller);110111 let properties = properties112 .into_iter()113 .map(|(key, value)| {114 let key = <Vec<u8>>::from(key)115 .try_into()116 .map_err(|_| "key too large")?;117118 let value = value.0.try_into().map_err(|_| "value too large")?;119120 Ok(Property { key, value })121 })122 .collect::<Result<Vec<_>>>()?;123124 <Pallet<T>>::set_collection_properties(self, &caller, properties)125 .map_err(dispatch_to_evm::<T>)126 }9312794 /// Delete collection property.128 /// Delete collection property.95 ///129 ///96 /// @param key Property key.130 /// @param key Property key.97 #[weight(<SelfWeightOf<T>>::delete_collection_properties(1))]131 #[weight(<SelfWeightOf<T>>::delete_collection_properties(1))]98 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {132 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {99 self.consume_store_reads_and_writes(1, 1)?;100101 let caller = T::CrossAccountId::from_eth(caller);133 let caller = T::CrossAccountId::from_eth(caller);102 let key = <Vec<u8>>::from(key)134 let key = <Vec<u8>>::from(key)106 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)138 <Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)107 }139 }140141 /// Delete collection properties.142 ///143 /// @param keys Properties keys.144 #[weight(<SelfWeightOf<T>>::delete_collection_properties(keys.len() as u32))]145 fn delete_collection_properties(&mut self, caller: caller, keys: Vec<string>) -> Result<()> {146 let caller = T::CrossAccountId::from_eth(caller);147 let keys = keys148 .into_iter()149 .map(|key| {150 <Vec<u8>>::from(key)151 .try_into()152 .map_err(|_| Error::Revert("key too large".into()))153 })154 .collect::<Result<Vec<_>>>()?;155156 <Pallet<T>>::delete_collection_properties(self, &caller, keys).map_err(dispatch_to_evm::<T>)157 }108158109 /// Get collection property.159 /// Get collection property.110 ///160 ///117 .try_into()167 .try_into()118 .map_err(|_| "key too large")?;168 .map_err(|_| "key too large")?;119169120 let props = <CollectionProperties<T>>::get(self.id);170 let props = CollectionProperties::<T>::get(self.id);121 let prop = props.get(&key).ok_or("key not found")?;171 let prop = props.get(&key).ok_or("key not found")?;122172123 Ok(prop.to_vec())173 Ok(bytes(prop.to_vec()))124 }174 }175176 /// Get collection properties.177 ///178 /// @param keys Properties keys. Empty keys for all propertyes.179 /// @return Vector of properties key/value pairs.180 fn collection_properties(&self, keys: Vec<string>) -> Result<Vec<(string, bytes)>> {181 let keys = keys182 .into_iter()183 .map(|key| {184 <Vec<u8>>::from(key)185 .try_into()186 .map_err(|_| Error::Revert("key too large".into()))187 })188 .collect::<Result<Vec<_>>>()?;189190 let properties = Pallet::<T>::filter_collection_properties(191 self.id,192 if keys.is_empty() { None } else { Some(keys) },193 )194 .map_err(dispatch_to_evm::<T>)?;195196 let properties = properties197 .into_iter()198 .map(|p| {199 let key =200 string::from_utf8(p.key.into()).map_err(|e| Error::Revert(format!("{}", e)))?;201 let value = bytes(p.value.to_vec());202 Ok((key, value))203 })204 .collect::<Result<Vec<_>>>()?;205 Ok(properties)206 }125207126 /// Set the sponsor of the collection.208 /// Set the sponsor of the collection.127 ///209 ///139 save(self)221 save(self)140 }222 }141223142 // TODO: Temprorary off. Need refactor143 // /// Set the substrate sponsor of the collection.224 /// Set the sponsor of the collection.144 // ///225 ///145 // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.226 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.146 // ///227 ///147 // /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract.228 /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.148 // fn set_collection_sponsor_substrate(229 fn set_collection_sponsor_cross(149 // &mut self,230 &mut self,150 // caller: caller,231 caller: caller,151 // sponsor: uint256,232 sponsor: (address, uint256),152 // ) -> Result<void> {233 ) -> Result<void> {153 // self.consume_store_reads_and_writes(1, 1)?;234 self.consume_store_reads_and_writes(1, 1)?;154235155 // check_is_owner_or_admin(caller, self)?;236 check_is_owner_or_admin(caller, self)?;156237157 // let sponsor = convert_uint256_to_cross_account::<T>(sponsor);238 let sponsor = convert_tuple_to_cross_account::<T>(sponsor)?;158 // self.set_sponsor(sponsor.as_sub().clone())239 self.set_sponsor(sponsor.as_sub().clone())159 // .map_err(dispatch_to_evm::<T>)?;240 .map_err(dispatch_to_evm::<T>)?;160 // save(self)241 save(self)161 // }242 }162243163 /// Whether there is a pending sponsor.244 /// Whether there is a pending sponsor.164 fn has_collection_pending_sponsor(&self) -> Result<bool> {245 fn has_collection_pending_sponsor(&self) -> Result<bool> {300 Ok(crate::eth::collection_id_to_address(self.id))381 Ok(crate::eth::collection_id_to_address(self.id))301 }382 }302383303 // TODO: Temprorary off. Need refactor304 // /// Add collection admin by substrate address.384 /// Add collection admin.305 // /// @param newAdmin Substrate administrator address.385 /// @param newAdmin Cross account administrator address.306 // fn add_collection_admin_substrate(386 fn add_collection_admin_cross(307 // &mut self,387 &mut self,308 // caller: caller,388 caller: caller,309 // new_admin: uint256,389 new_admin: (address, uint256),310 // ) -> Result<void> {390 ) -> Result<void> {311 // self.consume_store_writes(2)?;391 self.consume_store_writes(2)?;312392313 // let caller = T::CrossAccountId::from_eth(caller);393 let caller = T::CrossAccountId::from_eth(caller);314 // let new_admin = convert_uint256_to_cross_account::<T>(new_admin);394 let new_admin = convert_tuple_to_cross_account::<T>(new_admin)?;315 // <Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;395 <Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;316 // Ok(())396 Ok(())317 // }397 }318398319 // TODO: Temprorary off. Need refactor320 // /// Remove collection admin by substrate address.399 /// Remove collection admin.321 // /// @param admin Substrate administrator address.400 /// @param admin Cross account administrator address.322 // fn remove_collection_admin_substrate(401 fn remove_collection_admin_cross(323 // &mut self,402 &mut self,324 // caller: caller,403 caller: caller,325 // admin: uint256,404 admin: (address, uint256),326 // ) -> Result<void> {405 ) -> Result<void> {327 // self.consume_store_writes(2)?;406 self.consume_store_writes(2)?;328407329 // let caller = T::CrossAccountId::from_eth(caller);408 let caller = T::CrossAccountId::from_eth(caller);330 // let admin = convert_uint256_to_cross_account::<T>(admin);409 let admin = convert_tuple_to_cross_account::<T>(admin)?;331 // <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;410 <Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;332 // Ok(())411 Ok(())333 // }412 }334413335 /// Add collection admin.414 /// Add collection admin.336 /// @param newAdmin Address of the added administrator.415 /// @param newAdmin Address of the added administrator.479 Ok(())558 Ok(())480 }559 }481560482 // TODO: Temprorary off. Need refactor483 // /// Add substrate user to allowed list.561 /// Add user to allowed list.484 // ///562 ///485 // /// @param user User substrate address.563 /// @param user User cross account address.486 // fn add_to_collection_allow_list_substrate(564 fn add_to_collection_allow_list_cross(487 // &mut self,565 &mut self,488 // caller: caller,566 caller: caller,489 // user: uint256,567 user: (address, uint256),490 // ) -> Result<void> {568 ) -> Result<void> {491 // self.consume_store_writes(1)?;569 self.consume_store_writes(1)?;492570493 // let caller = T::CrossAccountId::from_eth(caller);571 let caller = T::CrossAccountId::from_eth(caller);494 // let user = convert_uint256_to_cross_account::<T>(user);572 let user = convert_tuple_to_cross_account::<T>(user)?;495 // Pallet::<T>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;573 Pallet::<T>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;496 // Ok(())574 Ok(())497 // }575 }498576499 /// Remove the user from the allowed list.577 /// Remove the user from the allowed list.500 ///578 ///508 Ok(())586 Ok(())509 }587 }510588511 // TODO: Temprorary off. Need refactor512 // /// Remove substrate user from allowed list.589 /// Remove user from allowed list.513 // ///590 ///514 // /// @param user User substrate address.591 /// @param user User cross account address.515 // fn remove_from_collection_allow_list_substrate(592 fn remove_from_collection_allow_list_cross(516 // &mut self,593 &mut self,517 // caller: caller,594 caller: caller,518 // user: uint256,595 user: (address, uint256),519 // ) -> Result<void> {596 ) -> Result<void> {520 // self.consume_store_writes(1)?;597 self.consume_store_writes(1)?;521598522 // let caller = T::CrossAccountId::from_eth(caller);599 let caller = T::CrossAccountId::from_eth(caller);523 // let user = convert_uint256_to_cross_account::<T>(user);600 let user = convert_tuple_to_cross_account::<T>(user)?;524 // Pallet::<T>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;601 Pallet::<T>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;525 // Ok(())602 Ok(())526 // }603 }527604528 /// Switch permission for minting.605 /// Switch permission for minting.529 ///606 ///556 Ok(self.is_owner_or_admin(&user))633 Ok(self.is_owner_or_admin(&user))557 }634 }558635559 // TODO: Temprorary off. Need refactor560 // /// Check that substrate account is the owner or admin of the collection636 /// Check that account is the owner or admin of the collection561 // ///637 ///562 // /// @param user account to verify638 /// @param user User cross account to verify563 // /// @return "true" if account is the owner or admin639 /// @return "true" if account is the owner or admin564 // fn is_owner_or_admin_substrate(&self, user: uint256) -> Result<bool> {640 fn is_owner_or_admin_cross(&self, user: (address, uint256)) -> Result<bool> {565 // let user = convert_uint256_to_cross_account::<T>(user);641 let user = convert_tuple_to_cross_account::<T>(user)?;566 // Ok(self.is_owner_or_admin(&user))642 Ok(self.is_owner_or_admin(&user))567 // }643 }568644569 /// Returns collection type645 /// Returns collection type570 ///646 ///580656581 /// Get collection owner.657 /// Get collection owner.582 ///658 ///583 /// @return Tuble with sponsor address and his substrate mirror.659 /// @return Tuple with sponsor address and his substrate mirror.584 /// If address is canonical then substrate mirror is zero and vice versa.660 /// If address is canonical then substrate mirror is zero and vice versa.585 fn collection_owner(&self) -> Result<(address, uint256)> {661 fn collection_owner(&self) -> Result<(address, uint256)> {586 Ok(convert_cross_account_to_tuple::<T>(662 Ok(convert_cross_account_to_tuple::<T>(602 .map_err(dispatch_to_evm::<T>)678 .map_err(dispatch_to_evm::<T>)603 }679 }604680605 // TODO: Temprorary off. Need refactor681 /// Get collection administrators682 ///683 /// @return Vector of tuples with admins address and his substrate mirror.684 /// If address is canonical then substrate mirror is zero and vice versa.685 fn collection_admins(&self) -> Result<Vec<(address, uint256)>> {686 let result = crate::IsAdmin::<T>::iter_prefix((self.id,))687 .map(|(admin, _)| crate::eth::convert_cross_account_to_tuple::<T>(&admin))688 .collect();689 Ok(result)690 }691606 // /// Changes collection owner to another substrate account692 /// Changes collection owner to another account607 // ///693 ///608 // /// @dev Owner can be changed only by current owner694 /// @dev Owner can be changed only by current owner609 // /// @param newOwner new owner substrate account695 /// @param newOwner new owner cross account610 // fn set_owner_substrate(&mut self, caller: caller, new_owner: uint256) -> Result<void> {696 fn set_owner_cross(&mut self, caller: caller, new_owner: (address, uint256)) -> Result<void> {611 // self.consume_store_writes(1)?;697 self.consume_store_writes(1)?;612698613 // let caller = T::CrossAccountId::from_eth(caller);699 let caller = T::CrossAccountId::from_eth(caller);614 // let new_owner = convert_uint256_to_cross_account::<T>(new_owner);700 let new_owner = convert_tuple_to_cross_account::<T>(new_owner)?;615 // self.set_owner_internal(caller, new_owner)701 self.set_owner_internal(caller, new_owner)616 // .map_err(dispatch_to_evm::<T>)702 .map_err(dispatch_to_evm::<T>)617 // }703 }618619 // TODO: need implement AbiWriter for &Vec<T>620 // fn collection_admins(&self) -> Result<Vec<(address, uint256)>> {621 // let result = pallet_common::IsAdmin::<T>::iter_prefix((self.id,))622 // .map(|(admin, _)| pallet_common::eth::convert_cross_account_to_tuple::<T>(&admin))623 // .collect();624 // Ok(result)625 // }626}704}627705628/// ### Note706/// ### Notepallets/common/src/eth.rsdiffbeforeafterboth86 }86 }87}87}8889/// Convert tuple `(address, uint256)` to `CrossAccountId`.90///91/// If `address` in the tuple has *default* value, then the canonical form is substrate,92/// if `uint256` has *default* value, then the ethereum form is canonical,93/// if both values are *default* or *non default*, then this is considered an invalid address and `Error` is returned.94pub fn convert_tuple_to_cross_account<T: Config>(95 eth_cross_account_id: (address, uint256),96) -> evm_coder::execution::Result<T::CrossAccountId>97where98 T::AccountId: From<[u8; 32]>,99{100 if eth_cross_account_id == Default::default() {101 Err("All fields of cross account is zeroed".into())102 } else if eth_cross_account_id.0 == Default::default() {103 Ok(convert_uint256_to_cross_account::<T>(104 eth_cross_account_id.1,105 ))106 } else if eth_cross_account_id.1 == Default::default() {107 Ok(T::CrossAccountId::from_eth(eth_cross_account_id.0))108 } else {109 Err("All fields of cross account is non zeroed".into())110 }111}88112pallets/common/src/lib.rsdiffbeforeafterboth100010001001 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));1001 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));10021003 <PalletEvm<T>>::deposit_log(1004 erc::CollectionHelpersEvents::CollectionDestroyed {1005 collection_id: eth::collection_id_to_address(collection.id),1006 }1007 .to_log(T::ContractAddress::get()),1008 );1002 Ok(())1009 Ok(())1003 }1010 }10041011pallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/erc.rsdiffbeforeafterboth19use core::char::{REPLACEMENT_CHARACTER, decode_utf16};19use core::char::{REPLACEMENT_CHARACTER, decode_utf16};20use core::convert::TryInto;20use core::convert::TryInto;21use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};21use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};22use pallet_common::eth::convert_tuple_to_cross_account;22use up_data_structs::CollectionMode;23use up_data_structs::CollectionMode;23use pallet_common::erc::{CommonEvmHandler, PrecompileResult};24use pallet_common::erc::{CommonEvmHandler, PrecompileResult};24use sp_std::vec::Vec;25use sp_std::vec::Vec;150151151#[solidity_interface(name = ERC20UniqueExtensions)]152#[solidity_interface(name = ERC20UniqueExtensions)]152impl<T: Config> FungibleHandle<T> {153impl<T: Config> FungibleHandle<T>154where155 T::AccountId: From<[u8; 32]>,156{157 #[weight(<SelfWeightOf<T>>::approve())]158 fn approve_cross(159 &mut self,160 caller: caller,161 spender: (address, uint256),162 amount: uint256,163 ) -> Result<bool> {164 let caller = T::CrossAccountId::from_eth(caller);165 let spender = convert_tuple_to_cross_account::<T>(spender)?;166 let amount = amount.try_into().map_err(|_| "amount overflow")?;167168 <Pallet<T>>::set_allowance(self, &caller, &spender, amount)169 .map_err(dispatch_to_evm::<T>)?;170 Ok(true)171 }172153 /// Burn tokens from account173 /// Burn tokens from account154 /// @dev Function that burns an `amount` of the tokens of a given account,174 /// @dev Function that burns an `amount` of the tokens of a given account,169 Ok(true)189 Ok(true)170 }190 }191192 /// Burn tokens from account193 /// @dev Function that burns an `amount` of the tokens of a given account,194 /// deducting from the sender's allowance for said account.195 /// @param from The account whose tokens will be burnt.196 /// @param amount The amount that will be burnt.197 #[weight(<SelfWeightOf<T>>::burn_from())]198 fn burn_from_cross(199 &mut self,200 caller: caller,201 from: (address, uint256),202 amount: uint256,203 ) -> Result<bool> {204 let caller = T::CrossAccountId::from_eth(caller);205 let from = convert_tuple_to_cross_account::<T>(from)?;206 let amount = amount.try_into().map_err(|_| "amount overflow")?;207 let budget = self208 .recorder209 .weight_calls_budget(<StructureWeight<T>>::find_parent());210211 <Pallet<T>>::burn_from(self, &caller, &from, amount, &budget)212 .map_err(dispatch_to_evm::<T>)?;213 Ok(true)214 }171215172 /// Mint tokens for multiple accounts.216 /// Mint tokens for multiple accounts.173 /// @param amounts array of pairs of account address and amount217 /// @param amounts array of pairs of account address and amount192 Ok(true)236 Ok(true)193 }237 }238239 #[weight(<SelfWeightOf<T>>::transfer_from())]240 fn transfer_from_cross(241 &mut self,242 caller: caller,243 from: (address, uint256),244 to: (address, uint256),245 amount: uint256,246 ) -> Result<bool> {247 let caller = T::CrossAccountId::from_eth(caller);248 let from = convert_tuple_to_cross_account::<T>(from)?;249 let to = convert_tuple_to_cross_account::<T>(to)?;250 let amount = amount.try_into().map_err(|_| "amount overflow")?;251 let budget = self252 .recorder253 .weight_calls_budget(<StructureWeight<T>>::find_parent());254255 <Pallet<T>>::transfer_from(self, &caller, &from, &to, amount, &budget)256 .map_err(dispatch_to_evm::<T>)?;257 Ok(true)258 }194}259}195260196#[solidity_interface(261#[solidity_interface(pallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth18}18}191920/// @title A contract that allows you to work with collections.20/// @title A contract that allows you to work with collections.21/// @dev the ERC-165 identifier for this interface is 0x62e2229021/// @dev the ERC-165 identifier for this interface is 0xb3152af322contract Collection is Dummy, ERC165 {22contract Collection is Dummy, ERC165 {23 /// Set collection property.23 /// Set collection property.24 ///24 ///33 dummy = 0;33 dummy = 0;34 }34 }3536 /// Set collection properties.37 ///38 /// @param properties Vector of properties key/value pair.39 /// @dev EVM selector for this function is: 0x50b26b2a,40 /// or in textual repr: setCollectionProperties((string,bytes)[])41 function setCollectionProperties(Tuple10[] memory properties) public {42 require(false, stub_error);43 properties;44 dummy = 0;45 }354636 /// Delete collection property.47 /// Delete collection property.37 ///48 ///44 dummy = 0;55 dummy = 0;45 }56 }5758 /// Delete collection properties.59 ///60 /// @param keys Properties keys.61 /// @dev EVM selector for this function is: 0xee206ee3,62 /// or in textual repr: deleteCollectionProperties(string[])63 function deleteCollectionProperties(string[] memory keys) public {64 require(false, stub_error);65 keys;66 dummy = 0;67 }466847 /// Get collection property.69 /// Get collection property.48 ///70 ///59 return hex"";81 return hex"";60 }82 }8384 /// Get collection properties.85 ///86 /// @param keys Properties keys. Empty keys for all propertyes.87 /// @return Vector of properties key/value pairs.88 /// @dev EVM selector for this function is: 0x285fb8e6,89 /// or in textual repr: collectionProperties(string[])90 function collectionProperties(string[] memory keys) public view returns (Tuple10[] memory) {91 require(false, stub_error);92 keys;93 dummy;94 return new Tuple10[](0);95 }619662 /// Set the sponsor of the collection.97 /// Set the sponsor of the collection.63 ///98 ///72 dummy = 0;107 dummy = 0;73 }108 }109110 /// Set the sponsor of the collection.111 ///112 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.113 ///114 /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.115 /// @dev EVM selector for this function is: 0x84a1d5a8,116 /// or in textual repr: setCollectionSponsorCross((address,uint256))117 function setCollectionSponsorCross(Tuple6 memory sponsor) public {118 require(false, stub_error);119 sponsor;120 dummy = 0;121 }7412275 /// Whether there is a pending sponsor.123 /// Whether there is a pending sponsor.76 /// @dev EVM selector for this function is: 0x058ac185,124 /// @dev EVM selector for this function is: 0x058ac185,154 return 0x0000000000000000000000000000000000000000;202 return 0x0000000000000000000000000000000000000000;155 }203 }204205 /// Add collection admin.206 /// @param newAdmin Cross account administrator address.207 /// @dev EVM selector for this function is: 0x859aa7d6,208 /// or in textual repr: addCollectionAdminCross((address,uint256))209 function addCollectionAdminCross(Tuple6 memory newAdmin) public {210 require(false, stub_error);211 newAdmin;212 dummy = 0;213 }214215 /// Remove collection admin.216 /// @param admin Cross account administrator address.217 /// @dev EVM selector for this function is: 0x6c0cd173,218 /// or in textual repr: removeCollectionAdminCross((address,uint256))219 function removeCollectionAdminCross(Tuple6 memory admin) public {220 require(false, stub_error);221 admin;222 dummy = 0;223 }156224157 /// Add collection admin.225 /// Add collection admin.158 /// @param newAdmin Address of the added administrator.226 /// @param newAdmin Address of the added administrator.234 dummy = 0;302 dummy = 0;235 }303 }304305 /// Add user to allowed list.306 ///307 /// @param user User cross account address.308 /// @dev EVM selector for this function is: 0xa0184a3a,309 /// or in textual repr: addToCollectionAllowListCross((address,uint256))310 function addToCollectionAllowListCross(Tuple6 memory user) public {311 require(false, stub_error);312 user;313 dummy = 0;314 }236315237 /// Remove the user from the allowed list.316 /// Remove the user from the allowed list.238 ///317 ///245 dummy = 0;324 dummy = 0;246 }325 }326327 /// Remove user from allowed list.328 ///329 /// @param user User cross account address.330 /// @dev EVM selector for this function is: 0x09ba452a,331 /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))332 function removeFromCollectionAllowListCross(Tuple6 memory user) public {333 require(false, stub_error);334 user;335 dummy = 0;336 }247337248 /// Switch permission for minting.338 /// Switch permission for minting.249 ///339 ///269 return false;359 return false;270 }360 }361362 /// Check that account is the owner or admin of the collection363 ///364 /// @param user User cross account to verify365 /// @return "true" if account is the owner or admin366 /// @dev EVM selector for this function is: 0x3e75a905,367 /// or in textual repr: isOwnerOrAdminCross((address,uint256))368 function isOwnerOrAdminCross(Tuple6 memory user) public view returns (bool) {369 require(false, stub_error);370 user;371 dummy;372 return false;373 }271374272 /// Returns collection type375 /// Returns collection type273 ///376 ///282385283 /// Get collection owner.386 /// Get collection owner.284 ///387 ///285 /// @return Tuble with sponsor address and his substrate mirror.388 /// @return Tuple with sponsor address and his substrate mirror.286 /// If address is canonical then substrate mirror is zero and vice versa.389 /// If address is canonical then substrate mirror is zero and vice versa.287 /// @dev EVM selector for this function is: 0xdf727d3b,390 /// @dev EVM selector for this function is: 0xdf727d3b,288 /// or in textual repr: collectionOwner()391 /// or in textual repr: collectionOwner()304 dummy = 0;407 dummy = 0;305 }408 }409410 /// Get collection administrators411 ///412 /// @return Vector of tuples with admins address and his substrate mirror.413 /// If address is canonical then substrate mirror is zero and vice versa.414 /// @dev EVM selector for this function is: 0x5813216b,415 /// or in textual repr: collectionAdmins()416 function collectionAdmins() public view returns (Tuple6[] memory) {417 require(false, stub_error);418 dummy;419 return new Tuple6[](0);420 }421422 /// Changes collection owner to another account423 ///424 /// @dev Owner can be changed only by current owner425 /// @param newOwner new owner cross account426 /// @dev EVM selector for this function is: 0xe5c9913f,427 /// or in textual repr: setOwnerCross((address,uint256))428 function setOwnerCross(Tuple6 memory newOwner) public {429 require(false, stub_error);430 newOwner;431 dummy = 0;432 }306}433}434435/// @dev anonymous struct436struct Tuple10 {437 string field_0;438 bytes field_1;439}307440308/// @dev the ERC-165 identifier for this interface is 0x63034ac5441/// @dev the ERC-165 identifier for this interface is 0x032e5926309contract ERC20UniqueExtensions is Dummy, ERC165 {442contract ERC20UniqueExtensions is Dummy, ERC165 {443 /// @dev EVM selector for this function is: 0x0ecd0ab0,444 /// or in textual repr: approveCross((address,uint256),uint256)445 function approveCross(Tuple6 memory spender, uint256 amount) public returns (bool) {446 require(false, stub_error);447 spender;448 amount;449 dummy = 0;450 return false;451 }452310 /// Burn tokens from account453 /// Burn tokens from account311 /// @dev Function that burns an `amount` of the tokens of a given account,454 /// @dev Function that burns an `amount` of the tokens of a given account,322 return false;465 return false;323 }466 }467468 /// Burn tokens from account469 /// @dev Function that burns an `amount` of the tokens of a given account,470 /// deducting from the sender's allowance for said account.471 /// @param from The account whose tokens will be burnt.472 /// @param amount The amount that will be burnt.473 /// @dev EVM selector for this function is: 0xbb2f5a58,474 /// or in textual repr: burnFromCross((address,uint256),uint256)475 function burnFromCross(Tuple6 memory from, uint256 amount) public returns (bool) {476 require(false, stub_error);477 from;478 amount;479 dummy = 0;480 return false;481 }324482325 /// Mint tokens for multiple accounts.483 /// Mint tokens for multiple accounts.326 /// @param amounts array of pairs of account address and amount484 /// @param amounts array of pairs of account address and amount333 return false;491 return false;334 }492 }493494 /// @dev EVM selector for this function is: 0xd5cf430b,495 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)496 function transferFromCross(497 Tuple6 memory from,498 Tuple6 memory to,499 uint256 amount500 ) public returns (bool) {501 require(false, stub_error);502 from;503 to;504 amount;505 dummy = 0;506 return false;507 }335}508}336509337/// @dev anonymous struct510/// @dev anonymous structpallets/nonfungible/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445<!-- bureaucrate goes here -->67## [v0.1.6] - 2022-20-1089### Change1011- Added `set_properties` method for `TokenProperties` interface.125## [v0.1.5] - 2022-08-2413## [v0.1.5] - 2022-08-246147### Change15### Change8 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.91610<!-- bureaucrate goes here -->17- Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.1811## [v0.1.4] 2022-08-1619## [v0.1.4] 2022-08-16122028- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b36- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b293730## [0.1.2] - 2022-07-2538## [0.1.2] - 2022-07-253931### Changed40### Changed4132- New `token_uri` retrieval logic:42- New `token_uri` retrieval logic:334334 If the collection has a `url` property and it is not empty, it is returned.44 If the collection has a `url` property and it is not empty, it is returned.39 otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).49 otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).405041## [0.1.1] - 2022-07-1451## [0.1.1] - 2022-07-145242### Added53### Added435444- Implementation of RPC method `token_owners`.55- Implementation of RPC method `token_owners`.45 For reasons of compatibility with this pallet, returns only one owner if token exists.56 For reasons of compatibility with this pallet, returns only one owner if token exists.46 This was an internal request to improve the web interface and support fractionalization event.57 This was an internal request to improve the web interface and support fractionalization event.4758pallets/nonfungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-nonfungible"2name = "pallet-nonfungible"3version = "0.1.5"3version = "0.1.6"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/nonfungible/src/erc.rsdiffbeforeafterboth35use pallet_common::{35use pallet_common::{36 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},36 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},37 CollectionHandle, CollectionPropertyPermissions,37 CollectionHandle, CollectionPropertyPermissions,38 eth::convert_tuple_to_cross_account,38};39};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};40use pallet_evm::{account::CrossAccountId, PrecompileHandle};40use pallet_evm_coder_substrate::call;41use pallet_evm_coder_substrate::call;97 let key = <Vec<u8>>::from(key)98 let key = <Vec<u8>>::from(key)98 .try_into()99 .try_into()99 .map_err(|_| "key too long")?;100 .map_err(|_| "key too long")?;100 let value = value.try_into().map_err(|_| "value too long")?;101 let value = value.0.try_into().map_err(|_| "value too long")?;101102102 let nesting_budget = self103 let nesting_budget = self103 .recorder104 .recorder113 .map_err(dispatch_to_evm::<T>)114 .map_err(dispatch_to_evm::<T>)114 }115 }116117 /// @notice Set token properties value.118 /// @dev Throws error if `msg.sender` has no permission to edit the property.119 /// @param tokenId ID of the token.120 /// @param properties settable properties121 #[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]122 fn set_properties(123 &mut self,124 caller: caller,125 token_id: uint256,126 properties: Vec<(string, bytes)>,127 ) -> Result<()> {128 let caller = T::CrossAccountId::from_eth(caller);129 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;130131 let nesting_budget = self132 .recorder133 .weight_calls_budget(<StructureWeight<T>>::find_parent());134135 let properties = properties136 .into_iter()137 .map(|(key, value)| {138 let key = <Vec<u8>>::from(key)139 .try_into()140 .map_err(|_| "key too large")?;141142 let value = value.0.try_into().map_err(|_| "value too large")?;143144 Ok(Property { key, value })145 })146 .collect::<Result<Vec<_>>>()?;147148 <Pallet<T>>::set_token_properties(149 self,150 &caller,151 TokenId(token_id),152 properties.into_iter(),153 <Pallet<T>>::token_exists(&self, TokenId(token_id)),154 &nesting_budget,155 )156 .map_err(dispatch_to_evm::<T>)157 }115158116 /// @notice Delete token property value.159 /// @notice Delete token property value.117 /// @dev Throws error if `msg.sender` has no permission to edit the property.160 /// @dev Throws error if `msg.sender` has no permission to edit the property.146 let props = <TokenProperties<T>>::get((self.id, token_id));189 let props = <TokenProperties<T>>::get((self.id, token_id));147 let prop = props.get(&key).ok_or("key not found")?;190 let prop = props.get(&key).ok_or("key not found")?;148191149 Ok(prop.to_vec())192 Ok(prop.to_vec().into())150 }193 }151}194}152195199/// @dev See https://eips.ethereum.org/EIPS/eip-721242/// @dev See https://eips.ethereum.org/EIPS/eip-721200#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]243#[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]201impl<T: Config> NonfungibleHandle<T> {244impl<T: Config> NonfungibleHandle<T>245where246 T::AccountId: From<[u8; 32]>,247{202 /// @notice A descriptive name for a collection of NFTs in this contract248 /// @notice A descriptive name for a collection of NFTs in this contract203 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`249 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`604/// @title Unique extensions for ERC721.650/// @title Unique extensions for ERC721.605#[solidity_interface(name = ERC721UniqueExtensions)]651#[solidity_interface(name = ERC721UniqueExtensions)]606impl<T: Config> NonfungibleHandle<T> {652impl<T: Config> NonfungibleHandle<T>653where654 T::AccountId: From<[u8; 32]>,655{607 /// @notice A descriptive name for a collection of NFTs in this contract656 /// @notice A descriptive name for a collection of NFTs in this contract608 fn name(&self) -> Result<string> {657 fn name(&self) -> Result<string> {616 Ok(string::from_utf8_lossy(&self.token_prefix).into())665 Ok(string::from_utf8_lossy(&self.token_prefix).into())617 }666 }667668 /// @notice Set or reaffirm the approved address for an NFT669 /// @dev The zero address indicates there is no approved address.670 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized671 /// operator of the current owner.672 /// @param approved The new substrate address approved NFT controller673 /// @param tokenId The NFT to approve674 #[weight(<SelfWeightOf<T>>::approve())]675 fn approve_cross(676 &mut self,677 caller: caller,678 approved: (address, uint256),679 token_id: uint256,680 ) -> Result<void> {681 let caller = T::CrossAccountId::from_eth(caller);682 let approved = convert_tuple_to_cross_account::<T>(approved)?;683 let token = token_id.try_into()?;684685 <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))686 .map_err(dispatch_to_evm::<T>)?;687 Ok(())688 }618689619 /// @notice Transfer ownership of an NFT690 /// @notice Transfer ownership of an NFT620 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`691 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`634 Ok(())705 Ok(())635 }706 }707708 /// @notice Transfer ownership of an NFT from cross account address to cross account address709 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`710 /// is the zero address. Throws if `tokenId` is not a valid NFT.711 /// @param from Cross acccount address of current owner712 /// @param to Cross acccount address of new owner713 /// @param tokenId The NFT to transfer714 #[weight(<SelfWeightOf<T>>::transfer())]715 fn transfer_from_cross(716 &mut self,717 caller: caller,718 from: (address, uint256),719 to: (address, uint256),720 token_id: uint256,721 ) -> Result<void> {722 let caller = T::CrossAccountId::from_eth(caller);723 let from = convert_tuple_to_cross_account::<T>(from)?;724 let to = convert_tuple_to_cross_account::<T>(to)?;725 let token_id = token_id.try_into()?;726 let budget = self727 .recorder728 .weight_calls_budget(<StructureWeight<T>>::find_parent());729 Pallet::<T>::transfer_from(self, &caller, &from, &to, token_id, &budget)730 .map_err(dispatch_to_evm::<T>)?;731 Ok(())732 }636733637 /// @notice Burns a specific ERC721 token.734 /// @notice Burns a specific ERC721 token.638 /// @dev Throws unless `msg.sender` is the current owner or an authorized735 /// @dev Throws unless `msg.sender` is the current owner or an authorized654 Ok(())751 Ok(())655 }752 }753754 /// @notice Burns a specific ERC721 token.755 /// @dev Throws unless `msg.sender` is the current owner or an authorized756 /// operator for this NFT. Throws if `from` is not the current owner. Throws757 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.758 /// @param from The current owner of the NFT759 /// @param tokenId The NFT to transfer760 #[weight(<SelfWeightOf<T>>::burn_from())]761 fn burn_from_cross(762 &mut self,763 caller: caller,764 from: (address, uint256),765 token_id: uint256,766 ) -> Result<void> {767 let caller = T::CrossAccountId::from_eth(caller);768 let from = convert_tuple_to_cross_account::<T>(from)?;769 let token = token_id.try_into()?;770 let budget = self771 .recorder772 .weight_calls_budget(<StructureWeight<T>>::find_parent());773774 <Pallet<T>>::burn_from(self, &caller, &from, token, &budget)775 .map_err(dispatch_to_evm::<T>)?;776 Ok(())777 }656778657 /// @notice Returns next free NFT ID.779 /// @notice Returns next free NFT ID.658 fn next_token_id(&self) -> Result<uint256> {780 fn next_token_id(&self) -> Result<uint256> {pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth18}18}191920/// @title A contract that allows to set and delete token properties and change token property permissions.20/// @title A contract that allows to set and delete token properties and change token property permissions.21/// @dev the ERC-165 identifier for this interface is 0x4136937721/// @dev the ERC-165 identifier for this interface is 0x55dba91922contract TokenProperties is Dummy, ERC165 {22contract TokenProperties is Dummy, ERC165 {23 /// @notice Set permissions for token property.23 /// @notice Set permissions for token property.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.61 dummy = 0;61 dummy = 0;62 }62 }6364 /// @notice Set token properties value.65 /// @dev Throws error if `msg.sender` has no permission to edit the property.66 /// @param tokenId ID of the token.67 /// @param properties settable properties68 /// @dev EVM selector for this function is: 0x14ed3a6e,69 /// or in textual repr: setProperties(uint256,(string,bytes)[])70 function setProperties(uint256 tokenId, Tuple19[] memory properties) public {71 require(false, stub_error);72 tokenId;73 properties;74 dummy = 0;75 }637664 /// @notice Delete token property value.77 /// @notice Delete token property value.65 /// @dev Throws error if `msg.sender` has no permission to edit the property.78 /// @dev Throws error if `msg.sender` has no permission to edit the property.91}104}9210593/// @title A contract that allows you to work with collections.106/// @title A contract that allows you to work with collections.94/// @dev the ERC-165 identifier for this interface is 0x62e22290107/// @dev the ERC-165 identifier for this interface is 0xb3152af395contract Collection is Dummy, ERC165 {108contract Collection is Dummy, ERC165 {96 /// Set collection property.109 /// Set collection property.97 ///110 ///106 dummy = 0;119 dummy = 0;107 }120 }121122 /// Set collection properties.123 ///124 /// @param properties Vector of properties key/value pair.125 /// @dev EVM selector for this function is: 0x50b26b2a,126 /// or in textual repr: setCollectionProperties((string,bytes)[])127 function setCollectionProperties(Tuple19[] memory properties) public {128 require(false, stub_error);129 properties;130 dummy = 0;131 }108132109 /// Delete collection property.133 /// Delete collection property.110 ///134 ///117 dummy = 0;141 dummy = 0;118 }142 }143144 /// Delete collection properties.145 ///146 /// @param keys Properties keys.147 /// @dev EVM selector for this function is: 0xee206ee3,148 /// or in textual repr: deleteCollectionProperties(string[])149 function deleteCollectionProperties(string[] memory keys) public {150 require(false, stub_error);151 keys;152 dummy = 0;153 }119154120 /// Get collection property.155 /// Get collection property.121 ///156 ///132 return hex"";167 return hex"";133 }168 }169170 /// Get collection properties.171 ///172 /// @param keys Properties keys. Empty keys for all propertyes.173 /// @return Vector of properties key/value pairs.174 /// @dev EVM selector for this function is: 0x285fb8e6,175 /// or in textual repr: collectionProperties(string[])176 function collectionProperties(string[] memory keys) public view returns (Tuple19[] memory) {177 require(false, stub_error);178 keys;179 dummy;180 return new Tuple19[](0);181 }134182135 /// Set the sponsor of the collection.183 /// Set the sponsor of the collection.136 ///184 ///145 dummy = 0;193 dummy = 0;146 }194 }195196 /// Set the sponsor of the collection.197 ///198 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.199 ///200 /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.201 /// @dev EVM selector for this function is: 0x84a1d5a8,202 /// or in textual repr: setCollectionSponsorCross((address,uint256))203 function setCollectionSponsorCross(Tuple6 memory sponsor) public {204 require(false, stub_error);205 sponsor;206 dummy = 0;207 }147208148 /// Whether there is a pending sponsor.209 /// Whether there is a pending sponsor.149 /// @dev EVM selector for this function is: 0x058ac185,210 /// @dev EVM selector for this function is: 0x058ac185,177 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.238 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.178 /// @dev EVM selector for this function is: 0x6ec0a9f1,239 /// @dev EVM selector for this function is: 0x6ec0a9f1,179 /// or in textual repr: collectionSponsor()240 /// or in textual repr: collectionSponsor()180 function collectionSponsor() public view returns (Tuple17 memory) {241 function collectionSponsor() public view returns (Tuple6 memory) {181 require(false, stub_error);242 require(false, stub_error);182 dummy;243 dummy;183 return Tuple17(0x0000000000000000000000000000000000000000, 0);244 return Tuple6(0x0000000000000000000000000000000000000000, 0);184 }245 }185246186 /// Set limits for the collection.247 /// Set limits for the collection.227 return 0x0000000000000000000000000000000000000000;288 return 0x0000000000000000000000000000000000000000;228 }289 }290291 /// Add collection admin.292 /// @param newAdmin Cross account administrator address.293 /// @dev EVM selector for this function is: 0x859aa7d6,294 /// or in textual repr: addCollectionAdminCross((address,uint256))295 function addCollectionAdminCross(Tuple6 memory newAdmin) public {296 require(false, stub_error);297 newAdmin;298 dummy = 0;299 }300301 /// Remove collection admin.302 /// @param admin Cross account administrator address.303 /// @dev EVM selector for this function is: 0x6c0cd173,304 /// or in textual repr: removeCollectionAdminCross((address,uint256))305 function removeCollectionAdminCross(Tuple6 memory admin) public {306 require(false, stub_error);307 admin;308 dummy = 0;309 }229310230 /// Add collection admin.311 /// Add collection admin.231 /// @param newAdmin Address of the added administrator.312 /// @param newAdmin Address of the added administrator.307 dummy = 0;388 dummy = 0;308 }389 }390391 /// Add user to allowed list.392 ///393 /// @param user User cross account address.394 /// @dev EVM selector for this function is: 0xa0184a3a,395 /// or in textual repr: addToCollectionAllowListCross((address,uint256))396 function addToCollectionAllowListCross(Tuple6 memory user) public {397 require(false, stub_error);398 user;399 dummy = 0;400 }309401310 /// Remove the user from the allowed list.402 /// Remove the user from the allowed list.311 ///403 ///318 dummy = 0;410 dummy = 0;319 }411 }412413 /// Remove user from allowed list.414 ///415 /// @param user User cross account address.416 /// @dev EVM selector for this function is: 0x09ba452a,417 /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))418 function removeFromCollectionAllowListCross(Tuple6 memory user) public {419 require(false, stub_error);420 user;421 dummy = 0;422 }320423321 /// Switch permission for minting.424 /// Switch permission for minting.322 ///425 ///342 return false;445 return false;343 }446 }447448 /// Check that account is the owner or admin of the collection449 ///450 /// @param user User cross account to verify451 /// @return "true" if account is the owner or admin452 /// @dev EVM selector for this function is: 0x3e75a905,453 /// or in textual repr: isOwnerOrAdminCross((address,uint256))454 function isOwnerOrAdminCross(Tuple6 memory user) public view returns (bool) {455 require(false, stub_error);456 user;457 dummy;458 return false;459 }344460345 /// Returns collection type461 /// Returns collection type346 ///462 ///355471356 /// Get collection owner.472 /// Get collection owner.357 ///473 ///358 /// @return Tuble with sponsor address and his substrate mirror.474 /// @return Tuple with sponsor address and his substrate mirror.359 /// If address is canonical then substrate mirror is zero and vice versa.475 /// If address is canonical then substrate mirror is zero and vice versa.360 /// @dev EVM selector for this function is: 0xdf727d3b,476 /// @dev EVM selector for this function is: 0xdf727d3b,361 /// or in textual repr: collectionOwner()477 /// or in textual repr: collectionOwner()362 function collectionOwner() public view returns (Tuple17 memory) {478 function collectionOwner() public view returns (Tuple6 memory) {363 require(false, stub_error);479 require(false, stub_error);364 dummy;480 dummy;365 return Tuple17(0x0000000000000000000000000000000000000000, 0);481 return Tuple6(0x0000000000000000000000000000000000000000, 0);366 }482 }367483368 /// Changes collection owner to another account484 /// Changes collection owner to another account377 dummy = 0;493 dummy = 0;378 }494 }495496 /// Get collection administrators497 ///498 /// @return Vector of tuples with admins address and his substrate mirror.499 /// If address is canonical then substrate mirror is zero and vice versa.500 /// @dev EVM selector for this function is: 0x5813216b,501 /// or in textual repr: collectionAdmins()502 function collectionAdmins() public view returns (Tuple6[] memory) {503 require(false, stub_error);504 dummy;505 return new Tuple6[](0);506 }507508 /// Changes collection owner to another account509 ///510 /// @dev Owner can be changed only by current owner511 /// @param newOwner new owner cross account512 /// @dev EVM selector for this function is: 0xe5c9913f,513 /// or in textual repr: setOwnerCross((address,uint256))514 function setOwnerCross(Tuple6 memory newOwner) public {515 require(false, stub_error);516 newOwner;517 dummy = 0;518 }379}519}380520381/// @dev anonymous struct521/// @dev anonymous struct382struct Tuple17 {522struct Tuple19 {383 address field_0;523 string field_0;384 uint256 field_1;524 bytes field_1;385}525}386526387/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension527/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension528}668}529669530/// @title Unique extensions for ERC721.670/// @title Unique extensions for ERC721.531/// @dev the ERC-165 identifier for this interface is 0x4468500d671/// @dev the ERC-165 identifier for this interface is 0x244543ee532contract ERC721UniqueExtensions is Dummy, ERC165 {672contract ERC721UniqueExtensions is Dummy, ERC165 {533 /// @notice A descriptive name for a collection of NFTs in this contract673 /// @notice A descriptive name for a collection of NFTs in this contract534 /// @dev EVM selector for this function is: 0x06fdde03,674 /// @dev EVM selector for this function is: 0x06fdde03,548 return "";688 return "";549 }689 }690691 /// @notice Set or reaffirm the approved address for an NFT692 /// @dev The zero address indicates there is no approved address.693 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized694 /// operator of the current owner.695 /// @param approved The new substrate address approved NFT controller696 /// @param tokenId The NFT to approve697 /// @dev EVM selector for this function is: 0x0ecd0ab0,698 /// or in textual repr: approveCross((address,uint256),uint256)699 function approveCross(Tuple6 memory approved, uint256 tokenId) public {700 require(false, stub_error);701 approved;702 tokenId;703 dummy = 0;704 }550705551 /// @notice Transfer ownership of an NFT706 /// @notice Transfer ownership of an NFT552 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`707 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`562 dummy = 0;717 dummy = 0;563 }718 }719720 /// @notice Transfer ownership of an NFT from cross account address to cross account address721 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`722 /// is the zero address. Throws if `tokenId` is not a valid NFT.723 /// @param from Cross acccount address of current owner724 /// @param to Cross acccount address of new owner725 /// @param tokenId The NFT to transfer726 /// @dev EVM selector for this function is: 0xd5cf430b,727 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)728 function transferFromCross(729 Tuple6 memory from,730 Tuple6 memory to,731 uint256 tokenId732 ) public {733 require(false, stub_error);734 from;735 to;736 tokenId;737 dummy = 0;738 }564739565 /// @notice Burns a specific ERC721 token.740 /// @notice Burns a specific ERC721 token.566 /// @dev Throws unless `msg.sender` is the current owner or an authorized741 /// @dev Throws unless `msg.sender` is the current owner or an authorized577 dummy = 0;752 dummy = 0;578 }753 }754755 /// @notice Burns a specific ERC721 token.756 /// @dev Throws unless `msg.sender` is the current owner or an authorized757 /// operator for this NFT. Throws if `from` is not the current owner. Throws758 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.759 /// @param from The current owner of the NFT760 /// @param tokenId The NFT to transfer761 /// @dev EVM selector for this function is: 0xbb2f5a58,762 /// or in textual repr: burnFromCross((address,uint256),uint256)763 function burnFromCross(Tuple6 memory from, uint256 tokenId) public {764 require(false, stub_error);765 from;766 tokenId;767 dummy = 0;768 }579769580 /// @notice Returns next free NFT ID.770 /// @notice Returns next free NFT ID.581 /// @dev EVM selector for this function is: 0x75794a3c,771 /// @dev EVM selector for this function is: 0x75794a3c,607 // /// @param tokens array of pairs of token ID and token URI for minted tokens797 // /// @param tokens array of pairs of token ID and token URI for minted tokens608 // /// @dev EVM selector for this function is: 0x36543006,798 // /// @dev EVM selector for this function is: 0x36543006,609 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])799 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])610 // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) public returns (bool) {800 // function mintBulkWithTokenURI(address to, Tuple8[] memory tokens) public returns (bool) {611 // require(false, stub_error);801 // require(false, stub_error);612 // to;802 // to;613 // tokens;803 // tokens;618}808}619809620/// @dev anonymous struct810/// @dev anonymous struct621struct Tuple6 {811struct Tuple8 {622 uint256 field_0;812 uint256 field_0;623 string field_1;813 string field_1;624}814}815816/// @dev anonymous struct817struct Tuple6 {818 address field_0;819 uint256 field_1;820}625821626/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension822/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension627/// @dev See https://eips.ethereum.org/EIPS/eip-721823/// @dev See https://eips.ethereum.org/EIPS/eip-721pallets/refungible/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [v0.2.5] - 2022-20-1067### Change89- Added `set_properties` method for `TokenProperties` interface.105## [v0.2.4] - 2022-08-2411## [v0.2.4] - 2022-08-246127### Change13### Change8 - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.91415- Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`.1610<!-- bureaucrate goes here -->17<!-- bureaucrate goes here -->1811## [v0.2.3] 2022-08-1619## [v0.2.3] 2022-08-16122013### Other changes21### Other changespallets/refungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-refungible"2name = "pallet-refungible"3version = "0.2.4"3version = "0.2.5"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/refungible/src/erc.rsdiffbeforeafterboth30use pallet_common::{30use pallet_common::{31 CollectionHandle, CollectionPropertyPermissions,31 CollectionHandle, CollectionPropertyPermissions,32 erc::{CommonEvmHandler, CollectionCall, static_property::key},32 erc::{CommonEvmHandler, CollectionCall, static_property::key},33 eth::convert_tuple_to_cross_account,33};34};34use pallet_evm::{account::CrossAccountId, PrecompileHandle};35use pallet_evm::{account::CrossAccountId, PrecompileHandle};35use pallet_evm_coder_substrate::{call, dispatch_to_evm};36use pallet_evm_coder_substrate::{call, dispatch_to_evm};100 let key = <Vec<u8>>::from(key)101 let key = <Vec<u8>>::from(key)101 .try_into()102 .try_into()102 .map_err(|_| "key too long")?;103 .map_err(|_| "key too long")?;103 let value = value.try_into().map_err(|_| "value too long")?;104 let value = value.0.try_into().map_err(|_| "value too long")?;104105105 let nesting_budget = self106 let nesting_budget = self106 .recorder107 .recorder116 .map_err(dispatch_to_evm::<T>)117 .map_err(dispatch_to_evm::<T>)117 }118 }119120 /// @notice Set token properties value.121 /// @dev Throws error if `msg.sender` has no permission to edit the property.122 /// @param tokenId ID of the token.123 /// @param properties settable properties124 fn set_properties(125 &mut self,126 caller: caller,127 token_id: uint256,128 properties: Vec<(string, bytes)>,129 ) -> Result<()> {130 let caller = T::CrossAccountId::from_eth(caller);131 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;132133 let nesting_budget = self134 .recorder135 .weight_calls_budget(<StructureWeight<T>>::find_parent());136137 let properties = properties138 .into_iter()139 .map(|(key, value)| {140 let key = <Vec<u8>>::from(key)141 .try_into()142 .map_err(|_| "key too large")?;143144 let value = value.0.try_into().map_err(|_| "value too large")?;145146 Ok(Property { key, value })147 })148 .collect::<Result<Vec<_>>>()?;149150 <Pallet<T>>::set_token_properties(151 self,152 &caller,153 TokenId(token_id),154 properties.into_iter(),155 <Pallet<T>>::token_exists(&self, TokenId(token_id)),156 &nesting_budget,157 )158 .map_err(dispatch_to_evm::<T>)159 }118160119 /// @notice Delete token property value.161 /// @notice Delete token property value.120 /// @dev Throws error if `msg.sender` has no permission to edit the property.162 /// @dev Throws error if `msg.sender` has no permission to edit the property.149 let props = <TokenProperties<T>>::get((self.id, token_id));191 let props = <TokenProperties<T>>::get((self.id, token_id));150 let prop = props.get(&key).ok_or("key not found")?;192 let prop = props.get(&key).ok_or("key not found")?;151193152 Ok(prop.to_vec())194 Ok(prop.to_vec().into())153 }195 }154}196}155197195237196#[solidity_interface(name = ERC721Metadata)]238#[solidity_interface(name = ERC721Metadata)]197impl<T: Config> RefungibleHandle<T> {239impl<T: Config> RefungibleHandle<T>240where241 T::AccountId: From<[u8; 32]>,242{198 /// @notice A descriptive name for a collection of NFTs in this contract243 /// @notice A descriptive name for a collection of NFTs in this contract199 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`244 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`632/// @title Unique extensions for ERC721.677/// @title Unique extensions for ERC721.633#[solidity_interface(name = ERC721UniqueExtensions)]678#[solidity_interface(name = ERC721UniqueExtensions)]634impl<T: Config> RefungibleHandle<T> {679impl<T: Config> RefungibleHandle<T>680where681 T::AccountId: From<[u8; 32]>,682{635 /// @notice A descriptive name for a collection of NFTs in this contract683 /// @notice A descriptive name for a collection of NFTs in this contract636 fn name(&self) -> Result<string> {684 fn name(&self) -> Result<string> {659 .recorder707 .recorder660 .weight_calls_budget(<StructureWeight<T>>::find_parent());708 .weight_calls_budget(<StructureWeight<T>>::find_parent());661709662 let balance = balance(&self, token, &caller)?;710 let balance = balance(self, token, &caller)?;663 ensure_single_owner(&self, token, balance)?;711 ensure_single_owner(self, token, balance)?;664712665 <Pallet<T>>::transfer(self, &caller, &to, token, balance, &budget)713 <Pallet<T>>::transfer(self, &caller, &to, token, balance, &budget)666 .map_err(dispatch_to_evm::<T>)?;714 .map_err(dispatch_to_evm::<T>)?;667 Ok(())715 Ok(())668 }716 }717718 /// @notice Transfer ownership of an RFT719 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`720 /// is the zero address. Throws if `tokenId` is not a valid RFT.721 /// Throws if RFT pieces have multiple owners.722 /// @param to The new owner723 /// @param tokenId The RFT to transfer724 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]725 fn transfer_from_cross(726 &mut self,727 caller: caller,728 from: (address, uint256),729 to: (address, uint256),730 token_id: uint256,731 ) -> Result<void> {732 let caller = T::CrossAccountId::from_eth(caller);733 let from = convert_tuple_to_cross_account::<T>(from)?;734 let to = convert_tuple_to_cross_account::<T>(to)?;735 let token_id = token_id.try_into()?;736 let budget = self737 .recorder738 .weight_calls_budget(<StructureWeight<T>>::find_parent());739740 let balance = balance(self, token_id, &from)?;741 ensure_single_owner(self, token_id, balance)?;742743 Pallet::<T>::transfer_from(self, &caller, &from, &to, token_id, balance, &budget)744 .map_err(dispatch_to_evm::<T>)?;745 Ok(())746 }669747670 /// @notice Burns a specific ERC721 token.748 /// @notice Burns a specific ERC721 token.671 /// @dev Throws unless `msg.sender` is the current owner or an authorized749 /// @dev Throws unless `msg.sender` is the current owner or an authorized683 .recorder761 .recorder684 .weight_calls_budget(<StructureWeight<T>>::find_parent());762 .weight_calls_budget(<StructureWeight<T>>::find_parent());685763686 let balance = balance(&self, token, &caller)?;764 let balance = balance(self, token, &from)?;687 ensure_single_owner(&self, token, balance)?;765 ensure_single_owner(self, token, balance)?;688766689 <Pallet<T>>::burn_from(self, &caller, &from, token, balance, &budget)767 <Pallet<T>>::burn_from(self, &caller, &from, token, balance, &budget)690 .map_err(dispatch_to_evm::<T>)?;768 .map_err(dispatch_to_evm::<T>)?;691 Ok(())769 Ok(())692 }770 }771772 /// @notice Burns a specific ERC721 token.773 /// @dev Throws unless `msg.sender` is the current owner or an authorized774 /// operator for this RFT. Throws if `from` is not the current owner. Throws775 /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.776 /// Throws if RFT pieces have multiple owners.777 /// @param from The current owner of the RFT778 /// @param tokenId The RFT to transfer779 #[weight(<SelfWeightOf<T>>::burn_from())]780 fn burn_from_cross(781 &mut self,782 caller: caller,783 from: (address, uint256),784 token_id: uint256,785 ) -> Result<void> {786 let caller = T::CrossAccountId::from_eth(caller);787 let from = convert_tuple_to_cross_account::<T>(from)?;788 let token = token_id.try_into()?;789 let budget = self790 .recorder791 .weight_calls_budget(<StructureWeight<T>>::find_parent());792793 let balance = balance(self, token, &from)?;794 ensure_single_owner(self, token, balance)?;795796 <Pallet<T>>::burn_from(self, &caller, &from, token, balance, &budget)797 .map_err(dispatch_to_evm::<T>)?;798 Ok(())799 }693800694 /// @notice Returns next free RFT ID.801 /// @notice Returns next free RFT ID.695 fn next_token_id(&self) -> Result<uint256> {802 fn next_token_id(&self) -> Result<uint256> {pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth18}18}191920/// @title A contract that allows to set and delete token properties and change token property permissions.20/// @title A contract that allows to set and delete token properties and change token property permissions.21/// @dev the ERC-165 identifier for this interface is 0x4136937721/// @dev the ERC-165 identifier for this interface is 0x55dba91922contract TokenProperties is Dummy, ERC165 {22contract TokenProperties is Dummy, ERC165 {23 /// @notice Set permissions for token property.23 /// @notice Set permissions for token property.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.61 dummy = 0;61 dummy = 0;62 }62 }6364 /// @notice Set token properties value.65 /// @dev Throws error if `msg.sender` has no permission to edit the property.66 /// @param tokenId ID of the token.67 /// @param properties settable properties68 /// @dev EVM selector for this function is: 0x14ed3a6e,69 /// or in textual repr: setProperties(uint256,(string,bytes)[])70 function setProperties(uint256 tokenId, Tuple19[] memory properties) public {71 require(false, stub_error);72 tokenId;73 properties;74 dummy = 0;75 }637664 /// @notice Delete token property value.77 /// @notice Delete token property value.65 /// @dev Throws error if `msg.sender` has no permission to edit the property.78 /// @dev Throws error if `msg.sender` has no permission to edit the property.91}104}9210593/// @title A contract that allows you to work with collections.106/// @title A contract that allows you to work with collections.94/// @dev the ERC-165 identifier for this interface is 0x62e22290107/// @dev the ERC-165 identifier for this interface is 0xb3152af395contract Collection is Dummy, ERC165 {108contract Collection is Dummy, ERC165 {96 /// Set collection property.109 /// Set collection property.97 ///110 ///106 dummy = 0;119 dummy = 0;107 }120 }121122 /// Set collection properties.123 ///124 /// @param properties Vector of properties key/value pair.125 /// @dev EVM selector for this function is: 0x50b26b2a,126 /// or in textual repr: setCollectionProperties((string,bytes)[])127 function setCollectionProperties(Tuple19[] memory properties) public {128 require(false, stub_error);129 properties;130 dummy = 0;131 }108132109 /// Delete collection property.133 /// Delete collection property.110 ///134 ///117 dummy = 0;141 dummy = 0;118 }142 }143144 /// Delete collection properties.145 ///146 /// @param keys Properties keys.147 /// @dev EVM selector for this function is: 0xee206ee3,148 /// or in textual repr: deleteCollectionProperties(string[])149 function deleteCollectionProperties(string[] memory keys) public {150 require(false, stub_error);151 keys;152 dummy = 0;153 }119154120 /// Get collection property.155 /// Get collection property.121 ///156 ///132 return hex"";167 return hex"";133 }168 }169170 /// Get collection properties.171 ///172 /// @param keys Properties keys. Empty keys for all propertyes.173 /// @return Vector of properties key/value pairs.174 /// @dev EVM selector for this function is: 0x285fb8e6,175 /// or in textual repr: collectionProperties(string[])176 function collectionProperties(string[] memory keys) public view returns (Tuple19[] memory) {177 require(false, stub_error);178 keys;179 dummy;180 return new Tuple19[](0);181 }134182135 /// Set the sponsor of the collection.183 /// Set the sponsor of the collection.136 ///184 ///145 dummy = 0;193 dummy = 0;146 }194 }195196 /// Set the sponsor of the collection.197 ///198 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.199 ///200 /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.201 /// @dev EVM selector for this function is: 0x84a1d5a8,202 /// or in textual repr: setCollectionSponsorCross((address,uint256))203 function setCollectionSponsorCross(Tuple6 memory sponsor) public {204 require(false, stub_error);205 sponsor;206 dummy = 0;207 }147208148 /// Whether there is a pending sponsor.209 /// Whether there is a pending sponsor.149 /// @dev EVM selector for this function is: 0x058ac185,210 /// @dev EVM selector for this function is: 0x058ac185,177 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.238 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.178 /// @dev EVM selector for this function is: 0x6ec0a9f1,239 /// @dev EVM selector for this function is: 0x6ec0a9f1,179 /// or in textual repr: collectionSponsor()240 /// or in textual repr: collectionSponsor()180 function collectionSponsor() public view returns (Tuple17 memory) {241 function collectionSponsor() public view returns (Tuple6 memory) {181 require(false, stub_error);242 require(false, stub_error);182 dummy;243 dummy;183 return Tuple17(0x0000000000000000000000000000000000000000, 0);244 return Tuple6(0x0000000000000000000000000000000000000000, 0);184 }245 }185246186 /// Set limits for the collection.247 /// Set limits for the collection.227 return 0x0000000000000000000000000000000000000000;288 return 0x0000000000000000000000000000000000000000;228 }289 }290291 /// Add collection admin.292 /// @param newAdmin Cross account administrator address.293 /// @dev EVM selector for this function is: 0x859aa7d6,294 /// or in textual repr: addCollectionAdminCross((address,uint256))295 function addCollectionAdminCross(Tuple6 memory newAdmin) public {296 require(false, stub_error);297 newAdmin;298 dummy = 0;299 }300301 /// Remove collection admin.302 /// @param admin Cross account administrator address.303 /// @dev EVM selector for this function is: 0x6c0cd173,304 /// or in textual repr: removeCollectionAdminCross((address,uint256))305 function removeCollectionAdminCross(Tuple6 memory admin) public {306 require(false, stub_error);307 admin;308 dummy = 0;309 }229310230 /// Add collection admin.311 /// Add collection admin.231 /// @param newAdmin Address of the added administrator.312 /// @param newAdmin Address of the added administrator.307 dummy = 0;388 dummy = 0;308 }389 }390391 /// Add user to allowed list.392 ///393 /// @param user User cross account address.394 /// @dev EVM selector for this function is: 0xa0184a3a,395 /// or in textual repr: addToCollectionAllowListCross((address,uint256))396 function addToCollectionAllowListCross(Tuple6 memory user) public {397 require(false, stub_error);398 user;399 dummy = 0;400 }309401310 /// Remove the user from the allowed list.402 /// Remove the user from the allowed list.311 ///403 ///318 dummy = 0;410 dummy = 0;319 }411 }412413 /// Remove user from allowed list.414 ///415 /// @param user User cross account address.416 /// @dev EVM selector for this function is: 0x09ba452a,417 /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))418 function removeFromCollectionAllowListCross(Tuple6 memory user) public {419 require(false, stub_error);420 user;421 dummy = 0;422 }320423321 /// Switch permission for minting.424 /// Switch permission for minting.322 ///425 ///342 return false;445 return false;343 }446 }447448 /// Check that account is the owner or admin of the collection449 ///450 /// @param user User cross account to verify451 /// @return "true" if account is the owner or admin452 /// @dev EVM selector for this function is: 0x3e75a905,453 /// or in textual repr: isOwnerOrAdminCross((address,uint256))454 function isOwnerOrAdminCross(Tuple6 memory user) public view returns (bool) {455 require(false, stub_error);456 user;457 dummy;458 return false;459 }344460345 /// Returns collection type461 /// Returns collection type346 ///462 ///355471356 /// Get collection owner.472 /// Get collection owner.357 ///473 ///358 /// @return Tuble with sponsor address and his substrate mirror.474 /// @return Tuple with sponsor address and his substrate mirror.359 /// If address is canonical then substrate mirror is zero and vice versa.475 /// If address is canonical then substrate mirror is zero and vice versa.360 /// @dev EVM selector for this function is: 0xdf727d3b,476 /// @dev EVM selector for this function is: 0xdf727d3b,361 /// or in textual repr: collectionOwner()477 /// or in textual repr: collectionOwner()362 function collectionOwner() public view returns (Tuple17 memory) {478 function collectionOwner() public view returns (Tuple6 memory) {363 require(false, stub_error);479 require(false, stub_error);364 dummy;480 dummy;365 return Tuple17(0x0000000000000000000000000000000000000000, 0);481 return Tuple6(0x0000000000000000000000000000000000000000, 0);366 }482 }367483368 /// Changes collection owner to another account484 /// Changes collection owner to another account377 dummy = 0;493 dummy = 0;378 }494 }495496 /// Get collection administrators497 ///498 /// @return Vector of tuples with admins address and his substrate mirror.499 /// If address is canonical then substrate mirror is zero and vice versa.500 /// @dev EVM selector for this function is: 0x5813216b,501 /// or in textual repr: collectionAdmins()502 function collectionAdmins() public view returns (Tuple6[] memory) {503 require(false, stub_error);504 dummy;505 return new Tuple6[](0);506 }507508 /// Changes collection owner to another account509 ///510 /// @dev Owner can be changed only by current owner511 /// @param newOwner new owner cross account512 /// @dev EVM selector for this function is: 0xe5c9913f,513 /// or in textual repr: setOwnerCross((address,uint256))514 function setOwnerCross(Tuple6 memory newOwner) public {515 require(false, stub_error);516 newOwner;517 dummy = 0;518 }379}519}380520381/// @dev anonymous struct521/// @dev anonymous struct382struct Tuple17 {522struct Tuple19 {383 address field_0;523 string field_0;384 uint256 field_1;524 bytes field_1;385}525}386526387/// @dev the ERC-165 identifier for this interface is 0x5b5e139f527/// @dev the ERC-165 identifier for this interface is 0x5b5e139f526}666}527667528/// @title Unique extensions for ERC721.668/// @title Unique extensions for ERC721.529/// @dev the ERC-165 identifier for this interface is 0xef1eaacb669/// @dev the ERC-165 identifier for this interface is 0x81feb398530contract ERC721UniqueExtensions is Dummy, ERC165 {670contract ERC721UniqueExtensions is Dummy, ERC165 {531 /// @notice A descriptive name for a collection of NFTs in this contract671 /// @notice A descriptive name for a collection of NFTs in this contract532 /// @dev EVM selector for this function is: 0x06fdde03,672 /// @dev EVM selector for this function is: 0x06fdde03,561 dummy = 0;701 dummy = 0;562 }702 }703704 /// @notice Transfer ownership of an RFT705 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`706 /// is the zero address. Throws if `tokenId` is not a valid RFT.707 /// Throws if RFT pieces have multiple owners.708 /// @param to The new owner709 /// @param tokenId The RFT to transfer710 /// @dev EVM selector for this function is: 0xd5cf430b,711 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)712 function transferFromCross(713 Tuple6 memory from,714 Tuple6 memory to,715 uint256 tokenId716 ) public {717 require(false, stub_error);718 from;719 to;720 tokenId;721 dummy = 0;722 }563723564 /// @notice Burns a specific ERC721 token.724 /// @notice Burns a specific ERC721 token.565 /// @dev Throws unless `msg.sender` is the current owner or an authorized725 /// @dev Throws unless `msg.sender` is the current owner or an authorized577 dummy = 0;737 dummy = 0;578 }738 }739740 /// @notice Burns a specific ERC721 token.741 /// @dev Throws unless `msg.sender` is the current owner or an authorized742 /// operator for this RFT. Throws if `from` is not the current owner. Throws743 /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.744 /// Throws if RFT pieces have multiple owners.745 /// @param from The current owner of the RFT746 /// @param tokenId The RFT to transfer747 /// @dev EVM selector for this function is: 0xbb2f5a58,748 /// or in textual repr: burnFromCross((address,uint256),uint256)749 function burnFromCross(Tuple6 memory from, uint256 tokenId) public {750 require(false, stub_error);751 from;752 tokenId;753 dummy = 0;754 }579755580 /// @notice Returns next free RFT ID.756 /// @notice Returns next free RFT ID.581 /// @dev EVM selector for this function is: 0x75794a3c,757 /// @dev EVM selector for this function is: 0x75794a3c,608 // /// @param tokens array of pairs of token ID and token URI for minted tokens784 // /// @param tokens array of pairs of token ID and token URI for minted tokens609 // /// @dev EVM selector for this function is: 0x36543006,785 // /// @dev EVM selector for this function is: 0x36543006,610 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])786 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])611 // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) public returns (bool) {787 // function mintBulkWithTokenURI(address to, Tuple8[] memory tokens) public returns (bool) {612 // require(false, stub_error);788 // require(false, stub_error);613 // to;789 // to;614 // tokens;790 // tokens;630}806}631807632/// @dev anonymous struct808/// @dev anonymous struct633struct Tuple6 {809struct Tuple8 {634 uint256 field_0;810 uint256 field_0;635 string field_1;811 string field_1;636}812}813814/// @dev anonymous struct815struct Tuple6 {816 address field_0;817 uint256 field_1;818}637819638/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension820/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension639/// @dev See https://eips.ethereum.org/EIPS/eip-721821/// @dev See https://eips.ethereum.org/EIPS/eip-721pallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterbothbinary blob — no preview
pallets/scheduler-v2/Cargo.tomldiffbeforeafterbothno changes
pallets/scheduler-v2/src/benchmarking.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/lib.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/mock.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/tests.rsdiffbeforeafterbothno changes
pallets/scheduler-v2/src/weights.rsdiffbeforeafterbothno changes
pallets/scheduler/src/benchmarking.rsdiffbeforeafterboth505051const BLOCK_NUMBER: u32 = 2;51const BLOCK_NUMBER: u32 = 2;5253fn make_scheduled_id(src: u32) -> ScheduledId {54 let slice_id: [u8; 4] = src.encode().try_into().unwrap();55 let mut id: [u8; 16] = [0; 16];56 id[..4].clone_from_slice(&slice_id);57 id58}525953/// Add `n` named items to the schedule.60/// Add `n` named items to the schedule.54///61///79 false => None,86 false => None,80 };87 };818882 let slice_id: [u8; 4] = i.encode().try_into().unwrap();89 let id = make_scheduled_id(i);83 let mut id: [u8; 16] = [0; 16];84 id[..4].clone_from_slice(&slice_id);8586 let origin = frame_system::RawOrigin::Signed(caller.clone()).into();90 let origin = frame_system::RawOrigin::Signed(caller.clone()).into();87 Scheduler::<T>::do_schedule_named(id, t, period, 0, origin, call_or_hash)?;91 Scheduler::<T>::do_schedule_named(id, t, period, 0, origin, call_or_hash)?;202 id[..4].clone_from_slice(&slice_id);206 id[..4].clone_from_slice(&slice_id);203 let when = BLOCK_NUMBER.into();207 let when = BLOCK_NUMBER.into();204 let periodic = Some((T::BlockNumber::one(), 100));208 let periodic = Some((T::BlockNumber::one(), 100));205 let priority = 0;209 let priority = None;206 // Essentially a no-op call.210 // Essentially a no-op call.207 let inner_call = frame_system::Call::set_storage { items: vec![] }.into();211 let inner_call = frame_system::Call::set_storage { items: vec![] }.into();208 let call = Box::new(CallOrHashOf::<T>::Value(inner_call));212 let call = Box::new(CallOrHashOf::<T>::Value(inner_call));220 let origin: RawOrigin<T::AccountId> = frame_system::RawOrigin::Signed(caller.clone());224 let origin: RawOrigin<T::AccountId> = frame_system::RawOrigin::Signed(caller.clone());221 let s in 1 .. T::MaxScheduledPerBlock::get();225 let s in 1 .. T::MaxScheduledPerBlock::get();222 let when = BLOCK_NUMBER.into();226 let when = BLOCK_NUMBER.into();227 let idx = s - 1;223 let id = 0.encode().try_into().unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]);228 let id = make_scheduled_id(idx);224 fill_schedule::<T>(when, s, true, Some(false))?;229 fill_schedule::<T>(when, s, true, Some(false))?;225 }: _(origin, id)230 }: _(origin, id)226 verify {231 verify {230 );235 );231 // Removed schedule is NONE236 // Removed schedule is NONE232 ensure!(237 ensure!(233 Agenda::<T>::get(when)[0].is_none(),238 Agenda::<T>::get(when)[idx as usize].is_none(),234 "didn't remove from schedule"239 "didn't remove from schedule"235 );240 );236 }241 }242243 change_named_priority {244 let origin: RawOrigin<T::AccountId> = frame_system::RawOrigin::Root;245 let s in 1 .. T::MaxScheduledPerBlock::get();246 let when = BLOCK_NUMBER.into();247 let idx = s - 1;248 let id = make_scheduled_id(idx);249 let priority = 42;250 fill_schedule::<T>(when, s, true, Some(false))?;251 }: _(origin, id, priority)252 verify {253 ensure!(254 Agenda::<T>::get(when)[idx as usize].clone().unwrap().priority == priority,255 "didn't change the priority"256 );257 }237258238 impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test);259 impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test);239}260}pallets/scheduler/src/lib.rsdiffbeforeafterboth878788use frame_support::{88use frame_support::{89 dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter, GetDispatchInfo},89 dispatch::{90 DispatchError, DispatchResult, Dispatchable, UnfilteredDispatchable, Parameter,91 GetDispatchInfo,92 },90 traits::{93 traits::{91 schedule::{self, DispatchTime, MaybeHashed},94 schedule::{self, DispatchTime, MaybeHashed},9710098pub use weights::WeightInfo;101pub use weights::WeightInfo;99102100/// Just a simple index for naming period tasks.101pub type PeriodicIndex = u32;102/// The location of a scheduled task that can be used to remove it.103/// The location of a scheduled task that can be used to remove it.103pub type TaskAddress<BlockNumber> = (BlockNumber, u32);104pub type TaskAddress<BlockNumber> = (BlockNumber, u32);104pub const MAX_TASK_ID_LENGTH_IN_BYTES: u8 = 16;105pub const MAX_TASK_ID_LENGTH_IN_BYTES: u8 = 16;105106106type ScheduledId = [u8; MAX_TASK_ID_LENGTH_IN_BYTES as usize];107pub type ScheduledId = [u8; MAX_TASK_ID_LENGTH_IN_BYTES as usize];107pub type CallOrHashOf<T> =108pub type CallOrHashOf<T> =108 MaybeHashed<<T as Config>::RuntimeCall, <T as frame_system::Config>::Hash>;109 MaybeHashed<<T as Config>::RuntimeCall, <T as frame_system::Config>::Hash>;109110137pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =138pub type Scheduled<Call, BlockNumber, PalletsOrigin, AccountId> =138 ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId>;139 ScheduledV3<Call, BlockNumber, PalletsOrigin, AccountId>;140141pub enum ScheduledEnsureOriginSuccess<AccountId> {142 Root,143 Signed(AccountId),144}139145140#[cfg(feature = "runtime-benchmarks")]146#[cfg(feature = "runtime-benchmarks")]141mod preimage_provider {147mod preimage_provider {194 dispatch::PostDispatchInfo,200 dispatch::PostDispatchInfo,195 pallet_prelude::*,201 pallet_prelude::*,196 traits::{schedule::LookupError, PreimageProvider},202 traits::{203 schedule::{LookupError, LOWEST_PRIORITY},204 PreimageProvider,205 },197 };206 };198 use frame_system::pallet_prelude::*;207 use frame_system::pallet_prelude::*;227 + Dispatchable<236 + Dispatchable<228 RuntimeOrigin = <Self as Config>::RuntimeOrigin,237 RuntimeOrigin = <Self as Config>::RuntimeOrigin,229 PostInfo = PostDispatchInfo,238 PostInfo = PostDispatchInfo,230 > + GetDispatchInfo239 > + UnfilteredDispatchable<RuntimeOrigin = <Self as system::Config>::RuntimeOrigin>240 + GetDispatchInfo231 + From<system::Call<Self>>;241 + From<system::Call<Self>>;232242237247238 /// Required origin to schedule or cancel calls.248 /// Required origin to schedule or cancel calls.239 type ScheduleOrigin: EnsureOrigin<<Self as system::Config>::RuntimeOrigin>;249 type ScheduleOrigin: EnsureOrigin<250 <Self as system::Config>::RuntimeOrigin,251 Success = ScheduledEnsureOriginSuccess<Self::AccountId>,252 >;253254 /// Required origin to set/change calls' priority.255 type PrioritySetOrigin: EnsureOrigin<<Self as system::Config>::RuntimeOrigin>;240256241 /// Compare the privileges of origins.257 /// Compare the privileges of origins.242 ///258 ///287303288 /// Resolve the call dispatch, including any post-dispatch operations.304 /// Resolve the call dispatch, including any post-dispatch operations.289 fn dispatch_call(305 fn dispatch_call(290 signer: T::AccountId,306 signer: Option<T::AccountId>,291 function: <T as Config>::RuntimeCall,307 function: <T as Config>::RuntimeCall,292 ) -> Result<308 ) -> Result<293 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,309 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,319 Scheduled { when: T::BlockNumber, index: u32 },335 Scheduled { when: T::BlockNumber, index: u32 },320 /// Canceled some task.336 /// Canceled some task.321 Canceled { when: T::BlockNumber, index: u32 },337 Canceled { when: T::BlockNumber, index: u32 },338 /// Scheduled task's priority has changed339 PriorityChanged {340 when: T::BlockNumber,341 index: u32,342 priority: schedule::Priority,343 },322 /// Dispatched some task.344 /// Dispatched some task.323 Dispatched {345 Dispatched {324 task: TaskAddress<T::BlockNumber>,346 task: TaskAddress<T::BlockNumber>,371393372 let mut total_weight: Weight = T::WeightInfo::on_initialize(0);394 let mut total_weight: Weight = T::WeightInfo::on_initialize(0);373 for (order, (index, mut s)) in queued.into_iter().enumerate() {395 for (order, (index, mut s)) in queued.into_iter().enumerate() {374 let named = if let Some(ref id) = s.maybe_id {396 let named = s.maybe_id.is_some();375 Lookup::<T>::remove(id);376 true377 } else {378 false379 };380397381 let (call, maybe_completed) = s.call.resolved::<T::PreimageProvider>();398 let (call, maybe_completed) = s.call.resolved::<T::PreimageProvider>();382 s.call = call;399 s.call = call;399 Lookup::<T>::insert(id, (until, index as u32));416 Lookup::<T>::insert(id, (until, index as u32));400 }417 }401 Agenda::<T>::append(until, Some(s));418 Agenda::<T>::append(until, Some(s));402 }419 } else if let Some(ref id) = s.maybe_id {420 Lookup::<T>::remove(id);421 }403 continue;422 continue;404 }423 }405 };424 };439 continue;458 continue;440 }459 }441460442 let sender = ensure_signed(461 let scheduled_origin =443 <<T as Config>::RuntimeOrigin as From<T::PalletsOrigin>>::from(462 <<T as Config>::RuntimeOrigin as From<T::PalletsOrigin>>::from(444 s.origin.clone(),463 s.origin.clone(),445 )464 );446 .into(),465 let ensured_origin = T::ScheduleOrigin::ensure_origin(scheduled_origin.into());447 )466448 .unwrap();449450 // // if call have id it was be reserved451 // if s.maybe_id.is_some() {452 // let _ = T::CallExecutor::pay_for_call(453 // s.maybe_id.unwrap(),454 // sender.clone(),455 // call.clone(),456 // );457 // }458459 // Execute transaction via chain default pipeline460 // That means dispatch will be processed like any user's extrinsic e.g. transaction fees will be taken461 let r = T::CallExecutor::dispatch_call(sender, call.clone());467 let r = match ensured_origin {468 Ok(ScheduledEnsureOriginSuccess::Root) => {469 Ok(call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()))470 }471 Ok(ScheduledEnsureOriginSuccess::Signed(sender)) => {472 // Execute transaction via chain default pipeline473 // That means dispatch will be processed like any user's extrinsic e.g. transaction fees will be taken474 T::CallExecutor::dispatch_call(Some(sender), call.clone())475 }476 Err(e) => Ok(Err(e.into())),477 };462478463 let mut actual_call_weight: Weight = item_weight;479 let mut actual_call_weight: Weight = item_weight;464 let result: Result<_, DispatchError> = match r {480 let result: Result<_, DispatchError> = match r {494 s.maybe_periodic = None;510 s.maybe_periodic = None;495 }511 }496 let wake = now + period;512 let wake = now + period;513 let is_canceled;514497 // If scheduled is named, place its information in `Lookup`515 // If scheduled is named, place its information in `Lookup`498 if let Some(ref id) = s.maybe_id {516 if let Some(ref id) = s.maybe_id {517 is_canceled = Lookup::<T>::get(id).is_none();499 let wake_index = Agenda::<T>::decode_len(wake).unwrap_or(0);518 let wake_index = Agenda::<T>::decode_len(wake).unwrap_or(0);519520 if !is_canceled {500 Lookup::<T>::insert(id, (wake, wake_index as u32));521 Lookup::<T>::insert(id, (wake, wake_index as u32));522 }501 }523 } else {524 is_canceled = false;525 }526527 if !is_canceled {502 Agenda::<T>::append(wake, Some(s));528 Agenda::<T>::append(wake, Some(s));529 }503 }530 } else if let Some(ref id) = s.maybe_id {531 Lookup::<T>::remove(id);532 }504 }533 }505 // Total weight should be 0, because the transaction is already paid for534 total_weight506 Weight::zero()507 }535 }508 }536 }509537516 id: ScheduledId,544 id: ScheduledId,517 when: T::BlockNumber,545 when: T::BlockNumber,518 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,546 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,519 priority: schedule::Priority,547 priority: Option<schedule::Priority>,520 call: Box<CallOrHashOf<T>>,548 call: Box<CallOrHashOf<T>>,521 ) -> DispatchResult {549 ) -> DispatchResult {522 T::ScheduleOrigin::ensure_origin(origin.clone())?;550 T::ScheduleOrigin::ensure_origin(origin.clone())?;551552 if priority.is_some() {553 T::PrioritySetOrigin::ensure_origin(origin.clone())?;554 }555523 let origin = <T as Config>::RuntimeOrigin::from(origin);556 let origin = <T as Config>::RuntimeOrigin::from(origin);524 Self::do_schedule_named(557 Self::do_schedule_named(525 id,558 id,526 DispatchTime::At(when),559 DispatchTime::At(when),527 maybe_periodic,560 maybe_periodic,528 priority,561 priority.unwrap_or(LOWEST_PRIORITY),529 origin.caller().clone(),562 origin.caller().clone(),530 *call,563 *call,531 )?;564 )?;552 id: ScheduledId,585 id: ScheduledId,553 after: T::BlockNumber,586 after: T::BlockNumber,554 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,587 maybe_periodic: Option<schedule::Period<T::BlockNumber>>,555 priority: schedule::Priority,588 priority: Option<schedule::Priority>,556 call: Box<CallOrHashOf<T>>,589 call: Box<CallOrHashOf<T>>,557 ) -> DispatchResult {590 ) -> DispatchResult {558 T::ScheduleOrigin::ensure_origin(origin.clone())?;591 T::ScheduleOrigin::ensure_origin(origin.clone())?;592593 if priority.is_some() {594 T::PrioritySetOrigin::ensure_origin(origin.clone())?;595 }596559 let origin = <T as Config>::RuntimeOrigin::from(origin);597 let origin = <T as Config>::RuntimeOrigin::from(origin);560 Self::do_schedule_named(598 Self::do_schedule_named(561 id,599 id,562 DispatchTime::After(after),600 DispatchTime::After(after),563 maybe_periodic,601 maybe_periodic,564 priority,602 priority.unwrap_or(LOWEST_PRIORITY),565 origin.caller().clone(),603 origin.caller().clone(),566 *call,604 *call,567 )?;605 )?;568 Ok(())606 Ok(())569 }607 }608609 #[pallet::weight(<T as Config>::WeightInfo::change_named_priority(T::MaxScheduledPerBlock::get()))]610 pub fn change_named_priority(611 origin: OriginFor<T>,612 id: ScheduledId,613 priority: schedule::Priority,614 ) -> DispatchResult {615 T::PrioritySetOrigin::ensure_origin(origin.clone())?;616 let origin = <T as Config>::RuntimeOrigin::from(origin);617 Self::do_change_named_priority(origin.caller().clone(), id, priority)618 }570 }619 }571}620}572621720 })769 })721 }770 }771772 fn do_change_named_priority(773 origin: T::PalletsOrigin,774 id: ScheduledId,775 priority: schedule::Priority,776 ) -> DispatchResult {777 match Lookup::<T>::get(id) {778 Some((when, index)) => {779 let i = index as usize;780 Agenda::<T>::try_mutate(when, |agenda| {781 if let Some(Some(s)) = agenda.get_mut(i) {782 if matches!(783 T::OriginPrivilegeCmp::cmp_privilege(&origin, &s.origin),784 Some(Ordering::Less) | None785 ) {786 return Err(BadOrigin.into());787 }788789 s.priority = priority;790 Self::deposit_event(Event::PriorityChanged {791 when,792 index,793 priority,794 });795 }796 Ok(())797 })798 }799 None => Err(Error::<T>::NotFound.into()),800 }801 }722}802}723803pallets/scheduler/src/weights.rsdiffbeforeafterboth3//! Autogenerated weights for pallet_unique_scheduler3//! Autogenerated weights for pallet_unique_scheduler4//!4//!5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev5//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev6//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`6//! DATE: 2022-09-14, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]`7//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 10247//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024889// Executed Command:9// Executed Command: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)]303131use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};32use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};44 fn on_initialize_resolved(s: u32, ) -> Weight;45 fn on_initialize_resolved(s: u32, ) -> Weight;45 fn schedule_named(s: u32, ) -> Weight;46 fn schedule_named(s: u32, ) -> Weight;46 fn cancel_named(s: u32, ) -> Weight;47 fn cancel_named(s: u32, ) -> Weight;48 fn change_named_priority(s: u32, ) -> Weight;47}49}485049/// Weights for pallet_unique_scheduler using the Substrate node and recommended hardware.51/// Weights for pallet_unique_scheduler using the Substrate node and recommended hardware.53 // Storage: System Account (r:1 w:1)55 // Storage: System Account (r:1 w:1)54 // Storage: System AllExtrinsicsLen (r:1 w:1)56 // Storage: System AllExtrinsicsLen (r:1 w:1)55 // Storage: System BlockWeight (r:1 w:1)57 // Storage: System BlockWeight (r:1 w:1)58 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)59 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)56 // Storage: Scheduler Lookup (r:0 w:1)60 // Storage: Scheduler Lookup (r:1 w:1)57 fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {61 fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {58 Weight::from_ref_time(26_641_000)62 Weight::from_ref_time(26_641_000)59 // Standard Error: 9_00063 // Standard Error: 9_00067 // Storage: System Account (r:1 w:1)71 // Storage: System Account (r:1 w:1)68 // Storage: System AllExtrinsicsLen (r:1 w:1)72 // Storage: System AllExtrinsicsLen (r:1 w:1)69 // Storage: System BlockWeight (r:1 w:1)73 // Storage: System BlockWeight (r:1 w:1)74 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)75 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)70 // Storage: Scheduler Lookup (r:0 w:1)76 // Storage: Scheduler Lookup (r:0 w:1)71 fn on_initialize_named_resolved(s: u32, ) -> Weight {77 fn on_initialize_named_resolved(s: u32, ) -> Weight {72 Weight::from_ref_time(23_941_000)78 Weight::from_ref_time(23_941_000)80 // Storage: System Account (r:1 w:1)86 // Storage: System Account (r:1 w:1)81 // Storage: System AllExtrinsicsLen (r:1 w:1)87 // Storage: System AllExtrinsicsLen (r:1 w:1)82 // Storage: System BlockWeight (r:1 w:1)88 // Storage: System BlockWeight (r:1 w:1)89 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)90 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)83 // Storage: Scheduler Lookup (r:0 w:1)91 // Storage: Scheduler Lookup (r:1 w:1)84 fn on_initialize_periodic(s: u32, ) -> Weight {92 fn on_initialize_periodic(s: u32, ) -> Weight {85 Weight::from_ref_time(24_858_000)93 Weight::from_ref_time(24_858_000)86 // Standard Error: 7_00094 // Standard Error: 7_00094 // Storage: System Account (r:1 w:1)102 // Storage: System Account (r:1 w:1)95 // Storage: System AllExtrinsicsLen (r:1 w:1)103 // Storage: System AllExtrinsicsLen (r:1 w:1)96 // Storage: System BlockWeight (r:1 w:1)104 // Storage: System BlockWeight (r:1 w:1)105 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)106 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)97 // Storage: Scheduler Lookup (r:0 w:1)107 // Storage: Scheduler Lookup (r:1 w:1)98 fn on_initialize_periodic_resolved(s: u32, ) -> Weight {108 fn on_initialize_periodic_resolved(s: u32, ) -> Weight {99 Weight::from_ref_time(25_515_000)109 Weight::from_ref_time(25_515_000)100 // Standard Error: 14_000110 // Standard Error: 14_000118 // Storage: System Account (r:1 w:1)128 // Storage: System Account (r:1 w:1)119 // Storage: System AllExtrinsicsLen (r:1 w:1)129 // Storage: System AllExtrinsicsLen (r:1 w:1)120 // Storage: System BlockWeight (r:1 w:1)130 // Storage: System BlockWeight (r:1 w:1)131 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)132 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)121 // Storage: Scheduler Lookup (r:0 w:1)133 // Storage: Scheduler Lookup (r:0 w:1)122 fn on_initialize_named_aborted(s: u32, ) -> Weight {134 fn on_initialize_named_aborted(s: u32, ) -> Weight {123 Weight::from_ref_time(25_552_000)135 Weight::from_ref_time(25_552_000)141 // Storage: System Account (r:1 w:1)153 // Storage: System Account (r:1 w:1)142 // Storage: System AllExtrinsicsLen (r:1 w:1)154 // Storage: System AllExtrinsicsLen (r:1 w:1)143 // Storage: System BlockWeight (r:1 w:1)155 // Storage: System BlockWeight (r:1 w:1)156 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)157 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)144 // Storage: Scheduler Lookup (r:0 w:1)158 // Storage: Scheduler Lookup (r:0 w:1)145 fn on_initialize(s: u32, ) -> Weight {159 fn on_initialize(s: u32, ) -> Weight {146 Weight::from_ref_time(24_482_000)160 Weight::from_ref_time(24_482_000)154 // Storage: System Account (r:1 w:1)168 // Storage: System Account (r:1 w:1)155 // Storage: System AllExtrinsicsLen (r:1 w:1)169 // Storage: System AllExtrinsicsLen (r:1 w:1)156 // Storage: System BlockWeight (r:1 w:1)170 // Storage: System BlockWeight (r:1 w:1)171 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)172 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)157 // Storage: Scheduler Lookup (r:0 w:1)173 // Storage: Scheduler Lookup (r:0 w:1)158 fn on_initialize_resolved(s: u32, ) -> Weight {174 fn on_initialize_resolved(s: u32, ) -> Weight {159 Weight::from_ref_time(25_187_000)175 Weight::from_ref_time(25_187_000)181 .saturating_add(T::DbWeight::get().reads(2 as u64))197 .saturating_add(T::DbWeight::get().reads(2 as u64))182 .saturating_add(T::DbWeight::get().writes(2 as u64))198 .saturating_add(T::DbWeight::get().writes(2 as u64))183 }199 }200 // Storage: Scheduler Lookup (r:1 w:1)201 // Storage: Scheduler Agenda (r:1 w:1)202 fn change_named_priority(s: u32, ) -> Weight {203 Weight::from_ref_time(8_642_000)204 // Standard Error: 0205 .saturating_add(Weight::from_ref_time(431_000).saturating_mul(s as u64))206 .saturating_add(T::DbWeight::get().reads(2 as u64))207 .saturating_add(T::DbWeight::get().writes(2 as u64))208 }184}209}185210186// For backwards compatibility and tests211// For backwards compatibility and tests189 // Storage: System Account (r:1 w:1)214 // Storage: System Account (r:1 w:1)190 // Storage: System AllExtrinsicsLen (r:1 w:1)215 // Storage: System AllExtrinsicsLen (r:1 w:1)191 // Storage: System BlockWeight (r:1 w:1)216 // Storage: System BlockWeight (r:1 w:1)217 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)218 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)192 // Storage: Scheduler Lookup (r:0 w:1)219 // Storage: Scheduler Lookup (r:1 w:1)193 fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {220 fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight {194 Weight::from_ref_time(26_641_000)221 Weight::from_ref_time(26_641_000)195 // Standard Error: 9_000222 // Standard Error: 9_000203 // Storage: System Account (r:1 w:1)230 // Storage: System Account (r:1 w:1)204 // Storage: System AllExtrinsicsLen (r:1 w:1)231 // Storage: System AllExtrinsicsLen (r:1 w:1)205 // Storage: System BlockWeight (r:1 w:1)232 // Storage: System BlockWeight (r:1 w:1)233 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)234 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)206 // Storage: Scheduler Lookup (r:0 w:1)235 // Storage: Scheduler Lookup (r:0 w:1)207 fn on_initialize_named_resolved(s: u32, ) -> Weight {236 fn on_initialize_named_resolved(s: u32, ) -> Weight {208 Weight::from_ref_time(23_941_000)237 Weight::from_ref_time(23_941_000)216 // Storage: System Account (r:1 w:1)245 // Storage: System Account (r:1 w:1)217 // Storage: System AllExtrinsicsLen (r:1 w:1)246 // Storage: System AllExtrinsicsLen (r:1 w:1)218 // Storage: System BlockWeight (r:1 w:1)247 // Storage: System BlockWeight (r:1 w:1)248 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)249 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)219 // Storage: Scheduler Lookup (r:0 w:1)250 // Storage: Scheduler Lookup (r:1 w:1)220 fn on_initialize_periodic(s: u32, ) -> Weight {251 fn on_initialize_periodic(s: u32, ) -> Weight {221 Weight::from_ref_time(24_858_000)252 Weight::from_ref_time(24_858_000)222 // Standard Error: 7_000253 // Standard Error: 7_000230 // Storage: System Account (r:1 w:1)261 // Storage: System Account (r:1 w:1)231 // Storage: System AllExtrinsicsLen (r:1 w:1)262 // Storage: System AllExtrinsicsLen (r:1 w:1)232 // Storage: System BlockWeight (r:1 w:1)263 // Storage: System BlockWeight (r:1 w:1)264 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)265 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)233 // Storage: Scheduler Lookup (r:0 w:1)266 // Storage: Scheduler Lookup (r:1 w:1)234 fn on_initialize_periodic_resolved(s: u32, ) -> Weight {267 fn on_initialize_periodic_resolved(s: u32, ) -> Weight {235 Weight::from_ref_time(25_515_000)268 Weight::from_ref_time(25_515_000)236 // Standard Error: 14_000269 // Standard Error: 14_000254 // Storage: System Account (r:1 w:1)287 // Storage: System Account (r:1 w:1)255 // Storage: System AllExtrinsicsLen (r:1 w:1)288 // Storage: System AllExtrinsicsLen (r:1 w:1)256 // Storage: System BlockWeight (r:1 w:1)289 // Storage: System BlockWeight (r:1 w:1)290 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)291 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)257 // Storage: Scheduler Lookup (r:0 w:1)292 // Storage: Scheduler Lookup (r:0 w:1)258 fn on_initialize_named_aborted(s: u32, ) -> Weight {293 fn on_initialize_named_aborted(s: u32, ) -> Weight {259 Weight::from_ref_time(25_552_000)294 Weight::from_ref_time(25_552_000)277 // Storage: System Account (r:1 w:1)312 // Storage: System Account (r:1 w:1)278 // Storage: System AllExtrinsicsLen (r:1 w:1)313 // Storage: System AllExtrinsicsLen (r:1 w:1)279 // Storage: System BlockWeight (r:1 w:1)314 // Storage: System BlockWeight (r:1 w:1)315 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)316 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)280 // Storage: Scheduler Lookup (r:0 w:1)317 // Storage: Scheduler Lookup (r:0 w:1)281 fn on_initialize(s: u32, ) -> Weight {318 fn on_initialize(s: u32, ) -> Weight {282 Weight::from_ref_time(24_482_000)319 Weight::from_ref_time(24_482_000)290 // Storage: System Account (r:1 w:1)327 // Storage: System Account (r:1 w:1)291 // Storage: System AllExtrinsicsLen (r:1 w:1)328 // Storage: System AllExtrinsicsLen (r:1 w:1)292 // Storage: System BlockWeight (r:1 w:1)329 // Storage: System BlockWeight (r:1 w:1)330 // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0)331 // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)293 // Storage: Scheduler Lookup (r:0 w:1)332 // Storage: Scheduler Lookup (r:0 w:1)294 fn on_initialize_resolved(s: u32, ) -> Weight {333 fn on_initialize_resolved(s: u32, ) -> Weight {295 Weight::from_ref_time(25_187_000)334 Weight::from_ref_time(25_187_000)318 .saturating_add(RocksDbWeight::get().writes(2 as u64))357 .saturating_add(RocksDbWeight::get().writes(2 as u64))319 }358 }359360 // Storage: Scheduler Lookup (r:1 w:1)361 // Storage: Scheduler Agenda (r:1 w:1)362 fn change_named_priority(s: u32, ) -> Weight {363 Weight::from_ref_time(8_642_000)364 // Standard Error: 0365 .saturating_add(Weight::from_ref_time(431_000).saturating_mul(s as u64))366 .saturating_add(RocksDbWeight::get().reads(2 as u64))367 .saturating_add(RocksDbWeight::get().writes(2 as u64))368 }320}369}321370pallets/unique/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [v0.2.1] 2022-10-1089### Changes1011- Added `destroyCollection` and `createFTCollection` methods to **CollectionHelpers**.127## [v0.2.0] 2022-09-1313## [v0.2.0] 2022-09-138149### Changes15### Changes1610- Change **collectionHelper** method `createRefungibleCollection` to `createRFTCollection`,17- Change **collectionHelper** method `createRefungibleCollection` to `createRFTCollection`,111812## [v0.1.4] 2022-09-0519## [v0.1.4] 2022-09-05132014### Added21### Added152216- Methods `force_set_sponsor` , `force_remove_collection_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic.23- Methods `force_set_sponsor` , `force_remove_collection_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic.172418## [v0.1.3] 2022-08-1625## [v0.1.3] 2022-08-16192620### Other changes27### Other changes212822- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a29- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a233024- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf831- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8253226- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd3133- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31273428Every extrinsic now runs in transaction implicitly, and35Every extrinsic now runs in transaction implicitly, and29`#[transactional]` on pallet dispatchable is now meaningless36`#[transactional]` on pallet dispatchable is now meaningless303731Upstream-Change: https://github.com/paritytech/substrate/issues/1080638Upstream-Change: https://github.com/paritytech/substrate/issues/10806323933- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d97540- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975344135New methods allows to call `remove_prefix` with limit multiple times42New methods allows to call `remove_prefix` with limit multiple times36in the same block43in the same block394640Upstream-Change: https://github.com/paritytech/substrate/pull/1149047Upstream-Change: https://github.com/paritytech/substrate/pull/11490414842- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b49- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b435044## [v0.1.1] - 2022-07-2551## [v0.1.1] - 2022-07-25455246### Added53### Added475448- Method for creating `ERC721Metadata` compatible NFT collection.55- Method for creating `ERC721Metadata` compatible NFT collection.49- Method for creating `ERC721Metadata` compatible ReFungible collection.56- Method for creating `ERC721Metadata` compatible ReFungible collection.50- Method for creating ReFungible collection.57- Method for creating ReFungible collection.5158pallets/unique/Cargo.tomldiffbeforeafterboth9license = 'GPLv3'9license = 'GPLv3'10name = 'pallet-unique'10name = 'pallet-unique'11repository = 'https://github.com/UniqueNetwork/unique-chain'11repository = 'https://github.com/UniqueNetwork/unique-chain'12version = "0.2.0"12version = "0.2.1"131314[package.metadata.docs.rs]14[package.metadata.docs.rs]15targets = ['x86_64-unknown-linux-gnu']15targets = ['x86_64-unknown-linux-gnu']pallets/unique/src/eth/mod.rsdiffbeforeafterboth181819use core::marker::PhantomData;19use core::marker::PhantomData;20use ethereum as _;20use ethereum as _;21use evm_coder::{execution::*, generate_stubgen, solidity_interface, solidity, weight, types::*};21use evm_coder::{execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};22use frame_support::traits::Get;22use frame_support::traits::Get;2324use crate::Pallet;2523use pallet_common::{26use pallet_common::{24 CollectionById,27 CollectionById,25 dispatch::CollectionDispatch,28 dispatch::CollectionDispatch,26 erc::{29 erc::{static_property::key, CollectionHelpersEvents},27 CollectionHelpersEvents,28 static_property::{key},29 },30 Pallet as PalletCommon,30 Pallet as PalletCommon,31};31};32use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};32use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};33use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};33use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};34use sp_std::vec;34use sp_std::vec;35use up_data_structs::{35use up_data_structs::{36 CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,36 CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix,37 CollectionMode, PropertyValue, CollectionFlags,37 CreateCollectionData,38};38};393940use crate::{Config, SelfWeightOf, weights::WeightInfo};40use crate::{weights::WeightInfo, Config, SelfWeightOf};414142use alloc::format;42use sp_std::vec::Vec;43use sp_std::vec::Vec;43use alloc::format;444445/// See [`CollectionHelpersCall`]45/// See [`CollectionHelpersCall`]46pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);46pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);84 Ok((caller, name, description, token_prefix))84 Ok((caller, name, description, token_prefix))85}85}868687#[inline(always)]87fn create_refungible_collection_internal<88fn create_collection_internal<T: Config>(88 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,89>(90 caller: caller,89 caller: caller,91 value: value,90 value: value,92 name: string,91 name: string,92 collection_mode: CollectionMode,93 description: string,93 description: string,94 token_prefix: string,94 token_prefix: string,95) -> Result<address> {95) -> Result<address> {96 let (caller, name, description, token_prefix) =96 let (caller, name, description, token_prefix) =97 convert_data::<T>(caller, name, description, token_prefix)?;97 convert_data::<T>(caller, name, description, token_prefix)?;98 let data = CreateCollectionData {98 let data = CreateCollectionData {99 name,99 name,100 mode: CollectionMode::ReFungible,100 mode: collection_mode,101 description,101 description,102 token_prefix,102 token_prefix,103 ..Default::default()103 ..Default::default()193 description: string,193 description: string,194 token_prefix: string,194 token_prefix: string,195 ) -> Result<address> {195 ) -> Result<address> {196 self.create_nft_collection(caller, value, name, description, token_prefix)196 create_collection_internal::<T>(197 caller,198 value,199 name,200 CollectionMode::NFT,201 description,202 token_prefix,203 )197 }204 }198205206 description: string,213 description: string,207 token_prefix: string,214 token_prefix: string,208 ) -> Result<address> {215 ) -> Result<address> {209 create_refungible_collection_internal::<T>(caller, value, name, description, token_prefix)216 create_collection_internal::<T>(217 caller,218 value,219 name,220 CollectionMode::ReFungible,221 description,222 token_prefix,223 )210 }224 }225226 #[weight(<SelfWeightOf<T>>::create_collection())]227 #[solidity(rename_selector = "createFTCollection")]228 fn create_fungible_collection(229 &mut self,230 caller: caller,231 value: value,232 name: string,233 decimals: uint8,234 description: string,235 token_prefix: string,236 ) -> Result<address> {237 create_collection_internal::<T>(238 caller,239 value,240 name,241 CollectionMode::Fungible(decimals),242 description,243 token_prefix,244 )245 }211246212 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]247 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]213 fn make_collection_metadata_compatible(248 fn make_collection_metadata_compatible(296 Ok(())331 Ok(())297 }332 }333334 #[weight(<SelfWeightOf<T>>::destroy_collection())]335 fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result<void> {336 let caller = T::CrossAccountId::from_eth(caller);337338 let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)339 .ok_or("Invalid collection address format")?;340 <Pallet<T>>::destroy_collection_internal(caller, collection_id)341 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)342 }298343299 /// Check if a collection exists344 /// Check if a collection exists300 /// @param collectionAddress Address of the collection in question345 /// @param collectionAddress Address of the collection in questionpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth20/// @dev inlined interface20/// @dev inlined interface21contract CollectionHelpersEvents {21contract CollectionHelpersEvents {22 event CollectionCreated(address indexed owner, address indexed collectionId);22 event CollectionCreated(address indexed owner, address indexed collectionId);23 event CollectionDestroyed(address indexed collectionId);23}24}242525/// @title Contract, which allows users to operate with collections26/// @title Contract, which allows users to operate with collections26/// @dev the ERC-165 identifier for this interface is 0x5891863127/// @dev the ERC-165 identifier for this interface is 0x7dea03b127contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {28contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {28 /// Create an NFT collection29 /// Create an NFT collection29 /// @param name Name of the collection30 /// @param name Name of the collection76 return 0x0000000000000000000000000000000000000000;77 return 0x0000000000000000000000000000000000000000;77 }78 }7980 /// @dev EVM selector for this function is: 0x7335b79f,81 /// or in textual repr: createFTCollection(string,uint8,string,string)82 function createFTCollection(83 string memory name,84 uint8 decimals,85 string memory description,86 string memory tokenPrefix87 ) public payable returns (address) {88 require(false, stub_error);89 name;90 decimals;91 description;92 tokenPrefix;93 dummy = 0;94 return 0x0000000000000000000000000000000000000000;95 }789679 /// @dev EVM selector for this function is: 0x85624258,97 /// @dev EVM selector for this function is: 0x85624258,80 /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string)98 /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string)85 dummy = 0;103 dummy = 0;86 }104 }105106 /// @dev EVM selector for this function is: 0x564e321f,107 /// or in textual repr: destroyCollection(address)108 function destroyCollection(address collectionAddress) public {109 require(false, stub_error);110 collectionAddress;111 dummy = 0;112 }8711388 /// Check if a collection exists114 /// Check if a collection exists89 /// @param collectionAddress Address of the collection in question115 /// @param collectionAddress Address of the collection in questionpallets/unique/src/lib.rsdiffbeforeafterboth363 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {363 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {364 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);364 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);365365 let collection = <CollectionHandle<T>>::try_get(collection_id)?;366 Self::destroy_collection_internal(sender, collection_id)366 collection.check_is_internal()?;367368 // =========369370 T::CollectionDispatch::destroy(sender, collection)?;371372 // TODO: basket cleanup should be moved elsewhere373 // Maybe runtime dispatch.rs should perform it?374375 let _ = <NftTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);376 let _ = <FungibleTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);377 let _ = <ReFungibleTransferBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);378379 let _ = <NftApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);380 let _ = <FungibleApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);381 let _ = <RefungibleApproveBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);382383 Ok(())384 }367 }385368386 /// Add an address to allow list.369 /// Add an address to allow list.1152 target_collection.save()1135 target_collection.save()1153 }1136 }11371138 #[inline(always)]1139 pub(crate) fn destroy_collection_internal(1140 sender: T::CrossAccountId,1141 collection_id: CollectionId,1142 ) -> DispatchResult {1143 let collection = <CollectionHandle<T>>::try_get(collection_id)?;1144 collection.check_is_internal()?;11451146 T::CollectionDispatch::destroy(sender, collection)?;11471148 // TODO: basket cleanup should be moved elsewhere1149 // Maybe runtime dispatch.rs should perform it?11501151 let _ = <NftTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1152 let _ = <FungibleTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1153 let _ = <ReFungibleTransferBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);11541155 let _ = <NftApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1156 let _ = <FungibleApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1157 let _ = <RefungibleApproveBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);11581159 Ok(())1160 }1154}1161}11551162primitives/data-structs/src/lib.rsdiffbeforeafterboth447}447}448448449/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).449/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).450#[struct_versioning::versioned(version = 2, upper)]450#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]451#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]451#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]452#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]452pub struct RpcCollection<AccountId> {453pub struct RpcCollection<AccountId> {484 pub read_only: bool,485 pub read_only: bool,485486486 /// Extra collection flags487 /// Extra collection flags488 #[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))]487 pub flags: RpcCollectionFlags,489 pub flags: RpcCollectionFlags,488}490}489491primitives/rpc/src/lib.rsdiffbeforeafterboth161617#![cfg_attr(not(feature = "std"), no_std)]17#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;182019use up_data_structs::{21use up_data_structs::{20 CollectionId, TokenId, RpcCollection, CollectionStats, CollectionLimits, Property,22 CollectionId, TokenId, RpcCollection, CollectionStats, CollectionLimits, Property,21 PropertyKeyPermission, TokenData, TokenChild,23 PropertyKeyPermission, TokenData, TokenChild, RpcCollectionVersion1,22};24};232524use sp_std::vec::Vec;26use sp_std::vec::Vec;28type Result<T> = core::result::Result<T, DispatchError>;30type Result<T> = core::result::Result<T, DispatchError>;293130sp_api::decl_runtime_apis! {32sp_api::decl_runtime_apis! {31 #[api_version(2)]33 #[api_version(3)]32 /// Trait for generate rpc.34 /// Trait for generate rpc.33 pub trait UniqueApi<CrossAccountId, AccountId> where35 pub trait UniqueApi<CrossAccountId, AccountId> where34 AccountId: Decode,36 AccountId: Decode,35 CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,37 CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,36 {38 {37 #[changed_in(2)]38 fn token_owner(collection: CollectionId, token: TokenId) -> Result<CrossAccountId>;3940 /// Get number of tokens in collection owned by account.39 /// Get number of tokens in collection owned by account.41 fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>>;40 fn account_tokens(collection: CollectionId, account: CrossAccountId) -> Result<Vec<TokenId>>;110 /// Get collection by id.109 /// Get collection by id.111 fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>>;110 fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>>;111112 #[changed_in(3)]113 fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollectionVersion1<AccountId>>>;112114113 /// Get collection stats.115 /// Get collection stats.114 fn collection_stats() -> Result<CollectionStats>;116 fn collection_stats() -> Result<CollectionStats>;runtime/common/config/mod.rsdiffbeforeafterboth22pub mod substrate;22pub mod substrate;23pub mod xcm;23pub mod xcm;2425#[cfg(feature = "pallet-test-utils")]26pub mod test_pallets;2427runtime/common/config/pallets/scheduler.rsdiffbeforeafterboth15// 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/>.161617use frame_support::{traits::PrivilegeCmp, weights::Weight, parameter_types};17use frame_support::{18 traits::{PrivilegeCmp, EnsureOrigin},19 weights::Weight,20 parameter_types,21};18use frame_system::EnsureSigned;22use frame_system::{EnsureRoot, RawOrigin};19use sp_runtime::Perbill;23use sp_runtime::Perbill;20use sp_std::cmp::Ordering;24use core::cmp::Ordering;25use codec::Decode;21use crate::{26use crate::{22 runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights},27 runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights},23 Runtime, Call, Event, Origin, OriginCaller, Balances,28 Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, OriginCaller, Balances,24};29};30use pallet_unique_scheduler_v2::ScheduledEnsureOriginSuccess;25use up_common::types::AccountId;31use up_common::types::AccountId;263227parameter_types! {33parameter_types! {33 pub const Preimage: Option<u32> = Some(10);39 pub const Preimage: Option<u32> = Some(10);34}40}354136/// Used the compare the privilege of an origin inside the scheduler.37pub struct OriginPrivilegeCmp;42pub struct EnsureSignedOrRoot<AccountId>(sp_std::marker::PhantomData<AccountId>);3843impl<O: Into<Result<RawOrigin<AccountId>, O>> + From<RawOrigin<AccountId>>, AccountId: Decode>44 EnsureOrigin<O> for EnsureSignedOrRoot<AccountId>45{46 type Success = ScheduledEnsureOriginSuccess<AccountId>;47 fn try_origin(o: O) -> Result<Self::Success, O> {48 o.into().and_then(|o| match o {49 RawOrigin::Root => Ok(ScheduledEnsureOriginSuccess::Root),50 RawOrigin::Signed(who) => Ok(ScheduledEnsureOriginSuccess::Signed(who)),51 r => Err(O::from(r)),52 })53 }54}5556pub struct EqualOrRootOnly;39impl PrivilegeCmp<OriginCaller> for OriginPrivilegeCmp {57impl PrivilegeCmp<OriginCaller> for EqualOrRootOnly {40 fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option<Ordering> {58 fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option<Ordering> {59 use RawOrigin::*;6061 let left = left.clone().try_into().ok()?;62 let right = right.clone().try_into().ok()?;6364 match (left, right) {41 Some(Ordering::Equal)65 (Root, Root) => Some(Ordering::Equal),66 (Root, _) => Some(Ordering::Greater),67 (_, Root) => Some(Ordering::Less),68 lr @ _ => (lr.0 == lr.1).then(|| Ordering::Equal),69 }42 }70 }43}71}7273// impl pallet_unique_scheduler::Config for Runtime {74// type RuntimeEvent = RuntimeEvent;75// type RuntimeOrigin = RuntimeOrigin;76// type Currency = Balances;77// type PalletsOrigin = OriginCaller;78// type RuntimeCall = RuntimeCall;79// type MaximumWeight = MaximumSchedulerWeight;80// type ScheduleOrigin = EnsureSignedOrRoot<AccountId>;81// type PrioritySetOrigin = EnsureRoot<AccountId>;82// type MaxScheduledPerBlock = MaxScheduledPerBlock;83// type WeightInfo = ();84// type CallExecutor = SchedulerPaymentExecutor;85// type OriginPrivilegeCmp = EqualOrRootOnly;86// type PreimageProvider = ();87// type NoPreimagePostponement = NoPreimagePostponement;88// }448945impl pallet_unique_scheduler::Config for Runtime {90impl pallet_unique_scheduler_v2::Config for Runtime {46 type RuntimeEvent = RuntimeEvent;91 type RuntimeEvent = RuntimeEvent;47 type RuntimeOrigin = RuntimeOrigin;92 type RuntimeOrigin = RuntimeOrigin;48 type Currency = Balances;49 type PalletsOrigin = OriginCaller;93 type PalletsOrigin = OriginCaller;50 type RuntimeCall = RuntimeCall;94 type RuntimeCall = RuntimeCall;51 type MaximumWeight = MaximumSchedulerWeight;95 type MaximumWeight = MaximumSchedulerWeight;52 type ScheduleOrigin = EnsureSigned<AccountId>;96 type ScheduleOrigin = EnsureSignedOrRoot<AccountId>;97 type OriginPrivilegeCmp = EqualOrRootOnly;53 type MaxScheduledPerBlock = MaxScheduledPerBlock;98 type MaxScheduledPerBlock = MaxScheduledPerBlock;54 type WeightInfo = ();99 type WeightInfo = ();55 type CallExecutor = SchedulerPaymentExecutor;100 type Preimages = ();56 type OriginPrivilegeCmp = OriginPrivilegeCmp;101 type CallExecutor = SchedulerPaymentExecutor;57 type PreimageProvider = ();102 type PrioritySetOrigin = EnsureRoot<AccountId>;58 type NoPreimagePostponement = NoPreimagePostponement;59}103}60104runtime/common/config/test_pallets.rsdiffbeforeafterbothno changes
runtime/common/construct_runtime/mod.rsdiffbeforeafterboth94 EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,94 EvmTransactionPayment: pallet_evm_transaction_payment::{Pallet} = 152,95 EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,95 EvmMigration: pallet_evm_migration::{Pallet, Call, Storage} = 153,9697 #[runtimes(opal)]98 Scheduler: pallet_unique_scheduler_v2::{Pallet, Call, Storage, Event<T>} = 154,99100 #[runtimes(opal)]101 TestUtils: pallet_test_utils = 255,96 }102 }97 }103 }98 }104 }runtime/common/scheduler.rsdiffbeforeafterboth161617use frame_support::{17use frame_support::{18 traits::NamedReservableCurrency,18 traits::NamedReservableCurrency,19 weights::{GetDispatchInfo, PostDispatchInfo, DispatchInfo},19 dispatch::{GetDispatchInfo, PostDispatchInfo, DispatchInfo},20};20};21use sp_runtime::{21use sp_runtime::{22 traits::{Dispatchable, Applyable, Member},22 traits::{Dispatchable, Applyable, Member},23 generic::Era,23 generic::Era,24 transaction_validity::TransactionValidityError,24 transaction_validity::TransactionValidityError,25 DispatchErrorWithPostInfo, DispatchError,25 DispatchErrorWithPostInfo, DispatchError,26};26};27use codec::Encode;27use crate::{Runtime, Call, Origin, Balances, ChargeTransactionPayment};28use crate::{Runtime, RuntimeCall, RuntimeOrigin, Balances};28use up_common::types::{AccountId, Balance};29use up_common::types::{AccountId, Balance};29use fp_self_contained::SelfContainedCall;30use fp_self_contained::SelfContainedCall;30use pallet_unique_scheduler::DispatchCall;31use pallet_unique_scheduler_v2::DispatchCall;32use pallet_transaction_payment::ChargeTransactionPayment;3334// type SponsorshipChargeTransactionPayment =35// pallet_charge_transaction::ChargeTransactionPayment<Runtime>;313632/// The SignedExtension to the basic transaction logic.37/// The SignedExtension to the basic transaction logic.33pub type SignedExtraScheduler = (38pub type SignedExtraScheduler = (36 frame_system::CheckEra<Runtime>,41 frame_system::CheckEra<Runtime>,37 frame_system::CheckNonce<Runtime>,42 frame_system::CheckNonce<Runtime>,38 frame_system::CheckWeight<Runtime>,43 frame_system::CheckWeight<Runtime>,44 ChargeTransactionPayment<Runtime>,39);45);404641fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {47fn get_signed_extras(from: <Runtime as frame_system::Config>::AccountId) -> SignedExtraScheduler {47 from,53 from,48 )),54 )),49 frame_system::CheckWeight::<Runtime>::new(),55 frame_system::CheckWeight::<Runtime>::new(),50 // sponsoring transaction logic56 ChargeTransactionPayment::<Runtime>::from(0),51 // pallet_charge_transaction::ChargeTransactionPayment::<Runtime>::new(0),52 )57 )53}58}545955pub struct SchedulerPaymentExecutor;60pub struct SchedulerPaymentExecutor;566157impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>62impl<T: frame_system::Config + pallet_unique_scheduler_v2::Config, SelfContainedSignedInfo>58 DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor63 DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor59where64where60 <T as frame_system::Config>::Call: Member65 <T as frame_system::Config>::RuntimeCall: Member61 + Dispatchable<Origin = Origin, Info = DispatchInfo>66 + Dispatchable<RuntimeOrigin = RuntimeOrigin, Info = DispatchInfo>62 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>67 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>63 + GetDispatchInfo68 + GetDispatchInfo64 + From<frame_system::Call<Runtime>>,69 + From<frame_system::Call<Runtime>>,65 SelfContainedSignedInfo: Send + Sync + 'static,70 SelfContainedSignedInfo: Send + Sync + 'static,66 Call: From<<T as frame_system::Config>::Call>71 RuntimeCall: From<<T as frame_system::Config>::RuntimeCall>67 + From<<T as pallet_unique_scheduler::Config>::Call>72 + From<<T as pallet_unique_scheduler_v2::Config>::RuntimeCall>68 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,73 + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,69 sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,74 sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,70{75{71 fn dispatch_call(76 fn dispatch_call(72 signer: <T as frame_system::Config>::AccountId,77 signer: Option<<T as frame_system::Config>::AccountId>,73 call: <T as pallet_unique_scheduler::Config>::Call,78 call: <T as pallet_unique_scheduler_v2::Config>::RuntimeCall,74 ) -> Result<79 ) -> Result<75 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,80 Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,76 TransactionValidityError,81 TransactionValidityError,77 > {82 > {78 let dispatch_info = call.get_dispatch_info();83 let dispatch_info = call.get_dispatch_info();84 let len = call.encoded_size();8579 let extrinsic = fp_self_contained::CheckedExtrinsic::<86 let signed = match signer {80 AccountId,81 Call,82 SignedExtraScheduler,83 SelfContainedSignedInfo,84 > {85 signed: fp_self_contained::CheckedSignature::<87 Some(signer) => fp_self_contained::CheckedSignature::Signed(86 AccountId,87 SignedExtraScheduler,88 SelfContainedSignedInfo,89 >::Signed(signer.clone().into(), get_signed_extras(signer.into())),88 signer.clone().into(),90 function: call.into(),89 get_signed_extras(signer.into()),90 ),91 None => fp_self_contained::CheckedSignature::Unsigned,91 };92 };9394 let extrinsic = fp_self_contained::CheckedExtrinsic::<95 AccountId,96 RuntimeCall,97 SignedExtraScheduler,98 SelfContainedSignedInfo,99 > {100 signed,101 function: call.into(),102 };9210393 extrinsic.apply::<Runtime>(&dispatch_info, 0)104 extrinsic.apply::<Runtime>(&dispatch_info, len)94 }105 }9596 fn reserve_balance(97 id: [u8; 16],98 sponsor: <T as frame_system::Config>::AccountId,99 call: <T as pallet_unique_scheduler::Config>::Call,100 count: u32,101 ) -> Result<(), DispatchError> {102 let dispatch_info = call.get_dispatch_info();103 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)104 .saturating_mul(count.into());105106 <Balances as NamedReservableCurrency<AccountId>>::reserve_named(107 &id,108 &(sponsor.into()),109 weight,110 )111 }112113 fn pay_for_call(114 id: [u8; 16],115 sponsor: <T as frame_system::Config>::AccountId,116 call: <T as pallet_unique_scheduler::Config>::Call,117 ) -> Result<u128, DispatchError> {118 let dispatch_info = call.get_dispatch_info();119 let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);120 Ok(121 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(122 &id,123 &(sponsor.into()),124 weight,125 ),126 )127 }128129 fn cancel_reserve(130 id: [u8; 16],131 sponsor: <T as frame_system::Config>::AccountId,132 ) -> Result<u128, DispatchError> {133 Ok(134 <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(135 &id,136 &(sponsor.into()),137 u128::MAX,138 ),139 )140 }141}106}107108// impl<T: frame_system::Config + pallet_unique_scheduler::Config, SelfContainedSignedInfo>109// DispatchCall<T, SelfContainedSignedInfo> for SchedulerPaymentExecutor110// where111// <T as frame_system::Config>::Call: Member112// + Dispatchable<Origin = Origin, Info = DispatchInfo>113// + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>114// + GetDispatchInfo115// + From<frame_system::Call<Runtime>>,116// SelfContainedSignedInfo: Send + Sync + 'static,117// Call: From<<T as frame_system::Config>::Call>118// + From<<T as pallet_unique_scheduler::Config>::Call>119// + SelfContainedCall<SignedInfo = SelfContainedSignedInfo>,120// sp_runtime::AccountId32: From<<T as frame_system::Config>::AccountId>,121// {122// fn dispatch_call(123// signer: Option<<T as frame_system::Config>::AccountId>,124// call: <T as pallet_unique_scheduler::Config>::Call,125// ) -> Result<126// Result<PostDispatchInfo, DispatchErrorWithPostInfo<PostDispatchInfo>>,127// TransactionValidityError,128// > {129// let dispatch_info = call.get_dispatch_info();130// let len = call.encoded_size();131132// let signed = match signer {133// Some(signer) => fp_self_contained::CheckedSignature::Signed(134// signer.clone().into(),135// get_signed_extras(signer.into()),136// ),137// None => fp_self_contained::CheckedSignature::Unsigned,138// };139140// let extrinsic = fp_self_contained::CheckedExtrinsic::<141// AccountId,142// Call,143// SignedExtraScheduler,144// SelfContainedSignedInfo,145// > {146// signed,147// function: call.into(),148// };149150// extrinsic.apply::<Runtime>(&dispatch_info, len)151// }152153// fn reserve_balance(154// id: [u8; 16],155// sponsor: <T as frame_system::Config>::AccountId,156// call: <T as pallet_unique_scheduler::Config>::Call,157// count: u32,158// ) -> Result<(), DispatchError> {159// let dispatch_info = call.get_dispatch_info();160// let weight: Balance =161// SponsorshipChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0)162// .saturating_mul(count.into());163164// <Balances as NamedReservableCurrency<AccountId>>::reserve_named(165// &id,166// &(sponsor.into()),167// weight,168// )169// }170171// fn pay_for_call(172// id: [u8; 16],173// sponsor: <T as frame_system::Config>::AccountId,174// call: <T as pallet_unique_scheduler::Config>::Call,175// ) -> Result<u128, DispatchError> {176// let dispatch_info = call.get_dispatch_info();177// let weight: Balance =178// SponsorshipChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0);179// Ok(180// <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(181// &id,182// &(sponsor.into()),183// weight,184// ),185// )186// }187188// fn cancel_reserve(189// id: [u8; 16],190// sponsor: <T as frame_system::Config>::AccountId,191// ) -> Result<u128, DispatchError> {192// Ok(193// <Balances as NamedReservableCurrency<AccountId>>::unreserve_named(194// &id,195// &(sponsor.into()),196// u128::MAX,197// ),198// )199// }200// }142201runtime/opal/Cargo.tomldiffbeforeafterboth42 'pallet-inflation/runtime-benchmarks',42 'pallet-inflation/runtime-benchmarks',43 'pallet-app-promotion/runtime-benchmarks',43 'pallet-app-promotion/runtime-benchmarks',44 'pallet-unique-scheduler/runtime-benchmarks',44 'pallet-unique-scheduler/runtime-benchmarks',45 'pallet-unique-scheduler-v2/runtime-benchmarks',45 'pallet-xcm/runtime-benchmarks',46 'pallet-xcm/runtime-benchmarks',46 'sp-runtime/runtime-benchmarks',47 'sp-runtime/runtime-benchmarks',47 'xcm-builder/runtime-benchmarks',48 'xcm-builder/runtime-benchmarks',140 'pallet-proxy-rmrk-equip/std',141 'pallet-proxy-rmrk-equip/std',141 'pallet-unique/std',142 'pallet-unique/std',142 'pallet-unique-scheduler/std',143 'pallet-unique-scheduler/std',144 'pallet-unique-scheduler-v2/std',143 'pallet-charge-transaction/std',145 'pallet-charge-transaction/std',144 'up-data-structs/std',146 'up-data-structs/std',145 'sp-api/std',147 'sp-api/std',168 "orml-traits/std",170 "orml-traits/std",169 "pallet-foreign-assets/std",171 "pallet-foreign-assets/std",172173 'pallet-test-utils?/std',170]174]171limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']175limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']172opal-runtime = ['refungible', 'rmrk', 'app-promotion', 'foreign-assets']176opal-runtime = ['refungible', 'scheduler', 'rmrk', 'app-promotion', 'foreign-assets', 'pallet-test-utils']173177174refungible = []178refungible = []175scheduler = []179scheduler = []470pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }474pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" }471pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }475pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false }472pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }476pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" }477pallet-unique-scheduler-v2 = { path = '../../pallets/scheduler-v2', default-features = false }473pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }478pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false }474pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false }479pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false }475pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false }480pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false }483up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' }488up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' }484pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }489pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }490491################################################################################492# Test dependencies493494pallet-test-utils = { optional = true, default-features = false, path = "../../test-pallets/utils" }485495486################################################################################496################################################################################487# Other Dependencies497# Other Dependenciesruntime/opal/src/lib.rsdiffbeforeafterboth50 spec_name: create_runtime_str!(RUNTIME_NAME),50 spec_name: create_runtime_str!(RUNTIME_NAME),51 impl_name: create_runtime_str!(RUNTIME_NAME),51 impl_name: create_runtime_str!(RUNTIME_NAME),52 authoring_version: 1,52 authoring_version: 1,53 spec_version: 930031,53 spec_version: 930032,54 impl_version: 0,54 impl_version: 0,55 apis: RUNTIME_API_VERSIONS,55 apis: RUNTIME_API_VERSIONS,56 transaction_version: 2,56 transaction_version: 2,runtime/quartz/src/lib.rsdiffbeforeafterboth50 spec_name: create_runtime_str!(RUNTIME_NAME),50 spec_name: create_runtime_str!(RUNTIME_NAME),51 impl_name: create_runtime_str!(RUNTIME_NAME),51 impl_name: create_runtime_str!(RUNTIME_NAME),52 authoring_version: 1,52 authoring_version: 1,53 spec_version: 930031,53 spec_version: 930032,54 impl_version: 0,54 impl_version: 0,55 apis: RUNTIME_API_VERSIONS,55 apis: RUNTIME_API_VERSIONS,56 transaction_version: 2,56 transaction_version: 2,runtime/unique/src/lib.rsdiffbeforeafterboth50 spec_name: create_runtime_str!(RUNTIME_NAME),50 spec_name: create_runtime_str!(RUNTIME_NAME),51 impl_name: create_runtime_str!(RUNTIME_NAME),51 impl_name: create_runtime_str!(RUNTIME_NAME),52 authoring_version: 1,52 authoring_version: 1,53 spec_version: 930031,53 spec_version: 930032,54 impl_version: 0,54 impl_version: 0,55 apis: RUNTIME_API_VERSIONS,55 apis: RUNTIME_API_VERSIONS,56 transaction_version: 2,56 transaction_version: 2,test-pallets/utils/Cargo.lockdiffbeforeafterbothno changes
test-pallets/utils/Cargo.tomldiffbeforeafterbothno changes
test-pallets/utils/src/lib.rsdiffbeforeafterbothno changes
tests/.vscode/settings.jsondiffbeforeafterboth1{1{2 "mocha.enabled": true,2 "mocha.enabled": true,3 "mochaExplorer.files": "**/*.test.ts",3 "mochaExplorer.files": "**/*.test.ts",4 "mochaExplorer.require": "ts-node/register"4 "mochaExplorer.require": "ts-node/register",5 "eslint.format.enable": true,6 "[javascript]": {7 "editor.defaultFormatter": "dbaeumer.vscode-eslint"8 },9 "[typescript]": {10 "editor.defaultFormatter": "dbaeumer.vscode-eslint"11 }5}12}613tests/src/.outdated/eth/scheduling.test.tsdiffbeforeafterbothno changes
tests/src/.outdated/scheduler.test.tsdiffbeforeafterbothno changes
tests/src/eth/allowlist.test.tsdiffbeforeafterboth89 expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false;89 expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false;90 });90 });919192 // TODO: Temprorary off. Need refactor93 // itEth('Collection allowlist can be added and removed by [sub] address', async ({helper}) => {92 //itEth('Collection allowlist can be added and removed by [cross] address', async ({helper}) => {94 // const owner = await helper.eth.createAccountWithBalance(donor);93 // const owner = await helper.eth.createAccountWithBalance(donor);95 // const user = donor;94 // const user = donor;9695 // 97 // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');96 // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');98 // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);97 // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);9998 // const userCross = helper.ethCrossAccount.fromKeyringPair(user);99 // 100 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;100 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;101 // await collectionEvm.methods.addToCollectionAllowListSubstrate(user.addressRaw).send({from: owner});101 // await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});102 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;102 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;103103 // 104 // await collectionEvm.methods.removeFromCollectionAllowListSubstrate(user.addressRaw).send({from: owner});104 // await collectionEvm.methods.removeFromCollectionAllowListCross(userCross).send({from: owner});105 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;105 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;106 // });106 //});107107108 itEth('Collection allowlist can not be add and remove [eth] address by not owner', async ({helper}) => {108 itEth('Collection allowlist can not be add and remove [eth] address by not owner', async ({helper}) => {109 const owner = await helper.eth.createAccountWithBalance(donor);109 const owner = await helper.eth.createAccountWithBalance(donor);123 expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true;122 expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true;124 });123 });125124126 // TODO: Temprorary off. Need refactor127 // itEth('Collection allowlist can not be add and remove [sub] address by not owner', async ({helper}) => {125 //itEth('Collection allowlist can not be add and remove [cross] address by not owner', async ({helper}) => {128 // const owner = await helper.eth.createAccountWithBalance(donor);126 // const owner = await helper.eth.createAccountWithBalance(donor);129 // const notOwner = await helper.eth.createAccountWithBalance(donor);127 // const notOwner = await helper.eth.createAccountWithBalance(donor);130 // const user = donor;128 // const user = donor;131129 // 132 // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');130 // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');133 // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);131 // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);134132 // 135 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;133 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;134 // const userCross = helper.ethCrossAccount.fromKeyringPair(user);136 // await expect(collectionEvm.methods.addToCollectionAllowListSubstrate(user.addressRaw).call({from: notOwner})).to.be.rejectedWith('NoPermission');135 // await expect(collectionEvm.methods.addToCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');137 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;136 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;138 // await collectionEvm.methods.addToCollectionAllowListSubstrate(user.addressRaw).send({from: owner});137 // await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});139138 // 140 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;139 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;141 // await expect(collectionEvm.methods.removeFromCollectionAllowListSubstrate(user.addressRaw).call({from: notOwner})).to.be.rejectedWith('NoPermission');140 // await expect(collectionEvm.methods.removeFromCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');142 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;141 // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;143 // });142 //});144});143});145144tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth15/// @dev inlined interface15/// @dev inlined interface16interface CollectionHelpersEvents {16interface CollectionHelpersEvents {17 event CollectionCreated(address indexed owner, address indexed collectionId);17 event CollectionCreated(address indexed owner, address indexed collectionId);18 event CollectionDestroyed(address indexed collectionId);18}19}192020/// @title Contract, which allows users to operate with collections21/// @title Contract, which allows users to operate with collections21/// @dev the ERC-165 identifier for this interface is 0x5891863122/// @dev the ERC-165 identifier for this interface is 0x7dea03b122interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {23interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {23 /// Create an NFT collection24 /// Create an NFT collection24 /// @param name Name of the collection25 /// @param name Name of the collection50 string memory tokenPrefix51 string memory tokenPrefix51 ) external payable returns (address);52 ) external payable returns (address);5354 /// @dev EVM selector for this function is: 0x7335b79f,55 /// or in textual repr: createFTCollection(string,uint8,string,string)56 function createFTCollection(57 string memory name,58 uint8 decimals,59 string memory description,60 string memory tokenPrefix61 ) external payable returns (address);526253 /// @dev EVM selector for this function is: 0x85624258,63 /// @dev EVM selector for this function is: 0x85624258,54 /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string)64 /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string)55 function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external;65 function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external;6667 /// @dev EVM selector for this function is: 0x564e321f,68 /// or in textual repr: destroyCollection(address)69 function destroyCollection(address collectionAddress) external;567057 /// Check if a collection exists71 /// Check if a collection exists58 /// @param collectionAddress Address of the collection in question72 /// @param collectionAddress Address of the collection in questiontests/src/eth/api/UniqueFungible.soldiffbeforeafterboth13}13}141415/// @title A contract that allows you to work with collections.15/// @title A contract that allows you to work with collections.16/// @dev the ERC-165 identifier for this interface is 0x62e2229016/// @dev the ERC-165 identifier for this interface is 0xb3152af317interface Collection is Dummy, ERC165 {17interface Collection is Dummy, ERC165 {18 /// Set collection property.18 /// Set collection property.19 ///19 ///23 /// or in textual repr: setCollectionProperty(string,bytes)23 /// or in textual repr: setCollectionProperty(string,bytes)24 function setCollectionProperty(string memory key, bytes memory value) external;24 function setCollectionProperty(string memory key, bytes memory value) external;2526 /// Set collection properties.27 ///28 /// @param properties Vector of properties key/value pair.29 /// @dev EVM selector for this function is: 0x50b26b2a,30 /// or in textual repr: setCollectionProperties((string,bytes)[])31 function setCollectionProperties(Tuple10[] memory properties) external;253226 /// Delete collection property.33 /// Delete collection property.27 ///34 ///30 /// or in textual repr: deleteCollectionProperty(string)37 /// or in textual repr: deleteCollectionProperty(string)31 function deleteCollectionProperty(string memory key) external;38 function deleteCollectionProperty(string memory key) external;3940 /// Delete collection properties.41 ///42 /// @param keys Properties keys.43 /// @dev EVM selector for this function is: 0xee206ee3,44 /// or in textual repr: deleteCollectionProperties(string[])45 function deleteCollectionProperties(string[] memory keys) external;324633 /// Get collection property.47 /// Get collection property.34 ///48 ///40 /// or in textual repr: collectionProperty(string)54 /// or in textual repr: collectionProperty(string)41 function collectionProperty(string memory key) external view returns (bytes memory);55 function collectionProperty(string memory key) external view returns (bytes memory);5657 /// Get collection properties.58 ///59 /// @param keys Properties keys. Empty keys for all propertyes.60 /// @return Vector of properties key/value pairs.61 /// @dev EVM selector for this function is: 0x285fb8e6,62 /// or in textual repr: collectionProperties(string[])63 function collectionProperties(string[] memory keys) external view returns (Tuple10[] memory);426443 /// Set the sponsor of the collection.65 /// Set the sponsor of the collection.44 ///66 ///49 /// or in textual repr: setCollectionSponsor(address)71 /// or in textual repr: setCollectionSponsor(address)50 function setCollectionSponsor(address sponsor) external;72 function setCollectionSponsor(address sponsor) external;7374 /// Set the sponsor of the collection.75 ///76 /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.77 ///78 /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.79 /// @dev EVM selector for this function is: 0x84a1d5a8,80 /// or in textual repr: setCollectionSponsorCross((address,uint256))81 function setCollectionSponsorCross(Tuple6 memory sponsor) external;518252 /// Whether there is a pending sponsor.83 /// Whether there is a pending sponsor.53 /// @dev EVM selector for this function is: 0x058ac185,84 /// @dev EVM selector for this function is: 0x058ac185,103 /// or in textual repr: contractAddress()134 /// or in textual repr: contractAddress()104 function contractAddress() external view returns (address);135 function contractAddress() external view returns (address);136137 /// Add collection admin.138 /// @param newAdmin Cross account administrator address.139 /// @dev EVM selector for this function is: 0x859aa7d6,140 /// or in textual repr: addCollectionAdminCross((address,uint256))141 function addCollectionAdminCross(Tuple6 memory newAdmin) external;142143 /// Remove collection admin.144 /// @param admin Cross account administrator address.145 /// @dev EVM selector for this function is: 0x6c0cd173,146 /// or in textual repr: removeCollectionAdminCross((address,uint256))147 function removeCollectionAdminCross(Tuple6 memory admin) external;105148106 /// Add collection admin.149 /// Add collection admin.107 /// @param newAdmin Address of the added administrator.150 /// @param newAdmin Address of the added administrator.153 /// or in textual repr: addToCollectionAllowList(address)196 /// or in textual repr: addToCollectionAllowList(address)154 function addToCollectionAllowList(address user) external;197 function addToCollectionAllowList(address user) external;198199 /// Add user to allowed list.200 ///201 /// @param user User cross account address.202 /// @dev EVM selector for this function is: 0xa0184a3a,203 /// or in textual repr: addToCollectionAllowListCross((address,uint256))204 function addToCollectionAllowListCross(Tuple6 memory user) external;155205156 /// Remove the user from the allowed list.206 /// Remove the user from the allowed list.157 ///207 ///160 /// or in textual repr: removeFromCollectionAllowList(address)210 /// or in textual repr: removeFromCollectionAllowList(address)161 function removeFromCollectionAllowList(address user) external;211 function removeFromCollectionAllowList(address user) external;212213 /// Remove user from allowed list.214 ///215 /// @param user User cross account address.216 /// @dev EVM selector for this function is: 0x09ba452a,217 /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))218 function removeFromCollectionAllowListCross(Tuple6 memory user) external;162219163 /// Switch permission for minting.220 /// Switch permission for minting.164 ///221 ///175 /// or in textual repr: isOwnerOrAdmin(address)232 /// or in textual repr: isOwnerOrAdmin(address)176 function isOwnerOrAdmin(address user) external view returns (bool);233 function isOwnerOrAdmin(address user) external view returns (bool);234235 /// Check that account is the owner or admin of the collection236 ///237 /// @param user User cross account to verify238 /// @return "true" if account is the owner or admin239 /// @dev EVM selector for this function is: 0x3e75a905,240 /// or in textual repr: isOwnerOrAdminCross((address,uint256))241 function isOwnerOrAdminCross(Tuple6 memory user) external view returns (bool);177242178 /// Returns collection type243 /// Returns collection type179 ///244 ///184249185 /// Get collection owner.250 /// Get collection owner.186 ///251 ///187 /// @return Tuble with sponsor address and his substrate mirror.252 /// @return Tuple with sponsor address and his substrate mirror.188 /// If address is canonical then substrate mirror is zero and vice versa.253 /// If address is canonical then substrate mirror is zero and vice versa.189 /// @dev EVM selector for this function is: 0xdf727d3b,254 /// @dev EVM selector for this function is: 0xdf727d3b,190 /// or in textual repr: collectionOwner()255 /// or in textual repr: collectionOwner()198 /// or in textual repr: changeCollectionOwner(address)263 /// or in textual repr: changeCollectionOwner(address)199 function changeCollectionOwner(address newOwner) external;264 function changeCollectionOwner(address newOwner) external;265266 /// Get collection administrators267 ///268 /// @return Vector of tuples with admins address and his substrate mirror.269 /// If address is canonical then substrate mirror is zero and vice versa.270 /// @dev EVM selector for this function is: 0x5813216b,271 /// or in textual repr: collectionAdmins()272 function collectionAdmins() external view returns (Tuple6[] memory);273274 /// Changes collection owner to another account275 ///276 /// @dev Owner can be changed only by current owner277 /// @param newOwner new owner cross account278 /// @dev EVM selector for this function is: 0xe5c9913f,279 /// or in textual repr: setOwnerCross((address,uint256))280 function setOwnerCross(Tuple6 memory newOwner) external;200}281}282283/// @dev anonymous struct284struct Tuple10 {285 string field_0;286 bytes field_1;287}201288202/// @dev the ERC-165 identifier for this interface is 0x63034ac5289/// @dev the ERC-165 identifier for this interface is 0x032e5926203interface ERC20UniqueExtensions is Dummy, ERC165 {290interface ERC20UniqueExtensions is Dummy, ERC165 {291 /// @dev EVM selector for this function is: 0x0ecd0ab0,292 /// or in textual repr: approveCross((address,uint256),uint256)293 function approveCross(Tuple6 memory spender, uint256 amount) external returns (bool);294204 /// Burn tokens from account295 /// Burn tokens from account205 /// @dev Function that burns an `amount` of the tokens of a given account,296 /// @dev Function that burns an `amount` of the tokens of a given account,210 /// or in textual repr: burnFrom(address,uint256)301 /// or in textual repr: burnFrom(address,uint256)211 function burnFrom(address from, uint256 amount) external returns (bool);302 function burnFrom(address from, uint256 amount) external returns (bool);303304 /// Burn tokens from account305 /// @dev Function that burns an `amount` of the tokens of a given account,306 /// deducting from the sender's allowance for said account.307 /// @param from The account whose tokens will be burnt.308 /// @param amount The amount that will be burnt.309 /// @dev EVM selector for this function is: 0xbb2f5a58,310 /// or in textual repr: burnFromCross((address,uint256),uint256)311 function burnFromCross(Tuple6 memory from, uint256 amount) external returns (bool);212312213 /// Mint tokens for multiple accounts.313 /// Mint tokens for multiple accounts.214 /// @param amounts array of pairs of account address and amount314 /// @param amounts array of pairs of account address and amount215 /// @dev EVM selector for this function is: 0x1acf2d55,315 /// @dev EVM selector for this function is: 0x1acf2d55,216 /// or in textual repr: mintBulk((address,uint256)[])316 /// or in textual repr: mintBulk((address,uint256)[])217 function mintBulk(Tuple6[] memory amounts) external returns (bool);317 function mintBulk(Tuple6[] memory amounts) external returns (bool);318319 /// @dev EVM selector for this function is: 0xd5cf430b,320 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)321 function transferFromCross(322 Tuple6 memory from,323 Tuple6 memory to,324 uint256 amount325 ) external returns (bool);218}326}219327220/// @dev anonymous struct328/// @dev anonymous structtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth13}13}141415/// @title A contract that allows to set and delete token properties and change token property permissions.15/// @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 0x4136937716/// @dev the ERC-165 identifier for this interface is 0x55dba91917interface TokenProperties is Dummy, ERC165 {17interface TokenProperties is Dummy, ERC165 {18 /// @notice Set permissions for token property.18 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.43 bytes memory value43 bytes memory value44 ) external;44 ) external;4546 /// @notice Set token properties value.47 /// @dev Throws error if `msg.sender` has no permission to edit the property.48 /// @param tokenId ID of the token.49 /// @param properties settable properties50 /// @dev EVM selector for this function is: 0x14ed3a6e,51 /// or in textual repr: setProperties(uint256,(string,bytes)[])52 function setProperties(uint256 tokenId, Tuple19[] memory properties) external;455346 /// @notice Delete token property value.54 /// @notice Delete token property value.47 /// @dev Throws error if `msg.sender` has no permission to edit the property.55 /// @dev Throws error if `msg.sender` has no permission to edit the property.62}70}637164/// @title A contract that allows you to work with collections.72/// @title A contract that allows you to work with collections.65/// @dev the ERC-165 identifier for this interface is 0x62e2229073/// @dev the ERC-165 identifier for this interface is 0xb3152af366interface Collection is Dummy, ERC165 {74interface Collection is Dummy, ERC165 {67 /// Set collection property.75 /// Set collection property.68 ///76 ///72 /// or in textual repr: setCollectionProperty(string,bytes)80 /// or in textual repr: setCollectionProperty(string,bytes)73 function setCollectionProperty(string memory key, bytes memory value) external;81 function setCollectionProperty(string memory key, bytes memory value) external;8283 /// Set collection properties.84 ///85 /// @param properties Vector of properties key/value pair.86 /// @dev EVM selector for this function is: 0x50b26b2a,87 /// or in textual repr: setCollectionProperties((string,bytes)[])88 function setCollectionProperties(Tuple19[] memory properties) external;748975 /// Delete collection property.90 /// Delete collection property.76 ///91 ///79 /// or in textual repr: deleteCollectionProperty(string)94 /// or in textual repr: deleteCollectionProperty(string)80 function deleteCollectionProperty(string memory key) external;95 function deleteCollectionProperty(string memory key) external;9697 /// Delete collection properties.98 ///99 /// @param keys Properties keys.100 /// @dev EVM selector for this function is: 0xee206ee3,101 /// or in textual repr: deleteCollectionProperties(string[])102 function deleteCollectionProperties(string[] memory keys) external;8110382 /// Get collection property.104 /// Get collection property.83 ///105 ///89 /// or in textual repr: collectionProperty(string)111 /// or in textual repr: collectionProperty(string)90 function collectionProperty(string memory key) external view returns (bytes memory);112 function collectionProperty(string memory key) external view returns (bytes memory);113114 /// Get collection properties.115 ///116 /// @param keys Properties keys. Empty keys for all propertyes.117 /// @return Vector of properties key/value pairs.118 /// @dev EVM selector for this function is: 0x285fb8e6,119 /// or in textual repr: collectionProperties(string[])120 function collectionProperties(string[] memory keys) external view returns (Tuple19[] memory);9112192 /// Set the sponsor of the collection.122 /// Set the sponsor of the collection.93 ///123 ///98 /// or in textual repr: setCollectionSponsor(address)128 /// or in textual repr: setCollectionSponsor(address)99 function setCollectionSponsor(address sponsor) external;129 function setCollectionSponsor(address sponsor) external;130131 /// Set the 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 Cross account address of the sponsor from whose account funds will be debited for operations with the contract.136 /// @dev EVM selector for this function is: 0x84a1d5a8,137 /// or in textual repr: setCollectionSponsorCross((address,uint256))138 function setCollectionSponsorCross(Tuple6 memory sponsor) external;100139101 /// Whether there is a pending sponsor.140 /// Whether there is a pending sponsor.102 /// @dev EVM selector for this function is: 0x058ac185,141 /// @dev EVM selector for this function is: 0x058ac185,120 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.159 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.121 /// @dev EVM selector for this function is: 0x6ec0a9f1,160 /// @dev EVM selector for this function is: 0x6ec0a9f1,122 /// or in textual repr: collectionSponsor()161 /// or in textual repr: collectionSponsor()123 function collectionSponsor() external view returns (Tuple17 memory);162 function collectionSponsor() external view returns (Tuple6 memory);124163125 /// Set limits for the collection.164 /// Set limits for the collection.126 /// @dev Throws error if limit not found.165 /// @dev Throws error if limit not found.152 /// or in textual repr: contractAddress()191 /// or in textual repr: contractAddress()153 function contractAddress() external view returns (address);192 function contractAddress() external view returns (address);193194 /// Add collection admin.195 /// @param newAdmin Cross account administrator address.196 /// @dev EVM selector for this function is: 0x859aa7d6,197 /// or in textual repr: addCollectionAdminCross((address,uint256))198 function addCollectionAdminCross(Tuple6 memory newAdmin) external;199200 /// Remove collection admin.201 /// @param admin Cross account administrator address.202 /// @dev EVM selector for this function is: 0x6c0cd173,203 /// or in textual repr: removeCollectionAdminCross((address,uint256))204 function removeCollectionAdminCross(Tuple6 memory admin) external;154205155 /// Add collection admin.206 /// Add collection admin.156 /// @param newAdmin Address of the added administrator.207 /// @param newAdmin Address of the added administrator.202 /// or in textual repr: addToCollectionAllowList(address)253 /// or in textual repr: addToCollectionAllowList(address)203 function addToCollectionAllowList(address user) external;254 function addToCollectionAllowList(address user) external;255256 /// Add user to allowed list.257 ///258 /// @param user User cross account address.259 /// @dev EVM selector for this function is: 0xa0184a3a,260 /// or in textual repr: addToCollectionAllowListCross((address,uint256))261 function addToCollectionAllowListCross(Tuple6 memory user) external;204262205 /// Remove the user from the allowed list.263 /// Remove the user from the allowed list.206 ///264 ///209 /// or in textual repr: removeFromCollectionAllowList(address)267 /// or in textual repr: removeFromCollectionAllowList(address)210 function removeFromCollectionAllowList(address user) external;268 function removeFromCollectionAllowList(address user) external;269270 /// Remove user from allowed list.271 ///272 /// @param user User cross account address.273 /// @dev EVM selector for this function is: 0x09ba452a,274 /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))275 function removeFromCollectionAllowListCross(Tuple6 memory user) external;211276212 /// Switch permission for minting.277 /// Switch permission for minting.213 ///278 ///224 /// or in textual repr: isOwnerOrAdmin(address)289 /// or in textual repr: isOwnerOrAdmin(address)225 function isOwnerOrAdmin(address user) external view returns (bool);290 function isOwnerOrAdmin(address user) external view returns (bool);291292 /// Check that account is the owner or admin of the collection293 ///294 /// @param user User cross account to verify295 /// @return "true" if account is the owner or admin296 /// @dev EVM selector for this function is: 0x3e75a905,297 /// or in textual repr: isOwnerOrAdminCross((address,uint256))298 function isOwnerOrAdminCross(Tuple6 memory user) external view returns (bool);226299227 /// Returns collection type300 /// Returns collection type228 ///301 ///233306234 /// Get collection owner.307 /// Get collection owner.235 ///308 ///236 /// @return Tuble with sponsor address and his substrate mirror.309 /// @return Tuple with sponsor address and his substrate mirror.237 /// If address is canonical then substrate mirror is zero and vice versa.310 /// If address is canonical then substrate mirror is zero and vice versa.238 /// @dev EVM selector for this function is: 0xdf727d3b,311 /// @dev EVM selector for this function is: 0xdf727d3b,239 /// or in textual repr: collectionOwner()312 /// or in textual repr: collectionOwner()240 function collectionOwner() external view returns (Tuple17 memory);313 function collectionOwner() external view returns (Tuple6 memory);241314242 /// Changes collection owner to another account315 /// Changes collection owner to another account243 ///316 ///247 /// or in textual repr: changeCollectionOwner(address)320 /// or in textual repr: changeCollectionOwner(address)248 function changeCollectionOwner(address newOwner) external;321 function changeCollectionOwner(address newOwner) external;322323 /// Get collection administrators324 ///325 /// @return Vector of tuples with admins address and his substrate mirror.326 /// If address is canonical then substrate mirror is zero and vice versa.327 /// @dev EVM selector for this function is: 0x5813216b,328 /// or in textual repr: collectionAdmins()329 function collectionAdmins() external view returns (Tuple6[] memory);330331 /// Changes collection owner to another account332 ///333 /// @dev Owner can be changed only by current owner334 /// @param newOwner new owner cross account335 /// @dev EVM selector for this function is: 0xe5c9913f,336 /// or in textual repr: setOwnerCross((address,uint256))337 function setOwnerCross(Tuple6 memory newOwner) external;249}338}250339251/// @dev anonymous struct340/// @dev anonymous struct252struct Tuple17 {341struct Tuple19 {253 address field_0;342 string field_0;254 uint256 field_1;343 bytes field_1;255}344}256345257/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension346/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension349}438}350439351/// @title Unique extensions for ERC721.440/// @title Unique extensions for ERC721.352/// @dev the ERC-165 identifier for this interface is 0x4468500d441/// @dev the ERC-165 identifier for this interface is 0x244543ee353interface ERC721UniqueExtensions is Dummy, ERC165 {442interface ERC721UniqueExtensions is Dummy, ERC165 {354 /// @notice A descriptive name for a collection of NFTs in this contract443 /// @notice A descriptive name for a collection of NFTs in this contract355 /// @dev EVM selector for this function is: 0x06fdde03,444 /// @dev EVM selector for this function is: 0x06fdde03,361 /// or in textual repr: symbol()450 /// or in textual repr: symbol()362 function symbol() external view returns (string memory);451 function symbol() external view returns (string memory);452453 /// @notice Set or reaffirm the approved address for an NFT454 /// @dev The zero address indicates there is no approved address.455 /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized456 /// operator of the current owner.457 /// @param approved The new substrate address approved NFT controller458 /// @param tokenId The NFT to approve459 /// @dev EVM selector for this function is: 0x0ecd0ab0,460 /// or in textual repr: approveCross((address,uint256),uint256)461 function approveCross(Tuple6 memory approved, uint256 tokenId) external;363462364 /// @notice Transfer ownership of an NFT463 /// @notice Transfer ownership of an NFT365 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`464 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`370 /// or in textual repr: transfer(address,uint256)469 /// or in textual repr: transfer(address,uint256)371 function transfer(address to, uint256 tokenId) external;470 function transfer(address to, uint256 tokenId) external;471472 /// @notice Transfer ownership of an NFT from cross account address to cross account address473 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`474 /// is the zero address. Throws if `tokenId` is not a valid NFT.475 /// @param from Cross acccount address of current owner476 /// @param to Cross acccount address of new owner477 /// @param tokenId The NFT to transfer478 /// @dev EVM selector for this function is: 0xd5cf430b,479 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)480 function transferFromCross(481 Tuple6 memory from,482 Tuple6 memory to,483 uint256 tokenId484 ) external;372485373 /// @notice Burns a specific ERC721 token.486 /// @notice Burns a specific ERC721 token.374 /// @dev Throws unless `msg.sender` is the current owner or an authorized487 /// @dev Throws unless `msg.sender` is the current owner or an authorized380 /// or in textual repr: burnFrom(address,uint256)493 /// or in textual repr: burnFrom(address,uint256)381 function burnFrom(address from, uint256 tokenId) external;494 function burnFrom(address from, uint256 tokenId) external;495496 /// @notice Burns a specific ERC721 token.497 /// @dev Throws unless `msg.sender` is the current owner or an authorized498 /// operator for this NFT. Throws if `from` is not the current owner. Throws499 /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT.500 /// @param from The current owner of the NFT501 /// @param tokenId The NFT to transfer502 /// @dev EVM selector for this function is: 0xbb2f5a58,503 /// or in textual repr: burnFromCross((address,uint256),uint256)504 function burnFromCross(Tuple6 memory from, uint256 tokenId) external;382505383 /// @notice Returns next free NFT ID.506 /// @notice Returns next free NFT ID.384 /// @dev EVM selector for this function is: 0x75794a3c,507 /// @dev EVM selector for this function is: 0x75794a3c,400 // /// @param tokens array of pairs of token ID and token URI for minted tokens523 // /// @param tokens array of pairs of token ID and token URI for minted tokens401 // /// @dev EVM selector for this function is: 0x36543006,524 // /// @dev EVM selector for this function is: 0x36543006,402 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])525 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])403 // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) external returns (bool);526 // function mintBulkWithTokenURI(address to, Tuple8[] memory tokens) external returns (bool);404527405}528}406529407/// @dev anonymous struct530/// @dev anonymous struct408struct Tuple6 {531struct Tuple8 {409 uint256 field_0;532 uint256 field_0;410 string field_1;533 string field_1;411}534}535536/// @dev anonymous struct537struct Tuple6 {538 address field_0;539 uint256 field_1;540}412541413/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension542/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension414/// @dev See https://eips.ethereum.org/EIPS/eip-721543/// @dev See https://eips.ethereum.org/EIPS/eip-721tests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth13}13}141415/// @title A contract that allows to set and delete token properties and change token property permissions.15/// @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 0x4136937716/// @dev the ERC-165 identifier for this interface is 0x55dba91917interface TokenProperties is Dummy, ERC165 {17interface TokenProperties is Dummy, ERC165 {18 /// @notice Set permissions for token property.18 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.43 bytes memory value43 bytes memory value44 ) external;44 ) external;4546 /// @notice Set token properties value.47 /// @dev Throws error if `msg.sender` has no permission to edit the property.48 /// @param tokenId ID of the token.49 /// @param properties settable properties50 /// @dev EVM selector for this function is: 0x14ed3a6e,51 /// or in textual repr: setProperties(uint256,(string,bytes)[])52 function setProperties(uint256 tokenId, Tuple19[] memory properties) external;455346 /// @notice Delete token property value.54 /// @notice Delete token property value.47 /// @dev Throws error if `msg.sender` has no permission to edit the property.55 /// @dev Throws error if `msg.sender` has no permission to edit the property.62}70}637164/// @title A contract that allows you to work with collections.72/// @title A contract that allows you to work with collections.65/// @dev the ERC-165 identifier for this interface is 0x62e2229073/// @dev the ERC-165 identifier for this interface is 0xb3152af366interface Collection is Dummy, ERC165 {74interface Collection is Dummy, ERC165 {67 /// Set collection property.75 /// Set collection property.68 ///76 ///72 /// or in textual repr: setCollectionProperty(string,bytes)80 /// or in textual repr: setCollectionProperty(string,bytes)73 function setCollectionProperty(string memory key, bytes memory value) external;81 function setCollectionProperty(string memory key, bytes memory value) external;8283 /// Set collection properties.84 ///85 /// @param properties Vector of properties key/value pair.86 /// @dev EVM selector for this function is: 0x50b26b2a,87 /// or in textual repr: setCollectionProperties((string,bytes)[])88 function setCollectionProperties(Tuple19[] memory properties) external;748975 /// Delete collection property.90 /// Delete collection property.76 ///91 ///79 /// or in textual repr: deleteCollectionProperty(string)94 /// or in textual repr: deleteCollectionProperty(string)80 function deleteCollectionProperty(string memory key) external;95 function deleteCollectionProperty(string memory key) external;9697 /// Delete collection properties.98 ///99 /// @param keys Properties keys.100 /// @dev EVM selector for this function is: 0xee206ee3,101 /// or in textual repr: deleteCollectionProperties(string[])102 function deleteCollectionProperties(string[] memory keys) external;8110382 /// Get collection property.104 /// Get collection property.83 ///105 ///89 /// or in textual repr: collectionProperty(string)111 /// or in textual repr: collectionProperty(string)90 function collectionProperty(string memory key) external view returns (bytes memory);112 function collectionProperty(string memory key) external view returns (bytes memory);113114 /// Get collection properties.115 ///116 /// @param keys Properties keys. Empty keys for all propertyes.117 /// @return Vector of properties key/value pairs.118 /// @dev EVM selector for this function is: 0x285fb8e6,119 /// or in textual repr: collectionProperties(string[])120 function collectionProperties(string[] memory keys) external view returns (Tuple19[] memory);9112192 /// Set the sponsor of the collection.122 /// Set the sponsor of the collection.93 ///123 ///98 /// or in textual repr: setCollectionSponsor(address)128 /// or in textual repr: setCollectionSponsor(address)99 function setCollectionSponsor(address sponsor) external;129 function setCollectionSponsor(address sponsor) external;130131 /// Set the 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 Cross account address of the sponsor from whose account funds will be debited for operations with the contract.136 /// @dev EVM selector for this function is: 0x84a1d5a8,137 /// or in textual repr: setCollectionSponsorCross((address,uint256))138 function setCollectionSponsorCross(Tuple6 memory sponsor) external;100139101 /// Whether there is a pending sponsor.140 /// Whether there is a pending sponsor.102 /// @dev EVM selector for this function is: 0x058ac185,141 /// @dev EVM selector for this function is: 0x058ac185,120 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.159 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.121 /// @dev EVM selector for this function is: 0x6ec0a9f1,160 /// @dev EVM selector for this function is: 0x6ec0a9f1,122 /// or in textual repr: collectionSponsor()161 /// or in textual repr: collectionSponsor()123 function collectionSponsor() external view returns (Tuple17 memory);162 function collectionSponsor() external view returns (Tuple6 memory);124163125 /// Set limits for the collection.164 /// Set limits for the collection.126 /// @dev Throws error if limit not found.165 /// @dev Throws error if limit not found.152 /// or in textual repr: contractAddress()191 /// or in textual repr: contractAddress()153 function contractAddress() external view returns (address);192 function contractAddress() external view returns (address);193194 /// Add collection admin.195 /// @param newAdmin Cross account administrator address.196 /// @dev EVM selector for this function is: 0x859aa7d6,197 /// or in textual repr: addCollectionAdminCross((address,uint256))198 function addCollectionAdminCross(Tuple6 memory newAdmin) external;199200 /// Remove collection admin.201 /// @param admin Cross account administrator address.202 /// @dev EVM selector for this function is: 0x6c0cd173,203 /// or in textual repr: removeCollectionAdminCross((address,uint256))204 function removeCollectionAdminCross(Tuple6 memory admin) external;154205155 /// Add collection admin.206 /// Add collection admin.156 /// @param newAdmin Address of the added administrator.207 /// @param newAdmin Address of the added administrator.202 /// or in textual repr: addToCollectionAllowList(address)253 /// or in textual repr: addToCollectionAllowList(address)203 function addToCollectionAllowList(address user) external;254 function addToCollectionAllowList(address user) external;255256 /// Add user to allowed list.257 ///258 /// @param user User cross account address.259 /// @dev EVM selector for this function is: 0xa0184a3a,260 /// or in textual repr: addToCollectionAllowListCross((address,uint256))261 function addToCollectionAllowListCross(Tuple6 memory user) external;204262205 /// Remove the user from the allowed list.263 /// Remove the user from the allowed list.206 ///264 ///209 /// or in textual repr: removeFromCollectionAllowList(address)267 /// or in textual repr: removeFromCollectionAllowList(address)210 function removeFromCollectionAllowList(address user) external;268 function removeFromCollectionAllowList(address user) external;269270 /// Remove user from allowed list.271 ///272 /// @param user User cross account address.273 /// @dev EVM selector for this function is: 0x09ba452a,274 /// or in textual repr: removeFromCollectionAllowListCross((address,uint256))275 function removeFromCollectionAllowListCross(Tuple6 memory user) external;211276212 /// Switch permission for minting.277 /// Switch permission for minting.213 ///278 ///224 /// or in textual repr: isOwnerOrAdmin(address)289 /// or in textual repr: isOwnerOrAdmin(address)225 function isOwnerOrAdmin(address user) external view returns (bool);290 function isOwnerOrAdmin(address user) external view returns (bool);291292 /// Check that account is the owner or admin of the collection293 ///294 /// @param user User cross account to verify295 /// @return "true" if account is the owner or admin296 /// @dev EVM selector for this function is: 0x3e75a905,297 /// or in textual repr: isOwnerOrAdminCross((address,uint256))298 function isOwnerOrAdminCross(Tuple6 memory user) external view returns (bool);226299227 /// Returns collection type300 /// Returns collection type228 ///301 ///233306234 /// Get collection owner.307 /// Get collection owner.235 ///308 ///236 /// @return Tuble with sponsor address and his substrate mirror.309 /// @return Tuple with sponsor address and his substrate mirror.237 /// If address is canonical then substrate mirror is zero and vice versa.310 /// If address is canonical then substrate mirror is zero and vice versa.238 /// @dev EVM selector for this function is: 0xdf727d3b,311 /// @dev EVM selector for this function is: 0xdf727d3b,239 /// or in textual repr: collectionOwner()312 /// or in textual repr: collectionOwner()240 function collectionOwner() external view returns (Tuple17 memory);313 function collectionOwner() external view returns (Tuple6 memory);241314242 /// Changes collection owner to another account315 /// Changes collection owner to another account243 ///316 ///247 /// or in textual repr: changeCollectionOwner(address)320 /// or in textual repr: changeCollectionOwner(address)248 function changeCollectionOwner(address newOwner) external;321 function changeCollectionOwner(address newOwner) external;322323 /// Get collection administrators324 ///325 /// @return Vector of tuples with admins address and his substrate mirror.326 /// If address is canonical then substrate mirror is zero and vice versa.327 /// @dev EVM selector for this function is: 0x5813216b,328 /// or in textual repr: collectionAdmins()329 function collectionAdmins() external view returns (Tuple6[] memory);330331 /// Changes collection owner to another account332 ///333 /// @dev Owner can be changed only by current owner334 /// @param newOwner new owner cross account335 /// @dev EVM selector for this function is: 0xe5c9913f,336 /// or in textual repr: setOwnerCross((address,uint256))337 function setOwnerCross(Tuple6 memory newOwner) external;249}338}250339251/// @dev anonymous struct340/// @dev anonymous struct252struct Tuple17 {341struct Tuple19 {253 address field_0;342 string field_0;254 uint256 field_1;343 bytes field_1;255}344}256345257/// @dev the ERC-165 identifier for this interface is 0x5b5e139f346/// @dev the ERC-165 identifier for this interface is 0x5b5e139f347}436}348437349/// @title Unique extensions for ERC721.438/// @title Unique extensions for ERC721.350/// @dev the ERC-165 identifier for this interface is 0xef1eaacb439/// @dev the ERC-165 identifier for this interface is 0x81feb398351interface ERC721UniqueExtensions is Dummy, ERC165 {440interface ERC721UniqueExtensions is Dummy, ERC165 {352 /// @notice A descriptive name for a collection of NFTs in this contract441 /// @notice A descriptive name for a collection of NFTs in this contract353 /// @dev EVM selector for this function is: 0x06fdde03,442 /// @dev EVM selector for this function is: 0x06fdde03,369 /// or in textual repr: transfer(address,uint256)458 /// or in textual repr: transfer(address,uint256)370 function transfer(address to, uint256 tokenId) external;459 function transfer(address to, uint256 tokenId) external;460461 /// @notice Transfer ownership of an RFT462 /// @dev Throws unless `msg.sender` is the current owner. Throws if `to`463 /// is the zero address. Throws if `tokenId` is not a valid RFT.464 /// Throws if RFT pieces have multiple owners.465 /// @param to The new owner466 /// @param tokenId The RFT to transfer467 /// @dev EVM selector for this function is: 0xd5cf430b,468 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)469 function transferFromCross(470 Tuple6 memory from,471 Tuple6 memory to,472 uint256 tokenId473 ) external;371474372 /// @notice Burns a specific ERC721 token.475 /// @notice Burns a specific ERC721 token.373 /// @dev Throws unless `msg.sender` is the current owner or an authorized476 /// @dev Throws unless `msg.sender` is the current owner or an authorized380 /// or in textual repr: burnFrom(address,uint256)483 /// or in textual repr: burnFrom(address,uint256)381 function burnFrom(address from, uint256 tokenId) external;484 function burnFrom(address from, uint256 tokenId) external;485486 /// @notice Burns a specific ERC721 token.487 /// @dev Throws unless `msg.sender` is the current owner or an authorized488 /// operator for this RFT. Throws if `from` is not the current owner. Throws489 /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT.490 /// Throws if RFT pieces have multiple owners.491 /// @param from The current owner of the RFT492 /// @param tokenId The RFT to transfer493 /// @dev EVM selector for this function is: 0xbb2f5a58,494 /// or in textual repr: burnFromCross((address,uint256),uint256)495 function burnFromCross(Tuple6 memory from, uint256 tokenId) external;382496383 /// @notice Returns next free RFT ID.497 /// @notice Returns next free RFT ID.384 /// @dev EVM selector for this function is: 0x75794a3c,498 /// @dev EVM selector for this function is: 0x75794a3c,401 // /// @param tokens array of pairs of token ID and token URI for minted tokens515 // /// @param tokens array of pairs of token ID and token URI for minted tokens402 // /// @dev EVM selector for this function is: 0x36543006,516 // /// @dev EVM selector for this function is: 0x36543006,403 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])517 // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])404 // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) external returns (bool);518 // function mintBulkWithTokenURI(address to, Tuple8[] memory tokens) external returns (bool);405519406 /// Returns EVM address for refungible token520 /// Returns EVM address for refungible token407 ///521 ///412}526}413527414/// @dev anonymous struct528/// @dev anonymous struct415struct Tuple6 {529struct Tuple8 {416 uint256 field_0;530 uint256 field_0;417 string field_1;531 string field_1;418}532}533534/// @dev anonymous struct535struct Tuple6 {536 address field_0;537 uint256 field_1;538}419539420/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension540/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension421/// @dev See https://eips.ethereum.org/EIPS/eip-721541/// @dev See https://eips.ethereum.org/EIPS/eip-721tests/src/eth/base.test.tsdiffbeforeafterboth116 await checkInterface(helper, '0x780e9d63', true, true);116 await checkInterface(helper, '0x780e9d63', true, true);117 });117 });118118119 itEth('ERC721UniqueExtensions - 0x4468500d - support', async ({helper}) => {119 itEth('ERC721UniqueExtensions - 0x244543ee - support', async ({helper}) => {120 await checkInterface(helper, '0x4468500d', true, true);120 await checkInterface(helper, '0x244543ee', true, true);121 });121 });122122123 itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {123 itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {tests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth49 .to.be.eq(newAdmin.toLocaleLowerCase());49 .to.be.eq(newAdmin.toLocaleLowerCase());50 });50 });515152 itEth.skip('Add substrate admin by owner', async ({helper}) => {52 itEth('Add cross account admin by owner', async ({helper, privateKey}) => {53 const owner = await helper.eth.createAccountWithBalance(donor);53 const owner = await helper.eth.createAccountWithBalance(donor);54 54 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');55 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');55 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);56 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);5657 58 const newAdmin = await privateKey('//Bob');57 const [newAdmin] = await helper.arrange.createAccounts([10n], donor);59 const newAdminCross = helper.ethCrossAccount.fromKeyringPair(newAdmin);58 await collectionEvm.methods.addCollectionAdminSubstrate(newAdmin.addressRaw).send();60 await collectionEvm.methods.addCollectionAdminCross(newAdminCross).send();596160 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);62 const adminList = await helper.collection.getAdmins(collectionId);61 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())63 expect(adminList).to.be.like([{Substrate: newAdmin.address}]);62 .to.be.eq(newAdmin.address.toLocaleLowerCase());63 });64 });6566 // itEth('Check adminlist', async ({helper, privateKey}) => {67 // const owner = await helper.eth.createAccountWithBalance(donor);68 69 // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');70 // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);7172 // const admin1 = helper.eth.createAccount();73 // const admin2 = await privateKey('admin');74 // await collectionEvm.methods.addCollectionAdmin(admin1).send();75 // await collectionEvm.methods.addCollectionAdminCross(helper.ethCrossAccount.fromKeyringPair(admin2)).send();7677 // const adminListRpc = await helper.collection.getAdmins(collectionId);78 // let adminListEth = await collectionEvm.methods.collectionAdmins().call();79 // adminListEth = adminListEth.map((element: IEthCrossAccountId) => {80 // return helper.address.convertCrossAccountFromEthCrossAcoount(element);81 // });82 // expect(adminListRpc).to.be.like(adminListEth);83 // });648465 itEth('Verify owner or admin', async ({helper}) => {85 itEth('Verify owner or admin', async ({helper}) => {66 const owner = await helper.eth.createAccountWithBalance(donor);86 const owner = await helper.eth.createAccountWithBalance(donor);73 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.true;94 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.true;74 });95 });759697 // itEth.skip('Check adminlist', async ({helper, privateKey}) => {98 // const owner = await helper.eth.createAccountWithBalance(donor);99 100 // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');101 // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);102103 // const admin1 = helper.eth.createAccount();104 // const admin2 = await privateKey('admin');105 // await collectionEvm.methods.addCollectionAdmin(admin1).send();106 // await collectionEvm.methods.addCollectionAdminSubstrate(admin2.addressRaw).send();107108 // const adminListRpc = await helper.collection.getAdmins(collectionId);109 // let adminListEth = await collectionEvm.methods.collectionAdmins().call();110 // adminListEth = adminListEth.map((element: IEthCrossAccountId) => {111 // return helper.address.convertCrossAccountFromEthCrossAcoount(element);112 // });113 // expect(adminListRpc).to.be.like(adminListEth);114 // });115 76 itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => {116 itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => {77 const owner = await helper.eth.createAccountWithBalance(donor);117 const owner = await helper.eth.createAccountWithBalance(donor);tests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth18 "name": "CollectionCreated",18 "name": "CollectionCreated",19 "type": "event"19 "type": "event"20 },20 },21 {22 "anonymous": false,23 "inputs": [24 {25 "indexed": true,26 "internalType": "address",27 "name": "collectionId",28 "type": "address"29 }30 ],31 "name": "CollectionDestroyed",32 "type": "event"33 },21 {34 {22 "inputs": [],35 "inputs": [],23 "name": "collectionCreationFee",36 "name": "collectionCreationFee",24 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],37 "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],25 "stateMutability": "view",38 "stateMutability": "view",26 "type": "function"39 "type": "function"27 },40 },41 {42 "inputs": [43 { "internalType": "string", "name": "name", "type": "string" },44 { "internalType": "uint8", "name": "decimals", "type": "uint8" },45 { "internalType": "string", "name": "description", "type": "string" },46 { "internalType": "string", "name": "tokenPrefix", "type": "string" }47 ],48 "name": "createFTCollection",49 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],50 "stateMutability": "payable",51 "type": "function"52 },28 {53 {29 "inputs": [54 "inputs": [30 { "internalType": "string", "name": "name", "type": "string" },55 { "internalType": "string", "name": "name", "type": "string" },47 "stateMutability": "payable",72 "stateMutability": "payable",48 "type": "function"73 "type": "function"49 },74 },75 {76 "inputs": [77 {78 "internalType": "address",79 "name": "collectionAddress",80 "type": "address"81 }82 ],83 "name": "destroyCollection",84 "outputs": [],85 "stateMutability": "nonpayable",86 "type": "function"87 },50 {88 {51 "inputs": [89 "inputs": [52 {90 {tests/src/eth/collectionProperties.test.tsdiffbeforeafterboth18import {Pallets} from '../util';18import {Pallets} from '../util';19import {IProperty, ITokenPropertyPermission} from '../util/playgrounds/types';19import {IProperty, ITokenPropertyPermission} from '../util/playgrounds/types';20import {IKeyringPair} from '@polkadot/types/types';20import {IKeyringPair} from '@polkadot/types/types';21import {TCollectionMode} from '../util/playgrounds/types';212222describe('EVM collection properties', () => {23describe('EVM collection properties', () => {23 let donor: IKeyringPair;24 let donor: IKeyringPair;162 });163 });163});164});165166describe('EVM collection property', () => {167 let donor: IKeyringPair;168169 before(async function() {170 await usingEthPlaygrounds(async (_helper, privateKey) => {171 donor = await privateKey({filename: __filename});172 });173 });174175 async function testSetReadProperties(helper: EthUniqueHelper, mode: TCollectionMode) {176 const collection = await helper[mode].mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});177178 const sender = await helper.eth.createAccountWithBalance(donor, 100n);179 await collection.addAdmin(donor, {Ethereum: sender});180181 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);182 const contract = helper.ethNativeContract.collection(collectionAddress, mode, sender);183184 const keys = ['key0', 'key1'];185186 const writeProperties = [187 helper.ethProperty.property(keys[0], 'value0'),188 helper.ethProperty.property(keys[1], 'value1'),189 ];190191 await contract.methods.setCollectionProperties(writeProperties).send();192 const readProperties = await contract.methods.collectionProperties([keys[0], keys[1]]).call();193 expect(readProperties).to.be.like(writeProperties);194 }195196 itEth('Set/read properties ft', async ({helper}) => {197 await testSetReadProperties(helper, 'ft');198 });199 itEth.ifWithPallets('Set/read properties rft', [Pallets.ReFungible], async ({helper}) => {200 await testSetReadProperties(helper, 'rft');201 });202 itEth('Set/read properties nft', async ({helper}) => {203 await testSetReadProperties(helper, 'nft');204 });205206 async function testDeleteProperties(helper: EthUniqueHelper, mode: TCollectionMode) {207 const collection = await helper[mode].mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});208209 const sender = await helper.eth.createAccountWithBalance(donor, 100n);210 await collection.addAdmin(donor, {Ethereum: sender});211212 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);213 const contract = helper.ethNativeContract.collection(collectionAddress, mode, sender);214215 const keys = ['key0', 'key1', 'key2', 'key3'];216217 {218 const writeProperties = [219 helper.ethProperty.property(keys[0], 'value0'),220 helper.ethProperty.property(keys[1], 'value1'),221 helper.ethProperty.property(keys[2], 'value2'),222 helper.ethProperty.property(keys[3], 'value3'),223 ];224225 await contract.methods.setCollectionProperties(writeProperties).send();226 const readProperties = await contract.methods.collectionProperties([keys[0], keys[1], keys[2], keys[3]]).call();227 expect(readProperties).to.be.like(writeProperties);228 }229230 {231 const expectProperties = [232 helper.ethProperty.property(keys[0], 'value0'),233 helper.ethProperty.property(keys[1], 'value1'),234 ];235236 await contract.methods.deleteCollectionProperties([keys[2], keys[3]]).send();237 const readProperties = await contract.methods.collectionProperties([]).call();238 expect(readProperties).to.be.like(expectProperties);239 }240 }241 242 itEth('Delete properties ft', async ({helper}) => {243 await testDeleteProperties(helper, 'ft');244 });245 itEth.ifWithPallets('Delete properties rft', [Pallets.ReFungible], async ({helper}) => {246 await testDeleteProperties(helper, 'rft');247 });248 itEth('Delete properties nft', async ({helper}) => {249 await testDeleteProperties(helper, 'nft');250 });251 252});164253tests/src/eth/createFTCollection.test.tsdiffbeforeafterbothno changes
tests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth35 const description = 'Some description';35 const description = 'Some description';36 const prefix = 'token prefix';36 const prefix = 'token prefix';373738 // todo:playgrounds this might fail when in async environment.39 const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;38 const {collectionId} = await helper.eth.createNFTCollection(owner, name, description, prefix);40 const {collectionId, collectionAddress, events} = await helper.eth.createNFTCollection(owner, name, description, prefix);41 42 expect(events).to.be.deep.equal([43 {44 address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',45 event: 'CollectionCreated',46 args: {47 owner: owner,48 collectionId: collectionAddress,49 },50 },51 ]);52 39 const data = (await helper.rft.getData(collectionId))!;53 const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;5440 const collection = helper.nft.getCollectionObject(collectionId);55 const collection = helper.nft.getCollectionObject(collectionId);41 56 const data = (await collection.getData())!;5758 expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);59 expect(collectionId).to.be.eq(collectionCountAfter);42 expect(data.name).to.be.eq(name);60 expect(data.name).to.be.eq(name);43 expect(data.description).to.be.eq(description);61 expect(data.description).to.be.eq(description);44 expect(data.raw.tokenPrefix).to.be.eq(prefix);62 expect(data.raw.tokenPrefix).to.be.eq(prefix);57 const prefix = 'token prefix';75 const prefix = 'token prefix';58 const baseUri = 'BaseURI';76 const baseUri = 'BaseURI';597760 const {collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);78 const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);7980 expect(events).to.be.deep.equal([81 {82 address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',83 event: 'CollectionCreated',84 args: {85 owner: owner,86 collectionId: collectionAddress,87 },88 },89 ]);619062 const collection = helper.nft.getCollectionObject(collectionId);91 const collection = helper.nft.getCollectionObject(collectionId);63 const data = (await collection.getData())!;92 const data = (await collection.getData())!;260 .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');289 .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');261 });290 });291292 itEth('destroyCollection', async ({helper}) => {293 const owner = await helper.eth.createAccountWithBalance(donor);294 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');295 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);296297298 const result = await collectionHelper.methods299 .destroyCollection(collectionAddress)300 .send({from: owner});301302 const events = helper.eth.normalizeEvents(result.events);303 304 expect(events).to.be.deep.equal([305 {306 address: collectionHelper.options.address,307 event: 'CollectionDestroyed',308 args: {309 collectionId: collectionAddress,310 },311 },312 ]);313314 expect(await collectionHelper.methods315 .isCollectionExist(collectionAddress)316 .call()).to.be.false;317 });262});318});263tests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth264 .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');264 .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');265 });265 });266 267 itEth('destroyCollection', async ({helper}) => {268 const owner = await helper.eth.createAccountWithBalance(donor);269 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');270 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);271 272 await expect(collectionHelper.methods273 .destroyCollection(collectionAddress)274 .send({from: owner})).to.be.fulfilled;275 276 expect(await collectionHelper.methods277 .isCollectionExist(collectionAddress)278 .call()).to.be.false; 279 });266});280});267281tests/src/eth/destroyCollection.test.tsdiffbeforeafterbothno changes
tests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterbothno syntactic changes
tests/src/eth/fungible.test.tsdiffbeforeafterboth148 }148 }149 });149 });150151 itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {152 const alice = await privateKey('//Alice');153 const sender = await helper.eth.createAccountWithBalance(alice, 100n);154155 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);156157 await collection.mint(alice, 200n, {Substrate: alice.address});158 await collection.approveTokens(alice, {Ethereum: sender}, 100n);159160 const address = helper.ethAddress.fromCollectionId(collection.collectionId);161 const contract = helper.ethNativeContract.collection(address, 'ft');162163 const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});164 165 const ownerCross = helper.ethCrossAccount.fromKeyringPair(alice);166 const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender});167 const events = result.events;168169 expect(events).to.be.like({170 Transfer: {171 address: helper.ethAddress.fromCollectionId(collection.collectionId),172 event: 'Transfer',173 returnValues: {174 from: helper.address.substrateToEth(alice.address),175 to: '0x0000000000000000000000000000000000000000',176 value: '49',177 },178 },179 Approval: {180 address: helper.ethAddress.fromCollectionId(collection.collectionId),181 returnValues: {182 owner: helper.address.substrateToEth(alice.address),183 spender: sender,184 value: '51',185 },186 event: 'Approval',187 },188 });189190 const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});191 expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n);192 });150193151 itEth('Can perform transferFrom()', async ({helper}) => {194 itEth('Can perform transferFrom()', async ({helper}) => {152 const owner = await helper.eth.createAccountWithBalance(donor);195 const owner = await helper.eth.createAccountWithBalance(donor);217 }260 }218 });261 });262263 itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {264 const alice = await privateKey('//Alice');265 const sender = await helper.eth.createAccountWithBalance(alice, 100n);266267 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);268269 const receiver = helper.eth.createAccount();270271 await collection.mint(alice, 200n, {Substrate: alice.address});272 await collection.approveTokens(alice, {Ethereum: sender}, 100n);273274 const address = helper.ethAddress.fromCollectionId(collection.collectionId);275 const contract = helper.ethNativeContract.collection(address, 'ft');276277 const from = helper.ethCrossAccount.fromKeyringPair(alice);278 const to = helper.ethCrossAccount.fromAddress(receiver);279280 const fromBalanceBefore = await collection.getBalance({Substrate: alice.address});281 const toBalanceBefore = await collection.getBalance({Ethereum: receiver});282 283 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});284285 expect(result.events).to.be.like({286 Transfer: {287 address,288 event: 'Transfer',289 returnValues: {290 from: helper.address.substrateToEth(alice.address),291 to: receiver,292 value: '51',293 },294 },295 Approval: {296 address,297 event: 'Approval',298 returnValues: {299 owner: helper.address.substrateToEth(alice.address),300 spender: sender,301 value: '49',302 },303 }});304305 const fromBalanceAfter = await collection.getBalance({Substrate: alice.address});306 expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n);307 const toBalanceAfter = await collection.getBalance({Ethereum: receiver});308 expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n);309 });219});310});220311221describe('Fungible: Fees', () => {312describe('Fungible: Fees', () => {363 expect(event.returnValues.value).to.be.equal('51');454 expect(event.returnValues.value).to.be.equal('51');364 });455 });456457 itEth('Events emitted for transferFromCross()', async ({helper, privateKey}) => {458 const alice = await privateKey('//Alice');459 const sender = await helper.eth.createAccountWithBalance(alice, 100n);460461 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);462463 const receiver = helper.eth.createAccount();464465 await collection.mint(alice, 200n, {Substrate: alice.address});466 await collection.approveTokens(alice, {Ethereum: sender}, 100n);467468 const address = helper.ethAddress.fromCollectionId(collection.collectionId);469 const contract = helper.ethNativeContract.collection(address, 'ft');470471 const from = helper.ethCrossAccount.fromKeyringPair(alice);472 const to = helper.ethCrossAccount.fromAddress(receiver);473 474 const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender});475476 expect(result.events).to.be.like({477 Transfer: {478 address,479 event: 'Transfer',480 returnValues: {481 from: helper.address.substrateToEth(alice.address),482 to: receiver,483 value: '51',484 },485 },486 Approval: {487 address,488 event: 'Approval',489 returnValues: {490 owner: helper.address.substrateToEth(alice.address),491 spender: sender,492 value: '49',493 },494 }});495 });365});496});366497tests/src/eth/fungibleAbi.jsondiffbeforeafterboth58 "stateMutability": "nonpayable",58 "stateMutability": "nonpayable",59 "type": "function"59 "type": "function"60 },60 },61 {62 "inputs": [63 {64 "components": [65 { "internalType": "address", "name": "field_0", "type": "address" },66 { "internalType": "uint256", "name": "field_1", "type": "uint256" }67 ],68 "internalType": "struct Tuple6",69 "name": "newAdmin",70 "type": "tuple"71 }72 ],73 "name": "addCollectionAdminCross",74 "outputs": [],75 "stateMutability": "nonpayable",76 "type": "function"77 },61 {78 {62 "inputs": [79 "inputs": [63 { "internalType": "address", "name": "user", "type": "address" }80 { "internalType": "address", "name": "user", "type": "address" }67 "stateMutability": "nonpayable",84 "stateMutability": "nonpayable",68 "type": "function"85 "type": "function"69 },86 },87 {88 "inputs": [89 {90 "components": [91 { "internalType": "address", "name": "field_0", "type": "address" },92 { "internalType": "uint256", "name": "field_1", "type": "uint256" }93 ],94 "internalType": "struct Tuple6",95 "name": "user",96 "type": "tuple"97 }98 ],99 "name": "addToCollectionAllowListCross",100 "outputs": [],101 "stateMutability": "nonpayable",102 "type": "function"103 },70 {104 {71 "inputs": [105 "inputs": [72 { "internalType": "address", "name": "owner", "type": "address" },106 { "internalType": "address", "name": "owner", "type": "address" },96 "stateMutability": "nonpayable",130 "stateMutability": "nonpayable",97 "type": "function"131 "type": "function"98 },132 },133 {134 "inputs": [135 {136 "components": [137 { "internalType": "address", "name": "field_0", "type": "address" },138 { "internalType": "uint256", "name": "field_1", "type": "uint256" }139 ],140 "internalType": "struct Tuple6",141 "name": "spender",142 "type": "tuple"143 },144 { "internalType": "uint256", "name": "amount", "type": "uint256" }145 ],146 "name": "approveCross",147 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],148 "stateMutability": "nonpayable",149 "type": "function"150 },99 {151 {100 "inputs": [152 "inputs": [101 { "internalType": "address", "name": "owner", "type": "address" }153 { "internalType": "address", "name": "owner", "type": "address" }115 "stateMutability": "nonpayable",167 "stateMutability": "nonpayable",116 "type": "function"168 "type": "function"117 },169 },170 {171 "inputs": [172 {173 "components": [174 { "internalType": "address", "name": "field_0", "type": "address" },175 { "internalType": "uint256", "name": "field_1", "type": "uint256" }176 ],177 "internalType": "struct Tuple6",178 "name": "from",179 "type": "tuple"180 },181 { "internalType": "uint256", "name": "amount", "type": "uint256" }182 ],183 "name": "burnFromCross",184 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],185 "stateMutability": "nonpayable",186 "type": "function"187 },118 {188 {119 "inputs": [189 "inputs": [120 { "internalType": "address", "name": "newOwner", "type": "address" }190 { "internalType": "address", "name": "newOwner", "type": "address" }124 "stateMutability": "nonpayable",194 "stateMutability": "nonpayable",125 "type": "function"195 "type": "function"126 },196 },197 {198 "inputs": [],199 "name": "collectionAdmins",200 "outputs": [201 {202 "components": [203 { "internalType": "address", "name": "field_0", "type": "address" },204 { "internalType": "uint256", "name": "field_1", "type": "uint256" }205 ],206 "internalType": "struct Tuple6[]",207 "name": "",208 "type": "tuple[]"209 }210 ],211 "stateMutability": "view",212 "type": "function"213 },127 {214 {128 "inputs": [],215 "inputs": [],129 "name": "collectionOwner",216 "name": "collectionOwner",141 "stateMutability": "view",228 "stateMutability": "view",142 "type": "function"229 "type": "function"143 },230 },231 {232 "inputs": [233 { "internalType": "string[]", "name": "keys", "type": "string[]" }234 ],235 "name": "collectionProperties",236 "outputs": [237 {238 "components": [239 { "internalType": "string", "name": "field_0", "type": "string" },240 { "internalType": "bytes", "name": "field_1", "type": "bytes" }241 ],242 "internalType": "struct Tuple10[]",243 "name": "",244 "type": "tuple[]"245 }246 ],247 "stateMutability": "view",248 "type": "function"249 },144 {250 {145 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],251 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],146 "name": "collectionProperty",252 "name": "collectionProperty",186 "stateMutability": "view",292 "stateMutability": "view",187 "type": "function"293 "type": "function"188 },294 },295 {296 "inputs": [297 { "internalType": "string[]", "name": "keys", "type": "string[]" }298 ],299 "name": "deleteCollectionProperties",300 "outputs": [],301 "stateMutability": "nonpayable",302 "type": "function"303 },189 {304 {190 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],305 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],191 "name": "deleteCollectionProperty",306 "name": "deleteCollectionProperty",209 "stateMutability": "view",324 "stateMutability": "view",210 "type": "function"325 "type": "function"211 },326 },327 {328 "inputs": [329 {330 "components": [331 { "internalType": "address", "name": "field_0", "type": "address" },332 { "internalType": "uint256", "name": "field_1", "type": "uint256" }333 ],334 "internalType": "struct Tuple6",335 "name": "user",336 "type": "tuple"337 }338 ],339 "name": "isOwnerOrAdminCross",340 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],341 "stateMutability": "view",342 "type": "function"343 },212 {344 {213 "inputs": [345 "inputs": [214 { "internalType": "address", "name": "to", "type": "address" },346 { "internalType": "address", "name": "to", "type": "address" },252 "stateMutability": "nonpayable",384 "stateMutability": "nonpayable",253 "type": "function"385 "type": "function"254 },386 },387 {388 "inputs": [389 {390 "components": [391 { "internalType": "address", "name": "field_0", "type": "address" },392 { "internalType": "uint256", "name": "field_1", "type": "uint256" }393 ],394 "internalType": "struct Tuple6",395 "name": "admin",396 "type": "tuple"397 }398 ],399 "name": "removeCollectionAdminCross",400 "outputs": [],401 "stateMutability": "nonpayable",402 "type": "function"403 },255 {404 {256 "inputs": [],405 "inputs": [],257 "name": "removeCollectionSponsor",406 "name": "removeCollectionSponsor",268 "stateMutability": "nonpayable",417 "stateMutability": "nonpayable",269 "type": "function"418 "type": "function"270 },419 },420 {421 "inputs": [422 {423 "components": [424 { "internalType": "address", "name": "field_0", "type": "address" },425 { "internalType": "uint256", "name": "field_1", "type": "uint256" }426 ],427 "internalType": "struct Tuple6",428 "name": "user",429 "type": "tuple"430 }431 ],432 "name": "removeFromCollectionAllowListCross",433 "outputs": [],434 "stateMutability": "nonpayable",435 "type": "function"436 },271 {437 {272 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],438 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],273 "name": "setCollectionAccess",439 "name": "setCollectionAccess",323 "stateMutability": "nonpayable",489 "stateMutability": "nonpayable",324 "type": "function"490 "type": "function"325 },491 },492 {493 "inputs": [494 {495 "components": [496 { "internalType": "string", "name": "field_0", "type": "string" },497 { "internalType": "bytes", "name": "field_1", "type": "bytes" }498 ],499 "internalType": "struct Tuple10[]",500 "name": "properties",501 "type": "tuple[]"502 }503 ],504 "name": "setCollectionProperties",505 "outputs": [],506 "stateMutability": "nonpayable",507 "type": "function"508 },326 {509 {327 "inputs": [510 "inputs": [328 { "internalType": "string", "name": "key", "type": "string" },511 { "internalType": "string", "name": "key", "type": "string" },342 "stateMutability": "nonpayable",525 "stateMutability": "nonpayable",343 "type": "function"526 "type": "function"344 },527 },528 {529 "inputs": [530 {531 "components": [532 { "internalType": "address", "name": "field_0", "type": "address" },533 { "internalType": "uint256", "name": "field_1", "type": "uint256" }534 ],535 "internalType": "struct Tuple6",536 "name": "sponsor",537 "type": "tuple"538 }539 ],540 "name": "setCollectionSponsorCross",541 "outputs": [],542 "stateMutability": "nonpayable",543 "type": "function"544 },545 {546 "inputs": [547 {548 "components": [549 { "internalType": "address", "name": "field_0", "type": "address" },550 { "internalType": "uint256", "name": "field_1", "type": "uint256" }551 ],552 "internalType": "struct Tuple6",553 "name": "newOwner",554 "type": "tuple"555 }556 ],557 "name": "setOwnerCross",558 "outputs": [],559 "stateMutability": "nonpayable",560 "type": "function"561 },345 {562 {346 "inputs": [563 "inputs": [347 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }564 { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }386 "stateMutability": "nonpayable",603 "stateMutability": "nonpayable",387 "type": "function"604 "type": "function"388 },605 },606 {607 "inputs": [608 {609 "components": [610 { "internalType": "address", "name": "field_0", "type": "address" },611 { "internalType": "uint256", "name": "field_1", "type": "uint256" }612 ],613 "internalType": "struct Tuple6",614 "name": "from",615 "type": "tuple"616 },617 {618 "components": [619 { "internalType": "address", "name": "field_0", "type": "address" },620 { "internalType": "uint256", "name": "field_1", "type": "uint256" }621 ],622 "internalType": "struct Tuple6",623 "name": "to",624 "type": "tuple"625 },626 { "internalType": "uint256", "name": "amount", "type": "uint256" }627 ],628 "name": "transferFromCross",629 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],630 "stateMutability": "nonpayable",631 "type": "function"632 },389 {633 {390 "inputs": [],634 "inputs": [],391 "name": "uniqueCollectionType",635 "name": "uniqueCollectionType",tests/src/eth/nonFungible.test.tsdiffbeforeafterboth246 }246 }247 });247 });248249 itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {250 const alice = await privateKey('//Alice');251 const collection = await helper.nft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});252253 const owner = await privateKey('//Bob');254 const spender = await helper.eth.createAccountWithBalance(alice, 100n);255256 const token = await collection.mintToken(alice, {Substrate: owner.address});257258 const address = helper.ethAddress.fromCollectionId(collection.collectionId);259 const contract = helper.ethNativeContract.collection(address, 'nft');260261 {262 await token.approve(owner, {Ethereum: spender});263 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);264 const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender});265 const events = result.events.Transfer;266267 expect(events).to.be.like({268 address,269 event: 'Transfer',270 returnValues: {271 from: helper.address.substrateToEth(owner.address),272 to: '0x0000000000000000000000000000000000000000',273 tokenId: token.tokenId.toString(),274 },275 });276 }277 });278279 itEth('Can perform approveCross()', async ({helper, privateKey}) => {280 const alice = await privateKey('//Alice');281 const collection = await helper.nft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});282283 const owner = await helper.eth.createAccountWithBalance(alice, 100n);284 const receiver = await privateKey('//Charlie');285286 const token = await collection.mintToken(alice, {Ethereum: owner});287288 const address = helper.ethAddress.fromCollectionId(collection.collectionId);289 const contract = helper.ethNativeContract.collection(address, 'nft');290291 {292 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);293 const result = await contract.methods.approveCross(recieverCross, token.tokenId).send({from: owner});294 const event = result.events.Approval;295 expect(event).to.be.like({296 address: helper.ethAddress.fromCollectionId(collection.collectionId),297 event: 'Approval',298 returnValues: {299 owner,300 approved: helper.address.substrateToEth(receiver.address),301 tokenId: token.tokenId.toString(),302 },303 });304 }305 });248306249 itEth('Can perform transferFrom()', async ({helper}) => {307 itEth('Can perform transferFrom()', async ({helper}) => {250 const owner = await helper.eth.createAccountWithBalance(donor);308 const owner = await helper.eth.createAccountWithBalance(donor);351 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));409 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));352 });410 });411412 itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {413 const alice = await privateKey('//Alice');414 const collection = await helper.nft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});415416 const owner = await privateKey('//Bob');417 const spender = await helper.eth.createAccountWithBalance(alice, 100n);418 const receiver = await privateKey('//Charlie');419420 const token = await collection.mintToken(alice, {Substrate: owner.address});421422 const address = helper.ethAddress.fromCollectionId(collection.collectionId);423 const contract = helper.ethNativeContract.collection(address, 'nft');424425 await token.approve(owner, {Ethereum: spender});426427 {428 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);429 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);430 const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});431 const event = result.events.Transfer;432 expect(event).to.be.like({433 address: helper.ethAddress.fromCollectionId(collection.collectionId),434 event: 'Transfer',435 returnValues: {436 from: helper.address.substrateToEth(owner.address),437 to: helper.address.substrateToEth(receiver.address),438 tokenId: token.tokenId.toString(),439 },440 });441 }442443 expect(await token.getOwner()).to.be.like({Substrate: receiver.address});444 });353445354 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {446 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {355 const owner = await helper.eth.createAccountWithBalance(donor);447 const owner = await helper.eth.createAccountWithBalance(donor);tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth89 "stateMutability": "nonpayable",89 "stateMutability": "nonpayable",90 "type": "function"90 "type": "function"91 },91 },92 {93 "inputs": [94 {95 "components": [96 { "internalType": "address", "name": "field_0", "type": "address" },97 { "internalType": "uint256", "name": "field_1", "type": "uint256" }98 ],99 "internalType": "struct Tuple6",100 "name": "newAdmin",101 "type": "tuple"102 }103 ],104 "name": "addCollectionAdminCross",105 "outputs": [],106 "stateMutability": "nonpayable",107 "type": "function"108 },92 {109 {93 "inputs": [110 "inputs": [94 { "internalType": "address", "name": "user", "type": "address" }111 { "internalType": "address", "name": "user", "type": "address" }98 "stateMutability": "nonpayable",115 "stateMutability": "nonpayable",99 "type": "function"116 "type": "function"100 },117 },118 {119 "inputs": [120 {121 "components": [122 { "internalType": "address", "name": "field_0", "type": "address" },123 { "internalType": "uint256", "name": "field_1", "type": "uint256" }124 ],125 "internalType": "struct Tuple6",126 "name": "user",127 "type": "tuple"128 }129 ],130 "name": "addToCollectionAllowListCross",131 "outputs": [],132 "stateMutability": "nonpayable",133 "type": "function"134 },101 {135 {102 "inputs": [136 "inputs": [103 { "internalType": "address", "name": "user", "type": "address" }137 { "internalType": "address", "name": "user", "type": "address" }117 "stateMutability": "nonpayable",151 "stateMutability": "nonpayable",118 "type": "function"152 "type": "function"119 },153 },154 {155 "inputs": [156 {157 "components": [158 { "internalType": "address", "name": "field_0", "type": "address" },159 { "internalType": "uint256", "name": "field_1", "type": "uint256" }160 ],161 "internalType": "struct Tuple6",162 "name": "approved",163 "type": "tuple"164 },165 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }166 ],167 "name": "approveCross",168 "outputs": [],169 "stateMutability": "nonpayable",170 "type": "function"171 },120 {172 {121 "inputs": [173 "inputs": [122 { "internalType": "address", "name": "owner", "type": "address" }174 { "internalType": "address", "name": "owner", "type": "address" }145 "stateMutability": "nonpayable",197 "stateMutability": "nonpayable",146 "type": "function"198 "type": "function"147 },199 },200 {201 "inputs": [202 {203 "components": [204 { "internalType": "address", "name": "field_0", "type": "address" },205 { "internalType": "uint256", "name": "field_1", "type": "uint256" }206 ],207 "internalType": "struct Tuple6",208 "name": "from",209 "type": "tuple"210 },211 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }212 ],213 "name": "burnFromCross",214 "outputs": [],215 "stateMutability": "nonpayable",216 "type": "function"217 },148 {218 {149 "inputs": [219 "inputs": [150 { "internalType": "address", "name": "newOwner", "type": "address" }220 { "internalType": "address", "name": "newOwner", "type": "address" }154 "stateMutability": "nonpayable",224 "stateMutability": "nonpayable",155 "type": "function"225 "type": "function"156 },226 },227 {228 "inputs": [],229 "name": "collectionAdmins",230 "outputs": [231 {232 "components": [233 { "internalType": "address", "name": "field_0", "type": "address" },234 { "internalType": "uint256", "name": "field_1", "type": "uint256" }235 ],236 "internalType": "struct Tuple6[]",237 "name": "",238 "type": "tuple[]"239 }240 ],241 "stateMutability": "view",242 "type": "function"243 },157 {244 {158 "inputs": [],245 "inputs": [],159 "name": "collectionOwner",246 "name": "collectionOwner",163 { "internalType": "address", "name": "field_0", "type": "address" },250 { "internalType": "address", "name": "field_0", "type": "address" },164 { "internalType": "uint256", "name": "field_1", "type": "uint256" }251 { "internalType": "uint256", "name": "field_1", "type": "uint256" }165 ],252 ],166 "internalType": "struct Tuple17",253 "internalType": "struct Tuple6",167 "name": "",254 "name": "",168 "type": "tuple"255 "type": "tuple"169 }256 }170 ],257 ],171 "stateMutability": "view",258 "stateMutability": "view",172 "type": "function"259 "type": "function"173 },260 },261 {262 "inputs": [263 { "internalType": "string[]", "name": "keys", "type": "string[]" }264 ],265 "name": "collectionProperties",266 "outputs": [267 {268 "components": [269 { "internalType": "string", "name": "field_0", "type": "string" },270 { "internalType": "bytes", "name": "field_1", "type": "bytes" }271 ],272 "internalType": "struct Tuple19[]",273 "name": "",274 "type": "tuple[]"275 }276 ],277 "stateMutability": "view",278 "type": "function"279 },174 {280 {175 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],281 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],176 "name": "collectionProperty",282 "name": "collectionProperty",187 { "internalType": "address", "name": "field_0", "type": "address" },293 { "internalType": "address", "name": "field_0", "type": "address" },188 { "internalType": "uint256", "name": "field_1", "type": "uint256" }294 { "internalType": "uint256", "name": "field_1", "type": "uint256" }189 ],295 ],190 "internalType": "struct Tuple17",296 "internalType": "struct Tuple6",191 "name": "",297 "name": "",192 "type": "tuple"298 "type": "tuple"193 }299 }209 "stateMutability": "view",315 "stateMutability": "view",210 "type": "function"316 "type": "function"211 },317 },318 {319 "inputs": [320 { "internalType": "string[]", "name": "keys", "type": "string[]" }321 ],322 "name": "deleteCollectionProperties",323 "outputs": [],324 "stateMutability": "nonpayable",325 "type": "function"326 },212 {327 {213 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],328 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],214 "name": "deleteCollectionProperty",329 "name": "deleteCollectionProperty",268 "stateMutability": "view",383 "stateMutability": "view",269 "type": "function"384 "type": "function"270 },385 },386 {387 "inputs": [388 {389 "components": [390 { "internalType": "address", "name": "field_0", "type": "address" },391 { "internalType": "uint256", "name": "field_1", "type": "uint256" }392 ],393 "internalType": "struct Tuple6",394 "name": "user",395 "type": "tuple"396 }397 ],398 "name": "isOwnerOrAdminCross",399 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],400 "stateMutability": "view",401 "type": "function"402 },271 {403 {272 "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],404 "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],273 "name": "mint",405 "name": "mint",334 "stateMutability": "nonpayable",466 "stateMutability": "nonpayable",335 "type": "function"467 "type": "function"336 },468 },469 {470 "inputs": [471 {472 "components": [473 { "internalType": "address", "name": "field_0", "type": "address" },474 { "internalType": "uint256", "name": "field_1", "type": "uint256" }475 ],476 "internalType": "struct Tuple6",477 "name": "admin",478 "type": "tuple"479 }480 ],481 "name": "removeCollectionAdminCross",482 "outputs": [],483 "stateMutability": "nonpayable",484 "type": "function"485 },337 {486 {338 "inputs": [],487 "inputs": [],339 "name": "removeCollectionSponsor",488 "name": "removeCollectionSponsor",350 "stateMutability": "nonpayable",499 "stateMutability": "nonpayable",351 "type": "function"500 "type": "function"352 },501 },502 {503 "inputs": [504 {505 "components": [506 { "internalType": "address", "name": "field_0", "type": "address" },507 { "internalType": "uint256", "name": "field_1", "type": "uint256" }508 ],509 "internalType": "struct Tuple6",510 "name": "user",511 "type": "tuple"512 }513 ],514 "name": "removeFromCollectionAllowListCross",515 "outputs": [],516 "stateMutability": "nonpayable",517 "type": "function"518 },353 {519 {354 "inputs": [520 "inputs": [355 { "internalType": "address", "name": "from", "type": "address" },521 { "internalType": "address", "name": "from", "type": "address" },438 "stateMutability": "nonpayable",604 "stateMutability": "nonpayable",439 "type": "function"605 "type": "function"440 },606 },607 {608 "inputs": [609 {610 "components": [611 { "internalType": "string", "name": "field_0", "type": "string" },612 { "internalType": "bytes", "name": "field_1", "type": "bytes" }613 ],614 "internalType": "struct Tuple19[]",615 "name": "properties",616 "type": "tuple[]"617 }618 ],619 "name": "setCollectionProperties",620 "outputs": [],621 "stateMutability": "nonpayable",622 "type": "function"623 },441 {624 {442 "inputs": [625 "inputs": [443 { "internalType": "string", "name": "key", "type": "string" },626 { "internalType": "string", "name": "key", "type": "string" },457 "stateMutability": "nonpayable",640 "stateMutability": "nonpayable",458 "type": "function"641 "type": "function"459 },642 },643 {644 "inputs": [645 {646 "components": [647 { "internalType": "address", "name": "field_0", "type": "address" },648 { "internalType": "uint256", "name": "field_1", "type": "uint256" }649 ],650 "internalType": "struct Tuple6",651 "name": "sponsor",652 "type": "tuple"653 }654 ],655 "name": "setCollectionSponsorCross",656 "outputs": [],657 "stateMutability": "nonpayable",658 "type": "function"659 },660 {661 "inputs": [662 {663 "components": [664 { "internalType": "address", "name": "field_0", "type": "address" },665 { "internalType": "uint256", "name": "field_1", "type": "uint256" }666 ],667 "internalType": "struct Tuple6",668 "name": "newOwner",669 "type": "tuple"670 }671 ],672 "name": "setOwnerCross",673 "outputs": [],674 "stateMutability": "nonpayable",675 "type": "function"676 },677 {678 "inputs": [679 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },680 {681 "components": [682 { "internalType": "string", "name": "field_0", "type": "string" },683 { "internalType": "bytes", "name": "field_1", "type": "bytes" }684 ],685 "internalType": "struct Tuple19[]",686 "name": "properties",687 "type": "tuple[]"688 }689 ],690 "name": "setProperties",691 "outputs": [],692 "stateMutability": "nonpayable",693 "type": "function"694 },460 {695 {461 "inputs": [696 "inputs": [462 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },697 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },552 "stateMutability": "nonpayable",787 "stateMutability": "nonpayable",553 "type": "function"788 "type": "function"554 },789 },790 {791 "inputs": [792 {793 "components": [794 { "internalType": "address", "name": "field_0", "type": "address" },795 { "internalType": "uint256", "name": "field_1", "type": "uint256" }796 ],797 "internalType": "struct Tuple6",798 "name": "from",799 "type": "tuple"800 },801 {802 "components": [803 { "internalType": "address", "name": "field_0", "type": "address" },804 { "internalType": "uint256", "name": "field_1", "type": "uint256" }805 ],806 "internalType": "struct Tuple6",807 "name": "to",808 "type": "tuple"809 },810 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }811 ],812 "name": "transferFromCross",813 "outputs": [],814 "stateMutability": "nonpayable",815 "type": "function"816 },555 {817 {556 "inputs": [],818 "inputs": [],557 "name": "uniqueCollectionType",819 "name": "uniqueCollectionType",tests/src/eth/reFungible.test.tsdiffbeforeafterboth227 }227 }228 });228 });229230 itEth('Can perform burnFrom()', async ({helper, privateKey}) => {231 const alice = await privateKey('//Alice');232 const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});233234 const owner = await helper.eth.createAccountWithBalance(alice, 100n);235 const spender = await helper.eth.createAccountWithBalance(alice, 100n);236237 const token = await collection.mintToken(alice, 100n, {Ethereum: owner});238239 const address = helper.ethAddress.fromCollectionId(collection.collectionId);240 const contract = helper.ethNativeContract.collection(address, 'rft');241242 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);243 const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner);244 await tokenContract.methods.repartition(15).send();245 await tokenContract.methods.approve(spender, 15).send();246247 {248 const result = await contract.methods.burnFrom(owner, token.tokenId).send({from: spender});249 const event = result.events.Transfer;250 expect(event).to.be.like({251 address: helper.ethAddress.fromCollectionId(collection.collectionId),252 event: 'Transfer',253 returnValues: {254 from: owner,255 to: '0x0000000000000000000000000000000000000000',256 tokenId: token.tokenId.toString(),257 },258 });259 }260261 expect(await collection.getTokenBalance(token.tokenId, {Ethereum: owner})).to.be.eq(0n);262 });263264 itEth('Can perform burnFromCross()', async ({helper, privateKey}) => {265 const alice = await privateKey('//Alice');266 const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});267268 const owner = await privateKey('//Bob');269 const spender = await helper.eth.createAccountWithBalance(alice, 100n);270271 const token = await collection.mintToken(alice, 100n, {Substrate: owner.address});272273 const address = helper.ethAddress.fromCollectionId(collection.collectionId);274 const contract = helper.ethNativeContract.collection(address, 'rft');275276 await token.repartition(owner, 15n);277 await token.approve(owner, {Ethereum: spender}, 15n);278279 {280 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);281 const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender});282 const event = result.events.Transfer;283 expect(event).to.be.like({284 address: helper.ethAddress.fromCollectionId(collection.collectionId),285 event: 'Transfer',286 returnValues: {287 from: helper.address.substrateToEth(owner.address),288 to: '0x0000000000000000000000000000000000000000',289 tokenId: token.tokenId.toString(),290 },291 });292 }293294 expect(await collection.getTokenBalance(token.tokenId, {Substrate: owner.address})).to.be.eq(0n);295 });296297 itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {298 const alice = await privateKey('//Alice');299 const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});300301 const owner = await privateKey('//Bob');302 const spender = await helper.eth.createAccountWithBalance(alice, 100n);303 const receiver = await privateKey('//Charlie');304305 const token = await collection.mintToken(alice, 100n, {Substrate: owner.address});306307 const address = helper.ethAddress.fromCollectionId(collection.collectionId);308 const contract = helper.ethNativeContract.collection(address, 'rft');309310 await token.repartition(owner, 15n);311 await token.approve(owner, {Ethereum: spender}, 15n);312313 {314 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);315 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);316 const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});317 const event = result.events.Transfer;318 expect(event).to.be.like({319 address: helper.ethAddress.fromCollectionId(collection.collectionId),320 event: 'Transfer',321 returnValues: {322 from: helper.address.substrateToEth(owner.address),323 to: helper.address.substrateToEth(receiver.address),324 tokenId: token.tokenId.toString(),325 },326 });327 }328329 expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);330 });229331230 itEth('Can perform transfer()', async ({helper}) => {332 itEth('Can perform transfer()', async ({helper}) => {231 const caller = await helper.eth.createAccountWithBalance(donor);333 const caller = await helper.eth.createAccountWithBalance(donor);tests/src/eth/reFungibleAbi.jsondiffbeforeafterboth89 "stateMutability": "nonpayable",89 "stateMutability": "nonpayable",90 "type": "function"90 "type": "function"91 },91 },92 {93 "inputs": [94 {95 "components": [96 { "internalType": "address", "name": "field_0", "type": "address" },97 { "internalType": "uint256", "name": "field_1", "type": "uint256" }98 ],99 "internalType": "struct Tuple6",100 "name": "newAdmin",101 "type": "tuple"102 }103 ],104 "name": "addCollectionAdminCross",105 "outputs": [],106 "stateMutability": "nonpayable",107 "type": "function"108 },92 {109 {93 "inputs": [110 "inputs": [94 { "internalType": "address", "name": "user", "type": "address" }111 { "internalType": "address", "name": "user", "type": "address" }98 "stateMutability": "nonpayable",115 "stateMutability": "nonpayable",99 "type": "function"116 "type": "function"100 },117 },118 {119 "inputs": [120 {121 "components": [122 { "internalType": "address", "name": "field_0", "type": "address" },123 { "internalType": "uint256", "name": "field_1", "type": "uint256" }124 ],125 "internalType": "struct Tuple6",126 "name": "user",127 "type": "tuple"128 }129 ],130 "name": "addToCollectionAllowListCross",131 "outputs": [],132 "stateMutability": "nonpayable",133 "type": "function"134 },101 {135 {102 "inputs": [136 "inputs": [103 { "internalType": "address", "name": "user", "type": "address" }137 { "internalType": "address", "name": "user", "type": "address" }145 "stateMutability": "nonpayable",179 "stateMutability": "nonpayable",146 "type": "function"180 "type": "function"147 },181 },182 {183 "inputs": [184 {185 "components": [186 { "internalType": "address", "name": "field_0", "type": "address" },187 { "internalType": "uint256", "name": "field_1", "type": "uint256" }188 ],189 "internalType": "struct Tuple6",190 "name": "from",191 "type": "tuple"192 },193 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }194 ],195 "name": "burnFromCross",196 "outputs": [],197 "stateMutability": "nonpayable",198 "type": "function"199 },148 {200 {149 "inputs": [201 "inputs": [150 { "internalType": "address", "name": "newOwner", "type": "address" }202 { "internalType": "address", "name": "newOwner", "type": "address" }154 "stateMutability": "nonpayable",206 "stateMutability": "nonpayable",155 "type": "function"207 "type": "function"156 },208 },209 {210 "inputs": [],211 "name": "collectionAdmins",212 "outputs": [213 {214 "components": [215 { "internalType": "address", "name": "field_0", "type": "address" },216 { "internalType": "uint256", "name": "field_1", "type": "uint256" }217 ],218 "internalType": "struct Tuple6[]",219 "name": "",220 "type": "tuple[]"221 }222 ],223 "stateMutability": "view",224 "type": "function"225 },157 {226 {158 "inputs": [],227 "inputs": [],159 "name": "collectionOwner",228 "name": "collectionOwner",163 { "internalType": "address", "name": "field_0", "type": "address" },232 { "internalType": "address", "name": "field_0", "type": "address" },164 { "internalType": "uint256", "name": "field_1", "type": "uint256" }233 { "internalType": "uint256", "name": "field_1", "type": "uint256" }165 ],234 ],166 "internalType": "struct Tuple17",235 "internalType": "struct Tuple6",167 "name": "",236 "name": "",168 "type": "tuple"237 "type": "tuple"169 }238 }170 ],239 ],171 "stateMutability": "view",240 "stateMutability": "view",172 "type": "function"241 "type": "function"173 },242 },243 {244 "inputs": [245 { "internalType": "string[]", "name": "keys", "type": "string[]" }246 ],247 "name": "collectionProperties",248 "outputs": [249 {250 "components": [251 { "internalType": "string", "name": "field_0", "type": "string" },252 { "internalType": "bytes", "name": "field_1", "type": "bytes" }253 ],254 "internalType": "struct Tuple19[]",255 "name": "",256 "type": "tuple[]"257 }258 ],259 "stateMutability": "view",260 "type": "function"261 },174 {262 {175 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],263 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],176 "name": "collectionProperty",264 "name": "collectionProperty",187 { "internalType": "address", "name": "field_0", "type": "address" },275 { "internalType": "address", "name": "field_0", "type": "address" },188 { "internalType": "uint256", "name": "field_1", "type": "uint256" }276 { "internalType": "uint256", "name": "field_1", "type": "uint256" }189 ],277 ],190 "internalType": "struct Tuple17",278 "internalType": "struct Tuple6",191 "name": "",279 "name": "",192 "type": "tuple"280 "type": "tuple"193 }281 }209 "stateMutability": "view",297 "stateMutability": "view",210 "type": "function"298 "type": "function"211 },299 },300 {301 "inputs": [302 { "internalType": "string[]", "name": "keys", "type": "string[]" }303 ],304 "name": "deleteCollectionProperties",305 "outputs": [],306 "stateMutability": "nonpayable",307 "type": "function"308 },212 {309 {213 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],310 "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],214 "name": "deleteCollectionProperty",311 "name": "deleteCollectionProperty",268 "stateMutability": "view",365 "stateMutability": "view",269 "type": "function"366 "type": "function"270 },367 },368 {369 "inputs": [370 {371 "components": [372 { "internalType": "address", "name": "field_0", "type": "address" },373 { "internalType": "uint256", "name": "field_1", "type": "uint256" }374 ],375 "internalType": "struct Tuple6",376 "name": "user",377 "type": "tuple"378 }379 ],380 "name": "isOwnerOrAdminCross",381 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],382 "stateMutability": "view",383 "type": "function"384 },271 {385 {272 "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],386 "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],273 "name": "mint",387 "name": "mint",334 "stateMutability": "nonpayable",448 "stateMutability": "nonpayable",335 "type": "function"449 "type": "function"336 },450 },451 {452 "inputs": [453 {454 "components": [455 { "internalType": "address", "name": "field_0", "type": "address" },456 { "internalType": "uint256", "name": "field_1", "type": "uint256" }457 ],458 "internalType": "struct Tuple6",459 "name": "admin",460 "type": "tuple"461 }462 ],463 "name": "removeCollectionAdminCross",464 "outputs": [],465 "stateMutability": "nonpayable",466 "type": "function"467 },337 {468 {338 "inputs": [],469 "inputs": [],339 "name": "removeCollectionSponsor",470 "name": "removeCollectionSponsor",350 "stateMutability": "nonpayable",481 "stateMutability": "nonpayable",351 "type": "function"482 "type": "function"352 },483 },484 {485 "inputs": [486 {487 "components": [488 { "internalType": "address", "name": "field_0", "type": "address" },489 { "internalType": "uint256", "name": "field_1", "type": "uint256" }490 ],491 "internalType": "struct Tuple6",492 "name": "user",493 "type": "tuple"494 }495 ],496 "name": "removeFromCollectionAllowListCross",497 "outputs": [],498 "stateMutability": "nonpayable",499 "type": "function"500 },353 {501 {354 "inputs": [502 "inputs": [355 { "internalType": "address", "name": "from", "type": "address" },503 { "internalType": "address", "name": "from", "type": "address" },438 "stateMutability": "nonpayable",586 "stateMutability": "nonpayable",439 "type": "function"587 "type": "function"440 },588 },589 {590 "inputs": [591 {592 "components": [593 { "internalType": "string", "name": "field_0", "type": "string" },594 { "internalType": "bytes", "name": "field_1", "type": "bytes" }595 ],596 "internalType": "struct Tuple19[]",597 "name": "properties",598 "type": "tuple[]"599 }600 ],601 "name": "setCollectionProperties",602 "outputs": [],603 "stateMutability": "nonpayable",604 "type": "function"605 },441 {606 {442 "inputs": [607 "inputs": [443 { "internalType": "string", "name": "key", "type": "string" },608 { "internalType": "string", "name": "key", "type": "string" },457 "stateMutability": "nonpayable",622 "stateMutability": "nonpayable",458 "type": "function"623 "type": "function"459 },624 },625 {626 "inputs": [627 {628 "components": [629 { "internalType": "address", "name": "field_0", "type": "address" },630 { "internalType": "uint256", "name": "field_1", "type": "uint256" }631 ],632 "internalType": "struct Tuple6",633 "name": "sponsor",634 "type": "tuple"635 }636 ],637 "name": "setCollectionSponsorCross",638 "outputs": [],639 "stateMutability": "nonpayable",640 "type": "function"641 },642 {643 "inputs": [644 {645 "components": [646 { "internalType": "address", "name": "field_0", "type": "address" },647 { "internalType": "uint256", "name": "field_1", "type": "uint256" }648 ],649 "internalType": "struct Tuple6",650 "name": "newOwner",651 "type": "tuple"652 }653 ],654 "name": "setOwnerCross",655 "outputs": [],656 "stateMutability": "nonpayable",657 "type": "function"658 },659 {660 "inputs": [661 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },662 {663 "components": [664 { "internalType": "string", "name": "field_0", "type": "string" },665 { "internalType": "bytes", "name": "field_1", "type": "bytes" }666 ],667 "internalType": "struct Tuple19[]",668 "name": "properties",669 "type": "tuple[]"670 }671 ],672 "name": "setProperties",673 "outputs": [],674 "stateMutability": "nonpayable",675 "type": "function"676 },460 {677 {461 "inputs": [678 "inputs": [462 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },679 { "internalType": "uint256", "name": "tokenId", "type": "uint256" },561 "stateMutability": "nonpayable",778 "stateMutability": "nonpayable",562 "type": "function"779 "type": "function"563 },780 },781 {782 "inputs": [783 {784 "components": [785 { "internalType": "address", "name": "field_0", "type": "address" },786 { "internalType": "uint256", "name": "field_1", "type": "uint256" }787 ],788 "internalType": "struct Tuple6",789 "name": "from",790 "type": "tuple"791 },792 {793 "components": [794 { "internalType": "address", "name": "field_0", "type": "address" },795 { "internalType": "uint256", "name": "field_1", "type": "uint256" }796 ],797 "internalType": "struct Tuple6",798 "name": "to",799 "type": "tuple"800 },801 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }802 ],803 "name": "transferFromCross",804 "outputs": [],805 "stateMutability": "nonpayable",806 "type": "function"807 },564 {808 {565 "inputs": [],809 "inputs": [],566 "name": "uniqueCollectionType",810 "name": "uniqueCollectionType",tests/src/eth/scheduling.test.tsdiffbeforeafterbothno changes
tests/src/eth/tokenProperties.test.tsdiffbeforeafterboth161617import {itEth, usingEthPlaygrounds, expect} from './util';17import {itEth, usingEthPlaygrounds, expect} from './util';18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';19import {ITokenPropertyPermission} from '../util/playgrounds/types';20import {Pallets} from '../util';192120describe('EVM token properties', () => {22describe('EVM token properties', () => {21 let donor: IKeyringPair;23 let donor: IKeyringPair;69 expect(value).to.equal('testValue');71 expect(value).to.equal('testValue');70 });72 });73 74 itEth('Can be multiple set for NFT ', async({helper}) => {75 const caller = await helper.eth.createAccountWithBalance(donor);76 77 const properties = Array(5).fill(0).map((_, i) => { return {field_0: `key_${i}`, field_1: Buffer.from(`value_${i}`)}; });78 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.field_0, permission: {tokenOwner: true,79 collectionAdmin: true,80 mutable: true}}; });81 82 const collection = await helper.nft.mintCollection(alice, {83 tokenPrefix: 'ethp',84 tokenPropertyPermissions: permissions,85 });86 87 const token = await collection.mintToken(alice);88 89 const valuesBefore = await token.getProperties(properties.map(p => p.field_0));90 expect(valuesBefore).to.be.deep.equal([]);91 92 await collection.addAdmin(alice, {Ethereum: caller});9394 const address = helper.ethAddress.fromCollectionId(collection.collectionId);95 const contract = helper.ethNativeContract.collection(address, 'nft', caller);9697 await contract.methods.setProperties(token.tokenId, properties).send({from: caller});9899 const values = await token.getProperties(properties.map(p => p.field_0));100 expect(values).to.be.deep.equal(properties.map(p => { return {key: p.field_0, value: p.field_1.toString()}; }));101 });102 103 itEth.ifWithPallets('Can be multiple set for RFT ', [Pallets.ReFungible], async({helper}) => {104 const caller = await helper.eth.createAccountWithBalance(donor);105 106 const properties = Array(5).fill(0).map((_, i) => { return {field_0: `key_${i}`, field_1: Buffer.from(`value_${i}`)}; });107 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.field_0, permission: {tokenOwner: true,108 collectionAdmin: true,109 mutable: true}}; });110 111 const collection = await helper.rft.mintCollection(alice, {112 tokenPrefix: 'ethp',113 tokenPropertyPermissions: permissions,114 });115 116 const token = await collection.mintToken(alice);117 118 const valuesBefore = await token.getProperties(properties.map(p => p.field_0));119 expect(valuesBefore).to.be.deep.equal([]);120 121 await collection.addAdmin(alice, {Ethereum: caller});122123 const address = helper.ethAddress.fromCollectionId(collection.collectionId);124 const contract = helper.ethNativeContract.collection(address, 'rft', caller);125126 await contract.methods.setProperties(token.tokenId, properties).send({from: caller});127128 const values = await token.getProperties(properties.map(p => p.field_0));129 expect(values).to.be.deep.equal(properties.map(p => { return {key: p.field_0, value: p.field_1.toString()}; }));130 });7113172 itEth('Can be deleted', async({helper}) => {132 itEth('Can be deleted', async({helper}) => {73 const caller = await helper.eth.createAccountWithBalance(donor);133 const caller = await helper.eth.createAccountWithBalance(donor);tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth13 event: string,13 event: string,14 args: { [key: string]: string }14 args: { [key: string]: string }15};15};16export interface TEthCrossAccount {17 readonly 0: string,18 readonly 1: string | Uint8Array,19 readonly field_0: string,20 readonly field_1: string | Uint8Array,21}2223export type EthProperty = string[];162425tests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth181819import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';19import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';202021import {ContractImports, CompiledContract, NormalizedEvent} from './types';21import {ContractImports, CompiledContract, TEthCrossAccount, NormalizedEvent, EthProperty} from './types';222223// Native contracts ABI23// Native contracts ABI24import collectionHelpersAbi from '../../collectionHelpersAbi.json';24import collectionHelpersAbi from '../../collectionHelpersAbi.json';28import refungibleTokenAbi from '../../reFungibleTokenAbi.json';28import refungibleTokenAbi from '../../reFungibleTokenAbi.json';29import contractHelpersAbi from './../contractHelpersAbi.json';29import contractHelpersAbi from './../contractHelpersAbi.json';30import {ICrossAccountId, TEthereumAccount} from '../../../util/playgrounds/types';30import {ICrossAccountId, TEthereumAccount} from '../../../util/playgrounds/types';31import {TCollectionMode} from '../../../util/playgrounds/types';313232class EthGroupBase {33class EthGroupBase {33 helper: EthUniqueHelper;34 helper: EthUniqueHelper;107 return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, gas: this.helper.eth.DEFAULT_GAS});108 return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, gas: this.helper.eth.DEFAULT_GAS});108 }109 }109110110 collection(address: string, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract {111 collection(address: string, mode: TCollectionMode, caller?: string): Contract {111 const abi = {112 const abi = {112 'nft': nonFungibleAbi,113 'nft': nonFungibleAbi,113 'rft': refungibleAbi,114 'rft': refungibleAbi,174 return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);175 return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);175 }176 }176177177 async createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {178 async createCollecion(functionName: string, signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {178 const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();179 const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();179 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);180 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);180181181 const result = await collectionHelper.methods.createNFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)});182 const result = await collectionHelper.methods[functionName](name, description, tokenPrefix).send({value: Number(collectionCreationPrice)});182183183 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);184 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);184 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);185 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);186 const events = this.helper.eth.normalizeEvents(result.events);185187186 return {collectionId, collectionAddress};188 return {collectionId, collectionAddress, events};187 }189 }190191 async createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {192 return this.createCollecion('createNFTCollection', signer, name, description, tokenPrefix);193 }188194189 async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> {195 async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {190 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);196 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);191197192 const {collectionId, collectionAddress} = await this.createNFTCollection(signer, name, description, tokenPrefix);198 const {collectionId, collectionAddress, events} = await this.createCollecion('createNFTCollection', signer, name, description, tokenPrefix);193199194 await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();200 await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();195201196 return {collectionId, collectionAddress};202 return {collectionId, collectionAddress, events};197 }203 }198204199 async createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {205 async createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> {206 return this.createCollecion('createRFTCollection', signer, name, description, tokenPrefix);207 }208209 async createFungibleCollection(signer: string, name: string, decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> {200 const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();210 const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();201 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);211 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);202212203 const result = await collectionHelper.methods.createRFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)});213 const result = await collectionHelper.methods.createFTCollection(name, decimals, description, tokenPrefix).send({value: Number(collectionCreationPrice)});204205 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);214 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);206 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);215 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);216217 const events = this.helper.eth.normalizeEvents(result.events);207218208 return {collectionId, collectionAddress};219 return {collectionId, collectionAddress, events};209 }220 }210221211 async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> {222 async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {212 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);223 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);213224214 const {collectionId, collectionAddress} = await this.createRFTCollection(signer, name, description, tokenPrefix);225 const {collectionId, collectionAddress, events} = await this.createCollecion('createRFTCollection', signer, name, description, tokenPrefix);215226216 await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();227 await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();217228218 return {collectionId, collectionAddress};229 return {collectionId, collectionAddress, events};219 }230 }220231221 async deployCollectorContract(signer: string): Promise<Contract> {232 async deployCollectorContract(signer: string): Promise<Contract> {340 return '0x' + address.substring(address.length - 40);351 return '0x' + address.substring(address.length - 40);341 }352 }342}353}343354export class EthPropertyGroup extends EthGroupBase {355 property(key: string, value: string): EthProperty {356 return [357 key,358 '0x'+Buffer.from(value).toString('hex'),359 ];360 }361}344export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;362export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;363364export class EthCrossAccountGroup extends EthGroupBase {365 fromAddress(address: TEthereumAccount): TEthCrossAccount {366 return {367 0: address,368 1: '0',369 field_0: address,370 field_1: '0',371 };372 }373374 fromKeyringPair(keyring: IKeyringPair): TEthCrossAccount {375 return {376 0: '0x0000000000000000000000000000000000000000',377 1: keyring.addressRaw,378 field_0: '0x0000000000000000000000000000000000000000',379 field_1: keyring.addressRaw,380 };381 }382}345383346export class EthUniqueHelper extends DevUniqueHelper {384export class EthUniqueHelper extends DevUniqueHelper {347 web3: Web3 | null = null;385 web3: Web3 | null = null;351 ethAddress: EthAddressGroup;389 ethAddress: EthAddressGroup;352 ethNativeContract: NativeContractGroup;390 ethNativeContract: NativeContractGroup;353 ethContract: ContractGroup;391 ethContract: ContractGroup;392 ethCrossAccount: EthCrossAccountGroup;393 ethProperty: EthPropertyGroup;354394355 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {395 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {356 options.helperBase = options.helperBase ?? EthUniqueHelper;396 options.helperBase = options.helperBase ?? EthUniqueHelper;357397358 super(logger, options);398 super(logger, options);359 this.eth = new EthGroup(this);399 this.eth = new EthGroup(this);360 this.ethAddress = new EthAddressGroup(this);400 this.ethAddress = new EthAddressGroup(this);401 this.ethCrossAccount = new EthCrossAccountGroup(this);361 this.ethNativeContract = new NativeContractGroup(this);402 this.ethNativeContract = new NativeContractGroup(this);362 this.ethContract = new ContractGroup(this);403 this.ethContract = new ContractGroup(this);404 this.ethProperty = new EthPropertyGroup(this);363 }405 }364406365 getWeb3(): Web3 {407 getWeb3(): Web3 {tests/src/pallet-presence.test.tsdiffbeforeafterboth62 const chain = await helper.callRpc('api.rpc.system.chain', []);62 const chain = await helper.callRpc('api.rpc.system.chain', []);636364 const refungible = 'refungible';64 const refungible = 'refungible';65 // const scheduler = 'scheduler';65 const scheduler = 'scheduler';66 const foreignAssets = 'foreignassets';66 const foreignAssets = 'foreignassets';67 const rmrkPallets = ['rmrkcore', 'rmrkequip'];67 const rmrkPallets = ['rmrkcore', 'rmrkequip'];68 const appPromotion = 'apppromotion';68 const appPromotion = 'apppromotion';69 const testUtils = 'testutils';697070 if (chain.eq('OPAL by UNIQUE')) {71 if (chain.eq('OPAL by UNIQUE')) {71 requiredPallets.push(72 requiredPallets.push(72 refungible,73 refungible,73 // scheduler,74 // scheduler,74 foreignAssets,75 foreignAssets,75 appPromotion,76 appPromotion,77 testUtils,78 scheduler,76 ...rmrkPallets,79 ...rmrkPallets,77 );80 );78 } else if (chain.eq('QUARTZ by UNIQUE')) {81 } else if (chain.eq('QUARTZ by UNIQUE')) {tests/src/scheduler.test.tsdiffbeforeafterbothno changes
tests/src/util/index.tsdiffbeforeafterboth95 NFT = 'nonfungible',95 NFT = 'nonfungible',96 Scheduler = 'scheduler',96 Scheduler = 'scheduler',97 AppPromotion = 'apppromotion',97 AppPromotion = 'apppromotion',98 TestUtils = 'testutils',98}99}99100100export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: string[]) {101export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: string[]) {tests/src/util/playgrounds/types.tsdiffbeforeafterboth70 ethereum?: TEthereumAccount;70 ethereum?: TEthereumAccount;71}71}7273export interface IEthCrossAccountId {74 0: TEthereumAccount;75 1: TSubstrateAccount;76 field_0: TEthereumAccount;77 field_1: TSubstrateAccount;78}727973export interface ICollectionLimits {80export interface ICollectionLimits {74 accountTokenOwnershipLimit?: number | null;81 accountTokenOwnershipLimit?: number | null;217export type TRelayNetworks = 'rococo' | 'westend';224export type TRelayNetworks = 'rococo' | 'westend';218export type TNetworks = TUniqueNetworks | TSiblingNetworkds | TRelayNetworks;225export type TNetworks = TUniqueNetworks | TSiblingNetworkds | TRelayNetworks;219export type TSigner = IKeyringPair; // | 'string'226export type TSigner = IKeyringPair; // | 'string'227export type TCollectionMode = 'nft' | 'rft' | 'ft';220228tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth8import * as defs from '../../interfaces/definitions';8import * as defs from '../../interfaces/definitions';9import {IKeyringPair} from '@polkadot/types/types';9import {IKeyringPair} from '@polkadot/types/types';10import {EventRecord} from '@polkadot/types/interfaces';10import {EventRecord} from '@polkadot/types/interfaces';11import {ICrossAccountId} from './types';11import {ICrossAccountId, TSigner} from './types';12import {FrameSystemEventRecord} from '@polkadot/types/lookup';12import {FrameSystemEventRecord} from '@polkadot/types/lookup';13import {VoidFn} from '@polkadot/api/types';14import {Pallets} from '..';131514export class SilentLogger {16export class SilentLogger {15 log(_msg: any, _level: any): void { }17 log(_msg: any, _level: any): void { }63 arrange: ArrangeGroup;65 arrange: ArrangeGroup;64 wait: WaitGroup;66 wait: WaitGroup;65 admin: AdminGroup;67 admin: AdminGroup;68 testUtils: TestUtilGroup;666967 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {70 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {68 options.helperBase = options.helperBase ?? DevUniqueHelper;71 options.helperBase = options.helperBase ?? DevUniqueHelper;71 this.arrange = new ArrangeGroup(this);74 this.arrange = new ArrangeGroup(this);72 this.wait = new WaitGroup(this);75 this.wait = new WaitGroup(this);73 this.admin = new AdminGroup(this);76 this.admin = new AdminGroup(this);77 this.testUtils = new TestUtilGroup(this);74 }78 }757976 async connect(wsEndpoint: string, _listeners?: any): Promise<void> {80 async connect(wsEndpoint: string, _listeners?: any): Promise<void> {154class ArrangeGroup {158class ArrangeGroup {155 helper: DevUniqueHelper;159 helper: DevUniqueHelper;160161 scheduledIdSlider = 0;156162157 constructor(helper: DevUniqueHelper) {163 constructor(helper: DevUniqueHelper) {158 this.helper = helper;164 this.helper = helper;298 return encodeAddress(address);304 return encodeAddress(address);299 }305 }306307 async makeScheduledIds(num: number): Promise<string[]> {308 await this.helper.wait.noScheduledTasks();309310 function makeId(slider: number) {311 const scheduledIdSize = 64;312 const hexId = slider.toString(16);313 const prefixSize = scheduledIdSize - hexId.length;314315 const scheduledId = '0x' + '0'.repeat(prefixSize) + hexId;316317 return scheduledId; 318 }319320 const ids = [];321 for (let i = 0; i < num; i++) {322 ids.push(makeId(this.scheduledIdSlider));323 this.scheduledIdSlider += 1;324 }325326 return ids;327 }328329 async makeScheduledId(): Promise<string> {330 return (await this.makeScheduledIds(1))[0];331 }332333 async captureEvents(eventSection: string, eventMethod: string): Promise<EventCapture> {334 const capture = new EventCapture(this.helper, eventSection, eventMethod);335 await capture.startCapture();336337 return capture;338 }300}339}301340302class MoonbeamAccountGroup {341class MoonbeamAccountGroup {389 });428 });390 }429 }430431 async noScheduledTasks() {432 const api = this.helper.getApi();433 434 // eslint-disable-next-line no-async-promise-executor435 const promise = new Promise<void>(async resolve => {436 const unsubscribe = await api.rpc.chain.subscribeNewHeads(async () => {437 const areThereScheduledTasks = await api.query.scheduler.lookup.entries();438439 if(areThereScheduledTasks.length == 0) {440 unsubscribe();441 resolve();442 }443 }); 444 });445446 return promise;447 }391448392 event(maxBlocksToWait: number, eventSection: string, eventMethod: string) {449 async event(maxBlocksToWait: number, eventSection: string, eventMethod: string) {393 // eslint-disable-next-line no-async-promise-executor450 // eslint-disable-next-line no-async-promise-executor394 const promise = new Promise<EventRecord | null>(async (resolve) => {451 const promise = new Promise<EventRecord | null>(async (resolve) => {395 const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(async header => {452 const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(async header => {424 }480 }425}481}482483class TestUtilGroup {484 helper: DevUniqueHelper;485486 constructor(helper: DevUniqueHelper) {487 this.helper = helper;488 }489490 async enable() {491 if (this.helper.fetchMissingPalletNames([Pallets.TestUtils]).length != 0) {492 return;493 }494495 const signer = this.helper.util.fromSeed('//Alice');496 await this.helper.getSudo<DevUniqueHelper>().executeExtrinsic(signer, 'api.tx.testUtils.enable', [], true);497 }498499 async setTestValue(signer: TSigner, testVal: number) {500 await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValue', [testVal], true);501 }502503 async incTestValue(signer: TSigner) {504 await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.incTestValue', [], true);505 }506507 async setTestValueAndRollback(signer: TSigner, testVal: number) {508 await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValueAndRollback', [testVal], true);509 }510511 async testValue() {512 return (await this.helper.callRpc('api.query.testUtils.testValue', [])).toNumber();513 }514515 async justTakeFee(signer: TSigner) {516 await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.justTakeFee', [], true);517 }518519 async selfCancelingInc(signer: TSigner, scheduledId: string, maxTestVal: number) {520 await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.selfCancelingInc', [scheduledId, maxTestVal], true);521 }522}523524class EventCapture {525 helper: DevUniqueHelper;526 eventSection: string;527 eventMethod: string;528 events: EventRecord[] = [];529 unsubscribe: VoidFn | null = null;530531 constructor(532 helper: DevUniqueHelper,533 eventSection: string,534 eventMethod: string,535 ) {536 this.helper = helper;537 this.eventSection = eventSection;538 this.eventMethod = eventMethod;539 }540541 async startCapture() {542 this.stopCapture();543 this.unsubscribe = (await this.helper.getApi().query.system.events((eventRecords: FrameSystemEventRecord[]) => {544 const newEvents = eventRecords.filter(r => {545 return r.event.section == this.eventSection && r.event.method == this.eventMethod;546 });547548 this.events.push(...newEvents);549 })) as any;550 }551552 stopCapture() {553 if (this.unsubscribe !== null) {554 this.unsubscribe();555 }556 }557558 extractCapturedEvents() {559 return this.events;560 }561}426562427class AdminGroup {563class AdminGroup {428 helper: UniqueHelper;564 helper: UniqueHelper;tests/src/util/playgrounds/unique.tsdiffbeforeafterboth9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';11import {IKeyringPair} from '@polkadot/types/types';11import {IKeyringPair} from '@polkadot/types/types';12import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISchedulerOptions, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, IForeignAssetMetadata, TNetworks, MoonbeamAssetInfo, DemocracyStandardAccountVote, AcalaAssetMetadata} from './types';12import {13 IApiListeners,14 IBlock,15 IEvent,16 IChainProperties,17 ICollectionCreationOptions,18 ICollectionLimits,19 ICollectionPermissions,20 ICrossAccountId,21 ICrossAccountIdLower,22 ILogger,23 INestingPermissions,24 IProperty,25 IStakingInfo,26 ISchedulerOptions,27 ISubstrateBalance,28 IToken,29 ITokenPropertyPermission,30 ITransactionResult,31 IUniqueHelperLog,32 TApiAllowedListeners,33 TEthereumAccount,34 TSigner,35 TSubstrateAccount,36 TNetworks,37 IForeignAssetMetadata,38 AcalaAssetMetadata,39 MoonbeamAssetInfo,40 DemocracyStandardAccountVote,41} from './types';42import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';134314export class CrossAccountId implements ICrossAccountId {44export class CrossAccountId implements ICrossAccountId {15 Substrate?: TSubstrateAccount;45 Substrate?: TSubstrateAccount;532 });562 });533 }563 }564565 async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {566 const api = this.getApi();567 const signingInfo = await api.derive.tx.signingInfo(signer.address);568569 // We need to sign the tx because570 // unsigned transactions does not have an inclusion fee571 tx.sign(signer, {572 blockHash: api.genesisHash,573 genesisHash: api.genesisHash,574 runtimeVersion: api.runtimeVersion,575 nonce: signingInfo.nonce,576 });577578 if (len === null) {579 return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;580 } else {581 return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;582 }583 }534584535 constructApiCall(apiCall: string, params: any[]) {585 constructApiCall(apiCall: string, params: any[]) {536 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);586 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);904 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved');954 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved');905 }955 }906956907 /**957 /**908 * Check if user is in allow list.958 * Check if user is in allow list.909 * 959 *910 * @param collectionId ID of collection960 * @param collectionId ID of collection911 * @param user Account to check961 * @param user Account to check912 * @example await getAdmins(1)962 * @example await getAdmins(1)913 * @returns is user in allow list963 * @returns is user in allow list914 */964 */915 async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {965 async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {916 return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();966 return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();917 }967 }1014 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1064 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1015 }1065 }101610661017 /**1067 /**1018 * Get collection properties.1068 * Get collection properties.1019 * 1069 *1020 * @param collectionId ID of collection1070 * @param collectionId ID of collection1021 * @param propertyKeys optionally filter the returned properties to only these keys1071 * @param propertyKeys optionally filter the returned properties to only these keys1022 * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1072 * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1023 * @returns array of key-value pairs1073 * @returns array of key-value pairs1024 */1074 */1025 async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1075 async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1026 return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1076 return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1027 }1077 }1266 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1316 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1267 }1317 }126813181269 /**1319 /**1270 * Get token property permissions.1320 * Get token property permissions.1271 * 1321 *1272 * @param collectionId ID of collection1322 * @param collectionId ID of collection1273 * @param propertyKeys optionally filter the returned property permissions to only these keys1323 * @param propertyKeys optionally filter the returned property permissions to only these keys1274 * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1324 * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1275 * @returns array of key-permission pairs1325 * @returns array of key-permission pairs1276 */1326 */1277 async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1327 async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1278 return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1328 return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1279 }1329 }1298 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1348 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1299 }1349 }130013501301 /**1351 /**1302 * Get properties, metadata assigned to a token.1352 * Get properties, metadata assigned to a token.1303 * 1353 *1304 * @param collectionId ID of collection1354 * @param collectionId ID of collection1305 * @param tokenId ID of token1355 * @param tokenId ID of token1306 * @param propertyKeys optionally filter the returned properties to only these keys1356 * @param propertyKeys optionally filter the returned properties to only these keys1307 * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1357 * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1308 * @returns array of key-value pairs1358 * @returns array of key-value pairs1309 */1359 */1310 async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1360 async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1311 return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1361 return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1312 }1362 }2255 return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2305 return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2256 }2306 }23072308 async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2309 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);23102311 let transfer = {from: null, to: null, amount: 0n} as any;2312 result.result.events.forEach(({event: {data, method, section}}) => {2313 if ((section === 'balances') && (method === 'Transfer')) {2314 transfer = {2315 from: this.helper.address.normalizeSubstrate(data[0]),2316 to: this.helper.address.normalizeSubstrate(data[1]),2317 amount: BigInt(data[2]),2318 };2319 }2320 });2321 let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2322 isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2323 isSuccess = isSuccess && BigInt(amount) === transfer.amount;2324 return isSuccess;2325 }2257}2326}225823272259class AddressGroup extends HelperGroup<ChainHelperBase> {2328class AddressGroup extends HelperGroup<ChainHelperBase> {2769 this.blocksNum,2838 this.blocksNum,2770 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2839 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2771 this.options.priority ?? null,2840 this.options.priority ?? null,2772 {Value: scheduledTx},2841 scheduledTx,2773 ],2842 ],2774 expectSuccess,2843 expectSuccess,2775 );2844 );