Permit Approval

Permit support

The Items v2 standard supports the EIP-2612 which proposes the additional permit method for making approvals by way of signed messages rather than direct transactions.

The following code can be used as an integration example of the permit operation at the Frontend level to obtain the off-chain signature.

window.permit = async function permit(tokenAddress, spender, value, deadline) {
    isNaN(deadline) && (deadline = window.numberToString((new Date().getTime() / 1000) + 300).split('.')[0]);

    var token = tokenAddress.options ? tokenAddress : window.newContract(window.context.ERC20ABI, tokenAddress);
    var owner = window.walletAddress;

    var nonce = await token.methods.nonces(owner).call();

    var EIP712Domain = [
        { name: 'name', type: 'string' },
        { name: 'version', type: 'string' },
        { name: 'chainId', type: 'uint256' },
        { name: 'verifyingContract', type: 'address' }
    ];

    var domainSeparatorName = "Item";
    var domainSeparatorVersion = "1";

    try {
        var domainSeparatorData = await token.methods.EIP712_PERMIT_DOMAINSEPARATOR_NAME_AND_VERSION().call();
        domainSeparatorName = domainSeparatorData[0];
        domainSeparatorVersion = domainSeparatorData[1];
    } catch(e) {
    }

    var domain = {
        name: domainSeparatorName,
        version: domainSeparatorVersion,
        chainId: await web3.eth.getChainId(),
        verifyingContract: token.options.address
    };

    var Permit = [
        { name: 'owner', type: 'address' },
        { name: 'spender', type: 'address' },
        { name: 'value', type: 'uint256' },
        { name: 'nonce', type: 'uint256' },
        { name: 'deadline', type: 'uint256' }
    ];

    var message = {
        owner,
        spender,
        value,
        nonce,
        deadline
    };

    var data = {
        types: {
            EIP712Domain,
            Permit
        },
        domain,
        primaryType: 'Permit',
        message
    };

    return await new Promise(async function(ok, ko) {
        await web3.currentProvider.sendAsync({
            method: 'eth_signTypedData_v4',
            params: [owner, JSON.stringify(data)],
            from: owner
        }, function(e, signature) {
            if (e) {
                return ko(e);
            }
            signature = signature.result.substring(2);
            return ok({
                r: '0x' + signature.slice(0, 64),
                s: '0x' + signature.slice(64, 128),
                v: web3.utils.toDecimal('0x' + signature.slice(128, 130)),
                ...message
            });
        });
    });
}

According to this pattern, once the off-chain sign is generated the permit function can be called by any address to execute the on-chain transaction. Through the permit function the allowanced amount that the spender address can spend is registered and saved in the Main Interface contract.

itemData.allowance[owner][spender] = value;

If the off-chain sign is correctly generated and signed by the owner but the permit function is not executed (passing all the parameters related to the sign and explained here) the spender address is not allowed to spend the owner's ITEMs amount.

Since the transaction can be performed by anyone (once the signature is correctly signed by the owner address), an ITEM v2 can be used to build also complex applications regarding gas-less transactions or meta-transactions that use a third party to execute the transaction and pay the gas fee.

Last updated