difftreelog
Merge branch 'develop' into feature/CORE-37
in: master
21 files changed
crates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth1#![allow(dead_code)]1#![allow(dead_code)]223use quote::quote;3use quote::quote;4use darling::FromMeta;4use darling::{FromMeta, ToTokens};5use inflector::cases;5use inflector::cases;6use std::fmt::Write;6use std::fmt::Write;7use syn::{7use syn::{8 FnArg, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Meta, NestedMeta, PatType, Path,8 Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta,9 ReturnType, Type, spanned::Spanned,9 NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned,10};10};111112use crate::{12use crate::{13 fn_selector_str, parse_ident_from_pat, parse_ident_from_path, parse_ident_from_type,13 fn_selector_str, parse_ident_from_pat, parse_ident_from_path, parse_path, parse_path_segment,14 parse_result_ok, pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal,14 parse_result_ok, pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal,15 snake_ident_to_screaming,15 snake_ident_to_screaming,16};16};77 fn expand_generator(&self) -> proc_macro2::TokenStream {77 fn expand_generator(&self) -> proc_macro2::TokenStream {78 let pascal_call_name = &self.pascal_call_name;78 let pascal_call_name = &self.pascal_call_name;79 quote! {79 quote! {80 #pascal_call_name::generate_solidity_interface(out_set, is_impl);80 #pascal_call_name::generate_solidity_interface(tc, is_impl);81 }81 }82 }82 }838384 fn expand_event_generator(&self) -> proc_macro2::TokenStream {84 fn expand_event_generator(&self) -> proc_macro2::TokenStream {85 let name = &self.name;85 let name = &self.name;86 quote! {86 quote! {87 #name::generate_solidity_interface(out_set, is_impl);87 #name::generate_solidity_interface(tc, is_impl);88 }88 }89 }89 }90}90}121 rename_selector: Option<String>,121 rename_selector: Option<String>,122}122}123124enum AbiType {125 // type126 Plain(Ident),127 // (type1,type2)128 Tuple(Vec<AbiType>),129 // type[]130 Vec(Box<AbiType>),131 // type[20]132 Array(Box<AbiType>, usize),133}134impl AbiType {135 fn try_from(value: &Type) -> syn::Result<Self> {136 let value = Self::try_maybe_special_from(value)?;137 if value.is_special() {138 return Err(syn::Error::new(value.span(), "unexpected special type"));139 }140 Ok(value)141 }142 fn try_maybe_special_from(value: &Type) -> syn::Result<Self> {143 match value {144 Type::Array(arr) => {145 let wrapped = AbiType::try_from(&arr.elem)?;146 match &arr.len {147 Expr::Lit(l) => match &l.lit {148 Lit::Int(i) => {149 let num = i.base10_parse::<usize>()?;150 Ok(AbiType::Array(Box::new(wrapped), num as usize))151 }152 _ => Err(syn::Error::new(arr.len.span(), "should be int literal")),153 },154 _ => Err(syn::Error::new(arr.len.span(), "should be literal")),155 }156 }157 Type::Path(_) => {158 let path = parse_path(value)?;159 let segment = parse_path_segment(path)?;160 if segment.ident == "Vec" {161 let args = match &segment.arguments {162 PathArguments::AngleBracketed(e) => e,163 _ => {164 return Err(syn::Error::new(165 segment.arguments.span(),166 "missing Vec generic",167 ))168 }169 };170 let args = &args.args;171 if args.len() != 1 {172 return Err(syn::Error::new(173 args.span(),174 "expected only one generic for vec",175 ));176 }177 let arg = args.first().unwrap();178179 let ty = match arg {180 GenericArgument::Type(ty) => ty,181 _ => {182 return Err(syn::Error::new(183 arg.span(),184 "expected first generic to be type",185 ))186 }187 };188189 let wrapped = AbiType::try_from(ty)?;190 Ok(Self::Vec(Box::new(wrapped)))191 } else {192 if !segment.arguments.is_empty() {193 return Err(syn::Error::new(194 segment.arguments.span(),195 "unexpected generic arguments for non-vec type",196 ));197 }198 Ok(Self::Plain(segment.ident.clone()))199 }200 }201 Type::Tuple(t) => {202 let mut out = Vec::with_capacity(t.elems.len());203 for el in t.elems.iter() {204 out.push(AbiType::try_from(el)?)205 }206 Ok(Self::Tuple(out))207 }208 _ => Err(syn::Error::new(209 value.span(),210 "unexpected type, only arrays, plain types and tuples are supported",211 )),212 }213 }214 fn is_value(&self) -> bool {215 match self {216 Self::Plain(v) if v == "value" => true,217 _ => false,218 }219 }220 fn is_caller(&self) -> bool {221 match self {222 Self::Plain(v) if v == "caller" => true,223 _ => false,224 }225 }226 fn is_special(&self) -> bool {227 self.is_caller() || self.is_value()228 }229 fn selector_ty_buf(&self, buf: &mut String) -> std::fmt::Result {230 match self {231 AbiType::Plain(t) => {232 write!(buf, "{}", t)233 }234 AbiType::Tuple(t) => {235 write!(buf, "(")?;236 for (i, t) in t.iter().enumerate() {237 if i != 0 {238 write!(buf, ",")?;239 }240 t.selector_ty_buf(buf)?;241 }242 write!(buf, ")")243 }244 AbiType::Vec(v) => {245 v.selector_ty_buf(buf)?;246 write!(buf, "[]")247 }248 AbiType::Array(v, len) => {249 v.selector_ty_buf(buf)?;250 write!(buf, "[{}]", len)251 }252 }253 }254 fn selector_ty(&self) -> String {255 let mut out = String::new();256 self.selector_ty_buf(&mut out).expect("no fmt error");257 out258 }259}260impl ToTokens for AbiType {261 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {262 match self {263 AbiType::Plain(t) => tokens.extend(quote! {#t}),264 AbiType::Tuple(t) => {265 tokens.extend(quote! {(266 #(#t),*267 )});268 }269 AbiType::Vec(v) => tokens.extend(quote! {Vec<#v>}),270 AbiType::Array(v, l) => tokens.extend(quote! {[#v; #l]}),271 }272 }273}123274124struct MethodArg {275struct MethodArg {125 name: Ident,276 name: Ident,126 camel_name: String,277 camel_name: String,127 ty: Ident,278 ty: AbiType,128}279}129impl MethodArg {280impl MethodArg {130 fn try_from(value: &PatType) -> syn::Result<Self> {281 fn try_from(value: &PatType) -> syn::Result<Self> {131 let name = parse_ident_from_pat(&value.pat)?.clone();282 let name = parse_ident_from_pat(&value.pat)?.clone();132 Ok(Self {283 Ok(Self {133 camel_name: cases::camelcase::to_camel_case(&name.to_string()),284 camel_name: cases::camelcase::to_camel_case(&name.to_string()),134 name,285 name,135 ty: parse_ident_from_type(&value.ty, false)?.clone(),286 ty: AbiType::try_maybe_special_from(&value.ty)?,136 })287 })137 }288 }138 fn is_value(&self) -> bool {289 fn is_value(&self) -> bool {139 self.ty == "value"290 self.ty.is_value()140 }291 }141 fn is_caller(&self) -> bool {292 fn is_caller(&self) -> bool {142 self.ty == "caller"293 self.ty.is_caller()143 }294 }144 fn is_special(&self) -> bool {295 fn is_special(&self) -> bool {145 self.is_value() || self.is_caller()296 self.ty.is_special()146 }297 }147 fn selector_ty(&self) -> &Ident {298 fn selector_ty(&self) -> String {148 assert!(!self.is_special());299 assert!(!self.is_special());149 &self.ty300 self.ty.selector_ty()150 }301 }151302152 fn expand_call_def(&self) -> proc_macro2::TokenStream {303 fn expand_call_def(&self) -> proc_macro2::TokenStream {419 .iter()570 .iter()420 .filter(|a| !a.is_special())571 .filter(|a| !a.is_special())421 .map(MethodArg::expand_solidity_argument);572 .map(MethodArg::expand_solidity_argument);573 let selector = format!("{} {:0>8x}", self.selector_str, self.selector);422574423 quote! {575 quote! {424 SolidityFunction {576 SolidityFunction {577 selector: #selector,425 name: #camel_name,578 name: #camel_name,426 mutability: #mutability,579 mutability: #mutability,427 args: (580 args: (544 )*697 )*545 )698 )546 }699 }547 pub fn generate_solidity_interface(out_set: &mut sp_std::collections::btree_set::BTreeSet<string>, is_impl: bool) {700 pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {548 use evm_coder::solidity::*;701 use evm_coder::solidity::*;549 use core::fmt::Write;702 use core::fmt::Write;550 let interface = SolidityInterface {703 let interface = SolidityInterface {559 )*),712 )*),560 };713 };561 if is_impl {714 if is_impl {562 out_set.insert("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\n".into());715 tc.collect("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\n".into());563 } else {716 } else {564 out_set.insert("// Common stubs holder\ninterface Dummy {\n}\n".into());717 tc.collect("// Common stubs holder\ninterface Dummy {\n}\n".into());565 }718 }566 #(719 #(567 #solidity_generators720 #solidity_generators576 if #solidity_name.starts_with("Inline") {729 if #solidity_name.starts_with("Inline") {577 out.push_str("// Inline\n");730 out.push_str("// Inline\n");578 }731 }579 let _ = interface.format(is_impl, &mut out);732 let _ = interface.format(is_impl, &mut out, tc);580 out_set.insert(out);733 tc.collect(out);581 }734 }582 }735 }583 impl ::evm_coder::Call for #call_name {736 impl ::evm_coder::Call for #call_name {crates/evm-coder-macros/src/to_log.rsdiffbeforeafterboth179 #consts179 #consts180 )*180 )*181181182 pub fn generate_solidity_interface(out_set: &mut sp_std::collections::btree_set::BTreeSet<string>, is_impl: bool) {182 pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {183 use evm_coder::solidity::*;183 use evm_coder::solidity::*;184 use core::fmt::Write;184 use core::fmt::Write;185 let interface = SolidityInterface {185 let interface = SolidityInterface {191 };191 };192 let mut out = string::new();192 let mut out = string::new();193 out.push_str("// Inline\n");193 out.push_str("// Inline\n");194 let _ = interface.format(is_impl, &mut out);194 let _ = interface.format(is_impl, &mut out, tc);195 out_set.insert(out);195 tc.collect(out);196 }196 }197 }197 }198198crates/evm-coder/src/abi.rsdiffbeforeafterboth211 self.memory(value.as_bytes())211 self.memory(value.as_bytes())212 }212 }213214 pub fn bytes(&mut self, value: &[u8]) {215 self.memory(value)216 }213217214 pub fn finish(mut self) -> Vec<u8> {218 pub fn finish(mut self) -> Vec<u8> {215 for (static_offset, part) in self.dynamic_part {219 for (static_offset, part) in self.dynamic_part {247impl_abi_readable!(bool, bool);251impl_abi_readable!(bool, bool);248impl_abi_readable!(string, string);252impl_abi_readable!(string, string);253254mod sealed {255 /// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead256 pub trait CanBePlacedInVec {}257}258259impl sealed::CanBePlacedInVec for U256 {}260impl sealed::CanBePlacedInVec for string {}261impl sealed::CanBePlacedInVec for H160 {}262263impl<R: sealed::CanBePlacedInVec> AbiRead<Vec<R>> for AbiReader<'_>264where265 Self: AbiRead<R>,266{267 fn abi_read(&mut self) -> Result<Vec<R>> {268 let mut sub = self.subresult()?;269 let size = sub.read_usize()?;270 sub.subresult_offset = sub.offset;271 let mut out = Vec::with_capacity(size);272 for _ in 0..size {273 out.push(<Self as AbiRead<R>>::abi_read(&mut sub)?);274 }275 Ok(out)276 }277}278279macro_rules! impl_tuples {280 ($($ident:ident)+) => {281 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}282 impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_>283 where284 $(Self: AbiRead<$ident>),+285 {286 fn abi_read(&mut self) -> Result<($($ident,)+)> {287 let mut subresult = self.subresult()?;288 Ok((289 $(<Self as AbiRead<$ident>>::abi_read(&mut subresult)?,)+290 ))291 }292 }293 };294}295296impl_tuples! {A}297impl_tuples! {A B}298impl_tuples! {A B C}299impl_tuples! {A B C D}300impl_tuples! {A B C D E}301impl_tuples! {A B C D E F}302impl_tuples! {A B C D E F G}303impl_tuples! {A B C D E F G H}304impl_tuples! {A B C D E F G H I}305impl_tuples! {A B C D E F G H I J}249306250pub trait AbiWrite {307pub trait AbiWrite {251 fn abi_write(&self, writer: &mut AbiWriter);308 fn abi_write(&self, writer: &mut AbiWriter);273 writer.string(self)330 writer.string(self)274 }331 }275}332}333impl AbiWrite for &Vec<u8> {334 fn abi_write(&self, writer: &mut AbiWriter) {335 writer.bytes(self)336 }337}276338277impl AbiWrite for () {339impl AbiWrite for () {278 fn abi_write(&self, _writer: &mut AbiWriter) {}340 fn abi_write(&self, _writer: &mut AbiWriter) {}308370309#[cfg(test)]371#[cfg(test)]310pub mod test {372pub mod test {373 use crate::{374 abi::AbiRead,375 types::{string, uint256},376 };377311 use super::{AbiReader, AbiWriter};378 use super::{AbiReader, AbiWriter};312 use hex_literal::hex;379 use hex_literal::hex;356 assert_eq!(decoder.string().unwrap(), "Test URI");423 assert_eq!(decoder.string().unwrap(), "Test URI");357 }424 }425426 #[test]427 fn mint_bulk() {428 let (call, mut decoder) = AbiReader::new_call(&hex!(429 "430 36543006431 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address432 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]433 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]434435 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem436 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem437 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem438439 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60440 0000000000000000000000000000000000000000000000000000000000000040 // offset of string441 000000000000000000000000000000000000000000000000000000000000000a // size of string442 5465737420555249203000000000000000000000000000000000000000000000 // string443444 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0445 0000000000000000000000000000000000000000000000000000000000000040 // offset of string446 000000000000000000000000000000000000000000000000000000000000000a // size of string447 5465737420555249203100000000000000000000000000000000000000000000 // string448449 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160450 0000000000000000000000000000000000000000000000000000000000000040 // offset of string451 000000000000000000000000000000000000000000000000000000000000000a // size of string452 5465737420555249203200000000000000000000000000000000000000000000 // string453 "454 ))455 .unwrap();456 assert_eq!(call, 0x36543006);457 let _ = decoder.address().unwrap();458 let data =459 <AbiReader<'_> as AbiRead<Vec<(uint256, string)>>>::abi_read(&mut decoder).unwrap();460 assert_eq!(461 data,462 vec![463 (1.into(), "Test URI 0".to_string()),464 (11.into(), "Test URI 1".to_string()),465 (12.into(), "Test URI 2".to_string())466 ]467 );468 }358}469}359470crates/evm-coder/src/lib.rsdiffbeforeafterboth67 #[test]67 #[test]68 #[ignore]68 #[ignore]69 fn $name() {69 fn $name() {70 use sp_std::collections::btree_set::BTreeSet;70 use evm_coder::solidity::TypeCollector;71 let mut out = BTreeSet::new();71 let mut out = TypeCollector::new();72 $decl::generate_solidity_interface(&mut out, $is_impl);72 $decl::generate_solidity_interface(&mut out, $is_impl);73 println!("=== SNIP START ===");73 println!("=== SNIP START ===");74 println!("// SPDX-License-Identifier: OTHER");74 println!("// SPDX-License-Identifier: OTHER");75 println!("// This code is automatically generated");75 println!("// This code is automatically generated");76 println!();76 println!();77 println!("pragma solidity >=0.8.0 <0.9.0;");77 println!("pragma solidity >=0.8.0 <0.9.0;");78 println!();78 println!();79 for b in out {79 for b in out.finish() {80 println!("{}", b);80 println!("{}", b);81 }81 }82 println!("=== SNIP END ===");82 println!("=== SNIP END ===");crates/evm-coder/src/solidity.rsdiffbeforeafterboth1#[cfg(not(feature = "std"))]1#[cfg(not(feature = "std"))]2use alloc::{string::String};2use alloc::{3 string::String,4 vec::Vec,5 collections::{BTreeSet, BTreeMap},6 format,7};8#[cfg(feature = "std")]9use std::collections::{BTreeSet, BTreeMap};3use core::{fmt, marker::PhantomData};10use core::{11 fmt::{self, Write},12 marker::PhantomData,13 cell::{Cell, RefCell},14};4use impl_trait_for_tuples::impl_for_tuples;15use impl_trait_for_tuples::impl_for_tuples;5use crate::types::*;16use crate::types::*;1718#[derive(Default)]19pub struct TypeCollector {20 structs: RefCell<BTreeSet<string>>,21 anonymous: RefCell<BTreeMap<Vec<string>, usize>>,22 id: Cell<usize>,23}24impl TypeCollector {25 pub fn new() -> Self {26 Self::default()27 }28 pub fn collect(&self, item: string) {29 self.structs.borrow_mut().insert(item);30 }31 pub fn next_id(&self) -> usize {32 let v = self.id.get();33 self.id.set(v + 1);34 v35 }36 pub fn collect_tuple<T: SolidityTupleType>(&self) -> String {37 let names = T::names(self);38 if let Some(id) = self.anonymous.borrow().get(&names).cloned() {39 return format!("Tuple{}", id);40 }41 let id = self.next_id();42 let mut str = String::new();43 writeln!(str, "// Anonymous struct").unwrap();44 writeln!(str, "struct Tuple{} {{", id).unwrap();45 for (i, name) in names.iter().enumerate() {46 writeln!(str, "\t{} field_{};", name, i).unwrap();47 }48 writeln!(str, "}}").unwrap();49 self.collect(str);50 self.anonymous.borrow_mut().insert(names, id);51 format!("Tuple{}", id)52 }53 pub fn finish(self) -> BTreeSet<string> {54 self.structs.into_inner()55 }56}6577pub trait SolidityTypeName: 'static {58pub trait SolidityTypeName: 'static {8 fn solidity_name(writer: &mut impl fmt::Write) -> fmt::Result;59 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;60 fn is_simple() -> bool;9 fn solidity_default(writer: &mut impl fmt::Write) -> fmt::Result;61 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;10 fn is_void() -> bool {62 fn is_void() -> bool {11 false63 false12 }64 }13}65}1415macro_rules! solidity_type_name {66macro_rules! solidity_type_name {16 ($($ty:ident => $name:literal = $default:literal),* $(,)?) => {67 ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => {17 $(68 $(18 impl SolidityTypeName for $ty {69 impl SolidityTypeName for $ty {19 fn solidity_name(writer: &mut impl core::fmt::Write) -> core::fmt::Result {70 fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {20 write!(writer, $name)71 write!(writer, $name)21 }72 }73 fn is_simple() -> bool {74 $simple75 }22 fn solidity_default(writer: &mut impl core::fmt::Write) -> core::fmt::Result {76 fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {23 write!(writer, $default)77 write!(writer, $default)24 }78 }25 }79 }28}82}298330solidity_type_name! {84solidity_type_name! {31 uint8 => "uint8" = "0",85 uint8 => "uint8" true = "0",32 uint32 => "uint32" = "0",86 uint32 => "uint32" true = "0",33 uint128 => "uint128" = "0",87 uint128 => "uint128" true = "0",34 uint256 => "uint256" = "0",88 uint256 => "uint256" true = "0",35 address => "address" = "0x0000000000000000000000000000000000000000",89 address => "address" true = "0x0000000000000000000000000000000000000000",36 string => "string memory" = "\"\"",90 string => "string" false = "\"\"",37 bytes => "bytes memory" = "hex\"\"",91 bytes => "bytes" false = "hex\"\"",38 bool => "bool" = "false",92 bool => "bool" true = "false",39}93}40impl SolidityTypeName for void {94impl SolidityTypeName for void {41 fn solidity_name(_writer: &mut impl fmt::Write) -> fmt::Result {95 fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {42 Ok(())96 Ok(())43 }97 }98 fn is_simple() -> bool {99 true100 }44 fn solidity_default(_writer: &mut impl fmt::Write) -> fmt::Result {101 fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {45 Ok(())102 Ok(())46 }103 }47 fn is_void() -> bool {104 fn is_void() -> bool {48 true105 true49 }106 }50}107}108109mod sealed {110 pub trait CanBePlacedInVec {}111}112113impl sealed::CanBePlacedInVec for uint256 {}114impl sealed::CanBePlacedInVec for string {}115impl sealed::CanBePlacedInVec for address {}116117impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {118 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {119 T::solidity_name(writer, tc)?;120 write!(writer, "[]")121 }122 fn is_simple() -> bool {123 false124 }125 fn solidity_default(writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {126 write!(writer, "[]")127 }128}129130pub trait SolidityTupleType {131 fn names(tc: &TypeCollector) -> Vec<String>;132 fn len() -> usize;133}134135macro_rules! count {136 () => (0usize);137 ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));138}139140macro_rules! impl_tuples {141 ($($ident:ident)+) => {142 impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}143 impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleType for ($($ident,)+) {144 fn names(tc: &TypeCollector) -> Vec<string> {145 let mut collected = Vec::with_capacity(Self::len());146 $({147 let mut out = string::new();148 $ident::solidity_name(&mut out, tc).expect("no fmt error");149 collected.push(out);150 })*;151 collected152 }153154 fn len() -> usize {155 count!($($ident)*)156 }157 }158 impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) {159 fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {160 write!(writer, "{}", tc.collect_tuple::<Self>())161 }162 fn is_simple() -> bool {163 false164 }165 fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {166 write!(writer, "{}(", tc.collect_tuple::<Self>())?;167 $(168 <$ident>::solidity_default(writer, tc)?;169 )*170 write!(writer, ")")171 }172 }173 };174}175176impl_tuples! {A}177impl_tuples! {A B}178impl_tuples! {A B C}179impl_tuples! {A B C D}180impl_tuples! {A B C D E}181impl_tuples! {A B C D E F}182impl_tuples! {A B C D E F G}183impl_tuples! {A B C D E F G H}184impl_tuples! {A B C D E F G H I}185impl_tuples! {A B C D E F G H I J}5118652pub trait SolidityArguments {187pub trait SolidityArguments {53 fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result;188 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;54 fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result;189 fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result;55 fn solidity_default(&self, writer: &mut impl fmt::Write) -> fmt::Result;190 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;56 fn is_empty(&self) -> bool {191 fn is_empty(&self) -> bool {57 self.len() == 0192 self.len() == 058 }193 }63pub struct UnnamedArgument<T>(PhantomData<*const T>);198pub struct UnnamedArgument<T>(PhantomData<*const T>);6419965impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {200impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {66 fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {201 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {67 if !T::is_void() {202 if !T::is_void() {68 T::solidity_name(writer)203 T::solidity_name(writer, tc)?;204 if !T::is_simple() {205 write!(writer, " memory")?;206 }207 Ok(())69 } else {208 } else {70 Ok(())209 Ok(())71 }210 }72 }211 }73 fn solidity_get(&self, _writer: &mut impl fmt::Write) -> fmt::Result {212 fn solidity_get(&self, _writer: &mut impl fmt::Write) -> fmt::Result {74 Ok(())213 Ok(())75 }214 }76 fn solidity_default(&self, writer: &mut impl fmt::Write) -> fmt::Result {215 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {77 T::solidity_default(writer)216 T::solidity_default(writer, tc)78 }217 }79 fn len(&self) -> usize {218 fn len(&self) -> usize {80 if T::is_void() {219 if T::is_void() {94}233}9523496impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {235impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {97 fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {236 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {98 if !T::is_void() {237 if !T::is_void() {99 T::solidity_name(writer)?;238 T::solidity_name(writer, tc)?;239 if !T::is_simple() {240 write!(writer, " memory")?;241 }100 write!(writer, " {}", self.0)242 write!(writer, " {}", self.0)101 } else {243 } else {102 Ok(())244 Ok(())105 fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result {247 fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result {106 writeln!(writer, "\t\t{};", self.0)248 writeln!(writer, "\t\t{};", self.0)107 }249 }108 fn solidity_default(&self, writer: &mut impl fmt::Write) -> fmt::Result {250 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {109 T::solidity_default(writer)251 T::solidity_default(writer, tc)110 }252 }111 fn len(&self) -> usize {253 fn len(&self) -> usize {112 if T::is_void() {254 if T::is_void() {126}268}127269128impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {270impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {129 fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {271 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {130 if !T::is_void() {272 if !T::is_void() {131 T::solidity_name(writer)?;273 T::solidity_name(writer, tc)?;132 if self.0 {274 if self.0 {133 write!(writer, " indexed")?;275 write!(writer, " indexed")?;134 }276 }140 fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result {282 fn solidity_get(&self, writer: &mut impl fmt::Write) -> fmt::Result {141 writeln!(writer, "\t\t{};", self.1)283 writeln!(writer, "\t\t{};", self.1)142 }284 }143 fn solidity_default(&self, writer: &mut impl fmt::Write) -> fmt::Result {285 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {144 T::solidity_default(writer)286 T::solidity_default(writer, tc)145 }287 }146 fn len(&self) -> usize {288 fn len(&self) -> usize {147 if T::is_void() {289 if T::is_void() {153}295}154296155impl SolidityArguments for () {297impl SolidityArguments for () {156 fn solidity_name(&self, _writer: &mut impl fmt::Write) -> fmt::Result {298 fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {157 Ok(())299 Ok(())158 }300 }159 fn solidity_get(&self, _writer: &mut impl fmt::Write) -> fmt::Result {301 fn solidity_get(&self, _writer: &mut impl fmt::Write) -> fmt::Result {160 Ok(())302 Ok(())161 }303 }162 fn solidity_default(&self, _writer: &mut impl fmt::Write) -> fmt::Result {304 fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {163 Ok(())305 Ok(())164 }306 }165 fn len(&self) -> usize {307 fn len(&self) -> usize {171impl SolidityArguments for Tuple {313impl SolidityArguments for Tuple {172 for_tuples!( where #( Tuple: SolidityArguments ),* );314 for_tuples!( where #( Tuple: SolidityArguments ),* );173315174 fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result {316 fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {175 let mut first = true;317 let mut first = true;176 for_tuples!( #(318 for_tuples!( #(177 if !Tuple.is_empty() {319 if !Tuple.is_empty() {178 if !first {320 if !first {179 write!(writer, ", ")?;321 write!(writer, ", ")?;180 }322 }181 first = false;323 first = false;182 Tuple.solidity_name(writer)?;324 Tuple.solidity_name(writer, tc)?;183 }325 }184 )* );326 )* );185 Ok(())327 Ok(())190 )* );332 )* );191 Ok(())333 Ok(())192 }334 }193 fn solidity_default(&self, writer: &mut impl fmt::Write) -> fmt::Result {335 fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {194 if self.is_empty() {336 if self.is_empty() {195 Ok(())337 Ok(())196 } else if self.len() == 1 {338 } else if self.len() == 1 {197 for_tuples!( #(339 for_tuples!( #(198 Tuple.solidity_default(writer)?;340 Tuple.solidity_default(writer, tc)?;199 )* );341 )* );200 Ok(())342 Ok(())201 } else {343 } else {207 write!(writer, ", ")?;349 write!(writer, ", ")?;208 }350 }209 first = false;351 first = false;210 Tuple.solidity_name(writer)?;352 Tuple.solidity_default(writer, tc)?;211 }353 }212 )* );354 )* );213 write!(writer, ")")?;355 write!(writer, ")")?;223 fn solidity_name(&self, is_impl: bool, writer: &mut impl fmt::Write) -> fmt::Result;365 fn solidity_name(366 &self,367 is_impl: bool,368 writer: &mut impl fmt::Write,369 tc: &TypeCollector,370 ) -> fmt::Result;224}371}225372229 Mutable,376 Mutable,230}377}231pub struct SolidityFunction<A, R> {378pub struct SolidityFunction<A, R> {379 pub selector: &'static str,232 pub name: &'static str,380 pub name: &'static str,233 pub args: A,381 pub args: A,234 pub result: R,382 pub result: R,235 pub mutability: SolidityMutability,383 pub mutability: SolidityMutability,236}384}237impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {385impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {238 fn solidity_name(&self, is_impl: bool, writer: &mut impl fmt::Write) -> fmt::Result {386 fn solidity_name(387 &self,388 is_impl: bool,389 writer: &mut impl fmt::Write,390 tc: &TypeCollector,391 ) -> fmt::Result {392 writeln!(writer, "\t// Selector: {}", self.selector)?;239 write!(writer, "\tfunction {}(", self.name)?;393 write!(writer, "\tfunction {}(", self.name)?;240 self.args.solidity_name(writer)?;394 self.args.solidity_name(writer, tc)?;241 write!(writer, ")")?;395 write!(writer, ")")?;242 if is_impl {396 if is_impl {243 write!(writer, " public")?;397 write!(writer, " public")?;251 }405 }252 if !self.result.is_empty() {406 if !self.result.is_empty() {253 write!(writer, " returns (")?;407 write!(writer, " returns (")?;254 self.result.solidity_name(writer)?;408 self.result.solidity_name(writer, tc)?;255 write!(writer, ")")?;409 write!(writer, ")")?;256 }410 }257 if is_impl {411 if is_impl {265 }419 }266 if !self.result.is_empty() {420 if !self.result.is_empty() {267 write!(writer, "\t\treturn ")?;421 write!(writer, "\t\treturn ")?;268 self.result.solidity_default(writer)?;422 self.result.solidity_default(writer, tc)?;269 writeln!(writer, ";")?;423 writeln!(writer, ";")?;270 }424 }271 writeln!(writer, "\t}}")?;425 writeln!(writer, "\t}}")?;283 fn solidity_name(&self, is_impl: bool, writer: &mut impl fmt::Write) -> fmt::Result {437 fn solidity_name(438 &self,439 is_impl: bool,440 writer: &mut impl fmt::Write,441 tc: &TypeCollector,442 ) -> fmt::Result {284 let mut first = false;443 let mut first = false;285 for_tuples!( #(444 for_tuples!( #(286 Tuple.solidity_name(is_impl, writer)?;445 Tuple.solidity_name(is_impl, writer, tc)?;287 )* );446 )* );288 Ok(())447 Ok(())289 }448 }299 pub fn format(&self, is_impl: bool, out: &mut impl fmt::Write) -> fmt::Result {458 pub fn format(459 &self,460 is_impl: bool,461 out: &mut impl fmt::Write,462 tc: &TypeCollector,463 ) -> fmt::Result {300 if is_impl {464 if is_impl {301 write!(out, "contract ")?;465 write!(out, "contract ")?;313 }477 }314 }478 }315 writeln!(out, " {{")?;479 writeln!(out, " {{")?;316 self.functions.solidity_name(is_impl, out)?;480 self.functions.solidity_name(is_impl, out, tc)?;317 writeln!(out, "}}")?;481 writeln!(out, "}}")?;318 Ok(())482 Ok(())319 }483 }328 fn solidity_name(&self, _is_impl: bool, writer: &mut impl fmt::Write) -> fmt::Result {492 fn solidity_name(493 &self,494 _is_impl: bool,495 writer: &mut impl fmt::Write,496 tc: &TypeCollector,497 ) -> fmt::Result {329 write!(writer, "\tevent {}(", self.name)?;498 write!(writer, "\tevent {}(", self.name)?;330 self.args.solidity_name(writer)?;499 self.args.solidity_name(writer, tc)?;331 writeln!(writer, ");")500 writeln!(writer, ");")332 }501 }333}502}pallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth10}10}111112contract ContractHelpers is Dummy {12contract ContractHelpers is Dummy {13 // Selector: contractOwner(address) 5152b14c13 function contractOwner(address contractAddress)14 function contractOwner(address contractAddress)14 public15 public15 view16 view21 return 0x0000000000000000000000000000000000000000;22 return 0x0000000000000000000000000000000000000000;22 }23 }232425 // Selector: sponsoringEnabled(address) 6027dc6124 function sponsoringEnabled(address contractAddress)26 function sponsoringEnabled(address contractAddress)25 public27 public26 view28 view32 return false;34 return false;33 }35 }343637 // Selector: toggleSponsoring(address,bool) fcac6d8635 function toggleSponsoring(address contractAddress, bool enabled) public {38 function toggleSponsoring(address contractAddress, bool enabled) public {36 require(false, stub_error);39 require(false, stub_error);37 contractAddress;40 contractAddress;38 enabled;41 enabled;39 dummy = 0;42 dummy = 0;40 }43 }414445 // Selector: setSponsoringRateLimit(address,uint32) 77b6c90842 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)46 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)43 public47 public44 {48 {48 dummy = 0;52 dummy = 0;49 }53 }505455 // Selector: allowed(address,address) 5c65816551 function allowed(address contractAddress, address user)56 function allowed(address contractAddress, address user)52 public57 public53 view58 view60 return false;65 return false;61 }66 }626768 // Selector: allowlistEnabled(address) c772ef6c63 function allowlistEnabled(address contractAddress)69 function allowlistEnabled(address contractAddress)64 public70 public65 view71 view71 return false;77 return false;72 }78 }737980 // Selector: toggleAllowlist(address,bool) 36de20f574 function toggleAllowlist(address contractAddress, bool enabled) public {81 function toggleAllowlist(address contractAddress, bool enabled) public {75 require(false, stub_error);82 require(false, stub_error);76 contractAddress;83 contractAddress;77 enabled;84 enabled;78 dummy = 0;85 dummy = 0;79 }86 }808788 // Selector: toggleAllowed(address,address,bool) 4706cc1c81 function toggleAllowed(89 function toggleAllowed(82 address contractAddress,90 address contractAddress,83 address user,91 address user,pallets/nft/src/eth/erc.rsdiffbeforeafterboth8};8};9use frame_support::storage::{StorageMap, StorageDoubleMap};9use frame_support::storage::{StorageMap, StorageDoubleMap};10use pallet_evm::AddressMapping;10use pallet_evm::AddressMapping;11use pallet_evm_coder_substrate::dispatch_to_evm;11use super::account::CrossAccountId;12use super::account::CrossAccountId;12use sp_std::{vec, vec::Vec};13use sp_std::{vec, vec::Vec};1314300 .into())301 .into())301 }302 }303304 fn set_variable_metadata(305 &mut self,306 caller: caller,307 token_id: uint256,308 data: bytes,309 ) -> Result<void> {310 let caller = T::CrossAccountId::from_eth(caller);311 let token_id = token_id.try_into().map_err(|_| "token id overflow")?;312313 <Module<T>>::set_variable_meta_data_internal(&caller, self, token_id, data)314 .map_err(dispatch_to_evm::<T>)?;315 Ok(())316 }317318 fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {319 let token_id = token_id.try_into().map_err(|_| "token id overflow")?;320321 <Module<T>>::get_variable_metadata(self, token_id).map_err(dispatch_to_evm::<T>)322 }323324 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {325 let caller = T::CrossAccountId::from_eth(caller);326 let to = T::CrossAccountId::from_eth(to);327 let mut expected_index = <ItemListIndex>::get(self.id)328 .checked_add(1)329 .ok_or("item id overflow")?;330331 let total_tokens = token_ids.len();332 for id in token_ids.into_iter() {333 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;334 if id != expected_index {335 return Err("item id should be next".into());336 }337 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;338 }339340 let data = (0..total_tokens)341 .map(|_| {342 CreateItemData::NFT(CreateNftData {343 const_data: vec![].try_into().unwrap(),344 variable_data: vec![].try_into().unwrap(),345 })346 })347 .collect();348349 <Module<T>>::create_multiple_items_internal(&caller, self, &to, data)350 .map_err(dispatch_to_evm::<T>)?;351 Ok(true)352 }353354 #[solidity(rename_selector = "mintBulkWithTokenURI")]355 fn mint_bulk_with_token_uri(356 &mut self,357 caller: caller,358 to: address,359 tokens: Vec<(uint256, string)>,360 ) -> Result<bool> {361 let caller = T::CrossAccountId::from_eth(caller);362 let to = T::CrossAccountId::from_eth(to);363 let mut expected_index = <ItemListIndex>::get(self.id)364 .checked_add(1)365 .ok_or("item id overflow")?;366367 let mut data = Vec::with_capacity(tokens.len());368 for (id, token_uri) in tokens {369 let id: u32 = id.try_into().map_err(|_| "token id overflow")?;370 if id != expected_index {371 panic!("item id should be next ({}) but got {}", expected_index, id);372 }373 expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;374375 data.push(CreateItemData::NFT(CreateNftData {376 const_data: Vec::<u8>::from(token_uri)377 .try_into()378 .map_err(|_| "token uri is too long")?,379 variable_data: vec![].try_into().unwrap(),380 }));381 }382383 <Module<T>>::create_multiple_items_internal(&caller, self, &to, data)384 .map_err(dispatch_to_evm::<T>)?;385 Ok(true)386 }302}387}303388304#[solidity_interface(389#[solidity_interface(pallets/nft/src/eth/stubs/UniqueFungible.soldiffbeforeafterboth212122// Inline22// Inline23contract InlineNameSymbol is Dummy {23contract InlineNameSymbol is Dummy {24 // Selector: name() 06fdde0324 function name() public view returns (string memory) {25 function name() public view returns (string memory) {25 require(false, stub_error);26 require(false, stub_error);26 dummy;27 dummy;27 return "";28 return "";28 }29 }293031 // Selector: symbol() 95d89b4130 function symbol() public view returns (string memory) {32 function symbol() public view returns (string memory) {31 require(false, stub_error);33 require(false, stub_error);32 dummy;34 dummy;363837// Inline39// Inline38contract InlineTotalSupply is Dummy {40contract InlineTotalSupply is Dummy {41 // Selector: totalSupply() 18160ddd39 function totalSupply() public view returns (uint256) {42 function totalSupply() public view returns (uint256) {40 require(false, stub_error);43 require(false, stub_error);41 dummy;44 dummy;44}47}454846contract ERC165 is Dummy {49contract ERC165 is Dummy {50 // Selector: supportsInterface(bytes4) 01ffc9a747 function supportsInterface(uint32 interfaceId) public view returns (bool) {51 function supportsInterface(uint32 interfaceId) public view returns (bool) {48 require(false, stub_error);52 require(false, stub_error);49 interfaceId;53 interfaceId;53}57}545855contract ERC20 is Dummy, InlineNameSymbol, InlineTotalSupply, ERC20Events {59contract ERC20 is Dummy, InlineNameSymbol, InlineTotalSupply, ERC20Events {60 // Selector: decimals() 313ce56756 function decimals() public view returns (uint8) {61 function decimals() public view returns (uint8) {57 require(false, stub_error);62 require(false, stub_error);58 dummy;63 dummy;59 return 0;64 return 0;60 }65 }616667 // Selector: balanceOf(address) 70a0823162 function balanceOf(address owner) public view returns (uint256) {68 function balanceOf(address owner) public view returns (uint256) {63 require(false, stub_error);69 require(false, stub_error);64 owner;70 owner;65 dummy;71 dummy;66 return 0;72 return 0;67 }73 }687475 // Selector: transfer(address,uint256) a9059cbb69 function transfer(address to, uint256 amount) public returns (bool) {76 function transfer(address to, uint256 amount) public returns (bool) {70 require(false, stub_error);77 require(false, stub_error);71 to;78 to;74 return false;81 return false;75 }82 }768384 // Selector: transferFrom(address,address,uint256) 23b872dd77 function transferFrom(85 function transferFrom(78 address from,86 address from,79 address to,87 address to,87 return false;95 return false;88 }96 }899798 // Selector: approve(address,uint256) 095ea7b390 function approve(address spender, uint256 amount) public returns (bool) {99 function approve(address spender, uint256 amount) public returns (bool) {91 require(false, stub_error);100 require(false, stub_error);92 spender;101 spender;95 return false;104 return false;96 }105 }97106107 // Selector: allowance(address,address) dd62ed3e98 function allowance(address owner, address spender)108 function allowance(address owner, address spender)99 public109 public100 view110 viewpallets/nft/src/eth/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nft/src/eth/stubs/UniqueNFT.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 uint256 field_0;9 string field_1;10}5116// Common stubs holder12// Common stubs holder7contract Dummy {13contract Dummy {354136// Inline42// Inline37contract InlineNameSymbol is Dummy {43contract InlineNameSymbol is Dummy {44 // Selector: name() 06fdde0338 function name() public view returns (string memory) {45 function name() public view returns (string memory) {39 require(false, stub_error);46 require(false, stub_error);40 dummy;47 dummy;41 return "";48 return "";42 }49 }435051 // Selector: symbol() 95d89b4144 function symbol() public view returns (string memory) {52 function symbol() public view returns (string memory) {45 require(false, stub_error);53 require(false, stub_error);46 dummy;54 dummy;505851// Inline59// Inline52contract InlineTotalSupply is Dummy {60contract InlineTotalSupply is Dummy {61 // Selector: totalSupply() 18160ddd53 function totalSupply() public view returns (uint256) {62 function totalSupply() public view returns (uint256) {54 require(false, stub_error);63 require(false, stub_error);55 dummy;64 dummy;58}67}596860contract ERC165 is Dummy {69contract ERC165 is Dummy {70 // Selector: supportsInterface(bytes4) 01ffc9a761 function supportsInterface(uint32 interfaceId) public view returns (bool) {71 function supportsInterface(uint32 interfaceId) public view returns (bool) {62 require(false, stub_error);72 require(false, stub_error);63 interfaceId;73 interfaceId;67}77}687869contract ERC721 is Dummy, ERC165, ERC721Events {79contract ERC721 is Dummy, ERC165, ERC721Events {80 // Selector: balanceOf(address) 70a0823170 function balanceOf(address owner) public view returns (uint256) {81 function balanceOf(address owner) public view returns (uint256) {71 require(false, stub_error);82 require(false, stub_error);72 owner;83 owner;73 dummy;84 dummy;74 return 0;85 return 0;75 }86 }768788 // Selector: ownerOf(uint256) 6352211e77 function ownerOf(uint256 tokenId) public view returns (address) {89 function ownerOf(uint256 tokenId) public view returns (address) {78 require(false, stub_error);90 require(false, stub_error);79 tokenId;91 tokenId;80 dummy;92 dummy;81 return 0x0000000000000000000000000000000000000000;93 return 0x0000000000000000000000000000000000000000;82 }94 }839596 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a1167284 function safeTransferFromWithData(97 function safeTransferFromWithData(85 address from,98 address from,86 address to,99 address to,95 dummy = 0;108 dummy = 0;96 }109 }97110111 // Selector: safeTransferFrom(address,address,uint256) 42842e0e98 function safeTransferFrom(112 function safeTransferFrom(99 address from,113 address from,100 address to,114 address to,107 dummy = 0;121 dummy = 0;108 }122 }109123124 // Selector: transferFrom(address,address,uint256) 23b872dd110 function transferFrom(125 function transferFrom(111 address from,126 address from,112 address to,127 address to,119 dummy = 0;134 dummy = 0;120 }135 }121136137 // Selector: approve(address,uint256) 095ea7b3122 function approve(address approved, uint256 tokenId) public {138 function approve(address approved, uint256 tokenId) public {123 require(false, stub_error);139 require(false, stub_error);124 approved;140 approved;125 tokenId;141 tokenId;126 dummy = 0;142 dummy = 0;127 }143 }128144145 // Selector: setApprovalForAll(address,bool) a22cb465129 function setApprovalForAll(address operator, bool approved) public {146 function setApprovalForAll(address operator, bool approved) public {130 require(false, stub_error);147 require(false, stub_error);131 operator;148 operator;132 approved;149 approved;133 dummy = 0;150 dummy = 0;134 }151 }135152153 // Selector: getApproved(uint256) 081812fc136 function getApproved(uint256 tokenId) public view returns (address) {154 function getApproved(uint256 tokenId) public view returns (address) {137 require(false, stub_error);155 require(false, stub_error);138 tokenId;156 tokenId;139 dummy;157 dummy;140 return 0x0000000000000000000000000000000000000000;158 return 0x0000000000000000000000000000000000000000;141 }159 }142160161 // Selector: isApprovedForAll(address,address) e985e9c5143 function isApprovedForAll(address owner, address operator)162 function isApprovedForAll(address owner, address operator)144 public163 public145 view164 view154}173}155174156contract ERC721Burnable is Dummy {175contract ERC721Burnable is Dummy {176 // Selector: burn(uint256) 42966c68157 function burn(uint256 tokenId) public {177 function burn(uint256 tokenId) public {158 require(false, stub_error);178 require(false, stub_error);159 tokenId;179 tokenId;162}182}163183164contract ERC721Enumerable is Dummy, InlineTotalSupply {184contract ERC721Enumerable is Dummy, InlineTotalSupply {185 // Selector: tokenByIndex(uint256) 4f6ccce7165 function tokenByIndex(uint256 index) public view returns (uint256) {186 function tokenByIndex(uint256 index) public view returns (uint256) {166 require(false, stub_error);187 require(false, stub_error);167 index;188 index;168 dummy;189 dummy;169 return 0;190 return 0;170 }191 }171192193 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59172 function tokenOfOwnerByIndex(address owner, uint256 index)194 function tokenOfOwnerByIndex(address owner, uint256 index)173 public195 public174 view196 view183}205}184206185contract ERC721Metadata is Dummy, InlineNameSymbol {207contract ERC721Metadata is Dummy, InlineNameSymbol {208 // Selector: tokenURI(uint256) c87b56dd186 function tokenURI(uint256 tokenId) public view returns (string memory) {209 function tokenURI(uint256 tokenId) public view returns (string memory) {187 require(false, stub_error);210 require(false, stub_error);188 tokenId;211 tokenId;192}215}193216194contract ERC721Mintable is Dummy, ERC721MintableEvents {217contract ERC721Mintable is Dummy, ERC721MintableEvents {218 // Selector: mintingFinished() 05d2035b195 function mintingFinished() public view returns (bool) {219 function mintingFinished() public view returns (bool) {196 require(false, stub_error);220 require(false, stub_error);197 dummy;221 dummy;198 return false;222 return false;199 }223 }200224225 // Selector: mint(address,uint256) 40c10f19201 function mint(address to, uint256 tokenId) public returns (bool) {226 function mint(address to, uint256 tokenId) public returns (bool) {202 require(false, stub_error);227 require(false, stub_error);203 to;228 to;206 return false;231 return false;207 }232 }208233234 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f209 function mintWithTokenURI(235 function mintWithTokenURI(210 address to,236 address to,211 uint256 tokenId,237 uint256 tokenId,219 return false;245 return false;220 }246 }221247248 // Selector: finishMinting() 7d64bcb4222 function finishMinting() public returns (bool) {249 function finishMinting() public returns (bool) {223 require(false, stub_error);250 require(false, stub_error);224 dummy = 0;251 dummy = 0;227}254}228255229contract ERC721UniqueExtensions is Dummy {256contract ERC721UniqueExtensions is Dummy {257 // Selector: transfer(address,uint256) a9059cbb230 function transfer(address to, uint256 tokenId) public {258 function transfer(address to, uint256 tokenId) public {231 require(false, stub_error);259 require(false, stub_error);232 to;260 to;233 tokenId;261 tokenId;234 dummy = 0;262 dummy = 0;235 }263 }236264265 // Selector: nextTokenId() 75794a3c237 function nextTokenId() public view returns (uint256) {266 function nextTokenId() public view returns (uint256) {238 require(false, stub_error);267 require(false, stub_error);239 dummy;268 dummy;240 return 0;269 return 0;241 }270 }271272 // Selector: setVariableMetadata(uint256,bytes) d4eac26d273 function setVariableMetadata(uint256 tokenId, bytes memory data) public {274 require(false, stub_error);275 tokenId;276 data;277 dummy = 0;278 }279280 // Selector: getVariableMetadata(uint256) e6c5ce6f281 function getVariableMetadata(uint256 tokenId)282 public283 view284 returns (bytes memory)285 {286 require(false, stub_error);287 tokenId;288 dummy;289 return hex"";290 }291292 // Selector: mintBulk(address,uint256[]) 44a9945e293 function mintBulk(address to, uint256[] memory tokenIds)294 public295 returns (bool)296 {297 require(false, stub_error);298 to;299 tokenIds;300 dummy = 0;301 return false;302 }303304 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006305 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)306 public307 returns (bool)308 {309 require(false, stub_error);310 to;311 tokens;312 dummy = 0;313 return false;314 }242}315}243316244contract UniqueNFT is317contract UniqueNFT ispallets/nft/src/lib.rsdiffbeforeafterboth1559 Ok(())1559 Ok(())1560 }1560 }15611562 pub fn get_variable_metadata(1563 collection: &CollectionHandle<T>,1564 item_id: TokenId,1565 ) -> Result<Vec<u8>, DispatchError> {1566 Ok(match collection.mode {1567 CollectionMode::NFT => {1568 <NftItemList<T>>::get(collection.id, item_id)1569 .ok_or(Error::<T>::TokenNotFound)?1570 .variable_data1571 }1572 CollectionMode::ReFungible => {1573 <ReFungibleItemList<T>>::get(collection.id, item_id)1574 .ok_or(Error::<T>::TokenNotFound)?1575 .variable_data1576 }1577 _ => fail!(Error::<T>::UnexpectedCollectionType),1578 })1579 }156115801562 pub fn create_multiple_items_internal(1581 pub fn create_multiple_items_internal(1563 sender: &T::CrossAccountId,1582 sender: &T::CrossAccountId,tests/src/eth/api/ContractHelpers.soldiffbeforeafterboth9}9}101011interface ContractHelpers is Dummy {11interface ContractHelpers is Dummy {12 // Selector: contractOwner(address) 5152b14c12 function contractOwner(address contractAddress)13 function contractOwner(address contractAddress)13 external14 external14 view15 view15 returns (address);16 returns (address);161718 // Selector: sponsoringEnabled(address) 6027dc6117 function sponsoringEnabled(address contractAddress)19 function sponsoringEnabled(address contractAddress)18 external20 external19 view21 view20 returns (bool);22 returns (bool);212324 // Selector: toggleSponsoring(address,bool) fcac6d8622 function toggleSponsoring(address contractAddress, bool enabled) external;25 function toggleSponsoring(address contractAddress, bool enabled) external;232627 // Selector: setSponsoringRateLimit(address,uint32) 77b6c90824 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)28 function setSponsoringRateLimit(address contractAddress, uint32 rateLimit)25 external;29 external;263031 // Selector: allowed(address,address) 5c65816527 function allowed(address contractAddress, address user)32 function allowed(address contractAddress, address user)28 external33 external29 view34 view30 returns (bool);35 returns (bool);313637 // Selector: allowlistEnabled(address) c772ef6c32 function allowlistEnabled(address contractAddress)38 function allowlistEnabled(address contractAddress)33 external39 external34 view40 view35 returns (bool);41 returns (bool);364243 // Selector: toggleAllowlist(address,bool) 36de20f537 function toggleAllowlist(address contractAddress, bool enabled) external;44 function toggleAllowlist(address contractAddress, bool enabled) external;384546 // Selector: toggleAllowed(address,address,bool) 4706cc1c39 function toggleAllowed(47 function toggleAllowed(40 address contractAddress,48 address contractAddress,41 address user,49 address user,tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth202021// Inline21// Inline22interface InlineNameSymbol is Dummy {22interface InlineNameSymbol is Dummy {23 // Selector: name() 06fdde0323 function name() external view returns (string memory);24 function name() external view returns (string memory);242526 // Selector: symbol() 95d89b4125 function symbol() external view returns (string memory);27 function symbol() external view returns (string memory);26}28}272928// Inline30// Inline29interface InlineTotalSupply is Dummy {31interface InlineTotalSupply is Dummy {32 // Selector: totalSupply() 18160ddd30 function totalSupply() external view returns (uint256);33 function totalSupply() external view returns (uint256);31}34}323533interface ERC165 is Dummy {36interface ERC165 is Dummy {37 // Selector: supportsInterface(bytes4) 01ffc9a734 function supportsInterface(uint32 interfaceId) external view returns (bool);38 function supportsInterface(uint32 interfaceId) external view returns (bool);35}39}364037interface ERC20 is Dummy, InlineNameSymbol, InlineTotalSupply, ERC20Events {41interface ERC20 is Dummy, InlineNameSymbol, InlineTotalSupply, ERC20Events {42 // Selector: decimals() 313ce56738 function decimals() external view returns (uint8);43 function decimals() external view returns (uint8);394445 // Selector: balanceOf(address) 70a0823140 function balanceOf(address owner) external view returns (uint256);46 function balanceOf(address owner) external view returns (uint256);414748 // Selector: transfer(address,uint256) a9059cbb42 function transfer(address to, uint256 amount) external returns (bool);49 function transfer(address to, uint256 amount) external returns (bool);435051 // Selector: transferFrom(address,address,uint256) 23b872dd44 function transferFrom(52 function transferFrom(45 address from,53 address from,46 address to,54 address to,47 uint256 amount55 uint256 amount48 ) external returns (bool);56 ) external returns (bool);495758 // Selector: approve(address,uint256) 095ea7b350 function approve(address spender, uint256 amount) external returns (bool);59 function approve(address spender, uint256 amount) external returns (bool);516061 // Selector: allowance(address,address) dd62ed3e52 function allowance(address owner, address spender)62 function allowance(address owner, address spender)53 external63 external54 view64 viewtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 uint256 field_0;9 string field_1;10}5116// Common stubs holder12// Common stubs holder7interface Dummy {13interface Dummy {344035// Inline41// Inline36interface InlineNameSymbol is Dummy {42interface InlineNameSymbol is Dummy {43 // Selector: name() 06fdde0337 function name() external view returns (string memory);44 function name() external view returns (string memory);384546 // Selector: symbol() 95d89b4139 function symbol() external view returns (string memory);47 function symbol() external view returns (string memory);40}48}414942// Inline50// Inline43interface InlineTotalSupply is Dummy {51interface InlineTotalSupply is Dummy {52 // Selector: totalSupply() 18160ddd44 function totalSupply() external view returns (uint256);53 function totalSupply() external view returns (uint256);45}54}465547interface ERC165 is Dummy {56interface ERC165 is Dummy {57 // Selector: supportsInterface(bytes4) 01ffc9a748 function supportsInterface(uint32 interfaceId) external view returns (bool);58 function supportsInterface(uint32 interfaceId) external view returns (bool);49}59}506051interface ERC721 is Dummy, ERC165, ERC721Events {61interface ERC721 is Dummy, ERC165, ERC721Events {62 // Selector: balanceOf(address) 70a0823152 function balanceOf(address owner) external view returns (uint256);63 function balanceOf(address owner) external view returns (uint256);536465 // Selector: ownerOf(uint256) 6352211e54 function ownerOf(uint256 tokenId) external view returns (address);66 function ownerOf(uint256 tokenId) external view returns (address);556768 // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a1167256 function safeTransferFromWithData(69 function safeTransferFromWithData(57 address from,70 address from,58 address to,71 address to,59 uint256 tokenId,72 uint256 tokenId,60 bytes memory data73 bytes memory data61 ) external;74 ) external;627576 // Selector: safeTransferFrom(address,address,uint256) 42842e0e63 function safeTransferFrom(77 function safeTransferFrom(64 address from,78 address from,65 address to,79 address to,66 uint256 tokenId80 uint256 tokenId67 ) external;81 ) external;688283 // Selector: transferFrom(address,address,uint256) 23b872dd69 function transferFrom(84 function transferFrom(70 address from,85 address from,71 address to,86 address to,72 uint256 tokenId87 uint256 tokenId73 ) external;88 ) external;748990 // Selector: approve(address,uint256) 095ea7b375 function approve(address approved, uint256 tokenId) external;91 function approve(address approved, uint256 tokenId) external;769293 // Selector: setApprovalForAll(address,bool) a22cb46577 function setApprovalForAll(address operator, bool approved) external;94 function setApprovalForAll(address operator, bool approved) external;789596 // Selector: getApproved(uint256) 081812fc79 function getApproved(uint256 tokenId) external view returns (address);97 function getApproved(uint256 tokenId) external view returns (address);809899 // Selector: isApprovedForAll(address,address) e985e9c581 function isApprovedForAll(address owner, address operator)100 function isApprovedForAll(address owner, address operator)82 external101 external83 view102 view84 returns (address);103 returns (address);85}104}8610587interface ERC721Burnable is Dummy {106interface ERC721Burnable is Dummy {107 // Selector: burn(uint256) 42966c6888 function burn(uint256 tokenId) external;108 function burn(uint256 tokenId) external;89}109}9011091interface ERC721Enumerable is Dummy, InlineTotalSupply {111interface ERC721Enumerable is Dummy, InlineTotalSupply {112 // Selector: tokenByIndex(uint256) 4f6ccce792 function tokenByIndex(uint256 index) external view returns (uint256);113 function tokenByIndex(uint256 index) external view returns (uint256);93114115 // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c5994 function tokenOfOwnerByIndex(address owner, uint256 index)116 function tokenOfOwnerByIndex(address owner, uint256 index)95 external117 external96 view118 view97 returns (uint256);119 returns (uint256);98}120}99121100interface ERC721Metadata is Dummy, InlineNameSymbol {122interface ERC721Metadata is Dummy, InlineNameSymbol {123 // Selector: tokenURI(uint256) c87b56dd101 function tokenURI(uint256 tokenId) external view returns (string memory);124 function tokenURI(uint256 tokenId) external view returns (string memory);102}125}103126104interface ERC721Mintable is Dummy, ERC721MintableEvents {127interface ERC721Mintable is Dummy, ERC721MintableEvents {128 // Selector: mintingFinished() 05d2035b105 function mintingFinished() external view returns (bool);129 function mintingFinished() external view returns (bool);106130131 // Selector: mint(address,uint256) 40c10f19107 function mint(address to, uint256 tokenId) external returns (bool);132 function mint(address to, uint256 tokenId) external returns (bool);108133134 // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f109 function mintWithTokenURI(135 function mintWithTokenURI(110 address to,136 address to,111 uint256 tokenId,137 uint256 tokenId,112 string memory tokenUri138 string memory tokenUri113 ) external returns (bool);139 ) external returns (bool);114140141 // Selector: finishMinting() 7d64bcb4115 function finishMinting() external returns (bool);142 function finishMinting() external returns (bool);116}143}117144118interface ERC721UniqueExtensions is Dummy {145interface ERC721UniqueExtensions is Dummy {146 // Selector: transfer(address,uint256) a9059cbb119 function transfer(address to, uint256 tokenId) external;147 function transfer(address to, uint256 tokenId) external;120148149 // Selector: nextTokenId() 75794a3c121 function nextTokenId() external view returns (uint256);150 function nextTokenId() external view returns (uint256);151152 // Selector: setVariableMetadata(uint256,bytes) d4eac26d153 function setVariableMetadata(uint256 tokenId, bytes memory data) external;154155 // Selector: getVariableMetadata(uint256) e6c5ce6f156 function getVariableMetadata(uint256 tokenId)157 external158 view159 returns (bytes memory);160161 // Selector: mintBulk(address,uint256[]) 44a9945e162 function mintBulk(address to, uint256[] memory tokenIds)163 external164 returns (bool);165166 // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006167 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)168 external169 returns (bool);122}170}123171124interface UniqueNFT is172interface UniqueNFT istests/src/eth/nonFungible.test.tsdiffbeforeafterboth4//4//556import privateKey from '../substrate/privateKey';6import privateKey from '../substrate/privateKey';7import { approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE } from '../util/helpers';7import { approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, setVariableMetaDataExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE } from '../util/helpers';8import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';8import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';9import nonFungibleAbi from './nonFungibleAbi.json';9import nonFungibleAbi from './nonFungibleAbi.json';10import { expect } from 'chai';10import { expect } from 'chai';105 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');105 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');106 }106 }107 });107 });108 itWeb3('Can perform mintBulk()', async ({ web3, api }) => {109 const collection = await createCollectionExpectSuccess({110 mode: { type: 'NFT' },111 });112 const alice = privateKey('//Alice');113114 const caller = await createEthAccountWithBalance(api, web3);115 const changeAdminTx = api.tx.nft.addCollectionAdmin(collection, { ethereum: caller });116 await submitTransactionAsync(alice, changeAdminTx);117 const receiver = createEthAccount(web3);118119 const address = collectionIdToAddress(collection);120 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});121122 {123 const nextTokenId = await contract.methods.nextTokenId().call();124 expect(nextTokenId).to.be.equal('1');125 const result = await contract.methods.mintBulkWithTokenURI(126 receiver,127 [128 [nextTokenId, 'Test URI 0'],129 [+nextTokenId + 1, 'Test URI 1'],130 [+nextTokenId + 2, 'Test URI 2'],131 ],132 ).send({ from: caller });133 const events = normalizeEvents(result.events);134135 expect(events).to.be.deep.equal([136 {137 address,138 event: 'Transfer',139 args: {140 from: '0x0000000000000000000000000000000000000000',141 to: receiver,142 tokenId: nextTokenId,143 },144 },145 {146 address,147 event: 'Transfer',148 args: {149 from: '0x0000000000000000000000000000000000000000',150 to: receiver,151 tokenId: String(+nextTokenId + 1),152 },153 },154 {155 address,156 event: 'Transfer',157 args: {158 from: '0x0000000000000000000000000000000000000000',159 to: receiver,160 tokenId: String(+nextTokenId + 2),161 },162 },163 ]);164165 await waitNewBlocks(api, 1);166 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');167 expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');168 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');169 }170 });108171109 itWeb3('Can perform burn()', async ({ web3, api }) => {172 itWeb3('Can perform burn()', async ({ web3, api }) => {110 const collection = await createCollectionExpectSuccess({173 const collection = await createCollectionExpectSuccess({264 }327 }265 });328 });329330 itWeb3('Can perform getVariableMetadata', async ({ web3, api }) => {331 const collection = await createCollectionExpectSuccess({332 mode: { type: 'NFT' },333 });334 const alice = privateKey('//Alice');335336 const owner = await createEthAccountWithBalance(api, web3);337338 const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });339 await setVariableMetaDataExpectSuccess(alice, collection, item, [1, 2, 3]);340341 const address = collectionIdToAddress(collection);342 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });343 344 expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');345 });346347 itWeb3('Can perform setVariableMetadata', async ({ web3, api }) => {348 const collection = await createCollectionExpectSuccess({349 mode: { type: 'NFT' },350 });351 const alice = privateKey('//Alice');352353 const owner = await createEthAccountWithBalance(api, web3);354355 const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });356357 const address = collectionIdToAddress(collection);358 const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });359 360 expect(await contract.methods.setVariableMetadata(item, '0x010203').send({ from: owner }));361 await waitNewBlocks(api, 1);362 expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');363 });266});364});267365268describe('NFT: Fees', () => {366describe('NFT: Fees', () => {tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth50 "type": "event"50 "type": "event"51 },51 },52 {52 {53 "anonymous": true,53 "anonymous": false,54 "inputs": [],54 "inputs": [],55 "name": "MintingFinished",55 "name": "MintingFinished",56 "type": "event"56 "type": "event"162 "stateMutability": "view",162 "stateMutability": "view",163 "type": "function"163 "type": "function"164 },164 },165 {166 "inputs": [167 {168 "internalType": "uint256",169 "name": "tokenId",170 "type": "uint256"171 }172 ],173 "name": "getVariableMetadata",174 "outputs": [175 {176 "internalType": "bytes",177 "name": "",178 "type": "bytes"179 }180 ],181 "stateMutability": "view",182 "type": "function"183 },165 {184 {166 "inputs": [185 "inputs": [167 {186 {210 "stateMutability": "nonpayable",229 "stateMutability": "nonpayable",211 "type": "function"230 "type": "function"212 },231 },232 {233 "inputs": [234 {235 "internalType": "address",236 "name": "to",237 "type": "address"238 },239 {240 "internalType": "uint256[]",241 "name": "tokenIds",242 "type": "uint256[]"243 }244 ],245 "name": "mintBulk",246 "outputs": [247 {248 "internalType": "bool",249 "name": "",250 "type": "bool"251 }252 ],253 "stateMutability": "nonpayable",254 "type": "function"255 },256 {257 "inputs": [258 {259 "internalType": "address",260 "name": "to",261 "type": "address"262 },263 {264 "components": [265 {266 "internalType": "uint256",267 "name": "field_0",268 "type": "uint256"269 },270 {271 "internalType": "string",272 "name": "field_1",273 "type": "string"274 }275 ],276 "internalType": "struct Tuple0[]",277 "name": "tokens",278 "type": "tuple[]"279 }280 ],281 "name": "mintBulkWithTokenURI",282 "outputs": [283 {284 "internalType": "bool",285 "name": "",286 "type": "bool"287 }288 ],289 "stateMutability": "nonpayable",290 "type": "function"291 },213 {292 {214 "inputs": [293 "inputs": [215 {294 {224 },303 },225 {304 {226 "internalType": "string",305 "internalType": "string",227 "name": "tokenURI",306 "name": "tokenUri",228 "type": "string"307 "type": "string"229 }308 }230 ],309 ],366 "stateMutability": "nonpayable",445 "stateMutability": "nonpayable",367 "type": "function"446 "type": "function"368 },447 },448 {449 "inputs": [450 {451 "internalType": "uint256",452 "name": "tokenId",453 "type": "uint256"454 },455 {456 "internalType": "bytes",457 "name": "data",458 "type": "bytes"459 }460 ],461 "name": "setVariableMetadata",462 "outputs": [],463 "stateMutability": "nonpayable",464 "type": "function"465 },369 {466 {370 "inputs": [467 "inputs": [371 {468 {tests/src/eth/proxy/UniqueNFTProxy.abidiffbeforeafterboth1[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"interfaceId","type":"uint32"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]1[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getVariableMetadata","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"mintBulk","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"uint256","name":"field_0","type":"uint256"},{"internalType":"string","name":"field_1","type":"string"}],"internalType":"struct Tuple0[]","name":"tokens","type":"tuple[]"}],"name":"mintBulkWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenUri","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setVariableMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"interfaceId","type":"uint32"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]tests/src/eth/proxy/UniqueNFTProxy.bindiffbeforeafterboth1608060405234801561001057600080fd5b506040516111e03803806111e083398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61114d806100936000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806350bb4e7f116100c357806395d89b411161007c57806395d89b41146102a8578063a22cb465146102b0578063a9059cbb146102c3578063c87b56dd146102d6578063e985e9c5146102e9578063f4f4b500146102fc57600080fd5b806350bb4e7f1461024c57806360a116721461025f5780636352211e1461027257806370a082311461028557806375794a3c146102985780637d64bcb4146102a057600080fd5b806323b872dd1161011557806323b872dd146101da5780632f745c59146101ed57806340c10f191461020057806342842e0e1461021357806342966c68146102265780634f6ccce71461023957600080fd5b806305d2035b1461015257806306fdde031461016f578063081812fc14610184578063095ea7b3146101af57806318160ddd146101c4575b600080fd5b61015a61030f565b60405190151581526020015b60405180910390f35b61017761039b565b6040516101669190611043565b610197610192366004610f5b565b61041b565b6040516001600160a01b039091168152602001610166565b6101c26101bd366004610e2e565b61049f565b005b6101cc61050a565b604051908152602001610166565b6101c26101e8366004610d3f565b610591565b6101cc6101fb366004610e2e565b610605565b61015a61020e366004610e2e565b610691565b6101c2610221366004610d3f565b610718565b6101c2610234366004610f5b565b610759565b6101cc610247366004610f5b565b6107ba565b61015a61025a366004610e5a565b610838565b6101c261026d366004610d80565b6108c7565b610197610280366004610f5b565b610936565b6101cc610293366004610ccc565b610968565b6101cc61099b565b61015a6109ea565b610177610a4f565b6101c26102be366004610e00565b610a93565b6101c26102d1366004610e2e565b610acd565b6101776102e4366004610f5b565b610b06565b6101976102f7366004610d06565b610b87565b61015a61030a366004610f8d565b610c0d565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561035e57600080fd5b505afa158015610372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103969190610ec7565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde039260048082019391829003018186803b1580156103df57600080fd5b505afa1580156103f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103969190810190610ee4565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b60206040518083038186803b15801561046157600080fd5b505afa158015610475573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610ce9565b92915050565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b1580156104ee57600080fd5b505af1158015610502573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561055957600080fd5b505afa15801561056d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103969190610f74565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b1580156105e857600080fd5b505af11580156105fc573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c599060440160206040518083038186803b15801561065257600080fd5b505afa158015610666573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610f74565b9392505050565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f1990604401602060405180830381600087803b1580156106e057600080fd5b505af11580156106f4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610ec7565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e906064016105ce565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b15801561079f57600080fd5b505af11580156107b3573d6000803e3d6000fd5b5050505050565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b60206040518083038186803b15801561080057600080fd5b505afa158015610814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610f74565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f9061086d9087908790879060040161101c565b602060405180830381600087803b15801561088757600080fd5b505af115801561089b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bf9190610ec7565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a11672906108fd908790879087908790600401610fdf565b600060405180830381600087803b15801561091757600080fd5b505af115801561092b573d6000803e3d6000fd5b505050505b50505050565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e90602401610449565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a08231906024016107e8565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561055957600080fd5b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610a3b57600080fd5b505af1158015610372573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b419260048082019391829003018186803b1580156103df57600080fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb465906044016104d4565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016104d4565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd9060240160006040518083038186803b158015610b4b57600080fd5b505afa158015610b5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104999190810190610ee4565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c59060440160206040518083038186803b158015610bd557600080fd5b505afa158015610be9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610ce9565b6000805460405162f4f4b560e81b815263ffffffff841660048201526001600160a01b039091169063f4f4b5009060240160206040518083038186803b158015610c5657600080fd5b505afa158015610c6a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610ec7565b6000610ca1610c9c84611087565b611056565b9050828152838383011115610cb557600080fd5b828260208301376000602084830101529392505050565b600060208284031215610cde57600080fd5b813561068a816110f1565b600060208284031215610cfb57600080fd5b815161068a816110f1565b60008060408385031215610d1957600080fd5b8235610d24816110f1565b91506020830135610d34816110f1565b809150509250929050565b600080600060608486031215610d5457600080fd5b8335610d5f816110f1565b92506020840135610d6f816110f1565b929592945050506040919091013590565b60008060008060808587031215610d9657600080fd5b8435610da1816110f1565b93506020850135610db1816110f1565b925060408501359150606085013567ffffffffffffffff811115610dd457600080fd5b8501601f81018713610de557600080fd5b610df487823560208401610c8e565b91505092959194509250565b60008060408385031215610e1357600080fd5b8235610e1e816110f1565b91506020830135610d3481611109565b60008060408385031215610e4157600080fd5b8235610e4c816110f1565b946020939093013593505050565b600080600060608486031215610e6f57600080fd5b8335610e7a816110f1565b925060208401359150604084013567ffffffffffffffff811115610e9d57600080fd5b8401601f81018613610eae57600080fd5b610ebd86823560208401610c8e565b9150509250925092565b600060208284031215610ed957600080fd5b815161068a81611109565b600060208284031215610ef657600080fd5b815167ffffffffffffffff811115610f0d57600080fd5b8201601f81018413610f1e57600080fd5b8051610f2c610c9c82611087565b818152856020838501011115610f4157600080fd5b610f528260208301602086016110af565b95945050505050565b600060208284031215610f6d57600080fd5b5035919050565b600060208284031215610f8657600080fd5b5051919050565b600060208284031215610f9f57600080fd5b813563ffffffff8116811461068a57600080fd5b60008151808452610fcb8160208601602086016110af565b601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061101290830184610fb3565b9695505050505050565b60018060a01b0384168152826020820152606060408201526000610f526060830184610fb3565b60208152600061068a6020830184610fb3565b604051601f8201601f1916810167ffffffffffffffff8111828210171561107f5761107f6110db565b604052919050565b600067ffffffffffffffff8211156110a1576110a16110db565b50601f01601f191660200190565b60005b838110156110ca5781810151838201526020016110b2565b838111156109305750506000910152565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461110657600080fd5b50565b801515811461110657600080fdfea2646970667358221220cd50bb20b48b73eddb390585af8699a01cd5f49b79ab50aa532df41df639f36764736f6c634300080700331608060405234801561001057600080fd5b5060405161168d38038061168d83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b6115fa806100936000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806350bb4e7f116100f9578063a22cb46511610097578063d4eac26d11610071578063d4eac26d1461036b578063e6c5ce6f1461037e578063e985e9c514610391578063f4f4b500146103a457600080fd5b8063a22cb46514610332578063a9059cbb14610345578063c87b56dd1461035857600080fd5b806370a08231116100d357806370a082311461030757806375794a3c1461031a5780637d64bcb41461032257806395d89b411461032a57600080fd5b806350bb4e7f146102ce57806360a11672146102e15780636352211e146102f457600080fd5b80632f745c591161016657806342842e0e1161014057806342842e0e1461028257806342966c681461029557806344a9945e146102a85780634f6ccce7146102bb57600080fd5b80632f745c5914610249578063365430061461025c57806340c10f191461026f57600080fd5b806305d2035b146101ae57806306fdde03146101cb578063081812fc146101e0578063095ea7b31461020b57806318160ddd1461022057806323b872dd14610236575b600080fd5b6101b66103b7565b60405190151581526020015b60405180910390f35b6101d3610443565b6040516101c2919061148a565b6101f36101ee366004611277565b6104c3565b6040516001600160a01b0390911681526020016101c2565b61021e61021936600461118c565b610547565b005b6102286105b2565b6040519081526020016101c2565b61021e610244366004610eff565b610639565b61022861025736600461118c565b6106ad565b6101b661026a366004610fac565b610739565b6101b661027d36600461118c565b6107be565b61021e610290366004610eff565b6107f8565b61021e6102a3366004611277565b610839565b6101b66102b63660046110b1565b61089a565b6102286102c9366004611277565b6108cd565b6101b66102dc3660046111b8565b61094b565b61021e6102ef366004610f40565b6109da565b6101f3610302366004611277565b610a49565b610228610315366004610e8c565b610a7b565b610228610aae565b6101b6610afd565b6101d3610b62565b61021e61034036600461115e565b610ba6565b61021e61035336600461118c565b610be0565b6101d3610366366004611277565b610c19565b61021e6103793660046112a9565b610c9b565b6101d361038c366004611277565b610ccd565b6101f361039f366004610ec6565b610cff565b6101b66103b23660046112f0565b610d85565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561040657600080fd5b505afa15801561041a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e9190611211565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde039260048082019391829003018186803b15801561048757600080fd5b505afa15801561049b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261043e919081019061122e565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b60206040518083038186803b15801561050957600080fd5b505afa15801561051d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190610ea9565b92915050565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b15801561059657600080fd5b505af11580156105aa573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561060157600080fd5b505afa158015610615573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e9190611290565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b15801561069057600080fd5b505af11580156106a4573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c599060440160206040518083038186803b1580156106fa57600080fd5b505afa15801561070e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190611290565b9392505050565b60008054604051631b2a180360e11b81526001600160a01b039091169063365430069061076c908690869060040161137f565b602060405180830381600087803b15801561078657600080fd5b505af115801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190611211565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f199060440161076c565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e90606401610676565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b15801561087f57600080fd5b505af1158015610893573d6000803e3d6000fd5b5050505050565b60008054604051632254ca2f60e11b81526001600160a01b03909116906344a9945e9061076c9086908690600401611404565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b60206040518083038186803b15801561091357600080fd5b505afa158015610927573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190611290565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f906109809087908790879060040161145a565b602060405180830381600087803b15801561099a57600080fd5b505af11580156109ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d29190611211565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a1167290610a10908790879087908790600401611342565b600060405180830381600087803b158015610a2a57600080fd5b505af1158015610a3e573d6000803e3d6000fd5b505050505b50505050565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e906024016104f1565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a08231906024016108fb565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561060157600080fd5b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610b4e57600080fd5b505af115801561041a573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b419260048082019391829003018186803b15801561048757600080fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb4659060440161057c565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb9060440161057c565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd906024015b60006040518083038186803b158015610c5f57600080fd5b505afa158015610c73573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610541919081019061122e565b60005460405163d4eac26d60e01b81526001600160a01b039091169063d4eac26d9061057c908590859060040161149d565b60005460405163e6c5ce6f60e01b8152600481018390526060916001600160a01b03169063e6c5ce6f90602401610c47565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c59060440160206040518083038186803b158015610d4d57600080fd5b505afa158015610d61573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190610ea9565b6000805460405162f4f4b560e81b815263ffffffff841660048201526001600160a01b039091169063f4f4b5009060240160206040518083038186803b158015610dce57600080fd5b505afa158015610de2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190611211565b6000610e19610e1484611534565b6114df565b9050828152838383011115610e2d57600080fd5b61073283602083018461155c565b600082601f830112610e4c57600080fd5b8135610e5a610e1482611534565b818152846020838601011115610e6f57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215610e9e57600080fd5b81356107328161159e565b600060208284031215610ebb57600080fd5b81516107328161159e565b60008060408385031215610ed957600080fd5b8235610ee48161159e565b91506020830135610ef48161159e565b809150509250929050565b600080600060608486031215610f1457600080fd5b8335610f1f8161159e565b92506020840135610f2f8161159e565b929592945050506040919091013590565b60008060008060808587031215610f5657600080fd5b8435610f618161159e565b93506020850135610f718161159e565b925060408501359150606085013567ffffffffffffffff811115610f9457600080fd5b610fa087828801610e3b565b91505092959194509250565b60008060408385031215610fbf57600080fd5b8235610fca8161159e565b915060208381013567ffffffffffffffff80821115610fe857600080fd5b818601915086601f830112610ffc57600080fd5b813561100a610e1482611510565b8082825285820191508585018a878560051b880101111561102a57600080fd5b60005b848110156110a05781358681111561104457600080fd5b87016040818e03601f1901121561105a57600080fd5b6110626114b6565b89820135815260408201358881111561107a57600080fd5b6110888f8c83860101610e3b565b828c015250855250928701929087019060010161102d565b50979a909950975050505050505050565b600080604083850312156110c457600080fd5b82356110cf8161159e565b915060208381013567ffffffffffffffff8111156110ec57600080fd5b8401601f810186136110fd57600080fd5b803561110b610e1482611510565b80828252848201915084840189868560051b870101111561112b57600080fd5b600094505b8385101561114e578035835260019490940193918501918501611130565b5080955050505050509250929050565b6000806040838503121561117157600080fd5b823561117c8161159e565b91506020830135610ef4816115b6565b6000806040838503121561119f57600080fd5b82356111aa8161159e565b946020939093013593505050565b6000806000606084860312156111cd57600080fd5b83356111d88161159e565b925060208401359150604084013567ffffffffffffffff8111156111fb57600080fd5b61120786828701610e3b565b9150509250925092565b60006020828403121561122357600080fd5b8151610732816115b6565b60006020828403121561124057600080fd5b815167ffffffffffffffff81111561125757600080fd5b8201601f8101841361126857600080fd5b6109d284825160208401610e06565b60006020828403121561128957600080fd5b5035919050565b6000602082840312156112a257600080fd5b5051919050565b600080604083850312156112bc57600080fd5b82359150602083013567ffffffffffffffff8111156112da57600080fd5b6112e685828601610e3b565b9150509250929050565b60006020828403121561130257600080fd5b813563ffffffff8116811461073257600080fd5b6000815180845261132e81602086016020860161155c565b601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061137590830184611316565b9695505050505050565b6001600160a01b0383168152604060208083018290528351828401819052600092916060600583901b860181019290860190878301865b828110156113f557888603605f190184528151805187528501518587018890526113e288880182611316565b96505092840192908401906001016113b6565b50939998505050505050505050565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b8181101561144d57845183529383019391830191600101611431565b5090979650505050505050565b60018060a01b03841681528260208201526060604082015260006114816060830184611316565b95945050505050565b6020815260006107326020830184611316565b8281526040602082015260006109d26040830184611316565b6040805190810167ffffffffffffffff811182821017156114d9576114d9611588565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561150857611508611588565b604052919050565b600067ffffffffffffffff82111561152a5761152a611588565b5060051b60200190565b600067ffffffffffffffff82111561154e5761154e611588565b50601f01601f191660200190565b60005b8381101561157757818101518382015260200161155f565b83811115610a435750506000910152565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146115b357600080fd5b50565b80151581146115b357600080fdfea2646970667358221220669a75a3efcdc6b60606caa5c7e41cab1d727e89a03fd231d1cda27f4de159a064736f6c63430008070033tests/src/eth/proxy/UniqueNFTProxy.soldiffbeforeafterboth157 return proxied.supportsInterface(interfaceId);157 return proxied.supportsInterface(interfaceId);158 }158 }159160 function setVariableMetadata(uint256 tokenId, bytes memory data)161 external162 override163 {164 return proxied.setVariableMetadata(tokenId, data);165 }166167 function getVariableMetadata(uint256 tokenId)168 external169 view170 override171 returns (bytes memory)172 {173 return proxied.getVariableMetadata(tokenId);174 }175176 function mintBulk(address to, uint256[] memory tokenIds)177 external178 override179 returns (bool)180 {181 return proxied.mintBulk(to, tokenIds);182 }183184 function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)185 external186 override187 returns (bool)188 {189 return proxied.mintBulkWithTokenURI(to, tokens);190 }159}191}160192tests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth4//4//556import privateKey from '../../substrate/privateKey';6import privateKey from '../../substrate/privateKey';7import { createCollectionExpectSuccess, createItemExpectSuccess } from '../../util/helpers';7import { createCollectionExpectSuccess, createItemExpectSuccess, setVariableMetaDataExpectSuccess } from '../../util/helpers';8import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents } from '../util/helpers';8import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents } from '../util/helpers';9import nonFungibleAbi from '../nonFungibleAbi.json';9import nonFungibleAbi from '../nonFungibleAbi.json';10import { expect } from 'chai';10import { expect } from 'chai';96 {96 {97 const nextTokenId = await contract.methods.nextTokenId().call();97 const nextTokenId = await contract.methods.nextTokenId().call();98 expect(nextTokenId).to.be.equal('1');98 expect(nextTokenId).to.be.equal('1');99 console.log('Before mint');100 const result = await contract.methods.mintWithTokenURI(99 const result = await contract.methods.mintWithTokenURI(101 receiver,100 receiver,102 nextTokenId,101 nextTokenId,103 'Test URI',102 'Test URI',104 ).send({ from: caller });103 ).send({ from: caller });105 console.log('After mint');106 const events = normalizeEvents(result.events);104 const events = normalizeEvents(result.events);107105108 expect(events).to.be.deep.equal([106 expect(events).to.be.deep.equal([121 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');119 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');122 }120 }123 });121 });122 itWeb3('Can perform mintBulk()', async ({ web3, api }) => {123 const collection = await createCollectionExpectSuccess({124 mode: { type: 'NFT' },125 });126 const alice = privateKey('//Alice');127128 const caller = await createEthAccountWithBalance(api, web3);129 const receiver = createEthAccount(web3);130131 const address = collectionIdToAddress(collection);132 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, { from: caller, ...GAS_ARGS }));133 const changeAdminTx = api.tx.nft.addCollectionAdmin(collection, { ethereum: contract.options.address });134 await submitTransactionAsync(alice, changeAdminTx);135136 {137 const nextTokenId = await contract.methods.nextTokenId().call();138 expect(nextTokenId).to.be.equal('1');139 const result = await contract.methods.mintBulkWithTokenURI(140 receiver,141 [142 [nextTokenId, 'Test URI 0'],143 [+nextTokenId + 1, 'Test URI 1'],144 [+nextTokenId + 2, 'Test URI 2'],145 ],146 ).send({ from: caller });147 const events = normalizeEvents(result.events);148149 expect(events).to.be.deep.equal([150 {151 address,152 event: 'Transfer',153 args: {154 from: '0x0000000000000000000000000000000000000000',155 to: receiver,156 tokenId: nextTokenId,157 },158 },159 {160 address,161 event: 'Transfer',162 args: {163 from: '0x0000000000000000000000000000000000000000',164 to: receiver,165 tokenId: String(+nextTokenId + 1),166 },167 },168 {169 address,170 event: 'Transfer',171 args: {172 from: '0x0000000000000000000000000000000000000000',173 to: receiver,174 tokenId: String(+nextTokenId + 2),175 },176 },177 ]);178179 await waitNewBlocks(api, 1);180 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');181 expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');182 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');183 }184 });124185125 itWeb3('Can perform burn()', async ({ web3, api }) => {186 itWeb3('Can perform burn()', async ({ web3, api }) => {126 const collection = await createCollectionExpectSuccess({187 const collection = await createCollectionExpectSuccess({268 }329 }269 });330 });331332 itWeb3('Can perform getVariableMetadata', async ({ web3, api }) => {333 const collection = await createCollectionExpectSuccess({334 mode: { type: 'NFT' },335 });336 const alice = privateKey('//Alice');337 const caller = await createEthAccountWithBalance(api, web3);338339 const address = collectionIdToAddress(collection);340 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, { from: caller, ...GAS_ARGS }));341 const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: contract.options.address });342 await setVariableMetaDataExpectSuccess(alice, collection, item, [1, 2, 3]);343 344 expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');345 });346347 itWeb3('Can perform setVariableMetadata', async ({ web3, api }) => {348 const collection = await createCollectionExpectSuccess({349 mode: { type: 'NFT' },350 });351 const alice = privateKey('//Alice');352 const caller = await createEthAccountWithBalance(api, web3);353354 const address = collectionIdToAddress(collection);355 const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, { from: caller, ...GAS_ARGS }));356 const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: contract.options.address });357 358 expect(await contract.methods.setVariableMetadata(item, '0x010203').send({ from: caller }));359 await waitNewBlocks(api, 1);360 expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');361 });270});362});271363tests/src/eth/util/helpers.tsdiffbeforeafterbothno syntactic changes