Approve Simplified
One of the most interesting features of ITEMs for dApps is the simplified approve function.
If you implement your smart contract with native wrap/unwrap, or give users the possibility to use ITEMs directly, you can:
1)--- Use the safeTranferFrom functionality with the ERC1155 methodology by helping users approve only transactions with a different msg.sender from the wallet owner, and only once for an entire collection.
2)--- If you need to use the ERC20 interface, you can implement ERC721 Approve by signing the Approve and saving the user from an extra transaction (Like how Uniswap V2 LP tokens work.)
ERC712 Approve Example
1
//The EthItemInteroperableInterface token implements the
2
function permit(address owner, address spender, uint value, uint8 v, bytes32 r, bytes32 s) external;
3
//and
4
function permitNonce(address sender) external view returns(uint256)
Copied!
These are useful to bypass the approve(address,uint256) ERC20 function by implementing an alternative way based on digital signature verification mechanism which follows the EIP-712 standard.
1
//Imagine you have the following Spender Smart Contract
2
/*
3
pragma solidity ^0.6.0;
4
5
contract Spender {
6
7
function oneShotTransferFrom(address interoperationalInterfaceAddress, address receiver, uint256 value, uint8 v, bytes32 r, bytes32 s) public {
8
IEthItemInteroperationalInterface token = IEthItemInteroperationalInterface(erc20NFTWrapperAddress);
9
token.permit(msg.sender, address(this), value, v, r, s);
10
token.transferFrom(msg.sender, receiver, value);
11
}
12
}
13
14
interface IEthItemInteroperationalInterface {
15
function permit(address owner, address spender, uint value, uint8 v, bytes32 r, bytes32 s) external;
16
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
17
}
18
*/
19
20
//oneShotTransferFrom let the Spender transfer the sender Tokens without calling the approve(address,uint256) function of the ERC20 Token because the sender digitally signed a Permit message,
21
//saving time and gas
22
23
//Grab the objectId to transfer
24
var objectId = configuration.myObjectId;
25
26
//Let's take the IEthItemInteroperationalInterfaceversion of the objectId
27
var itemInteroperableInterface = await collection.contract.methods.asInteroperable(objectId).call();
28
29
//The address of the spender
30
var spenderAddress = configuration.spenderAddress;
31
32
//The amount the spender can transfer for you
33
var amountToPermit = configuration.amountToPermit;
34
35
var itemInteroperableInterface = new web3.eth.Contract(configuration.IEthItemInteroperableInterfaceABI, erc20NFTWrapperAddress);
36
37
//Let's take the next useful nonce
38
var nonce = await itemInteroperableInterface.methods.permitNonce(web3.eth.accounts[0]).call();
39
40
//Build the signature following the EIP 712 v4 protocol
41
var EIP712Domain = [
42
{ name: 'name', type: 'string' },
43
{ name: 'version', type: 'string' },
44
{ name: 'chainId', type: 'uint256' },
45
{ name: 'verifyingContract', type: 'address' }
46
];
47
48
var domain = {
49
name: 'Item',
50
version: '1',
51
chainId: await web3.eth.getNetworkId(),
52
verifyingContract: itemInteroperableInterface
53
};
54
55
var Permit = [
56
{ name: 'owner', type: 'address' },
57
{ name: 'spender', type: 'address' },
58
{ name: 'value', type: 'uint256' },
59
{ name: 'nonce', type: 'uint256' },
60
];
61
62
var message = {
63
owner: web3.eth.accounts[0],
64
spenderAddress,
65
amountToPermit,
66
nonce
67
};
68
69
var data = JSON.stringify({
70
types: {
71
EIP712Domain,
72
Permit
73
},
74
domain,
75
primaryType: 'Permit',
76
message
77
});
78
79
var signatureParameters = await new Promise(function(ok, ko) {
80
window.web3.currentProvider.sendAsync({
81
method: 'eth_signTypedData_v4',
82
params: [web3.eth.accounts[0], data],
83
from: web3.eth.accounts[0]
84
}, function(e, signature) {
85
if (e) {
86
return ko(e);
87
}
88
signature = signature.result.substring(2);
89
return ok({
90
r: '0x' + signature.slice(0, 64),
91
s: '0x' + signature.slice(64, 128),
92
v: web3.utils.toDecimal('0x' + signature.slice(128, 130))
93
});
94
});
95
});
96
97
//Take the Spender Contract
98
var spender = new web3.eth.Contract(configuration.SpenderABI, spenderAddress);
99
100
//Grab the final receiver of the tokens
101
var tokensReceiver = configuration.tokensReceiver;
102
103
//Call the oneShotTransferFrom without the use of the approve function
104
await spender.methods.oneShotTransferFrom(itemInteroperableInterface, tokensReceiver, amountToPermit, signatureParameters.v, signatureParameters.r, signatureParameters.s).send();
Copied!
Copy link