Skip to content

experimental_grantPermissions

Grants permissions for an Application to perform actions on behalf of the account.

Applications MUST provide at least one spend permission and one scoped call permission.

Request

type Request = {
  method: 'experimental_grantPermissions',
  params: [{
    /** 
     * Address of the account to grant permissions on. 
     * Defaults to the current account. 
     */
    address?: `0x${string}`
 
    /** Chain ID to grant permissions on. */
    chainId?: `0x${string}`
 
    /** Expiry of the permissions. */
    expiry: number
 
    /** Key to grant permissions to. Defaults to a wallet-managed key. */
    key?: {
      /** 
       * Public key. 
       * Accepts an address for `contract` & `secp256k1` types. 
       */
      publicKey?: `0x${string}`,
      /** Key type. */
      type?: 'contract' | 'p256' | 'secp256k1' | 'webauthn-p256', 
    }
    
    /** Permissions to grant. */
    permissions: {
      /** Call permissions. */
      calls: {
        /** Function signature or 4-byte signature. */
        signature?: string
        /** Authorized target address. */
        to?: `0x${string}`
      }[],
 
      /** Spend permissions. */
      spend: {
        /** Spending limit (in wei) per period. */
        limit: `0x${string}`,
        /** Period of the spend limit. */
        period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
        /** 
         * ERC20 token to set the limit on. 
         * If not provided, the limit will be set on the 
         * native token (e.g. ETH).
         */
        token?: `0x${string}`
      }[],
 
      /** ERC-1271 verification permissions. */
      signatureVerification?: {
        /** 
         * Authorized contract addresses that can call the account's
         * ERC-1271 `isValidSignature` function. 
         */
        addresses: readonly `0x${string}`[]
      },
    },
  }]
}

Response

type Response = {
  address: `0x${string}`,
  chainId: `0x${string}`,
  expiry: number,
  id: `0x${string}`,
  key: {
    publicKey: `0x${string}`,
    type: 'contract' | 'p256' | 'secp256k1' | 'webauthn-p256',
  },
  permissions: {
    calls: {
      signature?: string,
      to?: `0x${string}`,
    }[],
    spend: {
      limit: `0x${string}`,
      period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year',
      token?: `0x${string}`,
    }[],
    signatureVerification?: {
      addresses: `0x${string}`[]
    },
  },
}

Example

The example below demonstrates granting permissions for an Application to perform transfer calls on the EXP ERC20 contract, with a spending limit of up to 50 EXP per day.

import { Porto } from 'porto'
import { parseEther, toHex } from 'viem'
const { provider } = Porto.create()
 
const token = '0x706aa5c8e5cc2c67da21ee220718f6f6b154e75c'
 
const permissions = await provider.request({
  method: 'experimental_grantPermissions',
  params: [{
    expiry: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60, // 1 week
    permissions: {
      calls: [{ 
        signature: 'transfer(address,uint256)',
        to: token
      }],
      spend: [{
        limit: toHex(parseEther('50')), // 50 EXP
        period: 'day',
        token: token,
      }]
    },
  }],
})

App-managed Keys

Applications can also grant permissions to a specific signing key by providing the key parameter.

This is useful for when the Application wants to perform signing themself, instead of the Wallet.

import { Porto } from 'porto'
import { parseEther, toHex } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
 
const { provider } = Porto.create()
 
const account = privateKeyToAccount('0x...') 
const token = '0x706aa5c8e5cc2c67da21ee220718f6f6b154e75c'
 
const permissions = await provider.request({
  method: 'experimental_grantPermissions',
  params: [{
    expiry: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60, // 1 week
    key: { 
      publicKey: account.address, 
      type: 'secp256k1', 
    }, 
    permissions: {
      calls: [{ 
        signature: 'transfer(address,uint256)',
        to: token
      }],
      spend: [{
        limit: toHex(parseEther('50')), // 50 EXP
        period: 'day',
        token: token,
      }]
    },
  }],
})