Skip to content

Capabilities

Porto supports EIP-5792 Capabilities. Capabilites are extension features that allow for extra functionality to be requested on particular JSON-RPC requests such as wallet_connect and wallet_sendCalls, and also enable additional JSON-RPC methods. Such features could be requesting to grant permissions on connection, or setting a custom fee token.

Porto supports the following capabilities:

CapabilityDescriptionStandard
feeTokenIndicates if custom fee tokens are supported.Experimental
merchantIndicates if merchant functionality is supported.Experimental
permissionsIndicates if permissions can be requested by the app.Experimental
signInWithEthereumAdds support for ERC-4361 Sign in with Ethereum.Experimental

Fee Tokens

Porto allows for an application developer to use custom fee (gas) tokens to pay for the execution of a call bundle.

Custom fee tokens are indicated by the feeToken capability on wallet_getCapabilities

Discovery

Tokens can be discovered by the application via feeToken.tokens on the wallet_getCapabilities method.

import { Porto } from 'porto'
 
const { provider } = Porto.create()
 
const capabilities = await provider.request({ 
  method: 'wallet_getCapabilities', 
}) 
 
const tokens = Object.values(capabilities)[0].feeToken.tokens 

Request Capabilities

feeToken

Custom fee token to use for the request.

The following JSON-RPC methods support the feeToken request capability:

type Capability = {
  /** Custom fee token address. */
  feeToken: `0x${string}`
}
Example
const capabilities = await provider.request({
  method: 'wallet_sendCalls',
  params: [{
    capabilities: { 
      feeToken: '0x036cbd53842c5426634e7929541ec2318f3dcf7e', // USDC 
    }, 
    /* ... */
  }]
})

permissions

Porto supports account permission management.

Methods

The permissions capability enables the following methods:

Request Capabilities

grantPermissions

Requests for the wallet to grant permissions.

The following JSON-RPC methods support the grantPermissions request capability:

type Capability = {
  /** Requests for the wallet to grant these permissions. */
  grantPermissions: {
    /** Expiry of the permissions. */
    expiry: number
 
    /** 
     * Limit that the key can spend on fees. When provided,
     * Porto will assign a spend permission on the user's
     * selected fee token that is equal to the limit provided.
     */
    feeLimit?: {
      /** Currency of the limit. */
      currency: 'ETH' | 'USD' | 'USDC' | 'USDT'
      /** Value of the limit in the currency's unit (e.g. '1' = 1 USDC). */
      value: string
    } | undefined,
 
    /**
     * Key to grant permissions to.
     * Defaults to a wallet-managed key.
     */
    key?: {
      /**
       * Public key.
       * Accepts an address for `address` & `secp256k1` types.
       */
      publicKey?: `0x${string}`,
      /** Key type. */
      type?: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256',
    }
 
    /** Permissions. */
    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}`
      }[],
    }
  },
}
Example
const capabilities = await provider.request({
  method: 'wallet_connect',
  params: [{
    capabilities: { 
      grantPermissions: { 
        expiry: 1727078400, 
        feeLimit: { 
          currency: 'USD', 
          value: '1', 
        }, 
        permissions: { 
          calls: [{ signature: 'subscribe()' }], 
          spend: [{ 
            limit: '0x5f5e100', // 100 USDC 
            period: 'day', 
            token: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC 
          }] 
        } 
      }, 
    }, 
    /* ... */
  }]
})

permissions

Use a provided permission for the request.

The following JSON-RPC methods support the permissions request capability:

type Capability = {
  /** Permission to use for the request. */
  permissions: {
    /** ID of the permission to use. */
    id: `0x${string}`
  }
}
Example
const capabilities = await provider.request({
  method: 'wallet_sendCalls',
  params: [{
    capabilities: { 
      permissions: { 
        id: '0x...', 
      }, 
    }, 
    /* ... */
  }]
})

Response Capabilities

permissions

Returns the permissions granted on the request.

The following JSON-RPC methods support the permissions response capability:

type Capability = {
  permissions: {
    expiry: number,
    id: `0x${string}`,
    key: {
      publicKey: `0x${string}`,
      type: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256',
    },
    permissions: {
      calls: {
        signature?: string
        to?: `0x${string}`
      }[],
      spend: {
        limit: bigint
        period: 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
        token?: `0x${string}`
      }[]
    }
    publicKey: `0x${string}`,
    type: 'address' | 'p256' | 'secp256k1' | 'webauthn-p256'
  }[]
}
Example
const capabilities = await provider.request({
  method: 'wallet_connect',
  params: [{
    capabilities: {
      grantPermissions: { /* ... */ },
    },
    /* ... */
  }]
})
[{
address: '0x1234567890123456789012345678901234567890',
capabilities: {
permissions: [{
expiry: 1727078400,
id: '0x...',
key: {
publicKey: '0x...',
type: 'p256'
},
permissions: {
calls: [{
signature: 'subscribe()',
}],
spend: [{
limit: '0x5f5e100', // 100 USDC
period: 'day',
token: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
}]
}
}]
},
}]

merchant

A merchant server can be set up by the Application to sponsor actions on behalf of their users.

Request Capabilities

merchantRpcUrl

URL of the endpoint that will be used to front (and sponsor) call bundles for users.

The following JSON-RPC methods support the merchantRpcUrl request capability:

type Capability = {
  merchantRpcUrl: string
}

Example

const capabilities = await provider.request({
  method: 'wallet_sendCalls',
  params: [{
    capabilities: {
      merchantRpcUrl: 'https://myapp.com/rpc'
    },
    /* ... */
  }]
})

signInWithEthereum

Adds support for ERC-4361 Sign-In with Ethereum.

Request Capabilities

signInWithEthereum

ERC-4361 Sign-In with Ethereum options.

The following JSON-RPC methods support the signInWithEthereum request capability:

type Capability = {
  signInWithEthereum: {
    /* Required fields */
    authUrl: string | {
      logout: string
      nonce: string
      verify: string
    }
    // OR
    nonce: string
    
    /* Optional fields */
    chainId?: number | undefined
    domain?: string | undefined // Defaults to window/iframe parent
    expirationTime?: Date | undefined
    issuedAt?: Date | undefined
    notBefore?: Date | undefined
    requestId?: string | undefined
    resources?: string[] | undefined
    scheme?: string | undefined
    statement?: string | undefined
    uri?: string | undefined // Defaults to window/iframe parent
    version?: '1' | undefined
  }
}

Example

const capabilities = await provider.request({
  method: 'wallet_connect',
  params: [{
    capabilities: {
      signInWithEthereum: {
        nonce: await fetch("/api/nonce"),
      }
    },
    /* ... */
  }]
})

Response Capabilities

signInWithEthereum

The following JSON-RPC methods support the signInWithEthereum request capability:

type Capability = {
  message: string
  signature: `0x${string}`
}

Example

const capabilities = await provider.request({
  method: 'wallet_connect',
  params: [{
    capabilities: {
      signInWithEthereum: {
        nonce: await fetch("/api/nonce"),
      }
    },
    /* ... */
  }]
})