//Imagine you have the following Spender Smart Contract
function oneShotTransferFrom(address interoperationalInterfaceAddress, address receiver, uint256 value, uint8 v, bytes32 r, bytes32 s) public {
IEthItemInteroperationalInterface token = IEthItemInteroperationalInterface(erc20NFTWrapperAddress);
token.permit(msg.sender, address(this), value, v, r, s);
token.transferFrom(msg.sender, receiver, value);
interface IEthItemInteroperationalInterface {
function permit(address owner, address spender, uint value, uint8 v, bytes32 r, bytes32 s) external;
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
//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,
//Grab the objectId to transfer
var objectId = configuration.myObjectId;
//Let's take the IEthItemInteroperationalInterfaceversion of the objectId
var itemInteroperableInterface = await collection.contract.methods.asInteroperable(objectId).call();
//The address of the spender
var spenderAddress = configuration.spenderAddress;
//The amount the spender can transfer for you
var amountToPermit = configuration.amountToPermit;
var itemInteroperableInterface = new web3.eth.Contract(configuration.IEthItemInteroperableInterfaceABI, erc20NFTWrapperAddress);
//Let's take the next useful nonce
var nonce = await itemInteroperableInterface.methods.permitNonce(web3.eth.accounts[0]).call();
//Build the signature following the EIP 712 v4 protocol
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' }
chainId: await web3.eth.getNetworkId(),
verifyingContract: itemInteroperableInterface
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'nonce', type: 'uint256' },
owner: web3.eth.accounts[0],
var data = JSON.stringify({
var signatureParameters = await new Promise(function(ok, ko) {
window.web3.currentProvider.sendAsync({
method: 'eth_signTypedData_v4',
params: [web3.eth.accounts[0], data],
from: web3.eth.accounts[0]
}, function(e, signature) {
signature = signature.result.substring(2);
r: '0x' + signature.slice(0, 64),
s: '0x' + signature.slice(64, 128),
v: web3.utils.toDecimal('0x' + signature.slice(128, 130))
//Take the Spender Contract
var spender = new web3.eth.Contract(configuration.SpenderABI, spenderAddress);
//Grab the final receiver of the tokens
var tokensReceiver = configuration.tokensReceiver;
//Call the oneShotTransferFrom without the use of the approve function
await spender.methods.oneShotTransferFrom(itemInteroperableInterface, tokensReceiver, amountToPermit, signatureParameters.v, signatureParameters.r, signatureParameters.s).send();