UNPKG

viem

Version:

TypeScript Interface for Ethereum

193 lines (179 loc) • 5.55 kB
import type { Address } from 'abitype' import type { Client } from '../../../clients/createClient.js' import type { Transport } from '../../../clients/transports/createTransport.js' import type { Account } from '../../../types/account.js' import type { WalletGrantPermissionsReturnType } from '../../../types/eip1193.js' import type { Hex } from '../../../types/misc.js' import type { OneOf } from '../../../types/utils.js' import { numberToHex, parseAccount } from '../../../utils/index.js' import type { Permission } from '../types/permission.js' import type { Signer } from '../types/signer.js' export type GrantPermissionsParameters = { /** Timestamp (in seconds) that specifies the time by which this session MUST expire. */ expiry: number /** Set of permissions to grant to the user. */ permissions: readonly Permission[] } & OneOf< | { /** Signer to assign the permissions to. */ signer?: Signer | undefined } | { /** Account to assign the permissions to. */ account?: Address | Account | undefined } > export type GrantPermissionsReturnType = { /** Timestamp (in seconds) that specifies the time by which this session MUST expire. */ expiry: number /** ERC-4337 Factory to deploy smart contract account. */ factory?: Hex | undefined /** Calldata to use when calling the ERC-4337 Factory. */ factoryData?: string | undefined /** Set of granted permissions. */ grantedPermissions: readonly Permission[] /** Permissions identifier. */ permissionsContext: string /** Signer attached to the permissions. */ signerData?: | { userOpBuilder?: Hex | undefined submitToAddress?: Hex | undefined } | undefined } /** * Request permissions from a wallet to perform actions on behalf of a user. * * - Docs: https://viem.sh/experimental/erc7715/grantPermissions * * @example * import { createWalletClient, custom } from 'viem' * import { mainnet } from 'viem/chains' * import { grantPermissions } from 'viem/experimental' * * const client = createWalletClient({ * chain: mainnet, * transport: custom(window.ethereum), * }) * * const result = await grantPermissions(client, { * expiry: 1716846083638, * permissions: [ * { * type: 'native-token-transfer', * data: { * ticker: 'ETH', * }, * policies: [ * { * type: 'token-allowance', * data: { * allowance: parseEther('1'), * }, * } * ], * required: true, * }, * ], * }) */ export async function grantPermissions( client: Client<Transport>, parameters: GrantPermissionsParameters, ): Promise<GrantPermissionsReturnType> { const { account, expiry, permissions, signer } = parameters const result = await client.request( { method: 'wallet_grantPermissions', params: [ formatParameters({ account, expiry, permissions, signer } as any), ], }, { retryCount: 0 }, ) return formatRequest(result) as GrantPermissionsReturnType } function formatParameters(parameters: GrantPermissionsParameters) { const { expiry, permissions, signer: signer_ } = parameters const account = parameters.account ? parseAccount(parameters.account) : undefined const signer = (() => { if (!account && !signer_) return undefined // JSON-RPC Account as signer. if (account?.type === 'json-rpc') return { type: 'wallet', } // Local Account as signer. if (account?.type === 'local') return { type: 'account', data: { id: account.address, }, } // ERC-7715 Signer as signer. return signer_ })() return { expiry, permissions: permissions.map((permission) => ({ ...permission, policies: permission.policies.map((policy) => { const data = (() => { if (policy.type === 'token-allowance') return { allowance: numberToHex(policy.data.allowance), } if (policy.type === 'gas-limit') return { limit: numberToHex(policy.data.limit), } return policy.data })() return { data, type: typeof policy.type === 'string' ? policy.type : policy.type.custom, } }), required: permission.required ?? false, type: typeof permission.type === 'string' ? permission.type : permission.type.custom, })), ...(signer ? { signer } : {}), } } function formatRequest(result: WalletGrantPermissionsReturnType) { return { expiry: result.expiry, ...(result.factory ? { factory: result.factory } : {}), ...(result.factoryData ? { factoryData: result.factoryData } : {}), grantedPermissions: result.grantedPermissions.map((permission) => ({ ...permission, policies: permission.policies.map((policy) => { const data = (() => { if (policy.type === 'token-allowance') return { allowance: BigInt((policy.data as any).allowance), } if (policy.type === 'gas-limit') return { limit: BigInt((policy.data as any).limit), } return policy.data })() return { data, type: policy.type, } }), })), permissionsContext: result.permissionsContext, ...(result.signerData ? { signerData: result.signerData } : {}), } }