difftreelog
Merge pull request #825 from UniqueNetwork/feature/evm_coder_types_refactor
in: master
Feature/evm_coder_types_refactor
39 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/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/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}301 /// @notice A descriptive name for a collection of NFTs in this contract301 /// @notice A descriptive name for a collection of NFTs in this contract302 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`302 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`303 #[solidity(hide, rename_selector = "name")]303 #[solidity(hide, rename_selector = "name")]304 fn name_proxy(&self) -> Result<string> {304 fn name_proxy(&self) -> Result<String> {305 self.name()305 self.name()306 }306 }307307308 /// @notice An abbreviated name for NFTs in this contract308 /// @notice An abbreviated name for NFTs in this contract309 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`309 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`310 #[solidity(hide, rename_selector = "symbol")]310 #[solidity(hide, rename_selector = "symbol")]311 fn symbol_proxy(&self) -> Result<string> {311 fn symbol_proxy(&self) -> Result<String> {312 self.symbol()312 self.symbol()313 }313 }314314322 ///322 ///323 /// @return token's const_metadata323 /// @return token's const_metadata324 #[solidity(rename_selector = "tokenURI")]324 #[solidity(rename_selector = "tokenURI")]325 fn token_uri(&self, token_id: uint256) -> Result<string> {325 fn token_uri(&self, token_id: U256) -> Result<String> {326 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")?;327327328 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() {335 let base_uri =335 let base_uri =336 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())337 .map(BoundedVec::into_inner)337 .map(BoundedVec::into_inner)338 .map(string::from_utf8)338 .map(String::from_utf8)339 .transpose()339 .transpose()340 .map_err(|e| {340 .map_err(|e| {341 Error::Revert(alloc::format!(341 Error::Revert(alloc::format!(368 /// @param index A counter less than `totalSupply()`368 /// @param index A counter less than `totalSupply()`369 /// @return The token identifier for the `index`th NFT,369 /// @return The token identifier for the `index`th NFT,370 /// (sort order not specified)370 /// (sort order not specified)371 fn token_by_index(&self, index: uint256) -> Result<uint256> {371 fn token_by_index(&self, index: U256) -> Result<U256> {372 Ok(index)372 Ok(index)373 }373 }374374375 /// @dev Not implemented375 /// @dev Not implemented376 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> {377 // TODO: Not implemetable377 // TODO: Not implemetable378 Err("not implemented".into())378 Err("not implemented".into())379 }379 }380380381 /// @notice Count NFTs tracked by this contract381 /// @notice Count NFTs tracked by this contract382 /// @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 of383 /// 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 address384 fn total_supply(&self) -> Result<uint256> {384 fn total_supply(&self) -> Result<U256> {385 self.consume_store_reads(1)?;385 self.consume_store_reads(1)?;386 Ok(<Pallet<T>>::total_supply(self).into())386 Ok(<Pallet<T>>::total_supply(self).into())387 }387 }396 /// function throws for queries about the zero address.396 /// function throws for queries about the zero address.397 /// @param owner An address for whom to query the balance397 /// @param owner An address for whom to query the balance398 /// @return The number of NFTs owned by `owner`, possibly zero398 /// @return The number of NFTs owned by `owner`, possibly zero399 fn balance_of(&self, owner: address) -> Result<uint256> {399 fn balance_of(&self, owner: Address) -> Result<U256> {400 self.consume_store_reads(1)?;400 self.consume_store_reads(1)?;401 let owner = T::CrossAccountId::from_eth(owner);401 let owner = T::CrossAccountId::from_eth(owner);402 let balance = <AccountBalance<T>>::get((self.id, owner));402 let balance = <AccountBalance<T>>::get((self.id, owner));407 /// about them do throw.407 /// about them do throw.408 /// @param tokenId The identifier for an NFT408 /// @param tokenId The identifier for an NFT409 /// @return The address of the owner of the NFT409 /// @return The address of the owner of the NFT410 fn owner_of(&self, token_id: uint256) -> Result<address> {410 fn owner_of(&self, token_id: U256) -> Result<Address> {411 self.consume_store_reads(1)?;411 self.consume_store_reads(1)?;412 let token: TokenId = token_id.try_into()?;412 let token: TokenId = token_id.try_into()?;413 Ok(*<TokenData<T>>::get((self.id, token))413 Ok(*<TokenData<T>>::get((self.id, token))419 #[solidity(rename_selector = "safeTransferFrom")]419 #[solidity(rename_selector = "safeTransferFrom")]420 fn safe_transfer_from_with_data(420 fn safe_transfer_from_with_data(421 &mut self,421 &mut self,422 _from: address,422 _from: Address,423 _to: address,423 _to: Address,424 _token_id: uint256,424 _token_id: U256,425 _data: bytes,425 _data: Bytes,426 ) -> Result<void> {426 ) -> Result<()> {427 // TODO: Not implemetable427 // TODO: Not implemetable428 Err("not implemented".into())428 Err("not implemented".into())429 }429 }430 /// @dev Not implemented430 /// @dev Not implemented431 fn safe_transfer_from(431 fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {432 &mut self,433 _from: address,434 _to: address,435 _token_id: uint256,436 ) -> Result<void> {437 // TODO: Not implemetable432 // TODO: Not implemetable438 Err("not implemented".into())433 Err("not implemented".into())439 }434 }450 #[weight(<SelfWeightOf<T>>::transfer_from())]445 #[weight(<SelfWeightOf<T>>::transfer_from())]451 fn transfer_from(446 fn transfer_from(452 &mut self,447 &mut self,453 caller: caller,448 caller: Caller,454 from: address,449 from: Address,455 to: address,450 to: Address,456 token_id: uint256,451 token_id: U256,457 ) -> Result<void> {452 ) -> Result<()> {458 let caller = T::CrossAccountId::from_eth(caller);453 let caller = T::CrossAccountId::from_eth(caller);459 let from = T::CrossAccountId::from_eth(from);454 let from = T::CrossAccountId::from_eth(from);460 let to = T::CrossAccountId::from_eth(to);455 let to = T::CrossAccountId::from_eth(to);475 /// @param approved The new approved NFT controller470 /// @param approved The new approved NFT controller476 /// @param tokenId The NFT to approve471 /// @param tokenId The NFT to approve477 #[weight(<SelfWeightOf<T>>::approve())]472 #[weight(<SelfWeightOf<T>>::approve())]478 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<()> {479 let caller = T::CrossAccountId::from_eth(caller);474 let caller = T::CrossAccountId::from_eth(caller);480 let approved = T::CrossAccountId::from_eth(approved);475 let approved = T::CrossAccountId::from_eth(approved);481 let token = token_id.try_into()?;476 let token = token_id.try_into()?;492 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]487 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]493 fn set_approval_for_all(488 fn set_approval_for_all(494 &mut self,489 &mut self,495 caller: caller,490 caller: Caller,496 operator: address,491 operator: Address,497 approved: bool,492 approved: bool,498 ) -> Result<void> {493 ) -> Result<()> {499 let caller = T::CrossAccountId::from_eth(caller);494 let caller = T::CrossAccountId::from_eth(caller);500 let operator = T::CrossAccountId::from_eth(operator);495 let operator = T::CrossAccountId::from_eth(operator);501496505 }500 }506501507 /// @dev Not implemented502 /// @dev Not implemented508 fn get_approved(&self, _token_id: uint256) -> Result<address> {503 fn get_approved(&self, _token_id: U256) -> Result<Address> {509 // TODO: Not implemetable504 // TODO: Not implemetable510 Err("not implemented".into())505 Err("not implemented".into())511 }506 }512507513 /// @notice Tells whether the given `owner` approves the `operator`.508 /// @notice Tells whether the given `owner` approves the `operator`.514 #[weight(<SelfWeightOf<T>>::allowance_for_all())]509 #[weight(<SelfWeightOf<T>>::allowance_for_all())]515 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> {516 let owner = T::CrossAccountId::from_eth(owner);511 let owner = T::CrossAccountId::from_eth(owner);517 let operator = T::CrossAccountId::from_eth(operator);512 let operator = T::CrossAccountId::from_eth(operator);518513528 /// operator of the current owner.523 /// operator of the current owner.529 /// @param tokenId The NFT to approve524 /// @param tokenId The NFT to approve530 #[weight(<SelfWeightOf<T>>::burn_item())]525 #[weight(<SelfWeightOf<T>>::burn_item())]531 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {526 fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {532 let caller = T::CrossAccountId::from_eth(caller);527 let caller = T::CrossAccountId::from_eth(caller);533 let token = token_id.try_into()?;528 let token = token_id.try_into()?;534529544 /// @param to The new owner539 /// @param to The new owner545 /// @return uint256 The id of the newly minted token540 /// @return uint256 The id of the newly minted token546 #[weight(<SelfWeightOf<T>>::create_item())]541 #[weight(<SelfWeightOf<T>>::create_item())]547 fn mint(&mut self, caller: caller, to: address) -> Result<uint256> {542 fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {548 let token_id: uint256 = <TokensMinted<T>>::get(self.id)543 let token_id: U256 = <TokensMinted<T>>::get(self.id)549 .checked_add(1)544 .checked_add(1)550 .ok_or("item id overflow")?545 .ok_or("item id overflow")?551 .into();546 .into();560 /// @param tokenId ID of the minted NFT555 /// @param tokenId ID of the minted NFT561 #[solidity(hide, rename_selector = "mint")]556 #[solidity(hide, rename_selector = "mint")]562 #[weight(<SelfWeightOf<T>>::create_item())]557 #[weight(<SelfWeightOf<T>>::create_item())]563 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> {564 let caller = T::CrossAccountId::from_eth(caller);559 let caller = T::CrossAccountId::from_eth(caller);565 let to = T::CrossAccountId::from_eth(to);560 let to = T::CrossAccountId::from_eth(to);566 let token_id: u32 = token_id.try_into()?;561 let token_id: u32 = token_id.try_into()?;598 #[weight(<SelfWeightOf<T>>::create_item())]593 #[weight(<SelfWeightOf<T>>::create_item())]599 fn mint_with_token_uri(594 fn mint_with_token_uri(600 &mut self,595 &mut self,601 caller: caller,596 caller: Caller,602 to: address,597 to: Address,603 token_uri: string,598 token_uri: String,604 ) -> Result<uint256> {599 ) -> Result<U256> {605 let token_id: uint256 = <TokensMinted<T>>::get(self.id)600 let token_id: U256 = <TokensMinted<T>>::get(self.id)606 .checked_add(1)601 .checked_add(1)607 .ok_or("item id overflow")?602 .ok_or("item id overflow")?608 .into();603 .into();620 #[weight(<SelfWeightOf<T>>::create_item())]615 #[weight(<SelfWeightOf<T>>::create_item())]621 fn mint_with_token_uri_check_id(616 fn mint_with_token_uri_check_id(622 &mut self,617 &mut self,623 caller: caller,618 caller: Caller,624 to: address,619 to: Address,625 token_id: uint256,620 token_id: U256,626 token_uri: string,621 token_uri: String,627 ) -> Result<bool> {622 ) -> Result<bool> {628 let key = key::url();623 let key = key::url();629 let permission = get_token_permission::<T>(self.id, &key)?;624 let permission = get_token_permission::<T>(self.id, &key)?;675 collection: &CollectionHandle<T>,670 collection: &CollectionHandle<T>,676 token_id: u32,671 token_id: u32,677 key: &up_data_structs::PropertyKey,672 key: &up_data_structs::PropertyKey,678) -> Result<string> {673) -> Result<String> {679 collection.consume_store_reads(1)?;674 collection.consume_store_reads(1)?;680 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))675 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))681 .map_err(|_| Error::Revert("Token properties not found".into()))?;676 .map_err(|_| Error::Revert("Token properties not found".into()))?;682 if let Some(property) = properties.get(key) {677 if let Some(property) = properties.get(key) {683 return Ok(string::from_utf8_lossy(property).into());678 return Ok(String::from_utf8_lossy(property).into());684 }679 }685680686 Err("Property tokenURI not found".into())681 Err("Property tokenURI not found".into())696 .get(key)691 .get(key)697 .map(Clone::clone)692 .map(Clone::clone)698 .ok_or_else(|| {693 .ok_or_else(|| {699 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();700 Error::Revert(alloc::format!("No permission for key {}", key))695 Error::Revert(alloc::format!("No permission for key {}", key))701 })?;696 })?;702 Ok(a)697 Ok(a)709 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,704 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,710{705{711 /// @notice A descriptive name for a collection of NFTs in this contract706 /// @notice A descriptive name for a collection of NFTs in this contract712 fn name(&self) -> Result<string> {707 fn name(&self) -> Result<String> {713 Ok(decode_utf16(self.name.iter().copied())708 Ok(decode_utf16(self.name.iter().copied())714 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))709 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))715 .collect::<string>())710 .collect::<String>())716 }711 }717712718 /// @notice An abbreviated name for NFTs in this contract713 /// @notice An abbreviated name for NFTs in this contract719 fn symbol(&self) -> Result<string> {714 fn symbol(&self) -> Result<String> {720 Ok(string::from_utf8_lossy(&self.token_prefix).into())715 Ok(String::from_utf8_lossy(&self.token_prefix).into())721 }716 }722717723 /// @notice A description for the collection.718 /// @notice A description for the collection.724 fn description(&self) -> Result<string> {719 fn description(&self) -> Result<String> {725 Ok(decode_utf16(self.description.iter().copied())720 Ok(decode_utf16(self.description.iter().copied())726 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))721 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))727 .collect::<string>())722 .collect::<String>())728 }723 }729724730 /// Returns the owner (in cross format) of the token.725 /// Returns the owner (in cross format) of the token.731 ///726 ///732 /// @param tokenId Id for the token.727 /// @param tokenId Id for the token.733 fn cross_owner_of(&self, token_id: uint256) -> Result<eth::CrossAddress> {728 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {734 Self::token_owner(&self, token_id.try_into()?)729 Self::token_owner(&self, token_id.try_into()?)735 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))730 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))736 .ok_or(Error::Revert("key too large".into()))731 .ok_or(Error::Revert("key too large".into()))741 /// @param tokenId Id for the token.736 /// @param tokenId Id for the token.742 /// @param keys Properties keys. Empty keys for all propertyes.737 /// @param keys Properties keys. Empty keys for all propertyes.743 /// @return Vector of properties key/value pairs.738 /// @return Vector of properties key/value pairs.744 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>> {745 let keys = keys740 let keys = keys746 .into_iter()741 .into_iter()747 .map(|key| {742 .map(|key| {770 #[weight(<SelfWeightOf<T>>::approve())]765 #[weight(<SelfWeightOf<T>>::approve())]771 fn approve_cross(766 fn approve_cross(772 &mut self,767 &mut self,773 caller: caller,768 caller: Caller,774 approved: eth::CrossAddress,769 approved: eth::CrossAddress,775 token_id: uint256,770 token_id: U256,776 ) -> Result<void> {771 ) -> Result<()> {777 let caller = T::CrossAccountId::from_eth(caller);772 let caller = T::CrossAccountId::from_eth(caller);778 let approved = approved.into_sub_cross_account::<T>()?;773 let approved = approved.into_sub_cross_account::<T>()?;779 let token = token_id.try_into()?;774 let token = token_id.try_into()?;789 /// @param to The new owner784 /// @param to The new owner790 /// @param tokenId The NFT to transfer785 /// @param tokenId The NFT to transfer791 #[weight(<SelfWeightOf<T>>::transfer())]786 #[weight(<SelfWeightOf<T>>::transfer())]792 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<()> {793 let caller = T::CrossAccountId::from_eth(caller);788 let caller = T::CrossAccountId::from_eth(caller);794 let to = T::CrossAccountId::from_eth(to);789 let to = T::CrossAccountId::from_eth(to);795 let token = token_id.try_into()?;790 let token = token_id.try_into()?;809 #[weight(<SelfWeightOf<T>>::transfer())]804 #[weight(<SelfWeightOf<T>>::transfer())]810 fn transfer_cross(805 fn transfer_cross(811 &mut self,806 &mut self,812 caller: caller,807 caller: Caller,813 to: eth::CrossAddress,808 to: eth::CrossAddress,814 token_id: uint256,809 token_id: U256,815 ) -> Result<void> {810 ) -> Result<()> {816 let caller = T::CrossAccountId::from_eth(caller);811 let caller = T::CrossAccountId::from_eth(caller);817 let to = to.into_sub_cross_account::<T>()?;812 let to = to.into_sub_cross_account::<T>()?;818 let token = token_id.try_into()?;813 let token = token_id.try_into()?;833 #[weight(<SelfWeightOf<T>>::transfer())]828 #[weight(<SelfWeightOf<T>>::transfer())]834 fn transfer_from_cross(829 fn transfer_from_cross(835 &mut self,830 &mut self,836 caller: caller,831 caller: Caller,837 from: eth::CrossAddress,832 from: eth::CrossAddress,838 to: eth::CrossAddress,833 to: eth::CrossAddress,839 token_id: uint256,834 token_id: U256,840 ) -> Result<void> {835 ) -> Result<()> {841 let caller = T::CrossAccountId::from_eth(caller);836 let caller = T::CrossAccountId::from_eth(caller);842 let from = from.into_sub_cross_account::<T>()?;837 let from = from.into_sub_cross_account::<T>()?;843 let to = to.into_sub_cross_account::<T>()?;838 let to = to.into_sub_cross_account::<T>()?;858 /// @param tokenId The NFT to transfer853 /// @param tokenId The NFT to transfer859 #[solidity(hide)]854 #[solidity(hide)]860 #[weight(<SelfWeightOf<T>>::burn_from())]855 #[weight(<SelfWeightOf<T>>::burn_from())]861 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<()> {862 let caller = T::CrossAccountId::from_eth(caller);857 let caller = T::CrossAccountId::from_eth(caller);863 let from = T::CrossAccountId::from_eth(from);858 let from = T::CrossAccountId::from_eth(from);864 let token = token_id.try_into()?;859 let token = token_id.try_into()?;880 #[weight(<SelfWeightOf<T>>::burn_from())]875 #[weight(<SelfWeightOf<T>>::burn_from())]881 fn burn_from_cross(876 fn burn_from_cross(882 &mut self,877 &mut self,883 caller: caller,878 caller: Caller,884 from: eth::CrossAddress,879 from: eth::CrossAddress,885 token_id: uint256,880 token_id: U256,886 ) -> Result<void> {881 ) -> Result<()> {887 let caller = T::CrossAccountId::from_eth(caller);882 let caller = T::CrossAccountId::from_eth(caller);888 let from = from.into_sub_cross_account::<T>()?;883 let from = from.into_sub_cross_account::<T>()?;889 let token = token_id.try_into()?;884 let token = token_id.try_into()?;897 }892 }898893899 /// @notice Returns next free NFT ID.894 /// @notice Returns next free NFT ID.900 fn next_token_id(&self) -> Result<uint256> {895 fn next_token_id(&self) -> Result<U256> {901 self.consume_store_reads(1)?;896 self.consume_store_reads(1)?;902 Ok(<TokensMinted<T>>::get(self.id)897 Ok(<TokensMinted<T>>::get(self.id)903 .checked_add(1)898 .checked_add(1)912 /// @param tokenIds IDs of the minted NFTs907 /// @param tokenIds IDs of the minted NFTs913 #[solidity(hide)]908 #[solidity(hide)]914 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]909 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]915 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> {916 let caller = T::CrossAccountId::from_eth(caller);911 let caller = T::CrossAccountId::from_eth(caller);917 let to = T::CrossAccountId::from_eth(to);912 let to = T::CrossAccountId::from_eth(to);918 let mut expected_index = <TokensMinted<T>>::get(self.id)913 let mut expected_index = <TokensMinted<T>>::get(self.id)951 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]946 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]952 fn mint_bulk_with_token_uri(947 fn mint_bulk_with_token_uri(953 &mut self,948 &mut self,954 caller: caller,949 caller: Caller,955 to: address,950 to: Address,956 tokens: Vec<(uint256, string)>,951 tokens: Vec<(U256, String)>,957 ) -> Result<bool> {952 ) -> Result<bool> {958 let key = key::url();953 let key = key::url();959 let caller = T::CrossAccountId::from_eth(caller);954 let caller = T::CrossAccountId::from_eth(caller);1002 #[weight(<SelfWeightOf<T>>::create_item())]997 #[weight(<SelfWeightOf<T>>::create_item())]1003 fn mint_cross(998 fn mint_cross(1004 &mut self,999 &mut self,1005 caller: caller,1000 caller: Caller,1006 to: eth::CrossAddress,1001 to: eth::CrossAddress,1007 properties: Vec<eth::Property>,1002 properties: Vec<eth::Property>,1008 ) -> Result<uint256> {1003 ) -> Result<U256> {1009 let token_id = <TokensMinted<T>>::get(self.id)1004 let token_id = <TokensMinted<T>>::get(self.id)1010 .checked_add(1)1005 .checked_add(1)1011 .ok_or("item id overflow")?;1006 .ok_or("item id overflow")?;1040 }1035 }104110361042 /// @notice Returns collection helper contract address1037 /// @notice Returns collection helper contract address1043 fn collection_helper_address(&self) -> Result<address> {1038 fn collection_helper_address(&self) -> Result<Address> {1044 Ok(T::ContractAddress::get())1039 Ok(T::ContractAddress::get())1045 }1040 }1046}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 {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}298 /// @notice A descriptive name for a collection of NFTs in this contract298 /// @notice A descriptive name for a collection of NFTs in this contract299 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`299 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`300 #[solidity(hide, rename_selector = "name")]300 #[solidity(hide, rename_selector = "name")]301 fn name_proxy(&self) -> Result<string> {301 fn name_proxy(&self) -> Result<String> {302 self.name()302 self.name()303 }303 }304304305 /// @notice An abbreviated name for NFTs in this contract305 /// @notice An abbreviated name for NFTs in this contract306 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`306 /// @dev real implementation of this function lies in `ERC721UniqueExtensions`307 #[solidity(hide, rename_selector = "symbol")]307 #[solidity(hide, rename_selector = "symbol")]308 fn symbol_proxy(&self) -> Result<string> {308 fn symbol_proxy(&self) -> Result<String> {309 self.symbol()309 self.symbol()310 }310 }311311319 ///319 ///320 /// @return token's const_metadata320 /// @return token's const_metadata321 #[solidity(rename_selector = "tokenURI")]321 #[solidity(rename_selector = "tokenURI")]322 fn token_uri(&self, token_id: uint256) -> Result<string> {322 fn token_uri(&self, token_id: U256) -> Result<String> {323 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")?;324324325 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() {332 let base_uri =332 let base_uri =333 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())334 .map(BoundedVec::into_inner)334 .map(BoundedVec::into_inner)335 .map(string::from_utf8)335 .map(String::from_utf8)336 .transpose()336 .transpose()337 .map_err(|e| {337 .map_err(|e| {338 Error::Revert(alloc::format!(338 Error::Revert(alloc::format!(365 /// @param index A counter less than `totalSupply()`365 /// @param index A counter less than `totalSupply()`366 /// @return The token identifier for the `index`th NFT,366 /// @return The token identifier for the `index`th NFT,367 /// (sort order not specified)367 /// (sort order not specified)368 fn token_by_index(&self, index: uint256) -> Result<uint256> {368 fn token_by_index(&self, index: U256) -> Result<U256> {369 Ok(index)369 Ok(index)370 }370 }371371372 /// Not implemented372 /// Not implemented373 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> {374 // TODO: Not implemetable374 // TODO: Not implemetable375 Err("not implemented".into())375 Err("not implemented".into())376 }376 }377377378 /// @notice Count RFTs tracked by this contract378 /// @notice Count RFTs tracked by this contract379 /// @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 of380 /// 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 address381 fn total_supply(&self) -> Result<uint256> {381 fn total_supply(&self) -> Result<U256> {382 self.consume_store_reads(1)?;382 self.consume_store_reads(1)?;383 Ok(<Pallet<T>>::total_supply(self).into())383 Ok(<Pallet<T>>::total_supply(self).into())384 }384 }393 /// function throws for queries about the zero address.393 /// function throws for queries about the zero address.394 /// @param owner An address for whom to query the balance394 /// @param owner An address for whom to query the balance395 /// @return The number of RFTs owned by `owner`, possibly zero395 /// @return The number of RFTs owned by `owner`, possibly zero396 fn balance_of(&self, owner: address) -> Result<uint256> {396 fn balance_of(&self, owner: Address) -> Result<U256> {397 self.consume_store_reads(1)?;397 self.consume_store_reads(1)?;398 let owner = T::CrossAccountId::from_eth(owner);398 let owner = T::CrossAccountId::from_eth(owner);399 let balance = <AccountBalance<T>>::get((self.id, owner));399 let balance = <AccountBalance<T>>::get((self.id, owner));407 /// the tokens that are partially owned.407 /// the tokens that are partially owned.408 /// @param tokenId The identifier for an RFT408 /// @param tokenId The identifier for an RFT409 /// @return The address of the owner of the RFT409 /// @return The address of the owner of the RFT410 fn owner_of(&self, token_id: uint256) -> Result<address> {410 fn owner_of(&self, token_id: U256) -> Result<Address> {411 self.consume_store_reads(2)?;411 self.consume_store_reads(2)?;412 let token = token_id.try_into()?;412 let token = token_id.try_into()?;413 let owner = <Pallet<T>>::token_owner(self.id, token);413 let owner = <Pallet<T>>::token_owner(self.id, token);420 #[solidity(rename_selector = "safeTransferFrom")]420 #[solidity(rename_selector = "safeTransferFrom")]421 fn safe_transfer_from_with_data(421 fn safe_transfer_from_with_data(422 &mut self,422 &mut self,423 _from: address,423 _from: Address,424 _to: address,424 _to: Address,425 _token_id: uint256,425 _token_id: U256,426 _data: bytes,426 _data: Bytes,427 ) -> Result<void> {427 ) -> Result<()> {428 // TODO: Not implemetable428 // TODO: Not implemetable429 Err("not implemented".into())429 Err("not implemented".into())430 }430 }431431432 /// @dev Not implemented432 /// @dev Not implemented433 #[solidity(rename_selector = "safeTransferFrom")]433 #[solidity(rename_selector = "safeTransferFrom")]434 fn safe_transfer_from(434 fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {435 &mut self,436 _from: address,437 _to: address,438 _token_id: uint256,439 ) -> Result<void> {440 // TODO: Not implemetable435 // TODO: Not implemetable441 Err("not implemented".into())436 Err("not implemented".into())442 }437 }454 #[weight(<SelfWeightOf<T>>::transfer_from_creating_removing())]449 #[weight(<SelfWeightOf<T>>::transfer_from_creating_removing())]455 fn transfer_from(450 fn transfer_from(456 &mut self,451 &mut self,457 caller: caller,452 caller: Caller,458 from: address,453 from: Address,459 to: address,454 to: Address,460 token_id: uint256,455 token_id: U256,461 ) -> Result<void> {456 ) -> Result<()> {462 let caller = T::CrossAccountId::from_eth(caller);457 let caller = T::CrossAccountId::from_eth(caller);463 let from = T::CrossAccountId::from_eth(from);458 let from = T::CrossAccountId::from_eth(from);464 let to = T::CrossAccountId::from_eth(to);459 let to = T::CrossAccountId::from_eth(to);477 }472 }478473479 /// @dev Not implemented474 /// @dev Not implemented480 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<()> {481 Err("not implemented".into())476 Err("not implemented".into())482 }477 }483478488 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]483 #[weight(<SelfWeightOf<T>>::set_allowance_for_all())]489 fn set_approval_for_all(484 fn set_approval_for_all(490 &mut self,485 &mut self,491 caller: caller,486 caller: Caller,492 operator: address,487 operator: Address,493 approved: bool,488 approved: bool,494 ) -> Result<void> {489 ) -> Result<()> {495 let caller = T::CrossAccountId::from_eth(caller);490 let caller = T::CrossAccountId::from_eth(caller);496 let operator = T::CrossAccountId::from_eth(operator);491 let operator = T::CrossAccountId::from_eth(operator);497492501 }496 }502497503 /// @dev Not implemented498 /// @dev Not implemented504 fn get_approved(&self, _token_id: uint256) -> Result<address> {499 fn get_approved(&self, _token_id: U256) -> Result<Address> {505 // TODO: Not implemetable500 // TODO: Not implemetable506 Err("not implemented".into())501 Err("not implemented".into())507 }502 }508503509 /// @notice Tells whether the given `owner` approves the `operator`.504 /// @notice Tells whether the given `owner` approves the `operator`.510 #[weight(<SelfWeightOf<T>>::allowance_for_all())]505 #[weight(<SelfWeightOf<T>>::allowance_for_all())]511 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> {512 let owner = T::CrossAccountId::from_eth(owner);507 let owner = T::CrossAccountId::from_eth(owner);513 let operator = T::CrossAccountId::from_eth(operator);508 let operator = T::CrossAccountId::from_eth(operator);514509556 /// operator of the current owner.551 /// operator of the current owner.557 /// @param tokenId The RFT to approve552 /// @param tokenId The RFT to approve558 #[weight(<SelfWeightOf<T>>::burn_item_fully())]553 #[weight(<SelfWeightOf<T>>::burn_item_fully())]559 fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {554 fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {560 let caller = T::CrossAccountId::from_eth(caller);555 let caller = T::CrossAccountId::from_eth(caller);561 let token = token_id.try_into()?;556 let token = token_id.try_into()?;562557575 /// @param to The new owner570 /// @param to The new owner576 /// @return uint256 The id of the newly minted token571 /// @return uint256 The id of the newly minted token577 #[weight(<SelfWeightOf<T>>::create_item())]572 #[weight(<SelfWeightOf<T>>::create_item())]578 fn mint(&mut self, caller: caller, to: address) -> Result<uint256> {573 fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {579 let token_id: uint256 = <TokensMinted<T>>::get(self.id)574 let token_id: U256 = <TokensMinted<T>>::get(self.id)580 .checked_add(1)575 .checked_add(1)581 .ok_or("item id overflow")?576 .ok_or("item id overflow")?582 .into();577 .into();591 /// @param tokenId ID of the minted RFT586 /// @param tokenId ID of the minted RFT592 #[solidity(hide, rename_selector = "mint")]587 #[solidity(hide, rename_selector = "mint")]593 #[weight(<SelfWeightOf<T>>::create_item())]588 #[weight(<SelfWeightOf<T>>::create_item())]594 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> {595 let caller = T::CrossAccountId::from_eth(caller);590 let caller = T::CrossAccountId::from_eth(caller);596 let to = T::CrossAccountId::from_eth(to);591 let to = T::CrossAccountId::from_eth(to);597 let token_id: u32 = token_id.try_into()?;592 let token_id: u32 = token_id.try_into()?;634 #[weight(<SelfWeightOf<T>>::create_item())]629 #[weight(<SelfWeightOf<T>>::create_item())]635 fn mint_with_token_uri(630 fn mint_with_token_uri(636 &mut self,631 &mut self,637 caller: caller,632 caller: Caller,638 to: address,633 to: Address,639 token_uri: string,634 token_uri: String,640 ) -> Result<uint256> {635 ) -> Result<U256> {641 let token_id: uint256 = <TokensMinted<T>>::get(self.id)636 let token_id: U256 = <TokensMinted<T>>::get(self.id)642 .checked_add(1)637 .checked_add(1)643 .ok_or("item id overflow")?638 .ok_or("item id overflow")?644 .into();639 .into();656 #[weight(<SelfWeightOf<T>>::create_item())]651 #[weight(<SelfWeightOf<T>>::create_item())]657 fn mint_with_token_uri_check_id(652 fn mint_with_token_uri_check_id(658 &mut self,653 &mut self,659 caller: caller,654 caller: Caller,660 to: address,655 to: Address,661 token_id: uint256,656 token_id: U256,662 token_uri: string,657 token_uri: String,663 ) -> Result<bool> {658 ) -> Result<bool> {664 let key = key::url();659 let key = key::url();665 let permission = get_token_permission::<T>(self.id, &key)?;660 let permission = get_token_permission::<T>(self.id, &key)?;713 collection: &CollectionHandle<T>,708 collection: &CollectionHandle<T>,714 token_id: u32,709 token_id: u32,715 key: &up_data_structs::PropertyKey,710 key: &up_data_structs::PropertyKey,716) -> Result<string> {711) -> Result<String> {717 collection.consume_store_reads(1)?;712 collection.consume_store_reads(1)?;718 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))713 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))719 .map_err(|_| Error::Revert("Token properties not found".into()))?;714 .map_err(|_| Error::Revert("Token properties not found".into()))?;720 if let Some(property) = properties.get(key) {715 if let Some(property) = properties.get(key) {721 return Ok(string::from_utf8_lossy(property).into());716 return Ok(String::from_utf8_lossy(property).into());722 }717 }723718724 Err("Property tokenURI not found".into())719 Err("Property tokenURI not found".into())734 .get(key)729 .get(key)735 .map(Clone::clone)730 .map(Clone::clone)736 .ok_or_else(|| {731 .ok_or_else(|| {737 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();738 Error::Revert(alloc::format!("No permission for key {}", key))733 Error::Revert(alloc::format!("No permission for key {}", key))739 })?;734 })?;740 Ok(a)735 Ok(a)747 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,742 T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,748{743{749 /// @notice A descriptive name for a collection of NFTs in this contract744 /// @notice A descriptive name for a collection of NFTs in this contract750 fn name(&self) -> Result<string> {745 fn name(&self) -> Result<String> {751 Ok(decode_utf16(self.name.iter().copied())746 Ok(decode_utf16(self.name.iter().copied())752 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))747 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))753 .collect::<string>())748 .collect::<String>())754 }749 }755750756 /// @notice An abbreviated name for NFTs in this contract751 /// @notice An abbreviated name for NFTs in this contract757 fn symbol(&self) -> Result<string> {752 fn symbol(&self) -> Result<String> {758 Ok(string::from_utf8_lossy(&self.token_prefix).into())753 Ok(String::from_utf8_lossy(&self.token_prefix).into())759 }754 }760755761 /// @notice A description for the collection.756 /// @notice A description for the collection.762 fn description(&self) -> Result<string> {757 fn description(&self) -> Result<String> {763 Ok(decode_utf16(self.description.iter().copied())758 Ok(decode_utf16(self.description.iter().copied())764 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))759 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))765 .collect::<string>())760 .collect::<String>())766 }761 }767762768 /// Returns the owner (in cross format) of the token.763 /// Returns the owner (in cross format) of the token.769 ///764 ///770 /// @param tokenId Id for the token.765 /// @param tokenId Id for the token.771 fn cross_owner_of(&self, token_id: uint256) -> Result<eth::CrossAddress> {766 fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {772 Self::token_owner(&self, token_id.try_into()?)767 Self::token_owner(&self, token_id.try_into()?)773 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))768 .map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))774 .ok_or(Error::Revert("key too large".into()))769 .ok_or(Error::Revert("key too large".into()))779 /// @param tokenId Id for the token.774 /// @param tokenId Id for the token.780 /// @param keys Properties keys. Empty keys for all propertyes.775 /// @param keys Properties keys. Empty keys for all propertyes.781 /// @return Vector of properties key/value pairs.776 /// @return Vector of properties key/value pairs.782 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>> {783 let keys = keys778 let keys = keys784 .into_iter()779 .into_iter()785 .map(|key| {780 .map(|key| {805 /// @param to The new owner800 /// @param to The new owner806 /// @param tokenId The RFT to transfer801 /// @param tokenId The RFT to transfer807 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]802 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]808 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<()> {809 let caller = T::CrossAccountId::from_eth(caller);804 let caller = T::CrossAccountId::from_eth(caller);810 let to = T::CrossAccountId::from_eth(to);805 let to = T::CrossAccountId::from_eth(to);811 let token = token_id.try_into()?;806 let token = token_id.try_into()?;830 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]825 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]831 fn transfer_cross(826 fn transfer_cross(832 &mut self,827 &mut self,833 caller: caller,828 caller: Caller,834 to: eth::CrossAddress,829 to: eth::CrossAddress,835 token_id: uint256,830 token_id: U256,836 ) -> Result<void> {831 ) -> Result<()> {837 let caller = T::CrossAccountId::from_eth(caller);832 let caller = T::CrossAccountId::from_eth(caller);838 let to = to.into_sub_cross_account::<T>()?;833 let to = to.into_sub_cross_account::<T>()?;839 let token = token_id.try_into()?;834 let token = token_id.try_into()?;858 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]853 #[weight(<SelfWeightOf<T>>::transfer_creating_removing())]859 fn transfer_from_cross(854 fn transfer_from_cross(860 &mut self,855 &mut self,861 caller: caller,856 caller: Caller,862 from: eth::CrossAddress,857 from: eth::CrossAddress,863 to: eth::CrossAddress,858 to: eth::CrossAddress,864 token_id: uint256,859 token_id: U256,865 ) -> Result<void> {860 ) -> Result<()> {866 let caller = T::CrossAccountId::from_eth(caller);861 let caller = T::CrossAccountId::from_eth(caller);867 let from = from.into_sub_cross_account::<T>()?;862 let from = from.into_sub_cross_account::<T>()?;868 let to = to.into_sub_cross_account::<T>()?;863 let to = to.into_sub_cross_account::<T>()?;888 /// @param tokenId The RFT to transfer883 /// @param tokenId The RFT to transfer889 #[solidity(hide)]884 #[solidity(hide)]890 #[weight(<SelfWeightOf<T>>::burn_from())]885 #[weight(<SelfWeightOf<T>>::burn_from())]891 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<()> {892 let caller = T::CrossAccountId::from_eth(caller);887 let caller = T::CrossAccountId::from_eth(caller);893 let from = T::CrossAccountId::from_eth(from);888 let from = T::CrossAccountId::from_eth(from);894 let token = token_id.try_into()?;889 let token = token_id.try_into()?;914 #[weight(<SelfWeightOf<T>>::burn_from())]909 #[weight(<SelfWeightOf<T>>::burn_from())]915 fn burn_from_cross(910 fn burn_from_cross(916 &mut self,911 &mut self,917 caller: caller,912 caller: Caller,918 from: eth::CrossAddress,913 from: eth::CrossAddress,919 token_id: uint256,914 token_id: U256,920 ) -> Result<void> {915 ) -> Result<()> {921 let caller = T::CrossAccountId::from_eth(caller);916 let caller = T::CrossAccountId::from_eth(caller);922 let from = from.into_sub_cross_account::<T>()?;917 let from = from.into_sub_cross_account::<T>()?;923 let token = token_id.try_into()?;918 let token = token_id.try_into()?;934 }929 }935930936 /// @notice Returns next free RFT ID.931 /// @notice Returns next free RFT ID.937 fn next_token_id(&self) -> Result<uint256> {932 fn next_token_id(&self) -> Result<U256> {938 self.consume_store_reads(1)?;933 self.consume_store_reads(1)?;939 Ok(<TokensMinted<T>>::get(self.id)934 Ok(<TokensMinted<T>>::get(self.id)940 .checked_add(1)935 .checked_add(1)949 /// @param tokenIds IDs of the minted RFTs944 /// @param tokenIds IDs of the minted RFTs950 #[solidity(hide)]945 #[solidity(hide)]951 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]946 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]952 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> {953 let caller = T::CrossAccountId::from_eth(caller);948 let caller = T::CrossAccountId::from_eth(caller);954 let to = T::CrossAccountId::from_eth(to);949 let to = T::CrossAccountId::from_eth(to);955 let mut expected_index = <TokensMinted<T>>::get(self.id)950 let mut expected_index = <TokensMinted<T>>::get(self.id)994 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]989 #[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]995 fn mint_bulk_with_token_uri(990 fn mint_bulk_with_token_uri(996 &mut self,991 &mut self,997 caller: caller,992 caller: Caller,998 to: address,993 to: Address,999 tokens: Vec<(uint256, string)>,994 tokens: Vec<(U256, String)>,1000 ) -> Result<bool> {995 ) -> Result<bool> {1001 let key = key::url();996 let key = key::url();1002 let caller = T::CrossAccountId::from_eth(caller);997 let caller = T::CrossAccountId::from_eth(caller);1051 #[weight(<SelfWeightOf<T>>::create_item())]1046 #[weight(<SelfWeightOf<T>>::create_item())]1052 fn mint_cross(1047 fn mint_cross(1053 &mut self,1048 &mut self,1054 caller: caller,1049 caller: Caller,1055 to: eth::CrossAddress,1050 to: eth::CrossAddress,1056 properties: Vec<eth::Property>,1051 properties: Vec<eth::Property>,1057 ) -> Result<uint256> {1052 ) -> Result<U256> {1058 let token_id = <TokensMinted<T>>::get(self.id)1053 let token_id = <TokensMinted<T>>::get(self.id)1059 .checked_add(1)1054 .checked_add(1)1060 .ok_or("item id overflow")?;1055 .ok_or("item id overflow")?;1093 /// Returns EVM address for refungible token1088 /// Returns EVM address for refungible token1094 ///1089 ///1095 /// @param token ID of the token1090 /// @param token ID of the token1096 fn token_contract_address(&self, token: uint256) -> Result<address> {1091 fn token_contract_address(&self, token: U256) -> Result<Address> {1097 Ok(T::EvmTokenAddressMapping::token_to_address(1092 Ok(T::EvmTokenAddressMapping::token_to_address(1098 self.id,1093 self.id,1099 token.try_into().map_err(|_| "token id overflow")?,1094 token.try_into().map_err(|_| "token id overflow")?,1100 ))1095 ))1101 }1096 }110210971103 /// @notice Returns collection helper contract address1098 /// @notice Returns collection helper contract address1104 fn collection_helper_address(&self) -> Result<address> {1099 fn collection_helper_address(&self) -> Result<Address> {1105 Ok(T::ContractAddress::get())1100 Ok(T::ContractAddress::get())1106 }1101 }1107}1102}pallets/refungible/src/erc_token.rsdiffbeforeafterboth37use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};37use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};38use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};38use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};39use sp_std::vec::Vec;39use sp_std::vec::Vec;40use sp_core::U256;40use up_data_structs::TokenId;41use up_data_structs::TokenId;414242use crate::{43use crate::{515252#[solidity_interface(name = ERC1633)]53#[solidity_interface(name = ERC1633)]53impl<T: Config> RefungibleTokenHandle<T> {54impl<T: Config> RefungibleTokenHandle<T> {54 fn parent_token(&self) -> Result<address> {55 fn parent_token(&self) -> Result<Address> {55 Ok(collection_id_to_address(self.id))56 Ok(collection_id_to_address(self.id))56 }57 }575858 fn parent_token_id(&self) -> Result<uint256> {59 fn parent_token_id(&self) -> Result<U256> {59 Ok(self.1.into())60 Ok(self.1.into())60 }61 }61}62}68 /// of burning tokens the transfer is to 0.69 /// of burning tokens the transfer is to 0.69 Transfer {70 Transfer {70 #[indexed]71 #[indexed]71 from: address,72 from: Address,72 #[indexed]73 #[indexed]73 to: address,74 to: Address,74 value: uint256,75 value: U256,75 },76 },76 /// @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 approved77 /// by the owner to be used by the spender.78 /// by the owner to be used by the spender.78 Approval {79 Approval {79 #[indexed]80 #[indexed]80 owner: address,81 owner: Address,81 #[indexed]82 #[indexed]82 spender: address,83 spender: Address,83 value: uint256,84 value: U256,84 },85 },85}86}868791#[solidity_interface(name = ERC20, events(ERC20Events))]92#[solidity_interface(name = ERC20, events(ERC20Events))]92impl<T: Config> RefungibleTokenHandle<T> {93impl<T: Config> RefungibleTokenHandle<T> {93 /// @return the name of the token.94 /// @return the name of the token.94 fn name(&self) -> Result<string> {95 fn name(&self) -> Result<String> {95 Ok(decode_utf16(self.name.iter().copied())96 Ok(decode_utf16(self.name.iter().copied())96 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))97 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))97 .collect::<string>())98 .collect::<String>())98 }99 }99100100 /// @return the symbol of the token.101 /// @return the symbol of the token.101 fn symbol(&self) -> Result<string> {102 fn symbol(&self) -> Result<String> {102 Ok(string::from_utf8_lossy(&self.token_prefix).into())103 Ok(String::from_utf8_lossy(&self.token_prefix).into())103 }104 }104105105 /// @dev Total number of tokens in existence106 /// @dev Total number of tokens in existence106 fn total_supply(&self) -> Result<uint256> {107 fn total_supply(&self) -> Result<U256> {107 self.consume_store_reads(1)?;108 self.consume_store_reads(1)?;108 Ok(<TotalSupply<T>>::get((self.id, self.1)).into())109 Ok(<TotalSupply<T>>::get((self.id, self.1)).into())109 }110 }110111111 /// @dev Not supported112 /// @dev Not supported112 fn decimals(&self) -> Result<uint8> {113 fn decimals(&self) -> Result<u8> {113 // Decimals aren't supported for refungible tokens114 // Decimals aren't supported for refungible tokens114 Ok(0)115 Ok(0)115 }116 }116117117 /// @dev Gets the balance of the specified address.118 /// @dev Gets the balance of the specified address.118 /// @param owner The address to query the balance of.119 /// @param owner The address to query the balance of.119 /// @return An uint256 representing the amount owned by the passed address.120 /// @return An uint256 representing the amount owned by the passed address.120 fn balance_of(&self, owner: address) -> Result<uint256> {121 fn balance_of(&self, owner: Address) -> Result<U256> {121 self.consume_store_reads(1)?;122 self.consume_store_reads(1)?;122 let owner = T::CrossAccountId::from_eth(owner);123 let owner = T::CrossAccountId::from_eth(owner);123 let balance = <Balance<T>>::get((self.id, self.1, owner));124 let balance = <Balance<T>>::get((self.id, self.1, owner));128 /// @param to The address to transfer to.129 /// @param to The address to transfer to.129 /// @param amount The amount to be transferred.130 /// @param amount The amount to be transferred.130 #[weight(<CommonWeights<T>>::transfer())]131 #[weight(<CommonWeights<T>>::transfer())]131 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> {132 let caller = T::CrossAccountId::from_eth(caller);133 let caller = T::CrossAccountId::from_eth(caller);133 let to = T::CrossAccountId::from_eth(to);134 let to = T::CrossAccountId::from_eth(to);134 let amount = amount.try_into().map_err(|_| "amount overflow")?;135 let amount = amount.try_into().map_err(|_| "amount overflow")?;148 #[weight(<CommonWeights<T>>::transfer_from())]149 #[weight(<CommonWeights<T>>::transfer_from())]149 fn transfer_from(150 fn transfer_from(150 &mut self,151 &mut self,151 caller: caller,152 caller: Caller,152 from: address,153 from: Address,153 to: address,154 to: Address,154 amount: uint256,155 amount: U256,155 ) -> Result<bool> {156 ) -> Result<bool> {156 let caller = T::CrossAccountId::from_eth(caller);157 let caller = T::CrossAccountId::from_eth(caller);157 let from = T::CrossAccountId::from_eth(from);158 let from = T::CrossAccountId::from_eth(from);174 /// @param spender The address which will spend the funds.175 /// @param spender The address which will spend the funds.175 /// @param amount The amount of tokens to be spent.176 /// @param amount The amount of tokens to be spent.176 #[weight(<SelfWeightOf<T>>::approve())]177 #[weight(<SelfWeightOf<T>>::approve())]177 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> {178 let caller = T::CrossAccountId::from_eth(caller);179 let caller = T::CrossAccountId::from_eth(caller);179 let spender = T::CrossAccountId::from_eth(spender);180 let spender = T::CrossAccountId::from_eth(spender);180 let amount = amount.try_into().map_err(|_| "amount overflow")?;181 let amount = amount.try_into().map_err(|_| "amount overflow")?;188 /// @param owner address The address which owns the funds.189 /// @param owner address The address which owns the funds.189 /// @param spender address The address which will spend the funds.190 /// @param spender address The address which will spend the funds.190 /// @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.191 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {192 fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {192 self.consume_store_reads(1)?;193 self.consume_store_reads(1)?;193 let owner = T::CrossAccountId::from_eth(owner);194 let owner = T::CrossAccountId::from_eth(owner);194 let spender = T::CrossAccountId::from_eth(spender);195 let spender = T::CrossAccountId::from_eth(spender);208 /// @param amount The amount that will be burnt.209 /// @param amount The amount that will be burnt.209 #[weight(<SelfWeightOf<T>>::burn_from())]210 #[weight(<SelfWeightOf<T>>::burn_from())]210 #[solidity(hide)]211 #[solidity(hide)]211 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> {212 let caller = T::CrossAccountId::from_eth(caller);213 let caller = T::CrossAccountId::from_eth(caller);213 let from = T::CrossAccountId::from_eth(from);214 let from = T::CrossAccountId::from_eth(from);214 let amount = amount.try_into().map_err(|_| "amount overflow")?;215 let amount = amount.try_into().map_err(|_| "amount overflow")?;228 #[weight(<SelfWeightOf<T>>::burn_from())]229 #[weight(<SelfWeightOf<T>>::burn_from())]229 fn burn_from_cross(230 fn burn_from_cross(230 &mut self,231 &mut self,231 caller: caller,232 caller: Caller,232 from: pallet_common::eth::CrossAddress,233 from: pallet_common::eth::CrossAddress,233 amount: uint256,234 amount: U256,234 ) -> Result<bool> {235 ) -> Result<bool> {235 let caller = T::CrossAccountId::from_eth(caller);236 let caller = T::CrossAccountId::from_eth(caller);236 let from = from.into_sub_cross_account::<T>()?;237 let from = from.into_sub_cross_account::<T>()?;254 #[weight(<SelfWeightOf<T>>::approve())]255 #[weight(<SelfWeightOf<T>>::approve())]255 fn approve_cross(256 fn approve_cross(256 &mut self,257 &mut self,257 caller: caller,258 caller: Caller,258 spender: pallet_common::eth::CrossAddress,259 spender: pallet_common::eth::CrossAddress,259 amount: uint256,260 amount: U256,260 ) -> Result<bool> {261 ) -> Result<bool> {261 let caller = T::CrossAccountId::from_eth(caller);262 let caller = T::CrossAccountId::from_eth(caller);262 let spender = spender.into_sub_cross_account::<T>()?;263 let spender = spender.into_sub_cross_account::<T>()?;270 /// Throws if `msg.sender` doesn't owns all of the tokens.271 /// Throws if `msg.sender` doesn't owns all of the tokens.271 /// @param amount New total amount of the tokens.272 /// @param amount New total amount of the tokens.272 #[weight(<SelfWeightOf<T>>::repartition_item())]273 #[weight(<SelfWeightOf<T>>::repartition_item())]273 fn repartition(&mut self, caller: caller, amount: uint256) -> Result<bool> {274 fn repartition(&mut self, caller: Caller, amount: U256) -> Result<bool> {274 let caller = T::CrossAccountId::from_eth(caller);275 let caller = T::CrossAccountId::from_eth(caller);275 let amount = amount.try_into().map_err(|_| "amount overflow")?;276 let amount = amount.try_into().map_err(|_| "amount overflow")?;276277284 #[weight(<CommonWeights<T>>::transfer())]285 #[weight(<CommonWeights<T>>::transfer())]285 fn transfer_cross(286 fn transfer_cross(286 &mut self,287 &mut self,287 caller: caller,288 caller: Caller,288 to: pallet_common::eth::CrossAddress,289 to: pallet_common::eth::CrossAddress,289 amount: uint256,290 amount: U256,290 ) -> Result<bool> {291 ) -> Result<bool> {291 let caller = T::CrossAccountId::from_eth(caller);292 let caller = T::CrossAccountId::from_eth(caller);292 let to = to.into_sub_cross_account::<T>()?;293 let to = to.into_sub_cross_account::<T>()?;307 #[weight(<CommonWeights<T>>::transfer_from())]308 #[weight(<CommonWeights<T>>::transfer_from())]308 fn transfer_from_cross(309 fn transfer_from_cross(309 &mut self,310 &mut self,310 caller: caller,311 caller: Caller,311 from: pallet_common::eth::CrossAddress,312 from: pallet_common::eth::CrossAddress,312 to: pallet_common::eth::CrossAddress,313 to: pallet_common::eth::CrossAddress,313 amount: uint256,314 amount: U256,314 ) -> Result<bool> {315 ) -> Result<bool> {315 let caller = T::CrossAccountId::from_eth(caller);316 let caller = T::CrossAccountId::from_eth(caller);316 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 {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!(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/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.jsondiffbeforeafterboth630 "type": "function"630 "type": "function"631 },631 },632 {632 {633 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],633 "inputs": [634 { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }635 ],634 "name": "setCollectionAccess",636 "name": "setCollectionAccess",635 "outputs": [],637 "outputs": [],tests/src/eth/abi/reFungible.jsondiffbeforeafterboth612 "type": "function"612 "type": "function"613 },613 },614 {614 {615 "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],615 "inputs": [616 { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }617 ],616 "name": "setCollectionAccess",618 "name": "setCollectionAccess",617 "outputs": [],619 "outputs": [],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 {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 {