Skip to content
Back to skills

Permit2 Allowance Flow

ASecurity

Complete approval flow with reset-to-zero pattern. Use when implementing full ERC20 and Permit2 approval workflow.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 10, 2026
businesstypescript

Works with

  • cli

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add cyotee/indexedex --skill permit2-allowance-flow --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Permit2 Allowance Flow?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Permit2 Allowance Flow
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/cyotee-permit2-allowance-flow/badge)](https://www.skillsdirectory.com/skills/cyotee-permit2-allowance-flow)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: permit2-allowance-flow
description: Complete approval flow with reset-to-zero pattern. Use when implementing full ERC20 and Permit2 approval workflow.
---

# Permit2 Allowance Transfer - Complete Flow

Full implementation with reset-to-zero pattern for tokens that require it.

## Constants

```typescript
const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3'

const PERMIT2_APPROVE_ABI = [
  {
    inputs: [
      { name: 'token', type: 'address' },
      { name: 'spender', type: 'address' },
      { name: 'amount', type: 'uint160' },
      { name: 'expiration', type: 'uint48' }
    ],
    name: 'approve',
    outputs: [],
    stateMutability: 'nonpayable',
    type: 'function'
  }
] as const
```

## Complete Approval Function

```typescript
async function ensureSpendingLimits(
  tokenAddress: string,
  spenderAddress: string,
  amountNeeded: bigint,
  writeContractAsync: (config: WriteContractParameters) => Promise<Hash>,
  publicClient: PublicClient,
  address: string
) {
  // Step 1: Ensure ERC20 → Permit2 allowance
  const currentErc20Allowance = await publicClient.readContract({
    address: tokenAddress,
    abi: erc20Abi,
    functionName: 'allowance',
    args: [address, PERMIT2_ADDRESS]
  })

  if (currentErc20Allowance < amountNeeded) {
    // Some tokens (like USDT) require resetting to 0 first
    try {
      const hash = await writeContractAsync({
        address: tokenAddress,
        abi: erc20Abi,
        functionName: 'approve',
        args: [PERMIT2_ADDRESS, amountNeeded]
      })
      await publicClient.waitForTransactionReceipt({ hash })
    } catch {
      // Reset to 0, then approve
      const hash0 = await writeContractAsync({
        address: tokenAddress,
        abi: erc20Abi,
        functionName: 'approve',
        args: [PERMIT2_ADDRESS, 0n]
      })
      await publicClient.waitForTransactionReceipt({ hash: hash0 })

      const hash1 = await writeContractAsync({
        address: tokenAddress,
        abi: erc20Abi,
        functionName: 'approve',
        args: [PERMIT2_ADDRESS, amountNeeded]
      })
      await publicClient.waitForTransactionReceipt({ hash: hash1 })
    }
  }

  // Step 2: Ensure Permit2 → Spender allowance
  const currentPermit2Allowance = await publicClient.readContract({
    address: PERMIT2_ADDRESS,
    abi: [{
      inputs: [
        { name: 'owner', type: 'address' },
        { name: 'token', type: 'address' },
        { name: 'spender', type: 'address' }
      ],
      name: 'allowance',
      outputs: [
        { name: 'amount', type: 'uint160' },
        { name: 'expiration', type: 'uint48' },
        { name: 'nonce', type: 'uint48' }
      ],
      stateMutability: 'view',
      type: 'function'
    }],
    functionName: 'allowance',
    args: [address, tokenAddress, spenderAddress]
  })

  if (currentPermit2Allowance[0] < amountNeeded) {
    const threeDaysSecs = 3n * 24n * 60n * 60n
    const expiration = BigInt(Math.floor(Date.now() / 1000)) + threeDaysSecs

    const hash = await writeContractAsync({
      address: PERMIT2_ADDRESS,
      abi: PERMIT2_APPROVE_ABI,
      functionName: 'approve',
      args: [tokenAddress, spenderAddress, amountNeeded, expiration]
    })
    await publicClient.waitForTransactionReceipt({ hash })
  }
}
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.