Skip to main content
This guide shows an example of how to grant a USDC token allowance to the Permit2 contract using a Circle Wallets developer-controlled wallet. The Permit2 documentation provides additional examples of how to grant this allowance. When using the StableFX API to deliver the funds onchain for an FX trade, you must grant an allowance to the Permit2 contract for the token you are funding. This allows the Permit2 contract to transfer the token from your wallet to the FxEscrow contract.

Prerequisites

Before you begin, ensure you have:

Set up your project

  1. Initialize a new Node.js project and install dependencies:
    npm init -y
    npm pkg set type=module
    npm install viem dotenv
    
  2. In the project root, create a .env file and add the following variables:
    USDC_CONTRACT_ADDRESS=<USDC_CONTRACT_ADDRESS>
    PERMIT2_CONTRACT_ADDRESS=<PERMIT2_CONTRACT_ADDRESS>
    APPROVAL_AMOUNT=<APPROVAL_AMOUNT>
    WALLET_ADDRESS=<WALLET_ADDRESS>
    
    The PERMIT2_CONTRACT_ADDRESS is the same across all EVM blockchains (0x000000000022D473030F116dDEE9F6B43aC78BA3), but you should verify it with the blockchain explorer on the chain you are using. You can find the USDC_CONTRACT_ADDRESS on the USDC contract address page.
    The USDC token has 6 decimals. To approve $100 USDC, set APPROVAL_AMOUNT to 100000000 (100 * 106).
    If you are following the Circle Wallets example, you will also need to add the following variables:
    CIRCLE_WALLET_ID=<CIRCLE_WALLET_ID>
    CIRCLE_WALLETS_API_KEY=<CIRCLE_WALLETS_API_KEY>
    ENTITY_SECRET=<ENTITY_SECRET>
    
    If you are not funding USDC, you need to grant allowance using the contract address of the token you are funding.
  3. Create an index.js file. You’ll add code step by step in the following sections.

Grant a USDC token allowance to the Permit2 contract

Add the following code to your index.js file to grant a USDC token allowance to the Permit2 contract using a Circle Wallets developer-controlled wallet on supported EVM blockchains.
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";
import { randomUUID } from "crypto";
import dotenv from "dotenv";

dotenv.config();

/**
 * Approves a specified amount of USDC for the Permit2 contract using
 * a developer-controlled wallet managed by Circle.
 *
 * This function sends an on-chain transaction to call the ERC-20 `approve`
 * method on the USDC contract, allowing the Permit2 contract to spend
 * the specified amount on behalf of the wallet.
 *
 * @async
 * @function approveUSDCWithCircleWallets
 * @returns {Promise<object>} The transaction response data returned by Circle's API.
 */
export async function approveUSDCWithCircleWallets() {
  const client = initiateDeveloperControlledWalletsClient({
    apiKey: process.env.CIRCLE_WALLETS_API_KEY,
    entitySecret: process.env.ENTITY_SECRET,
  });

  const response = await client.createContractExecutionTransaction({
    walletId: process.env.CIRCLE_WALLET_ID,
    contractAddress: process.env.USDC_CONTRACT_ADDRESS,
    abiFunctionSignature: "approve(address,uint256)",
    abiParameters: [
      process.env.PERMIT2_CONTRACT_ADDRESS,
      process.env.APPROVAL_AMOUNT,
    ],
    idempotencyKey: randomUUID(),
    fee: { type: "level", config: { feeLevel: "MEDIUM" } },
  });

  return response.data;
}

/* -------- Example usage with Circle ---------

// For auth and wallet creation, see: https://developers.circle.com/interactive-quickstarts/dev-controlled-wallets
const response = await approveUSDCWithCircleWallets();
console.log('Response:', response);

---------------------------------- */