diff --git a/typescript/agentkit/src/action-providers/cdp-v2/cdpApiV2ActionProvider.ts b/typescript/agentkit/src/action-providers/cdp-v2/cdpApiV2ActionProvider.ts index a461caf64..658637509 100644 --- a/typescript/agentkit/src/action-providers/cdp-v2/cdpApiV2ActionProvider.ts +++ b/typescript/agentkit/src/action-providers/cdp-v2/cdpApiV2ActionProvider.ts @@ -1,19 +1,17 @@ import { z } from "zod"; import { Network } from "../../network"; import { WalletProvider } from "../../wallet-providers"; -import { WalletProviderWithClient } from "../../wallet-providers/cdpV2Shared"; +import { isWalletProviderWithClient } from "../../wallet-providers/cdpV2Shared"; import { CreateAction } from "../actionDecorator"; import { ActionProvider } from "../actionProvider"; import { RequestFaucetFundsV2Schema } from "./schemas"; -type CdpV2WalletProviderWithClient = WalletProvider & WalletProviderWithClient; - /** * CdpApiActionProvider is an action provider for CDP API. * * This provider is used for any action that uses the CDP API, but does not require a CDP Wallet. */ -export class CdpApiV2ActionProvider extends ActionProvider { +export class CdpApiV2ActionProvider extends ActionProvider { /** * Constructor for the CdpApiActionProvider class. */ @@ -39,43 +37,47 @@ from another wallet and provide the user with your wallet details.`, schema: RequestFaucetFundsV2Schema, }) async faucet( - walletProvider: CdpV2WalletProviderWithClient, + walletProvider: WalletProvider, args: z.infer, ): Promise { const network = walletProvider.getNetwork(); const networkId = network.networkId!; - if (network.protocolFamily === "evm") { - if (networkId !== "base-sepolia" && networkId !== "ethereum-sepolia") { - throw new Error( - "Faucet is only supported on 'base-sepolia' or 'ethereum-sepolia' evm networks.", - ); - } + if (isWalletProviderWithClient(walletProvider)) { + if (network.protocolFamily === "evm") { + if (networkId !== "base-sepolia" && networkId !== "ethereum-sepolia") { + throw new Error( + "Faucet is only supported on 'base-sepolia' or 'ethereum-sepolia' evm networks.", + ); + } - const faucetTx = await walletProvider.getClient().evm.requestFaucet({ - address: walletProvider.getAddress(), - token: (args.assetId || "eth") as "eth" | "usdc" | "eurc" | "cbbtc", - network: networkId, - }); + const faucetTx = await walletProvider.getClient().evm.requestFaucet({ + address: walletProvider.getAddress(), + token: (args.assetId || "eth") as "eth" | "usdc" | "eurc" | "cbbtc", + network: networkId, + }); - return `Received ${ - args.assetId || "ETH" - } from the faucet. Transaction hash: ${faucetTx.transactionHash}`; - } else if (network.protocolFamily === "svm") { - if (networkId !== "solana-devnet") { - throw new Error("Faucet is only supported on 'solana-devnet' solana networks."); - } + return `Received ${ + args.assetId || "ETH" + } from the faucet. Transaction hash: ${faucetTx.transactionHash}`; + } else if (network.protocolFamily === "svm") { + if (networkId !== "solana-devnet") { + throw new Error("Faucet is only supported on 'solana-devnet' solana networks."); + } - const faucetTx = await walletProvider.getClient().solana.requestFaucet({ - address: walletProvider.getAddress(), - token: (args.assetId || "sol") as "sol" | "usdc", - }); + const faucetTx = await walletProvider.getClient().solana.requestFaucet({ + address: walletProvider.getAddress(), + token: (args.assetId || "sol") as "sol" | "usdc", + }); - return `Received ${ - args.assetId || "SOL" - } from the faucet. Transaction signature hash: ${faucetTx.signature}`; + return `Received ${ + args.assetId || "SOL" + } from the faucet. Transaction signature hash: ${faucetTx.signature}`; + } else { + throw new Error("Faucet is only supported on Ethereum and Solana protocol families."); + } } else { - throw new Error("Faucet is only supported on Ethereum and Solana protocol families."); + throw new Error("Wallet provider is not a CDP Wallet Provider."); } } diff --git a/typescript/agentkit/src/wallet-providers/cdpV2EvmWalletProvider.ts b/typescript/agentkit/src/wallet-providers/cdpV2EvmWalletProvider.ts index 3f9d3d81a..84bb6cd21 100644 --- a/typescript/agentkit/src/wallet-providers/cdpV2EvmWalletProvider.ts +++ b/typescript/agentkit/src/wallet-providers/cdpV2EvmWalletProvider.ts @@ -158,9 +158,30 @@ export class CdpV2EvmWalletProvider extends EvmWalletProvider implements WalletP * @returns The hash of the transaction. */ async sendTransaction(transaction: TransactionRequest): Promise { + const txWithGasParams = { + ...transaction, + chainId: this.#network.chainId, + }; + + if (!txWithGasParams.maxFeePerGas && !txWithGasParams.gasPrice) { + const feeData = await this.#publicClient.estimateFeesPerGas(); + txWithGasParams.maxFeePerGas = feeData.maxFeePerGas; + txWithGasParams.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas; + } + + if (!txWithGasParams.gas) { + try { + txWithGasParams.gas = await this.#publicClient.estimateGas({ + account: this.#serverAccount.address as Address, + ...txWithGasParams, + }); + } catch (error) { + console.warn("Failed to estimate gas, continuing without gas estimation", error); + } + } const result = await this.#cdp.evm.sendTransaction({ address: this.#serverAccount.address, - transaction: serializeTransaction(transaction as TransactionSerializable), + transaction: serializeTransaction(txWithGasParams as TransactionSerializable), network: this.#getCdpSdkNetwork(), }); return result.transactionHash; diff --git a/typescript/agentkit/src/wallet-providers/cdpV2Shared.ts b/typescript/agentkit/src/wallet-providers/cdpV2Shared.ts index 0c8214b70..264dbc4b7 100644 --- a/typescript/agentkit/src/wallet-providers/cdpV2Shared.ts +++ b/typescript/agentkit/src/wallet-providers/cdpV2Shared.ts @@ -46,3 +46,20 @@ export interface WalletProviderWithClient { */ getClient(): CdpClient; } + +/** + * Type guard to check if a wallet provider implements WalletProviderWithClient interface. + * + * @param provider - The provider to check + * @returns True if the provider implements WalletProviderWithClient + */ +export function isWalletProviderWithClient( + provider: unknown, +): provider is WalletProviderWithClient { + return ( + provider !== null && + typeof provider === "object" && + "getClient" in provider && + typeof (provider as WalletProviderWithClient).getClient === "function" + ); +}