Gasless tx/ Transfer with authorization - ERC20
This guide describes how to execute a gasless transaction or transferWithAuthorization (EIP-3009) with ERC20 tokens.
Intro
Gasless transactions with "Transfer with Authorization" for ERC-20 tokens offer a seamless way to send tokens without needing to hold or spend gas fees. This feature empowers users to authorize an ERC20 token transfer via a signed message, allowing someone else to cover the gas costs. It simplifies the process by eliminating the need for a gas balance in your wallet, making transactions more accessible and user-friendly.

Gasless/ transferWithAuthorization on ERC20 Diagram
Scope
This only works for ERC20 token contracts supporting
transferWithAuthorizationfunction or EIP-3009.
Code Example
View the code example for the implementation of ERC20 gasless transaction.
Prerequisites
This example describes a gasless transaction on the Avalanche Fuji Testnet which carries out an ERC20 transfer. Make sure you have the following params ready:
| Params | Description/ Value | 
|---|---|
| ERC20 token holder wallet address | 0x8952fcc43F55c60C3Bf4FD565ABdd066CC1aD60c | 
| Name of ERC20 token contract | Zap | 
| ERC20 token contract address | 0x8c2e84c37fa226fdaa13999a725a638dbf2bc6a0 | 
| Wallet address where the tokens are to be transferred | 0xe56a14Cc9DbbA42D1DE1314051CA00AA742BaEfa | 
| chainId | 43113 for Avalanche Fuji Testnet (find the chainIdfrom the chain list) | 
| nonce | It can be generated with this JSFiddle by running the web3.utils.randomHex(32)command in the console. (the nonce has to be unique for every tx) | 
| validBefore | The time until the signed message is valid in Unix time format | 
| validAfter | The time after which the signed message will be valid in Unix time format | 
Terminologies Explained
- User Wallet: The user wallet is the wallet associated with the end-user or the person who holds the ERC20 tokens.
- Payer Wallet: The wallet that pays for the transaction fees associated with executing a smart contract or a transaction on the blockchain.
- from address: The public wallet address of the user wallet.
- to address(Wallet X): The public wallet address where the ERC20 tokens will be transferred to.
Prepare EIP712 JSON document
{
    "types": { // copy the types section as it is
        "EIP712Domain": [
            {
                "name": "name",
                "type": "string"
            },
            {
                "name": "version",
                "type": "string"
            },
            {
                "name": "chainId",
                "type": "uint256"
            },
            {
                "name": "verifyingContract",
                "type": "address"
            }
        ],
        "TransferWithAuthorization": [
            {
                "name": "from",
                "type": "address"
            },
            {
                "name": "to",
                "type": "address"
            },
            {
                "name": "value",
                "type": "uint256"
            },
            {
                "name": "validAfter",
                "type": "uint256"
            },
            {
                "name": "validBefore",
                "type": "uint256"
            },
            {
                "name": "nonce",
                "type": "bytes32"
            }
        ]
    },
    "primaryType": "TransferWithAuthorization", // this will be TransferWithAuthorization
    "domain": {
        "name": "Zap", // name of the ERC20 token contract
        "version": "1", // hardcoded to 1
        "chainId": "43113", // the chainId
        "verifyingContract": "0x8c2e84c37fa226fdaa13999a725a638dbf2bc6a0" // the ERC20 token contract address
    },
    "message": {
        "from": "0x8952fcc43F55c60C3Bf4FD565ABdd066CC1aD60c", // from wallet address
        "to": "0xe56a14Cc9DbbA42D1DE1314051CA00AA742BaEfa", // to wallet address
        "value": "1000000000000000000", // value being transferred
        "validAfter": "0", // time after which the signed message will be valid
        "validBefore": "1726207709", // time until the signed message will be valid
        "nonce": "0x0d42cac740099322f948214abb0b6b9aff59ed712ed7d85d6922ee5da0b43a2e" // random byte32 nonce
    }
}
Sign the EIP712 JSON document
- This has to be done by the user wallet (that holds the ERC20 tokens)!
- Signing is done off chain, so no gas fee has to be paid.
Request: reference
POST /api/signatures
| Parameter | Param Type | Value | Description | Example Value | 
|---|---|---|---|---|
| Signing-Method | Header | id:value | id: This is the ID of the signing methodvalue: This is the value of the signing method | 756ae7a7-3713-43ee-9936-0dff50306488:123456 | 
{
    "signatureRequest": {
        "secretType": "AVAC", // blockhain of the tx
        "walletId": "e57350bd-5273-4905-9152-b848df0057b4", // the wallet ID that will sign the message (user wallet)
        "type": "EIP712", // the message type
        "data": {
            "types": {
                "EIP712Domain": [
                    {
                        "name": "name",
                        "type": "string"
                    },
                    {
                        "name": "version",
                        "type": "string"
                    },
                    {
                        "name": "chainId",
                        "type": "uint256"
                    },
                    {
                        "name": "verifyingContract",
                        "type": "address"
                    }
                ],
                "TransferWithAuthorization": [
                    {
                        "name": "from",
                        "type": "address"
                    },
                    {
                        "name": "to",
                        "type": "address"
                    },
                    {
                        "name": "value",
                        "type": "uint256"
                    },
                    {
                        "name": "validAfter",
                        "type": "uint256"
                    },
                    {
                        "name": "validBefore",
                        "type": "uint256"
                    },
                    {
                        "name": "nonce",
                        "type": "bytes32"
                    }
                ]
            },
            "primaryType": "TransferWithAuthorization", // this will be TransferWithAuthorization
            "domain": {
                "name": "Zap", // name of the token contract
                "version": "1", // hardcoded to 1
                "chainId": "43113", // the chainId
                "verifyingContract": "0x8c2e84c37fa226fdaa13999a725a638dbf2bc6a0" // the ERC20 token contract address
            },
            "message": {
                "from": "0x8952fcc43F55c60C3Bf4FD565ABdd066CC1aD60c", // from wallet address
                "to": "0xe56a14Cc9DbbA42D1DE1314051CA00AA742BaEfa", // to wallet address
                "value": "1000000000000000000", // value being transferred
                "validAfter": "0", // time after which the signed message will be valid
                "validBefore": "1726207709", // time until the signed message will be valid
                "nonce": "0x0d42cac740099322f948214abb0b6b9aff59ed712ed7d85d6922ee5da0b43a2e" // random byte32 nonce
            }
        }
    }
}
Response body
The
r,s, andvvalues are to be provided to the payer wallet who will execute the transaction and pay the gas fee.
{
    "success": true,
    "result": {
        "type": "HEX_SIGNATURE",
        "r": "0x270e08bda85dd5d78106c018753938bb4cc32a428e55446d08cdc486d3b05324",
        "s": "0x0f7d77217aaef9ea3cc4c2dda6e134cc5c7b556114e35ee2d55f15ad0291f271",
        "v": "0x1b",
        "signature": "0x270e08bda85dd5d78106c018753938bb4cc32a428e55446d08cdc486d3b053240f7d77217aaef9ea3cc4c2dda6e134cc5c7b556114e35ee2d55f15ad0291f2711b"
    }
}
Executing the transaction
This has to be done by the payer wallet (who will be paying for the gas fee)!
Request: reference
POST /api/transactions/execute
| Parameter | Param Type | Value | Description | Example Value | 
|---|---|---|---|---|
| Signing-Method | Header | id:value | id: This is the ID of the signing methodvalue: This is the value of the signing method | 756ae7a7-3713-43ee-9936-0dff50306488:123456 | 
{
    "transactionRequest": {
        "type": "CONTRACT_EXECUTION",
        "functionName": "transferWithAuthorization", // the function name to call
        "value": 0.0, // this value will be 0.0
        "inputs": [
            {
                "type": "address", // the from wallet address
                "value": "0x8952fcc43F55c60C3Bf4FD565ABdd066CC1aD60c"
            },
            {
                "type": "address", // the to wallet address
                "value": "0xe56a14Cc9DbbA42D1DE1314051CA00AA742BaEfa"
            },
            {
                "type": "uint256", // the amount being transferred
                "value": "1000000000000000000"
            },
            {
                "type": "uint256", // validAfter from the EIP172.message
                "value": "0"
            },
            {
                "type": "uint256", // validBefore from the EIP172.message
                "value": "1726207709"
            },
            {
                "type": "bytes32", // random byte32 nonce from EIP712.message
                "value": "0x0d42cac740099322f948214abb0b6b9aff59ed712ed7d85d6922ee5da0b43a2e"
            },
            {
                "type": "uint8", // v value from the sign eip712 message response
                "value": "0x1b"
            },
            {
                "type": "bytes32", // r value from the sign eip712 message response
                "value": "0x270e08bda85dd5d78106c018753938bb4cc32a428e55446d08cdc486d3b05324"
            },
            {
                "type": "bytes32", // s value from the sign eip712 message response
                "value": "0x0f7d77217aaef9ea3cc4c2dda6e134cc5c7b556114e35ee2d55f15ad0291f271"
            }
        ],
        "walletId": "d1c28a8d-c2a3-443a-a4f8-f826f147cc91", // the wallet ID of the PAYER WALLET (who will pay the gas fee)
        "to": "0x8c2e84c37fa226fdaa13999a725a638dbf2bc6a0", // the token contract address for which we want to do a transfer
        "secretType": "AVAC" // blockchain of the tx
    }
}
Response body
{
    "success": true,
    "result": {
        "id": "2e1de5d9-cfba-47b9-b41c-5d722a9b3a9f",
        "transactionHash": "0x05f18312e116fcbc6292c981e9a169b389ceb531153fce91fa9f47f929912c9e"
    }
}
Result: Successful Gasless Transaction for ERC20 token

Successful Gasless Transaction for ERC20
Updated about 1 year ago
