Skip to main content

Use ERC-20 token permissions

Advanced Permissions (ERC-7715) supports ERC-20 token permission types that allow you to request fine-grained permissions for ERC-20 token transfers with time-based (periodic), streaming, or revocation conditions, depending on your use case.

Prerequisites

ERC-20 periodic permission

This permission type ensures a per-period limit for ERC-20 token transfers. At the start of each new period, the allowance resets.

For example, a user signs an ERC-7715 permission that lets a dapp spend up to 10 USDC on their behalf each day. The dapp can transfer a total of 10 USDC per day; the limit resets at the beginning of the next day.

See the ERC-20 periodic permission API reference for more information.

import { sepolia as chain } from 'viem/chains'
import { parseUnits } from 'viem'
import { walletClient } from './client.ts'

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const grantedPermissions = await walletClient.requestExecutionPermissions([
{
chainId: chain.id,
expiry,
// The requested permissions will granted to the
// session account.
to: sessionAccount.address,
permission: {
type: 'erc20-token-periodic',
data: {
tokenAddress,
// 10 USDC in WEI format. Since USDC has 6 decimals, 10 * 10^6.
periodAmount: parseUnits('10', 6),
// 1 day in seconds.
periodDuration: 86400,
justification: 'Permission to transfer 10 USDC every day',
},
isAdjustmentAllowed: true,
},
},
])

ERC-20 stream permission

This permission type ensures a linear streaming transfer limit for ERC-20 tokens. Token transfers are blocked until the defined start timestamp. At the start, a specified initial amount is released, after which tokens accrue linearly at the configured rate, up to the maximum allowed amount.

For example, a user signs an ERC-7715 permission that allows a dapp to spend 0.1 USDC per second, starting with an initial amount of 1 USDC, up to a maximum of 2 USDC.

See the ERC-20 stream permission API reference for more information.

import { sepolia as chain } from 'viem/chains'
import { parseUnits } from 'viem'
import { walletClient } from './client.ts'

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const grantedPermissions = await walletClient.requestExecutionPermissions([
{
chainId: chain.id,
expiry,
// The requested permissions will granted to the
// session account.
to: sessionAccount.address,
permission: {
type: 'erc20-token-stream',
data: {
tokenAddress,
// 0.1 USDC in WEI format. Since USDC has 6 decimals, 0.1 * 10^6.
amountPerSecond: parseUnits('0.1', 6),
// 1 USDC in WEI format. Since USDC has 6 decimals, 1 * 10^6.
initialAmount: parseUnits('1', 6),
// 2 USDC in WEI format. Since USDC has 6 decimals, 2 * 10^6.
maxAmount: parseUnits('2', 6),
startTime: currentTime,
justification: 'Permission to use 0.1 USDC per second',
},
isAdjustmentAllowed: true,
},
},
])

ERC-20 revocation permission

This permission type enables revoking an existing ERC-20 token allowance on behalf of the user.

For example, a user signs an ERC-7715 permission that lets a dapp revoke any ERC-20 token allowances periodically, or during an ongoing exploit.

See the ERC-20 revocation permission API reference for more information.

import { sepolia as chain } from 'viem/chains'
import { walletClient } from './client.ts'

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

const grantedPermissions = await walletClient.requestExecutionPermissions([
{
chainId: chain.id,
expiry,
// The requested permissions will granted to the
// session account.
to: sessionAccount.address,
permission: {
type: 'erc20-token-revocation',
data: {
justification: 'Permission to revoke ERC-20 token allowances',
},
isAdjustmentAllowed: true,
},
},
])