UNPKG

@coinbase/agentkit

Version:

Coinbase AgentKit core primitives

439 lines (438 loc) 19.6 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _PrivyEvmDelegatedEmbeddedWalletProvider_walletId, _PrivyEvmDelegatedEmbeddedWalletProvider_address, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, _PrivyEvmDelegatedEmbeddedWalletProvider_network, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient; Object.defineProperty(exports, "__esModule", { value: true }); exports.PrivyEvmDelegatedEmbeddedWalletProvider = void 0; const canonicalize_1 = __importDefault(require("canonicalize")); const crypto_1 = __importDefault(require("crypto")); const viem_1 = require("viem"); const network_1 = require("../network/network"); const privyShared_1 = require("./privyShared"); const walletProvider_1 = require("./walletProvider"); /** * A wallet provider that uses Privy's embedded wallets with delegation. * This provider extends the EvmWalletProvider to provide Privy-specific wallet functionality * while maintaining compatibility with the base wallet provider interface. */ class PrivyEvmDelegatedEmbeddedWalletProvider extends walletProvider_1.WalletProvider { /** * Private constructor to enforce use of factory method. * * @param config - The configuration options for the wallet provider */ constructor(config) { super(); _PrivyEvmDelegatedEmbeddedWalletProvider_walletId.set(this, void 0); _PrivyEvmDelegatedEmbeddedWalletProvider_address.set(this, void 0); _PrivyEvmDelegatedEmbeddedWalletProvider_appId.set(this, void 0); _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret.set(this, void 0); _PrivyEvmDelegatedEmbeddedWalletProvider_authKey.set(this, void 0); _PrivyEvmDelegatedEmbeddedWalletProvider_network.set(this, void 0); _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient.set(this, void 0); __classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_walletId, config.walletId, "f"); __classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, config.address, "f"); __classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, config.appId, "f"); __classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret, config.appSecret, "f"); __classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, config.authorizationPrivateKey || "", "f"); const networkId = config.networkId || "base-sepolia"; const chainId = config.chainId || network_1.NETWORK_ID_TO_CHAIN_ID[networkId]; __classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, { protocolFamily: "evm", networkId: networkId, chainId: chainId, }, "f"); // Create a public client for read operations const chain = (0, network_1.getChain)(chainId); if (!chain) { throw new Error(`Chain with ID ${chainId} not found`); } __classPrivateFieldSet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, (0, viem_1.createPublicClient)({ chain, transport: (0, viem_1.http)(), }), "f"); } /** * Creates and configures a new PrivyEvmDelegatedEmbeddedWalletProvider instance. * * @param config - The configuration options for the Privy wallet * @returns A configured PrivyEvmDelegatedEmbeddedWalletProvider instance * * @example * ```typescript * const provider = await PrivyEvmDelegatedEmbeddedWalletProvider.configureWithWallet({ * appId: "your-app-id", * appSecret: "your-app-secret", * authorizationPrivateKey: "your-auth-key", * walletId: "privy-wallet-id", * networkId: "base-mainnet" * }); * ``` */ static async configureWithWallet(config) { try { if (!config.walletId) { throw new Error("walletId is required for PrivyEvmDelegatedEmbeddedWalletProvider"); } if (!config.appId || !config.appSecret) { throw new Error("appId and appSecret are required for PrivyEvmDelegatedEmbeddedWalletProvider"); } if (!config.authorizationPrivateKey) { throw new Error("authorizationPrivateKey is required for PrivyEvmDelegatedEmbeddedWalletProvider"); } const privyClient = (0, privyShared_1.createPrivyClient)(config); const user = await privyClient.getUser(config.walletId); const embeddedWallets = user.linkedAccounts.filter((account) => account.type === "wallet" && account.walletClientType === "privy"); if (embeddedWallets.length === 0) { throw new Error(`Could not find wallet address for wallet ID ${config.walletId}`); } const walletAddress = embeddedWallets[0].address; // Verify the network/chain ID if provided if (config.chainId) { const chain = (0, network_1.getChain)(config.chainId); if (!chain) { throw new Error(`Chain with ID ${config.chainId} not found`); } } return new PrivyEvmDelegatedEmbeddedWalletProvider({ ...config, address: walletAddress, }); } catch (error) { if (error instanceof Error) { throw new Error(`Failed to configure Privy embedded wallet provider: ${error.message}`); } throw new Error("Failed to configure Privy embedded wallet provider"); } } /** * Gets the address of the wallet. * * @returns The address of the wallet. */ getAddress() { return __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"); } /** * Gets the network of the wallet. * * @returns The network of the wallet. */ getNetwork() { return __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f"); } /** * Gets the name of the wallet provider. * * @returns The name of the wallet provider. */ getName() { return "privy_evm_embedded_wallet_provider"; } /** * Gets the balance of the wallet. * * @returns The balance of the wallet in wei */ async getBalance() { try { const balance = await __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, "f").getBalance({ address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), }); return balance; } catch (error) { if (error instanceof Error) { throw new Error(`Error getting balance: ${error.message}`); } throw new Error("Error getting balance"); } } /** * Signs a message. * * @param message - The message to sign. * @returns The signed message. */ async signMessage(message) { const body = { address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), chain_type: "ethereum", method: "personal_sign", params: { message, encoding: "utf-8", }, }; try { const response = await this.executePrivyRequest(body); return response.data?.signature; } catch (error) { if (error instanceof Error) { throw new Error(`Message signing failed: ${error.message}`); } throw new Error("Message signing failed"); } } /** * Signs typed data according to EIP-712. * * @param typedData - The typed data object to sign * @param typedData.domain - The domain object containing contract and chain information * @param typedData.types - The type definitions for the structured data * @param typedData.primaryType - The primary type being signed * @param typedData.message - The actual data to sign * @returns A Address that resolves to the signed typed data as a hex string */ async signTypedData(typedData) { const body = { address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), chain_type: "ethereum", chain_id: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId, ...typedData, }; try { const response = await this.executePrivyRequest({ method: "eth_signTypedData_v4", params: body, }); return response.signature; } catch (error) { if (error instanceof Error) { throw new Error("Typed data signing failed: " + error.message); } throw new Error("Typed data signing failed with unknown error"); } } /** * Signs a transaction. * * @param transaction - The transaction to sign. * @returns The signed transaction. */ async signTransaction(transaction) { const body = { address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), chain_type: "ethereum", method: "eth_signTransaction", params: { transaction: { ...transaction, from: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), }, }, }; try { const response = await this.executePrivyRequest(body); return response.data?.signed_transaction; } catch (error) { if (error instanceof Error) { throw new Error(`Transaction signing failed: ${error.message}`); } throw new Error("Transaction signing failed"); } } /** * Sends a transaction. * * @param transaction - The transaction to send. * @returns The hash of the transaction. */ async sendTransaction(transaction) { const body = { address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), chain_type: "ethereum", method: "eth_sendTransaction", caip2: `eip155:${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId}`, params: { transaction: { ...transaction, from: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), }, }, }; try { const response = await this.executePrivyRequest(body); return response.data?.hash; } catch (error) { if (error instanceof Error) { throw new Error(`Transaction sending failed: ${error.message}`); } throw new Error("Transaction sending failed"); } } /** * Waits for a transaction receipt. * * @param txHash - The hash of the transaction to wait for. * @returns The transaction receipt. */ async waitForTransactionReceipt(txHash) { return await __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, "f").waitForTransactionReceipt({ hash: txHash, }); } /** * Reads data from a smart contract. * * @param params - Parameters for reading the contract * @param params.address - The address of the contract * @param params.abi - The ABI of the contract * @param params.functionName - The name of the function to call * @param params.args - The arguments to pass to the function * @returns A Address that resolves to the contract function's return value */ async readContract(params) { return __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient, "f").readContract(params); } /** * Transfer the native asset of the network. * * @param to - The destination address. * @param value - The amount to transfer in Wei. * @returns The transaction hash. */ async nativeTransfer(to, value) { const valueInWei = (0, viem_1.parseEther)(value); const valueHex = `0x${valueInWei.toString(16)}`; const body = { address: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_address, "f"), chain_type: "ethereum", method: "eth_sendTransaction", caip2: `eip155:${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId}`, params: { transaction: { to, value: valueHex, }, }, }; try { const response = await this.executePrivyRequest(body); const receipt = await this.waitForTransactionReceipt(response.data.hash); if (!receipt) { throw new Error("Transaction failed"); } return receipt.transactionHash; } catch (error) { if (error instanceof Error) { throw new Error(`Native transfer failed: ${error.message}`); } throw new Error("Native transfer failed"); } } /** * Exports the wallet information. * * @returns The wallet data */ exportWallet() { return { walletId: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_walletId, "f"), authorizationPrivateKey: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, "f"), networkId: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").networkId, chainId: __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_network, "f").chainId, }; } /** * Generate Privy authorization signature for API requests * * @param url - The URL for the request * @param body - The request body * @returns The generated signature */ generatePrivySignature(url, body) { try { const payload = { version: 1, method: "POST", url, body, headers: { "privy-app-id": __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, "f"), }, }; const serializedPayload = (0, canonicalize_1.default)(payload); if (!serializedPayload) throw new Error("Failed to canonicalize payload"); const serializedPayloadBuffer = Buffer.from(serializedPayload); const privateKeyAsString = __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_authKey, "f").replace("wallet-auth:", ""); const privateKeyAsPem = `-----BEGIN PRIVATE KEY-----\n${privateKeyAsString}\n-----END PRIVATE KEY-----`; const privateKey = crypto_1.default.createPrivateKey({ key: privateKeyAsPem, format: "pem", }); const signatureBuffer = crypto_1.default.sign("sha256", serializedPayloadBuffer, privateKey); return signatureBuffer.toString("base64"); } catch (error) { if (error instanceof Error) { throw new Error(`Error generating Privy authorization signature: ${error.message}`); } throw new Error("Error generating Privy authorization signature"); } } /** * Get Privy headers for API requests * * @param url - The URL for the request * @param body - The request body * @returns The headers for the request */ getPrivyHeaders(url, body) { return { "Content-Type": "application/json", Authorization: `Basic ${Buffer.from(`${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, "f")}:${__classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret, "f")}`).toString("base64")}`, "privy-app-id": __classPrivateFieldGet(this, _PrivyEvmDelegatedEmbeddedWalletProvider_appId, "f"), "privy-authorization-signature": this.generatePrivySignature(url, body), }; } /** * Execute a Privy API request. * * @param body - The request body to send to the Privy API * @returns A promise that resolves to the response data * @throws Error if the request fails */ async executePrivyRequest(body) { const url = `https://api.privy.io/v1/wallets/rpc`; const headers = this.getPrivyHeaders(url, body); try { const response = await fetch(url, { method: "POST", headers, body: JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value), }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { if (error instanceof Error) { throw new Error("Privy request failed: " + error.message); } throw new Error("Privy request failed with unknown error"); } } } exports.PrivyEvmDelegatedEmbeddedWalletProvider = PrivyEvmDelegatedEmbeddedWalletProvider; _PrivyEvmDelegatedEmbeddedWalletProvider_walletId = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_address = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_appId = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_appSecret = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_authKey = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_network = new WeakMap(), _PrivyEvmDelegatedEmbeddedWalletProvider_publicClient = new WeakMap();