ERC-2612
ERC2612¶
ERC2612 is an extension standard for enhancing ERC20 token functionality. Specifically, ERC2612 introduces signed authorization (permit) functionality for ERC20 tokens, enabling users to authorize token transfers through signatures without needing to pay Ethereum transaction fees.
Off-chain signature authorization not only simplifies the user experience but also reduces the number of on-chain transactions, thereby lowering transaction costs.
ERC2612 Interface¶
pragma solidity ^0.8.0;
interface IERC2612 {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
Methods¶
- permit: Authorizes
spenderto spendvaluetokens fromowner's token account via signature. - nonces: Returns the nonce value for a specific address, used to prevent replay attacks.
- DOMAIN_SEPARATOR: Returns the EIP-712 domain separator used for signing messages.
ERC2612 Contract Example¶
Below is an example contract implementing ERC2612:
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
contract UpChainToken is ERC20, ERC20Permit {
constructor() ERC20("UpChainToken", "MTK") ERC20Permit("UpChainToken") {
_mint(msg.sender, 1000000 * 10 ** decimals());
}
}
In this example, we inherit the ERC20 and ERC20Permit contracts from the OpenZeppelin library to implement ERC2612 functionality.
Usage Example¶
Assuming we have deployed the above UpChainToken contract, below demonstrates how to interact with the contract via ethers.js (v5) to implement the permit functionality:
Generating a Signature¶
First, generate an offline signature:
const { ethers } = require("ethers");
const provider = new ethers.providers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID");
const wallet = new ethers.Wallet("YOUR_PRIVATE_KEY", provider);
const contractAddress = "0xYourContractAddress";
const contractABI = [
"function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external",
"function nonces(address owner) external view returns (uint256)",
"function DOMAIN_SEPARATOR() external view returns (bytes32)"
];
const contract = new ethers.Contract(contractAddress, contractABI, wallet);
async function createPermitSignature(owner, spender, value, deadline) {
const nonce = await contract.nonces(owner);
const domainSeparator = await contract.DOMAIN_SEPARATOR();
const permitData = {
owner: owner,
spender: spender,
value: value,
nonce: nonce,
deadline: deadline
};
const types = {
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
const signature = await wallet._signTypedData(
{ name: "UpChainToken", version: "1", chainId: 1, verifyingContract: contractAddress },
types,
permitData
);
return ethers.utils.splitSignature(signature);
}
Executing the permit Method¶
Use the generated signature to call the permit method on-chain:
async function permit(owner, spender, value, deadline, v, r, s) {
const tx = await contract.permit(owner, spender, value, deadline, v, r, s);
await tx.wait();
console.log("Permit transaction submitted: ", tx.hash);
}
const owner = wallet.address;
const spender = "0xSpenderAddress";
const value = ethers.utils.parseUnits("100", 18);
const deadline = Math.floor(Date.now() / 1000) + 60 * 60; // 1 hour from now
const { v, r, s } = await createPermitSignature(owner, spender, value, deadline);
await permit(owner, spender, value, deadline, v, r, s);
Summary¶
The ERC2612 standard, by introducing the permit method, enhances ERC20 token functionality, enabling users to perform authorization operations through offline signatures, thereby simplifying the user experience and reducing the number of on-chain transactions. The above contract example demonstrates how to implement and use ERC2612 functionality.