Permit2

Here’s the guideline of using Permit2 in OpenOcean Swap API

About Permit2

OpenOcean Swap API supports Uniswap’s Permit2 SignatureTransfer contract, which standardizes token approvals across applications and improves both UX and security. Permit2 is a universal token approval contract from Uniswap. Instead of requiring users to first send an approve transaction and then a swap, Permit2 allows approvals to be handled through a single EIP-712 signature. This removes the “double transaction” flow and gives developers more control over allowance scope (amounts, deadlines, nonces). For simpler integration, you may also consider using AllowanceHolder contract, which requires a one-time approval without additional signatures.

Using Permit2 with OpenOcean Swap API

To integrate Permit2 (SignatureTransfer) into your swap flow, follow these steps:

  1. Check the current allowance

  2. (Optional) Approve Permit2 if needed

  3. Generate the Permit2 signature and data

  4. Build the transaction body

  5. Send the transaction with the Permit2 signature

1. Check the current allowance for permit2

Verify whether the target token has granted Permit2 sufficient spending allowance.

import { ethers } from 'ethers';

async function allowance() {
    const rpcUrl = 'https://base.llamarpc.com';
    const token = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
    const account = "";
    const permit2Address = "0x000000000022D473030F116dDEE9F6B43aC78BA3";

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    const contract = new ethers.Contract(token, ERC20_ABI, provider);
    const allowance = await contract.allowance(account, permit2Address);
    console.log(`allowance: ${allowance.toString()}`)
}

2. Approve Permit2 if needed (Optional)

If the allowance is insufficient, call the token’s approve() method once to authorize Permit2 with the required amount.

import { ethers, Contract } from 'ethers';
async function approve() {
    const rpcUrl = 'https://base.llamarpc.com';
    const inTokenAddress = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913';
    const privateKey = '';
    const permit2Address = '0x000000000022D473030F116dDEE9F6B43aC78BA3';
    let provider = new ethers.JsonRpcProvider(rpcUrl);
    const wallet = new ethers.Wallet(privateKey, provider);
    const contract = await new Contract(inTokenAddress, ERC20_ABI, wallet); 
    
    try {
      await contract.approve(permit2Address, new BigNumber('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff').toFixed(0, 1));
    } catch (error) {
        return error;
    }
    return true;
}

3. Generate the Permit2 signature and data

Create the authorization signature and encoded data using the Permit2 standard for later use in the transaction.

import { PERMIT2_ADDRESS, PermitTransferFrom, SignatureTransfer } from '@uniswap/permit2-sdk';
import { ethers } from 'ethers';

async function signAndBuildData() {
  const privateKey = "";
  const token = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // in token address
  const amount = "1000000000"; // in amount
  const spender = "0x6352a56caadC4F1E25CD6c75970Fa768A3304e64"; // openocean contract
  const nonce = 0;
  const chainId = 8453;
  const deadline = 1761877730;

  const wallet = new ethers.Wallet(privateKey);
  const permit: PermitTransferFrom = { permitted: { token, amount }, spender, nonce, deadline };
  const { domain, types, values } = SignatureTransfer.getPermitData(permit, PERMIT2_ADDRESS, chainId, undefined);
  const signature = await wallet._signTypedData(domain, types, values);
  console.log(`signature: ${signature}`)

  const iface = new ethers.utils.Interface(PERMIT2_ABI);
  const permitTransferFromData = [[[token, amount], nonce, deadline], [spender, amount], wallet.address, signature];
  const data = iface.encodeFunctionData('permitTransferFrom', permitTransferFromData);
  console.log(`data: ${data}`)
}

4. Build the transaction body

Use the OpenOcean Swap API response to construct the final on-chain transaction calldata.

async function swap() {
    const params = {
        inTokenAddress: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', 
        outTokenAddress: '0x4200000000000000000000000000000000000006',
        slippage: 1, // 1 means 1%
        amount: 1000, // without decimals
        gasPrice: 1, // without decimals, get from gasPrice api
        account: '0xB3cbe...', // wallet address
      	permit: '0x30f28b7a000...' // build from step 3 data
    }
    const { data } = await axios({
        url: `https://open-api.openocean.finance/v4/8453/swap`,
        method: 'GET',
        params
    })
    return data;
}

**5. Send the transaction with the Permit2 signature **

Submit the transaction on-chain, including the Permit2 signature to complete the token swap process.

async function send_transaction() {
    const rpcUrl = 'https://base.llamarpc.com';
    const privateKey = ''; // wallet privateKey
    const provider = new ethers.JsonRpcProvider(rpcUrl);
    // get from swap
    const params: any = {
        from: '', // wallet address, get from swap
        to: '', // contract address, get from swap
        gasPrice: '', // wei, get from swap
        data: '', // input data, get from swap
        value: '', // native token amount, get from swap
        gasLimit: '' // get from swap
    }
    const gasLimit = await provider.estimateGas(params);
    params.gasLimit = gasLimit;
    const wallet = new ethers.Wallet(privateKey, provider);
    const { hash } = await wallet.sendTransaction(params);
    return hash;
}

Supported Chains

Chain Name
ChainId
Permit2 Address

Ethereum

1

0x000000000022D473030F116dDEE9F6B43aC78BA3

BNB Chain

56

0x000000000022D473030F116dDEE9F6B43aC78BA3

Polygon

137

0x000000000022D473030F116dDEE9F6B43aC78BA3

Arbitrum

42161

0x000000000022D473030F116dDEE9F6B43aC78BA3

Base

8453

0x000000000022D473030F116dDEE9F6B43aC78BA3

Linea

59144

0x000000000022D473030F116dDEE9F6B43aC78BA3

Optimism

10

0x000000000022D473030F116dDEE9F6B43aC78BA3

Avalanche

43114

0x000000000022D473030F116dDEE9F6B43aC78BA3

Sei

1329

0x000000000022D473030F116dDEE9F6B43aC78BA3

zkSync

324

0x0000000000225e31D15943971F47aD3022F714Fa

Scroll

534352

0x000000000022D473030F116dDEE9F6B43aC78BA3

Celo

42220

0x000000000022D473030F116dDEE9F6B43aC78BA3

Gnosis

100

0x000000000022D473030F116dDEE9F6B43aC78BA3

Sonic

146

0x000000000022D473030F116dDEE9F6B43aC78BA3

Berachain

80094

0x000000000022D473030F116dDEE9F6B43aC78BA3

Unichain

130

0x000000000022D473030F116dDEE9F6B43aC78BA3

Swell

130

0x000000000022D473030F116dDEE9F6B43aC78BA3

HyperEVM

999

0x000000000022D473030F116dDEE9F6B43aC78BA3

Plume

98866

0x000000000022D473030F116dDEE9F6B43aC78BA3

Tac

239

0x000000000022D473030F116dDEE9F6B43aC78BA3

Plasma

9745

0x000000000022D473030F116dDEE9F6B43aC78BA3

Last updated