From fa10a01fefef560651fad17d70bc2fa37fe672b6 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 13 Jan 2023 08:22:04 +0000 Subject: [PATCH] Merge branch 'develop' into tests/generalization --- --- a/Cargo.lock +++ b/Cargo.lock @@ -2321,7 +2321,7 @@ [[package]] name = "evm-coder" -version = "0.1.5" +version = "0.1.6" dependencies = [ "ethereum 0.14.0", "evm-coder-procedural", --- a/crates/evm-coder/CHANGELOG.md +++ b/crates/evm-coder/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. +## [v0.1.6] - 2023-01-12 + +### Added +- Support Option type. +### Removed +- Frontier dependency. + ## [v0.1.5] - 2022-11-30 ### Added --- a/crates/evm-coder/Cargo.toml +++ b/crates/evm-coder/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evm-coder" -version = "0.1.5" +version = "0.1.6" license = "GPLv3" edition = "2021" --- a/crates/evm-coder/src/abi/impls.rs +++ b/crates/evm-coder/src/abi/impls.rs @@ -258,3 +258,39 @@ impl_tuples! {A B C D E F G H} impl_tuples! {A B C D E F G H I} impl_tuples! {A B C D E F G H I J} + +//----- impls for Option ----- +impl AbiType for Option { + const SIGNATURE: SignatureUnit = <(bool, T)>::SIGNATURE; + + fn is_dynamic() -> bool { + <(bool, T)>::is_dynamic() + } + + fn size() -> usize { + <(bool, T)>::size() + } +} + +impl AbiWrite for Option { + fn abi_write(&self, writer: &mut AbiWriter) { + match self { + Some(value) => (true, value).abi_write(writer), + None => (false, T::default()).abi_write(writer), + } + } +} + +impl AbiRead for Option +where + Self: AbiType, + T: AbiRead + AbiType, +{ + fn abi_read(reader: &mut AbiReader) -> Result + where + Self: Sized, + { + let (status, value) = <(bool, T)>::abi_read(reader)?; + Ok(if status { Some(value) } else { None }) + } +} --- a/crates/evm-coder/src/abi/test.rs +++ b/crates/evm-coder/src/abi/test.rs @@ -538,3 +538,68 @@ assert_eq!(p1, 0x0a); assert_eq!(p2, 0x0b); } + +#[test] +fn encode_decode_option_uint8_some() { + test_impl::>( + 0xdeadbeef, + Some(44), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000001 + 000000000000000000000000000000000000000000000000000000000000002c + " + ), + ); +} + +#[test] +fn encode_decode_option_uint8_none() { + test_impl::>( + 0xdeadbeef, + None, + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_option_string_some() { + test_impl::>( + 0xdeadbeef, + Some("some string".to_string()), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000040 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_option_string_none() { + test_impl::>( + 0xdeadbeef, + None, + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000000 + " + ), + ); +} --- a/crates/evm-coder/src/solidity/impls.rs +++ b/crates/evm-coder/src/solidity/impls.rs @@ -121,3 +121,59 @@ impl_tuples! {A B C D E F G H} impl_tuples! {A B C D E F G H I} impl_tuples! {A B C D E F G H I J} + +//----- impls for Option ----- +impl SolidityTypeName for Option { + fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + write!(writer, "{}", tc.collect_struct::()) + } + fn is_simple() -> bool { + false + } + fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + write!(writer, "{}(", tc.collect_struct::())?; + bool::solidity_default(writer, tc)?; + write!(writer, ", "); + T::solidity_default(writer, tc)?; + write!(writer, ")") + } +} + +impl super::SolidityStructTy for Option { + fn generate_solidity_interface(tc: &TypeCollector) -> String { + let mut solidity_name = "Option".to_string(); + let mut generic_name = String::new(); + T::solidity_name(&mut generic_name, tc); + solidity_name.push( + generic_name + .chars() + .next() + .expect("Generic name is empty") + .to_ascii_uppercase(), + ); + solidity_name.push_str(&generic_name[1..]); + + let interface = super::SolidityStruct { + docs: &[" Optional value"], + name: solidity_name.as_str(), + fields: ( + super::SolidityStructField:: { + docs: &[" Shows the status of accessibility of value"], + name: "status", + ty: ::core::marker::PhantomData, + }, + super::SolidityStructField:: { + docs: &[" Actual value if `status` is true"], + name: "value", + ty: ::core::marker::PhantomData, + }, + ), + }; + + let mut out = String::new(); + let _ = interface.format(&mut out, tc); + tc.collect(out); + + solidity_name.to_string() + } +} --- a/crates/evm-coder/src/solidity/mod.rs +++ b/crates/evm-coder/src/solidity/mod.rs @@ -456,13 +456,13 @@ Ok(()) } } -pub struct SolidityStruct { - pub docs: &'static [&'static str], +pub struct SolidityStruct<'a, F> { + pub docs: &'a [&'a str], // pub generics: - pub name: &'static str, + pub name: &'a str, pub fields: F, } -impl SolidityStruct +impl SolidityStruct<'_, F> where F: SolidityItems, { --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -284,6 +284,11 @@ fn collection_limits(&self) -> Result> { let limits = &self.collection.limits; + let convert_value_from_bool = |ob: Option| match ob { + Some(b) => Some(b as u32), + None => None, + }; + Ok(vec![ eth::CollectionLimit::new( eth::CollectionLimitField::AccountTokenOwnership, @@ -297,15 +302,15 @@ .sponsored_data_rate_limit .and_then(|limit| { if let SponsoringRateLimit::Blocks(blocks) = limit { - Some(eth::CollectionLimit::new::( + Some(eth::CollectionLimit::new( eth::CollectionLimitField::SponsoredDataRateLimit, - blocks, + Some(blocks), )) } else { None } }) - .unwrap_or(eth::CollectionLimit::new::( + .unwrap_or(eth::CollectionLimit::new( eth::CollectionLimitField::SponsoredDataRateLimit, Default::default(), )), @@ -320,15 +325,15 @@ ), eth::CollectionLimit::new( eth::CollectionLimitField::OwnerCanTransfer, - limits.owner_can_transfer, + convert_value_from_bool(limits.owner_can_transfer), ), eth::CollectionLimit::new( eth::CollectionLimitField::OwnerCanDestroy, - limits.owner_can_destroy, + convert_value_from_bool(limits.owner_can_destroy), ), eth::CollectionLimit::new( eth::CollectionLimitField::TransferEnabled, - limits.transfers_enabled, + convert_value_from_bool(limits.transfers_enabled), ), ]) } --- a/pallets/common/src/eth.rs +++ b/pallets/common/src/eth.rs @@ -66,71 +66,6 @@ T::CrossAccountId::from_sub(account_id) } -/// Ethereum representation of Optional value with uint256. -#[derive(Debug, Default, AbiCoder)] -pub struct OptionUint { - status: bool, - value: uint256, -} - -impl From for OptionUint { - fn from(value: u32) -> Self { - Self { - status: true, - value: uint256::from(value), - } - } -} - -impl From> for OptionUint { - fn from(value: Option) -> Self { - match value { - Some(value) => Self { - status: true, - value: value.into(), - }, - None => Self { - status: false, - value: Default::default(), - }, - } - } -} - -impl From for OptionUint { - fn from(value: bool) -> Self { - Self { - status: true, - value: if value { - uint256::from(1) - } else { - Default::default() - }, - } - } -} - -impl From> for OptionUint { - fn from(value: Option) -> Self { - match value { - Some(value) => Self::from(value), - None => Self { - status: false, - value: Default::default(), - }, - } - } -} - -/// Ethereum representation of Optional value with CrossAddress. -#[derive(Debug, Default, AbiCoder)] -pub struct OptionCrossAddress { - /// Whether or not this CrossAdress is valid and has meaning. - pub status: bool, - /// The underlying CrossAddress value. If the status is false, can be set to whatever. - pub value: CrossAddress, -} - /// Cross account struct #[derive(Debug, Default, AbiCoder)] pub struct CrossAddress { @@ -252,23 +187,23 @@ #[derive(Debug, Default, AbiCoder)] pub struct CollectionLimit { field: CollectionLimitField, - value: OptionUint, + value: Option, } impl CollectionLimit { /// Create [`CollectionLimit`] from field and value. - pub fn new(field: CollectionLimitField, value: T) -> Self - where - OptionUint: From, - { + pub fn new(field: CollectionLimitField, value: Option) -> Self { Self { field, - value: value.into(), + value: match value { + Some(value) => Some(value.into()), + None => None, + }, } } /// Whether the field contains a value. pub fn has_value(&self) -> bool { - self.value.status + self.value.is_some() } } @@ -276,52 +211,60 @@ type Error = evm_coder::execution::Error; fn try_into(self) -> Result { - let value = self.value.value.try_into().map_err(|error| { + let value = self + .value + .ok_or::("can't convert `None` value to boolean".into())?; + let value = Some(value.try_into().map_err(|error| { Self::Error::Revert(format!( "can't convert value to u32 \"{}\" because: \"{error}\"", - self.value.value + value )) - })?; + })?); let convert_value_to_bool = || match value { - 0 => Ok(false), - 1 => Ok(true), - _ => { - return Err(Self::Error::Revert(format!( - "can't convert value to boolean \"{value}\"" - ))) - } + Some(value) => match value { + 0 => Ok(Some(false)), + 1 => Ok(Some(true)), + _ => { + return Err(Self::Error::Revert(format!( + "can't convert value to boolean \"{value}\"" + ))) + } + }, + None => Ok(None), }; let mut limits = up_data_structs::CollectionLimits::default(); match self.field { CollectionLimitField::AccountTokenOwnership => { - limits.account_token_ownership_limit = Some(value); + limits.account_token_ownership_limit = value; } CollectionLimitField::SponsoredDataSize => { - limits.sponsored_data_size = Some(value); + limits.sponsored_data_size = value; } CollectionLimitField::SponsoredDataRateLimit => { - limits.sponsored_data_rate_limit = - Some(up_data_structs::SponsoringRateLimit::Blocks(value)); + limits.sponsored_data_rate_limit = match value { + Some(value) => Some(up_data_structs::SponsoringRateLimit::Blocks(value)), + None => None, + }; } CollectionLimitField::TokenLimit => { - limits.token_limit = Some(value); + limits.token_limit = value; } CollectionLimitField::SponsorTransferTimeout => { - limits.sponsor_transfer_timeout = Some(value); + limits.sponsor_transfer_timeout = value; } CollectionLimitField::SponsorApproveTimeout => { - limits.sponsor_approve_timeout = Some(value); + limits.sponsor_approve_timeout = value; } CollectionLimitField::OwnerCanTransfer => { - limits.owner_can_transfer = Some(convert_value_to_bool()?); + limits.owner_can_transfer = convert_value_to_bool()?; } CollectionLimitField::OwnerCanDestroy => { - limits.owner_can_destroy = Some(convert_value_to_bool()?); + limits.owner_can_destroy = convert_value_to_bool()?; } CollectionLimitField::TransferEnabled => { - limits.transfers_enabled = Some(convert_value_to_bool()?); + limits.transfers_enabled = convert_value_to_bool()?; } }; Ok(limits) --- a/pallets/evm-contract-helpers/src/eth.rs +++ b/pallets/evm-contract-helpers/src/eth.rs @@ -175,16 +175,10 @@ /// /// @param contractAddress The contract for which a sponsor is requested. /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. - fn sponsor(&self, contract_address: address) -> Result { + fn sponsor(&self, contract_address: address) -> Result> { Ok(match Pallet::::get_sponsor(contract_address) { - Some(ref value) => eth::OptionCrossAddress { - status: true, - value: eth::CrossAddress::from_sub_cross_account::(value), - }, - None => eth::OptionCrossAddress { - status: false, - value: Default::default(), - }, + Some(ref value) => Some(eth::CrossAddress::from_sub_cross_account::(value)), + None => None, }) } --- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol +++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol @@ -281,10 +281,10 @@ uint256 sub; } -/// Ethereum representation of Optional value with CrossAddress. +/// Optional value struct OptionCrossAddress { - /// Whether or not this CrossAdress is valid and has meaning. + /// Shows the status of accessibility of value bool status; - /// The underlying CrossAddress value. If the status is false, can be set to whatever. + /// Actual value if `status` is true CrossAddress value; } --- a/pallets/fungible/src/stubs/UniqueFungible.sol +++ b/pallets/fungible/src/stubs/UniqueFungible.sol @@ -466,12 +466,14 @@ /// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. struct CollectionLimit { CollectionLimitField field; - OptionUint value; + OptionUint256 value; } -/// Ethereum representation of Optional value with uint256. -struct OptionUint { +/// Optional value +struct OptionUint256 { + /// Shows the status of accessibility of value bool status; + /// Actual value if `status` is true uint256 value; } --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -608,12 +608,14 @@ /// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. struct CollectionLimit { CollectionLimitField field; - OptionUint value; + OptionUint256 value; } -/// Ethereum representation of Optional value with uint256. -struct OptionUint { +/// Optional value +struct OptionUint256 { + /// Shows the status of accessibility of value bool status; + /// Actual value if `status` is true uint256 value; } --- a/pallets/refungible/src/stubs/UniqueRefungible.sol +++ b/pallets/refungible/src/stubs/UniqueRefungible.sol @@ -608,12 +608,14 @@ /// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. struct CollectionLimit { CollectionLimitField field; - OptionUint value; + OptionUint256 value; } -/// Ethereum representation of Optional value with uint256. -struct OptionUint { +/// Optional value +struct OptionUint256 { + /// Shows the status of accessibility of value bool status; + /// Actual value if `status` is true uint256 value; } --- a/runtime/common/identity.rs +++ b/runtime/common/identity.rs @@ -24,9 +24,6 @@ transaction_validity::{TransactionValidity, ValidTransaction, TransactionValidityError}, }; -#[cfg(feature = "collator-selection")] -use sp_runtime::transaction_validity::InvalidTransaction; - #[derive(Debug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] pub struct DisableIdentityCalls; --- a/tests/src/eth/abi/fungible.json +++ b/tests/src/eth/abi/fungible.json @@ -222,7 +222,7 @@ { "internalType": "bool", "name": "status", "type": "bool" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], - "internalType": "struct OptionUint", + "internalType": "struct OptionUint256", "name": "value", "type": "tuple" } @@ -508,7 +508,7 @@ { "internalType": "bool", "name": "status", "type": "bool" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], - "internalType": "struct OptionUint", + "internalType": "struct OptionUint256", "name": "value", "type": "tuple" } --- a/tests/src/eth/abi/fungibleDeprecated.json +++ b/tests/src/eth/abi/fungibleDeprecated.json @@ -88,14 +88,5 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "changeCollectionOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" } ] --- a/tests/src/eth/abi/nonFungible.json +++ b/tests/src/eth/abi/nonFungible.json @@ -51,12 +51,6 @@ }, { "anonymous": false, - "inputs": [], - "name": "MintingFinished", - "type": "event" - }, - { - "anonymous": false, "inputs": [ { "indexed": true, @@ -252,7 +246,7 @@ { "internalType": "bool", "name": "status", "type": "bool" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], - "internalType": "struct OptionUint", + "internalType": "struct OptionUint256", "name": "value", "type": "tuple" } @@ -420,13 +414,6 @@ "name": "description", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finishMinting", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", "type": "function" }, { @@ -513,13 +500,6 @@ "name": "mintWithTokenURI", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mintingFinished", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", "type": "function" }, { @@ -670,7 +650,7 @@ { "internalType": "bool", "name": "status", "type": "bool" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], - "internalType": "struct OptionUint", + "internalType": "struct OptionUint256", "name": "value", "type": "tuple" } --- a/tests/src/eth/abi/reFungible.json +++ b/tests/src/eth/abi/reFungible.json @@ -51,12 +51,6 @@ }, { "anonymous": false, - "inputs": [], - "name": "MintingFinished", - "type": "event" - }, - { - "anonymous": false, "inputs": [ { "indexed": true, @@ -234,7 +228,7 @@ { "internalType": "bool", "name": "status", "type": "bool" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], - "internalType": "struct OptionUint", + "internalType": "struct OptionUint256", "name": "value", "type": "tuple" } @@ -402,13 +396,6 @@ "name": "description", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "finishMinting", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", "type": "function" }, { @@ -495,13 +482,6 @@ "name": "mintWithTokenURI", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mintingFinished", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", "type": "function" }, { @@ -652,7 +632,7 @@ { "internalType": "bool", "name": "status", "type": "bool" }, { "internalType": "uint256", "name": "value", "type": "uint256" } ], - "internalType": "struct OptionUint", + "internalType": "struct OptionUint256", "name": "value", "type": "tuple" } --- a/tests/src/eth/abi/reFungibleDeprecated.json +++ b/tests/src/eth/abi/reFungibleDeprecated.json @@ -82,6 +82,17 @@ }, { "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "changeCollectionOwner", --- a/tests/src/eth/abi/reFungibleToken.json +++ b/tests/src/eth/abi/reFungibleToken.json @@ -98,16 +98,6 @@ }, { "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "name": "burnFrom", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ { "components": [ { "internalType": "address", "name": "eth", "type": "address" }, --- /dev/null +++ b/tests/src/eth/abi/reFungibleTokenDeprecated.json @@ -0,0 +1,12 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "burnFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + } +] --- a/tests/src/eth/api/ContractHelpers.sol +++ b/tests/src/eth/api/ContractHelpers.sol @@ -181,11 +181,11 @@ Generous } -/// Ethereum representation of Optional value with CrossAddress. +/// Optional value struct OptionCrossAddress { - /// Whether or not this CrossAdress is valid and has meaning. + /// Shows the status of accessibility of value bool status; - /// The underlying CrossAddress value. If the status is false, can be set to whatever. + /// Actual value if `status` is true CrossAddress value; } --- a/tests/src/eth/api/UniqueFungible.sol +++ b/tests/src/eth/api/UniqueFungible.sol @@ -308,12 +308,14 @@ /// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. struct CollectionLimit { CollectionLimitField field; - OptionUint value; + OptionUint256 value; } -/// Ethereum representation of Optional value with uint256. -struct OptionUint { +/// Optional value +struct OptionUint256 { + /// Shows the status of accessibility of value bool status; + /// Actual value if `status` is true uint256 value; } --- a/tests/src/eth/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -408,12 +408,14 @@ /// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. struct CollectionLimit { CollectionLimitField field; - OptionUint value; + OptionUint256 value; } -/// Ethereum representation of Optional value with uint256. -struct OptionUint { +/// Optional value +struct OptionUint256 { + /// Shows the status of accessibility of value bool status; + /// Actual value if `status` is true uint256 value; } --- a/tests/src/eth/api/UniqueRefungible.sol +++ b/tests/src/eth/api/UniqueRefungible.sol @@ -408,12 +408,14 @@ /// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. struct CollectionLimit { CollectionLimitField field; - OptionUint value; + OptionUint256 value; } -/// Ethereum representation of Optional value with uint256. -struct OptionUint { +/// Optional value +struct OptionUint256 { + /// Shows the status of accessibility of value bool status; + /// Actual value if `status` is true uint256 value; } --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -213,7 +213,7 @@ const address = helper.ethAddress.fromCollectionId(collection.collectionId); const contract = await helper.ethNativeContract.collection(address, 'rft'); - const rftToken = await helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner); + const rftToken = await helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner, true); { await rftToken.methods.approve(operator, 15n).send({from: owner}); --- a/tests/src/eth/reFungibleToken.test.ts +++ b/tests/src/eth/reFungibleToken.test.ts @@ -413,7 +413,7 @@ const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId); - const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller); + const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller, true); await tokenContract.methods.repartition(2).send(); await tokenContract.methods.transfer(receiver, 1).send(); --- a/tests/src/eth/util/playgrounds/unique.dev.ts +++ b/tests/src/eth/util/playgrounds/unique.dev.ts @@ -29,6 +29,7 @@ import refungibleAbi from '../../abi/reFungible.json'; import refungibleDeprecatedAbi from '../../abi/reFungibleDeprecated.json'; import refungibleTokenAbi from '../../abi/reFungibleToken.json'; +import refungibleTokenDeprecatedAbi from '../../abi/reFungibleTokenDeprecated.json'; import contractHelpersAbi from '../../abi/contractHelpers.json'; import {ICrossAccountId, TEthereumAccount} from '../../../util/playgrounds/types'; import {TCollectionMode} from '../../../util/playgrounds/types'; @@ -187,17 +188,18 @@ return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated); } - async rftToken(address: string, caller?: string) { + async rftToken(address: string, caller?: string, mergeDeprecated = false) { const web3 = this.helper.getWeb3(); - return unlimitedMoneyHack(new web3.eth.Contract(refungibleTokenAbi as any, address, { + const abi = mergeDeprecated ? [...refungibleTokenAbi, ...refungibleTokenDeprecatedAbi] : refungibleTokenAbi; + return unlimitedMoneyHack(new web3.eth.Contract(abi as any, address, { gas: this.helper.eth.DEFAULT_GAS, gasPrice: await this.getGasPrice(), ...(caller ? {from: caller} : {}), })); } - rftTokenById(collectionId: number, tokenId: number, caller?: string) { - return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller); + rftTokenById(collectionId: number, tokenId: number, caller?: string, mergeDeprecated = false) { + return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller, mergeDeprecated); } } -- gitstuff