UNPKG

@coinbase/cdp-sdk

Version:

SDK for interacting with the Coinbase Developer Platform Wallet API

362 lines (328 loc) 12.7 kB
import { Analytics } from "../../analytics.js"; import type { EndUserAccount, AddEndUserEvmAccountResult, AddEndUserEvmSmartAccountResult, AddEndUserSolanaAccountResult, AddEvmSmartAccountOptions, GetDelegationForEndUserResult, GetDelegationForEndUserAccountResult, AccountGetDelegationForAccountOptions, AccountRevokeDelegationForAccountOptions, SignEvmTransactionResult, SignEvmMessageResult, SignEvmTypedDataResult, SendEvmTransactionResult, SendEvmAssetResult, SendUserOperationResult, CreateEvmEip7702DelegationForEndUserResult, SignSolanaMessageResult, SignSolanaTransactionResult, SendSolanaTransactionResult, SendSolanaAssetResult, AccountSignEvmTransactionOptions, AccountSignEvmMessageOptions, AccountSignEvmTypedDataOptions, AccountSendEvmTransactionOptions, AccountSendEvmAssetOptions, AccountSendUserOperationOptions, AccountCreateEvmEip7702DelegationOptions, AccountSignSolanaMessageOptions, AccountSignSolanaTransactionOptions, AccountSendSolanaTransactionOptions, AccountSendSolanaAssetOptions, } from "./endUser.types.js"; import type { CdpOpenApiClientType, EndUser as OpenAPIEndUser, } from "../../openapi-client/index.js"; /** * Options for converting an OpenAPI EndUser to an EndUserAccount with actions. */ export type ToEndUserAccountOptions = { /** The end user from the API response. */ endUser: OpenAPIEndUser; }; /** * Resolves the first EVM EOA address for this end user, or throws if none exist and no override was provided. * * @param endUser - The OpenAPI end user. * @param override - An optional address override. * @returns The resolved EVM address. */ function resolveEvmAddress(endUser: OpenAPIEndUser, override?: string): string { const address = override ?? endUser.evmAccountObjects[0]?.address; if (!address) { throw new Error( "No EVM account found on this end user. Provide an explicit address or add an EVM account first.", ); } return address; } /** * Resolves the first EVM smart account address for this end user, or throws if none exist and no override was provided. * * @param endUser - The OpenAPI end user. * @param override - An optional address override. * @returns The resolved EVM smart account address. */ function resolveEvmSmartAccountAddress(endUser: OpenAPIEndUser, override?: string): string { const address = override ?? endUser.evmSmartAccountObjects[0]?.address; if (!address) { throw new Error( "No EVM smart account found on this end user. Provide an explicit address or add an EVM smart account first.", ); } return address; } /** * Resolves the first Solana address for this end user, or throws if none exist and no override was provided. * * @param endUser - The OpenAPI end user. * @param override - An optional address override. * @returns The resolved Solana address. */ function resolveSolanaAddress(endUser: OpenAPIEndUser, override?: string): string { const address = override ?? endUser.solanaAccountObjects[0]?.address; if (!address) { throw new Error( "No Solana account found on this end user. Provide an explicit address or add a Solana account first.", ); } return address; } /** * Creates an EndUserAccount instance with actions from an existing OpenAPI EndUser. * This wraps the raw API response and adds convenience methods for adding accounts * and performing delegated signing/sending operations. * * @param apiClient - The API client. * @param options - Configuration options. * @param options.endUser - The end user from the API response. * @returns An EndUserAccount instance with action methods. */ export function toEndUserAccount( apiClient: CdpOpenApiClientType, options: ToEndUserAccountOptions, ): EndUserAccount { const { endUser } = options; const endUserAccount: EndUserAccount = { // Pass through all properties from the OpenAPI EndUser userId: endUser.userId, authenticationMethods: endUser.authenticationMethods, mfaMethods: endUser.mfaMethods, evmAccounts: endUser.evmAccounts, evmAccountObjects: endUser.evmAccountObjects, evmSmartAccounts: endUser.evmSmartAccounts, evmSmartAccountObjects: endUser.evmSmartAccountObjects, solanaAccounts: endUser.solanaAccounts, solanaAccountObjects: endUser.solanaAccountObjects, createdAt: endUser.createdAt, // ─── Account Management Methods ─── async addEvmAccount(idempotencyKey?: string): Promise<AddEndUserEvmAccountResult> { Analytics.trackAction({ action: "end_user_add_evm_account" }); return apiClient.addEndUserEvmAccount(endUser.userId, {}, idempotencyKey); }, async addEvmSmartAccount( smartAccountOptions: AddEvmSmartAccountOptions, ): Promise<AddEndUserEvmSmartAccountResult> { Analytics.trackAction({ action: "end_user_add_evm_smart_account" }); return apiClient.addEndUserEvmSmartAccount( endUser.userId, { enableSpendPermissions: smartAccountOptions.enableSpendPermissions }, smartAccountOptions.idempotencyKey, ); }, async addSolanaAccount(idempotencyKey?: string): Promise<AddEndUserSolanaAccountResult> { Analytics.trackAction({ action: "end_user_add_solana_account" }); return apiClient.addEndUserSolanaAccount(endUser.userId, {}, idempotencyKey); }, async getDelegation(): Promise<GetDelegationForEndUserResult> { Analytics.trackAction({ action: "end_user_get_delegation" }); return apiClient.getDelegationForEndUser(endUser.userId); }, async revokeDelegation(idempotencyKey?: string): Promise<void> { Analytics.trackAction({ action: "end_user_revoke_delegation" }); await apiClient.revokeDelegationForEndUser(endUser.userId, {}, undefined, idempotencyKey); }, // ─── Account-Scoped Delegation Methods ─── async getDelegationForAccount( opts: AccountGetDelegationForAccountOptions, ): Promise<GetDelegationForEndUserAccountResult> { Analytics.trackAction({ action: "end_user_get_delegation_for_account" }); const address = resolveEvmAddress(endUser, opts.address); return apiClient.getDelegationForEndUserAccount(endUser.userId, address); }, async revokeDelegationForAccount( opts: AccountRevokeDelegationForAccountOptions, ): Promise<void> { Analytics.trackAction({ action: "end_user_revoke_delegation_for_account" }); const address = resolveEvmAddress(endUser, opts.address); await apiClient.revokeDelegationForEndUserAccount( endUser.userId, address, {}, undefined, opts.idempotencyKey, ); }, // ─── Delegated EVM Sign Methods ─── async signEvmTransaction( opts: AccountSignEvmTransactionOptions, ): Promise<SignEvmTransactionResult> { Analytics.trackAction({ action: "end_user_sign_evm_transaction" }); const address = resolveEvmAddress(endUser, opts.address); return apiClient.signEvmTransactionWithEndUserAccount( endUser.userId, { address, transaction: opts.transaction }, undefined, opts.idempotencyKey, ); }, async signEvmMessage(opts: AccountSignEvmMessageOptions): Promise<SignEvmMessageResult> { Analytics.trackAction({ action: "end_user_sign_evm_message" }); const address = resolveEvmAddress(endUser, opts.address); return apiClient.signEvmMessageWithEndUserAccount( endUser.userId, { address, message: opts.message }, undefined, opts.idempotencyKey, ); }, async signEvmTypedData(opts: AccountSignEvmTypedDataOptions): Promise<SignEvmTypedDataResult> { Analytics.trackAction({ action: "end_user_sign_evm_typed_data" }); const address = resolveEvmAddress(endUser, opts.address); return apiClient.signEvmTypedDataWithEndUserAccount( endUser.userId, { address, typedData: opts.typedData }, undefined, opts.idempotencyKey, ); }, // ─── Delegated EVM Send Methods ─── async sendEvmTransaction( opts: AccountSendEvmTransactionOptions, ): Promise<SendEvmTransactionResult> { Analytics.trackAction({ action: "end_user_send_evm_transaction" }); const address = resolveEvmAddress(endUser, opts.address); return apiClient.sendEvmTransactionWithEndUserAccount( endUser.userId, { address, transaction: opts.transaction, network: opts.network }, undefined, opts.idempotencyKey, ); }, async sendEvmAsset(opts: AccountSendEvmAssetOptions): Promise<SendEvmAssetResult> { Analytics.trackAction({ action: "end_user_send_evm_asset" }); const address = resolveEvmAddress(endUser, opts.address); const asset = opts.asset ?? "usdc"; return apiClient.sendEvmAssetWithEndUserAccount( endUser.userId, address, asset, { to: opts.to, amount: opts.amount, network: opts.network, useCdpPaymaster: opts.useCdpPaymaster, paymasterUrl: opts.paymasterUrl, }, undefined, opts.idempotencyKey, ); }, async sendUserOperation( opts: AccountSendUserOperationOptions, ): Promise<SendUserOperationResult> { Analytics.trackAction({ action: "end_user_send_user_operation" }); const address = resolveEvmSmartAccountAddress(endUser, opts.address); return apiClient.sendUserOperationWithEndUserAccount( endUser.userId, address, { network: opts.network, calls: opts.calls, useCdpPaymaster: opts.useCdpPaymaster, paymasterUrl: opts.paymasterUrl, dataSuffix: opts.dataSuffix, }, undefined, opts.idempotencyKey, ); }, // ─── Delegated EVM EIP-7702 Delegation Method ─── async createEvmEip7702Delegation( opts: AccountCreateEvmEip7702DelegationOptions, ): Promise<CreateEvmEip7702DelegationForEndUserResult> { Analytics.trackAction({ action: "end_user_create_evm_eip7702_delegation" }); const address = resolveEvmAddress(endUser, opts.address); return apiClient.createEvmEip7702DelegationWithEndUserAccount( endUser.userId, { address, network: opts.network, enableSpendPermissions: opts.enableSpendPermissions, }, undefined, opts.idempotencyKey, ); }, // ─── Delegated Solana Sign Methods ─── async signSolanaMessage( opts: AccountSignSolanaMessageOptions, ): Promise<SignSolanaMessageResult> { Analytics.trackAction({ action: "end_user_sign_solana_message" }); const address = resolveSolanaAddress(endUser, opts.address); return apiClient.signSolanaMessageWithEndUserAccount( endUser.userId, { address, message: opts.message }, undefined, opts.idempotencyKey, ); }, async signSolanaTransaction( opts: AccountSignSolanaTransactionOptions, ): Promise<SignSolanaTransactionResult> { Analytics.trackAction({ action: "end_user_sign_solana_transaction" }); const address = resolveSolanaAddress(endUser, opts.address); return apiClient.signSolanaTransactionWithEndUserAccount( endUser.userId, { address, transaction: opts.transaction }, undefined, opts.idempotencyKey, ); }, // ─── Delegated Solana Send Methods ─── async sendSolanaTransaction( opts: AccountSendSolanaTransactionOptions, ): Promise<SendSolanaTransactionResult> { Analytics.trackAction({ action: "end_user_send_solana_transaction" }); const address = resolveSolanaAddress(endUser, opts.address); return apiClient.sendSolanaTransactionWithEndUserAccount( endUser.userId, { address, transaction: opts.transaction, network: opts.network }, undefined, opts.idempotencyKey, ); }, async sendSolanaAsset(opts: AccountSendSolanaAssetOptions): Promise<SendSolanaAssetResult> { Analytics.trackAction({ action: "end_user_send_solana_asset" }); const address = resolveSolanaAddress(endUser, opts.address); const asset = opts.asset ?? "usdc"; return apiClient.sendSolanaAssetWithEndUserAccount( endUser.userId, address, asset, { to: opts.to, amount: opts.amount, network: opts.network, createRecipientAta: opts.createRecipientAta, }, undefined, opts.idempotencyKey, ); }, }; return endUserAccount; }