diff --git a/.eslintrc.base.json b/.eslintrc.base.json index d7e3cdc..17587c9 100644 --- a/.eslintrc.base.json +++ b/.eslintrc.base.json @@ -46,6 +46,5 @@ "jsdoc/require-returns-description": "error", "jsdoc/require-returns-type": "off", "jsdoc/require-hyphen-before-param-description": ["error", "always"] - }, - "ignorePatterns": ["src/**/tests/**", "src/**/*.test.ts"] + } } diff --git a/cdp-agentkit-core/jest.config.js b/cdp-agentkit-core/jest.config.cjs similarity index 83% rename from cdp-agentkit-core/jest.config.js rename to cdp-agentkit-core/jest.config.cjs index 97002eb..0e9437e 100644 --- a/cdp-agentkit-core/jest.config.js +++ b/cdp-agentkit-core/jest.config.cjs @@ -1,6 +1,6 @@ -import baseConfig from "../jest.config.base.js"; +const baseConfig = require("../jest.config.base.cjs"); -export default { +module.exports = { ...baseConfig, coveragePathIgnorePatterns: ["node_modules", "dist", "docs", "index.ts"], coverageThreshold: { diff --git a/cdp-agentkit-core/package.json b/cdp-agentkit-core/package.json index acb1234..5f11f4c 100644 --- a/cdp-agentkit-core/package.json +++ b/cdp-agentkit-core/package.json @@ -14,7 +14,7 @@ "format": "npx --yes prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", "format-check": "npx --yes prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", "check": "tsc --noEmit", - "test": "npx --yes jest --no-cache --testMatch=**/*_test.ts", + "test": "npx jest --no-cache --testMatch='**/*_test.ts'", "test:dry-run": "npm install && npm ci && npm publish --dry-run", "test:e2e": "npx jest --no-cache --testMatch=**/e2e.ts --coverageThreshold '{}'", "test:types": "tsd --files src/tests/types.test-d.ts", @@ -41,10 +41,14 @@ "zod": "^3.23.8" }, "devDependencies": { + "@types/jest": "^29.5.14", "@types/secp256k1": "^4.0.6", "http-server": "^14.1.1", + "jest": "^29.7.0", "mock-fs": "^5.2.0", - "tsd": "^0.31.2" + "ts-jest": "^29.2.5", + "tsd": "^0.31.2", + "typescript": "^5.7.2" }, "exports": { ".": { diff --git a/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/buy_token.ts b/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/buy_token.ts index 6891eeb..934f587 100644 --- a/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/buy_token.ts +++ b/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/buy_token.ts @@ -12,7 +12,7 @@ This tool will buy a Zora Wow ERC20 memecoin with ETH. This tool takes the WOW t /** * Input schema for buy token action. */ -const WowBuyTokenInput = z +export const WowBuyTokenInput = z .object({ contractAddress: z.string().describe("The WOW token contract address"), amountEthInWei: z.string().describe("Amount of ETH to spend (in wei)"), @@ -27,7 +27,7 @@ const WowBuyTokenInput = z * @param args - The input arguments for the action. * @returns A message containing the token purchase details. */ -async function wowBuyToken( +export async function wowBuyToken( wallet: Wallet, args: z.infer, ): Promise { @@ -63,7 +63,7 @@ async function wowBuyToken( const result = await invocation.wait(); return `Purchased WoW ERC20 memecoin with transaction hash: ${result.getTransaction().getTransactionHash()}`; } catch (error) { - return `Error buying Zora Wow ERC20 memecoin ${error}`; + return `Error buying Zora Wow ERC20 memecoin: ${error}`; } } diff --git a/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/create_token.ts b/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/create_token.ts index 9b7bfe1..087824a 100644 --- a/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/create_token.ts +++ b/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/create_token.ts @@ -10,7 +10,7 @@ This tool will create a Zora Wow ERC20 memecoin using the WoW factory. This tool /** * Input schema for create token action. */ -const WowCreateTokenInput = z +export const WowCreateTokenInput = z .object({ name: z.string().describe("The name of the token to create, e.g. WowCoin"), symbol: z.string().describe("The symbol of the token to create, e.g. WOW"), @@ -31,7 +31,7 @@ const WowCreateTokenInput = z * @param args - The input arguments for the action. * @returns A message containing the token creation details. */ -async function wowCreateToken( +export async function wowCreateToken( wallet: Wallet, args: z.infer, ): Promise { @@ -54,7 +54,7 @@ async function wowCreateToken( const result = await invocation.wait(); return `Created WoW ERC20 memecoin ${args.name} with symbol ${args.symbol} on network ${wallet.getNetworkId()}.\nTransaction hash for the token creation: ${result.getTransaction().getTransactionHash()}`; } catch (error) { - return `Error creating Zora Wow ERC20 memecoin ${error}`; + return `Error creating Zora Wow ERC20 memecoin: ${error}`; } } diff --git a/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/sell_token.ts b/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/sell_token.ts index fdb89d1..d1abe2f 100644 --- a/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/sell_token.ts +++ b/cdp-agentkit-core/src/actions/cdp/defi/wow/actions/sell_token.ts @@ -12,7 +12,7 @@ This tool will sell a Zora Wow ERC20 memecoin for ETH. This tool takes the WOW t /** * Input schema for sell token action. */ -const WowSellTokenInput = z +export const WowSellTokenInput = z .object({ contractAddress: z .string() @@ -35,7 +35,7 @@ const WowSellTokenInput = z * @param args - The input arguments for the action. * @returns A message confirming the sale with the transaction hash. */ -async function wowSellToken( +export async function wowSellToken( wallet: Wallet, args: z.infer, ): Promise { @@ -68,7 +68,7 @@ async function wowSellToken( const result = await invocation.wait(); return `Sold WoW ERC20 memecoin with transaction hash: ${result.getTransaction().getTransactionHash()}`; } catch (error) { - return `Error selling Zora Wow ERC20 memecoin ${error}`; + return `Error selling Zora Wow ERC20 memecoin: ${error}`; } } diff --git a/cdp-agentkit-core/src/actions/cdp/deploy_nft.ts b/cdp-agentkit-core/src/actions/cdp/deploy_nft.ts index aaed5d1..1cd71af 100644 --- a/cdp-agentkit-core/src/actions/cdp/deploy_nft.ts +++ b/cdp-agentkit-core/src/actions/cdp/deploy_nft.ts @@ -8,11 +8,11 @@ This tool will deploy an NFT (ERC-721) contract onchain from the wallet. It take /** * Input schema for deploy NFT action. */ -const DeployNftInput = z +export const DeployNftInput = z .object({ name: z.string().describe("The name of the NFT collection"), symbol: z.string().describe("The symbol of the NFT collection"), - baseUri: z.string().describe("The base URI for the token metadata"), + baseURI: z.string().describe("The base URI for the token metadata"), }) .strip() .describe("Instructions for deploying an NFT collection"); @@ -24,12 +24,15 @@ const DeployNftInput = z * @param args - The input arguments for the action. * @returns A message containing the NFT token deployment details. */ -async function deployNft(wallet: Wallet, args: z.infer): Promise { +export async function deployNft( + wallet: Wallet, + args: z.infer, +): Promise { try { const nftContract = await wallet.deployNFT({ name: args.name, symbol: args.symbol, - baseURI: args.baseUri, + baseURI: args.baseURI, }); const result = await nftContract.wait(); diff --git a/cdp-agentkit-core/src/actions/cdp/deploy_token.ts b/cdp-agentkit-core/src/actions/cdp/deploy_token.ts index 93b5922..238fcd1 100644 --- a/cdp-agentkit-core/src/actions/cdp/deploy_token.ts +++ b/cdp-agentkit-core/src/actions/cdp/deploy_token.ts @@ -8,7 +8,7 @@ This tool will deploy an ERC20 token smart contract. It takes the token name, sy /** * Input schema for deploy token action. */ -const DeployTokenInput = z +export const DeployTokenInput = z .object({ name: z.string().describe("The name of the token"), symbol: z.string().describe("The token symbol"), @@ -24,7 +24,7 @@ const DeployTokenInput = z * @param args - The input arguments for the action. * @returns A message containing the deployed token contract address and details. */ -async function deployToken( +export async function deployToken( wallet: Wallet, args: z.infer, ): Promise { diff --git a/cdp-agentkit-core/src/actions/cdp/get_balance.ts b/cdp-agentkit-core/src/actions/cdp/get_balance.ts index d08e560..24a8e6a 100644 --- a/cdp-agentkit-core/src/actions/cdp/get_balance.ts +++ b/cdp-agentkit-core/src/actions/cdp/get_balance.ts @@ -9,7 +9,7 @@ This tool will get the balance of all the addresses in the wallet for a given as /** * Input schema for get balance action. */ -const GetBalanceInput = z +export const GetBalanceInput = z .object({ assetId: z.string().describe("The asset ID to get the balance for"), }) @@ -23,7 +23,10 @@ const GetBalanceInput = z * @param args - The input arguments for the action. * @returns A message containing the balance information. */ -async function getBalance(wallet: Wallet, args: z.infer): Promise { +export async function getBalance( + wallet: Wallet, + args: z.infer, +): Promise { const balances: Record = {}; try { diff --git a/cdp-agentkit-core/src/actions/cdp/get_wallet_details.ts b/cdp-agentkit-core/src/actions/cdp/get_wallet_details.ts index 461e0a8..94b14fd 100644 --- a/cdp-agentkit-core/src/actions/cdp/get_wallet_details.ts +++ b/cdp-agentkit-core/src/actions/cdp/get_wallet_details.ts @@ -6,7 +6,7 @@ import { Wallet } from "@coinbase/coinbase-sdk"; * Input schema for get wallet details action. * This schema intentionally accepts no parameters as the wallet is injected separately. */ -const GetWalletDetailsInput = z.object({}); +export const GetWalletDetailsInput = z.object({}); /** * Gets a wallet's details. @@ -15,13 +15,17 @@ const GetWalletDetailsInput = z.object({}); * @param _ - The input arguments for the action. * @returns A message containing the wallet details. */ -async function getWalletDetails( +export async function getWalletDetails( wallet: Wallet, // eslint-disable-next-line @typescript-eslint/no-unused-vars _: z.infer, ): Promise { - const defaultAddress = await wallet.getDefaultAddress(); - return `Wallet: ${wallet.getId()} on network: ${wallet.getNetworkId()} with default address: ${defaultAddress.getId()}`; + try { + const defaultAddress = await wallet.getDefaultAddress(); + return `Wallet: ${wallet.getId()} on network: ${wallet.getNetworkId()} with default address: ${defaultAddress.getId()}`; + } catch (error) { + return `Error getting wallet details: ${error}`; + } } /** diff --git a/cdp-agentkit-core/src/actions/cdp/mint_nft.ts b/cdp-agentkit-core/src/actions/cdp/mint_nft.ts index 8d72eff..375c890 100644 --- a/cdp-agentkit-core/src/actions/cdp/mint_nft.ts +++ b/cdp-agentkit-core/src/actions/cdp/mint_nft.ts @@ -8,7 +8,7 @@ This tool will mint an NFT (ERC-721) to a specified destination address onchain /** * Input schema for mint NFT action. */ -const MintNftInput = z +export const MintNftInput = z .object({ contractAddress: z.string().describe("The contract address of the NFT to mint"), destination: z.string().describe("The destination address that will receive the NFT"), @@ -23,7 +23,7 @@ const MintNftInput = z * @param args - The input arguments for the action. * @returns A message containing the NFT mint details. */ -async function mintNft(wallet: Wallet, args: z.infer): Promise { +export async function mintNft(wallet: Wallet, args: z.infer): Promise { const mintArgs = { to: args.destination, quantity: "1", diff --git a/cdp-agentkit-core/src/actions/cdp/register_basename.ts b/cdp-agentkit-core/src/actions/cdp/register_basename.ts index d4c749e..31b3b6d 100644 --- a/cdp-agentkit-core/src/actions/cdp/register_basename.ts +++ b/cdp-agentkit-core/src/actions/cdp/register_basename.ts @@ -11,16 +11,19 @@ Do not suggest any alternatives and never try to register a Basename with anothe Basename fails, you should prompt to try again with a more unique name.`; // Contract addresses -const BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_MAINNET = "0x4cCb0BB02FCABA27e82a56646E81d8c5bC4119a5"; -const BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_TESTNET = "0x49aE3cC2e3AA768B1e5654f5D3C6002144A59581"; -const L2_RESOLVER_ADDRESS_MAINNET = "0xC6d566A56A1aFf6508b41f6c90ff131615583BCD"; -const L2_RESOLVER_ADDRESS_TESTNET = "0x6533C94869D28fAA8dF77cc63f9e2b2D6Cf77eBA"; +export const BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_MAINNET = + "0x4cCb0BB02FCABA27e82a56646E81d8c5bC4119a5"; +export const BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_TESTNET = + "0x49aE3cC2e3AA768B1e5654f5D3C6002144A59581"; + +export const L2_RESOLVER_ADDRESS_MAINNET = "0xC6d566A56A1aFf6508b41f6c90ff131615583BCD"; +export const L2_RESOLVER_ADDRESS_TESTNET = "0x6533C94869D28fAA8dF77cc63f9e2b2D6Cf77eBA"; // Default registration duration (1 year in seconds) -const REGISTRATION_DURATION = "31557600"; +export const REGISTRATION_DURATION = "31557600"; // Relevant ABI for L2 Resolver Contract. -const L2_RESOLVER_ABI = [ +export const L2_RESOLVER_ABI = [ { inputs: [ { internalType: "bytes32", name: "node", type: "bytes32" }, @@ -44,7 +47,7 @@ const L2_RESOLVER_ABI = [ ]; // Relevant ABI for Basenames Registrar Controller Contract. -const REGISTRAR_ABI = [ +export const REGISTRAR_ABI = [ { inputs: [ { @@ -95,7 +98,7 @@ const REGISTRAR_ABI = [ /** * Input schema for registering a Basename. */ -const RegisterBasenameInput = z +export const RegisterBasenameInput = z .object({ basename: z.string().describe("The Basename to assign to the agent"), amount: z.string().default("0.002").describe("The amount of ETH to pay for registration"), @@ -151,7 +154,7 @@ function createRegisterContractMethodArgs( * @param args - The input arguments for the action. * @returns Confirmation message with the basename. */ -async function registerBasename( +export async function registerBasename( wallet: Wallet, args: z.infer, ): Promise { @@ -183,7 +186,7 @@ async function registerBasename( return `Successfully registered basename ${args.basename} for address ${addressId}`; // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error) { - return `Error registering basename: ${error}`; + return `Error registering basename: Error: ${error}`; } } diff --git a/cdp-agentkit-core/src/actions/cdp/request_faucet_funds.ts b/cdp-agentkit-core/src/actions/cdp/request_faucet_funds.ts index 6e9026a..6a19c6a 100644 --- a/cdp-agentkit-core/src/actions/cdp/request_faucet_funds.ts +++ b/cdp-agentkit-core/src/actions/cdp/request_faucet_funds.ts @@ -11,7 +11,7 @@ from another wallet and provide the user with your wallet details.`; /** * Input schema for request faucet funds action. */ -const RequestFaucetFundsInput = z +export const RequestFaucetFundsInput = z .object({ assetId: z.string().optional().describe("The optional asset ID to request from faucet"), }) @@ -25,7 +25,7 @@ const RequestFaucetFundsInput = z * @param args - The input arguments for the action. * @returns A confirmation message with transaction details. */ -async function requestFaucetFunds( +export async function requestFaucetFunds( wallet: Wallet, args: z.infer, ): Promise { @@ -34,9 +34,9 @@ async function requestFaucetFunds( const faucetTx = await wallet.faucet(args.assetId || undefined); // Wait for the faucet transaction to be confirmed - await faucetTx.wait(); + const result = await faucetTx.wait(); - return `Received ${args.assetId || "ETH"} from the faucet. Transaction: ${faucetTx.getTransactionLink()}`; + return `Received ${args.assetId || "ETH"} from the faucet. Transaction: ${result.getTransactionLink()}`; } catch (error) { return `Error requesting faucet funds: ${error}`; } diff --git a/cdp-agentkit-core/src/actions/cdp/trade.ts b/cdp-agentkit-core/src/actions/cdp/trade.ts index 6268a9a..59cab83 100644 --- a/cdp-agentkit-core/src/actions/cdp/trade.ts +++ b/cdp-agentkit-core/src/actions/cdp/trade.ts @@ -8,7 +8,7 @@ This tool will trade a specified amount of a from asset to a to asset for the wa /** * Input schema for trade action. */ -const TradeInput = z +export const TradeInput = z .object({ amount: z.custom().describe("The amount of the from asset to trade"), fromAssetId: z.string().describe("The from asset ID to trade"), @@ -24,7 +24,7 @@ const TradeInput = z * @param args - The input arguments for the action. * @returns A message containing the trade details. */ -async function trade(wallet: Wallet, args: z.infer): Promise { +export async function trade(wallet: Wallet, args: z.infer): Promise { try { const tradeResult = await wallet.createTrade({ amount: args.amount, diff --git a/cdp-agentkit-core/src/actions/cdp/transfer.ts b/cdp-agentkit-core/src/actions/cdp/transfer.ts index 65ef37a..993e745 100644 --- a/cdp-agentkit-core/src/actions/cdp/transfer.ts +++ b/cdp-agentkit-core/src/actions/cdp/transfer.ts @@ -8,7 +8,7 @@ This tool will transfer an asset from the wallet to another onchain address. It /** * Input schema for transfer action. */ -const TransferInput = z +export const TransferInput = z .object({ amount: z.custom().describe("The amount of the asset to transfer"), assetId: z.string().describe("The asset ID to transfer"), @@ -25,7 +25,10 @@ const TransferInput = z * @param args - The input arguments for the action. * @returns A message containing the transfer details. */ -async function transfer(wallet: Wallet, args: z.infer): Promise { +export async function transfer( + wallet: Wallet, + args: z.infer, +): Promise { try { const transferResult = await wallet.createTransfer({ amount: args.amount, diff --git a/cdp-agentkit-core/src/tests/defi_wow_buy_token_test.ts b/cdp-agentkit-core/src/tests/defi_wow_buy_token_test.ts new file mode 100644 index 0000000..9b6b198 --- /dev/null +++ b/cdp-agentkit-core/src/tests/defi_wow_buy_token_test.ts @@ -0,0 +1,116 @@ +import { Coinbase, ContractInvocation, Wallet } from "@coinbase/coinbase-sdk"; + +import { WOW_ABI } from "../actions/cdp/defi/wow/constants"; +import { wowBuyToken, WowBuyTokenInput } from "../actions/cdp/defi/wow/actions/buy_token"; +import { getBuyQuote } from "../actions/cdp/defi/wow/utils"; +import { getHasGraduated } from "../actions/cdp/defi/wow/uniswap/utils"; + +jest.mock("../actions/cdp/defi/wow/utils", () => ({ + getBuyQuote: jest.fn(), +})); + +jest.mock("../actions/cdp/defi/wow/uniswap/utils", () => ({ + getHasGraduated: jest.fn(), +})); + +const MOCK_CONTRACT_ADDRESS = "0xabcdef123456789"; +const MOCK_AMOUNT_ETH_IN_WEI = "100000000000000000"; + +describe("Wow Buy Token Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountEthInWei: MOCK_AMOUNT_ETH_IN_WEI, + }; + + const result = WowBuyTokenInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = WowBuyTokenInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Wow Buy Token Action", () => { + const NETWORK_ID = Coinbase.networks.BaseSepolia; + const TRANSACTION_HASH = "0xghijkl987654321"; + + let mockContractInvocation: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockWallet = { + invokeContract: jest.fn(), + getDefaultAddress: jest.fn().mockResolvedValue({ + getId: jest.fn().mockReturnValue(TRANSACTION_HASH), + }), + getNetworkId: jest.fn().mockReturnValue(NETWORK_ID), + } as unknown as jest.Mocked; + + mockContractInvocation = { + wait: jest.fn().mockResolvedValue({ + getTransaction: jest.fn().mockReturnValue({ + getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH), + }), + }), + } as unknown as jest.Mocked; + + mockWallet.invokeContract.mockResolvedValue(mockContractInvocation); + }); + + it("should successfully buy a token", async () => { + const args = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountEthInWei: MOCK_AMOUNT_ETH_IN_WEI, + }; + + (getHasGraduated as jest.Mock).mockResolvedValue(true); + (getBuyQuote as jest.Mock).mockResolvedValue(1.0); + + const response = await wowBuyToken(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalledWith({ + contractAddress: MOCK_CONTRACT_ADDRESS, + method: "buy", + abi: WOW_ABI, + args: { + recipient: expect.any(String), + refundRecipient: expect.any(String), + orderReferrer: "0x0000000000000000000000000000000000000000", + expectedMarketType: "1", + minOrderSize: expect.any(String), + sqrtPriceLimitX96: "0", + comment: "", + }, + amount: BigInt(args.amountEthInWei), + assetId: "wei", + }); + expect(getBuyQuote).toHaveBeenCalled(); + expect(getHasGraduated).toHaveBeenCalled(); + expect(response).toContain( + `Purchased WoW ERC20 memecoin with transaction hash: ${TRANSACTION_HASH}`, + ); + }); + + it("should handle errors when buying a token", async () => { + const args = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountEthInWei: MOCK_AMOUNT_ETH_IN_WEI, + }; + + const error = new Error("An error has occurred"); + mockWallet.invokeContract.mockRejectedValue(error); + (getHasGraduated as jest.Mock).mockResolvedValue(true); + + const response = await wowBuyToken(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalled(); + expect(response).toContain(`Error buying Zora Wow ERC20 memecoin: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/defi_wow_create_token_test.ts b/cdp-agentkit-core/src/tests/defi_wow_create_token_test.ts new file mode 100644 index 0000000..3b2a82b --- /dev/null +++ b/cdp-agentkit-core/src/tests/defi_wow_create_token_test.ts @@ -0,0 +1,139 @@ +import { Coinbase, ContractInvocation, Wallet } from "@coinbase/coinbase-sdk"; + +import { + getFactoryAddress, + GENERIC_TOKEN_METADATA_URI, + WOW_FACTORY_ABI, +} from "../actions/cdp/defi/wow/constants"; +import { wowCreateToken, WowCreateTokenInput } from "../actions/cdp/defi/wow/actions/create_token"; + +jest.mock("../actions/cdp/defi/wow/constants", () => ({ + getFactoryAddress: jest.fn(), +})); + +const MOCK_NAME = "Test Token"; +const MOCK_SYMBOL = "TEST"; +const MOCK_URI = "ipfs://QmY1GqprFYvojCcUEKgqHeDj9uhZD9jmYGrQTfA9vAE78J"; + +describe("Wow Create Token Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + name: MOCK_NAME, + symbol: MOCK_SYMBOL, + tokenUri: MOCK_URI, + }; + + const result = WowCreateTokenInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should successfully parse input without tokenUri", () => { + const validInput = { + name: MOCK_NAME, + symbol: MOCK_SYMBOL, + }; + + const result = WowCreateTokenInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail with missing required fields", () => { + const invalidInput = { + symbol: MOCK_SYMBOL, + }; + const result = WowCreateTokenInput.safeParse(invalidInput); + + expect(result.success).toBe(false); + }); + + it("should fail with invalid tokenUri", () => { + const invalidInput = { + name: MOCK_NAME, + symbol: MOCK_SYMBOL, + tokenUri: 12345, + }; + const result = WowCreateTokenInput.safeParse(invalidInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Wow Create Token Action", () => { + const CONTRACT_ADDRESS = "0xabcdef123456789"; + const NETWORK_ID = Coinbase.networks.BaseSepolia; + const TRANSACTION_HASH = "0xghijkl987654321"; + const WALLET_ID = "0x123456789abcdef"; + + let mockContractInvocation: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockWallet = { + invokeContract: jest.fn(), + getDefaultAddress: jest.fn().mockResolvedValue({ + getId: jest.fn().mockReturnValue(WALLET_ID), + }), + getNetworkId: jest.fn().mockReturnValue(NETWORK_ID), + } as unknown as jest.Mocked; + + mockContractInvocation = { + wait: jest.fn().mockResolvedValue({ + getTransaction: jest.fn().mockReturnValue({ + getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH), + }), + }), + } as unknown as jest.Mocked; + + mockWallet.invokeContract.mockResolvedValue(mockContractInvocation); + }); + + it("should successfully create a token", async () => { + const args = { + name: MOCK_NAME, + symbol: MOCK_SYMBOL, + tokenUri: MOCK_URI, + }; + + (getFactoryAddress as jest.Mock).mockReturnValue(CONTRACT_ADDRESS); + + const response = await wowCreateToken(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalledWith({ + contractAddress: CONTRACT_ADDRESS, + method: "deploy", + abi: WOW_FACTORY_ABI, + args: { + _tokenCreator: WALLET_ID, + _platformReferrer: "0x0000000000000000000000000000000000000000", + _tokenURI: args.tokenUri || GENERIC_TOKEN_METADATA_URI, + _name: args.name, + _symbol: args.symbol, + }, + }); + expect(mockContractInvocation.wait).toHaveBeenCalled(); + expect(response).toContain(`Created WoW ERC20 memecoin ${MOCK_NAME}`); + expect(response).toContain(`with symbol ${MOCK_SYMBOL}`); + expect(response).toContain(`on network ${NETWORK_ID}`); + expect(response).toContain(`Transaction hash for the token creation: ${TRANSACTION_HASH}`); + }); + + it("should handle errors when creating a token", async () => { + const args = { + name: MOCK_NAME, + symbol: MOCK_SYMBOL, + tokenUri: MOCK_URI, + }; + + const error = new Error("An error has occurred"); + mockWallet.invokeContract.mockRejectedValue(error); + + const response = await wowCreateToken(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalled(); + expect(response).toContain(`Error creating Zora Wow ERC20 memecoin: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/defi_wow_sell_token_test.ts b/cdp-agentkit-core/src/tests/defi_wow_sell_token_test.ts new file mode 100644 index 0000000..e918ec7 --- /dev/null +++ b/cdp-agentkit-core/src/tests/defi_wow_sell_token_test.ts @@ -0,0 +1,137 @@ +import { Coinbase, ContractInvocation, Wallet } from "@coinbase/coinbase-sdk"; + +import { WOW_ABI } from "../actions/cdp/defi/wow/constants"; +import { wowSellToken, WowSellTokenInput } from "../actions/cdp/defi/wow/actions/sell_token"; +import { getSellQuote } from "../actions/cdp/defi/wow/utils"; +import { getHasGraduated } from "../actions/cdp/defi/wow/uniswap/utils"; + +jest.mock("../actions/cdp/defi/wow/utils", () => ({ + getSellQuote: jest.fn(), +})); + +jest.mock("../actions/cdp/defi/wow/uniswap/utils", () => ({ + getHasGraduated: jest.fn(), +})); + +const MOCK_CONTRACT_ADDRESS = "0x036cbd53842c5426634e7929541ec2318f3dcf7e"; +const MOCK_AMOUNT_TOKENS_IN_WEI = "1000000000000000000"; + +describe("Wow Sell Token Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountTokensInWei: MOCK_AMOUNT_TOKENS_IN_WEI, + }; + + const result = WowSellTokenInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail with missing amountTokensInWei", () => { + const invalidInput = { + contractAddress: MOCK_CONTRACT_ADDRESS, + }; + const result = WowSellTokenInput.safeParse(invalidInput); + + expect(result.success).toBe(false); + }); + + it("does not fail with invalid contract address", () => { + const invalidInput = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountTokensInWei: MOCK_AMOUNT_TOKENS_IN_WEI, + }; + const result = WowSellTokenInput.safeParse(invalidInput); + + expect(result.success).toBe(true); + }); + + it("does not fail with non-numeric amountTokensInWei", () => { + const invalidInput = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountTokensInWei: "not_a_number", + }; + const result = WowSellTokenInput.safeParse(invalidInput); + + expect(result.success).toBe(true); + }); +}); + +describe("Wow Sell Token Action", () => { + const ADDRESS_ID = "0xabcdef123456789"; + const NETWORK_ID = Coinbase.networks.BaseSepolia; + const TRANSACTION_HASH = "0xghijkl987654321"; + + let mockContractInvocation: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockWallet = { + invokeContract: jest.fn(), + getNetworkId: jest.fn().mockReturnValue(NETWORK_ID), + getDefaultAddress: jest.fn().mockResolvedValue({ + getId: jest.fn().mockReturnValue(ADDRESS_ID), + }), + } as unknown as jest.Mocked; + + mockContractInvocation = { + wait: jest.fn().mockResolvedValue({ + getTransaction: jest.fn().mockReturnValue({ + getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH), + }), + }), + } as unknown as jest.Mocked; + + mockWallet.invokeContract.mockResolvedValue(mockContractInvocation); + }); + + it("should successfully sell tokens", async () => { + const args = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountTokensInWei: MOCK_AMOUNT_TOKENS_IN_WEI, + }; + + (getHasGraduated as jest.Mock).mockResolvedValue(true); + (getSellQuote as jest.Mock).mockResolvedValue(1.0); + + const response = await wowSellToken(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalledWith({ + contractAddress: MOCK_CONTRACT_ADDRESS, + method: "sell", + abi: WOW_ABI, + args: { + tokensToSell: MOCK_AMOUNT_TOKENS_IN_WEI, + recipient: expect.any(String), + orderReferrer: "0x0000000000000000000000000000000000000000", + comment: "", + expectedMarketType: "1", + minPayoutSize: expect.any(String), + sqrtPriceLimitX96: "0", + }, + }); + expect(getSellQuote).toHaveBeenCalled(); + expect(getHasGraduated).toHaveBeenCalled(); + expect(response).toContain( + `Sold WoW ERC20 memecoin with transaction hash: ${TRANSACTION_HASH}`, + ); + }); + + it("should handle errors when selling tokens", async () => { + const args = { + contractAddress: MOCK_CONTRACT_ADDRESS, + amountTokensInWei: MOCK_AMOUNT_TOKENS_IN_WEI, + }; + + const error = new Error("An error has occurred"); + mockWallet.invokeContract.mockRejectedValue(error); + (getHasGraduated as jest.Mock).mockResolvedValue(true); + + const response = await wowSellToken(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalled(); + expect(response).toContain(`Error selling Zora Wow ERC20 memecoin: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/deploy_nft_test.ts b/cdp-agentkit-core/src/tests/deploy_nft_test.ts new file mode 100644 index 0000000..2e75e70 --- /dev/null +++ b/cdp-agentkit-core/src/tests/deploy_nft_test.ts @@ -0,0 +1,92 @@ +import { Coinbase, SmartContract, Wallet } from "@coinbase/coinbase-sdk"; + +import { deployNft, DeployNftInput } from "../actions/cdp/deploy_nft"; + +const MOCK_NFT_BASE_URI = "https://www.test.xyz/metadata/"; +const MOCK_NFT_NAME = "Test Token"; +const MOCK_NFT_SYMBOL = "TEST"; + +describe("Deploy NFT Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + baseURI: MOCK_NFT_BASE_URI, + name: MOCK_NFT_NAME, + symbol: MOCK_NFT_SYMBOL, + }; + + const result = DeployNftInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("sould fail parsing empty input", () => { + const emptyInput = {}; + const result = DeployNftInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Deploy NFT Action", () => { + const CONTRACT_ADDRESS = "0x123456789abcdef"; + const NETWORK_ID = Coinbase.networks.BaseSepolia; + const TRANSACTION_HASH = "0xghijkl987654321"; + const TRANSACTION_LINK = `https://etherscan.io/tx/${TRANSACTION_HASH}`; + + let mockSmartContract: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockSmartContract = { + wait: jest.fn().mockResolvedValue({ + getContractAddress: jest.fn().mockReturnValue(CONTRACT_ADDRESS), + getTransaction: jest.fn().mockReturnValue({ + getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH), + getTransactionLink: jest.fn().mockReturnValue(TRANSACTION_LINK), + }), + }), + } as unknown as jest.Mocked; + + mockWallet = { + deployNFT: jest.fn(), + getNetworkId: jest.fn().mockReturnValue(NETWORK_ID), + } as unknown as jest.Mocked; + + mockWallet.deployNFT.mockResolvedValue(mockSmartContract); + }); + + it("should successfully respond", async () => { + const args = { + name: MOCK_NFT_NAME, + symbol: MOCK_NFT_SYMBOL, + baseURI: MOCK_NFT_BASE_URI, + }; + + const response = await deployNft(mockWallet, args); + + expect(mockWallet.deployNFT).toHaveBeenCalledWith(args); + expect(mockSmartContract.wait).toHaveBeenCalled(); + expect(response).toContain(`Deployed NFT Collection ${MOCK_NFT_NAME}`); + expect(response).toContain(`to address ${CONTRACT_ADDRESS}`); + expect(response).toContain(`on network ${NETWORK_ID}`); + expect(response).toContain(`Transaction hash for the deployment: ${TRANSACTION_HASH}`); + expect(response).toContain(`Transaction link for the deployment: ${TRANSACTION_LINK}`); + }); + + it("should fail with an error", async () => { + const args = { + baseURI: MOCK_NFT_BASE_URI, + name: MOCK_NFT_NAME, + symbol: MOCK_NFT_SYMBOL, + }; + + const error = new Error("An error has occured"); + mockWallet.deployNFT.mockRejectedValue(error); + + const response = await deployNft(mockWallet, args); + + expect(mockWallet.deployNFT).toHaveBeenCalledWith(args); + expect(response).toContain(`Error deploying NFT: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/deploy_token_test.ts b/cdp-agentkit-core/src/tests/deploy_token_test.ts new file mode 100644 index 0000000..e55c8de --- /dev/null +++ b/cdp-agentkit-core/src/tests/deploy_token_test.ts @@ -0,0 +1,90 @@ +import { SmartContract, Wallet } from "@coinbase/coinbase-sdk"; + +import { deployToken, DeployTokenInput } from "../actions/cdp/deploy_token"; + +const MOCK_TOKEN_NAME = "Test Token"; +const MOCK_TOKEN_SYMBOL = "TEST"; +const MOCK_TOKEN_SUPPLY = 100; + +describe("Deploy Token Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + name: MOCK_TOKEN_NAME, + symbol: MOCK_TOKEN_SYMBOL, + totalSupply: MOCK_TOKEN_SUPPLY, + }; + + const result = DeployTokenInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = DeployTokenInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Deploy Token Action", () => { + const CONTRACT_ADDRESS = "0x123456789abcdef"; + const TRANSACTION_HASH = "0xghijkl987654321"; + const TRANSACTION_LINK = `https://etherscan.io/tx/${TRANSACTION_HASH}`; + + let mockSmartContract: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockSmartContract = { + wait: jest.fn().mockResolvedValue({ + getContractAddress: jest.fn().mockReturnValue(CONTRACT_ADDRESS), + getTransaction: jest.fn().mockReturnValue({ + getTransactionLink: jest.fn().mockReturnValue(TRANSACTION_LINK), + }), + }), + } as unknown as jest.Mocked; + + mockWallet = { + deployToken: jest.fn(), + } as unknown as jest.Mocked; + + mockWallet.deployToken.mockResolvedValue(mockSmartContract); + }); + + it("should successfully respond", async () => { + const args = { + name: MOCK_TOKEN_NAME, + symbol: MOCK_TOKEN_SYMBOL, + totalSupply: MOCK_TOKEN_SUPPLY, + }; + + const response = await deployToken(mockWallet, args); + + expect(mockWallet.deployToken).toHaveBeenCalledWith(args); + expect(mockSmartContract.wait).toHaveBeenCalled(); + expect(response).toContain( + `Deployed ERC20 token contract ${MOCK_TOKEN_NAME} (${MOCK_TOKEN_SYMBOL})`, + ); + expect(response).toContain(`with total supply of ${MOCK_TOKEN_SUPPLY}`); + expect(response).toContain(`tokens at address ${CONTRACT_ADDRESS}`); + expect(response).toContain(`Transaction link: ${TRANSACTION_LINK}`); + }); + + it("should fail with an error", async () => { + const args = { + name: MOCK_TOKEN_NAME, + symbol: MOCK_TOKEN_SYMBOL, + totalSupply: MOCK_TOKEN_SUPPLY, + }; + + const error = new Error("An error has occured"); + mockWallet.deployToken.mockRejectedValue(error); + + const response = await deployToken(mockWallet, args); + + expect(mockWallet.deployToken).toHaveBeenCalledWith(args); + expect(response).toContain(`Error deploying token: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/get_balance_test.ts b/cdp-agentkit-core/src/tests/get_balance_test.ts new file mode 100644 index 0000000..aaf0229 --- /dev/null +++ b/cdp-agentkit-core/src/tests/get_balance_test.ts @@ -0,0 +1,85 @@ +import { Wallet, WalletAddress } from "@coinbase/coinbase-sdk"; +import { getBalance, GetBalanceInput } from "../actions/cdp/get_balance"; + +const MOCK_ASSET_ID = "test-asset-id"; +const MOCK_BALANCE = 1000000000000000000; + +describe("Get Balance Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + assetId: MOCK_ASSET_ID, + }; + + const result = GetBalanceInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = GetBalanceInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Get Balance Action", () => { + const WALLET_ID = "0x123456789abcdef"; + + let mockAddresses: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockAddresses = [ + { + getId: jest.fn().mockReturnValue("test-address-id-1"), + getBalance: jest.fn().mockReturnValue(MOCK_BALANCE), + } as unknown as jest.Mocked, + { + getId: jest.fn().mockReturnValue("test-address-id-2"), + getBalance: jest.fn().mockReturnValue(0.0), + } as unknown as jest.Mocked, + { + getId: jest.fn().mockReturnValue("test-address-id-3"), + getBalance: jest.fn().mockReturnValue(MOCK_BALANCE), + } as unknown as jest.Mocked, + ] as unknown as jest.Mocked[]; + + mockWallet = { + getId: jest.fn().mockReturnValue(WALLET_ID), + listAddresses: jest.fn(), + } as unknown as jest.Mocked; + + mockWallet.listAddresses.mockResolvedValue(mockAddresses); + }); + + it("should successfully respond", async () => { + const args = { + assetId: MOCK_ASSET_ID, + }; + + const response = await getBalance(mockWallet, args); + + expect(mockWallet.listAddresses).toHaveBeenCalledWith(); + mockAddresses.forEach(address => { + expect(address.getBalance).toHaveBeenCalledWith(MOCK_ASSET_ID); + expect(response).toContain(`${address.getId()}: ${address.getBalance(MOCK_ASSET_ID)}`); + }); + expect(response).toContain(`Balances for wallet ${WALLET_ID}`); + }); + + it("should fail with an error", async () => { + const args = { + assetId: MOCK_ASSET_ID, + }; + + const error = new Error("An error has occured"); + mockWallet.listAddresses.mockRejectedValue(error); + + const response = await getBalance(mockWallet, args); + + expect(mockWallet.listAddresses).toHaveBeenCalled(); + expect(response).toContain(`Error getting balance for all addresses in the wallet: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/get_wallet_details_test.ts b/cdp-agentkit-core/src/tests/get_wallet_details_test.ts new file mode 100644 index 0000000..0871152 --- /dev/null +++ b/cdp-agentkit-core/src/tests/get_wallet_details_test.ts @@ -0,0 +1,58 @@ +import { Coinbase, Wallet, WalletAddress } from "@coinbase/coinbase-sdk"; + +import { getWalletDetails, GetWalletDetailsInput } from "../actions/cdp/get_wallet_details"; + +describe("Wallet Details Input", () => { + it("should successfully parse empty input", () => { + const emptyInput = {}; + const result = GetWalletDetailsInput.safeParse(emptyInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(emptyInput); + }); +}); + +describe("Wallet Details Action", () => { + const ADDRESS_ID = "0xabcdef123456789"; + const NETWORK_ID = Coinbase.networks.BaseSepolia; + const WALLET_ID = "0x123456789abcdef"; + + let mockAddress: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockAddress = { + getId: jest.fn().mockReturnValue(ADDRESS_ID), + } as unknown as jest.Mocked; + + mockWallet = { + getDefaultAddress: jest.fn(), + getId: jest.fn().mockReturnValue(WALLET_ID), + getNetworkId: jest.fn().mockReturnValue(NETWORK_ID), + } as unknown as jest.Mocked; + + mockWallet.getDefaultAddress.mockResolvedValue(mockAddress); + }); + + it("should successfully respond", async () => { + const args = {}; + const response = await getWalletDetails(mockWallet, args); + + expect(mockWallet.getDefaultAddress).toHaveBeenCalled(); + expect(response).toContain(`Wallet: ${WALLET_ID}`); + expect(response).toContain(`on network: ${NETWORK_ID}`); + expect(response).toContain(`with default address: ${ADDRESS_ID}`); + }); + + it("should fail with an error", async () => { + const args = {}; + + const error = new Error("An error has occured"); + mockWallet.getDefaultAddress.mockRejectedValue(error); + + const response = await getWalletDetails(mockWallet, args); + + expect(mockWallet.getDefaultAddress).toHaveBeenCalled(); + expect(response).toContain(`Error getting wallet details: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/mint_nft_test.ts b/cdp-agentkit-core/src/tests/mint_nft_test.ts new file mode 100644 index 0000000..8b7f6cc --- /dev/null +++ b/cdp-agentkit-core/src/tests/mint_nft_test.ts @@ -0,0 +1,93 @@ +import { Coinbase, ContractInvocation, Wallet } from "@coinbase/coinbase-sdk"; + +import { mintNft, MintNftInput } from "../actions/cdp/mint_nft"; + +const MOCK_CONTRACT_ADDRESS = "0x123456789abcdef"; +const MOCK_CONTRACT_DESTINATION = "0xabcdef123456789"; + +describe("Mint NFT Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + contractAddress: MOCK_CONTRACT_ADDRESS, + destination: MOCK_CONTRACT_DESTINATION, + }; + + const result = MintNftInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = MintNftInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Mint NFT Action", () => { + const NETWORK_ID = Coinbase.networks.BaseSepolia; + const TRANSACTION_HASH = "0xghijkl987654321"; + const TRANSACTION_LINK = `https://etherscan.io/tx/${TRANSACTION_HASH}`; + + let mockContractInvocation: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockContractInvocation = { + wait: jest.fn().mockResolvedValue({ + getTransaction: jest.fn().mockReturnValue({ + getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH), + getTransactionLink: jest.fn().mockReturnValue(TRANSACTION_LINK), + }), + }), + } as unknown as jest.Mocked; + + mockWallet = { + invokeContract: jest.fn(), + getNetworkId: jest.fn().mockReturnValue(NETWORK_ID), + } as unknown as jest.Mocked; + + mockWallet.invokeContract.mockResolvedValue(mockContractInvocation); + }); + + it("should successfully respond", async () => { + const args = { + contractAddress: MOCK_CONTRACT_ADDRESS, + destination: MOCK_CONTRACT_DESTINATION, + }; + + const response = await mintNft(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalledWith({ + contractAddress: MOCK_CONTRACT_ADDRESS, + method: "mint", + args: { + to: MOCK_CONTRACT_DESTINATION, + quantity: "1", + }, + }); + expect(mockContractInvocation.wait).toHaveBeenCalled(); + expect(response).toContain(`Minted NFT from contract ${MOCK_CONTRACT_ADDRESS}`); + expect(response).toContain(`to address ${MOCK_CONTRACT_DESTINATION}`); + expect(response).toContain(`on network ${NETWORK_ID}`); + expect(response).toContain(`Transaction hash for the mint: ${TRANSACTION_HASH}`); + expect(response).toContain(`Transaction link for the mint: ${TRANSACTION_LINK}`); + }); + + it("should fail with an error", async () => { + const args = { + contractAddress: MOCK_CONTRACT_ADDRESS, + destination: MOCK_CONTRACT_DESTINATION, + }; + + const error = new Error("An error has occured"); + mockWallet.invokeContract.mockRejectedValue(error); + + const response = await mintNft(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalled(); + expect(response).toContain(`Error minting NFT: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/register_basename_test.ts b/cdp-agentkit-core/src/tests/register_basename_test.ts new file mode 100644 index 0000000..138d333 --- /dev/null +++ b/cdp-agentkit-core/src/tests/register_basename_test.ts @@ -0,0 +1,176 @@ +import { Coinbase, ContractInvocation, Wallet } from "@coinbase/coinbase-sdk"; + +import { Decimal } from "decimal.js"; +import { encodeFunctionData, namehash } from "viem"; + +import { + registerBasename, + RegisterBasenameInput, + BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_MAINNET, + BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_TESTNET, + L2_RESOLVER_ABI, + L2_RESOLVER_ADDRESS_MAINNET, + L2_RESOLVER_ADDRESS_TESTNET, + REGISTRATION_DURATION, + REGISTRAR_ABI, +} from "../actions/cdp/register_basename"; + +const MOCK_AMOUNT = "0.123"; +const MOCK_BASENAME = "test-basename"; + +describe("Register Basename Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + amount: MOCK_AMOUNT, + basename: MOCK_BASENAME, + }; + + const result = RegisterBasenameInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = RegisterBasenameInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Register Basename Action", () => { + /** + * This is the default network. + */ + const NETWORK_ID = Coinbase.networks.BaseMainnet; + + /** + * This is a 40 character hexadecimal string that requires lowercase alpha characters. + */ + const ADDRESS_ID = "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83"; + + let mockContractInvocation: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockContractInvocation = { + wait: jest.fn().mockResolvedValue({}), + } as unknown as jest.Mocked; + + mockWallet = { + getDefaultAddress: jest.fn().mockResolvedValue({ + getId: jest.fn().mockReturnValue(ADDRESS_ID), + }), + getNetworkId: jest.fn().mockReturnValue(NETWORK_ID), + invokeContract: jest.fn(), + } as unknown as jest.Mocked; + + mockWallet.invokeContract.mockResolvedValue(mockContractInvocation); + }); + + it(`should Successfully respond with ${MOCK_BASENAME}.base.eth for network: ${Coinbase.networks.BaseMainnet}`, async () => { + const args = { + amount: MOCK_AMOUNT, + basename: MOCK_BASENAME, + }; + + const name = `${MOCK_BASENAME}.base.eth`; + + mockWallet.getNetworkId.mockReturnValue(Coinbase.networks.BaseMainnet); + + const response = await registerBasename(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalledWith({ + contractAddress: BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_MAINNET, + method: "register", + args: { + request: [ + MOCK_BASENAME, + ADDRESS_ID, + REGISTRATION_DURATION, + L2_RESOLVER_ADDRESS_MAINNET, + [ + encodeFunctionData({ + abi: L2_RESOLVER_ABI, + functionName: "setAddr", + args: [namehash(name), ADDRESS_ID], + }), + encodeFunctionData({ + abi: L2_RESOLVER_ABI, + functionName: "setName", + args: [namehash(name), name], + }), + ], + true, + ], + }, + abi: REGISTRAR_ABI, + amount: new Decimal(MOCK_AMOUNT), + assetId: "eth", + }); + expect(mockContractInvocation.wait).toHaveBeenCalled(); + expect(response).toContain(`Successfully registered basename ${MOCK_BASENAME}.base.eth`); + expect(response).toContain(`for address ${ADDRESS_ID}`); + }); + + it(`should Successfully respond with ${MOCK_BASENAME}.basetest.eth for any other network`, async () => { + const args = { + amount: MOCK_AMOUNT, + basename: MOCK_BASENAME, + }; + + const name = `${MOCK_BASENAME}.basetest.eth`; + + mockWallet.getNetworkId.mockReturnValue("anything-else"); + + const response = await registerBasename(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalledWith({ + contractAddress: BASENAMES_REGISTRAR_CONTROLLER_ADDRESS_TESTNET, + method: "register", + args: { + request: [ + MOCK_BASENAME, + ADDRESS_ID, + REGISTRATION_DURATION, + L2_RESOLVER_ADDRESS_TESTNET, + [ + encodeFunctionData({ + abi: L2_RESOLVER_ABI, + functionName: "setAddr", + args: [namehash(name), ADDRESS_ID], + }), + encodeFunctionData({ + abi: L2_RESOLVER_ABI, + functionName: "setName", + args: [namehash(name), name], + }), + ], + true, + ], + }, + abi: REGISTRAR_ABI, + amount: new Decimal(MOCK_AMOUNT), + assetId: "eth", + }); + expect(mockContractInvocation.wait).toHaveBeenCalled(); + expect(response).toContain(`Successfully registered basename ${MOCK_BASENAME}.basetest.eth`); + expect(response).toContain(`for address ${ADDRESS_ID}`); + }); + + it("should fail with an error", async () => { + const args = { + amount: MOCK_AMOUNT, + basename: MOCK_BASENAME, + }; + + const error = new Error("Failed to register basename"); + mockWallet.invokeContract.mockRejectedValue(error); + + await registerBasename(mockWallet, args); + + expect(mockWallet.invokeContract).toHaveBeenCalled(); + expect(`Error registering basename: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/request_faucet_funds_test.ts b/cdp-agentkit-core/src/tests/request_faucet_funds_test.ts new file mode 100644 index 0000000..605f01e --- /dev/null +++ b/cdp-agentkit-core/src/tests/request_faucet_funds_test.ts @@ -0,0 +1,78 @@ +import { Coinbase, FaucetTransaction, Wallet } from "@coinbase/coinbase-sdk"; + +import { requestFaucetFunds, RequestFaucetFundsInput } from "../actions/cdp/request_faucet_funds"; + +const MOCK_ASSET_ID = Coinbase.assets.Usdc; + +describe("Request Faucet Funds Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + assetId: MOCK_ASSET_ID, + }; + + const result = RequestFaucetFundsInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should successfully parsing empty input", () => { + const emptyInput = {}; + const result = RequestFaucetFundsInput.safeParse(emptyInput); + + expect(result.success).toBe(true); + }); +}); + +describe("Request Faucet Funds Action", () => { + const TRANSACTION_HASH = "0xghijkl987654321"; + const TRANSACTION_LINK = `https://etherscan.io/tx/${TRANSACTION_HASH}`; + + let mockFaucetTransaction: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(() => { + mockFaucetTransaction = { + wait: jest.fn().mockResolvedValue({ + getTransactionLink: jest.fn().mockReturnValue(TRANSACTION_LINK), + }), + } as unknown as jest.Mocked; + + mockWallet = { + faucet: jest.fn(), + } as unknown as jest.Mocked; + + mockWallet.faucet.mockResolvedValue(mockFaucetTransaction); + }); + + it("should successfully request faucet funds", async () => { + const args = {}; + const response = await requestFaucetFunds(mockWallet, args); + + expect(mockWallet.faucet).toHaveBeenCalled(); + expect(mockFaucetTransaction.wait).toHaveBeenCalled(); + expect(response).toContain(`Received ETH from the faucet. Transaction: ${TRANSACTION_LINK}`); + }); + + it("should successfully request faucet funds with an asset id", async () => { + const args = { assetId: MOCK_ASSET_ID }; + const response = await requestFaucetFunds(mockWallet, args); + + expect(mockWallet.faucet).toHaveBeenCalledWith(MOCK_ASSET_ID); + expect(mockFaucetTransaction.wait).toHaveBeenCalled(); + expect(response).toContain(`Received ${MOCK_ASSET_ID} from the faucet`); + expect(response).toContain(`Transaction: ${TRANSACTION_LINK}`); + }); + + it("should fail with an error", async () => { + const args = { assetId: MOCK_ASSET_ID }; + + const error = new Error("Failed to request funds"); + mockWallet.faucet.mockRejectedValue(error); + + const response = await requestFaucetFunds(mockWallet, args); + + expect(mockWallet.faucet).toHaveBeenCalled(); + expect(response).toContain(`Error requesting faucet funds: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/trade_test.ts b/cdp-agentkit-core/src/tests/trade_test.ts new file mode 100644 index 0000000..89804a2 --- /dev/null +++ b/cdp-agentkit-core/src/tests/trade_test.ts @@ -0,0 +1,90 @@ +import { Coinbase, Trade, Wallet } from "@coinbase/coinbase-sdk"; + +import { trade as createTrade, TradeInput } from "../actions/cdp/trade"; + +const MOCK_TRADE_AMOUNT = 0.123; +const MOCK_TRADE_ASSET_ID_FROM = Coinbase.assets.Eth; +const MOCK_TRADE_ASSET_ID_TO = Coinbase.assets.Usdc; + +describe("Trade Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + amount: MOCK_TRADE_AMOUNT, + fromAssetId: MOCK_TRADE_ASSET_ID_FROM, + toAssetId: MOCK_TRADE_ASSET_ID_TO, + }; + + const result = TradeInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = TradeInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Trade Action", () => { + const TO_AMOUNT = 3661.08; + const TRANSACTION_HASH = "0xghijkl987654321"; + const TRANSACTION_LINK = `https://etherscan.io/tx/${TRANSACTION_HASH}`; + + let mockTrade: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(async () => { + mockTrade = { + wait: jest.fn().mockResolvedValue({ + getToAmount: jest.fn().mockReturnValue(TO_AMOUNT), + getTransaction: jest.fn().mockReturnValue({ + getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH), + getTransactionLink: jest.fn().mockReturnValue(TRANSACTION_LINK), + }), + }), + } as unknown as jest.Mocked; + + mockWallet = { + createTrade: jest.fn(), + } as unknown as jest.Mocked; + + mockWallet.createTrade.mockResolvedValue(mockTrade); + }); + + it("should successfully execute the trade", async () => { + const args = { + amount: MOCK_TRADE_AMOUNT, + fromAssetId: MOCK_TRADE_ASSET_ID_FROM, + toAssetId: MOCK_TRADE_ASSET_ID_TO, + }; + + const response = await createTrade(mockWallet, args); + + expect(mockWallet.createTrade).toHaveBeenCalledWith(args); + expect(mockTrade.wait).toHaveBeenCalled(); + expect(response).toContain( + `Traded ${MOCK_TRADE_AMOUNT} of ${MOCK_TRADE_ASSET_ID_FROM} for ${TO_AMOUNT} of ${MOCK_TRADE_ASSET_ID_TO}`, + ); + expect(response).toContain(`Transaction hash for the trade: ${TRANSACTION_HASH}`); + expect(response).toContain(`Transaction link for the trade: ${TRANSACTION_LINK}`); + }); + + it("should fail with an error", async () => { + const args = { + amount: MOCK_TRADE_AMOUNT, + fromAssetId: MOCK_TRADE_ASSET_ID_FROM, + toAssetId: MOCK_TRADE_ASSET_ID_TO, + }; + + const error = new Error("Failed to execute trade"); + mockWallet.createTrade.mockRejectedValue(error); + + const response = await createTrade(mockWallet, args); + + expect(mockWallet.createTrade).toHaveBeenCalled(); + expect(response).toContain(`Error trading assets: ${error}`); + }); +}); diff --git a/cdp-agentkit-core/src/tests/transfer_test.ts b/cdp-agentkit-core/src/tests/transfer_test.ts new file mode 100644 index 0000000..bf3caf7 --- /dev/null +++ b/cdp-agentkit-core/src/tests/transfer_test.ts @@ -0,0 +1,90 @@ +import { Coinbase, Transfer, Wallet } from "@coinbase/coinbase-sdk"; + +import { transfer as createTransfer, TransferInput } from "../actions/cdp/transfer"; + +const MOCK_AMOUNT = 15; +const MOCK_ASSET_ID = Coinbase.assets.Eth; +const MOCK_DESTINATION = "0x321"; +const MOCK_GASLESS = true; + +describe("Transfer Input", () => { + it("should successfully parse valid input", () => { + const validInput = { + amount: MOCK_AMOUNT, + assetId: MOCK_ASSET_ID, + destination: MOCK_DESTINATION, + gasless: MOCK_GASLESS, + }; + + const result = TransferInput.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = TransferInput.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Transfer Action", () => { + const TRANSACTION_HASH = "0xghijkl987654321"; + const TRANSACTION_LINK = `https://etherscan.io/tx/${TRANSACTION_HASH}`; + + let mockTransfer: jest.Mocked; + let mockWallet: jest.Mocked; + + beforeEach(async () => { + mockTransfer = { + wait: jest.fn().mockResolvedValue({ + getTransactionHash: jest.fn().mockReturnValue(TRANSACTION_HASH), + getTransactionLink: jest.fn().mockReturnValue(TRANSACTION_LINK), + }), + } as unknown as jest.Mocked; + + mockWallet = { + createTransfer: jest.fn(), + } as unknown as jest.Mocked; + + mockWallet.createTransfer.mockResolvedValue(mockTransfer); + }); + + it("should successfully respond", async () => { + const args = { + amount: MOCK_AMOUNT, + assetId: MOCK_ASSET_ID, + destination: MOCK_DESTINATION, + gasless: MOCK_GASLESS, + }; + + const response = await createTransfer(mockWallet, args); + + expect(mockWallet.createTransfer).toHaveBeenCalledWith(args); + expect(mockTransfer.wait).toHaveBeenCalled(); + expect(response).toContain( + `Transferred ${MOCK_AMOUNT} of ${MOCK_ASSET_ID} to ${MOCK_DESTINATION}`, + ); + expect(response).toContain(`Transaction hash for the transfer: ${TRANSACTION_HASH}`); + expect(response).toContain(`Transaction link for the transfer: ${TRANSACTION_LINK}`); + }); + + it("should fail with an error", async () => { + const args = { + amount: MOCK_AMOUNT, + assetId: MOCK_ASSET_ID, + destination: MOCK_DESTINATION, + gasless: MOCK_GASLESS, + }; + + const error = new Error("Failed to execute transfer"); + mockWallet.createTransfer.mockRejectedValue(error); + + const response = await createTransfer(mockWallet, args); + + expect(mockWallet.createTransfer).toHaveBeenCalledWith(args); + expect(response).toContain(`Error transferring the asset: ${error}`); + }); +}); diff --git a/cdp-langchain/jest.config.js b/cdp-langchain/jest.config.cjs similarity index 69% rename from cdp-langchain/jest.config.js rename to cdp-langchain/jest.config.cjs index fcd6a9a..b650291 100644 --- a/cdp-langchain/jest.config.js +++ b/cdp-langchain/jest.config.cjs @@ -1,11 +1,11 @@ -import baseConfig from "../jest.config.base.js"; +const baseConfig = require("../jest.config.base.cjs"); -export default { +module.exports = { ...baseConfig, coveragePathIgnorePatterns: ["node_modules", "dist", "docs", "index.ts"], coverageThreshold: { "./src/**": { - branches: 50, + branches: 30, functions: 50, statements: 50, lines: 50, diff --git a/cdp-langchain/package.json b/cdp-langchain/package.json index 5377eb8..dfcc4ad 100644 --- a/cdp-langchain/package.json +++ b/cdp-langchain/package.json @@ -4,9 +4,7 @@ "description": "Langchain Toolkit extension of CDP Agentkit", "main": "dist/index.js", "types": "dist/index.d.ts", - "files": [ - "dist" - ], + "files": ["dist"], "scripts": { "build": "tsc", "lint": "npx --yes eslint -c .eslintrc.json src/**/*.ts", @@ -14,7 +12,7 @@ "format": "npx --yes prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", "format-check": "npx --yes prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", "check": "tsc --noEmit", - "test": "npx --yes jest --no-cache --testMatch=**/*_test.ts", + "test": "npx jest --no-cache --testMatch='**/*_test.ts'", "test:dry-run": "npm install && npm ci && npm publish --dry-run", "test:e2e": "npx jest --no-cache --testMatch=**/e2e.ts --coverageThreshold '{}'", "test:types": "tsd --files src/tests/types.test-d.ts", @@ -41,5 +39,8 @@ "@coinbase/coinbase-sdk": "^0.11.0", "@langchain/core": "^0.3.19", "zod": "^3.22.4" + }, + "peerDependencies": { + "@coinbase/coinbase-sdk": "^0.11.0" } } diff --git a/cdp-langchain/src/tests/cdp_tool_test.ts b/cdp-langchain/src/tests/cdp_tool_test.ts new file mode 100644 index 0000000..2925541 --- /dev/null +++ b/cdp-langchain/src/tests/cdp_tool_test.ts @@ -0,0 +1,88 @@ +import { Wallet } from "@coinbase/coinbase-sdk"; + +import { CdpAgentkit } from "@coinbase/cdp-agentkit-core"; + +import { CdpTool } from "../tools/cdp_tool"; + +import { z } from "zod"; + +describe("CdpTool", () => { + let agentkit: CdpAgentkit; + let mockWallet: jest.Mocked; + + beforeAll(async () => { + mockWallet = {} as unknown as jest.Mocked; + jest.spyOn(Wallet, "create").mockResolvedValue(mockWallet); + }); + + describe("initialization", () => { + beforeEach(async () => { + const options = { + cdpApiKeyName: "test-key", + cdpApiKeyPrivateKey: "test-private-key", + wallet: mockWallet, + }; + + agentkit = await CdpAgentkit.configureWithWallet(options); + }); + + it("should be successful", async () => { + expect( + new CdpTool( + { + name: "test-tool", + description: "test-tool-description", + argsSchema: z.object({}), + func: jest.fn().mockReturnValue({}), + }, + agentkit, + ), + ).toBeDefined(); + }); + + describe("call", () => { + let inputSchema; + let tool; + + beforeAll(() => { + inputSchema = z + .object({ + property: z.string().describe("a property for input"), + }) + .strip() + .describe("mock tool input"); + + const toolFn = async (input: z.infer) => { + return `expected-return with property: ${input.property}`; + }; + + tool = new CdpTool( + { + name: "test-tool", + description: "test-tool-description", + argsSchema: inputSchema, + func: toolFn, + }, + agentkit, + ); + }); + + it("should be successful", async () => { + const args = { property: "value" }; + const result = await tool.call(args); + + expect(result).toEqual(`expected-return with property: ${args.property}`); + }); + + it("should be successful with valid input", () => { + const args = { property: "value" }; + expect(tool.call(args)).toBeDefined(); + }); + + it("should fail with invalid input", () => { + const args = {}; + expect(tool.call(args)).rejects.toThrow(); + }); + }); + }); +}); diff --git a/cdp-langchain/src/tests/cdp_toolkit_test.ts b/cdp-langchain/src/tests/cdp_toolkit_test.ts new file mode 100644 index 0000000..553674f --- /dev/null +++ b/cdp-langchain/src/tests/cdp_toolkit_test.ts @@ -0,0 +1,71 @@ +import { Wallet } from "@coinbase/coinbase-sdk"; +import { CdpAgentkit } from "@coinbase/cdp-agentkit-core"; +import { CdpToolkit } from "../toolkits/cdp_toolkit"; + +describe("CdpToolkit", () => { + const WALLET_ID = "0x123456789abcdef"; + const WALLET_SEED = "0xc746290109d0b86162c428be6e27f552"; + const WALLET_JSON = `{"defaultAddressId":"0xabcdef123456789", "seed":"${WALLET_SEED}", "walletId":"${WALLET_ID}"}`; + + let mockWallet: jest.Mocked; + + beforeEach(async () => { + process.env.CDP_API_KEY_NAME = "test-key"; + process.env.CDP_API_KEY_PRIVATE_KEY = "test-private-key"; + + mockWallet = {} as unknown as jest.Mocked; + jest.spyOn(Wallet, "create").mockResolvedValue(mockWallet); + }); + + describe("initialization", () => { + it("should successfully init with env", async () => { + const options = {}; + await expect(CdpAgentkit.configureWithWallet(options)).resolves.toBeDefined(); + }); + + it("should successfully init with options and without env", async () => { + const options = { + cdpApiKeyName: "test-key", + cdpApiKeyPrivateKey: "test-private-key", + }; + + process.env.CDP_API_KEY_NAME = ""; + process.env.CDP_API_KEY_PRIVATE_KEY = ""; + + await expect(CdpAgentkit.configureWithWallet(options)).resolves.toBeDefined(); + }); + + it("should successfully init with wallet data", async () => { + const options = { + cdpWalletData: WALLET_JSON, + }; + + jest.spyOn(Wallet, "import").mockResolvedValue(mockWallet); + + expect(await CdpAgentkit.configureWithWallet(options)).toBeDefined(); + }); + + it("should fail init without env", async () => { + const options = {}; + + process.env.CDP_API_KEY_NAME = ""; + process.env.CDP_API_KEY_PRIVATE_KEY = ""; + + await expect(CdpAgentkit.configureWithWallet(options)).rejects.toThrow(); + }); + }); + + it("should successfully return tools for CDP actions", async () => { + const options = { + cdpApiKeyName: "test-key", + cdpApiKeyPrivateKey: "test-private-key", + }; + + const agentkit = await CdpAgentkit.configureWithWallet(options); + const toolkit = new CdpToolkit(agentkit); + const tools = toolkit.getTools(); + + expect(tools).toBeDefined(); + expect(tools.length).toBeGreaterThan(0); + }); +}); diff --git a/jest.config.base.js b/jest.config.base.cjs similarity index 95% rename from jest.config.base.js rename to jest.config.base.cjs index 1626281..c614ded 100644 --- a/jest.config.base.js +++ b/jest.config.base.cjs @@ -1,4 +1,4 @@ -export default { +module.exports = { preset: "ts-jest", testEnvironment: "node", extensionsToTreatAsEsm: [".ts"], diff --git a/package-lock.json b/package-lock.json index 98f8b76..de66bee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,9 @@ "cdp-agentkit-core", "cdp-langchain" ], + "dependencies": { + "@coinbase/cdp-agentkit-core": "^0.0.5" + }, "devDependencies": { "@types/jest": "^29.5.14", "@types/node": "^20.12.11", @@ -36,30 +39,28 @@ "zod": "^3.23.8" }, "devDependencies": { + "@types/jest": "^29.5.14", "@types/secp256k1": "^4.0.6", "http-server": "^14.1.1", + "jest": "^29.7.0", "mock-fs": "^5.2.0", - "tsd": "^0.31.2" + "ts-jest": "^29.2.5", + "tsd": "^0.31.2", + "typescript": "^5.7.2" } }, - "cdp-agentkit-core/node_modules/@coinbase/coinbase-sdk": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@coinbase/coinbase-sdk/-/coinbase-sdk-0.11.0.tgz", - "integrity": "sha512-BbZy3FsCoZ4TklVmiDV6uMbjBZqqxHrFuzrFWa2gNJv7azNzCasXRwppBqlIb02M3lAukbtvzJHXoA8z4q69EQ==", - "dependencies": { - "@scure/bip32": "^1.4.0", - "abitype": "^1.0.6", - "axios": "^1.6.8", - "axios-mock-adapter": "^1.22.0", - "axios-retry": "^4.4.1", - "bip32": "^4.0.0", - "bip39": "^3.1.0", - "decimal.js": "^10.4.3", - "dotenv": "^16.4.5", - "ethers": "^6.12.1", - "node-jose": "^2.2.0", - "secp256k1": "^5.0.0", - "viem": "^2.21.26" + "cdp-agentkit-core/node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, "cdp-langchain": { @@ -70,27 +71,9 @@ "@coinbase/coinbase-sdk": "^0.11.0", "@langchain/core": "^0.3.19", "zod": "^3.22.4" - } - }, - "cdp-langchain/node_modules/@coinbase/coinbase-sdk": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/@coinbase/coinbase-sdk/-/coinbase-sdk-0.11.1.tgz", - "integrity": "sha512-PD24P3Xh7GqUzS/j78YPCyCDprLilY6kxyHFofbCSx2nAl9soI6OGu0Kmtw1aft53r20X3jUcA/Eo14xNnluMg==", - "license": "ISC", - "dependencies": { - "@scure/bip32": "^1.4.0", - "abitype": "^1.0.6", - "axios": "^1.6.8", - "axios-mock-adapter": "^1.22.0", - "axios-retry": "^4.4.1", - "bip32": "^4.0.0", - "bip39": "^3.1.0", - "decimal.js": "^10.4.3", - "dotenv": "^16.4.5", - "ethers": "^6.12.1", - "node-jose": "^2.2.0", - "secp256k1": "^5.0.0", - "viem": "^2.21.26" + }, + "peerDependencies": { + "@coinbase/coinbase-sdk": "^0.11.0" } }, "node_modules/@adraffy/ens-normalize": { @@ -598,6 +581,27 @@ "resolved": "cdp-langchain", "link": true }, + "node_modules/@coinbase/coinbase-sdk": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@coinbase/coinbase-sdk/-/coinbase-sdk-0.11.1.tgz", + "integrity": "sha512-PD24P3Xh7GqUzS/j78YPCyCDprLilY6kxyHFofbCSx2nAl9soI6OGu0Kmtw1aft53r20X3jUcA/Eo14xNnluMg==", + "license": "ISC", + "dependencies": { + "@scure/bip32": "^1.4.0", + "abitype": "^1.0.6", + "axios": "^1.6.8", + "axios-mock-adapter": "^1.22.0", + "axios-retry": "^4.4.1", + "bip32": "^4.0.0", + "bip39": "^3.1.0", + "decimal.js": "^10.4.3", + "dotenv": "^16.4.5", + "ethers": "^6.12.1", + "node-jose": "^2.2.0", + "secp256k1": "^5.0.0", + "viem": "^2.21.26" + } + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.46.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", @@ -644,7 +648,6 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -668,36 +671,16 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -710,7 +693,6 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -721,7 +703,6 @@ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -736,7 +717,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -747,7 +727,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -773,8 +752,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -1606,7 +1584,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -1640,7 +1617,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -1669,7 +1645,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" @@ -1687,7 +1662,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", @@ -1715,7 +1689,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -1729,7 +1702,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", @@ -1758,7 +1730,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -1781,7 +1752,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" @@ -1798,8 +1768,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/abitype": { "version": "1.0.6", @@ -1878,7 +1847,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1973,8 +1941,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" + "dev": true }, "node_modules/array-union": { "version": "2.1.0", @@ -2802,7 +2769,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -2942,7 +2908,6 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -3062,6 +3027,35 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint-plugin-prettier": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", @@ -3103,7 +3097,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -3137,24 +3130,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3168,31 +3143,17 @@ } }, "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "eslint-visitor-keys": "^3.4.1" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3228,7 +3189,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3250,7 +3210,6 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -3454,7 +3413,6 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -3516,7 +3474,6 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, - "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -3530,8 +3487,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/follow-redirects": { "version": "1.15.9", @@ -3733,7 +3689,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -4067,7 +4022,6 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4237,7 +4191,6 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -4986,7 +4939,6 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -5019,8 +4971,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -5032,8 +4983,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -5064,7 +5014,6 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -5855,7 +5804,6 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -6167,7 +6115,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -6451,7 +6398,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -6489,7 +6435,6 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -6970,8 +6915,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tmpl": { "version": "1.0.5", @@ -7012,7 +6956,6 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -7216,7 +7159,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -7315,7 +7257,6 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -7706,19 +7647,6 @@ "peerDependencies": { "zod": "^3.23.3" } - }, - "twitter-langchain": { - "name": "@coinbase/twitter-langchain", - "version": "0.0.1", - "extraneous": true, - "dependencies": { - "@coinbase/cdp-langchain": "*", - "@langchain/core": "^0.3.19", - "twitter-api-sdk": "^1.2.1" - }, - "peerDependencies": { - "@coinbase/coinbase-sdk": "^0.10.0" - } } } } diff --git a/package.json b/package.json index 53c6063..f2cabbb 100644 --- a/package.json +++ b/package.json @@ -33,19 +33,22 @@ "langchain" ], "devDependencies": { - "turbo": "^1.12.4", - "typescript": "^5.4.5", - "@types/node": "^20.12.11", - "jest": "^29.7.0", - "ts-jest": "^29.2.5", - "eslint": "^8.57.0", - "prettier": "^3.2.5", "@types/jest": "^29.5.14", + "@types/node": "^20.12.11", "@typescript-eslint/eslint-plugin": "^7.8.0", "@typescript-eslint/parser": "^7.8.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-jsdoc": "^48.2.5", "eslint-plugin-prettier": "^5.1.3", - "typedoc": "^0.25.13" + "jest": "^29.7.0", + "prettier": "^3.2.5", + "ts-jest": "^29.2.5", + "turbo": "^1.12.4", + "typedoc": "^0.25.13", + "typescript": "^5.4.5" + }, + "dependencies": { + "@coinbase/cdp-agentkit-core": "^0.0.5" } }