difftreelog
Merge branch 'develop' into tests/generalization
in: master
57 files changed
Cargo.lockdiffbeforeafterboth2330 "hex",2330 "hex",2331 "hex-literal",2331 "hex-literal",2332 "impl-trait-for-tuples",2332 "impl-trait-for-tuples",2333 "pallet-evm",2334 "primitive-types 0.12.1",2333 "primitive-types 0.12.1",2335 "sha3-const",2334 "sha3-const",2336 "similar-asserts",2335 "similar-asserts",crates/evm-coder/Cargo.tomldiffbeforeafterboth19# We have tuple-heavy code in solidity.rs19# We have tuple-heavy code in solidity.rs20impl-trait-for-tuples = "0.2.2"20impl-trait-for-tuples = "0.2.2"2122pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }232124[dev-dependencies]22[dev-dependencies]25# We want to assert some large binary blobs equality in tests23# We want to assert some large binary blobs equality in testscrates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth347347348 fn is_value(&self) -> bool {348 fn is_value(&self) -> bool {349 if let Ok(ident) = self.plain() {349 if let Ok(ident) = self.plain() {350 return ident == "value";350 return ident == "Value";351 }351 }352 false352 false353 }353 }354354355 fn is_caller(&self) -> bool {355 fn is_caller(&self) -> bool {356 if let Ok(ident) = self.plain() {356 if let Ok(ident) = self.plain() {357 return ident == "caller";357 return ident == "Caller";358 }358 }359 false359 false360 }360 }610 let custom_signature = self.expand_custom_signature();610 let custom_signature = self.expand_custom_signature();611 quote! {611 quote! {612 const #screaming_name_signature: ::evm_coder::custom_signature::SignatureUnit = #custom_signature;612 const #screaming_name_signature: ::evm_coder::custom_signature::SignatureUnit = #custom_signature;613 const #screaming_name: ::evm_coder::types::bytes4 = {613 const #screaming_name: ::evm_coder::types::Bytes4 = {614 let mut sum = ::evm_coder::sha3_const::Keccak256::new();614 let mut sum = ::evm_coder::sha3_const::Keccak256::new();615 let mut pos = 0;615 let mut pos = 0;616 while pos < Self::#screaming_name_signature.len {616 while pos < Self::#screaming_name_signature.len {974 #consts974 #consts975 )*975 )*976 /// Return this call ERC165 selector976 /// Return this call ERC165 selector977 pub const fn interface_id() -> ::evm_coder::types::bytes4 {977 pub const fn interface_id() -> ::evm_coder::types::Bytes4 {978 let mut interface_id = 0;978 let mut interface_id = 0;979 #(#interface_id)*979 #(#interface_id)*980 #(#inline_interface_id)*980 #(#inline_interface_id)*999 )*),999 )*),1000 };1000 };100110011002 let mut out = ::evm_coder::types::string::new();1002 let mut out = ::evm_coder::types::String::new();1003 if #solidity_name.starts_with("Inline") {1003 if #solidity_name.starts_with("Inline") {1004 out.push_str("/// @dev inlined interface\n");1004 out.push_str("/// @dev inlined interface\n");1005 }1005 }1019 }1019 }1020 }1020 }1021 impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {1021 impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {1022 fn parse(method_id: ::evm_coder::types::bytes4, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {1022 fn parse(method_id: ::evm_coder::types::Bytes4, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {1023 use ::evm_coder::abi::AbiRead;1023 use ::evm_coder::abi::AbiRead;1024 match method_id {1024 match method_id {1025 ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(1025 ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(1041 #gen_where1041 #gen_where1042 {1042 {1043 /// Is this contract implements specified ERC165 selector1043 /// Is this contract implements specified ERC165 selector1044 pub fn supports_interface(this: &#name, interface_id: ::evm_coder::types::bytes4) -> bool {1044 pub fn supports_interface(this: &#name, interface_id: ::evm_coder::types::Bytes4) -> bool {1045 interface_id != u32::to_be_bytes(0xffffff) && (1045 interface_id != u32::to_be_bytes(0xffffff) && (1046 interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||1046 interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||1047 interface_id == Self::interface_id()1047 interface_id == Self::interface_id()crates/evm-coder/procedural/src/to_log.rsdiffbeforeafterboth137 Self::#name {#(137 Self::#name {#(138 #fields,138 #fields,139 )*} => {139 )*} => {140 topics.push(topic::from(Self::#name_screaming));140 topics.push(::evm_coder::types::Topic::from(Self::#name_screaming));141 #(141 #(142 topics.push(#indexed.to_topic());142 topics.push(#indexed.to_topic());143 )*143 )*222 #solidity_functions,222 #solidity_functions,223 )*),223 )*),224 };224 };225 let mut out = string::new();225 let mut out = ::evm_coder::types::String::new();226 out.push_str("/// @dev inlined interface\n");226 out.push_str("/// @dev inlined interface\n");227 let _ = interface.format(is_impl, &mut out, tc);227 let _ = interface.format(is_impl, &mut out, tc);228 tc.collect(out);228 tc.collect(out);231231232 #[automatically_derived]232 #[automatically_derived]233 impl ::evm_coder::events::ToLog for #name {233 impl ::evm_coder::events::ToLog for #name {234 fn to_log(&self, contract: address) -> ::ethereum::Log {234 fn to_log(&self, contract: Address) -> ::ethereum::Log {235 use ::evm_coder::events::ToTopic;235 use ::evm_coder::events::ToTopic;236 use ::evm_coder::abi::AbiWrite;236 use ::evm_coder::abi::AbiWrite;237 let mut writer = ::evm_coder::abi::AbiWriter::new();237 let mut writer = ::evm_coder::abi::AbiWriter::new();crates/evm-coder/src/abi/impls.rsdiffbeforeafterboth63impl_abi!(u128, uint128, false);63impl_abi!(u128, uint128, false);64impl_abi!(U256, uint256, false);64impl_abi!(U256, uint256, false);65impl_abi!(H160, address, false);65impl_abi!(H160, address, false);66impl_abi!(string, string, true);66impl_abi!(String, string, true);676768impl_abi_writeable!(&str, string);68impl_abi_writeable!(&str, string);696970impl_abi_type!(bytes, bytes, true);70impl_abi_type!(Bytes, bytes, true);717172impl AbiRead for bytes {72impl AbiRead for Bytes {73 fn abi_read(reader: &mut AbiReader) -> Result<bytes> {73 fn abi_read(reader: &mut AbiReader) -> Result<Bytes> {74 Ok(bytes(reader.bytes()?))74 Ok(Bytes(reader.bytes()?))75 }75 }76}76}777778impl AbiWrite for bytes {78impl AbiWrite for Bytes {79 fn abi_write(&self, writer: &mut AbiWriter) {79 fn abi_write(&self, writer: &mut AbiWriter) {80 writer.bytes(self.0.as_slice())80 writer.bytes(self.0.as_slice())81 }81 }82}82}838384impl_abi_type!(bytes4, bytes4, false);84impl_abi_type!(Bytes4, bytes4, false);85impl AbiRead for bytes4 {85impl AbiRead for Bytes4 {86 fn abi_read(reader: &mut AbiReader) -> Result<bytes4> {86 fn abi_read(reader: &mut AbiReader) -> Result<Bytes4> {87 reader.bytes4()87 reader.bytes4()88 }88 }89}89}crates/evm-coder/src/abi/mod.rsdiffbeforeafterboth54 }54 }55 }55 }56 /// Start reading RLP buffer, parsing first 4 bytes as selector56 /// Start reading RLP buffer, parsing first 4 bytes as selector57 pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {57 pub fn new_call(buf: &'i [u8]) -> Result<(Bytes4, Self)> {58 if buf.len() < 4 {58 if buf.len() < 4 {59 return Err(Error::Error(ExitError::OutOfOffset));59 return Err(Error::Error(ExitError::OutOfOffset));60 }60 }148 }148 }149149150 /// Read [`string`] at current position, then advance150 /// Read [`string`] at current position, then advance151 pub fn string(&mut self) -> Result<string> {151 pub fn string(&mut self) -> Result<String> {152 string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))152 String::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))153 }153 }154154155 /// Read [`u8`] at current position, then advance155 /// Read [`u8`] at current position, then advancecrates/evm-coder/src/abi/test.rsdiffbeforeafterboth393940#[test]40#[test]41fn encode_decode_uint8() {41fn encode_decode_uint8() {42 test_impl_uint!(uint8);42 test_impl_uint!(u8);43}43}444445#[test]45#[test]46fn encode_decode_uint32() {46fn encode_decode_uint32() {47 test_impl_uint!(uint32);47 test_impl_uint!(u32);48}48}494950#[test]50#[test]51fn encode_decode_uint128() {51fn encode_decode_uint128() {52 test_impl_uint!(uint128);52 test_impl_uint!(u128);53}53}545455#[test]55#[test]56fn encode_decode_uint256() {56fn encode_decode_uint256() {57 test_impl::<uint256>(57 test_impl::<U256>(58 0xdeadbeef,58 0xdeadbeef,59 U256([255, 0, 0, 0]),59 U256([255, 0, 0, 0]),60 &hex!(60 &hex!(101101102#[test]102#[test]103fn encode_decode_vec_tuple_address_uint256() {103fn encode_decode_vec_tuple_address_uint256() {104 test_impl::<Vec<(address, uint256)>>(104 test_impl::<Vec<(Address, U256)>>(105 0x1ACF2D55,105 0x1ACF2D55,106 vec![106 vec![107 (107 (138138139#[test]139#[test]140fn encode_decode_vec_tuple_uint256_string() {140fn encode_decode_vec_tuple_uint256_string() {141 test_impl::<Vec<(uint256, string)>>(141 test_impl::<Vec<(U256, String)>>(142 0xdeadbeef,142 0xdeadbeef,143 vec![143 vec![144 (1.into(), "Test URI 0".to_string()),144 (1.into(), "Test URI 0".to_string()),261 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();261 let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();262 assert_eq!(call, u32::to_be_bytes(decoded_data.0));262 assert_eq!(call, u32::to_be_bytes(decoded_data.0));263 let address = decoder.address().unwrap();263 let address = decoder.address().unwrap();264 let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();264 let data = <Vec<(U256, String)>>::abi_read(&mut decoder).unwrap();265 assert_eq!(data, decoded_data.1);265 assert_eq!(data, decoded_data.1);266266267 let mut writer = AbiWriter::new_call(decoded_data.0);267 let mut writer = AbiWriter::new_call(decoded_data.0);273273274#[test]274#[test]275fn encode_decode_vec_tuple_string_bytes() {275fn encode_decode_vec_tuple_string_bytes() {276 test_impl::<Vec<(string, bytes)>>(276 test_impl::<Vec<(String, Bytes)>>(277 0xdeadbeef,277 0xdeadbeef,278 vec![278 vec![279 (279 (280 "Test URI 0".to_string(),280 "Test URI 0".to_string(),281 bytes(vec![281 Bytes(vec![282 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,282 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,283 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,283 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,284 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,284 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,287 ),287 ),288 (288 (289 "Test URI 1".to_string(),289 "Test URI 1".to_string(),290 bytes(vec![290 Bytes(vec![291 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,291 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,292 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,292 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,293 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,293 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,294 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,294 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,295 ]),295 ]),296 ),296 ),297 ("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),297 ("Test URI 2".to_string(), Bytes(vec![0x33, 0x33])),298 ],298 ],299 &hex!(299 &hex!(300 "300 "337// #[ignore = "reason"]337// #[ignore = "reason"]338fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {338fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {339 let int = 0xff;339 let int = 0xff;340 let by = bytes(vec![0x11, 0x22, 0x33]);340 let by = Bytes(vec![0x11, 0x22, 0x33]);341 let string = "some string".to_string();341 let string = "some string".to_string();342342343 test_impl::<((u8,), (String, bytes), (u8, bytes))>(343 test_impl::<((u8,), (String, Bytes), (u8, Bytes))>(344 0xdeadbeef,344 0xdeadbeef,345 ((int,), (string.clone(), by.clone()), (int, by)),345 ((int,), (string.clone(), by.clone()), (int, by)),346 &hex!(346 &hex!(485485486#[test]486#[test]487fn encode_decode_tuple0_tuple1_string_bytes() {487fn encode_decode_tuple0_tuple1_string_bytes() {488 test_impl::<((String, bytes),)>(488 test_impl::<((String, Bytes),)>(489 0xdeadbeef,489 0xdeadbeef,490 (("some string".to_string(), bytes(vec![1, 2, 3])),),490 (("some string".to_string(), Bytes(vec![1, 2, 3])),),491 &hex!(491 &hex!(492 "492 "493 deadbeef493 deadbeefcrates/evm-coder/src/events.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 ethereum::Log;17use ethereum::Log;18use primitive_types::{H160, H256};18use primitive_types::{H160, H256, U256};191920use crate::types::*;20use crate::types::*;212145 }45 }46}46}474748impl ToTopic for uint256 {48impl ToTopic for U256 {49 fn to_topic(&self) -> H256 {49 fn to_topic(&self) -> H256 {50 let mut out = [0u8; 32];50 let mut out = [0u8; 32];51 self.to_big_endian(&mut out);51 self.to_big_endian(&mut out);52 H256(out)52 H256(out)53 }53 }54}54}555556impl ToTopic for address {56impl ToTopic for Address {57 fn to_topic(&self) -> H256 {57 fn to_topic(&self) -> H256 {58 let mut out = [0u8; 32];58 let mut out = [0u8; 32];59 out[12..32].copy_from_slice(&self.0);59 out[12..32].copy_from_slice(&self.0);60 H256(out)60 H256(out)61 }61 }62}62}636364impl ToTopic for uint32 {64impl ToTopic for u32 {65 fn to_topic(&self) -> H256 {65 fn to_topic(&self) -> H256 {66 let mut out = [0u8; 32];66 let mut out = [0u8; 32];67 out[28..32].copy_from_slice(&self.to_be_bytes());67 out[28..32].copy_from_slice(&self.to_be_bytes());crates/evm-coder/src/lib.rsdiffbeforeafterboth131 use alloc::{vec::Vec};131 use alloc::{vec::Vec};132 use primitive_types::{U256, H160, H256};132 use primitive_types::{U256, H160, H256};133133134 pub type address = H160;134 pub type Address = H160;135 pub type uint8 = u8;136 pub type uint16 = u16;137 pub type uint32 = u32;138 pub type uint64 = u64;139 pub type uint128 = u128;140 pub type uint256 = U256;141 pub type bytes4 = [u8; 4];135 pub type Bytes4 = [u8; 4];142 pub type topic = H256;136 pub type Topic = H256;143137144 #[cfg(not(feature = "std"))]138 #[cfg(not(feature = "std"))]145 pub type string = ::alloc::string::String;139 pub type String = ::alloc::string::String;146 #[cfg(feature = "std")]140 #[cfg(feature = "std")]147 pub type string = ::std::string::String;141 pub type String = ::std::string::String;148142149 #[derive(Default, Debug, PartialEq, Eq, Clone)]143 #[derive(Default, Debug, PartialEq, Eq, Clone)]150 pub struct bytes(pub Vec<u8>);144 pub struct Bytes(pub Vec<u8>);151152 /// Solidity doesn't have `void` type, however we have special implementation153 /// for empty tuple return type154 pub type void = ();155145156 //#region Special types146 //#region Special types157 /// Makes function payable147 /// Makes function payable158 pub type value = U256;148 pub type Value = U256;159 /// Makes function caller-sensitive149 /// Makes function caller-sensitive160 pub type caller = address;150 pub type Caller = Address;161 //#endregion151 //#endregion162152163 /// Ethereum typed call message, similar to solidity153 /// Ethereum typed call message, similar to solidity172 pub value: U256,162 pub value: U256,173 }163 }174164175 impl From<Vec<u8>> for bytes {165 impl From<Vec<u8>> for Bytes {176 fn from(src: Vec<u8>) -> Self {166 fn from(src: Vec<u8>) -> Self {177 Self(src)167 Self(src)178 }168 }179 }169 }180170181 #[allow(clippy::from_over_into)]171 #[allow(clippy::from_over_into)]182 impl Into<Vec<u8>> for bytes {172 impl Into<Vec<u8>> for Bytes {183 fn into(self) -> Vec<u8> {173 fn into(self) -> Vec<u8> {184 self.0174 self.0185 }175 }186 }176 }187177188 impl bytes {178 impl Bytes {189 #[must_use]179 #[must_use]190 pub fn len(&self) -> usize {180 pub fn len(&self) -> usize {191 self.0.len()181 self.0.len()201/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro191/// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro202pub trait Call: Sized {192pub trait Call: Sized {203 /// Parse call buffer into typed call enum193 /// Parse call buffer into typed call enum204 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;194 fn parse(selector: types::Bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;205}195}206196207/// Intended to be used as `#[weight]` output type197/// Intended to be used as `#[weight]` output type237 /// implements specified interface227 /// implements specified interface238 SupportsInterface {228 SupportsInterface {239 /// Requested interface229 /// Requested interface240 interface_id: types::bytes4,230 interface_id: types::Bytes4,241 },231 },242}232}243233244impl ERC165Call {234impl ERC165Call {245 /// ERC165 selector is provided by standard235 /// ERC165 selector is provided by standard246 pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);236 pub const INTERFACE_ID: types::Bytes4 = u32::to_be_bytes(0x01ffc9a7);247}237}248238249impl Call for ERC165Call {239impl Call for ERC165Call {250 fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {240 fn parse(selector: types::Bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {251 if selector != Self::INTERFACE_ID {241 if selector != Self::INTERFACE_ID {252 return Ok(None);242 return Ok(None);253 }243 }254 Ok(Some(Self::SupportsInterface {244 Ok(Some(Self::SupportsInterface {255 interface_id: types::bytes4::abi_read(input)?,245 interface_id: types::Bytes4::abi_read(input)?,256 }))246 }))257 }247 }258}248}crates/evm-coder/src/solidity/impls.rsdiffbeforeafterboth27 u64 => "uint64" true = "0",27 u64 => "uint64" true = "0",28 u128 => "uint128" true = "0",28 u128 => "uint128" true = "0",29 U256 => "uint256" true = "0",29 U256 => "uint256" true = "0",30 bytes4 => "bytes4" true = "bytes4(0)",30 Bytes4 => "bytes4" true = "bytes4(0)",31 H160 => "address" true = "0x0000000000000000000000000000000000000000",31 H160 => "address" true = "0x0000000000000000000000000000000000000000",32 string => "string" false = "\"\"",32 String => "string" false = "\"\"",33 bytes => "bytes" false = "hex\"\"",33 Bytes => "bytes" false = "hex\"\"",34 bool => "bool" true = "false",34 bool => "bool" true = "false",35}35}363637impl SolidityTypeName for void {37impl SolidityTypeName for () {38 fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {38 fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {39 Ok(())39 Ok(())40 }40 }72macro_rules! impl_tuples {72macro_rules! impl_tuples {73 ($($ident:ident)+) => {73 ($($ident:ident)+) => {74 impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleTy for ($($ident,)+) {74 impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleTy for ($($ident,)+) {75 fn fields(tc: &TypeCollector) -> Vec<string> {75 fn fields(tc: &TypeCollector) -> Vec<String> {76 let mut collected = Vec::with_capacity(Self::len());76 let mut collected = Vec::with_capacity(Self::len());77 $({77 $({78 let mut out = string::new();78 let mut out = String::new();79 $ident::solidity_name(&mut out, tc).expect("no fmt error");79 $ident::solidity_name(&mut out, tc).expect("no fmt error");80 collected.push(out);80 collected.push(out);81 })*;81 })*;crates/evm-coder/src/solidity/mod.rsdiffbeforeafterboth26mod impls;26mod impls;272728#[cfg(not(feature = "std"))]28#[cfg(not(feature = "std"))]29use alloc::{string::String, vec::Vec, collections::BTreeMap, format};29use alloc::{vec::Vec, collections::BTreeMap, format};30#[cfg(feature = "std")]30#[cfg(feature = "std")]31use std::collections::BTreeMap;31use std::collections::BTreeMap;32use core::{32use core::{42pub struct TypeCollector {42pub struct TypeCollector {43 /// Code => id43 /// Code => id44 /// id ordering is required to perform topo-sort on the resulting data44 /// id ordering is required to perform topo-sort on the resulting data45 structs: RefCell<BTreeMap<string, usize>>,45 structs: RefCell<BTreeMap<String, usize>>,46 anonymous: RefCell<BTreeMap<Vec<string>, usize>>,46 anonymous: RefCell<BTreeMap<Vec<String>, usize>>,47 // generic: RefCell<BTreeMap<string, usize>>,47 // generic: RefCell<BTreeMap<String, usize>>,48 id: Cell<usize>,48 id: Cell<usize>,49}49}50impl TypeCollector {50impl TypeCollector {51 pub fn new() -> Self {51 pub fn new() -> Self {52 Self::default()52 Self::default()53 }53 }54 pub fn collect(&self, item: string) {54 pub fn collect(&self, item: String) {55 let id = self.next_id();55 let id = self.next_id();56 self.structs.borrow_mut().insert(item, id);56 self.structs.borrow_mut().insert(item, id);57 }57 }84 pub fn collect_enum<T: SolidityEnumTy>(&self) -> String {84 pub fn collect_enum<T: SolidityEnumTy>(&self) -> String {85 T::generate_solidity_interface(self)85 T::generate_solidity_interface(self)86 }86 }87 pub fn finish(self) -> Vec<string> {87 pub fn finish(self) -> Vec<String> {88 let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();88 let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();89 data.sort_by_key(|(_, id)| Reverse(*id));89 data.sort_by_key(|(_, id)| Reverse(*id));90 data.into_iter().map(|(code, _)| code).collect()90 data.into_iter().map(|(code, _)| code).collect()360360361pub struct SolidityInterface<F: SolidityFunctions> {361pub struct SolidityInterface<F: SolidityFunctions> {362 pub docs: &'static [&'static str],362 pub docs: &'static [&'static str],363 pub selector: bytes4,363 pub selector: Bytes4,364 pub name: &'static str,364 pub name: &'static str,365 pub is: &'static [&'static str],365 pub is: &'static [&'static str],366 pub functions: F,366 pub functions: F,crates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth1mod test_struct {1mod test_struct {2 use evm_coder_procedural::AbiCoder;2 use evm_coder_procedural::AbiCoder;3 use evm_coder::types::bytes;3 use evm_coder::types::Bytes;445 #[test]5 #[test]6 fn empty_struct() {6 fn empty_struct() {27 #[derive(AbiCoder, PartialEq, Debug)]27 #[derive(AbiCoder, PartialEq, Debug)]28 struct TypeStruct2DynamicParam {28 struct TypeStruct2DynamicParam {29 _a: String,29 _a: String,30 _b: bytes,30 _b: Bytes,31 }31 }323233 #[derive(AbiCoder, PartialEq, Debug)]33 #[derive(AbiCoder, PartialEq, Debug)]34 struct TypeStruct2MixedParam {34 struct TypeStruct2MixedParam {35 _a: u8,35 _a: u8,36 _b: bytes,36 _b: Bytes,37 }37 }383839 #[derive(AbiCoder, PartialEq, Debug)]39 #[derive(AbiCoder, PartialEq, Debug)]236 struct TupleStruct2SimpleParam(u8, u32);236 struct TupleStruct2SimpleParam(u8, u32);237237238 #[derive(AbiCoder, PartialEq, Debug)]238 #[derive(AbiCoder, PartialEq, Debug)]239 struct TupleStruct2DynamicParam(String, bytes);239 struct TupleStruct2DynamicParam(String, Bytes);240240241 #[derive(AbiCoder, PartialEq, Debug)]241 #[derive(AbiCoder, PartialEq, Debug)]242 struct TupleStruct2MixedParam(u8, bytes);242 struct TupleStruct2MixedParam(u8, Bytes);243243244 #[derive(AbiCoder, PartialEq, Debug)]244 #[derive(AbiCoder, PartialEq, Debug)]245 struct TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam);245 struct TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam);562 #[test]562 #[test]563 fn codec_struct_2_dynamic() {563 fn codec_struct_2_dynamic() {564 let _a: String = "some string".into();564 let _a: String = "some string".into();565 let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);565 let _b: Bytes = Bytes(vec![0x11, 0x22, 0x33]);566 test_impl::<(String, bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(566 test_impl::<(String, Bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(567 (_a.clone(), _b.clone()),567 (_a.clone(), _b.clone()),568 TupleStruct2DynamicParam(_a.clone(), _b.clone()),568 TupleStruct2DynamicParam(_a.clone(), _b.clone()),569 TypeStruct2DynamicParam { _a, _b },569 TypeStruct2DynamicParam { _a, _b },573 #[test]573 #[test]574 fn codec_struct_2_mixed() {574 fn codec_struct_2_mixed() {575 let _a: u8 = 0xff;575 let _a: u8 = 0xff;576 let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);576 let _b: Bytes = Bytes(vec![0x11, 0x22, 0x33]);577 test_impl::<(u8, bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(577 test_impl::<(u8, Bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(578 (_a.clone(), _b.clone()),578 (_a.clone(), _b.clone()),579 TupleStruct2MixedParam(_a.clone(), _b.clone()),579 TupleStruct2MixedParam(_a.clone(), _b.clone()),580 TypeStruct2MixedParam { _a, _b },580 TypeStruct2MixedParam { _a, _b },605 #[test]605 #[test]606 fn codec_struct_2_derived_dynamic() {606 fn codec_struct_2_derived_dynamic() {607 let _a = "some string".to_string();607 let _a = "some string".to_string();608 let _b = bytes(vec![0x11, 0x22, 0x33]);608 let _b = Bytes(vec![0x11, 0x22, 0x33]);609 test_impl::<609 test_impl::<610 ((String,), (String, bytes)),610 ((String,), (String, Bytes)),611 TupleStruct2DerivedDynamicParam,611 TupleStruct2DerivedDynamicParam,612 TypeStruct2DerivedDynamicParam,612 TypeStruct2DerivedDynamicParam,613 >(613 >(626 #[test]626 #[test]627 fn codec_struct_3_derived_mixed() {627 fn codec_struct_3_derived_mixed() {628 let int = 0xff;628 let int = 0xff;629 let by = bytes(vec![0x11, 0x22, 0x33]);629 let by = Bytes(vec![0x11, 0x22, 0x33]);630 let string = "some string".to_string();630 let string = "some string".to_string();631 test_impl::<631 test_impl::<632 ((u8,), (String, bytes), (u8, bytes)),632 ((u8,), (String, Bytes), (u8, Bytes)),633 TupleStruct3DerivedMixedParam,633 TupleStruct3DerivedMixedParam,634 TypeStruct3DerivedMixedParam,634 TypeStruct3DerivedMixedParam,635 >(635 >(crates/evm-coder/tests/conditional_is.rsdiffbeforeafterboth445#[solidity_interface(name = A)]5#[solidity_interface(name = A)]6impl Contract {6impl Contract {7 fn method_a() -> Result<void> {7 fn method_a() -> Result<()> {8 Ok(())8 Ok(())9 }9 }10}10}111112#[solidity_interface(name = B)]12#[solidity_interface(name = B)]13impl Contract {13impl Contract {14 fn method_b() -> Result<void> {14 fn method_b() -> Result<()> {15 Ok(())15 Ok(())16 }16 }17}17}crates/evm-coder/tests/generics.rsdiffbeforeafterboth161617use std::marker::PhantomData;17use std::marker::PhantomData;18use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};18use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};19use primitive_types::U256;192020pub struct Generic<T>(PhantomData<T>);21pub struct Generic<T>(PhantomData<T>);212222#[solidity_interface(name = GenericIs)]23#[solidity_interface(name = GenericIs)]23impl<T> Generic<T> {24impl<T> Generic<T> {24 fn test_1(&self) -> Result<uint256> {25 fn test_1(&self) -> Result<U256> {25 unreachable!()26 unreachable!()26 }27 }27}28}282929#[solidity_interface(name = Generic, is(GenericIs))]30#[solidity_interface(name = Generic, is(GenericIs))]30impl<T: Into<u32>> Generic<T> {31impl<T: Into<u32>> Generic<T> {31 fn test_2(&self) -> Result<uint256> {32 fn test_2(&self) -> Result<U256> {32 unreachable!()33 unreachable!()33 }34 }34}35}40where41where41 T: core::fmt::Debug,42 T: core::fmt::Debug,42{43{43 fn test_3(&self) -> Result<uint256> {44 fn test_3(&self) -> Result<U256> {44 unreachable!()45 unreachable!()45 }46 }46}47}crates/evm-coder/tests/log.rsdiffbeforeafterboth17#![allow(dead_code)]17#![allow(dead_code)]181819use evm_coder::{ToLog, types::*};19use evm_coder::{ToLog, types::*};20use primitive_types::U256;202121#[derive(ToLog)]22#[derive(ToLog)]22enum ERC721Log {23enum ERC721Log {23 Transfer {24 Transfer {24 #[indexed]25 #[indexed]25 from: address,26 from: Address,26 #[indexed]27 #[indexed]27 to: address,28 to: Address,28 value: uint256,29 value: U256,29 },30 },30 Eee {31 Eee {31 #[indexed]32 #[indexed]32 aaa: address,33 aaa: Address,33 bbb: uint256,34 bbb: U256,34 },35 },35}36}3637crates/evm-coder/tests/random.rsdiffbeforeafterboth19use evm_coder::{19use evm_coder::{20 abi::AbiType, ToLog, execution::Result, solidity_interface, types::*, solidity, weight,20 abi::AbiType, ToLog, execution::Result, solidity_interface, types::*, solidity, weight,21};21};22use primitive_types::U256;222323pub struct Impls;24pub struct Impls;242525#[solidity_interface(name = OurInterface)]26#[solidity_interface(name = OurInterface)]26impl Impls {27impl Impls {27 fn fn_a(&self, _input: uint256) -> Result<bool> {28 fn fn_a(&self, _input: U256) -> Result<bool> {28 unreachable!()29 unreachable!()29 }30 }30}31}313232#[solidity_interface(name = OurInterface1)]33#[solidity_interface(name = OurInterface1)]33impl Impls {34impl Impls {34 fn fn_b(&self, _input: uint128) -> Result<uint32> {35 fn fn_b(&self, _input: u128) -> Result<u32> {35 unreachable!()36 unreachable!()36 }37 }37}38}383939#[derive(ToLog)]40#[derive(ToLog)]40enum OurEvents {41enum OurEvents {41 Event1 {42 Event1 {42 field1: uint32,43 field1: u32,43 },44 },44 Event2 {45 Event2 {45 field1: uint32,46 field1: u32,46 #[indexed]47 #[indexed]47 field2: uint32,48 field2: u32,48 },49 },49}50}505156)]57)]57impl Impls {58impl Impls {58 #[solidity(rename_selector = "fnK")]59 #[solidity(rename_selector = "fnK")]59 fn fn_c(&self, _input: uint32) -> Result<uint8> {60 fn fn_c(&self, _input: u32) -> Result<u8> {60 unreachable!()61 unreachable!()61 }62 }62 fn fn_d(&self, _value: uint32) -> Result<uint32> {63 fn fn_d(&self, _value: u32) -> Result<u32> {63 unreachable!()64 unreachable!()64 }65 }656666 fn caller_sensitive(&self, _caller: caller) -> Result<uint8> {67 fn caller_sensitive(&self, _caller: Caller) -> Result<u8> {67 unreachable!()68 unreachable!()68 }69 }69 fn payable(&mut self, _value: value) -> Result<uint8> {70 fn payable(&mut self, _value: Value) -> Result<u8> {70 unreachable!()71 unreachable!()71 }72 }727373 #[weight(*_weight)]74 #[weight(*_weight)]74 fn with_weight(&self, _weight: uint64) -> Result<void> {75 fn with_weight(&self, _weight: u64) -> Result<()> {75 unreachable!()76 unreachable!()76 }77 }777878 /// Doccoment example79 /// Doccoment example79 fn with_doc(&self) -> Result<void> {80 fn with_doc(&self) -> Result<()> {80 unreachable!()81 unreachable!()81 }82 }82}83}crates/evm-coder/tests/solidity_generation.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 evm_coder::{abi::AbiType, execution::Result, generate_stubgen, solidity_interface, types::*};17use evm_coder::{abi::AbiType, execution::Result, generate_stubgen, solidity_interface, types::*};18use primitive_types::U256;181919pub struct ERC20;20pub struct ERC20;202121#[solidity_interface(name = ERC20)]22#[solidity_interface(name = ERC20)]22impl ERC20 {23impl ERC20 {23 fn decimals(&self) -> Result<uint8> {24 fn decimals(&self) -> Result<u8> {24 unreachable!()25 unreachable!()25 }26 }26 /// Get balance of specified owner27 /// Get balance of specified owner27 fn balance_of(&self, _owner: address) -> Result<uint256> {28 fn balance_of(&self, _owner: Address) -> Result<U256> {28 unreachable!()29 unreachable!()29 }30 }30 fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result<bool> {31 fn transfer(&mut self, _caller: Caller, _to: Address, _value: U256) -> Result<bool> {31 unreachable!()32 unreachable!()32 }33 }33 fn transfer_from(34 fn transfer_from(34 &mut self,35 &mut self,35 _caller: caller,36 _caller: Caller,36 _from: address,37 _from: Address,37 _to: address,38 _to: Address,38 _value: uint256,39 _value: U256,39 ) -> Result<bool> {40 ) -> Result<bool> {40 unreachable!()41 unreachable!()41 }42 }42 fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result<bool> {43 fn approve(&mut self, _caller: Caller, _spender: Address, _value: U256) -> Result<bool> {43 unreachable!()44 unreachable!()44 }45 }45 fn allowance(&self, _owner: address, _spender: address) -> Result<uint256> {46 fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {46 unreachable!()47 unreachable!()47 }48 }48}49}pallets/common/src/erc.rsdiffbeforeafterboth26};26};27use pallet_evm_coder_substrate::dispatch_to_evm;27use pallet_evm_coder_substrate::dispatch_to_evm;28use sp_std::{vec, vec::Vec};28use sp_std::{vec, vec::Vec};29use sp_core::U256;29use up_data_structs::{30use up_data_structs::{30 AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,31 AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,31 SponsoringRateLimit, SponsorshipState,32 SponsoringRateLimit, SponsorshipState,42 CollectionCreated {43 CollectionCreated {43 /// Collection owner.44 /// Collection owner.44 #[indexed]45 #[indexed]45 owner: address,46 owner: Address,464747 /// Collection ID.48 /// Collection ID.48 #[indexed]49 #[indexed]49 collection_id: address,50 collection_id: Address,50 },51 },51 /// The collection has been destroyed.52 /// The collection has been destroyed.52 CollectionDestroyed {53 CollectionDestroyed {53 /// Collection ID.54 /// Collection ID.54 #[indexed]55 #[indexed]55 collection_id: address,56 collection_id: Address,56 },57 },57 /// The collection has been changed.58 /// The collection has been changed.58 CollectionChanged {59 CollectionChanged {59 /// Collection ID.60 /// Collection ID.60 #[indexed]61 #[indexed]61 collection_id: address,62 collection_id: Address,62 },63 },636464 /// The token has been changed.65 /// The token has been changed.65 TokenChanged {66 TokenChanged {66 /// Collection ID.67 /// Collection ID.67 #[indexed]68 #[indexed]68 collection_id: address,69 collection_id: Address,69 /// Token ID.70 /// Token ID.70 token_id: uint256,71 token_id: U256,71 },72 },72}73}737493 /// @param value Propery value.94 /// @param value Propery value.94 #[solidity(hide)]95 #[solidity(hide)]95 #[weight(<SelfWeightOf<T>>::set_collection_properties(1))]96 #[weight(<SelfWeightOf<T>>::set_collection_properties(1))]96 fn set_collection_property(97 fn set_collection_property(&mut self, caller: Caller, key: String, value: Bytes) -> Result<()> {97 &mut self,98 caller: caller,99 key: string,100 value: bytes,101 ) -> Result<void> {102 let caller = T::CrossAccountId::from_eth(caller);98 let caller = T::CrossAccountId::from_eth(caller);103 let key = <Vec<u8>>::from(key)99 let key = <Vec<u8>>::from(key)104 .try_into()100 .try_into()115 #[weight(<SelfWeightOf<T>>::set_collection_properties(properties.len() as u32))]111 #[weight(<SelfWeightOf<T>>::set_collection_properties(properties.len() as u32))]116 fn set_collection_properties(112 fn set_collection_properties(117 &mut self,113 &mut self,118 caller: caller,114 caller: Caller,119 properties: Vec<eth::Property>,115 properties: Vec<eth::Property>,120 ) -> Result<void> {116 ) -> Result<()> {121 let caller = T::CrossAccountId::from_eth(caller);117 let caller = T::CrossAccountId::from_eth(caller);122118123 let properties = properties119 let properties = properties134 /// @param key Property key.130 /// @param key Property key.135 #[solidity(hide)]131 #[solidity(hide)]136 #[weight(<SelfWeightOf<T>>::delete_collection_properties(1))]132 #[weight(<SelfWeightOf<T>>::delete_collection_properties(1))]137 fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {133 fn delete_collection_property(&mut self, caller: Caller, key: String) -> Result<()> {138 let caller = T::CrossAccountId::from_eth(caller);134 let caller = T::CrossAccountId::from_eth(caller);139 let key = <Vec<u8>>::from(key)135 let key = <Vec<u8>>::from(key)140 .try_into()136 .try_into()147 ///143 ///148 /// @param keys Properties keys.144 /// @param keys Properties keys.149 #[weight(<SelfWeightOf<T>>::delete_collection_properties(keys.len() as u32))]145 #[weight(<SelfWeightOf<T>>::delete_collection_properties(keys.len() as u32))]150 fn delete_collection_properties(&mut self, caller: caller, keys: Vec<string>) -> Result<()> {146 fn delete_collection_properties(&mut self, caller: Caller, keys: Vec<String>) -> Result<()> {151 let caller = T::CrossAccountId::from_eth(caller);147 let caller = T::CrossAccountId::from_eth(caller);152 let keys = keys148 let keys = keys153 .into_iter()149 .into_iter()168 ///164 ///169 /// @param key Property key.165 /// @param key Property key.170 /// @return bytes The property corresponding to the key.166 /// @return bytes The property corresponding to the key.171 fn collection_property(&self, key: string) -> Result<bytes> {167 fn collection_property(&self, key: String) -> Result<Bytes> {172 let key = <Vec<u8>>::from(key)168 let key = <Vec<u8>>::from(key)173 .try_into()169 .try_into()174 .map_err(|_| "key too large")?;170 .map_err(|_| "key too large")?;175171176 let props = CollectionProperties::<T>::get(self.id);172 let props = CollectionProperties::<T>::get(self.id);177 let prop = props.get(&key).ok_or("key not found")?;173 let prop = props.get(&key).ok_or("key not found")?;178174179 Ok(bytes(prop.to_vec()))175 Ok(Bytes(prop.to_vec()))180 }176 }181177182 /// Get collection properties.178 /// Get collection properties.183 ///179 ///184 /// @param keys Properties keys. Empty keys for all propertyes.180 /// @param keys Properties keys. Empty keys for all propertyes.185 /// @return Vector of properties key/value pairs.181 /// @return Vector of properties key/value pairs.186 fn collection_properties(&self, keys: Vec<string>) -> Result<Vec<eth::Property>> {182 fn collection_properties(&self, keys: Vec<String>) -> Result<Vec<eth::Property>> {187 let keys = keys183 let keys = keys188 .into_iter()184 .into_iter()189 .map(|key| {185 .map(|key| {212 ///208 ///213 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.209 /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.214 #[solidity(hide)]210 #[solidity(hide)]215 fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {211 fn set_collection_sponsor(&mut self, caller: Caller, sponsor: Address) -> Result<()> {216 self.consume_store_reads_and_writes(1, 1)?;212 self.consume_store_reads_and_writes(1, 1)?;217213218 let caller = T::CrossAccountId::from_eth(caller);214 let caller = T::CrossAccountId::from_eth(caller);229 /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.225 /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.230 fn set_collection_sponsor_cross(226 fn set_collection_sponsor_cross(231 &mut self,227 &mut self,232 caller: caller,228 caller: Caller,233 sponsor: eth::CrossAddress,229 sponsor: eth::CrossAddress,234 ) -> Result<void> {230 ) -> Result<()> {235 self.consume_store_reads_and_writes(1, 1)?;231 self.consume_store_reads_and_writes(1, 1)?;236232237 let caller = T::CrossAccountId::from_eth(caller);233 let caller = T::CrossAccountId::from_eth(caller);252 /// Collection sponsorship confirmation.248 /// Collection sponsorship confirmation.253 ///249 ///254 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.250 /// @dev After setting the sponsor for the collection, it must be confirmed with this function.255 fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {251 fn confirm_collection_sponsorship(&mut self, caller: Caller) -> Result<()> {256 self.consume_store_writes(1)?;252 self.consume_store_writes(1)?;257253258 let caller = T::CrossAccountId::from_eth(caller);254 let caller = T::CrossAccountId::from_eth(caller);261 }257 }262258263 /// Remove collection sponsor.259 /// Remove collection sponsor.264 fn remove_collection_sponsor(&mut self, caller: caller) -> Result<void> {260 fn remove_collection_sponsor(&mut self, caller: Caller) -> Result<()> {265 self.consume_store_reads_and_writes(1, 1)?;261 self.consume_store_reads_and_writes(1, 1)?;266 let caller = T::CrossAccountId::from_eth(caller);262 let caller = T::CrossAccountId::from_eth(caller);267 self.remove_sponsor(&caller).map_err(dispatch_to_evm::<T>)263 self.remove_sponsor(&caller).map_err(dispatch_to_evm::<T>)343 /// @dev Throws error if limit not found.339 /// @dev Throws error if limit not found.344 /// @param limit Some limit.340 /// @param limit Some limit.345 #[solidity(rename_selector = "setCollectionLimit")]341 #[solidity(rename_selector = "setCollectionLimit")]346 fn set_collection_limit(342 fn set_collection_limit(&mut self, caller: Caller, limit: eth::CollectionLimit) -> Result<()> {347 &mut self,348 caller: caller,349 limit: eth::CollectionLimit,350 ) -> Result<void> {351 self.consume_store_reads_and_writes(1, 1)?;343 self.consume_store_reads_and_writes(1, 1)?;352344353 if !limit.has_value() {345 if !limit.has_value() {359 }351 }360352361 /// Get contract address.353 /// Get contract address.362 fn contract_address(&self) -> Result<address> {354 fn contract_address(&self) -> Result<Address> {363 Ok(crate::eth::collection_id_to_address(self.id))355 Ok(crate::eth::collection_id_to_address(self.id))364 }356 }365357366 /// Add collection admin.358 /// Add collection admin.367 /// @param newAdmin Cross account administrator address.359 /// @param newAdmin Cross account administrator address.368 fn add_collection_admin_cross(360 fn add_collection_admin_cross(369 &mut self,361 &mut self,370 caller: caller,362 caller: Caller,371 new_admin: eth::CrossAddress,363 new_admin: eth::CrossAddress,372 ) -> Result<void> {364 ) -> Result<()> {373 self.consume_store_reads_and_writes(2, 2)?;365 self.consume_store_reads_and_writes(2, 2)?;374366375 let caller = T::CrossAccountId::from_eth(caller);367 let caller = T::CrossAccountId::from_eth(caller);382 /// @param admin Cross account administrator address.374 /// @param admin Cross account administrator address.383 fn remove_collection_admin_cross(375 fn remove_collection_admin_cross(384 &mut self,376 &mut self,385 caller: caller,377 caller: Caller,386 admin: eth::CrossAddress,378 admin: eth::CrossAddress,387 ) -> Result<void> {379 ) -> Result<()> {388 self.consume_store_reads_and_writes(2, 2)?;380 self.consume_store_reads_and_writes(2, 2)?;389381390 let caller = T::CrossAccountId::from_eth(caller);382 let caller = T::CrossAccountId::from_eth(caller);396 /// Add collection admin.388 /// Add collection admin.397 /// @param newAdmin Address of the added administrator.389 /// @param newAdmin Address of the added administrator.398 #[solidity(hide)]390 #[solidity(hide)]399 fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result<void> {391 fn add_collection_admin(&mut self, caller: Caller, new_admin: Address) -> Result<()> {400 self.consume_store_reads_and_writes(2, 2)?;392 self.consume_store_reads_and_writes(2, 2)?;401393402 let caller = T::CrossAccountId::from_eth(caller);394 let caller = T::CrossAccountId::from_eth(caller);409 ///401 ///410 /// @param admin Address of the removed administrator.402 /// @param admin Address of the removed administrator.411 #[solidity(hide)]403 #[solidity(hide)]412 fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result<void> {404 fn remove_collection_admin(&mut self, caller: Caller, admin: Address) -> Result<()> {413 self.consume_store_reads_and_writes(2, 2)?;405 self.consume_store_reads_and_writes(2, 2)?;414406415 let caller = T::CrossAccountId::from_eth(caller);407 let caller = T::CrossAccountId::from_eth(caller);422 ///414 ///423 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'415 /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'424 #[solidity(rename_selector = "setCollectionNesting")]416 #[solidity(rename_selector = "setCollectionNesting")]425 fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {417 fn set_nesting_bool(&mut self, caller: Caller, enable: bool) -> Result<()> {426 self.consume_store_reads_and_writes(1, 1)?;418 self.consume_store_reads_and_writes(1, 1)?;427419428 let caller = T::CrossAccountId::from_eth(caller);420 let caller = T::CrossAccountId::from_eth(caller);443 #[solidity(rename_selector = "setCollectionNesting")]435 #[solidity(rename_selector = "setCollectionNesting")]444 fn set_nesting(436 fn set_nesting(445 &mut self,437 &mut self,446 caller: caller,438 caller: Caller,447 enable: bool,439 enable: bool,448 collections: Vec<address>,440 collections: Vec<Address>,449 ) -> Result<void> {441 ) -> Result<()> {450 self.consume_store_reads_and_writes(1, 1)?;442 self.consume_store_reads_and_writes(1, 1)?;451443452 if collections.is_empty() {444 if collections.is_empty() {511 }503 }512 /// Set the collection access method.504 /// Set the collection access method.513 /// @param mode Access mode505 /// @param mode Access mode514 /// 0 for Normal515 /// 1 for AllowList516 fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {506 fn set_collection_access(&mut self, caller: Caller, mode: eth::AccessMode) -> Result<()> {517 self.consume_store_reads_and_writes(1, 1)?;507 self.consume_store_reads_and_writes(1, 1)?;518508519 let caller = T::CrossAccountId::from_eth(caller);509 let caller = T::CrossAccountId::from_eth(caller);520 let permissions = CollectionPermissions {510 let permissions = CollectionPermissions {521 access: Some(match mode {511 access: Some(mode.into()),522 0 => AccessMode::Normal,523 1 => AccessMode::AllowList,524 _ => return Err("not supported access mode".into()),525 }),526 ..Default::default()512 ..Default::default()527 };513 };528 <Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)514 <Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)540 ///526 ///541 /// @param user Address of a trusted user.527 /// @param user Address of a trusted user.542 #[solidity(hide)]528 #[solidity(hide)]543 fn add_to_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {529 fn add_to_collection_allow_list(&mut self, caller: Caller, user: Address) -> Result<()> {544 self.consume_store_writes(1)?;530 self.consume_store_writes(1)?;545531546 let caller = T::CrossAccountId::from_eth(caller);532 let caller = T::CrossAccountId::from_eth(caller);554 /// @param user User cross account address.540 /// @param user User cross account address.555 fn add_to_collection_allow_list_cross(541 fn add_to_collection_allow_list_cross(556 &mut self,542 &mut self,557 caller: caller,543 caller: Caller,558 user: eth::CrossAddress,544 user: eth::CrossAddress,559 ) -> Result<void> {545 ) -> Result<()> {560 self.consume_store_writes(1)?;546 self.consume_store_writes(1)?;561547562 let caller = T::CrossAccountId::from_eth(caller);548 let caller = T::CrossAccountId::from_eth(caller);569 ///555 ///570 /// @param user Address of a removed user.556 /// @param user Address of a removed user.571 #[solidity(hide)]557 #[solidity(hide)]572 fn remove_from_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {558 fn remove_from_collection_allow_list(&mut self, caller: Caller, user: Address) -> Result<()> {573 self.consume_store_writes(1)?;559 self.consume_store_writes(1)?;574560575 let caller = T::CrossAccountId::from_eth(caller);561 let caller = T::CrossAccountId::from_eth(caller);583 /// @param user User cross account address.569 /// @param user User cross account address.584 fn remove_from_collection_allow_list_cross(570 fn remove_from_collection_allow_list_cross(585 &mut self,571 &mut self,586 caller: caller,572 caller: Caller,587 user: eth::CrossAddress,573 user: eth::CrossAddress,588 ) -> Result<void> {574 ) -> Result<()> {589 self.consume_store_writes(1)?;575 self.consume_store_writes(1)?;590576591 let caller = T::CrossAccountId::from_eth(caller);577 let caller = T::CrossAccountId::from_eth(caller);597 /// Switch permission for minting.583 /// Switch permission for minting.598 ///584 ///599 /// @param mode Enable if "true".585 /// @param mode Enable if "true".600 fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {586 fn set_collection_mint_mode(&mut self, caller: Caller, mode: bool) -> Result<()> {601 self.consume_store_reads_and_writes(1, 1)?;587 self.consume_store_reads_and_writes(1, 1)?;602588603 let caller = T::CrossAccountId::from_eth(caller);589 let caller = T::CrossAccountId::from_eth(caller);613 /// @param user account to verify599 /// @param user account to verify614 /// @return "true" if account is the owner or admin600 /// @return "true" if account is the owner or admin615 #[solidity(hide, rename_selector = "isOwnerOrAdmin")]601 #[solidity(hide, rename_selector = "isOwnerOrAdmin")]616 fn is_owner_or_admin_eth(&self, user: address) -> Result<bool> {602 fn is_owner_or_admin_eth(&self, user: Address) -> Result<bool> {617 let user = T::CrossAccountId::from_eth(user);603 let user = T::CrossAccountId::from_eth(user);618 Ok(self.is_owner_or_admin(&user))604 Ok(self.is_owner_or_admin(&user))619 }605 }630 /// Returns collection type616 /// Returns collection type631 ///617 ///632 /// @return `Fungible` or `NFT` or `ReFungible`618 /// @return `Fungible` or `NFT` or `ReFungible`633 fn unique_collection_type(&self) -> Result<string> {619 fn unique_collection_type(&self) -> Result<String> {634 let mode = match self.collection.mode {620 let mode = match self.collection.mode {635 CollectionMode::Fungible(_) => "Fungible",621 CollectionMode::Fungible(_) => "Fungible",636 CollectionMode::NFT => "NFT",622 CollectionMode::NFT => "NFT",654 /// @dev Owner can be changed only by current owner640 /// @dev Owner can be changed only by current owner655 /// @param newOwner new owner account641 /// @param newOwner new owner account656 #[solidity(hide, rename_selector = "changeCollectionOwner")]642 #[solidity(hide, rename_selector = "changeCollectionOwner")]657 fn set_owner(&mut self, caller: caller, new_owner: address) -> Result<void> {643 fn set_owner(&mut self, caller: Caller, new_owner: Address) -> Result<()> {658 self.consume_store_writes(1)?;644 self.consume_store_writes(1)?;659645660 let caller = T::CrossAccountId::from_eth(caller);646 let caller = T::CrossAccountId::from_eth(caller);680 /// @param newOwner new owner cross account666 /// @param newOwner new owner cross account681 fn change_collection_owner_cross(667 fn change_collection_owner_cross(682 &mut self,668 &mut self,683 caller: caller,669 caller: Caller,684 new_owner: eth::CrossAddress,670 new_owner: eth::CrossAddress,685 ) -> Result<void> {671 ) -> Result<()> {686 self.consume_store_writes(1)?;672 self.consume_store_writes(1)?;687673688 let caller = T::CrossAccountId::from_eth(caller);674 let caller = T::CrossAccountId::from_eth(caller);pallets/common/src/eth.rsdiffbeforeafterboth181819use alloc::format;19use alloc::format;20use sp_std::{vec, vec::Vec};20use sp_std::{vec, vec::Vec};21use evm_coder::{21use evm_coder::{AbiCoder, types::Address};22 AbiCoder,23 types::{uint256, address},24};25pub use pallet_evm::{Config, account::CrossAccountId};22pub use pallet_evm::{Config, account::CrossAccountId};26use sp_core::H160;23use sp_core::{H160, U256};27use up_data_structs::CollectionId;24use up_data_structs::CollectionId;282529// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 126// 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 133];30];343135/// Maps the ethereum address of the collection in substrate.32/// Maps the ethereum address of the collection in substrate.36pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {33pub fn map_eth_to_id(eth: &Address) -> Option<CollectionId> {37 if eth[0..16] != ETH_COLLECTION_PREFIX {34 if eth[0..16] != ETH_COLLECTION_PREFIX {38 return None;35 return None;39 }36 }43}40}444145/// Maps the substrate collection id in ethereum.42/// Maps the substrate collection id in ethereum.46pub fn collection_id_to_address(id: CollectionId) -> H160 {43pub fn collection_id_to_address(id: CollectionId) -> Address {47 let mut out = [0; 20];44 let mut out = [0; 20];48 out[0..16].copy_from_slice(Ð_COLLECTION_PREFIX);45 out[0..16].copy_from_slice(Ð_COLLECTION_PREFIX);49 out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));46 out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));50 H160(out)47 H160(out)51}48}524953/// Check if the ethereum address is a collection.50/// Check if the ethereum address is a collection.54pub fn is_collection(address: &H160) -> bool {51pub fn is_collection(address: &Address) -> bool {55 address[0..16] == ETH_COLLECTION_PREFIX52 address[0..16] == ETH_COLLECTION_PREFIX56}53}575458/// Convert `uint256` to `CrossAccountId`.55/// Convert `U256` to `CrossAccountId`.59pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId56pub fn convert_uint256_to_cross_account<T: Config>(from: U256) -> T::CrossAccountId60where57where61 T::AccountId: From<[u8; 32]>,58 T::AccountId: From<[u8; 32]>,62{59{69/// Cross account struct66/// Cross account struct70#[derive(Debug, Default, AbiCoder)]67#[derive(Debug, Default, AbiCoder)]71pub struct CrossAddress {68pub struct CrossAddress {72 pub(crate) eth: address,69 pub(crate) eth: Address,73 pub(crate) sub: uint256,70 pub(crate) sub: U256,74}71}757276impl CrossAddress {73impl CrossAddress {97 {94 {98 Self {95 Self {99 eth: Default::default(),96 eth: Default::default(),100 sub: uint256::from_big_endian(account_id.as_ref()),97 sub: U256::from_big_endian(account_id.as_ref()),101 }98 }102 }99 }103 /// Converts [`CrossAddress`] to `CrossAccountId`.100 /// Converts [`CrossAddress`] to `CrossAccountId`.121/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).118/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).122#[derive(Debug, Default, AbiCoder)]119#[derive(Debug, Default, AbiCoder)]123pub struct Property {120pub struct Property {124 key: evm_coder::types::string,121 key: evm_coder::types::String,125 value: evm_coder::types::bytes,122 value: evm_coder::types::Bytes,126}123}127124128impl TryFrom<up_data_structs::Property> for Property {125impl TryFrom<up_data_structs::Property> for Property {129 type Error = evm_coder::execution::Error;126 type Error = evm_coder::execution::Error;130127131 fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {128 fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {132 let key = evm_coder::types::string::from_utf8(from.key.into())129 let key = evm_coder::types::String::from_utf8(from.key.into())133 .map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?;130 .map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?;134 let value = evm_coder::types::bytes(from.value.to_vec());131 let value = evm_coder::types::Bytes(from.value.to_vec());135 Ok(Property { key, value })132 Ok(Property { key, value })136 }133 }137}134}187#[derive(Debug, Default, AbiCoder)]184#[derive(Debug, Default, AbiCoder)]188pub struct CollectionLimit {185pub struct CollectionLimit {189 field: CollectionLimitField,186 field: CollectionLimitField,190 value: Option<uint256>,187 value: Option<U256>,191}188}192189193impl CollectionLimit {190impl CollectionLimit {345#[derive(Debug, Default, AbiCoder)]342#[derive(Debug, Default, AbiCoder)]346pub struct TokenPropertyPermission {343pub struct TokenPropertyPermission {347 /// Token property key.344 /// Token property key.348 key: evm_coder::types::string,345 key: evm_coder::types::String,349 /// Token property permissions.346 /// Token property permissions.350 permissions: Vec<PropertyPermission>,347 permissions: Vec<PropertyPermission>,351}348}363 ),360 ),364 ) -> Self {361 ) -> Self {365 let (key, permission) = value;362 let (key, permission) = value;366 let key = evm_coder::types::string::from_utf8(key.into_inner())363 let key = evm_coder::types::String::from_utf8(key.into_inner())367 .expect("Stored key must be valid");364 .expect("Stored key must be valid");368 let permissions = PropertyPermission::into_vec(permission);365 let permissions = PropertyPermission::into_vec(permission);369 Self { key, permissions }366 Self { key, permissions }393#[derive(Debug, Default, AbiCoder)]390#[derive(Debug, Default, AbiCoder)]394pub struct CollectionNesting {391pub struct CollectionNesting {395 token_owner: bool,392 token_owner: bool,396 ids: Vec<uint256>,393 ids: Vec<U256>,397}394}398395399impl CollectionNesting {396impl CollectionNesting {400 /// Create [`CollectionNesting`].397 /// Create [`CollectionNesting`].401 pub fn new(token_owner: bool, ids: Vec<uint256>) -> Self {398 pub fn new(token_owner: bool, ids: Vec<U256>) -> Self {402 Self { token_owner, ids }399 Self { token_owner, ids }403 }400 }404}401}417 }414 }418}415}416417/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).418#[derive(AbiCoder, Copy, Clone, Default, Debug)]419#[repr(u8)]420pub enum AccessMode {421 /// Access grant for owner and admins. Used as default.422 #[default]423 Normal,424 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.425 AllowList,426}427428impl From<up_data_structs::AccessMode> for AccessMode {429 fn from(value: up_data_structs::AccessMode) -> Self {430 match value {431 up_data_structs::AccessMode::Normal => AccessMode::Normal,432 up_data_structs::AccessMode::AllowList => AccessMode::AllowList,433 }434 }435}436437impl Into<up_data_structs::AccessMode> for AccessMode {438 fn into(self) -> up_data_structs::AccessMode {439 match self {440 AccessMode::Normal => up_data_structs::AccessMode::Normal,441 AccessMode::AllowList => up_data_structs::AccessMode::AllowList,442 }443 }444}419445pallets/common/src/lib.rsdiffbeforeafterboth500 }500 }501 }501 }502503 impl<T: Config> Pallet<T> {504 /// Helper function that handles deposit events505 pub fn deposit_event(event: Event<T>) {506 let event = <T as Config>::RuntimeEvent::from(event);507 let event = event.into();508 <frame_system::Pallet<T>>::deposit_event(event)509 }510 }502511503 #[pallet::event]512 #[pallet::event]504 #[pallet::generate_deposit(pub fn deposit_event)]505 pub enum Event<T: Config> {513 pub enum Event<T: Config> {506 /// New collection was created514 /// New collection was created507 CollectionCreated(515 CollectionCreated(pallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth41use evm_coder::{41use evm_coder::{42 abi::{AbiReader, AbiWrite, AbiWriter},42 abi::{AbiReader, AbiWrite, AbiWriter},43 execution,43 execution,44 types::{Msg, value},44 types::{Msg, Value},45};45};464647pub use pallet::*;47pub use pallet::*;256>(256>(257 caller: H160,257 caller: H160,258 e: &mut E,258 e: &mut E,259 value: value,259 value: Value,260 input: &[u8],260 input: &[u8],261) -> execution::Result<Option<AbiWriter>> {261) -> execution::Result<Option<AbiWriter>> {262 let (selector, mut reader) = AbiReader::new_call(input)?;262 let (selector, mut reader) = AbiReader::new_call(input)?;pallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth49 ContractSponsorSet {49 ContractSponsorSet {50 /// Contract address of the affected collection.50 /// Contract address of the affected collection.51 #[indexed]51 #[indexed]52 contract_address: address,52 contract_address: Address,53 /// New sponsor address.53 /// New sponsor address.54 sponsor: address,54 sponsor: Address,55 },55 },565657 /// New sponsor was confirm.57 /// New sponsor was confirm.58 ContractSponsorshipConfirmed {58 ContractSponsorshipConfirmed {59 /// Contract address of the affected collection.59 /// Contract address of the affected collection.60 #[indexed]60 #[indexed]61 contract_address: address,61 contract_address: Address,62 /// New sponsor address.62 /// New sponsor address.63 sponsor: address,63 sponsor: Address,64 },64 },656566 /// Collection sponsor was removed.66 /// Collection sponsor was removed.67 ContractSponsorRemoved {67 ContractSponsorRemoved {68 /// Contract address of the affected collection.68 /// Contract address of the affected collection.69 #[indexed]69 #[indexed]70 contract_address: address,70 contract_address: Address,71 },71 },72}72}737396 /// @dev Returns zero address if contract does not exists96 /// @dev Returns zero address if contract does not exists97 /// @param contractAddress Contract to get owner of97 /// @param contractAddress Contract to get owner of98 /// @return address Owner of contract98 /// @return address Owner of contract99 fn contract_owner(&self, contract_address: address) -> Result<address> {99 fn contract_owner(&self, contract_address: Address) -> Result<Address> {100 Ok(<Owner<T>>::get(contract_address))100 Ok(<Owner<T>>::get(contract_address))101 }101 }102102105 /// @param sponsor User address who set as pending sponsor.105 /// @param sponsor User address who set as pending sponsor.106 fn set_sponsor(106 fn set_sponsor(107 &mut self,107 &mut self,108 caller: caller,108 caller: Caller,109 contract_address: address,109 contract_address: Address,110 sponsor: address,110 sponsor: Address,111 ) -> Result<void> {111 ) -> Result<()> {112 self.recorder().consume_sload()?;112 self.recorder().consume_sload()?;113 self.recorder().consume_sstore()?;113 self.recorder().consume_sstore()?;114114125 /// Set contract as self sponsored.125 /// Set contract as self sponsored.126 ///126 ///127 /// @param contractAddress Contract for which a self sponsoring is being enabled.127 /// @param contractAddress Contract for which a self sponsoring is being enabled.128 fn self_sponsored_enable(&mut self, caller: caller, contract_address: address) -> Result<void> {128 fn self_sponsored_enable(&mut self, caller: Caller, contract_address: Address) -> Result<()> {129 self.recorder().consume_sload()?;129 self.recorder().consume_sload()?;130 self.recorder().consume_sstore()?;130 self.recorder().consume_sstore()?;131131146 /// Remove sponsor.146 /// Remove sponsor.147 ///147 ///148 /// @param contractAddress Contract for which a sponsorship is being removed.148 /// @param contractAddress Contract for which a sponsorship is being removed.149 fn remove_sponsor(&mut self, caller: caller, contract_address: address) -> Result<void> {149 fn remove_sponsor(&mut self, caller: Caller, contract_address: Address) -> Result<()> {150 self.recorder().consume_sload()?;150 self.recorder().consume_sload()?;151 self.recorder().consume_sstore()?;151 self.recorder().consume_sstore()?;152152161 /// @dev Caller must be same that set via [`setSponsor`].161 /// @dev Caller must be same that set via [`setSponsor`].162 ///162 ///163 /// @param contractAddress Сontract for which need to confirm sponsorship.163 /// @param contractAddress Сontract for which need to confirm sponsorship.164 fn confirm_sponsorship(&mut self, caller: caller, contract_address: address) -> Result<void> {164 fn confirm_sponsorship(&mut self, caller: Caller, contract_address: Address) -> Result<()> {165 self.recorder().consume_sload()?;165 self.recorder().consume_sload()?;166 self.recorder().consume_sstore()?;166 self.recorder().consume_sstore()?;167167175 ///175 ///176 /// @param contractAddress The contract for which a sponsor is requested.176 /// @param contractAddress The contract for which a sponsor is requested.177 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.177 /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.178 fn sponsor(&self, contract_address: address) -> Result<Option<eth::CrossAddress>> {178 fn sponsor(&self, contract_address: Address) -> Result<Option<eth::CrossAddress>> {179 Ok(match Pallet::<T>::get_sponsor(contract_address) {179 Ok(match Pallet::<T>::get_sponsor(contract_address) {180 Some(ref value) => Some(eth::CrossAddress::from_sub_cross_account::<T>(value)),180 Some(ref value) => Some(eth::CrossAddress::from_sub_cross_account::<T>(value)),181 None => None,181 None => None,186 ///186 ///187 /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.187 /// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.188 /// @return **true** if contract has confirmed sponsor.188 /// @return **true** if contract has confirmed sponsor.189 fn has_sponsor(&self, contract_address: address) -> Result<bool> {189 fn has_sponsor(&self, contract_address: Address) -> Result<bool> {190 Ok(Pallet::<T>::get_sponsor(contract_address).is_some())190 Ok(Pallet::<T>::get_sponsor(contract_address).is_some())191 }191 }192192193 /// Check tat contract has pending sponsor.193 /// Check tat contract has pending sponsor.194 ///194 ///195 /// @param contractAddress The contract for which the presence of a pending sponsor is checked.195 /// @param contractAddress The contract for which the presence of a pending sponsor is checked.196 /// @return **true** if contract has pending sponsor.196 /// @return **true** if contract has pending sponsor.197 fn has_pending_sponsor(&self, contract_address: address) -> Result<bool> {197 fn has_pending_sponsor(&self, contract_address: Address) -> Result<bool> {198 Ok(match Sponsoring::<T>::get(contract_address) {198 Ok(match Sponsoring::<T>::get(contract_address) {199 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => false,199 SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => false,200 SponsorshipState::Unconfirmed(_) => true,200 SponsorshipState::Unconfirmed(_) => true,201 })201 })202 }202 }203203204 fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {204 fn sponsoring_enabled(&self, contract_address: Address) -> Result<bool> {205 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)205 Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)206 }206 }207207208 fn set_sponsoring_mode(208 fn set_sponsoring_mode(209 &mut self,209 &mut self,210 caller: caller,210 caller: Caller,211 contract_address: address,211 contract_address: Address,212 mode: SponsoringModeT,212 mode: SponsoringModeT,213 ) -> Result<void> {213 ) -> Result<()> {214 self.recorder().consume_sload()?;214 self.recorder().consume_sload()?;215 self.recorder().consume_sstore()?;215 self.recorder().consume_sstore()?;216216223 /// Get current contract sponsoring rate limit223 /// Get current contract sponsoring rate limit224 /// @param contractAddress Contract to get sponsoring rate limit of224 /// @param contractAddress Contract to get sponsoring rate limit of225 /// @return uint32 Amount of blocks between two sponsored transactions225 /// @return uint32 Amount of blocks between two sponsored transactions226 fn sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {226 fn sponsoring_rate_limit(&self, contract_address: Address) -> Result<u32> {227 self.recorder().consume_sload()?;227 self.recorder().consume_sload()?;228228229 Ok(<SponsoringRateLimit<T>>::get(contract_address)229 Ok(<SponsoringRateLimit<T>>::get(contract_address)239 /// @dev Only contract owner can change this setting239 /// @dev Only contract owner can change this setting240 fn set_sponsoring_rate_limit(240 fn set_sponsoring_rate_limit(241 &mut self,241 &mut self,242 caller: caller,242 caller: Caller,243 contract_address: address,243 contract_address: Address,244 rate_limit: uint32,244 rate_limit: u32,245 ) -> Result<void> {245 ) -> Result<()> {246 self.recorder().consume_sload()?;246 self.recorder().consume_sload()?;247 self.recorder().consume_sstore()?;247 self.recorder().consume_sstore()?;248248259 /// @dev Only contract owner can change this setting259 /// @dev Only contract owner can change this setting260 fn set_sponsoring_fee_limit(260 fn set_sponsoring_fee_limit(261 &mut self,261 &mut self,262 caller: caller,262 caller: Caller,263 contract_address: address,263 contract_address: Address,264 fee_limit: uint256,264 fee_limit: U256,265 ) -> Result<void> {265 ) -> Result<()> {266 self.recorder().consume_sload()?;266 self.recorder().consume_sload()?;267 self.recorder().consume_sstore()?;267 self.recorder().consume_sstore()?;268268276 /// @param contractAddress Contract to get sponsoring fee limit of276 /// @param contractAddress Contract to get sponsoring fee limit of277 /// @return uint256 Maximum amount of fee that could be spent by single277 /// @return uint256 Maximum amount of fee that could be spent by single278 /// transaction278 /// transaction279 fn sponsoring_fee_limit(&self, contract_address: address) -> Result<uint256> {279 fn sponsoring_fee_limit(&self, contract_address: Address) -> Result<U256> {280 self.recorder().consume_sload()?;280 self.recorder().consume_sload()?;281281282 Ok(get_sponsoring_fee_limit::<T>(contract_address))282 Ok(get_sponsoring_fee_limit::<T>(contract_address))287 /// @param contractAddress Contract to check allowlist of287 /// @param contractAddress Contract to check allowlist of288 /// @param user User to check288 /// @param user User to check289 /// @return bool Is specified users exists in contract allowlist289 /// @return bool Is specified users exists in contract allowlist290 fn allowed(&self, contract_address: address, user: address) -> Result<bool> {290 fn allowed(&self, contract_address: Address, user: Address) -> Result<bool> {291 self.0.consume_sload()?;291 self.0.consume_sload()?;292 Ok(<Pallet<T>>::allowed(contract_address, user))292 Ok(<Pallet<T>>::allowed(contract_address, user))293 }293 }300 /// @dev Only contract owner can change this setting300 /// @dev Only contract owner can change this setting301 fn toggle_allowed(301 fn toggle_allowed(302 &mut self,302 &mut self,303 caller: caller,303 caller: Caller,304 contract_address: address,304 contract_address: Address,305 user: address,305 user: Address,306 is_allowed: bool,306 is_allowed: bool,307 ) -> Result<void> {307 ) -> Result<()> {308 self.recorder().consume_sload()?;308 self.recorder().consume_sload()?;309 self.recorder().consume_sstore()?;309 self.recorder().consume_sstore()?;310310320 /// in case of allowlist access enabled, only users from allowlist may call this contract320 /// in case of allowlist access enabled, only users from allowlist may call this contract321 /// @param contractAddress Contract to get allowlist access of321 /// @param contractAddress Contract to get allowlist access of322 /// @return bool Is specified contract has allowlist access enabled322 /// @return bool Is specified contract has allowlist access enabled323 fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {323 fn allowlist_enabled(&self, contract_address: Address) -> Result<bool> {324 Ok(<AllowlistEnabled<T>>::get(contract_address))324 Ok(<AllowlistEnabled<T>>::get(contract_address))325 }325 }326326329 /// @param enabled Should allowlist access to be enabled?329 /// @param enabled Should allowlist access to be enabled?330 fn toggle_allowlist(330 fn toggle_allowlist(331 &mut self,331 &mut self,332 caller: caller,332 caller: Caller,333 contract_address: address,333 contract_address: Address,334 enabled: bool,334 enabled: bool,335 ) -> Result<void> {335 ) -> Result<()> {336 self.recorder().consume_sload()?;336 self.recorder().consume_sload()?;337 self.recorder().consume_sstore()?;337 self.recorder().consume_sstore()?;338338441 }441 }442}442}443443444fn get_sponsoring_fee_limit<T: Config>(contract_address: address) -> uint256 {444fn get_sponsoring_fee_limit<T: Config>(contract_address: Address) -> U256 {445 <SponsoringFeeLimit<T>>::get(contract_address)445 <SponsoringFeeLimit<T>>::get(contract_address)446 .get(&0xffffffff)446 .get(&0xffffffff)447 .cloned()447 .cloned()pallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth69 }69 }707071 #[pallet::pallet]71 #[pallet::pallet]72 #[pallet::generate_store(pub(super) trait Store)]72 #[pallet::generate_store(trait Store)]73 pub struct Pallet<T>(_);73 pub struct Pallet<T>(_);747475 /// Store owner for contract.75 /// Store owner for contract.80 pub(super) type Owner<T: Config> =80 pub(super) type Owner<T: Config> =81 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;81 StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;828283 /// Deprecated: this storage is deprecated83 #[pallet::storage]84 #[pallet::storage]84 #[deprecated]85 pub(super) type SelfSponsoring<T: Config> =85 type SelfSponsoring<T: Config> =86 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;86 StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;878788 /// Store for contract sponsorship state.88 /// Store for contract sponsorship state.349 }349 }350350351 /// Get current sponsoring mode, performing lazy migration from legacy storage351 /// Get current sponsoring mode, performing lazy migration from legacy storage352 /// Deprecated: this method is for deprecated storage352 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {353 pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {353 <SponsoringMode<T>>::get(contract)354 <SponsoringMode<T>>::get(contract)354 .or_else(|| {355 .or_else(|| {359 }360 }360361361 /// Reconfigure contract sponsoring mode362 /// Reconfigure contract sponsoring mode363 /// Deprecated: this method is for deprecated storage362 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {364 pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {363 if mode == SponsoringModeT::Disabled {365 if mode == SponsoringModeT::Disabled {364 <SponsoringMode<T>>::remove(contract);366 <SponsoringMode<T>>::remove(contract);pallets/fungible/src/erc.rsdiffbeforeafterboth32use pallet_evm::{account::CrossAccountId, PrecompileHandle};32use pallet_evm::{account::CrossAccountId, PrecompileHandle};33use pallet_evm_coder_substrate::{call, dispatch_to_evm};33use pallet_evm_coder_substrate::{call, dispatch_to_evm};34use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};34use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};35use sp_core::Get;35use sp_core::{U256, Get};363637use crate::{37use crate::{38 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,38 Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,43pub enum ERC20Events {43pub enum ERC20Events {44 Transfer {44 Transfer {45 #[indexed]45 #[indexed]46 from: address,46 from: Address,47 #[indexed]47 #[indexed]48 to: address,48 to: Address,49 value: uint256,49 value: U256,50 },50 },51 Approval {51 Approval {52 #[indexed]52 #[indexed]53 owner: address,53 owner: Address,54 #[indexed]54 #[indexed]55 spender: address,55 spender: Address,56 value: uint256,56 value: U256,57 },57 },58}58}595960#[solidity_interface(name = ERC20, events(ERC20Events))]60#[solidity_interface(name = ERC20, events(ERC20Events))]61impl<T: Config> FungibleHandle<T> {61impl<T: Config> FungibleHandle<T> {62 fn name(&self) -> Result<string> {62 fn name(&self) -> Result<String> {63 Ok(decode_utf16(self.name.iter().copied())63 Ok(decode_utf16(self.name.iter().copied())64 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))64 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))65 .collect::<string>())65 .collect::<String>())66 }66 }67 fn symbol(&self) -> Result<string> {67 fn symbol(&self) -> Result<String> {68 Ok(string::from_utf8_lossy(&self.token_prefix).into())68 Ok(String::from_utf8_lossy(&self.token_prefix).into())69 }69 }70 fn total_supply(&self) -> Result<uint256> {70 fn total_supply(&self) -> Result<U256> {71 self.consume_store_reads(1)?;71 self.consume_store_reads(1)?;72 Ok(<TotalSupply<T>>::get(self.id).into())72 Ok(<TotalSupply<T>>::get(self.id).into())73 }73 }747475 fn decimals(&self) -> Result<uint8> {75 fn decimals(&self) -> Result<u8> {76 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {76 Ok(if let CollectionMode::Fungible(decimals) = &self.mode {77 *decimals77 *decimals78 } else {78 } else {79 unreachable!()79 unreachable!()80 })80 })81 }81 }82 fn balance_of(&self, owner: address) -> Result<uint256> {82 fn balance_of(&self, owner: Address) -> Result<U256> {83 self.consume_store_reads(1)?;83 self.consume_store_reads(1)?;84 let owner = T::CrossAccountId::from_eth(owner);84 let owner = T::CrossAccountId::from_eth(owner);85 let balance = <Balance<T>>::get((self.id, owner));85 let balance = <Balance<T>>::get((self.id, owner));86 Ok(balance.into())86 Ok(balance.into())87 }87 }88 #[weight(<SelfWeightOf<T>>::transfer())]88 #[weight(<SelfWeightOf<T>>::transfer())]89 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {89 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {90 let caller = T::CrossAccountId::from_eth(caller);90 let caller = T::CrossAccountId::from_eth(caller);91 let to = T::CrossAccountId::from_eth(to);91 let to = T::CrossAccountId::from_eth(to);92 let amount = amount.try_into().map_err(|_| "amount overflow")?;92 let amount = amount.try_into().map_err(|_| "amount overflow")?;101 #[weight(<SelfWeightOf<T>>::transfer_from())]101 #[weight(<SelfWeightOf<T>>::transfer_from())]102 fn transfer_from(102 fn transfer_from(103 &mut self,103 &mut self,104 caller: caller,104 caller: Caller,105 from: address,105 from: Address,106 to: address,106 to: Address,107 amount: uint256,107 amount: U256,108 ) -> Result<bool> {108 ) -> Result<bool> {109 let caller = T::CrossAccountId::from_eth(caller);109 let caller = T::CrossAccountId::from_eth(caller);110 let from = T::CrossAccountId::from_eth(from);110 let from = T::CrossAccountId::from_eth(from);119 Ok(true)119 Ok(true)120 }120 }121 #[weight(<SelfWeightOf<T>>::approve())]121 #[weight(<SelfWeightOf<T>>::approve())]122 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {122 fn approve(&mut self, caller: Caller, spender: Address, amount: U256) -> Result<bool> {123 let caller = T::CrossAccountId::from_eth(caller);123 let caller = T::CrossAccountId::from_eth(caller);124 let spender = T::CrossAccountId::from_eth(spender);124 let spender = T::CrossAccountId::from_eth(spender);125 let amount = amount.try_into().map_err(|_| "amount overflow")?;125 let amount = amount.try_into().map_err(|_| "amount overflow")?;128 .map_err(dispatch_to_evm::<T>)?;128 .map_err(dispatch_to_evm::<T>)?;129 Ok(true)129 Ok(true)130 }130 }131 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {131 fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {132 self.consume_store_reads(1)?;132 self.consume_store_reads(1)?;133 let owner = T::CrossAccountId::from_eth(owner);133 let owner = T::CrossAccountId::from_eth(owner);134 let spender = T::CrossAccountId::from_eth(spender);134 let spender = T::CrossAccountId::from_eth(spender);137 }137 }138138139 /// @notice Returns collection helper contract address139 /// @notice Returns collection helper contract address140 fn collection_helper_address(&self) -> Result<address> {140 fn collection_helper_address(&self) -> Result<Address> {141 Ok(T::ContractAddress::get())141 Ok(T::ContractAddress::get())142 }142 }143}143}148 /// @param to account that will receive minted tokens148 /// @param to account that will receive minted tokens149 /// @param amount amount of tokens to mint149 /// @param amount amount of tokens to mint150 #[weight(<SelfWeightOf<T>>::create_item())]150 #[weight(<SelfWeightOf<T>>::create_item())]151 fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {151 fn mint(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {152 let caller = T::CrossAccountId::from_eth(caller);152 let caller = T::CrossAccountId::from_eth(caller);153 let to = T::CrossAccountId::from_eth(to);153 let to = T::CrossAccountId::from_eth(to);154 let amount = amount.try_into().map_err(|_| "amount overflow")?;154 let amount = amount.try_into().map_err(|_| "amount overflow")?;167 T::AccountId: From<[u8; 32]>,167 T::AccountId: From<[u8; 32]>,168{168{169 /// @notice A description for the collection.169 /// @notice A description for the collection.170 fn description(&self) -> Result<string> {170 fn description(&self) -> Result<String> {171 Ok(decode_utf16(self.description.iter().copied())171 Ok(decode_utf16(self.description.iter().copied())172 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))172 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))173 .collect::<string>())173 .collect::<String>())174 }174 }175175176 #[weight(<SelfWeightOf<T>>::create_item())]176 #[weight(<SelfWeightOf<T>>::create_item())]177 fn mint_cross(177 fn mint_cross(178 &mut self,178 &mut self,179 caller: caller,179 caller: Caller,180 to: pallet_common::eth::CrossAddress,180 to: pallet_common::eth::CrossAddress,181 amount: uint256,181 amount: U256,182 ) -> Result<bool> {182 ) -> Result<bool> {183 let caller = T::CrossAccountId::from_eth(caller);183 let caller = T::CrossAccountId::from_eth(caller);184 let to = to.into_sub_cross_account::<T>()?;184 let to = to.into_sub_cross_account::<T>()?;194 #[weight(<SelfWeightOf<T>>::approve())]194 #[weight(<SelfWeightOf<T>>::approve())]195 fn approve_cross(195 fn approve_cross(196 &mut self,196 &mut self,197 caller: caller,197 caller: Caller,198 spender: pallet_common::eth::CrossAddress,198 spender: pallet_common::eth::CrossAddress,199 amount: uint256,199 amount: U256,200 ) -> Result<bool> {200 ) -> Result<bool> {201 let caller = T::CrossAccountId::from_eth(caller);201 let caller = T::CrossAccountId::from_eth(caller);202 let spender = spender.into_sub_cross_account::<T>()?;202 let spender = spender.into_sub_cross_account::<T>()?;214 /// @param amount The amount that will be burnt.214 /// @param amount The amount that will be burnt.215 #[solidity(hide)]215 #[solidity(hide)]216 #[weight(<SelfWeightOf<T>>::burn_from())]216 #[weight(<SelfWeightOf<T>>::burn_from())]217 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {217 fn burn_from(&mut self, caller: Caller, from: Address, amount: U256) -> Result<bool> {218 let caller = T::CrossAccountId::from_eth(caller);218 let caller = T::CrossAccountId::from_eth(caller);219 let from = T::CrossAccountId::from_eth(from);219 let from = T::CrossAccountId::from_eth(from);220 let amount = amount.try_into().map_err(|_| "amount overflow")?;220 let amount = amount.try_into().map_err(|_| "amount overflow")?;235 #[weight(<SelfWeightOf<T>>::burn_from())]235 #[weight(<SelfWeightOf<T>>::burn_from())]236 fn burn_from_cross(236 fn burn_from_cross(237 &mut self,237 &mut self,238 caller: caller,238 caller: Caller,239 from: pallet_common::eth::CrossAddress,239 from: pallet_common::eth::CrossAddress,240 amount: uint256,240 amount: U256,241 ) -> Result<bool> {241 ) -> Result<bool> {242 let caller = T::CrossAccountId::from_eth(caller);242 let caller = T::CrossAccountId::from_eth(caller);243 let from = from.into_sub_cross_account::<T>()?;243 let from = from.into_sub_cross_account::<T>()?;254 /// Mint tokens for multiple accounts.254 /// Mint tokens for multiple accounts.255 /// @param amounts array of pairs of account address and amount255 /// @param amounts array of pairs of account address and amount256 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]256 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]257 fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {257 fn mint_bulk(&mut self, caller: Caller, amounts: Vec<(Address, U256)>) -> Result<bool> {258 let caller = T::CrossAccountId::from_eth(caller);258 let caller = T::CrossAccountId::from_eth(caller);259 let budget = self259 let budget = self260 .recorder260 .recorder277 #[weight(<SelfWeightOf<T>>::transfer())]277 #[weight(<SelfWeightOf<T>>::transfer())]278 fn transfer_cross(278 fn transfer_cross(279 &mut self,279 &mut self,280 caller: caller,280 caller: Caller,281 to: pallet_common::eth::CrossAddress,281 to: pallet_common::eth::CrossAddress,282 amount: uint256,282 amount: U256,283 ) -> Result<bool> {283 ) -> Result<bool> {284 let caller = T::CrossAccountId::from_eth(caller);284 let caller = T::CrossAccountId::from_eth(caller);285 let to = to.into_sub_cross_account::<T>()?;285 let to = to.into_sub_cross_account::<T>()?;295 #[weight(<SelfWeightOf<T>>::transfer_from())]295 #[weight(<SelfWeightOf<T>>::transfer_from())]296 fn transfer_from_cross(296 fn transfer_from_cross(297 &mut self,297 &mut self,298 caller: caller,298 caller: Caller,299 from: pallet_common::eth::CrossAddress,299 from: pallet_common::eth::CrossAddress,300 to: pallet_common::eth::CrossAddress,300 to: pallet_common::eth::CrossAddress,301 amount: uint256,301 amount: U256,302 ) -> Result<bool> {302 ) -> Result<bool> {303 let caller = T::CrossAccountId::from_eth(caller);303 let caller = T::CrossAccountId::from_eth(caller);304 let from = from.into_sub_cross_account::<T>()?;304 let from = from.into_sub_cross_account::<T>()?;pallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth274274275 /// Set the collection access method.275 /// Set the collection access method.276 /// @param mode Access mode276 /// @param mode Access mode277 /// 0 for Normal278 /// 1 for AllowList279 /// @dev EVM selector for this function is: 0x41835d4c,277 /// @dev EVM selector for this function is: 0x41835d4c,280 /// or in textual repr: setCollectionAccess(uint8)278 /// or in textual repr: setCollectionAccess(uint8)281 function setCollectionAccess(uint8 mode) public {279 function setCollectionAccess(AccessMode mode) public {282 require(false, stub_error);280 require(false, stub_error);283 mode;281 mode;284 dummy = 0;282 dummy = 0;443 uint256 sub;441 uint256 sub;444}442}443444/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).445enum AccessMode {446 /// Access grant for owner and admins. Used as default.447 Normal,448 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.449 AllowList450}445451446/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.452/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.447struct CollectionNestingPermission {453struct CollectionNestingPermission {pallets/nonfungible/src/erc.rsdiffbeforeafterboth43use pallet_evm::{account::CrossAccountId, PrecompileHandle};43use pallet_evm::{account::CrossAccountId, PrecompileHandle};44use pallet_evm_coder_substrate::call;44use pallet_evm_coder_substrate::call;45use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};45use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};46use sp_core::Get;46use sp_core::{U256, Get};474748use crate::{48use crate::{49 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,49 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,63 #[solidity(hide)]63 #[solidity(hide)]64 fn set_token_property_permission(64 fn set_token_property_permission(65 &mut self,65 &mut self,66 caller: caller,66 caller: Caller,67 key: string,67 key: String,68 is_mutable: bool,68 is_mutable: bool,69 collection_admin: bool,69 collection_admin: bool,70 token_owner: bool,70 token_owner: bool,93 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]93 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]94 fn set_token_property_permissions(94 fn set_token_property_permissions(95 &mut self,95 &mut self,96 caller: caller,96 caller: Caller,97 permissions: Vec<eth::TokenPropertyPermission>,97 permissions: Vec<eth::TokenPropertyPermission>,98 ) -> Result<()> {98 ) -> Result<()> {99 let caller = T::CrossAccountId::from_eth(caller);99 let caller = T::CrossAccountId::from_eth(caller);121 #[weight(<SelfWeightOf<T>>::set_token_properties(1))]121 #[weight(<SelfWeightOf<T>>::set_token_properties(1))]122 fn set_property(122 fn set_property(123 &mut self,123 &mut self,124 caller: caller,124 caller: Caller,125 token_id: uint256,125 token_id: U256,126 key: string,126 key: String,127 value: bytes,127 value: Bytes,128 ) -> Result<()> {128 ) -> Result<()> {129 let caller = T::CrossAccountId::from_eth(caller);129 let caller = T::CrossAccountId::from_eth(caller);130 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;130 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;154 #[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]154 #[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]155 fn set_properties(155 fn set_properties(156 &mut self,156 &mut self,157 caller: caller,157 caller: Caller,158 token_id: uint256,158 token_id: U256,159 properties: Vec<eth::Property>,159 properties: Vec<eth::Property>,160 ) -> Result<()> {160 ) -> Result<()> {161 let caller = T::CrossAccountId::from_eth(caller);161 let caller = T::CrossAccountId::from_eth(caller);187 /// @param key Property key.187 /// @param key Property key.188 #[solidity(hide)]188 #[solidity(hide)]189 #[weight(<SelfWeightOf<T>>::delete_token_properties(1))]189 #[weight(<SelfWeightOf<T>>::delete_token_properties(1))]190 fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {190 fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> {191 let caller = T::CrossAccountId::from_eth(caller);191 let caller = T::CrossAccountId::from_eth(caller);192 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;192 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;193 let key = <Vec<u8>>::from(key)193 let key = <Vec<u8>>::from(key)209 #[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]209 #[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]210 fn delete_properties(210 fn delete_properties(211 &mut self,211 &mut self,212 token_id: uint256,212 token_id: U256,213 caller: caller,213 caller: Caller,214 keys: Vec<string>,214 keys: Vec<String>,215 ) -> Result<()> {215 ) -> Result<()> {216 let caller = T::CrossAccountId::from_eth(caller);216 let caller = T::CrossAccountId::from_eth(caller);217 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;217 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;239 /// @param tokenId ID of the token.239 /// @param tokenId ID of the token.240 /// @param key Property key.240 /// @param key Property key.241 /// @return Property value bytes241 /// @return Property value bytes242 fn property(&self, token_id: uint256, key: string) -> Result<bytes> {242 fn property(&self, token_id: U256, key: String) -> Result<Bytes> {243 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;243 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;244 let key = <Vec<u8>>::from(key)244 let key = <Vec<u8>>::from(key)245 .try_into()245 .try_into()261 /// any transfer, the approved address for that NFT (if any) is reset to none.261 /// any transfer, the approved address for that NFT (if any) is reset to none.262 Transfer {262 Transfer {263 #[indexed]263 #[indexed]264 from: address,264 from: Address,265 #[indexed]265 #[indexed]266 to: address,266 to: Address,267 #[indexed]267 #[indexed]268 token_id: uint256,268 token_id: U256,269 },269 },270 /// @dev This emits when the approved address for an NFT is changed or270 /// @dev This emits when the approved address for an NFT is changed or271 /// reaffirmed. The zero address indicates there is no approved address.271 /// reaffirmed. The zero address indicates there is no approved address.272 /// When a Transfer event emits, this also indicates that the approved272 /// When a Transfer event emits, this also indicates that the approved273 /// address for that NFT (if any) is reset to none.273 /// address for that NFT (if any) is reset to none.274 Approval {274 Approval {275 #[indexed]275 #[indexed]276 owner: address,276 owner: Address,277 #[indexed]277 #[indexed]278 approved: address,278 approved: Address,279 #[indexed]279 #[indexed]280 token_id: uint256,280 token_id: U256,281 },281 },282 /// @dev This emits when an operator is enabled or disabled for an owner.282 /// @dev This emits when an operator is enabled or disabled for an owner.283 /// The operator can manage all NFTs of the owner.283 /// The operator can manage all NFTs of the owner.284 #[allow(dead_code)]284 #[allow(dead_code)]285 ApprovalForAll {285 ApprovalForAll {286 #[indexed]286 #[indexed]287 owner: address,287 owner: Address,288 #[indexed]288 #[indexed]289 operator: address,289 operator: Address,290 approved: bool,290 approved: bool,291 },291 },292}292}293294#[derive(ToLog)]295pub enum ERC721UniqueMintableEvents {296 #[allow(dead_code)]297 MintingFinished {},298}299293300/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension294/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension301/// @dev See https://eips.ethereum.org/EIPS/eip-721295/// @dev See https://eips.ethereum.org/EIPS/eip-721307 /// @notice A descriptive name for a collection of NFTs in this contract301 /// @notice A descriptive name for a collection of NFTs in this contract308 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`302 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`309 #[solidity(hide, rename_selector = "name")]303 #[solidity(hide, rename_selector = "name")]310 fn name_proxy(&self) -> Result<string> {304 fn name_proxy(&self) -> Result<String> {311 self.name()305 self.name()312 }306 }313307314 /// @notice An abbreviated name for NFTs in this contract308 /// @notice An abbreviated name for NFTs in this contract315 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`309 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`316 #[solidity(hide, rename_selector = "symbol")]310 #[solidity(hide, rename_selector = "symbol")]317 fn symbol_proxy(&self) -> Result<string> {311 fn symbol_proxy(&self) -> Result<String> {318 self.symbol()312 self.symbol()319 }313 }320314328 ///322 ///329 /// @return token's const_metadata323 /// @return token's const_metadata330 #[solidity(rename_selector = "tokenURI")]324 #[solidity(rename_selector = "tokenURI")]331 fn token_uri(&self, token_id: uint256) -> Result<string> {325 fn token_uri(&self, token_id: U256) -> Result<String> {332 let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;326 let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;333327334 match get_token_property(self, token_id_u32, &key::url()).as_deref() {328 match get_token_property(self, token_id_u32, &key::url()).as_deref() {341 let base_uri =335 let base_uri =342 pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())336 pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())343 .map(BoundedVec::into_inner)337 .map(BoundedVec::into_inner)344 .map(string::from_utf8)338 .map(String::from_utf8)345 .transpose()339 .transpose()346 .map_err(|e| {340 .map_err(|e| {347 Error::Revert(alloc::format!(341 Error::Revert(alloc::format!(374 /// @param index A counter less than `totalSupply()`368 /// @param index A counter less than `totalSupply()`375 /// @return The token identifier for the `index`th NFT,369 /// @return The token identifier for the `index`th NFT,376 /// (sort order not specified)370 /// (sort order not specified)377 fn token_by_index(&self, index: uint256) -> Result<uint256> {371 fn token_by_index(&self, index: U256) -> Result<U256> {378 Ok(index)372 Ok(index)379 }373 }380374381 /// @dev Not implemented375 /// @dev Not implemented382 fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {376 fn token_of_owner_by_index(&self, _owner: Address, _index: U256) -> Result<U256> {383 // TODO: Not implemetable377 // TODO: Not implemetable384 Err("not implemented".into())378 Err("not implemented".into())385 }379 }386380387 /// @notice Count NFTs tracked by this contract381 /// @notice Count NFTs tracked by this contract388 /// @return A count of valid NFTs tracked by this contract, where each one of382 /// @return A count of valid NFTs tracked by this contract, where each one of389 /// them has an assigned and queryable owner not equal to the zero address383 /// them has an assigned and queryable owner not equal to the zero address390 fn total_supply(&self) -> Result<uint256> {384 fn total_supply(&self) -> Result<U256> {391 self.consume_store_reads(1)?;385 self.consume_store_reads(1)?;392 Ok(<Pallet<T>>::total_supply(self).into())386 Ok(<Pallet<T>>::total_supply(self).into())393 }387 }402 /// function throws for queries about the zero address.396 /// function throws for queries about the zero address.403 /// @param owner An address for whom to query the balance397 /// @param owner An address for whom to query the balance404 /// @return The number of NFTs owned by `owner`, possibly zero398 /// @return The number of NFTs owned by `owner`, possibly zero405 fn balance_of(&self, owner: address) -> Result<uint256> {399 fn balance_of(&self, owner: Address) -> Result<U256> {406 self.consume_store_reads(1)?;400 self.consume_store_reads(1)?;407 let owner = T::CrossAccountId::from_eth(owner);401 let owner = T::CrossAccountId::from_eth(owner);408 let balance = <AccountBalance<T>>::get((self.id, owner));402 let balance = <AccountBalance<T>>::get((self.id, owner));413 /// about them do throw.407 /// about them do throw.414 /// @param tokenId The identifier for an NFT408 /// @param tokenId The identifier for an NFT415 /// @return The address of the owner of the NFT409 /// @return The address of the owner of the NFT416 fn owner_of(&self, token_id: uint256) -> Result<address> {410 fn owner_of(&self, token_id: U256) -> Result<Address> {417 self.consume_store_reads(1)?;411 self.consume_store_reads(1)?;418 let token: TokenId = token_id.try_into()?;412 let token: TokenId = token_id.try_into()?;419 Ok(*<TokenData<T>>::get((self.id, token))413 Ok(*<TokenData<T>>::get((self.id, token))425 #[solidity(rename_selector = "safeTransferFrom")]419 #[solidity(rename_selector = "safeTransferFrom")]426 fn safe_transfer_from_with_data(420 fn safe_transfer_from_with_data(427 &mut self,421 &mut self,428 _from: address,422 _from: Address,429 _to: address,423 _to: Address,430 _token_id: uint256,424 _token_id: U256,431 _data: bytes,425 _data: Bytes,432 ) -> Result<void> {426 ) -> Result<()> {433 // TODO: Not implemetable427 // TODO: Not implemetable434 Err("not implemented".into())428 Err("not implemented".into())435 }429 }436 /// @dev Not implemented430 /// @dev Not implemented437 fn safe_transfer_from(431 fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {438 &mut self,439 _from: address,440 _to: address,441 _token_id: uint256,442 ) -> Result<void> {443 // TODO: Not implemetable432 // TODO: Not implemetable444 Err("not implemented".into())433 Err("not implemented".into())445 }434 }456 #[weight(<SelfWeightOf<T>>::transfer_from())]445 #[weight(<SelfWeightOf<T>>::transfer_from())]457 fn transfer_from(446 fn transfer_from(458 &mut self,447 &mut self,459 caller: caller,448 caller: Caller,460 from: address,449 from: Address,461 to: address,450 to: Address,462 token_id: uint256,451 token_id: U256,463 ) -> Result<void> {452 ) -> Result<()> {464 let caller = T::CrossAccountId::from_eth(caller);453 let caller = T::CrossAccountId::from_eth(caller);465 let from = T::CrossAccountId::from_eth(from);454 let from = T::CrossAccountId::from_eth(from);466 let to = T::CrossAccountId::from_eth(to);455 let to = T::CrossAccountId::from_eth(to);481 /// @param approved The new approved NFT controller470 /// @param approved The new approved NFT controller482 /// @param tokenId The NFT to approve471 /// @param tokenId The NFT to approve483 #[weight(<SelfWeightOf<T>>::approve())]472 #[weight(<SelfWeightOf<T>>::approve())]484 fn approve(&mut self, caller: caller, approved: address, token_id: uint256) -> Result<void> {473 fn approve(&mut self, caller: Caller, approved: Address, token_id: U256) -> Result<()> {485 let caller = T::CrossAccountId::from_eth(caller);474 let caller = T::CrossAccountId::from_eth(caller);486 let approved = T::CrossAccountId::from_eth(approved);475 let approved = T::CrossAccountId::from_eth(approved);487 let token = token_id.try_into()?;476 let token = token_id.try_into()?;498 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]487 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]499 fn set_approval_for_all(488 fn set_approval_for_all(500 &mut self,489 &mut self,501 caller: caller,490 caller: Caller,502 operator: address,491 operator: Address,503 approved: bool,492 approved: bool,504 ) -> Result<void> {493 ) -> Result<()> {505 let caller = T::CrossAccountId::from_eth(caller);494 let caller = T::CrossAccountId::from_eth(caller);506 let operator = T::CrossAccountId::from_eth(operator);495 let operator = T::CrossAccountId::from_eth(operator);507496511 }500 }512501513 /// @dev Not implemented502 /// @dev Not implemented514 fn get_approved(&self, _token_id: uint256) -> Result<address> {503 fn get_approved(&self, _token_id: U256) -> Result<Address> {515 // TODO: Not implemetable504 // TODO: Not implemetable516 Err("not implemented".into())505 Err("not implemented".into())517 }506 }518507519 /// @notice Tells whether the given `owner` approves the `operator`.508 /// @notice Tells whether the given `owner` approves the `operator`.520 #[weight(<SelfWeightOf<T>>::allowance_for_all())]509 #[weight(<SelfWeightOf<T>>::allowance_for_all())]521 fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {510 fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {522 let owner = T::CrossAccountId::from_eth(owner);511 let owner = T::CrossAccountId::from_eth(owner);523 let operator = T::CrossAccountId::from_eth(operator);512 let operator = T::CrossAccountId::from_eth(operator);524513534 /// operator of the current owner.523 /// operator of the current owner.535 /// @param tokenId The NFT to approve524 /// @param tokenId The NFT to approve536 #[weight(<SelfWeightOf<T>>::burn_item())]525 #[weight(<SelfWeightOf<T>>::burn_item())]537 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {526 fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {538 let caller = T::CrossAccountId::from_eth(caller);527 let caller = T::CrossAccountId::from_eth(caller);539 let token = token_id.try_into()?;528 let token = token_id.try_into()?;540529544}533}545534546/// @title ERC721 minting logic.535/// @title ERC721 minting logic.547#[solidity_interface(name = ERC721UniqueMintable, events(ERC721UniqueMintableEvents))]536#[solidity_interface(name = ERC721UniqueMintable)]548impl<T: Config> NonfungibleHandle<T> {537impl<T: Config> NonfungibleHandle<T> {549 fn minting_finished(&self) -> Result<bool> {550 Ok(false)551 }552553 /// @notice Function to mint a token.538 /// @notice Function to mint a token.554 /// @param to The new owner539 /// @param to The new owner555 /// @return uint256 The id of the newly minted token540 /// @return uint256 The id of the newly minted token556 #[weight(<SelfWeightOf<T>>::create_item())]541 #[weight(<SelfWeightOf<T>>::create_item())]557 fn mint(&mut self, caller: caller, to: address) -> Result<uint256> {542 fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {558 let token_id: uint256 = <TokensMinted<T>>::get(self.id)543 let token_id: U256 = <TokensMinted<T>>::get(self.id)559 .checked_add(1)544 .checked_add(1)560 .ok_or("item id overflow")?545 .ok_or("item id overflow")?561 .into();546 .into();570 /// @param tokenId ID of the minted NFT555 /// @param tokenId ID of the minted NFT571 #[solidity(hide, rename_selector = "mint")]556 #[solidity(hide, rename_selector = "mint")]572 #[weight(<SelfWeightOf<T>>::create_item())]557 #[weight(<SelfWeightOf<T>>::create_item())]573 fn mint_check_id(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {558 fn mint_check_id(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<bool> {574 let caller = T::CrossAccountId::from_eth(caller);559 let caller = T::CrossAccountId::from_eth(caller);575 let to = T::CrossAccountId::from_eth(to);560 let to = T::CrossAccountId::from_eth(to);576 let token_id: u32 = token_id.try_into()?;561 let token_id: u32 = token_id.try_into()?;608 #[weight(<SelfWeightOf<T>>::create_item())]593 #[weight(<SelfWeightOf<T>>::create_item())]609 fn mint_with_token_uri(594 fn mint_with_token_uri(610 &mut self,595 &mut self,611 caller: caller,596 caller: Caller,612 to: address,597 to: Address,613 token_uri: string,598 token_uri: String,614 ) -> Result<uint256> {599 ) -> Result<U256> {615 let token_id: uint256 = <TokensMinted<T>>::get(self.id)600 let token_id: U256 = <TokensMinted<T>>::get(self.id)616 .checked_add(1)601 .checked_add(1)617 .ok_or("item id overflow")?602 .ok_or("item id overflow")?618 .into();603 .into();630 #[weight(<SelfWeightOf<T>>::create_item())]615 #[weight(<SelfWeightOf<T>>::create_item())]631 fn mint_with_token_uri_check_id(616 fn mint_with_token_uri_check_id(632 &mut self,617 &mut self,633 caller: caller,618 caller: Caller,634 to: address,619 to: Address,635 token_id: uint256,620 token_id: U256,636 token_uri: string,621 token_uri: String,637 ) -> Result<bool> {622 ) -> Result<bool> {638 let key = key::url();623 let key = key::url();639 let permission = get_token_permission::<T>(self.id, &key)?;624 let permission = get_token_permission::<T>(self.id, &key)?;680 Ok(true)665 Ok(true)681 }666 }682683 /// @dev Not implemented684 fn finish_minting(&mut self, _caller: caller) -> Result<bool> {685 Err("not implementable".into())686 }687}667}688668689fn get_token_property<T: Config>(669fn get_token_property<T: Config>(690 collection: &CollectionHandle<T>,670 collection: &CollectionHandle<T>,691 token_id: u32,671 token_id: u32,692 key: &up_data_structs::PropertyKey,672 key: &up_data_structs::PropertyKey,693) -> Result<string> {673) -> Result<String> {694 collection.consume_store_reads(1)?;674 collection.consume_store_reads(1)?;695 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))675 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))696 .map_err(|_| Error::Revert("Token properties not found".into()))?;676 .map_err(|_| Error::Revert("Token properties not found".into()))?;697 if let Some(property) = properties.get(key) {677 if let Some(property) = properties.get(key) {698 return Ok(string::from_utf8_lossy(property).into());678 return Ok(String::from_utf8_lossy(property).into());699 }679 }700680701 Err("Property tokenURI not found".into())681 Err("Property tokenURI not found".into())711 .get(key)691 .get(key)712 .map(Clone::clone)692 .map(Clone::clone)713 .ok_or_else(|| {693 .ok_or_else(|| {714 let key = string::from_utf8(key.clone().into_inner()).unwrap_or_default();694 let key = String::from_utf8(key.clone().into_inner()).unwrap_or_default();715 Error::Revert(alloc::format!("No permission for key {}", key))695 Error::Revert(alloc::format!("No permission for key {}", key))716 })?;696 })?;717 Ok(a)697 Ok(a)724 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,704 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,725{705{726 /// @notice A descriptive name for a collection of NFTs in this contract706 /// @notice A descriptive name for a collection of NFTs in this contract727 fn name(&self) -> Result<string> {707 fn name(&self) -> Result<String> {728 Ok(decode_utf16(self.name.iter().copied())708 Ok(decode_utf16(self.name.iter().copied())729 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))709 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))730 .collect::<string>())710 .collect::<String>())731 }711 }732712733 /// @notice An abbreviated name for NFTs in this contract713 /// @notice An abbreviated name for NFTs in this contract734 fn symbol(&self) -> Result<string> {714 fn symbol(&self) -> Result<String> {735 Ok(string::from_utf8_lossy(&self.token_prefix).into())715 Ok(String::from_utf8_lossy(&self.token_prefix).into())736 }716 }737717738 /// @notice A description for the collection.718 /// @notice A description for the collection.739 fn description(&self) -> Result<string> {719 fn description(&self) -> Result<String> {740 Ok(decode_utf16(self.description.iter().copied())720 Ok(decode_utf16(self.description.iter().copied())741 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))721 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))742 .collect::<string>())722 .collect::<String>())743 }723 }744724745 /// Returns the owner (in cross format) of the token.725 /// Returns the owner (in cross format) of the token.746 ///726 ///747 /// @param tokenId Id for the token.727 /// @param tokenId Id for the token.748 fn cross_owner_of(&self, token_id: uint256) -> Result<eth::CrossAddress> {728 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {749 Self::token_owner(&self, token_id.try_into()?)729 Self::token_owner(&self, token_id.try_into()?)750 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))730 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))751 .ok_or(Error::Revert("key too large".into()))731 .ok_or(Error::Revert("key too large".into()))756 /// @param tokenId Id for the token.736 /// @param tokenId Id for the token.757 /// @param keys Properties keys. Empty keys for all propertyes.737 /// @param keys Properties keys. Empty keys for all propertyes.758 /// @return Vector of properties key/value pairs.738 /// @return Vector of properties key/value pairs.759 fn properties(&self, token_id: uint256, keys: Vec<string>) -> Result<Vec<eth::Property>> {739 fn properties(&self, token_id: U256, keys: Vec<String>) -> Result<Vec<eth::Property>> {760 let keys = keys740 let keys = keys761 .into_iter()741 .into_iter()762 .map(|key| {742 .map(|key| {785 #[weight(<SelfWeightOf<T>>::approve())]765 #[weight(<SelfWeightOf<T>>::approve())]786 fn approve_cross(766 fn approve_cross(787 &mut self,767 &mut self,788 caller: caller,768 caller: Caller,789 approved: eth::CrossAddress,769 approved: eth::CrossAddress,790 token_id: uint256,770 token_id: U256,791 ) -> Result<void> {771 ) -> Result<()> {792 let caller = T::CrossAccountId::from_eth(caller);772 let caller = T::CrossAccountId::from_eth(caller);793 let approved = approved.into_sub_cross_account::<T>()?;773 let approved = approved.into_sub_cross_account::<T>()?;794 let token = token_id.try_into()?;774 let token = token_id.try_into()?;804 /// @param to The new owner784 /// @param to The new owner805 /// @param tokenId The NFT to transfer785 /// @param tokenId The NFT to transfer806 #[weight(<SelfWeightOf<T>>::transfer())]786 #[weight(<SelfWeightOf<T>>::transfer())]807 fn transfer(&mut self, caller: caller, to: address, token_id: uint256) -> Result<void> {787 fn transfer(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<()> {808 let caller = T::CrossAccountId::from_eth(caller);788 let caller = T::CrossAccountId::from_eth(caller);809 let to = T::CrossAccountId::from_eth(to);789 let to = T::CrossAccountId::from_eth(to);810 let token = token_id.try_into()?;790 let token = token_id.try_into()?;824 #[weight(<SelfWeightOf<T>>::transfer())]804 #[weight(<SelfWeightOf<T>>::transfer())]825 fn transfer_cross(805 fn transfer_cross(826 &mut self,806 &mut self,827 caller: caller,807 caller: Caller,828 to: eth::CrossAddress,808 to: eth::CrossAddress,829 token_id: uint256,809 token_id: U256,830 ) -> Result<void> {810 ) -> Result<()> {831 let caller = T::CrossAccountId::from_eth(caller);811 let caller = T::CrossAccountId::from_eth(caller);832 let to = to.into_sub_cross_account::<T>()?;812 let to = to.into_sub_cross_account::<T>()?;833 let token = token_id.try_into()?;813 let token = token_id.try_into()?;848 #[weight(<SelfWeightOf<T>>::transfer())]828 #[weight(<SelfWeightOf<T>>::transfer())]849 fn transfer_from_cross(829 fn transfer_from_cross(850 &mut self,830 &mut self,851 caller: caller,831 caller: Caller,852 from: eth::CrossAddress,832 from: eth::CrossAddress,853 to: eth::CrossAddress,833 to: eth::CrossAddress,854 token_id: uint256,834 token_id: U256,855 ) -> Result<void> {835 ) -> Result<()> {856 let caller = T::CrossAccountId::from_eth(caller);836 let caller = T::CrossAccountId::from_eth(caller);857 let from = from.into_sub_cross_account::<T>()?;837 let from = from.into_sub_cross_account::<T>()?;858 let to = to.into_sub_cross_account::<T>()?;838 let to = to.into_sub_cross_account::<T>()?;873 /// @param tokenId The NFT to transfer853 /// @param tokenId The NFT to transfer874 #[solidity(hide)]854 #[solidity(hide)]875 #[weight(<SelfWeightOf<T>>::burn_from())]855 #[weight(<SelfWeightOf<T>>::burn_from())]876 fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result<void> {856 fn burn_from(&mut self, caller: Caller, from: Address, token_id: U256) -> Result<()> {877 let caller = T::CrossAccountId::from_eth(caller);857 let caller = T::CrossAccountId::from_eth(caller);878 let from = T::CrossAccountId::from_eth(from);858 let from = T::CrossAccountId::from_eth(from);879 let token = token_id.try_into()?;859 let token = token_id.try_into()?;895 #[weight(<SelfWeightOf<T>>::burn_from())]875 #[weight(<SelfWeightOf<T>>::burn_from())]896 fn burn_from_cross(876 fn burn_from_cross(897 &mut self,877 &mut self,898 caller: caller,878 caller: Caller,899 from: eth::CrossAddress,879 from: eth::CrossAddress,900 token_id: uint256,880 token_id: U256,901 ) -> Result<void> {881 ) -> Result<()> {902 let caller = T::CrossAccountId::from_eth(caller);882 let caller = T::CrossAccountId::from_eth(caller);903 let from = from.into_sub_cross_account::<T>()?;883 let from = from.into_sub_cross_account::<T>()?;904 let token = token_id.try_into()?;884 let token = token_id.try_into()?;912 }892 }913893914 /// @notice Returns next free NFT ID.894 /// @notice Returns next free NFT ID.915 fn next_token_id(&self) -> Result<uint256> {895 fn next_token_id(&self) -> Result<U256> {916 self.consume_store_reads(1)?;896 self.consume_store_reads(1)?;917 Ok(<TokensMinted<T>>::get(self.id)897 Ok(<TokensMinted<T>>::get(self.id)918 .checked_add(1)898 .checked_add(1)927 /// @param tokenIds IDs of the minted NFTs907 /// @param tokenIds IDs of the minted NFTs928 #[solidity(hide)]908 #[solidity(hide)]929 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]909 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]930 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {910 fn mint_bulk(&mut self, caller: Caller, to: Address, token_ids: Vec<U256>) -> Result<bool> {931 let caller = T::CrossAccountId::from_eth(caller);911 let caller = T::CrossAccountId::from_eth(caller);932 let to = T::CrossAccountId::from_eth(to);912 let to = T::CrossAccountId::from_eth(to);933 let mut expected_index = <TokensMinted<T>>::get(self.id)913 let mut expected_index = <TokensMinted<T>>::get(self.id)966 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]946 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]967 fn mint_bulk_with_token_uri(947 fn mint_bulk_with_token_uri(968 &mut self,948 &mut self,969 caller: caller,949 caller: Caller,970 to: address,950 to: Address,971 tokens: Vec<(uint256, string)>,951 tokens: Vec<(U256, String)>,972 ) -> Result<bool> {952 ) -> Result<bool> {973 let key = key::url();953 let key = key::url();974 let caller = T::CrossAccountId::from_eth(caller);954 let caller = T::CrossAccountId::from_eth(caller);1017 #[weight(<SelfWeightOf<T>>::create_item())]997 #[weight(<SelfWeightOf<T>>::create_item())]1018 fn mint_cross(998 fn mint_cross(1019 &mut self,999 &mut self,1020 caller: caller,1000 caller: Caller,1021 to: eth::CrossAddress,1001 to: eth::CrossAddress,1022 properties: Vec<eth::Property>,1002 properties: Vec<eth::Property>,1023 ) -> Result<uint256> {1003 ) -> Result<U256> {1024 let token_id = <TokensMinted<T>>::get(self.id)1004 let token_id = <TokensMinted<T>>::get(self.id)1025 .checked_add(1)1005 .checked_add(1)1026 .ok_or("item id overflow")?;1006 .ok_or("item id overflow")?;1055 }1035 }105610361057 /// @notice Returns collection helper contract address1037 /// @notice Returns collection helper contract address1058 fn collection_helper_address(&self) -> Result<address> {1038 fn collection_helper_address(&self) -> Result<Address> {1059 Ok(T::ContractAddress::get())1039 Ok(T::ContractAddress::get())1060 }1040 }1061}1041}pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth416416417 /// Set the collection access method.417 /// Set the collection access method.418 /// @param mode Access mode418 /// @param mode Access mode419 /// 0 for Normal420 /// 1 for AllowList421 /// @dev EVM selector for this function is: 0x41835d4c,419 /// @dev EVM selector for this function is: 0x41835d4c,422 /// or in textual repr: setCollectionAccess(uint8)420 /// or in textual repr: setCollectionAccess(uint8)423 function setCollectionAccess(uint8 mode) public {421 function setCollectionAccess(AccessMode mode) public {424 require(false, stub_error);422 require(false, stub_error);425 mode;423 mode;426 dummy = 0;424 dummy = 0;585 uint256 sub;583 uint256 sub;586}584}585586/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).587enum AccessMode {588 /// Access grant for owner and admins. Used as default.589 Normal,590 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.591 AllowList592}587593588/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.594/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.589struct CollectionNestingPermission {595struct CollectionNestingPermission {700 }706 }701}707}702703/// @dev inlined interface704contract ERC721UniqueMintableEvents {705 event MintingFinished();706}707708708/// @title ERC721 minting logic.709/// @title ERC721 minting logic.709/// @dev the ERC-165 identifier for this interface is 0x476ff149710/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6710contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {711contract ERC721UniqueMintable is Dummy, ERC165 {711 /// @dev EVM selector for this function is: 0x05d2035b,712 /// or in textual repr: mintingFinished()713 function mintingFinished() public view returns (bool) {714 require(false, stub_error);715 dummy;716 return false;717 }718719 /// @notice Function to mint a token.712 /// @notice Function to mint a token.720 /// @param to The new owner713 /// @param to The new owner774 // return false;766 // return false;775 // }767 // }776768777 /// @dev Not implemented778 /// @dev EVM selector for this function is: 0x7d64bcb4,779 /// or in textual repr: finishMinting()780 function finishMinting() public returns (bool) {781 require(false, stub_error);782 dummy = 0;783 return false;784 }785}769}786770787/// @title Unique extensions for ERC721.771/// @title Unique extensions for ERC721.pallets/refungible/src/erc.rsdiffbeforeafterboth39use pallet_evm::{account::CrossAccountId, PrecompileHandle};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};40use pallet_evm_coder_substrate::{call, dispatch_to_evm};40use pallet_evm_coder_substrate::{call, dispatch_to_evm};41use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};41use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};42use sp_core::{H160, Get};42use sp_core::{H160, U256, Get};43use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};43use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};44use up_data_structs::{44use up_data_structs::{45 CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey,45 CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey,66 #[solidity(hide)]66 #[solidity(hide)]67 fn set_token_property_permission(67 fn set_token_property_permission(68 &mut self,68 &mut self,69 caller: caller,69 caller: Caller,70 key: string,70 key: String,71 is_mutable: bool,71 is_mutable: bool,72 collection_admin: bool,72 collection_admin: bool,73 token_owner: bool,73 token_owner: bool,96 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]96 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]97 fn set_token_property_permissions(97 fn set_token_property_permissions(98 &mut self,98 &mut self,99 caller: caller,99 caller: Caller,100 permissions: Vec<eth::TokenPropertyPermission>,100 permissions: Vec<eth::TokenPropertyPermission>,101 ) -> Result<()> {101 ) -> Result<()> {102 let caller = T::CrossAccountId::from_eth(caller);102 let caller = T::CrossAccountId::from_eth(caller);124 #[weight(<SelfWeightOf<T>>::set_token_properties(1))]124 #[weight(<SelfWeightOf<T>>::set_token_properties(1))]125 fn set_property(125 fn set_property(126 &mut self,126 &mut self,127 caller: caller,127 caller: Caller,128 token_id: uint256,128 token_id: U256,129 key: string,129 key: String,130 value: bytes,130 value: Bytes,131 ) -> Result<()> {131 ) -> Result<()> {132 let caller = T::CrossAccountId::from_eth(caller);132 let caller = T::CrossAccountId::from_eth(caller);133 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;133 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;157 #[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]157 #[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]158 fn set_properties(158 fn set_properties(159 &mut self,159 &mut self,160 caller: caller,160 caller: Caller,161 token_id: uint256,161 token_id: U256,162 properties: Vec<eth::Property>,162 properties: Vec<eth::Property>,163 ) -> Result<()> {163 ) -> Result<()> {164 let caller = T::CrossAccountId::from_eth(caller);164 let caller = T::CrossAccountId::from_eth(caller);190 /// @param key Property key.190 /// @param key Property key.191 #[solidity(hide)]191 #[solidity(hide)]192 #[weight(<SelfWeightOf<T>>::delete_token_properties(1))]192 #[weight(<SelfWeightOf<T>>::delete_token_properties(1))]193 fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {193 fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> {194 let caller = T::CrossAccountId::from_eth(caller);194 let caller = T::CrossAccountId::from_eth(caller);195 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;195 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;196 let key = <Vec<u8>>::from(key)196 let key = <Vec<u8>>::from(key)212 #[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]212 #[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]213 fn delete_properties(213 fn delete_properties(214 &mut self,214 &mut self,215 token_id: uint256,215 token_id: U256,216 caller: caller,216 caller: Caller,217 keys: Vec<string>,217 keys: Vec<String>,218 ) -> Result<()> {218 ) -> Result<()> {219 let caller = T::CrossAccountId::from_eth(caller);219 let caller = T::CrossAccountId::from_eth(caller);220 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;220 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;242 /// @param tokenId ID of the token.242 /// @param tokenId ID of the token.243 /// @param key Property key.243 /// @param key Property key.244 /// @return Property value bytes244 /// @return Property value bytes245 fn property(&self, token_id: uint256, key: string) -> Result<bytes> {245 fn property(&self, token_id: U256, key: String) -> Result<Bytes> {246 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;246 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;247 let key = <Vec<u8>>::from(key)247 let key = <Vec<u8>>::from(key)248 .try_into()248 .try_into()262 /// may be created and assigned without emitting Transfer.262 /// may be created and assigned without emitting Transfer.263 Transfer {263 Transfer {264 #[indexed]264 #[indexed]265 from: address,265 from: Address,266 #[indexed]266 #[indexed]267 to: address,267 to: Address,268 #[indexed]268 #[indexed]269 token_id: uint256,269 token_id: U256,270 },270 },271 /// @dev Not supported271 /// @dev Not supported272 Approval {272 Approval {273 #[indexed]273 #[indexed]274 owner: address,274 owner: Address,275 #[indexed]275 #[indexed]276 approved: address,276 approved: Address,277 #[indexed]277 #[indexed]278 token_id: uint256,278 token_id: U256,279 },279 },280 /// @dev Not supported280 /// @dev Not supported281 #[allow(dead_code)]281 #[allow(dead_code)]282 ApprovalForAll {282 ApprovalForAll {283 #[indexed]283 #[indexed]284 owner: address,284 owner: Address,285 #[indexed]285 #[indexed]286 operator: address,286 operator: Address,287 approved: bool,287 approved: bool,288 },288 },289}289}290291#[derive(ToLog)]292pub enum ERC721UniqueMintableEvents {293 /// @dev Not supported294 #[allow(dead_code)]295 MintingFinished {},296}297290298/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension291/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension299/// @dev See https://eips.ethereum.org/EIPS/eip-721292/// @dev See https://eips.ethereum.org/EIPS/eip-721305 /// @notice A descriptive name for a collection of NFTs in this contract298 /// @notice A descriptive name for a collection of NFTs in this contract306 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`299 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`307 #[solidity(hide, rename_selector = "name")]300 #[solidity(hide, rename_selector = "name")]308 fn name_proxy(&self) -> Result<string> {301 fn name_proxy(&self) -> Result<String> {309 self.name()302 self.name()310 }303 }311304312 /// @notice An abbreviated name for NFTs in this contract305 /// @notice An abbreviated name for NFTs in this contract313 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`306 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`314 #[solidity(hide, rename_selector = "symbol")]307 #[solidity(hide, rename_selector = "symbol")]315 fn symbol_proxy(&self) -> Result<string> {308 fn symbol_proxy(&self) -> Result<String> {316 self.symbol()309 self.symbol()317 }310 }318311326 ///319 ///327 /// @return token's const_metadata320 /// @return token's const_metadata328 #[solidity(rename_selector = "tokenURI")]321 #[solidity(rename_selector = "tokenURI")]329 fn token_uri(&self, token_id: uint256) -> Result<string> {322 fn token_uri(&self, token_id: U256) -> Result<String> {330 let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;323 let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;331324332 match get_token_property(self, token_id_u32, &key::url()).as_deref() {325 match get_token_property(self, token_id_u32, &key::url()).as_deref() {339 let base_uri =332 let base_uri =340 pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())333 pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())341 .map(BoundedVec::into_inner)334 .map(BoundedVec::into_inner)342 .map(string::from_utf8)335 .map(String::from_utf8)343 .transpose()336 .transpose()344 .map_err(|e| {337 .map_err(|e| {345 Error::Revert(alloc::format!(338 Error::Revert(alloc::format!(372 /// @param index A counter less than `totalSupply()`365 /// @param index A counter less than `totalSupply()`373 /// @return The token identifier for the `index`th NFT,366 /// @return The token identifier for the `index`th NFT,374 /// (sort order not specified)367 /// (sort order not specified)375 fn token_by_index(&self, index: uint256) -> Result<uint256> {368 fn token_by_index(&self, index: U256) -> Result<U256> {376 Ok(index)369 Ok(index)377 }370 }378371379 /// Not implemented372 /// Not implemented380 fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {373 fn token_of_owner_by_index(&self, _owner: Address, _index: U256) -> Result<U256> {381 // TODO: Not implemetable374 // TODO: Not implemetable382 Err("not implemented".into())375 Err("not implemented".into())383 }376 }384377385 /// @notice Count RFTs tracked by this contract378 /// @notice Count RFTs tracked by this contract386 /// @return A count of valid RFTs tracked by this contract, where each one of379 /// @return A count of valid RFTs tracked by this contract, where each one of387 /// them has an assigned and queryable owner not equal to the zero address380 /// them has an assigned and queryable owner not equal to the zero address388 fn total_supply(&self) -> Result<uint256> {381 fn total_supply(&self) -> Result<U256> {389 self.consume_store_reads(1)?;382 self.consume_store_reads(1)?;390 Ok(<Pallet<T>>::total_supply(self).into())383 Ok(<Pallet<T>>::total_supply(self).into())391 }384 }400 /// function throws for queries about the zero address.393 /// function throws for queries about the zero address.401 /// @param owner An address for whom to query the balance394 /// @param owner An address for whom to query the balance402 /// @return The number of RFTs owned by `owner`, possibly zero395 /// @return The number of RFTs owned by `owner`, possibly zero403 fn balance_of(&self, owner: address) -> Result<uint256> {396 fn balance_of(&self, owner: Address) -> Result<U256> {404 self.consume_store_reads(1)?;397 self.consume_store_reads(1)?;405 let owner = T::CrossAccountId::from_eth(owner);398 let owner = T::CrossAccountId::from_eth(owner);406 let balance = <AccountBalance<T>>::get((self.id, owner));399 let balance = <AccountBalance<T>>::get((self.id, owner));414 /// the tokens that are partially owned.407 /// the tokens that are partially owned.415 /// @param tokenId The identifier for an RFT408 /// @param tokenId The identifier for an RFT416 /// @return The address of the owner of the RFT409 /// @return The address of the owner of the RFT417 fn owner_of(&self, token_id: uint256) -> Result<address> {410 fn owner_of(&self, token_id: U256) -> Result<Address> {418 self.consume_store_reads(2)?;411 self.consume_store_reads(2)?;419 let token = token_id.try_into()?;412 let token = token_id.try_into()?;420 let owner = <Pallet<T>>::token_owner(self.id, token);413 let owner = <Pallet<T>>::token_owner(self.id, token);427 #[solidity(rename_selector = "safeTransferFrom")]420 #[solidity(rename_selector = "safeTransferFrom")]428 fn safe_transfer_from_with_data(421 fn safe_transfer_from_with_data(429 &mut self,422 &mut self,430 _from: address,423 _from: Address,431 _to: address,424 _to: Address,432 _token_id: uint256,425 _token_id: U256,433 _data: bytes,426 _data: Bytes,434 ) -> Result<void> {427 ) -> Result<()> {435 // TODO: Not implemetable428 // TODO: Not implemetable436 Err("not implemented".into())429 Err("not implemented".into())437 }430 }438431439 /// @dev Not implemented432 /// @dev Not implemented440 #[solidity(rename_selector = "safeTransferFrom")]433 #[solidity(rename_selector = "safeTransferFrom")]441 fn safe_transfer_from(434 fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {442 &mut self,443 _from: address,444 _to: address,445 _token_id: uint256,446 ) -> Result<void> {447 // TODO: Not implemetable435 // TODO: Not implemetable448 Err("not implemented".into())436 Err("not implemented".into())449 }437 }461 #[weight(<SelfWeightOf<T>>::transfer_from_creating_removing())]449 #[weight(<SelfWeightOf<T>>::transfer_from_creating_removing())]462 fn transfer_from(450 fn transfer_from(463 &mut self,451 &mut self,464 caller: caller,452 caller: Caller,465 from: address,453 from: Address,466 to: address,454 to: Address,467 token_id: uint256,455 token_id: U256,468 ) -> Result<void> {456 ) -> Result<()> {469 let caller = T::CrossAccountId::from_eth(caller);457 let caller = T::CrossAccountId::from_eth(caller);470 let from = T::CrossAccountId::from_eth(from);458 let from = T::CrossAccountId::from_eth(from);471 let to = T::CrossAccountId::from_eth(to);459 let to = T::CrossAccountId::from_eth(to);484 }472 }485473486 /// @dev Not implemented474 /// @dev Not implemented487 fn approve(&mut self, _caller: caller, _approved: address, _token_id: uint256) -> Result<void> {475 fn approve(&mut self, _caller: Caller, _approved: Address, _token_id: U256) -> Result<()> {488 Err("not implemented".into())476 Err("not implemented".into())489 }477 }490478495 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]483 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]496 fn set_approval_for_all(484 fn set_approval_for_all(497 &mut self,485 &mut self,498 caller: caller,486 caller: Caller,499 operator: address,487 operator: Address,500 approved: bool,488 approved: bool,501 ) -> Result<void> {489 ) -> Result<()> {502 let caller = T::CrossAccountId::from_eth(caller);490 let caller = T::CrossAccountId::from_eth(caller);503 let operator = T::CrossAccountId::from_eth(operator);491 let operator = T::CrossAccountId::from_eth(operator);504492508 }496 }509497510 /// @dev Not implemented498 /// @dev Not implemented511 fn get_approved(&self, _token_id: uint256) -> Result<address> {499 fn get_approved(&self, _token_id: U256) -> Result<Address> {512 // TODO: Not implemetable500 // TODO: Not implemetable513 Err("not implemented".into())501 Err("not implemented".into())514 }502 }515503516 /// @notice Tells whether the given `owner` approves the `operator`.504 /// @notice Tells whether the given `owner` approves the `operator`.517 #[weight(<SelfWeightOf<T>>::allowance_for_all())]505 #[weight(<SelfWeightOf<T>>::allowance_for_all())]518 fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {506 fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {519 let owner = T::CrossAccountId::from_eth(owner);507 let owner = T::CrossAccountId::from_eth(owner);520 let operator = T::CrossAccountId::from_eth(operator);508 let operator = T::CrossAccountId::from_eth(operator);521509563 /// operator of the current owner.551 /// operator of the current owner.564 /// @param tokenId The RFT to approve552 /// @param tokenId The RFT to approve565 #[weight(<SelfWeightOf<T>>::burn_item_fully())]553 #[weight(<SelfWeightOf<T>>::burn_item_fully())]566 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {554 fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {567 let caller = T::CrossAccountId::from_eth(caller);555 let caller = T::CrossAccountId::from_eth(caller);568 let token = token_id.try_into()?;556 let token = token_id.try_into()?;569557576}564}577565578/// @title ERC721 minting logic.566/// @title ERC721 minting logic.579#[solidity_interface(name = ERC721UniqueMintable, events(ERC721UniqueMintableEvents))]567#[solidity_interface(name = ERC721UniqueMintable)]580impl<T: Config> RefungibleHandle<T> {568impl<T: Config> RefungibleHandle<T> {581 fn minting_finished(&self) -> Result<bool> {582 Ok(false)583 }584585 /// @notice Function to mint a token.569 /// @notice Function to mint a token.586 /// @param to The new owner570 /// @param to The new owner587 /// @return uint256 The id of the newly minted token571 /// @return uint256 The id of the newly minted token588 #[weight(<SelfWeightOf<T>>::create_item())]572 #[weight(<SelfWeightOf<T>>::create_item())]589 fn mint(&mut self, caller: caller, to: address) -> Result<uint256> {573 fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {590 let token_id: uint256 = <TokensMinted<T>>::get(self.id)574 let token_id: U256 = <TokensMinted<T>>::get(self.id)591 .checked_add(1)575 .checked_add(1)592 .ok_or("item id overflow")?576 .ok_or("item id overflow")?593 .into();577 .into();602 /// @param tokenId ID of the minted RFT586 /// @param tokenId ID of the minted RFT603 #[solidity(hide, rename_selector = "mint")]587 #[solidity(hide, rename_selector = "mint")]604 #[weight(<SelfWeightOf<T>>::create_item())]588 #[weight(<SelfWeightOf<T>>::create_item())]605 fn mint_check_id(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {589 fn mint_check_id(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<bool> {606 let caller = T::CrossAccountId::from_eth(caller);590 let caller = T::CrossAccountId::from_eth(caller);607 let to = T::CrossAccountId::from_eth(to);591 let to = T::CrossAccountId::from_eth(to);608 let token_id: u32 = token_id.try_into()?;592 let token_id: u32 = token_id.try_into()?;645 #[weight(<SelfWeightOf<T>>::create_item())]629 #[weight(<SelfWeightOf<T>>::create_item())]646 fn mint_with_token_uri(630 fn mint_with_token_uri(647 &mut self,631 &mut self,648 caller: caller,632 caller: Caller,649 to: address,633 to: Address,650 token_uri: string,634 token_uri: String,651 ) -> Result<uint256> {635 ) -> Result<U256> {652 let token_id: uint256 = <TokensMinted<T>>::get(self.id)636 let token_id: U256 = <TokensMinted<T>>::get(self.id)653 .checked_add(1)637 .checked_add(1)654 .ok_or("item id overflow")?638 .ok_or("item id overflow")?655 .into();639 .into();667 #[weight(<SelfWeightOf<T>>::create_item())]651 #[weight(<SelfWeightOf<T>>::create_item())]668 fn mint_with_token_uri_check_id(652 fn mint_with_token_uri_check_id(669 &mut self,653 &mut self,670 caller: caller,654 caller: Caller,671 to: address,655 to: Address,672 token_id: uint256,656 token_id: U256,673 token_uri: string,657 token_uri: String,674 ) -> Result<bool> {658 ) -> Result<bool> {675 let key = key::url();659 let key = key::url();676 let permission = get_token_permission::<T>(self.id, &key)?;660 let permission = get_token_permission::<T>(self.id, &key)?;719 Ok(true)703 Ok(true)720 }704 }721722 /// @dev Not implemented723 fn finish_minting(&mut self, _caller: caller) -> Result<bool> {724 Err("not implementable".into())725 }726}705}727706728fn get_token_property<T: Config>(707fn get_token_property<T: Config>(729 collection: &CollectionHandle<T>,708 collection: &CollectionHandle<T>,730 token_id: u32,709 token_id: u32,731 key: &up_data_structs::PropertyKey,710 key: &up_data_structs::PropertyKey,732) -> Result<string> {711) -> Result<String> {733 collection.consume_store_reads(1)?;712 collection.consume_store_reads(1)?;734 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))713 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))735 .map_err(|_| Error::Revert("Token properties not found".into()))?;714 .map_err(|_| Error::Revert("Token properties not found".into()))?;736 if let Some(property) = properties.get(key) {715 if let Some(property) = properties.get(key) {737 return Ok(string::from_utf8_lossy(property).into());716 return Ok(String::from_utf8_lossy(property).into());738 }717 }739718740 Err("Property tokenURI not found".into())719 Err("Property tokenURI not found".into())750 .get(key)729 .get(key)751 .map(Clone::clone)730 .map(Clone::clone)752 .ok_or_else(|| {731 .ok_or_else(|| {753 let key = string::from_utf8(key.clone().into_inner()).unwrap_or_default();732 let key = String::from_utf8(key.clone().into_inner()).unwrap_or_default();754 Error::Revert(alloc::format!("No permission for key {}", key))733 Error::Revert(alloc::format!("No permission for key {}", key))755 })?;734 })?;756 Ok(a)735 Ok(a)763 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,742 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,764{743{765 /// @notice A descriptive name for a collection of NFTs in this contract744 /// @notice A descriptive name for a collection of NFTs in this contract766 fn name(&self) -> Result<string> {745 fn name(&self) -> Result<String> {767 Ok(decode_utf16(self.name.iter().copied())746 Ok(decode_utf16(self.name.iter().copied())768 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))747 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))769 .collect::<string>())748 .collect::<String>())770 }749 }771750772 /// @notice An abbreviated name for NFTs in this contract751 /// @notice An abbreviated name for NFTs in this contract773 fn symbol(&self) -> Result<string> {752 fn symbol(&self) -> Result<String> {774 Ok(string::from_utf8_lossy(&self.token_prefix).into())753 Ok(String::from_utf8_lossy(&self.token_prefix).into())775 }754 }776755777 /// @notice A description for the collection.756 /// @notice A description for the collection.778 fn description(&self) -> Result<string> {757 fn description(&self) -> Result<String> {779 Ok(decode_utf16(self.description.iter().copied())758 Ok(decode_utf16(self.description.iter().copied())780 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))759 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))781 .collect::<string>())760 .collect::<String>())782 }761 }783762784 /// Returns the owner (in cross format) of the token.763 /// Returns the owner (in cross format) of the token.785 ///764 ///786 /// @param tokenId Id for the token.765 /// @param tokenId Id for the token.787 fn cross_owner_of(&self, token_id: uint256) -> Result<eth::CrossAddress> {766 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {788 Self::token_owner(&self, token_id.try_into()?)767 Self::token_owner(&self, token_id.try_into()?)789 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))768 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))790 .ok_or(Error::Revert("key too large".into()))769 .ok_or(Error::Revert("key too large".into()))795 /// @param tokenId Id for the token.774 /// @param tokenId Id for the token.796 /// @param keys Properties keys. Empty keys for all propertyes.775 /// @param keys Properties keys. Empty keys for all propertyes.797 /// @return Vector of properties key/value pairs.776 /// @return Vector of properties key/value pairs.798 fn properties(&self, token_id: uint256, keys: Vec<string>) -> Result<Vec<eth::Property>> {777 fn properties(&self, token_id: U256, keys: Vec<String>) -> Result<Vec<eth::Property>> {799 let keys = keys778 let keys = keys800 .into_iter()779 .into_iter()801 .map(|key| {780 .map(|key| {821 /// @param to The new owner800 /// @param to The new owner822 /// @param tokenId The RFT to transfer801 /// @param tokenId The RFT to transfer823 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]802 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]824 fn transfer(&mut self, caller: caller, to: address, token_id: uint256) -> Result<void> {803 fn transfer(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<()> {825 let caller = T::CrossAccountId::from_eth(caller);804 let caller = T::CrossAccountId::from_eth(caller);826 let to = T::CrossAccountId::from_eth(to);805 let to = T::CrossAccountId::from_eth(to);827 let token = token_id.try_into()?;806 let token = token_id.try_into()?;846 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]825 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]847 fn transfer_cross(826 fn transfer_cross(848 &mut self,827 &mut self,849 caller: caller,828 caller: Caller,850 to: eth::CrossAddress,829 to: eth::CrossAddress,851 token_id: uint256,830 token_id: U256,852 ) -> Result<void> {831 ) -> Result<()> {853 let caller = T::CrossAccountId::from_eth(caller);832 let caller = T::CrossAccountId::from_eth(caller);854 let to = to.into_sub_cross_account::<T>()?;833 let to = to.into_sub_cross_account::<T>()?;855 let token = token_id.try_into()?;834 let token = token_id.try_into()?;874 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]853 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]875 fn transfer_from_cross(854 fn transfer_from_cross(876 &mut self,855 &mut self,877 caller: caller,856 caller: Caller,878 from: eth::CrossAddress,857 from: eth::CrossAddress,879 to: eth::CrossAddress,858 to: eth::CrossAddress,880 token_id: uint256,859 token_id: U256,881 ) -> Result<void> {860 ) -> Result<()> {882 let caller = T::CrossAccountId::from_eth(caller);861 let caller = T::CrossAccountId::from_eth(caller);883 let from = from.into_sub_cross_account::<T>()?;862 let from = from.into_sub_cross_account::<T>()?;884 let to = to.into_sub_cross_account::<T>()?;863 let to = to.into_sub_cross_account::<T>()?;904 /// @param tokenId The RFT to transfer883 /// @param tokenId The RFT to transfer905 #[solidity(hide)]884 #[solidity(hide)]906 #[weight(<SelfWeightOf<T>>::burn_from())]885 #[weight(<SelfWeightOf<T>>::burn_from())]907 fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result<void> {886 fn burn_from(&mut self, caller: Caller, from: Address, token_id: U256) -> Result<()> {908 let caller = T::CrossAccountId::from_eth(caller);887 let caller = T::CrossAccountId::from_eth(caller);909 let from = T::CrossAccountId::from_eth(from);888 let from = T::CrossAccountId::from_eth(from);910 let token = token_id.try_into()?;889 let token = token_id.try_into()?;930 #[weight(<SelfWeightOf<T>>::burn_from())]909 #[weight(<SelfWeightOf<T>>::burn_from())]931 fn burn_from_cross(910 fn burn_from_cross(932 &mut self,911 &mut self,933 caller: caller,912 caller: Caller,934 from: eth::CrossAddress,913 from: eth::CrossAddress,935 token_id: uint256,914 token_id: U256,936 ) -> Result<void> {915 ) -> Result<()> {937 let caller = T::CrossAccountId::from_eth(caller);916 let caller = T::CrossAccountId::from_eth(caller);938 let from = from.into_sub_cross_account::<T>()?;917 let from = from.into_sub_cross_account::<T>()?;939 let token = token_id.try_into()?;918 let token = token_id.try_into()?;950 }929 }951930952 /// @notice Returns next free RFT ID.931 /// @notice Returns next free RFT ID.953 fn next_token_id(&self) -> Result<uint256> {932 fn next_token_id(&self) -> Result<U256> {954 self.consume_store_reads(1)?;933 self.consume_store_reads(1)?;955 Ok(<TokensMinted<T>>::get(self.id)934 Ok(<TokensMinted<T>>::get(self.id)956 .checked_add(1)935 .checked_add(1)965 /// @param tokenIds IDs of the minted RFTs944 /// @param tokenIds IDs of the minted RFTs966 #[solidity(hide)]945 #[solidity(hide)]967 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]946 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]968 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {947 fn mint_bulk(&mut self, caller: Caller, to: Address, token_ids: Vec<U256>) -> Result<bool> {969 let caller = T::CrossAccountId::from_eth(caller);948 let caller = T::CrossAccountId::from_eth(caller);970 let to = T::CrossAccountId::from_eth(to);949 let to = T::CrossAccountId::from_eth(to);971 let mut expected_index = <TokensMinted<T>>::get(self.id)950 let mut expected_index = <TokensMinted<T>>::get(self.id)1010 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]989 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]1011 fn mint_bulk_with_token_uri(990 fn mint_bulk_with_token_uri(1012 &mut self,991 &mut self,1013 caller: caller,992 caller: Caller,1014 to: address,993 to: Address,1015 tokens: Vec<(uint256, string)>,994 tokens: Vec<(U256, String)>,1016 ) -> Result<bool> {995 ) -> Result<bool> {1017 let key = key::url();996 let key = key::url();1018 let caller = T::CrossAccountId::from_eth(caller);997 let caller = T::CrossAccountId::from_eth(caller);1067 #[weight(<SelfWeightOf<T>>::create_item())]1046 #[weight(<SelfWeightOf<T>>::create_item())]1068 fn mint_cross(1047 fn mint_cross(1069 &mut self,1048 &mut self,1070 caller: caller,1049 caller: Caller,1071 to: eth::CrossAddress,1050 to: eth::CrossAddress,1072 properties: Vec<eth::Property>,1051 properties: Vec<eth::Property>,1073 ) -> Result<uint256> {1052 ) -> Result<U256> {1074 let token_id = <TokensMinted<T>>::get(self.id)1053 let token_id = <TokensMinted<T>>::get(self.id)1075 .checked_add(1)1054 .checked_add(1)1076 .ok_or("item id overflow")?;1055 .ok_or("item id overflow")?;1109 /// Returns EVM address for refungible token1088 /// Returns EVM address for refungible token1110 ///1089 ///1111 /// @param token ID of the token1090 /// @param token ID of the token1112 fn token_contract_address(&self, token: uint256) -> Result<address> {1091 fn token_contract_address(&self, token: U256) -> Result<Address> {1113 Ok(T::EvmTokenAddressMapping::token_to_address(1092 Ok(T::EvmTokenAddressMapping::token_to_address(1114 self.id,1093 self.id,1115 token.try_into().map_err(|_| "token id overflow")?,1094 token.try_into().map_err(|_| "token id overflow")?,1116 ))1095 ))1117 }1096 }111810971119 /// @notice Returns collection helper contract address1098 /// @notice Returns collection helper contract address1120 fn collection_helper_address(&self) -> Result<address> {1099 fn collection_helper_address(&self) -> Result<Address> {1121 Ok(T::ContractAddress::get())1100 Ok(T::ContractAddress::get())1122 }1101 }1123}1102}pallets/refungible/src/erc_token.rsdiffbeforeafterboth25 ops::Deref,25 ops::Deref,26};26};27use evm_coder::{27use evm_coder::{28 abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight,28 abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, solidity, types::*,29 weight,29};30};30use pallet_common::{31use pallet_common::{36use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};37use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};37use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};38use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};38use sp_std::vec::Vec;39use sp_std::vec::Vec;40use sp_core::U256;39use up_data_structs::TokenId;41use up_data_structs::TokenId;404241use crate::{43use crate::{505251#[solidity_interface(name = ERC1633)]53#[solidity_interface(name = ERC1633)]52impl<T: Config> RefungibleTokenHandle<T> {54impl<T: Config> RefungibleTokenHandle<T> {53 fn parent_token(&self) -> Result<address> {55 fn parent_token(&self) -> Result<Address> {54 Ok(collection_id_to_address(self.id))56 Ok(collection_id_to_address(self.id))55 }57 }565857 fn parent_token_id(&self) -> Result<uint256> {59 fn parent_token_id(&self) -> Result<U256> {58 Ok(self.1.into())60 Ok(self.1.into())59 }61 }60}62}67 /// of burning tokens the transfer is to 0.69 /// of burning tokens the transfer is to 0.68 Transfer {70 Transfer {69 #[indexed]71 #[indexed]70 from: address,72 from: Address,71 #[indexed]73 #[indexed]72 to: address,74 to: Address,73 value: uint256,75 value: U256,74 },76 },75 /// @dev This event is emitted when the amount of tokens (value) is approved77 /// @dev This event is emitted when the amount of tokens (value) is approved76 /// by the owner to be used by the spender.78 /// by the owner to be used by the spender.77 Approval {79 Approval {78 #[indexed]80 #[indexed]79 owner: address,81 owner: Address,80 #[indexed]82 #[indexed]81 spender: address,83 spender: Address,82 value: uint256,84 value: U256,83 },85 },84}86}858790#[solidity_interface(name = ERC20, events(ERC20Events))]92#[solidity_interface(name = ERC20, events(ERC20Events))]91impl<T: Config> RefungibleTokenHandle<T> {93impl<T: Config> RefungibleTokenHandle<T> {92 /// @return the name of the token.94 /// @return the name of the token.93 fn name(&self) -> Result<string> {95 fn name(&self) -> Result<String> {94 Ok(decode_utf16(self.name.iter().copied())96 Ok(decode_utf16(self.name.iter().copied())95 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))97 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))96 .collect::<string>())98 .collect::<String>())97 }99 }9810099 /// @return the symbol of the token.101 /// @return the symbol of the token.100 fn symbol(&self) -> Result<string> {102 fn symbol(&self) -> Result<String> {101 Ok(string::from_utf8_lossy(&self.token_prefix).into())103 Ok(String::from_utf8_lossy(&self.token_prefix).into())102 }104 }103105104 /// @dev Total number of tokens in existence106 /// @dev Total number of tokens in existence105 fn total_supply(&self) -> Result<uint256> {107 fn total_supply(&self) -> Result<U256> {106 self.consume_store_reads(1)?;108 self.consume_store_reads(1)?;107 Ok(<TotalSupply<T>>::get((self.id, self.1)).into())109 Ok(<TotalSupply<T>>::get((self.id, self.1)).into())108 }110 }109111110 /// @dev Not supported112 /// @dev Not supported111 fn decimals(&self) -> Result<uint8> {113 fn decimals(&self) -> Result<u8> {112 // Decimals aren't supported for refungible tokens114 // Decimals aren't supported for refungible tokens113 Ok(0)115 Ok(0)114 }116 }115117116 /// @dev Gets the balance of the specified address.118 /// @dev Gets the balance of the specified address.117 /// @param owner The address to query the balance of.119 /// @param owner The address to query the balance of.118 /// @return An uint256 representing the amount owned by the passed address.120 /// @return An uint256 representing the amount owned by the passed address.119 fn balance_of(&self, owner: address) -> Result<uint256> {121 fn balance_of(&self, owner: Address) -> Result<U256> {120 self.consume_store_reads(1)?;122 self.consume_store_reads(1)?;121 let owner = T::CrossAccountId::from_eth(owner);123 let owner = T::CrossAccountId::from_eth(owner);122 let balance = <Balance<T>>::get((self.id, self.1, owner));124 let balance = <Balance<T>>::get((self.id, self.1, owner));127 /// @param to The address to transfer to.129 /// @param to The address to transfer to.128 /// @param amount The amount to be transferred.130 /// @param amount The amount to be transferred.129 #[weight(<CommonWeights<T>>::transfer())]131 #[weight(<CommonWeights<T>>::transfer())]130 fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {132 fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {131 let caller = T::CrossAccountId::from_eth(caller);133 let caller = T::CrossAccountId::from_eth(caller);132 let to = T::CrossAccountId::from_eth(to);134 let to = T::CrossAccountId::from_eth(to);133 let amount = amount.try_into().map_err(|_| "amount overflow")?;135 let amount = amount.try_into().map_err(|_| "amount overflow")?;147 #[weight(<CommonWeights<T>>::transfer_from())]149 #[weight(<CommonWeights<T>>::transfer_from())]148 fn transfer_from(150 fn transfer_from(149 &mut self,151 &mut self,150 caller: caller,152 caller: Caller,151 from: address,153 from: Address,152 to: address,154 to: Address,153 amount: uint256,155 amount: U256,154 ) -> Result<bool> {156 ) -> Result<bool> {155 let caller = T::CrossAccountId::from_eth(caller);157 let caller = T::CrossAccountId::from_eth(caller);156 let from = T::CrossAccountId::from_eth(from);158 let from = T::CrossAccountId::from_eth(from);173 /// @param spender The address which will spend the funds.175 /// @param spender The address which will spend the funds.174 /// @param amount The amount of tokens to be spent.176 /// @param amount The amount of tokens to be spent.175 #[weight(<SelfWeightOf<T>>::approve())]177 #[weight(<SelfWeightOf<T>>::approve())]176 fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {178 fn approve(&mut self, caller: Caller, spender: Address, amount: U256) -> Result<bool> {177 let caller = T::CrossAccountId::from_eth(caller);179 let caller = T::CrossAccountId::from_eth(caller);178 let spender = T::CrossAccountId::from_eth(spender);180 let spender = T::CrossAccountId::from_eth(spender);179 let amount = amount.try_into().map_err(|_| "amount overflow")?;181 let amount = amount.try_into().map_err(|_| "amount overflow")?;187 /// @param owner address The address which owns the funds.189 /// @param owner address The address which owns the funds.188 /// @param spender address The address which will spend the funds.190 /// @param spender address The address which will spend the funds.189 /// @return A uint256 specifying the amount of tokens still available for the spender.191 /// @return A uint256 specifying the amount of tokens still available for the spender.190 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {192 fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {191 self.consume_store_reads(1)?;193 self.consume_store_reads(1)?;192 let owner = T::CrossAccountId::from_eth(owner);194 let owner = T::CrossAccountId::from_eth(owner);193 let spender = T::CrossAccountId::from_eth(spender);195 let spender = T::CrossAccountId::from_eth(spender);206 /// @param from The account whose tokens will be burnt.208 /// @param from The account whose tokens will be burnt.207 /// @param amount The amount that will be burnt.209 /// @param amount The amount that will be burnt.208 #[weight(<SelfWeightOf<T>>::burn_from())]210 #[weight(<SelfWeightOf<T>>::burn_from())]211 #[solidity(hide)]209 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {212 fn burn_from(&mut self, caller: Caller, from: Address, amount: U256) -> Result<bool> {210 let caller = T::CrossAccountId::from_eth(caller);213 let caller = T::CrossAccountId::from_eth(caller);211 let from = T::CrossAccountId::from_eth(from);214 let from = T::CrossAccountId::from_eth(from);212 let amount = amount.try_into().map_err(|_| "amount overflow")?;215 let amount = amount.try_into().map_err(|_| "amount overflow")?;226 #[weight(<SelfWeightOf<T>>::burn_from())]229 #[weight(<SelfWeightOf<T>>::burn_from())]227 fn burn_from_cross(230 fn burn_from_cross(228 &mut self,231 &mut self,229 caller: caller,232 caller: Caller,230 from: pallet_common::eth::CrossAddress,233 from: pallet_common::eth::CrossAddress,231 amount: uint256,234 amount: U256,232 ) -> Result<bool> {235 ) -> Result<bool> {233 let caller = T::CrossAccountId::from_eth(caller);236 let caller = T::CrossAccountId::from_eth(caller);234 let from = from.into_sub_cross_account::<T>()?;237 let from = from.into_sub_cross_account::<T>()?;252 #[weight(<SelfWeightOf<T>>::approve())]255 #[weight(<SelfWeightOf<T>>::approve())]253 fn approve_cross(256 fn approve_cross(254 &mut self,257 &mut self,255 caller: caller,258 caller: Caller,256 spender: pallet_common::eth::CrossAddress,259 spender: pallet_common::eth::CrossAddress,257 amount: uint256,260 amount: U256,258 ) -> Result<bool> {261 ) -> Result<bool> {259 let caller = T::CrossAccountId::from_eth(caller);262 let caller = T::CrossAccountId::from_eth(caller);260 let spender = spender.into_sub_cross_account::<T>()?;263 let spender = spender.into_sub_cross_account::<T>()?;268 /// Throws if `msg.sender` doesn't owns all of the tokens.271 /// Throws if `msg.sender` doesn't owns all of the tokens.269 /// @param amount New total amount of the tokens.272 /// @param amount New total amount of the tokens.270 #[weight(<SelfWeightOf<T>>::repartition_item())]273 #[weight(<SelfWeightOf<T>>::repartition_item())]271 fn repartition(&mut self, caller: caller, amount: uint256) -> Result<bool> {274 fn repartition(&mut self, caller: Caller, amount: U256) -> Result<bool> {272 let caller = T::CrossAccountId::from_eth(caller);275 let caller = T::CrossAccountId::from_eth(caller);273 let amount = amount.try_into().map_err(|_| "amount overflow")?;276 let amount = amount.try_into().map_err(|_| "amount overflow")?;274277282 #[weight(<CommonWeights<T>>::transfer())]285 #[weight(<CommonWeights<T>>::transfer())]283 fn transfer_cross(286 fn transfer_cross(284 &mut self,287 &mut self,285 caller: caller,288 caller: Caller,286 to: pallet_common::eth::CrossAddress,289 to: pallet_common::eth::CrossAddress,287 amount: uint256,290 amount: U256,288 ) -> Result<bool> {291 ) -> Result<bool> {289 let caller = T::CrossAccountId::from_eth(caller);292 let caller = T::CrossAccountId::from_eth(caller);290 let to = to.into_sub_cross_account::<T>()?;293 let to = to.into_sub_cross_account::<T>()?;305 #[weight(<CommonWeights<T>>::transfer_from())]308 #[weight(<CommonWeights<T>>::transfer_from())]306 fn transfer_from_cross(309 fn transfer_from_cross(307 &mut self,310 &mut self,308 caller: caller,311 caller: Caller,309 from: pallet_common::eth::CrossAddress,312 from: pallet_common::eth::CrossAddress,310 to: pallet_common::eth::CrossAddress,313 to: pallet_common::eth::CrossAddress,311 amount: uint256,314 amount: U256,312 ) -> Result<bool> {315 ) -> Result<bool> {313 let caller = T::CrossAccountId::from_eth(caller);316 let caller = T::CrossAccountId::from_eth(caller);314 let from = from.into_sub_cross_account::<T>()?;317 let from = from.into_sub_cross_account::<T>()?;pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth416416417 /// Set the collection access method.417 /// Set the collection access method.418 /// @param mode Access mode418 /// @param mode Access mode419 /// 0 for Normal420 /// 1 for AllowList421 /// @dev EVM selector for this function is: 0x41835d4c,419 /// @dev EVM selector for this function is: 0x41835d4c,422 /// or in textual repr: setCollectionAccess(uint8)420 /// or in textual repr: setCollectionAccess(uint8)423 function setCollectionAccess(uint8 mode) public {421 function setCollectionAccess(AccessMode mode) public {424 require(false, stub_error);422 require(false, stub_error);425 mode;423 mode;426 dummy = 0;424 dummy = 0;585 uint256 sub;583 uint256 sub;586}584}585586/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).587enum AccessMode {588 /// Access grant for owner and admins. Used as default.589 Normal,590 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.591 AllowList592}587593588/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.594/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.589struct CollectionNestingPermission {595struct CollectionNestingPermission {700 }706 }701}707}702703/// @dev inlined interface704contract ERC721UniqueMintableEvents {705 event MintingFinished();706}707708708/// @title ERC721 minting logic.709/// @title ERC721 minting logic.709/// @dev the ERC-165 identifier for this interface is 0x476ff149710/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6710contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {711contract ERC721UniqueMintable is Dummy, ERC165 {711 /// @dev EVM selector for this function is: 0x05d2035b,712 /// or in textual repr: mintingFinished()713 function mintingFinished() public view returns (bool) {714 require(false, stub_error);715 dummy;716 return false;717 }718719 /// @notice Function to mint a token.712 /// @notice Function to mint a token.720 /// @param to The new owner713 /// @param to The new owner774 // return false;766 // return false;775 // }767 // }776768777 /// @dev Not implemented778 /// @dev EVM selector for this function is: 0x7d64bcb4,779 /// or in textual repr: finishMinting()780 function finishMinting() public returns (bool) {781 require(false, stub_error);782 dummy = 0;783 return false;784 }785}769}786770787/// @title Unique extensions for ERC721.771/// @title Unique extensions for ERC721.pallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth383839/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b39/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b40contract ERC20UniqueExtensions is Dummy, ERC165 {40contract ERC20UniqueExtensions is Dummy, ERC165 {41 /// @dev Function that burns an amount of the token of a given account,41 // /// @dev Function that burns an amount of the token of a given account,42 /// deducting from the sender's allowance for said account.42 // /// deducting from the sender's allowance for said account.43 /// @param from The account whose tokens will be burnt.43 // /// @param from The account whose tokens will be burnt.44 /// @param amount The amount that will be burnt.44 // /// @param amount The amount that will be burnt.45 /// @dev EVM selector for this function is: 0x79cc6790,45 // /// @dev EVM selector for this function is: 0x79cc6790,46 /// or in textual repr: burnFrom(address,uint256)46 // /// or in textual repr: burnFrom(address,uint256)47 function burnFrom(address from, uint256 amount) public returns (bool) {47 // function burnFrom(address from, uint256 amount) public returns (bool) {48 require(false, stub_error);48 // require(false, stub_error);49 from;49 // from;50 amount;50 // amount;51 dummy = 0;51 // dummy = 0;52 return false;52 // return false;53 }53 // }545455 /// @dev Function that burns an amount of the token of a given account,55 /// @dev Function that burns an amount of the token of a given account,56 /// deducting from the sender's allowance for said account.56 /// deducting from the sender's allowance for said account.pallets/unique/src/eth/mod.rsdiffbeforeafterboth56}56}575758fn convert_data<T: Config>(58fn convert_data<T: Config>(59 caller: caller,59 caller: Caller,60 name: string,60 name: String,61 description: string,61 description: String,62 token_prefix: string,62 token_prefix: String,63) -> Result<(63) -> Result<(64 T::CrossAccountId,64 T::CrossAccountId,65 CollectionName,65 CollectionName,878788#[inline(always)]88#[inline(always)]89fn create_collection_internal<T: Config>(89fn create_collection_internal<T: Config>(90 caller: caller,90 caller: Caller,91 value: value,91 value: Value,92 name: string,92 name: String,93 collection_mode: CollectionMode,93 collection_mode: CollectionMode,94 description: string,94 description: String,95 token_prefix: string,95 token_prefix: String,96) -> Result<address> {96) -> Result<Address> {97 let (caller, name, description, token_prefix) =97 let (caller, name, description, token_prefix) =98 convert_data::<T>(caller, name, description, token_prefix)?;98 convert_data::<T>(caller, name, description, token_prefix)?;99 let data = CreateCollectionData {99 let data = CreateCollectionData {118 Ok(address)118 Ok(address)119}119}120120121fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {121fn check_sent_amount_equals_collection_creation_price<T: Config>(value: Value) -> Result<()> {122 let value = value.as_u128();122 let value = value.as_u128();123 let creation_price: u128 = T::CollectionCreationPrice::get()123 let creation_price: u128 = T::CollectionCreationPrice::get()124 .try_into()124 .try_into()149 #[solidity(rename_selector = "createNFTCollection")]149 #[solidity(rename_selector = "createNFTCollection")]150 fn create_nft_collection(150 fn create_nft_collection(151 &mut self,151 &mut self,152 caller: caller,152 caller: Caller,153 value: value,153 value: Value,154 name: string,154 name: String,155 description: string,155 description: String,156 token_prefix: string,156 token_prefix: String,157 ) -> Result<address> {157 ) -> Result<Address> {158 let (caller, name, description, token_prefix) =158 let (caller, name, description, token_prefix) =159 convert_data::<T>(caller, name, description, token_prefix)?;159 convert_data::<T>(caller, name, description, token_prefix)?;160 let data = CreateCollectionData {160 let data = CreateCollectionData {188 #[solidity(hide)]188 #[solidity(hide)]189 fn create_nonfungible_collection(189 fn create_nonfungible_collection(190 &mut self,190 &mut self,191 caller: caller,191 caller: Caller,192 value: value,192 value: Value,193 name: string,193 name: String,194 description: string,194 description: String,195 token_prefix: string,195 token_prefix: String,196 ) -> Result<address> {196 ) -> Result<Address> {197 create_collection_internal::<T>(197 create_collection_internal::<T>(198 caller,198 caller,199 value,199 value,208 #[solidity(rename_selector = "createRFTCollection")]208 #[solidity(rename_selector = "createRFTCollection")]209 fn create_rft_collection(209 fn create_rft_collection(210 &mut self,210 &mut self,211 caller: caller,211 caller: Caller,212 value: value,212 value: Value,213 name: string,213 name: String,214 description: string,214 description: String,215 token_prefix: string,215 token_prefix: String,216 ) -> Result<address> {216 ) -> Result<Address> {217 create_collection_internal::<T>(217 create_collection_internal::<T>(218 caller,218 caller,219 value,219 value,228 #[solidity(rename_selector = "createFTCollection")]228 #[solidity(rename_selector = "createFTCollection")]229 fn create_fungible_collection(229 fn create_fungible_collection(230 &mut self,230 &mut self,231 caller: caller,231 caller: Caller,232 value: value,232 value: Value,233 name: string,233 name: String,234 decimals: uint8,234 decimals: u8,235 description: string,235 description: String,236 token_prefix: string,236 token_prefix: String,237 ) -> Result<address> {237 ) -> Result<Address> {238 create_collection_internal::<T>(238 create_collection_internal::<T>(239 caller,239 caller,240 value,240 value,248 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]248 #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]249 fn make_collection_metadata_compatible(249 fn make_collection_metadata_compatible(250 &mut self,250 &mut self,251 caller: caller,251 caller: Caller,252 collection: address,252 collection: Address,253 base_uri: string,253 base_uri: String,254 ) -> Result<()> {254 ) -> Result<()> {255 let caller = T::CrossAccountId::from_eth(caller);255 let caller = T::CrossAccountId::from_eth(caller);256 let collection =256 let collection =334 }334 }335335336 #[weight(<SelfWeightOf<T>>::destroy_collection())]336 #[weight(<SelfWeightOf<T>>::destroy_collection())]337 fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result<void> {337 fn destroy_collection(&mut self, caller: Caller, collection_address: Address) -> Result<()> {338 let caller = T::CrossAccountId::from_eth(caller);338 let caller = T::CrossAccountId::from_eth(caller);339339340 let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)340 let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)346 /// Check if a collection exists346 /// Check if a collection exists347 /// @param collectionAddress Address of the collection in question347 /// @param collectionAddress Address of the collection in question348 /// @return bool Does the collection exist?348 /// @return bool Does the collection exist?349 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {349 fn is_collection_exist(&self, _caller: Caller, collection_address: Address) -> Result<bool> {350 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {350 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {351 let collection_id = id;351 let collection_id = id;352 return Ok(<CollectionById<T>>::contains_key(collection_id));352 return Ok(<CollectionById<T>>::contains_key(collection_id));355 Ok(false)355 Ok(false)356 }356 }357357358 fn collection_creation_fee(&self) -> Result<value> {358 fn collection_creation_fee(&self) -> Result<Value> {359 let price: u128 = T::CollectionCreationPrice::get()359 let price: u128 = T::CollectionCreationPrice::get()360 .try_into()360 .try_into()361 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait361 .map_err(|_| ()) // workaround for `expect` requiring `Debug` trait366 /// Returns address of a collection.366 /// Returns address of a collection.367 /// @param collectionId - CollectionId of the collection367 /// @param collectionId - CollectionId of the collection368 /// @return eth mirror address of the collection368 /// @return eth mirror address of the collection369 fn collection_address(&self, collection_id: uint32) -> Result<address> {369 fn collection_address(&self, collection_id: u32) -> Result<Address> {370 Ok(collection_id_to_address(collection_id.into()))370 Ok(collection_id_to_address(collection_id.into()))371 }371 }372372373 /// Returns collectionId of a collection.373 /// Returns collectionId of a collection.374 /// @param collectionAddress - Eth address of the collection374 /// @param collectionAddress - Eth address of the collection375 /// @return collectionId of the collection375 /// @return collectionId of the collection376 fn collection_id(&self, collection_address: address) -> Result<uint32> {376 fn collection_id(&self, collection_address: Address) -> Result<u32> {377 map_eth_to_id(&collection_address)377 map_eth_to_id(&collection_address)378 .map(|id| id.0)378 .map(|id| id.0)379 .ok_or(Error::Revert(format!(379 .ok_or(Error::Revert(format!(pallets/unique/src/lib.rsdiffbeforeafterboth266 /// * `token_prefix`: Byte string containing the token prefix to mark a collection266 /// * `token_prefix`: Byte string containing the token prefix to mark a collection267 /// to which a token belongs (limit [`MAX_TOKEN_PREFIX_LENGTH`]).267 /// to which a token belongs (limit [`MAX_TOKEN_PREFIX_LENGTH`]).268 /// * `mode`: Type of items stored in the collection and type dependent data.268 /// * `mode`: Type of items stored in the collection and type dependent data.269 ///269 // returns collection ID270 /// returns collection ID271 ///272 /// Deprecated: `create_collection_ex` is more up-to-date and advanced, prefer it instead.270 #[weight = <SelfWeightOf<T>>::create_collection()]273 #[weight = <SelfWeightOf<T>>::create_collection()]271 #[deprecated(note = "`create_collection_ex` is more up-to-date and advanced, prefer it instead")]272 pub fn create_collection(274 fn create_collection(273 origin,275 origin,274 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,276 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,275 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,277 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,runtime/common/ethereum/sponsoring/refungible.rsdiffbeforeafterboth265265266 match call {266 match call {267 // Readonly267 // Readonly268 ERC165Call(_, _) | MintingFinished => None,268 ERC165Call(_, _) => None,269269270 // Not sponsored270 // Sponsored271 FinishMinting => None,272273 Mint { .. }271 Mint { .. }274 | MintCheckId { .. }272 | MintCheckId { .. }runtime/tests/src/tests.rsdiffbeforeafterboth323 .map(|d| { d.into() })323 .map(|d| { d.into() })324 .collect()324 .collect()325 ));325 ));326 for (index, data) in items_data.into_iter().enumerate() {326 for (index, _data) in items_data.into_iter().enumerate() {327 let balance = <pallet_refungible::Balance<Test>>::get((327 let balance = <pallet_refungible::Balance<Test>>::get((328 CollectionId(1),328 CollectionId(1),329 TokenId((index + 1) as u32),329 TokenId((index + 1) as u32),tests/src/benchmarks/mintFee/benchmark.tsdiffbeforeafterboth293 const evmContract = await helper.ethNativeContract.collection(293 const evmContract = await helper.ethNativeContract.collection(294 helper.ethAddress.fromCollectionId(collection.collectionId),294 helper.ethAddress.fromCollectionId(collection.collectionId),295 'nft',295 'nft',296 undefined,297 true,296 );298 );297299298 const subTokenId = await evmContract.methods.nextTokenId().call();300 const subTokenId = await evmContract.methods.nextTokenId().call();351 encodedCall = await evmContract.methods353 encodedCall = await evmContract.methods352 .setProperties(354 .setProperties(353 subTokenId,355 subTokenId,354 PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {356 PROPERTIES.slice(0, setup.propertiesNumber),355 return {field_0: p.key, field_1: p.value};356 }),357 )357 )358 .encodeABI();358 .encodeABI();359359394 .mintToSubstrateBulkProperty(394 .mintToSubstrateBulkProperty(395 helper.ethAddress.fromCollectionId(collection.collectionId),395 helper.ethAddress.fromCollectionId(collection.collectionId),396 susbstrateReceiver.addressRaw,396 susbstrateReceiver.addressRaw,397 PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {397 PROPERTIES.slice(0, setup.propertiesNumber),398 return {field_0: p.key, field_1: p.value};399 }),400 )398 )401 .send({from: ethSigner, gas: 25_000_000});399 .send({from: ethSigner, gas: 25_000_000});402 },400 },tests/src/benchmarks/mintFee/proxyContract.soldiffbeforeafterboth3import {CollectionHelpers} from "../../eth/api/CollectionHelpers.sol";3import {CollectionHelpers} from "../../eth/api/CollectionHelpers.sol";4import {ContractHelpers} from "../../eth/api/ContractHelpers.sol";4import {ContractHelpers} from "../../eth/api/ContractHelpers.sol";5import {UniqueRefungibleToken} from "../../eth/api/UniqueRefungibleToken.sol";5import {UniqueRefungibleToken} from "../../eth/api/UniqueRefungibleToken.sol";6import {UniqueRefungible, Collection, EthCrossAccount as RftCrossAccountId, Tuple20 as RftProperties} from "../../eth/api/UniqueRefungible.sol";6import {UniqueRefungible, Collection, CrossAddress as RftCrossAccountId, Property as RftProperty} from "../../eth/api/UniqueRefungible.sol";7import {UniqueNFT, EthCrossAccount as NftCrossAccountId, Tuple21 as NftProperty, TokenProperties} from "../../eth/api/UniqueNFT.sol";7import {UniqueNFT, CrossAddress as NftCrossAccountId, Property as NftProperty} from "../../eth/api/UniqueNFT.sol";889struct Property {9struct Property {10 string key;10 string key;11 bytes value;11 bytes value;12}12}1314interface SoftDeprecatedMethods {15 /// @notice Set token property value.16 /// @dev Throws error if `msg.sender` has no permission to edit the property.17 /// @param tokenId ID of the token.18 /// @param key Property key.19 /// @param value Property value.20 /// @dev EVM selector for this function is: 0x1752d67b,21 /// or in textual repr: setProperty(uint256,string,bytes)22 function setProperty(23 uint256 tokenId,24 string memory key,25 bytes memory value26 ) external;27}2829interface BenchUniqueRefungible is UniqueRefungible, SoftDeprecatedMethods {}30interface BenchUniqueNFT is UniqueNFT, SoftDeprecatedMethods {}31321333173718 modifier checkRestrictions(address _collection) {38 modifier checkRestrictions(address _collection) {19 Collection commonContract = Collection(_collection);39 Collection commonContract = Collection(_collection);20 require(commonContract.isOwnerOrAdmin(msg.sender), "Only collection admin/owner can call this method");40 require(41 commonContract.isOwnerOrAdminCross(RftCrossAccountId(msg.sender, 0)),42 "Only collection admin/owner can call this method"43 );21 _;44 _;58 function mintToSubstrateWithProperty(81 function mintToSubstrateWithProperty(59 address _collection,82 address _collection,60 uint256 _substrateReceiver,83 uint256 _substrateReceiver,61 Property[] calldata properties84 Property[] calldata _properties62 ) external checkRestrictions(_collection) {85 ) external checkRestrictions(_collection) {63 uint256 propertiesLength = properties.length;86 uint256 propertiesLength = _properties.length;64 require(propertiesLength > 0, "Properies is empty");87 require(propertiesLength > 0, "Properies is empty");658866 Collection commonContract = Collection(_collection);89 Collection commonContract = Collection(_collection);67 bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));90 bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));68 uint256 tokenId;91 uint256 tokenId;699270 if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {93 if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {71 UniqueRefungible rftCollection = UniqueRefungible(_collection);94 BenchUniqueRefungible rftCollection = BenchUniqueRefungible(_collection);72 tokenId = rftCollection.nextTokenId();95 tokenId = rftCollection.nextTokenId();73 rftCollection.mint(address(this));96 rftCollection.mint(address(this));9774 for (uint256 i = 0; i < propertiesLength; ++i) {98 for (uint256 i = 0; i < propertiesLength; ++i) {75 rftCollection.setProperty(tokenId, properties[i].key, properties[i].value);99 rftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);76 }100 }77 rftCollection.transferFromCross(101 rftCollection.transferFromCross(78 RftCrossAccountId(address(this), 0),102 RftCrossAccountId(address(this), 0),79 RftCrossAccountId(address(0), _substrateReceiver),103 RftCrossAccountId(address(0), _substrateReceiver),80 tokenId104 tokenId81 );105 );82 } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {106 } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {83 UniqueNFT nftCollection = UniqueNFT(_collection);107 BenchUniqueNFT nftCollection = BenchUniqueNFT(_collection);84 tokenId = nftCollection.mint(address(this));108 tokenId = nftCollection.mint(address(this));85 for (uint256 i = 0; i < propertiesLength; ++i) {109 for (uint256 i = 0; i < propertiesLength; ++i) {86 nftCollection.setProperty(tokenId, properties[i].key, properties[i].value);110 nftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);87 }111 }88 nftCollection.transferFromCross(112 nftCollection.transferFromCross(89 NftCrossAccountId(address(this), 0),113 NftCrossAccountId(address(this), 0),tests/src/check-event/burnItemEvent.test.tsdiffbeforeafterboth32 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});32 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});33 const token = await collection.mintToken(alice, {Substrate: alice.address});33 const token = await collection.mintToken(alice, {Substrate: alice.address});34 await token.burn(alice);34 await token.burn(alice);35 await helper.wait.newBlocks(1);353636 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];37 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];37 const eventStrings = event.map(e => `${e.section}.${e.method}`);38 const eventStrings = event.map(e => `${e.section}.${e.method}`);tests/src/check-event/createCollectionEvent.test.tsdiffbeforeafterboth29 });29 });30 itSub('Check event from createCollection(): ', async ({helper}) => {30 itSub('Check event from createCollection(): ', async ({helper}) => {31 await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});31 await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});32 await helper.wait.newBlocks(1);32 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];33 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];33 const eventStrings = event.map(e => `${e.section}.${e.method}`);34 const eventStrings = event.map(e => `${e.section}.${e.method}`);3435tests/src/check-event/createItemEvent.test.tsdiffbeforeafterboth30 itSub('Check event from createItem(): ', async ({helper}) => {30 itSub('Check event from createItem(): ', async ({helper}) => {31 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});31 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});32 await collection.mintToken(alice, {Substrate: alice.address});32 await collection.mintToken(alice, {Substrate: alice.address});33 await helper.wait.newBlocks(1);33 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];34 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];34 const eventStrings = event.map(e => `${e.section}.${e.method}`);35 const eventStrings = event.map(e => `${e.section}.${e.method}`);3536tests/src/check-event/createMultipleItemsEvent.test.tsdiffbeforeafterboth35 {owner: {Substrate: alice.address}},35 {owner: {Substrate: alice.address}},36 ]);36 ]);373738 await helper.wait.newBlocks(1);38 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];39 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];39 const eventStrings = event.map(e => `${e.section}.${e.method}`);40 const eventStrings = event.map(e => `${e.section}.${e.method}`);4041tests/src/check-event/destroyCollectionEvent.test.tsdiffbeforeafterboth31 itSub('Check event from destroyCollection(): ', async ({helper}) => {31 itSub('Check event from destroyCollection(): ', async ({helper}) => {32 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});32 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});33 await collection.burn(alice);33 await collection.burn(alice);34 await helper.wait.newBlocks(1);34 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];35 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];35 const eventStrings = event.map(e => `${e.section}.${e.method}`);36 const eventStrings = event.map(e => `${e.section}.${e.method}`);3637tests/src/check-event/transferEvent.test.tsdiffbeforeafterboth34 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});34 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});35 const token = await collection.mintToken(alice, {Substrate: alice.address});35 const token = await collection.mintToken(alice, {Substrate: alice.address});36 await token.transfer(alice, {Substrate: bob.address});36 await token.transfer(alice, {Substrate: bob.address});37 await helper.wait.newBlocks(1);37 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];38 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];38 const eventStrings = event.map(e => `${e.section}.${e.method}`);39 const eventStrings = event.map(e => `${e.section}.${e.method}`);3940tests/src/check-event/transferFromEvent.test.tsdiffbeforeafterboth33 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});33 const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});34 const token = await collection.mintToken(alice, {Substrate: alice.address});34 const token = await collection.mintToken(alice, {Substrate: alice.address});35 await token.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address});35 await token.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address});36 await helper.wait.newBlocks(1);36 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];37 const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];37 const eventStrings = event.map(e => `${e.section}.${e.method}`);38 const eventStrings = event.map(e => `${e.section}.${e.method}`);3839tests/src/eth/abi/fungible.jsondiffbeforeafterboth488 "type": "function"488 "type": "function"489 },489 },490 {490 {491 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],491 "inputs": [492 { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }493 ],492 "name": "setCollectionAccess",494 "name": "setCollectionAccess",493 "outputs": [],495 "outputs": [],tests/src/eth/abi/nonFungible.jsondiffbeforeafterboth49 "name": "ApprovalForAll",49 "name": "ApprovalForAll",50 "type": "event"50 "type": "event"51 },51 },52 {53 "anonymous": false,54 "inputs": [],55 "name": "MintingFinished",56 "type": "event"57 },58 {52 {59 "anonymous": false,53 "anonymous": false,60 "inputs": [54 "inputs": [422 "stateMutability": "view",416 "stateMutability": "view",423 "type": "function"417 "type": "function"424 },418 },425 {426 "inputs": [],427 "name": "finishMinting",428 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],429 "stateMutability": "nonpayable",430 "type": "function"431 },432 {419 {433 "inputs": [420 "inputs": [434 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }421 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }515 "stateMutability": "nonpayable",502 "stateMutability": "nonpayable",516 "type": "function"503 "type": "function"517 },504 },518 {519 "inputs": [],520 "name": "mintingFinished",521 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],522 "stateMutability": "view",523 "type": "function"524 },525 {505 {526 "inputs": [],506 "inputs": [],527 "name": "name",507 "name": "name",650 "type": "function"630 "type": "function"651 },631 },652 {632 {653 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],633 "inputs": [634 { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }635 ],654 "name": "setCollectionAccess",636 "name": "setCollectionAccess",655 "outputs": [],637 "outputs": [],tests/src/eth/abi/reFungible.jsondiffbeforeafterboth49 "name": "ApprovalForAll",49 "name": "ApprovalForAll",50 "type": "event"50 "type": "event"51 },51 },52 {53 "anonymous": false,54 "inputs": [],55 "name": "MintingFinished",56 "type": "event"57 },58 {52 {59 "anonymous": false,53 "anonymous": false,60 "inputs": [54 "inputs": [404 "stateMutability": "view",398 "stateMutability": "view",405 "type": "function"399 "type": "function"406 },400 },407 {408 "inputs": [],409 "name": "finishMinting",410 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],411 "stateMutability": "nonpayable",412 "type": "function"413 },414 {401 {415 "inputs": [402 "inputs": [416 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }403 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }497 "stateMutability": "nonpayable",484 "stateMutability": "nonpayable",498 "type": "function"485 "type": "function"499 },486 },500 {501 "inputs": [],502 "name": "mintingFinished",503 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],504 "stateMutability": "view",505 "type": "function"506 },507 {487 {508 "inputs": [],488 "inputs": [],509 "name": "name",489 "name": "name",632 "type": "function"612 "type": "function"633 },613 },634 {614 {635 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],615 "inputs": [616 { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }617 ],636 "name": "setCollectionAccess",618 "name": "setCollectionAccess",637 "outputs": [],619 "outputs": [],tests/src/eth/abi/reFungibleToken.jsondiffbeforeafterboth96 "stateMutability": "view",96 "stateMutability": "view",97 "type": "function"97 "type": "function"98 },98 },99 {100 "inputs": [101 { "internalType": "address", "name": "from", "type": "address" },102 { "internalType": "uint256", "name": "amount", "type": "uint256" }103 ],104 "name": "burnFrom",105 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],106 "stateMutability": "nonpayable",107 "type": "function"108 },109 {99 {110 "inputs": [100 "inputs": [111 {101 {tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth175175176 /// Set the collection access method.176 /// Set the collection access method.177 /// @param mode Access mode177 /// @param mode Access mode178 /// 0 for Normal179 /// 1 for AllowList180 /// @dev EVM selector for this function is: 0x41835d4c,178 /// @dev EVM selector for this function is: 0x41835d4c,181 /// or in textual repr: setCollectionAccess(uint8)179 /// or in textual repr: setCollectionAccess(uint8)182 function setCollectionAccess(uint8 mode) external;180 function setCollectionAccess(AccessMode mode) external;183181184 /// Checks that user allowed to operate with collection.182 /// Checks that user allowed to operate with collection.185 ///183 ///285 uint256 sub;283 uint256 sub;286}284}285286/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).287enum AccessMode {288 /// Access grant for owner and admins. Used as default.289 Normal,290 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.291 AllowList292}287293288/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.294/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.289struct CollectionNestingPermission {295struct CollectionNestingPermission {tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth275275276 /// Set the collection access method.276 /// Set the collection access method.277 /// @param mode Access mode277 /// @param mode Access mode278 /// 0 for Normal279 /// 1 for AllowList280 /// @dev EVM selector for this function is: 0x41835d4c,278 /// @dev EVM selector for this function is: 0x41835d4c,281 /// or in textual repr: setCollectionAccess(uint8)279 /// or in textual repr: setCollectionAccess(uint8)282 function setCollectionAccess(uint8 mode) external;280 function setCollectionAccess(AccessMode mode) external;283281284 /// Checks that user allowed to operate with collection.282 /// Checks that user allowed to operate with collection.285 ///283 ///385 uint256 sub;383 uint256 sub;386}384}385386/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).387enum AccessMode {388 /// Access grant for owner and admins. Used as default.389 Normal,390 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.391 AllowList392}387393388/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.394/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.389struct CollectionNestingPermission {395struct CollectionNestingPermission {483 function burn(uint256 tokenId) external;489 function burn(uint256 tokenId) external;484}490}485486/// @dev inlined interface487interface ERC721UniqueMintableEvents {488 event MintingFinished();489}490491491/// @title ERC721 minting logic.492/// @title ERC721 minting logic.492/// @dev the ERC-165 identifier for this interface is 0x476ff149493/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6493interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {494interface ERC721UniqueMintable is Dummy, ERC165 {494 /// @dev EVM selector for this function is: 0x05d2035b,495 /// or in textual repr: mintingFinished()496 function mintingFinished() external view returns (bool);497498 /// @notice Function to mint a token.495 /// @notice Function to mint a token.499 /// @param to The new owner496 /// @param to The new owner529 // /// or in textual repr: mintWithTokenURI(address,uint256,string)525 // /// or in textual repr: mintWithTokenURI(address,uint256,string)530 // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);526 // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);531527532 /// @dev Not implemented533 /// @dev EVM selector for this function is: 0x7d64bcb4,534 /// or in textual repr: finishMinting()535 function finishMinting() external returns (bool);536}528}537529538/// @title Unique extensions for ERC721.530/// @title Unique extensions for ERC721.tests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth275275276 /// Set the collection access method.276 /// Set the collection access method.277 /// @param mode Access mode277 /// @param mode Access mode278 /// 0 for Normal279 /// 1 for AllowList280 /// @dev EVM selector for this function is: 0x41835d4c,278 /// @dev EVM selector for this function is: 0x41835d4c,281 /// or in textual repr: setCollectionAccess(uint8)279 /// or in textual repr: setCollectionAccess(uint8)282 function setCollectionAccess(uint8 mode) external;280 function setCollectionAccess(AccessMode mode) external;283281284 /// Checks that user allowed to operate with collection.282 /// Checks that user allowed to operate with collection.285 ///283 ///385 uint256 sub;383 uint256 sub;386}384}385386/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).387enum AccessMode {388 /// Access grant for owner and admins. Used as default.389 Normal,390 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.391 AllowList392}387393388/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.394/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.389struct CollectionNestingPermission {395struct CollectionNestingPermission {483 function burn(uint256 tokenId) external;489 function burn(uint256 tokenId) external;484}490}485486/// @dev inlined interface487interface ERC721UniqueMintableEvents {488 event MintingFinished();489}490491491/// @title ERC721 minting logic.492/// @title ERC721 minting logic.492/// @dev the ERC-165 identifier for this interface is 0x476ff149493/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6493interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {494interface ERC721UniqueMintable is Dummy, ERC165 {494 /// @dev EVM selector for this function is: 0x05d2035b,495 /// or in textual repr: mintingFinished()496 function mintingFinished() external view returns (bool);497498 /// @notice Function to mint a token.495 /// @notice Function to mint a token.499 /// @param to The new owner496 /// @param to The new owner529 // /// or in textual repr: mintWithTokenURI(address,uint256,string)525 // /// or in textual repr: mintWithTokenURI(address,uint256,string)530 // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);526 // function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);531527532 /// @dev Not implemented533 /// @dev EVM selector for this function is: 0x7d64bcb4,534 /// or in textual repr: finishMinting()535 function finishMinting() external returns (bool);536}528}537529538/// @title Unique extensions for ERC721.530/// @title Unique extensions for ERC721.tests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth252526/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b26/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b27interface ERC20UniqueExtensions is Dummy, ERC165 {27interface ERC20UniqueExtensions is Dummy, ERC165 {28 /// @dev Function that burns an amount of the token of a given account,28 // /// @dev Function that burns an amount of the token of a given account,29 /// deducting from the sender's allowance for said account.29 // /// deducting from the sender's allowance for said account.30 /// @param from The account whose tokens will be burnt.30 // /// @param from The account whose tokens will be burnt.31 /// @param amount The amount that will be burnt.31 // /// @param amount The amount that will be burnt.32 /// @dev EVM selector for this function is: 0x79cc6790,32 // /// @dev EVM selector for this function is: 0x79cc6790,33 /// or in textual repr: burnFrom(address,uint256)33 // /// or in textual repr: burnFrom(address,uint256)34 function burnFrom(address from, uint256 amount) external returns (bool);34 // function burnFrom(address from, uint256 amount) external returns (bool);353536 /// @dev Function that burns an amount of the token of a given account,36 /// @dev Function that burns an amount of the token of a given account,37 /// deducting from the sender's allowance for said account.37 /// deducting from the sender's allowance for said account.tests/src/eth/base.test.tsdiffbeforeafterboth108 await checkInterface(helper, '0x5b5e139f', false, true);108 await checkInterface(helper, '0x5b5e139f', false, true);109 });109 });110111 itEth('ERC721UniqueMintable - 0x476ff149 - support', async ({helper}) => {112 await checkInterface(helper, '0x476ff149', true, true);113 });114110115 itEth('ERC721Enumerable - 0x780e9d63 - support', async ({helper}) => {111 itEth('ERC721Enumerable - 0x780e9d63 - support', async ({helper}) => {116 await checkInterface(helper, '0x780e9d63', true, true);112 await checkInterface(helper, '0x780e9d63', true, true);