git.delta.rocks / unique-network / refs/commits / 238681dec68a

difftreelog

added `transferFromCross` method in `ERC20` refungible pallet interface

PraetorP2022-12-07parent: #b238f7b.patch.diff
in: master

5 files changed

modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc_token.rs
+++ b/pallets/refungible/src/erc_token.rs
@@ -299,6 +299,31 @@
 			.map_err(dispatch_to_evm::<T>)?;
 		Ok(true)
 	}
+
+	/// @dev Transfer tokens from one address to another
+	/// @param from address The address which you want to send tokens from
+	/// @param to address The address which you want to transfer to
+	/// @param amount uint256 the amount of tokens to be transferred
+	#[weight(<CommonWeights<T>>::transfer_from())]
+	fn transfer_from_cross(
+		&mut self,
+		caller: caller,
+		from: EthCrossAccount,
+		to: EthCrossAccount,
+		amount: uint256,
+	) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let from = from.into_sub_cross_account::<T>()?;
+		let to = to.into_sub_cross_account::<T>()?;
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+		let budget = self
+			.recorder
+			.weight_calls_budget(<StructureWeight<T>>::find_parent());
+
+		<Pallet<T>>::transfer_from(self, &caller, &from, &to, self.1, amount, &budget)
+			.map_err(dispatch_to_evm::<T>)?;
+		Ok(true)
+	}
 }
 
 impl<T: Config> RefungibleTokenHandle<T> {
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth
before · pallets/refungible/src/stubs/UniqueRefungibleToken.sol
1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56/// @dev common stubs holder7contract Dummy {8	uint8 dummy;9	string stub_error = "this contract is implemented in native";10}1112contract ERC165 is Dummy {13	function supportsInterface(bytes4 interfaceID) external view returns (bool) {14		require(false, stub_error);15		interfaceID;16		return true;17	}18}1920/// @dev the ERC-165 identifier for this interface is 0x5755c3f221contract ERC1633 is Dummy, ERC165 {22	/// @dev EVM selector for this function is: 0x80a54001,23	///  or in textual repr: parentToken()24	function parentToken() public view returns (address) {25		require(false, stub_error);26		dummy;27		return 0x0000000000000000000000000000000000000000;28	}2930	/// @dev EVM selector for this function is: 0xd7f083f3,31	///  or in textual repr: parentTokenId()32	function parentTokenId() public view returns (uint256) {33		require(false, stub_error);34		dummy;35		return 0;36	}37}3839/// @dev the ERC-165 identifier for this interface is 0x34b53e2040contract ERC20UniqueExtensions is Dummy, ERC165 {41	/// @dev Function that burns an amount of the token of a given account,42	/// deducting from the sender's allowance for said account.43	/// @param from The account whose tokens will be burnt.44	/// @param amount The amount that will be burnt.45	/// @dev EVM selector for this function is: 0x79cc6790,46	///  or in textual repr: burnFrom(address,uint256)47	function burnFrom(address from, uint256 amount) public returns (bool) {48		require(false, stub_error);49		from;50		amount;51		dummy = 0;52		return false;53	}5455	/// @dev Function that burns an amount of the token of a given account,56	/// deducting from the sender's allowance for said account.57	/// @param from The account whose tokens will be burnt.58	/// @param amount The amount that will be burnt.59	/// @dev EVM selector for this function is: 0xbb2f5a58,60	///  or in textual repr: burnFromCross((address,uint256),uint256)61	function burnFromCross(EthCrossAccount memory from, uint256 amount) public returns (bool) {62		require(false, stub_error);63		from;64		amount;65		dummy = 0;66		return false;67	}6869	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.70	/// Beware that changing an allowance with this method brings the risk that someone may use both the old71	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this72	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:73	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-26352472974	/// @param spender The crossaccount which will spend the funds.75	/// @param amount The amount of tokens to be spent.76	/// @dev EVM selector for this function is: 0x0ecd0ab0,77	///  or in textual repr: approveCross((address,uint256),uint256)78	function approveCross(EthCrossAccount memory spender, uint256 amount) public returns (bool) {79		require(false, stub_error);80		spender;81		amount;82		dummy = 0;83		return false;84	}8586	/// @dev Function that changes total amount of the tokens.87	///  Throws if `msg.sender` doesn't owns all of the tokens.88	/// @param amount New total amount of the tokens.89	/// @dev EVM selector for this function is: 0xd2418ca7,90	///  or in textual repr: repartition(uint256)91	function repartition(uint256 amount) public returns (bool) {92		require(false, stub_error);93		amount;94		dummy = 0;95		return false;96	}9798	/// @dev Transfer token for a specified address99	/// @param to The crossaccount to transfer to.100	/// @param amount The amount to be transferred.101	/// @dev EVM selector for this function is: 0x2ada85ff,102	///  or in textual repr: transferCross((address,uint256),uint256)103	function transferCross(EthCrossAccount memory to, uint256 amount) public returns (bool) {104		require(false, stub_error);105		to;106		amount;107		dummy = 0;108		return false;109	}110}111112/// @dev Cross account struct113struct EthCrossAccount {114	address eth;115	uint256 sub;116}117118/// @dev inlined interface119contract ERC20Events {120	event Transfer(address indexed from, address indexed to, uint256 value);121	event Approval(address indexed owner, address indexed spender, uint256 value);122}123124/// @title Standard ERC20 token125///126/// @dev Implementation of the basic standard token.127/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md128/// @dev the ERC-165 identifier for this interface is 0x942e8b22129contract ERC20 is Dummy, ERC165, ERC20Events {130	/// @return the name of the token.131	/// @dev EVM selector for this function is: 0x06fdde03,132	///  or in textual repr: name()133	function name() public view returns (string memory) {134		require(false, stub_error);135		dummy;136		return "";137	}138139	/// @return the symbol of the token.140	/// @dev EVM selector for this function is: 0x95d89b41,141	///  or in textual repr: symbol()142	function symbol() public view returns (string memory) {143		require(false, stub_error);144		dummy;145		return "";146	}147148	/// @dev Total number of tokens in existence149	/// @dev EVM selector for this function is: 0x18160ddd,150	///  or in textual repr: totalSupply()151	function totalSupply() public view returns (uint256) {152		require(false, stub_error);153		dummy;154		return 0;155	}156157	/// @dev Not supported158	/// @dev EVM selector for this function is: 0x313ce567,159	///  or in textual repr: decimals()160	function decimals() public view returns (uint8) {161		require(false, stub_error);162		dummy;163		return 0;164	}165166	/// @dev Gets the balance of the specified address.167	/// @param owner The address to query the balance of.168	/// @return An uint256 representing the amount owned by the passed address.169	/// @dev EVM selector for this function is: 0x70a08231,170	///  or in textual repr: balanceOf(address)171	function balanceOf(address owner) public view returns (uint256) {172		require(false, stub_error);173		owner;174		dummy;175		return 0;176	}177178	/// @dev Transfer token for a specified address179	/// @param to The address to transfer to.180	/// @param amount The amount to be transferred.181	/// @dev EVM selector for this function is: 0xa9059cbb,182	///  or in textual repr: transfer(address,uint256)183	function transfer(address to, uint256 amount) public returns (bool) {184		require(false, stub_error);185		to;186		amount;187		dummy = 0;188		return false;189	}190191	/// @dev Transfer tokens from one address to another192	/// @param from address The address which you want to send tokens from193	/// @param to address The address which you want to transfer to194	/// @param amount uint256 the amount of tokens to be transferred195	/// @dev EVM selector for this function is: 0x23b872dd,196	///  or in textual repr: transferFrom(address,address,uint256)197	function transferFrom(198		address from,199		address to,200		uint256 amount201	) public returns (bool) {202		require(false, stub_error);203		from;204		to;205		amount;206		dummy = 0;207		return false;208	}209210	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.211	/// Beware that changing an allowance with this method brings the risk that someone may use both the old212	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this213	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:214	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729215	/// @param spender The address which will spend the funds.216	/// @param amount The amount of tokens to be spent.217	/// @dev EVM selector for this function is: 0x095ea7b3,218	///  or in textual repr: approve(address,uint256)219	function approve(address spender, uint256 amount) public returns (bool) {220		require(false, stub_error);221		spender;222		amount;223		dummy = 0;224		return false;225	}226227	/// @dev Function to check the amount of tokens that an owner allowed to a spender.228	/// @param owner address The address which owns the funds.229	/// @param spender address The address which will spend the funds.230	/// @return A uint256 specifying the amount of tokens still available for the spender.231	/// @dev EVM selector for this function is: 0xdd62ed3e,232	///  or in textual repr: allowance(address,address)233	function allowance(address owner, address spender) public view returns (uint256) {234		require(false, stub_error);235		owner;236		spender;237		dummy;238		return 0;239	}240}241242contract UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions, ERC1633 {}
after · pallets/refungible/src/stubs/UniqueRefungibleToken.sol
1// SPDX-License-Identifier: OTHER2// This code is automatically generated34pragma solidity >=0.8.0 <0.9.0;56/// @dev common stubs holder7contract Dummy {8	uint8 dummy;9	string stub_error = "this contract is implemented in native";10}1112contract ERC165 is Dummy {13	function supportsInterface(bytes4 interfaceID) external view returns (bool) {14		require(false, stub_error);15		interfaceID;16		return true;17	}18}1920/// @dev the ERC-165 identifier for this interface is 0x5755c3f221contract ERC1633 is Dummy, ERC165 {22	/// @dev EVM selector for this function is: 0x80a54001,23	///  or in textual repr: parentToken()24	function parentToken() public view returns (address) {25		require(false, stub_error);26		dummy;27		return 0x0000000000000000000000000000000000000000;28	}2930	/// @dev EVM selector for this function is: 0xd7f083f3,31	///  or in textual repr: parentTokenId()32	function parentTokenId() public view returns (uint256) {33		require(false, stub_error);34		dummy;35		return 0;36	}37}3839/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b40contract ERC20UniqueExtensions is Dummy, ERC165 {41	/// @dev Function that burns an amount of the token of a given account,42	/// deducting from the sender's allowance for said account.43	/// @param from The account whose tokens will be burnt.44	/// @param amount The amount that will be burnt.45	/// @dev EVM selector for this function is: 0x79cc6790,46	///  or in textual repr: burnFrom(address,uint256)47	function burnFrom(address from, uint256 amount) public returns (bool) {48		require(false, stub_error);49		from;50		amount;51		dummy = 0;52		return false;53	}5455	/// @dev Function that burns an amount of the token of a given account,56	/// deducting from the sender's allowance for said account.57	/// @param from The account whose tokens will be burnt.58	/// @param amount The amount that will be burnt.59	/// @dev EVM selector for this function is: 0xbb2f5a58,60	///  or in textual repr: burnFromCross((address,uint256),uint256)61	function burnFromCross(EthCrossAccount memory from, uint256 amount) public returns (bool) {62		require(false, stub_error);63		from;64		amount;65		dummy = 0;66		return false;67	}6869	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.70	/// Beware that changing an allowance with this method brings the risk that someone may use both the old71	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this72	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:73	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-26352472974	/// @param spender The crossaccount which will spend the funds.75	/// @param amount The amount of tokens to be spent.76	/// @dev EVM selector for this function is: 0x0ecd0ab0,77	///  or in textual repr: approveCross((address,uint256),uint256)78	function approveCross(EthCrossAccount memory spender, uint256 amount) public returns (bool) {79		require(false, stub_error);80		spender;81		amount;82		dummy = 0;83		return false;84	}8586	/// @dev Function that changes total amount of the tokens.87	///  Throws if `msg.sender` doesn't owns all of the tokens.88	/// @param amount New total amount of the tokens.89	/// @dev EVM selector for this function is: 0xd2418ca7,90	///  or in textual repr: repartition(uint256)91	function repartition(uint256 amount) public returns (bool) {92		require(false, stub_error);93		amount;94		dummy = 0;95		return false;96	}9798	/// @dev Transfer token for a specified address99	/// @param to The crossaccount to transfer to.100	/// @param amount The amount to be transferred.101	/// @dev EVM selector for this function is: 0x2ada85ff,102	///  or in textual repr: transferCross((address,uint256),uint256)103	function transferCross(EthCrossAccount memory to, uint256 amount) public returns (bool) {104		require(false, stub_error);105		to;106		amount;107		dummy = 0;108		return false;109	}110111	/// @dev Transfer tokens from one address to another112	/// @param from address The address which you want to send tokens from113	/// @param to address The address which you want to transfer to114	/// @param amount uint256 the amount of tokens to be transferred115	/// @dev EVM selector for this function is: 0xd5cf430b,116	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)117	function transferFromCross(118		EthCrossAccount memory from,119		EthCrossAccount memory to,120		uint256 amount121	) public returns (bool) {122		require(false, stub_error);123		from;124		to;125		amount;126		dummy = 0;127		return false;128	}129}130131/// @dev Cross account struct132struct EthCrossAccount {133	address eth;134	uint256 sub;135}136137/// @dev inlined interface138contract ERC20Events {139	event Transfer(address indexed from, address indexed to, uint256 value);140	event Approval(address indexed owner, address indexed spender, uint256 value);141}142143/// @title Standard ERC20 token144///145/// @dev Implementation of the basic standard token.146/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md147/// @dev the ERC-165 identifier for this interface is 0x942e8b22148contract ERC20 is Dummy, ERC165, ERC20Events {149	/// @return the name of the token.150	/// @dev EVM selector for this function is: 0x06fdde03,151	///  or in textual repr: name()152	function name() public view returns (string memory) {153		require(false, stub_error);154		dummy;155		return "";156	}157158	/// @return the symbol of the token.159	/// @dev EVM selector for this function is: 0x95d89b41,160	///  or in textual repr: symbol()161	function symbol() public view returns (string memory) {162		require(false, stub_error);163		dummy;164		return "";165	}166167	/// @dev Total number of tokens in existence168	/// @dev EVM selector for this function is: 0x18160ddd,169	///  or in textual repr: totalSupply()170	function totalSupply() public view returns (uint256) {171		require(false, stub_error);172		dummy;173		return 0;174	}175176	/// @dev Not supported177	/// @dev EVM selector for this function is: 0x313ce567,178	///  or in textual repr: decimals()179	function decimals() public view returns (uint8) {180		require(false, stub_error);181		dummy;182		return 0;183	}184185	/// @dev Gets the balance of the specified address.186	/// @param owner The address to query the balance of.187	/// @return An uint256 representing the amount owned by the passed address.188	/// @dev EVM selector for this function is: 0x70a08231,189	///  or in textual repr: balanceOf(address)190	function balanceOf(address owner) public view returns (uint256) {191		require(false, stub_error);192		owner;193		dummy;194		return 0;195	}196197	/// @dev Transfer token for a specified address198	/// @param to The address to transfer to.199	/// @param amount The amount to be transferred.200	/// @dev EVM selector for this function is: 0xa9059cbb,201	///  or in textual repr: transfer(address,uint256)202	function transfer(address to, uint256 amount) public returns (bool) {203		require(false, stub_error);204		to;205		amount;206		dummy = 0;207		return false;208	}209210	/// @dev Transfer tokens from one address to another211	/// @param from address The address which you want to send tokens from212	/// @param to address The address which you want to transfer to213	/// @param amount uint256 the amount of tokens to be transferred214	/// @dev EVM selector for this function is: 0x23b872dd,215	///  or in textual repr: transferFrom(address,address,uint256)216	function transferFrom(217		address from,218		address to,219		uint256 amount220	) public returns (bool) {221		require(false, stub_error);222		from;223		to;224		amount;225		dummy = 0;226		return false;227	}228229	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.230	/// Beware that changing an allowance with this method brings the risk that someone may use both the old231	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this232	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:233	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729234	/// @param spender The address which will spend the funds.235	/// @param amount The amount of tokens to be spent.236	/// @dev EVM selector for this function is: 0x095ea7b3,237	///  or in textual repr: approve(address,uint256)238	function approve(address spender, uint256 amount) public returns (bool) {239		require(false, stub_error);240		spender;241		amount;242		dummy = 0;243		return false;244	}245246	/// @dev Function to check the amount of tokens that an owner allowed to a spender.247	/// @param owner address The address which owns the funds.248	/// @param spender address The address which will spend the funds.249	/// @return A uint256 specifying the amount of tokens still available for the spender.250	/// @dev EVM selector for this function is: 0xdd62ed3e,251	///  or in textual repr: allowance(address,address)252	function allowance(address owner, address spender) public view returns (uint256) {253		require(false, stub_error);254		owner;255		spender;256		dummy;257		return 0;258	}259}260261contract UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions, ERC1633 {}
modifiedtests/src/eth/abi/reFungibleToken.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungibleToken.json
+++ b/tests/src/eth/abi/reFungibleToken.json
@@ -222,5 +222,32 @@
     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
     "stateMutability": "nonpayable",
     "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct EthCrossAccount",
+        "name": "from",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct EthCrossAccount",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFromCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
   }
 ]
modifiedtests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungibleToken.sol
+++ b/tests/src/eth/api/UniqueRefungibleToken.sol
@@ -23,7 +23,7 @@
 	function parentTokenId() external view returns (uint256);
 }
 
-/// @dev the ERC-165 identifier for this interface is 0x34b53e20
+/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b
 interface ERC20UniqueExtensions is Dummy, ERC165 {
 	/// @dev Function that burns an amount of the token of a given account,
 	/// deducting from the sender's allowance for said account.
@@ -65,6 +65,18 @@
 	/// @dev EVM selector for this function is: 0x2ada85ff,
 	///  or in textual repr: transferCross((address,uint256),uint256)
 	function transferCross(EthCrossAccount memory to, uint256 amount) external returns (bool);
+
+	/// @dev Transfer tokens from one address to another
+	/// @param from address The address which you want to send tokens from
+	/// @param to address The address which you want to transfer to
+	/// @param amount uint256 the amount of tokens to be transferred
+	/// @dev EVM selector for this function is: 0xd5cf430b,
+	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+	function transferFromCross(
+		EthCrossAccount memory from,
+		EthCrossAccount memory to,
+		uint256 amount
+	) external returns (bool);
 }
 
 /// @dev Cross account struct
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -223,6 +223,46 @@
       expect(+balance).to.equal(151);
     }
   });
+  
+  itEth('Can perform transferFromCross()', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+    const spender = await helper.eth.createAccountWithBalance(donor);
+    const receiver = helper.eth.createAccount();
+    const receiverCross = helper.ethCrossAccount.fromAddress(receiver);
+    const collection = await helper.rft.mintCollection(alice);
+    const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});
+
+    const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);
+    const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);
+
+    await contract.methods.approve(spender, 100).send();
+
+    {
+      const result = await contract.methods.transferFromCross(ownerCross, receiverCross, 49).send({from: spender});
+      let event = result.events.Transfer;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.value).to.be.equal('49');
+
+      event = result.events.Approval;
+      expect(event.address).to.be.equal(tokenAddress);
+      expect(event.returnValues.owner).to.be.equal(owner);
+      expect(event.returnValues.spender).to.be.equal(spender);
+      expect(event.returnValues.value).to.be.equal('51');
+    }
+
+    {
+      const balance = await contract.methods.balanceOf(receiver).call();
+      expect(+balance).to.equal(49);
+    }
+
+    {
+      const balance = await contract.methods.balanceOf(owner).call();
+      expect(+balance).to.equal(151);
+    }
+  });
 
   itEth('Can perform transfer()', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);