DEV Community

Majid Kareem
Majid Kareem

Posted on

What is EIP2612 and How to Implement EIP2612 in NextJS?

To implement EIP-2612 in a Next.js application, you need to handle both the off-chain signature creation and the on-chain execution of the permit function followed by the transferFrom. Below is a detailed step-by-step guide on how to achieve this using ethers.js in your Next.js app.

Step 1: Set Up the Next.js Project

Ensure your Next.js project is set up. If not, you can create one using:

npx create-next-app my-eip2612-app
cd my-eip2612-app
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Required Dependencies

Install ethers.js to interact with Ethereum blockchain:

npm install ethers
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a Permit Component

Create a Next.js component that will handle both the off-chain signing of the permit and the on-chain execution of permit and transferFrom.

Component Structure

  1. Sign the Permit: This part is done off-chain by the token owner using their private key via a connected wallet like MetaMask.
  2. Execute Permit and Transfer: This is done on-chain by the spender, which involves calling the permit function followed by the transferFrom function.

PermitComponent.js

Create a file named PermitComponent.js inside your components folder:

// components/PermitComponent.js
import { ethers } from "ethers";
import { useEffect, useState } from "react";

// Replace with the ABI of your ERC20 token with permit functionality
const ERC20_ABI = [
  "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external",
  "function transferFrom(address sender, address recipient, uint256 amount) external returns (bool)",
  "function nonces(address owner) external view returns (uint256)",
  "function DOMAIN_SEPARATOR() external view returns (bytes32)"
];

export default function PermitComponent() {
  const [provider, setProvider] = useState(null);
  const [signer, setSigner] = useState(null);
  const [owner, setOwner] = useState("");
  const [spender, setSpender] = useState("");
  const [value, setValue] = useState(0);
  const [deadline, setDeadline] = useState(Math.floor(Date.now() / 1000) + 3600); // 1 hour from now
  const [tokenAddress, setTokenAddress] = useState("0xYourTokenAddressHere"); // Replace with your token address

  useEffect(() => {
    // Initialize provider and signer when the component mounts
    const initializeProvider = async () => {
      if (window.ethereum) {
        const web3Provider = new ethers.providers.Web3Provider(window.ethereum);
        await web3Provider.send("eth_requestAccounts", []); // Request access to user accounts
        setProvider(web3Provider);
        const web3Signer = web3Provider.getSigner();
        setSigner(web3Signer);
        const accounts = await web3Provider.listAccounts();
        setOwner(accounts[0]);
      } else {
        console.error("Please install MetaMask!");
      }
    };

    initializeProvider();
  }, []);

  const handlePermitAndTransfer = async () => {
    try {
      if (!provider || !signer || !tokenAddress) {
        console.error("Provider, signer, or token address not set");
        return;
      }

      const tokenContract = new ethers.Contract(tokenAddress, ERC20_ABI, signer);
      const nonce = await tokenContract.nonces(owner);
      const domainSeparator = await tokenContract.DOMAIN_SEPARATOR();

      // EIP712 Domain and Permit Type Definitions
      const domain = {
        name: "My Token", // Replace with your token's name
        version: "1",
        chainId: (await provider.getNetwork()).chainId,
        verifyingContract: tokenAddress
      };

      const types = {
        Permit: [
          { name: "owner", type: "address" },
          { name: "spender", type: "address" },
          { name: "value", type: "uint256" },
          { name: "nonce", type: "uint256" },
          { name: "deadline