diff --git a/README.md b/README.md
index d00020f08..439ae5a8f 100644
--- a/README.md
+++ b/README.md
@@ -143,6 +143,7 @@ agentkit/
│ │ └── wallet-providers/
│ │ ├── cdp/
│ │ ├── privy/
+| | ├── dynamic/
│ │ └── viem/
│ │ └── scripts/generate-action-provider/ # use this to create new actions
│ ├── create-onchain-agent/
@@ -156,6 +157,7 @@ agentkit/
│ ├── langchain-farcaster-chatbot/
│ ├── langchain-legacy-cdp-chatbot/
│ ├── langchain-privy-chatbot/
+| ├── langchain-dynamic-chatbot/
│ ├── langchain-solana-chatbot/
│ ├── langchain-twitter-chatbot/
│ ├── langchain-xmtp-chatbot/
@@ -273,6 +275,7 @@ AgentKit is proud to have support for the following protocols, frameworks, walle
### Wallets
+
diff --git a/assets/wallets/dynamic.svg b/assets/wallets/dynamic.svg
new file mode 100644
index 000000000..05a3b0399
--- /dev/null
+++ b/assets/wallets/dynamic.svg
@@ -0,0 +1,15 @@
+
diff --git a/typescript/.changeset/small-banks-reply.md b/typescript/.changeset/small-banks-reply.md
new file mode 100644
index 000000000..8b7af6ff1
--- /dev/null
+++ b/typescript/.changeset/small-banks-reply.md
@@ -0,0 +1,6 @@
+---
+"langchain-dynamic-chatbot": minor
+"@coinbase/agentkit": minor
+---
+
+Adds Dynamic as wallet provider
diff --git a/typescript/agentkit/package.json b/typescript/agentkit/package.json
index 537907c06..3a5c69df6 100644
--- a/typescript/agentkit/package.json
+++ b/typescript/agentkit/package.json
@@ -45,11 +45,14 @@
"@coinbase/cdp-sdk": "^1.38.0",
"@coinbase/coinbase-sdk": "^0.20.0",
"@coinbase/x402": "^0.6.3",
+ "@dynamic-labs-wallet/node": "0.0.169",
+ "@dynamic-labs-wallet/node-evm": "0.0.169",
+ "@dynamic-labs-wallet/node-svm": "0.0.169",
"@jup-ag/api": "^6.0.39",
"@privy-io/public-api": "2.18.5",
"@privy-io/server-auth": "1.18.4",
"@solana/spl-token": "^0.4.12",
- "@solana/web3.js": "^1.98.1",
+ "@solana/web3.js": "^1.98.2",
"@zerodev/ecdsa-validator": "^5.4.5",
"@zerodev/intent": "^0.0.24",
"@zerodev/sdk": "^5.4.28",
diff --git a/typescript/agentkit/src/wallet-providers/dynamicEvmWalletProvider.test.ts b/typescript/agentkit/src/wallet-providers/dynamicEvmWalletProvider.test.ts
new file mode 100644
index 000000000..061deb90d
--- /dev/null
+++ b/typescript/agentkit/src/wallet-providers/dynamicEvmWalletProvider.test.ts
@@ -0,0 +1,370 @@
+import { DynamicEvmWalletProvider } from "./dynamicEvmWalletProvider";
+import { createPublicClient, http } from "viem";
+import { getChain } from "../network/network";
+import { createDynamicWallet, createDynamicClient } from "./dynamicShared";
+
+// Mock dynamic imports
+jest.mock("@dynamic-labs-wallet/node-evm", () => ({
+ DynamicEvmWalletClient: jest.fn(),
+}));
+jest.mock("@dynamic-labs-wallet/node", () => ({
+ ThresholdSignatureScheme: {
+ TWO_OF_TWO: "TWO_OF_TWO",
+ TWO_OF_THREE: "TWO_OF_THREE",
+ THREE_OF_FIVE: "THREE_OF_FIVE",
+ },
+}));
+
+jest.mock("viem", () => ({
+ createPublicClient: jest.fn(),
+ http: jest.fn(),
+}));
+jest.mock("../network/network");
+jest.mock("../analytics", () => ({
+ sendAnalyticsEvent: jest.fn().mockImplementation(() => Promise.resolve()),
+}));
+jest.mock("./dynamicShared", () => ({
+ createDynamicWallet: jest.fn(),
+ createDynamicClient: jest.fn(),
+}));
+
+const MOCK_ADDRESS = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e";
+const MOCK_TRANSACTION_HASH = "0xef01";
+const MOCK_SIGNATURE_HASH = "0x1234";
+
+describe("DynamicEvmWalletProvider", () => {
+ const MOCK_CONFIG = {
+ authToken: "test-auth-token",
+ environmentId: "test-environment-id",
+ baseApiUrl: "https://app.dynamicauth.com",
+ baseMPCRelayApiUrl: "relay.dynamicauth.com",
+ chainId: "84532",
+ networkId: "base-sepolia",
+ chainType: "ethereum" as const,
+ thresholdSignatureScheme: "TWO_OF_TWO",
+ };
+
+ const mockWallet = {
+ accountAddress: MOCK_ADDRESS,
+ publicKeyHex: "0x123",
+ };
+
+ const mockDynamicClient = {
+ createViemPublicClient: jest.fn().mockReturnValue({
+ getBalance: jest.fn(),
+ getTransactionCount: jest.fn(),
+ }),
+ signMessage: jest.fn().mockResolvedValue(MOCK_SIGNATURE_HASH),
+ signTransaction: jest.fn().mockResolvedValue(MOCK_SIGNATURE_HASH),
+ exportPrivateKey: jest.fn().mockResolvedValue({ derivedPrivateKey: "0xprivate" }),
+ importPrivateKey: jest.fn().mockResolvedValue({
+ accountAddress: MOCK_ADDRESS,
+ publicKeyHex: "0x123",
+ }),
+ };
+
+ const mockPublicClient = {
+ chain: {
+ id: 84532,
+ name: "Base Goerli",
+ rpcUrls: {
+ default: { http: ["https://goerli.base.org"] },
+ },
+ nativeCurrency: {
+ name: "Ether",
+ symbol: "ETH",
+ decimals: 18,
+ },
+ },
+ getBalance: jest.fn().mockResolvedValue(BigInt(1000000000000000000)),
+ getTransactionCount: jest.fn(),
+ prepareTransactionRequest: jest.fn().mockResolvedValue({
+ to: "0x123" as `0x${string}`,
+ value: BigInt(1000),
+ data: "0x" as `0x${string}`,
+ gas: BigInt(21000),
+ nonce: 1,
+ maxFeePerGas: BigInt(1000000),
+ maxPriorityFeePerGas: BigInt(1000000),
+ }),
+ sendRawTransaction: jest.fn().mockResolvedValue(MOCK_TRANSACTION_HASH),
+ waitForTransactionReceipt: jest.fn().mockResolvedValue({
+ transactionHash: MOCK_TRANSACTION_HASH,
+ status: "success",
+ }),
+ readContract: jest.fn(),
+ };
+
+ beforeEach(async () => {
+ jest.clearAllMocks();
+
+ // Import the mocked modules
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const { DynamicEvmWalletClient } = (await import("@dynamic-labs-wallet/node-evm")) as any;
+
+ // Mock DynamicEvmWalletClient
+ DynamicEvmWalletClient.mockImplementation(() => mockDynamicClient);
+
+ // Mock getChain
+ (getChain as jest.Mock).mockReturnValue({
+ id: 84532,
+ name: "Base Goerli",
+ rpcUrls: {
+ default: { http: ["https://goerli.base.org"] },
+ },
+ nativeCurrency: {
+ name: "Ether",
+ symbol: "ETH",
+ decimals: 18,
+ },
+ });
+
+ // Mock viem functions
+ (createPublicClient as jest.Mock).mockReturnValue(mockPublicClient);
+ (http as jest.Mock).mockReturnValue(jest.fn());
+
+ // Mock createDynamicClient
+ (createDynamicClient as jest.Mock).mockResolvedValue(mockDynamicClient);
+
+ // Mock createDynamicWallet
+ (createDynamicWallet as jest.Mock).mockResolvedValue({
+ wallet: mockWallet,
+ dynamic: mockDynamicClient,
+ });
+ });
+
+ describe("configureWithWallet", () => {
+ it("should create a new wallet with Dynamic client", async () => {
+ const _provider = await DynamicEvmWalletProvider.configureWithWallet(MOCK_CONFIG);
+
+ expect(createDynamicWallet).toHaveBeenCalledWith(
+ {
+ ...MOCK_CONFIG,
+ },
+ "ethereum",
+ );
+
+ expect(getChain).toHaveBeenCalledWith(MOCK_CONFIG.chainId);
+ expect(createPublicClient).toHaveBeenCalled();
+ });
+
+ it("should throw error when wallet creation fails", async () => {
+ (createDynamicWallet as jest.Mock).mockRejectedValue(new Error("Failed to create wallet"));
+
+ await expect(DynamicEvmWalletProvider.configureWithWallet(MOCK_CONFIG)).rejects.toThrow(
+ "Failed to create wallet",
+ );
+ });
+
+ it("should throw error when chain is not found", async () => {
+ (getChain as jest.Mock).mockReturnValue(null);
+
+ await expect(DynamicEvmWalletProvider.configureWithWallet(MOCK_CONFIG)).rejects.toThrow(
+ `Chain with ID ${MOCK_CONFIG.chainId} not found`,
+ );
+ });
+
+ it("should use default chain ID when not provided", async () => {
+ const { chainId: _chainId, ...configWithoutChainId } = MOCK_CONFIG;
+
+ await DynamicEvmWalletProvider.configureWithWallet(configWithoutChainId);
+
+ expect(getChain).toHaveBeenCalledWith("84532");
+ });
+ });
+
+ describe("wallet methods", () => {
+ let provider: DynamicEvmWalletProvider;
+
+ beforeEach(async () => {
+ provider = await DynamicEvmWalletProvider.configureWithWallet(MOCK_CONFIG);
+ });
+
+ it("should get the wallet address", () => {
+ expect(provider.getAddress()).toBe(MOCK_ADDRESS);
+ });
+
+ it("should get the network information", () => {
+ expect(provider.getNetwork()).toEqual({
+ protocolFamily: "evm",
+ chainId: MOCK_CONFIG.chainId,
+ networkId: "base-sepolia",
+ });
+ });
+
+ it("should get the provider name", () => {
+ expect(provider.getName()).toBe("dynamic_evm_wallet_provider");
+ });
+
+ it("should sign a string message using Dynamic client", async () => {
+ const result = await provider.signMessage("Hello, world!");
+ expect(result).toBe(MOCK_SIGNATURE_HASH);
+ expect(mockDynamicClient.signMessage).toHaveBeenCalledWith({
+ message: "Hello, world!",
+ accountAddress: MOCK_ADDRESS,
+ });
+ });
+
+ it("should sign a Uint8Array message using Dynamic client", async () => {
+ const messageBytes = new TextEncoder().encode("Hello, world!");
+ const result = await provider.signMessage(messageBytes);
+ expect(result).toBe(MOCK_SIGNATURE_HASH);
+ expect(mockDynamicClient.signMessage).toHaveBeenCalledWith({
+ message: "Hello, world!",
+ accountAddress: MOCK_ADDRESS,
+ });
+ });
+
+ it("should export private key", async () => {
+ const result = await provider.exportPrivateKey();
+ expect(result).toBe("0xprivate");
+ expect(mockDynamicClient.exportPrivateKey).toHaveBeenCalledWith({
+ accountAddress: MOCK_ADDRESS,
+ });
+ });
+
+ it("should import private key", async () => {
+ const result = await provider.importPrivateKey("0xprivate");
+ expect(result).toEqual({
+ accountAddress: MOCK_ADDRESS,
+ publicKeyHex: "0x123",
+ });
+ expect(mockDynamicClient.importPrivateKey).toHaveBeenCalledWith({
+ privateKey: "0xprivate",
+ chainName: "EVM",
+ thresholdSignatureScheme: "TWO_OF_TWO",
+ });
+ });
+
+ it("should export wallet information", async () => {
+ const result = await provider.exportWallet();
+ expect(result).toEqual({
+ accountAddress: MOCK_ADDRESS,
+ networkId: "base-sepolia",
+ });
+ });
+
+ it("should sign a transaction using Dynamic client", async () => {
+ const mockTransaction = {
+ to: "0x123" as `0x${string}`,
+ value: BigInt(1000),
+ data: "0x" as `0x${string}`,
+ };
+
+ const result = await provider.signTransaction(mockTransaction);
+ expect(result).toBe(MOCK_SIGNATURE_HASH);
+
+ // Should prepare transaction with viem
+ expect(mockPublicClient.prepareTransactionRequest).toHaveBeenCalledWith({
+ to: mockTransaction.to,
+ value: mockTransaction.value,
+ data: mockTransaction.data,
+ account: MOCK_ADDRESS,
+ chain: mockPublicClient.chain,
+ });
+
+ // Should sign with Dynamic
+ expect(mockDynamicClient.signTransaction).toHaveBeenCalledWith({
+ senderAddress: MOCK_ADDRESS,
+ transaction: expect.objectContaining({
+ to: mockTransaction.to,
+ value: mockTransaction.value,
+ data: mockTransaction.data,
+ gas: BigInt(21000),
+ nonce: 1,
+ }),
+ });
+ });
+
+ it("should send a transaction by signing and broadcasting", async () => {
+ const mockTransaction = {
+ to: "0x123" as `0x${string}`,
+ value: BigInt(1000),
+ data: "0x" as `0x${string}`,
+ };
+
+ const result = await provider.sendTransaction(mockTransaction);
+ expect(result).toBe(MOCK_TRANSACTION_HASH);
+
+ // Should prepare and sign transaction
+ expect(mockPublicClient.prepareTransactionRequest).toHaveBeenCalled();
+ expect(mockDynamicClient.signTransaction).toHaveBeenCalled();
+
+ // Should broadcast signed transaction
+ expect(mockPublicClient.sendRawTransaction).toHaveBeenCalledWith({
+ serializedTransaction: MOCK_SIGNATURE_HASH,
+ });
+ });
+
+ it("should get wallet balance", async () => {
+ const balance = await provider.getBalance();
+ expect(balance).toBe(BigInt(1000000000000000000));
+ expect(mockPublicClient.getBalance).toHaveBeenCalledWith({
+ address: MOCK_ADDRESS,
+ });
+ });
+
+ it("should get public client", () => {
+ const publicClient = provider.getPublicClient();
+ expect(publicClient).toBe(mockPublicClient);
+ });
+
+ it("should wait for transaction receipt", async () => {
+ const receipt = await provider.waitForTransactionReceipt(
+ MOCK_TRANSACTION_HASH as `0x${string}`,
+ );
+ expect(receipt).toEqual({
+ transactionHash: MOCK_TRANSACTION_HASH,
+ status: "success",
+ });
+ expect(mockPublicClient.waitForTransactionReceipt).toHaveBeenCalledWith({
+ hash: MOCK_TRANSACTION_HASH,
+ });
+ });
+
+ it("should read contract", async () => {
+ const mockParams = {
+ address: "0x123" as `0x${string}`,
+ abi: [],
+ functionName: "balanceOf",
+ args: [MOCK_ADDRESS],
+ };
+
+ await provider.readContract(mockParams);
+ expect(mockPublicClient.readContract).toHaveBeenCalledWith(mockParams);
+ });
+
+ it("should perform native transfer", async () => {
+ const to = "0x456";
+ const value = "1000000000000000000"; // 1 ETH in wei
+
+ const txHash = await provider.nativeTransfer(to, value);
+ expect(txHash).toBe(MOCK_TRANSACTION_HASH);
+ expect(mockPublicClient.prepareTransactionRequest).toHaveBeenCalled();
+ expect(mockDynamicClient.signTransaction).toHaveBeenCalled();
+ expect(mockPublicClient.sendRawTransaction).toHaveBeenCalled();
+ expect(mockPublicClient.waitForTransactionReceipt).toHaveBeenCalled();
+ });
+
+ it("should throw error when signing raw hash", async () => {
+ await expect(
+ provider.sign(
+ "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" as `0x${string}`,
+ ),
+ ).rejects.toThrow("Raw hash signing not implemented for Dynamic wallet provider");
+ });
+
+ it("should throw error when signing typed data", async () => {
+ const typedData = {
+ domain: { name: "Test" },
+ types: {},
+ message: {},
+ primaryType: "Test",
+ };
+
+ await expect(provider.signTypedData(typedData)).rejects.toThrow(
+ "Typed data signing not implemented for Dynamic wallet provider",
+ );
+ });
+ });
+});
diff --git a/typescript/agentkit/src/wallet-providers/dynamicEvmWalletProvider.ts b/typescript/agentkit/src/wallet-providers/dynamicEvmWalletProvider.ts
new file mode 100644
index 000000000..60bc76d34
--- /dev/null
+++ b/typescript/agentkit/src/wallet-providers/dynamicEvmWalletProvider.ts
@@ -0,0 +1,411 @@
+import { EvmWalletProvider } from "./evmWalletProvider";
+import {
+ createPublicClient,
+ http,
+ type PublicClient,
+ type TransactionRequest,
+ type Hex,
+ type Abi,
+ type ContractFunctionName,
+ type ContractFunctionArgs,
+ type ReadContractParameters,
+ type ReadContractReturnType,
+} from "viem";
+import { getChain, NETWORK_ID_TO_CHAIN_ID } from "../network/network";
+import { type Network } from "../network";
+import {
+ type DynamicWalletConfig,
+ type DynamicWalletExport,
+ type DynamicWalletClient,
+ createDynamicWallet,
+} from "./dynamicShared";
+
+/**
+ * Configuration options for the Dynamic wallet provider.
+ *
+ * @interface
+ */
+export interface DynamicEvmWalletConfig extends DynamicWalletConfig {
+ /** Optional chain ID to connect to */
+ chainId?: string;
+ /** Optional RPC URL override for Viem public client */
+ rpcUrl?: string;
+}
+
+/**
+ * A wallet provider that uses Dynamic's wallet API.
+ * This provider extends EvmWalletProvider and implements all signing operations
+ * using Dynamic's embedded wallet infrastructure.
+ */
+export class DynamicEvmWalletProvider extends EvmWalletProvider {
+ #accountAddress: string;
+ #dynamicClient: DynamicWalletClient;
+ #publicClient: PublicClient;
+ #network: Network;
+
+ /**
+ * Private constructor to enforce use of factory method.
+ *
+ * @param accountAddress - The wallet account address
+ * @param dynamicClient - The Dynamic wallet client instance
+ * @param publicClient - The public client for read operations and broadcasting
+ * @param network - The network configuration
+ */
+ private constructor(
+ accountAddress: string,
+ dynamicClient: DynamicWalletClient,
+ publicClient: PublicClient,
+ network: Network,
+ ) {
+ super();
+ this.#accountAddress = accountAddress;
+ this.#dynamicClient = dynamicClient;
+ this.#publicClient = publicClient;
+ this.#network = network;
+ }
+
+ /**
+ * Creates and configures a new DynamicWalletProvider instance.
+ *
+ * @param config - The configuration options for the Dynamic wallet
+ * @returns A configured DynamicWalletProvider instance
+ *
+ * @example
+ * ```typescript
+ * const provider = await DynamicWalletProvider.configureWithWallet({
+ * authToken: "your-auth-token",
+ * environmentId: "your-environment-id",
+ * networkId: "base-sepolia",
+ * thresholdSignatureScheme: "TWO_OF_TWO"
+ * });
+ * ```
+ */
+ public static async configureWithWallet(
+ config: DynamicEvmWalletConfig,
+ ): Promise {
+ const networkId = config.networkId || "base-sepolia";
+ const chainId = NETWORK_ID_TO_CHAIN_ID[networkId];
+
+ if (!chainId) {
+ throw new Error(`Unsupported network ID: ${networkId}`);
+ }
+
+ console.log("[DynamicEvmWalletProvider] Starting wallet configuration with config:", {
+ networkId,
+ chainId,
+ environmentId: config.environmentId,
+ });
+
+ const { wallet, dynamic } = await createDynamicWallet(config, "ethereum");
+
+ const chain = getChain(chainId);
+ if (!chain) {
+ throw new Error(`Chain with ID ${chainId} not found`);
+ }
+
+ const network: Network = {
+ protocolFamily: "evm",
+ chainId,
+ networkId,
+ };
+
+ const rpcUrl = config.rpcUrl || process.env.RPC_URL;
+ const publicClient = createPublicClient({
+ chain,
+ transport: rpcUrl ? http(rpcUrl) : http(),
+ });
+
+ console.log("[DynamicEvmWalletProvider] Wallet configured successfully:", {
+ address: wallet.accountAddress,
+ network: networkId,
+ });
+
+ return new DynamicEvmWalletProvider(wallet.accountAddress, dynamic, publicClient, network);
+ }
+
+ /**
+ * Signs a raw hash.
+ *
+ * @param _hash - The hash to sign
+ * @returns The signed hash
+ * @throws Error indicating this operation is not supported
+ */
+ async sign(_hash: `0x${string}`): Promise<`0x${string}`> {
+ throw new Error(
+ "Raw hash signing not implemented for Dynamic wallet provider. Use signMessage or signTransaction instead.",
+ );
+ }
+
+ /**
+ * Signs a message using Dynamic's signing service.
+ *
+ * @param message - The message to sign (string or Uint8Array)
+ * @returns The signature as a hex string with 0x prefix
+ */
+ async signMessage(message: string | Uint8Array): Promise<`0x${string}`> {
+ const messageStr = typeof message === "string" ? message : new TextDecoder().decode(message);
+
+ const signature = await this.#dynamicClient.signMessage({
+ message: messageStr,
+ accountAddress: this.#accountAddress,
+ });
+ return signature as `0x${string}`;
+ }
+
+ /**
+ * Signs typed data.
+ *
+ * @param _typedData - The typed data to sign
+ * @returns The signed typed data
+ * @throws Error indicating this operation is not supported
+ */
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ async signTypedData(_typedData: any): Promise<`0x${string}`> {
+ throw new Error("Typed data signing not implemented for Dynamic wallet provider.");
+ }
+
+ /**
+ * Signs a transaction using Dynamic's signing service.
+ *
+ * @param transaction - The transaction to sign
+ * @returns The signed transaction as a hex string
+ */
+ async signTransaction(transaction: TransactionRequest): Promise {
+ if (!this.#publicClient.chain) {
+ throw new Error("Chain not found");
+ }
+
+ console.log("[DynamicEvmWalletProvider] Preparing transaction for signing:", {
+ to: transaction.to,
+ value: transaction.value?.toString(),
+ data: transaction.data,
+ });
+
+ // Prepare transaction with gas estimation using Viem
+ // This follows Dynamic's recommended pattern from their docs
+ const preparedTx = await this.#publicClient.prepareTransactionRequest({
+ to: transaction.to,
+ value: transaction.value,
+ data: transaction.data,
+ account: this.#accountAddress as `0x${string}`,
+ chain: this.#publicClient.chain,
+ });
+
+ console.log("[DynamicEvmWalletProvider] Transaction prepared, signing with Dynamic:", {
+ to: preparedTx.to,
+ value: preparedTx.value?.toString(),
+ gas: preparedTx.gas?.toString(),
+ nonce: preparedTx.nonce,
+ });
+
+ try {
+ // Dynamic import for ESM compatibility
+ const { DynamicEvmWalletClient: _DynamicEvmWalletClient } = (await import(
+ "@dynamic-labs-wallet/node-evm"
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ )) as any;
+
+ // Retrieve external server key shares required for signing
+ // This is required when wallet was created without backUpToClientShareService: true
+ console.log("[DynamicEvmWalletProvider] Retrieving external server key shares...");
+ const keyShares = await (
+ this.#dynamicClient as InstanceType
+ ).getExternalServerKeyShares({
+ accountAddress: this.#accountAddress,
+ });
+ if (keyShares && keyShares.length)
+ console.log("[DynamicEvmWalletProvider] Retrieved", keyShares.length, "key shares");
+
+ // Sign using Dynamic's signTransaction with external key shares
+ const signedTx = await (
+ this.#dynamicClient as InstanceType
+ ).signTransaction({
+ senderAddress: this.#accountAddress as `0x${string}`,
+ externalServerKeyShares: keyShares || [],
+ transaction: preparedTx,
+ });
+
+ console.log("[DynamicEvmWalletProvider] Transaction signed successfully");
+ return signedTx as Hex;
+ } catch (error) {
+ console.error("[DynamicEvmWalletProvider] Error signing transaction:", error);
+ throw error;
+ }
+ }
+
+ /**
+ * Sends a transaction by signing it with Dynamic and broadcasting it.
+ *
+ * @param transaction - The transaction to send
+ * @returns The transaction hash
+ */
+ async sendTransaction(transaction: TransactionRequest): Promise {
+ console.log("[DynamicEvmWalletProvider] Sending transaction:", {
+ to: transaction.to,
+ value: transaction.value?.toString(),
+ data: transaction.data,
+ });
+
+ // Sign the transaction using Dynamic
+ const signedTx = await this.signTransaction(transaction);
+
+ // Broadcast the signed transaction
+ console.log("[DynamicEvmWalletProvider] Broadcasting signed transaction...");
+ const txHash = await this.#publicClient.sendRawTransaction({
+ serializedTransaction: signedTx,
+ });
+
+ console.log("[DynamicEvmWalletProvider] Transaction sent successfully:", txHash);
+ return txHash;
+ }
+
+ /**
+ * Exports the private key for the wallet.
+ *
+ * @param password - Optional password for encrypted backup shares
+ * @returns The private key
+ */
+ public async exportPrivateKey(password?: string): Promise {
+ const result = await this.#dynamicClient.exportPrivateKey({
+ accountAddress: this.getAddress(),
+ password,
+ });
+ return result.derivedPrivateKey || "";
+ }
+
+ /**
+ * Imports a private key.
+ *
+ * @param privateKey - The private key to import
+ * @param password - Optional password for encrypted backup shares
+ * @returns The account address and public key
+ */
+ public async importPrivateKey(
+ privateKey: string,
+ password?: string,
+ ): Promise<{
+ accountAddress: string;
+ publicKeyHex: string;
+ }> {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const { ThresholdSignatureScheme } = (await import("@dynamic-labs-wallet/node")) as any;
+ const result = await this.#dynamicClient.importPrivateKey({
+ privateKey,
+ chainName: "EVM",
+ thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO,
+ password,
+ });
+ return {
+ accountAddress: result.accountAddress,
+ publicKeyHex: "publicKeyHex" in result ? result.publicKeyHex : "",
+ };
+ }
+
+ /**
+ * Waits for a transaction receipt.
+ *
+ * @param txHash - The hash of the transaction to wait for
+ * @returns The transaction receipt
+ */
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ async waitForTransactionReceipt(txHash: `0x${string}`): Promise {
+ return await this.#publicClient.waitForTransactionReceipt({ hash: txHash });
+ }
+
+ /**
+ * Reads a contract.
+ *
+ * @param params - The parameters to read the contract
+ * @returns The response from the contract
+ */
+ async readContract<
+ const abi extends Abi | readonly unknown[],
+ functionName extends ContractFunctionName,
+ const args extends ContractFunctionArgs,
+ >(
+ params: ReadContractParameters,
+ ): Promise> {
+ return this.#publicClient.readContract(params);
+ }
+
+ /**
+ * Gets the Viem PublicClient used for read-only operations.
+ *
+ * @returns The Viem PublicClient instance
+ */
+ getPublicClient(): PublicClient {
+ return this.#publicClient;
+ }
+
+ /**
+ * Gets the balance of the wallet.
+ *
+ * @returns The balance of the wallet in wei
+ */
+ async getBalance(): Promise {
+ return await this.#publicClient.getBalance({
+ address: this.#accountAddress as `0x${string}`,
+ });
+ }
+
+ /**
+ * Transfer the native asset of the network.
+ *
+ * @param to - The destination address
+ * @param value - The amount to transfer in atomic units (Wei)
+ * @returns The transaction hash
+ */
+ async nativeTransfer(to: string, value: string): Promise {
+ const tx = await this.sendTransaction({
+ to: to as `0x${string}`,
+ value: BigInt(value),
+ });
+
+ const receipt = await this.waitForTransactionReceipt(tx);
+
+ if (!receipt) {
+ throw new Error("Transaction failed");
+ }
+
+ return receipt.transactionHash;
+ }
+
+ /**
+ * Gets the address of the wallet.
+ *
+ * @returns The wallet address
+ */
+ getAddress(): string {
+ return this.#accountAddress;
+ }
+
+ /**
+ * Gets the network of the wallet.
+ *
+ * @returns The network of the wallet
+ */
+ getNetwork(): Network {
+ return this.#network;
+ }
+
+ /**
+ * Gets the name of the provider.
+ *
+ * @returns The provider name
+ */
+ getName(): string {
+ return "dynamic_evm_wallet_provider";
+ }
+
+ /**
+ * Exports the wallet information.
+ *
+ * @returns The wallet information
+ */
+ async exportWallet(): Promise {
+ return {
+ accountAddress: this.#accountAddress,
+ networkId: this.#network.networkId,
+ };
+ }
+}
diff --git a/typescript/agentkit/src/wallet-providers/dynamicShared.ts b/typescript/agentkit/src/wallet-providers/dynamicShared.ts
new file mode 100644
index 000000000..80db1dd53
--- /dev/null
+++ b/typescript/agentkit/src/wallet-providers/dynamicShared.ts
@@ -0,0 +1,157 @@
+/**
+ * Configuration options for the Dynamic wallet provider.
+ *
+ * @interface
+ */
+export interface DynamicWalletConfig {
+ /** The Dynamic authentication token */
+ authToken: string;
+ /** The Dynamic environment ID */
+ environmentId: string;
+ /** The account address of the wallet to use, if not provided a new wallet will be created */
+ accountAddress?: string;
+ /** The network ID to use for the wallet */
+ networkId: string;
+ /** The threshold signature scheme to use for wallet creation */
+ thresholdSignatureScheme?: string;
+ /** Optional password for encrypted backup shares */
+ password?: string;
+}
+
+export type DynamicWalletExport = {
+ accountAddress: string;
+ networkId: string | undefined;
+};
+
+export type DynamicWalletClient = Awaited>;
+
+type CreateDynamicWalletReturnType = {
+ wallet: {
+ accountAddress: string;
+ publicKeyHex?: string; // Only for EVM
+ rawPublicKey: Uint8Array;
+ externalServerKeyShares: unknown[]; // Specify a more appropriate type if known
+ };
+ dynamic: DynamicWalletClient;
+};
+
+/**
+ * Converts a string threshold signature scheme to the enum value
+ *
+ * @param scheme - The string representation of the threshold signature scheme
+ * @returns The corresponding ThresholdSignatureScheme enum value
+ */
+const convertThresholdSignatureScheme = async (scheme?: string) => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const { ThresholdSignatureScheme } = (await import("@dynamic-labs-wallet/node")) as any;
+ if (scheme === "TWO_OF_THREE") return ThresholdSignatureScheme.TWO_OF_THREE;
+ if (scheme === "THREE_OF_FIVE") return ThresholdSignatureScheme.THREE_OF_FIVE;
+ return ThresholdSignatureScheme.TWO_OF_TWO;
+};
+/**
+ * Create a Dynamic client based on the chain type
+ *
+ * @param config - The configuration options for the Dynamic client
+ * @param chainType - The type of chain to create the client for
+ * @returns The created Dynamic client
+ */
+export const createDynamicClient = async (
+ config: DynamicWalletConfig,
+ chainType: "ethereum" | "solana",
+) => {
+ const clientConfig = {
+ authToken: config.authToken,
+ environmentId: config.environmentId,
+ };
+
+ try {
+ let client;
+
+ if (chainType === "ethereum") {
+ // Dynamic import for ESM compatibility - only load EVM package when needed
+ // Using type assertion due to dual-format package export issues with Node16 module resolution
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const evmModule = (await import("@dynamic-labs-wallet/node-evm")) as any;
+ const { DynamicEvmWalletClient } = evmModule;
+ client = new DynamicEvmWalletClient(clientConfig);
+ } else {
+ // Dynamic import for ESM compatibility - only load SVM package when needed
+ // Using type assertion due to dual-format package export issues with Node16 module resolution
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const svmModule = (await import("@dynamic-labs-wallet/node-svm")) as any;
+ const { DynamicSvmWalletClient } = svmModule;
+ client = new DynamicSvmWalletClient(clientConfig);
+ }
+
+ await client.authenticateApiToken(config.authToken);
+ const evmWallets = await client.getWallets();
+ console.log("wallets:", evmWallets);
+
+ return client;
+ } catch (error) {
+ console.error("[createDynamicClient] Error creating client:", error);
+ throw error;
+ }
+};
+
+/**
+ * Create a Dynamic wallet
+ *
+ * @param config - The configuration options for the Dynamic wallet
+ * @param chainType - The type of chain to create the wallet for
+ * @returns The created Dynamic wallet and client
+ */
+export const createDynamicWallet = async (
+ config: DynamicWalletConfig,
+ chainType: "ethereum" | "solana",
+): Promise => {
+ const client = await createDynamicClient(config, chainType);
+ console.log("[createDynamicWallet] Dynamic client created");
+
+ let wallet: CreateDynamicWalletReturnType["wallet"];
+ const wallets =
+ chainType === "solana" ? await client.getSvmWallets() : await client.getEvmWallets();
+ const existingWallet = wallets.find(wallet => wallet.accountAddress === config.accountAddress);
+ if (existingWallet) {
+ console.log(
+ "[createDynamicWallet] Found existing wallet with address:",
+ existingWallet.accountAddress,
+ );
+ wallet = existingWallet;
+ } else {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const { ThresholdSignatureScheme } = (await import("@dynamic-labs-wallet/node")) as any;
+ console.log("[createDynamicWallet] Creating new wallet");
+ console.log("[createDynamicWallet] createWalletAccount params:", {
+ thresholdSignatureScheme:
+ config.thresholdSignatureScheme || ThresholdSignatureScheme.TWO_OF_TWO,
+ password: config.password ? "***" : undefined,
+ networkId: config.networkId,
+ chainType: chainType,
+ });
+
+ const thresholdSignatureScheme = await convertThresholdSignatureScheme(
+ config.thresholdSignatureScheme,
+ );
+ try {
+ const result = await client.createWalletAccount({
+ thresholdSignatureScheme,
+ password: config.password,
+ backUpToClientShareService: true,
+ });
+ wallet = {
+ accountAddress: result.accountAddress,
+ rawPublicKey: result.rawPublicKey,
+ externalServerKeyShares: result.externalServerKeyShares,
+ };
+ } catch (error) {
+ throw new Error("Failed to create wallet: " + error);
+ }
+ }
+
+ console.log("[createDynamicWallet] Wallet created/retrieved:", {
+ accountAddress: wallet.accountAddress,
+ });
+
+ return { wallet, dynamic: client };
+};
diff --git a/typescript/agentkit/src/wallet-providers/dynamicSvmWalletProvider.test.ts b/typescript/agentkit/src/wallet-providers/dynamicSvmWalletProvider.test.ts
new file mode 100644
index 000000000..4d65c2a8c
--- /dev/null
+++ b/typescript/agentkit/src/wallet-providers/dynamicSvmWalletProvider.test.ts
@@ -0,0 +1,330 @@
+import { DynamicSvmWalletProvider } from "./dynamicSvmWalletProvider";
+// import { DynamicSvmWalletClient } from "@dynamic-labs-wallet/node-svm";
+import {
+ Connection,
+ clusterApiUrl,
+ PublicKey,
+ VersionedTransaction,
+ MessageV0,
+} from "@solana/web3.js";
+import { createDynamicWallet, createDynamicClient } from "./dynamicShared";
+// import { ThresholdSignatureScheme } from "@dynamic-labs-wallet/node";
+
+// Mock dynamic imports
+jest.mock("@dynamic-labs-wallet/node-svm", () => ({
+ DynamicSvmWalletClient: jest.fn(),
+}));
+jest.mock("@dynamic-labs-wallet/node", () => ({
+ ThresholdSignatureScheme: {
+ TWO_OF_TWO: "TWO_OF_TWO",
+ TWO_OF_THREE: "TWO_OF_THREE",
+ THREE_OF_FIVE: "THREE_OF_FIVE",
+ },
+}));
+jest.mock("../network/svm", () => ({
+ SOLANA_CLUSTER_ID_BY_NETWORK_ID: {
+ "": "mainnet-beta",
+ "mainnet-beta": "mainnet-beta",
+ testnet: "testnet",
+ devnet: "devnet",
+ },
+ SOLANA_NETWORKS: {
+ "test-genesis-hash": {
+ protocolFamily: "svm",
+ chainId: "test-genesis-hash",
+ networkId: "mainnet-beta",
+ },
+ },
+}));
+jest.mock("@solana/web3.js", () => {
+ const actual = jest.requireActual("@solana/web3.js");
+ const mockVersionedTransaction = jest.fn().mockImplementation(message => {
+ const tx = {
+ signatures: [],
+ message: message || { compiledMessage: Buffer.from([]) },
+ };
+ Object.setPrototypeOf(tx, actual.VersionedTransaction.prototype);
+ return tx;
+ });
+
+ return {
+ ...actual,
+ Connection: jest.fn().mockImplementation((endpoint, commitment = "confirmed") => {
+ // Store the commitment for verification
+ (Connection as jest.Mock).mock.lastCall = [endpoint, commitment];
+ return {
+ getGenesisHash: jest.fn().mockResolvedValue("test-genesis-hash"),
+ commitment,
+ rpcEndpoint: endpoint,
+ getBalance: jest.fn(),
+ getBalanceAndContext: jest.fn(),
+ sendTransaction: jest.fn().mockResolvedValue(MOCK_TRANSACTION_HASH),
+ getSignatureStatus: jest.fn().mockResolvedValue({
+ context: { slot: 123 },
+ value: { slot: 123, confirmations: 10, err: null },
+ }),
+ getLatestBlockhash: jest.fn().mockResolvedValue({
+ blockhash: "test-blockhash",
+ lastValidBlockHeight: 123,
+ }),
+ };
+ }),
+ PublicKey: jest.fn().mockImplementation(address => ({
+ toBase58: jest.fn().mockReturnValue(address),
+ toString: jest.fn().mockReturnValue(address),
+ toBuffer: jest.fn().mockReturnValue(Buffer.from(address)),
+ toArrayLike: jest.fn().mockReturnValue(Buffer.from(address)),
+ })),
+ VersionedTransaction: mockVersionedTransaction,
+ MessageV0: {
+ compile: jest.fn().mockReturnValue({
+ compiledMessage: Buffer.from([]),
+ }),
+ },
+ clusterApiUrl: jest.fn().mockImplementation(network => {
+ // Always use mainnet-beta as default
+ const networkId = network || "mainnet-beta";
+ return `https://api.${networkId}.solana.com`;
+ }),
+ };
+});
+jest.mock("../analytics", () => ({
+ sendAnalyticsEvent: jest.fn().mockImplementation(() => Promise.resolve()),
+}));
+jest.mock("./dynamicShared", () => ({
+ createDynamicWallet: jest.fn(),
+ createDynamicClient: jest.fn(),
+}));
+
+const MOCK_ADDRESS = "test-address";
+const MOCK_TRANSACTION_HASH = "test-tx-hash";
+const MOCK_SIGNATURE_HASH = "test-signature";
+const MOCK_NETWORK = {
+ protocolFamily: "svm",
+ chainId: "test-genesis-hash",
+ networkId: "mainnet-beta",
+};
+
+describe("DynamicSvmWalletProvider", () => {
+ const MOCK_CONFIG = {
+ authToken: "test-auth-token",
+ environmentId: "test-environment-id",
+ baseApiUrl: "https://app.dynamicauth.com",
+ baseMPCRelayApiUrl: "relay.dynamicauth.com",
+ networkId: "mainnet-beta",
+ chainType: "solana" as const,
+ thresholdSignatureScheme: "TWO_OF_TWO", // Will be converted by the function
+ };
+
+ const mockWallet = {
+ accountAddress: MOCK_ADDRESS,
+ publicKeyHex: "0x123",
+ };
+
+ const mockDynamicClient = {
+ signMessage: jest.fn().mockResolvedValue(MOCK_SIGNATURE_HASH),
+ signTransaction: jest.fn().mockImplementation(({ transaction }) => {
+ // Return the transaction directly, not the whole object
+ if (!(transaction instanceof VersionedTransaction)) {
+ Object.setPrototypeOf(transaction, VersionedTransaction.prototype);
+ }
+ return transaction;
+ }),
+ createWalletAccount: jest.fn().mockResolvedValue({
+ accountAddress: MOCK_ADDRESS,
+ rawPublicKey: new Uint8Array(),
+ externalServerKeyShares: [],
+ }),
+ deriveAccountAddress: jest.fn().mockResolvedValue({
+ accountAddress: MOCK_ADDRESS,
+ }),
+ exportPrivateKey: jest.fn().mockResolvedValue({
+ derivedPrivateKey: "test-private-key",
+ }),
+ importPrivateKey: jest.fn().mockResolvedValue({
+ accountAddress: MOCK_ADDRESS,
+ rawPublicKey: new Uint8Array(),
+ externalServerKeyShares: [],
+ }),
+ getSvmWallets: jest.fn().mockResolvedValue([]),
+ };
+
+ beforeEach(async () => {
+ jest.clearAllMocks();
+
+ // Import the mocked modules
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const { DynamicSvmWalletClient } = (await import("@dynamic-labs-wallet/node-svm")) as any;
+
+ // Mock DynamicSvmWalletClient
+ DynamicSvmWalletClient.mockImplementation(() => mockDynamicClient);
+
+ // Mock createDynamicClient
+ (createDynamicClient as jest.Mock).mockResolvedValue(mockDynamicClient);
+
+ // Mock createDynamicWallet
+ (createDynamicWallet as jest.Mock).mockResolvedValue({
+ wallet: mockWallet,
+ dynamic: mockDynamicClient,
+ });
+ });
+
+ describe("configureWithWallet", () => {
+ it("should create a new wallet with Dynamic client", async () => {
+ const _provider = await DynamicSvmWalletProvider.configureWithWallet(MOCK_CONFIG);
+
+ expect(createDynamicWallet).toHaveBeenCalledWith({
+ ...MOCK_CONFIG,
+ chainType: "solana",
+ });
+
+ expect(Connection).toHaveBeenCalledWith("https://api.mainnet-beta.solana.com");
+ const connection = (Connection as jest.Mock).mock.results[0].value;
+ expect(connection.getGenesisHash).toHaveBeenCalled();
+ });
+
+ it("should throw error when wallet creation fails", async () => {
+ (createDynamicWallet as jest.Mock).mockRejectedValue(new Error("Failed to create wallet"));
+
+ await expect(DynamicSvmWalletProvider.configureWithWallet(MOCK_CONFIG)).rejects.toThrow(
+ "Failed to create wallet",
+ );
+ });
+
+ it("should use provided connection when available", async () => {
+ const mockConnection = {
+ getGenesisHash: jest.fn().mockResolvedValue("test-genesis-hash"),
+ commitment: "confirmed",
+ rpcEndpoint: "https://custom-rpc.example.com",
+ getBalance: jest.fn(),
+ getBalanceAndContext: jest.fn(),
+ sendTransaction: jest.fn().mockResolvedValue(MOCK_TRANSACTION_HASH),
+ getSignatureStatus: jest.fn().mockResolvedValue({
+ context: { slot: 123 },
+ value: { slot: 123, confirmations: 10, err: null },
+ }),
+ getLatestBlockhash: jest.fn().mockResolvedValue({
+ blockhash: "test-blockhash",
+ lastValidBlockHeight: 123,
+ }),
+ };
+ const config = {
+ ...MOCK_CONFIG,
+ connection: mockConnection as unknown as Connection,
+ };
+ const _provider = await DynamicSvmWalletProvider.configureWithWallet(config);
+
+ expect(Connection).not.toHaveBeenCalled();
+ expect(mockConnection.getGenesisHash).toHaveBeenCalled();
+ });
+
+ it("should use provided network ID", async () => {
+ await DynamicSvmWalletProvider.configureWithWallet(MOCK_CONFIG);
+
+ expect(clusterApiUrl).toHaveBeenCalledWith("mainnet-beta");
+ });
+ });
+
+ describe("wallet methods", () => {
+ let provider: DynamicSvmWalletProvider;
+
+ beforeEach(async () => {
+ provider = await DynamicSvmWalletProvider.configureWithWallet(MOCK_CONFIG);
+ });
+
+ it("should get the wallet address", () => {
+ expect(provider.getAddress()).toBe(MOCK_ADDRESS);
+ });
+
+ it("should get the network information", () => {
+ expect(provider.getNetwork()).toEqual(MOCK_NETWORK);
+ });
+
+ it("should get the provider name", () => {
+ expect(provider.getName()).toBe("dynamic_svm_wallet_provider");
+ });
+
+ it("should sign a message using Dynamic client", async () => {
+ const result = await provider.signMessage("Hello, world!");
+ expect(result).toBe(MOCK_SIGNATURE_HASH);
+ expect(mockDynamicClient.signMessage).toHaveBeenCalledWith({
+ message: "Hello, world!",
+ accountAddress: MOCK_ADDRESS,
+ });
+ });
+
+ it("should sign a transaction using Dynamic client", async () => {
+ const message = MessageV0.compile({
+ payerKey: new PublicKey(MOCK_ADDRESS),
+ instructions: [],
+ recentBlockhash: "test-blockhash",
+ });
+ const transaction = new VersionedTransaction(message);
+ const result = await provider.signTransaction(transaction);
+ expect(result).toBe(transaction);
+ expect(mockDynamicClient.signTransaction).toHaveBeenCalledWith({
+ senderAddress: MOCK_ADDRESS,
+ transaction,
+ });
+ });
+
+ it("should send a transaction", async () => {
+ const message = MessageV0.compile({
+ payerKey: new PublicKey(MOCK_ADDRESS),
+ instructions: [],
+ recentBlockhash: "test-blockhash",
+ });
+ const transaction = new VersionedTransaction(message);
+ const result = await provider.sendTransaction(transaction);
+ expect(result).toBe(MOCK_TRANSACTION_HASH);
+ const connection = (Connection as jest.Mock).mock.results[0].value;
+ expect(connection.sendTransaction).toHaveBeenCalledWith(transaction);
+ });
+
+ it("should sign and send a transaction", async () => {
+ const message = MessageV0.compile({
+ payerKey: new PublicKey(MOCK_ADDRESS),
+ instructions: [],
+ recentBlockhash: "test-blockhash",
+ });
+ const transaction = new VersionedTransaction(message);
+ const result = await provider.signAndSendTransaction(transaction);
+ expect(result).toBe(MOCK_TRANSACTION_HASH);
+ expect(mockDynamicClient.signTransaction).toHaveBeenCalledWith({
+ senderAddress: MOCK_ADDRESS,
+ transaction,
+ });
+ const connection = (Connection as jest.Mock).mock.results[0].value;
+ expect(connection.sendTransaction).toHaveBeenCalledWith(transaction);
+ });
+
+ it("should get signature status", async () => {
+ const result = await provider.getSignatureStatus(MOCK_TRANSACTION_HASH);
+ expect(result).toEqual({
+ context: { slot: 123 },
+ value: { slot: 123, confirmations: 10, err: null },
+ });
+ const connection = (Connection as jest.Mock).mock.results[0].value;
+ expect(connection.getSignatureStatus).toHaveBeenCalledWith(MOCK_TRANSACTION_HASH, undefined);
+ });
+
+ it("should wait for signature result", async () => {
+ const result = await provider.waitForSignatureResult(MOCK_TRANSACTION_HASH);
+ expect(result).toEqual({
+ context: { slot: 123 },
+ value: { slot: 123, confirmations: 10, err: null },
+ });
+ const connection = (Connection as jest.Mock).mock.results[0].value;
+ expect(connection.getSignatureStatus).toHaveBeenCalledWith(MOCK_TRANSACTION_HASH);
+ });
+
+ it("should export wallet information", async () => {
+ const result = await provider.exportWallet();
+ expect(result).toEqual({
+ walletId: MOCK_ADDRESS,
+ chainId: undefined,
+ networkId: "mainnet-beta",
+ });
+ });
+ });
+});
diff --git a/typescript/agentkit/src/wallet-providers/dynamicSvmWalletProvider.ts b/typescript/agentkit/src/wallet-providers/dynamicSvmWalletProvider.ts
new file mode 100644
index 000000000..52fd1aa24
--- /dev/null
+++ b/typescript/agentkit/src/wallet-providers/dynamicSvmWalletProvider.ts
@@ -0,0 +1,354 @@
+import { SvmWalletProvider } from "./svmWalletProvider";
+import {
+ clusterApiUrl,
+ LAMPORTS_PER_SOL,
+ SystemProgram,
+ ComputeBudgetProgram,
+ Connection,
+ PublicKey,
+ VersionedTransaction,
+ MessageV0,
+} from "@solana/web3.js";
+import { SOLANA_CLUSTER_ID_BY_NETWORK_ID, SOLANA_NETWORKS } from "../network/svm";
+import {
+ type DynamicWalletConfig,
+ type DynamicWalletExport,
+ type DynamicWalletClient,
+ createDynamicWallet,
+} from "./dynamicShared";
+import type {
+ SignatureStatus,
+ SignatureStatusConfig,
+ RpcResponseAndContext,
+ SignatureResult,
+ Cluster,
+} from "@solana/web3.js";
+import type { Network } from "../network";
+
+/**
+ * Configuration options for the Dynamic Svm wallet provider.
+ */
+export interface DynamicSvmWalletConfig extends DynamicWalletConfig {
+ /** Optional custom connection to use for the wallet */
+ connection?: Connection;
+}
+
+/**
+ * A wallet provider that uses Dynamic's wallet API.
+ * This provider extends the SvmWalletProvider to provide Dynamic-specific wallet functionality
+ * while maintaining compatibility with the base wallet provider interface.
+ */
+export class DynamicSvmWalletProvider extends SvmWalletProvider {
+ #accountAddress: string;
+ #dynamicClient: DynamicWalletClient;
+ #connection: Connection;
+ #genesisHash: string;
+ #publicKey: PublicKey;
+
+ /**
+ * Private constructor to enforce use of factory method.
+ *
+ * @param config - The configuration options for the Dynamic wallet
+ */
+ private constructor(
+ config: DynamicSvmWalletConfig & {
+ accountAddress: string;
+ dynamicClient: DynamicWalletClient;
+ connection: Connection;
+ genesisHash: string;
+ },
+ ) {
+ super();
+ console.log("[DynamicSvmWalletProvider] Initializing provider with:", {
+ accountAddress: config.accountAddress,
+ genesisHash: config.genesisHash,
+ networkId: config.networkId,
+ });
+
+ this.#accountAddress = config.accountAddress;
+ this.#dynamicClient = config.dynamicClient;
+ this.#connection = config.connection;
+ this.#genesisHash = config.genesisHash;
+ this.#publicKey = new PublicKey(config.accountAddress);
+
+ console.log("[DynamicSvmWalletProvider] Provider initialization complete");
+ }
+
+ /**
+ * Creates and configures a new DynamicSvmWalletProvider instance.
+ *
+ * @param config - The configuration options for the Dynamic wallet
+ * @returns A configured DynamicSvmWalletProvider instance
+ *
+ * @example
+ * ```typescript
+ * const provider = await DynamicSvmWalletProvider.configureWithWallet({
+ * authToken: "your-auth-token",
+ * environmentId: "your-environment-id",
+ * chainType: "solana",
+ * networkId: "mainnet-beta",
+ * thresholdSignatureScheme: ThresholdSignatureScheme.TWO_OF_TWO
+ * });
+ * ```
+ */
+ public static async configureWithWallet(
+ config: DynamicSvmWalletConfig,
+ ): Promise {
+ // Derive cluster config from networkId using existing mappings
+ const clusterId = SOLANA_CLUSTER_ID_BY_NETWORK_ID[
+ config.networkId as keyof typeof SOLANA_CLUSTER_ID_BY_NETWORK_ID
+ ] as Cluster;
+ if (!clusterId) {
+ throw new Error(
+ `Unsupported Solana network ID: ${config.networkId}. Use DynamicEvmWalletProvider for EVM networks.`,
+ );
+ }
+
+ console.log("[DynamicSvmWalletProvider] Starting wallet configuration with config:", {
+ networkId: config.networkId,
+ clusterId,
+ environmentId: config.environmentId,
+ });
+
+ try {
+ const { wallet, dynamic } = await createDynamicWallet(config, "solana");
+
+ console.log("[DynamicSvmWalletProvider] Wallet created:", {
+ accountAddress: wallet.accountAddress,
+ });
+
+ const connection = config.connection ?? new Connection(clusterApiUrl(clusterId));
+
+ console.log(
+ "[DynamicSvmWalletProvider] Connection established with endpoint:",
+ connection.rpcEndpoint,
+ );
+
+ const genesisHash = await connection.getGenesisHash();
+ console.log("[DynamicSvmWalletProvider] Genesis hash retrieved:", genesisHash);
+
+ const provider = new DynamicSvmWalletProvider({
+ ...config,
+ accountAddress: wallet.accountAddress,
+ dynamicClient: dynamic,
+ connection,
+ genesisHash,
+ });
+
+ console.log("[DynamicSvmWalletProvider] Provider initialized with:", {
+ address: provider.getAddress(),
+ network: provider.getNetwork(),
+ name: provider.getName(),
+ });
+
+ return provider;
+ } catch (error) {
+ console.error("[DynamicSvmWalletProvider] Error during configuration:", error);
+ throw error;
+ }
+ }
+
+ /**
+ * Signs a message.
+ *
+ * @param message - The message to sign
+ * @returns The signature
+ */
+ public async signMessage(message: string): Promise {
+ return this.#dynamicClient.signMessage({
+ message,
+ accountAddress: this.getAddress(),
+ });
+ }
+
+ /**
+ * Signs a transaction.
+ *
+ * @param transaction - The transaction to sign
+ * @returns The signed transaction
+ */
+ public async signTransaction(transaction: VersionedTransaction): Promise {
+ // Dynamic import for ESM compatibility
+ const { DynamicSvmWalletClient: _DynamicSvmWalletClient } = (await import(
+ "@dynamic-labs-wallet/node-svm"
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ )) as any;
+ const signedTransaction = await (
+ this.#dynamicClient as InstanceType
+ ).signTransaction({
+ senderAddress: this.#accountAddress,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ transaction: transaction as any,
+ });
+ if (!(signedTransaction instanceof VersionedTransaction)) {
+ throw new Error("Expected VersionedTransaction from signTransaction");
+ }
+ return signedTransaction;
+ }
+
+ /**
+ * Sends a transaction.
+ *
+ * @param transaction - The transaction to send
+ * @returns The transaction signature
+ */
+ public async sendTransaction(transaction: VersionedTransaction): Promise {
+ const result = await this.#connection.sendTransaction(transaction);
+ return result;
+ }
+
+ /**
+ * Signs and sends a transaction.
+ *
+ * @param transaction - The transaction to sign and send
+ * @returns The transaction signature
+ */
+ public async signAndSendTransaction(transaction: VersionedTransaction): Promise {
+ const signedTransaction = await this.signTransaction(transaction);
+ return this.sendTransaction(signedTransaction);
+ }
+
+ /**
+ * Gets the status of a transaction.
+ *
+ * @param signature - The transaction signature
+ * @param options - Optional configuration for the status check
+ * @returns The transaction status
+ */
+ public async getSignatureStatus(
+ signature: string,
+ options?: SignatureStatusConfig,
+ ): Promise> {
+ return this.#connection.getSignatureStatus(signature, options);
+ }
+
+ /**
+ * Waits for a transaction signature result.
+ *
+ * @param signature - The transaction signature
+ * @returns The transaction result
+ */
+ public async waitForSignatureResult(
+ signature: string,
+ ): Promise> {
+ const status = await this.#connection.getSignatureStatus(signature);
+ if (!status.value) {
+ throw new Error(`Transaction ${signature} not found`);
+ }
+ return status as RpcResponseAndContext;
+ }
+
+ /**
+ * Gets the network of the wallet.
+ *
+ * @returns The network
+ */
+ public getNetwork(): Network {
+ return SOLANA_NETWORKS[this.#genesisHash];
+ }
+
+ /**
+ * Gets the name of the wallet provider.
+ *
+ * @returns The wallet provider name
+ */
+ public getName(): string {
+ return "dynamic_svm_wallet_provider";
+ }
+
+ /**
+ * Exports the wallet information.
+ *
+ * @returns The wallet information
+ */
+ public async exportWallet(): Promise {
+ return {
+ accountAddress: this.#accountAddress,
+ networkId: this.getNetwork().networkId,
+ };
+ }
+
+ /**
+ * Gets the Solana connection.
+ *
+ * @returns The Solana connection
+ */
+ public getConnection(): Connection {
+ return this.#connection;
+ }
+
+ /**
+ * Gets the public key of the wallet.
+ *
+ * @returns The public key
+ */
+ public getPublicKey(): PublicKey {
+ return this.#publicKey;
+ }
+
+ /**
+ * Gets the address of the wallet.
+ *
+ * @returns The wallet address
+ */
+ public getAddress(): string {
+ return this.#accountAddress;
+ }
+
+ /**
+ * Gets the balance of the wallet.
+ *
+ * @returns The wallet balance in lamports
+ */
+ public async getBalance(): Promise {
+ const balance = await this.#connection.getBalance(this.#publicKey);
+ return BigInt(balance);
+ }
+
+ /**
+ * Performs a native transfer.
+ *
+ * @param to - The recipient address
+ * @param value - The amount to transfer in SOL (as a decimal string, e.g. "0.0001")
+ * @returns The transaction signature
+ */
+ public async nativeTransfer(to: string, value: string): Promise {
+ const initialBalance = await this.getBalance();
+ const solAmount = Number.parseFloat(value);
+ const lamports = BigInt(Math.floor(solAmount * LAMPORTS_PER_SOL));
+
+ // Check if we have enough balance (including estimated fees)
+ if (initialBalance < lamports + BigInt(5000)) {
+ throw new Error(
+ `Insufficient balance. Have ${Number(initialBalance) / LAMPORTS_PER_SOL} SOL, need ${
+ solAmount + 0.000005
+ } SOL (including fees)`,
+ );
+ }
+
+ const toPubkey = new PublicKey(to);
+ const instructions = [
+ ComputeBudgetProgram.setComputeUnitPrice({
+ microLamports: 10000,
+ }),
+ ComputeBudgetProgram.setComputeUnitLimit({
+ units: 2000,
+ }),
+ SystemProgram.transfer({
+ fromPubkey: this.getPublicKey(),
+ toPubkey: toPubkey,
+ lamports: lamports,
+ }),
+ ];
+
+ const tx = new VersionedTransaction(
+ MessageV0.compile({
+ payerKey: this.getPublicKey(),
+ instructions: instructions,
+ recentBlockhash: (await this.#connection.getLatestBlockhash()).blockhash,
+ }),
+ );
+
+ return this.signAndSendTransaction(tx);
+ }
+}
diff --git a/typescript/agentkit/src/wallet-providers/dynamicWalletProvider.test.ts b/typescript/agentkit/src/wallet-providers/dynamicWalletProvider.test.ts
new file mode 100644
index 000000000..6f0cf71fd
--- /dev/null
+++ b/typescript/agentkit/src/wallet-providers/dynamicWalletProvider.test.ts
@@ -0,0 +1,144 @@
+import { DynamicWalletProvider } from "./dynamicWalletProvider";
+import type { DynamicEvmWalletConfig } from "./dynamicEvmWalletProvider";
+import type { DynamicSvmWalletConfig } from "./dynamicSvmWalletProvider";
+import { DynamicEvmWalletProvider } from "./dynamicEvmWalletProvider";
+import { DynamicSvmWalletProvider } from "./dynamicSvmWalletProvider";
+
+global.fetch = jest.fn(() =>
+ Promise.resolve({
+ ok: true,
+ json: () => Promise.resolve({}),
+ } as Response),
+);
+
+jest.mock("../analytics", () => ({
+ sendAnalyticsEvent: jest.fn().mockImplementation(() => Promise.resolve()),
+}));
+
+jest.mock("./dynamicEvmWalletProvider", () => ({
+ DynamicEvmWalletProvider: {
+ configureWithWallet: jest.fn().mockResolvedValue({
+ getAddress: jest.fn().mockReturnValue("0x742d35Cc6634C0532925a3b844Bc454e4438f44e"),
+ getNetwork: jest.fn().mockReturnValue({
+ protocolFamily: "evm",
+ chainId: "1",
+ networkId: "mainnet",
+ }),
+ }),
+ },
+}));
+
+jest.mock("./dynamicSvmWalletProvider", () => ({
+ DynamicSvmWalletProvider: {
+ configureWithWallet: jest.fn().mockResolvedValue({
+ getAddress: jest.fn().mockReturnValue("AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM"),
+ getNetwork: jest.fn().mockReturnValue({
+ protocolFamily: "solana",
+ chainId: "mainnet-beta",
+ networkId: "mainnet-beta",
+ }),
+ }),
+ },
+}));
+
+describe("DynamicWalletProvider", () => {
+ const MOCK_EVM_CONFIG: DynamicEvmWalletConfig = {
+ authToken: "test-auth-token",
+ environmentId: "test-environment-id",
+ chainId: "1",
+ networkId: "mainnet",
+ };
+
+ const MOCK_SVM_CONFIG: DynamicSvmWalletConfig = {
+ authToken: "test-auth-token",
+ environmentId: "test-environment-id",
+ networkId: "mainnet-beta",
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it("should create an EVM wallet provider by default", async () => {
+ const provider = await DynamicWalletProvider.configureWithWallet(MOCK_EVM_CONFIG);
+
+ expect(DynamicEvmWalletProvider.configureWithWallet).toHaveBeenCalledWith(MOCK_EVM_CONFIG);
+ expect(DynamicSvmWalletProvider.configureWithWallet).not.toHaveBeenCalled();
+
+ expect(provider.getAddress()).toBe("0x742d35Cc6634C0532925a3b844Bc454e4438f44e");
+ expect(provider.getNetwork().protocolFamily).toBe("evm");
+ });
+
+ it("should create an EVM wallet provider when explicitly requested", async () => {
+ const config: DynamicEvmWalletConfig = {
+ ...MOCK_EVM_CONFIG,
+ };
+
+ const provider = await DynamicWalletProvider.configureWithWallet(config);
+
+ expect(DynamicEvmWalletProvider.configureWithWallet).toHaveBeenCalledWith(config);
+ expect(DynamicSvmWalletProvider.configureWithWallet).not.toHaveBeenCalled();
+
+ expect(provider.getAddress()).toBe("0x742d35Cc6634C0532925a3b844Bc454e4438f44e");
+ expect(provider.getNetwork().protocolFamily).toBe("evm");
+ });
+
+ it("should create an SVM wallet provider when solana is specified", async () => {
+ const provider = await DynamicWalletProvider.configureWithWallet(MOCK_SVM_CONFIG);
+
+ expect(DynamicSvmWalletProvider.configureWithWallet).toHaveBeenCalledWith(MOCK_SVM_CONFIG);
+ expect(DynamicEvmWalletProvider.configureWithWallet).not.toHaveBeenCalled();
+
+ expect(provider.getAddress()).toBe("AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM");
+ expect(provider.getNetwork().protocolFamily).toBe("solana");
+ });
+
+ it("should pass through all config properties", async () => {
+ const fullConfig: DynamicEvmWalletConfig = {
+ ...MOCK_EVM_CONFIG,
+ chainId: "5",
+ };
+
+ await DynamicWalletProvider.configureWithWallet(fullConfig);
+
+ expect(DynamicEvmWalletProvider.configureWithWallet).toHaveBeenCalledWith(fullConfig);
+ });
+
+ it("should handle initialization failures properly", async () => {
+ const mockEvmConfigureWithWallet = DynamicEvmWalletProvider.configureWithWallet as jest.Mock;
+
+ const originalImplementation = mockEvmConfigureWithWallet.getMockImplementation();
+
+ mockEvmConfigureWithWallet.mockImplementation(() => {
+ throw new Error("Auth token not found");
+ });
+
+ await expect(DynamicWalletProvider.configureWithWallet(MOCK_EVM_CONFIG)).rejects.toThrow(
+ "Auth token not found",
+ );
+
+ mockEvmConfigureWithWallet.mockImplementation(originalImplementation);
+ });
+
+ it("should validate config properly", async () => {
+ const mockEvmConfigureWithWallet = DynamicEvmWalletProvider.configureWithWallet as jest.Mock;
+ const originalImplementation = mockEvmConfigureWithWallet.getMockImplementation();
+
+ mockEvmConfigureWithWallet.mockImplementation(config => {
+ if (!config.authToken) {
+ throw new Error("Missing required authToken");
+ }
+ return Promise.resolve({});
+ });
+
+ const testConfig: Partial = {
+ environmentId: "test-environment-id",
+ };
+
+ await expect(
+ DynamicWalletProvider.configureWithWallet(testConfig as DynamicEvmWalletConfig),
+ ).rejects.toThrow("Missing required authToken");
+
+ mockEvmConfigureWithWallet.mockImplementation(originalImplementation);
+ });
+});
diff --git a/typescript/agentkit/src/wallet-providers/dynamicWalletProvider.ts b/typescript/agentkit/src/wallet-providers/dynamicWalletProvider.ts
new file mode 100644
index 000000000..53413efa0
--- /dev/null
+++ b/typescript/agentkit/src/wallet-providers/dynamicWalletProvider.ts
@@ -0,0 +1,49 @@
+import { DynamicEvmWalletProvider, DynamicEvmWalletConfig } from "./dynamicEvmWalletProvider";
+import { DynamicSvmWalletProvider, DynamicSvmWalletConfig } from "./dynamicSvmWalletProvider";
+
+type DynamicWalletConfig = (DynamicEvmWalletConfig | DynamicSvmWalletConfig) & {
+ chainType?: "ethereum" | "solana";
+};
+
+/**
+ * Factory class for creating Dynamic wallet providers.
+ * This class provides a unified interface for creating both EVM and SVM wallet providers.
+ */
+export class DynamicWalletProvider {
+ /**
+ * Creates and configures a new Dynamic wallet provider instance.
+ *
+ * @param config - The configuration options for the Dynamic wallet
+ * @returns A configured Dynamic wallet provider instance
+ *
+ * @example
+ * ```typescript
+ * // Create an EVM wallet provider
+ * const evmProvider = await DynamicWalletProvider.configureWithWallet({
+ * authToken: "your-auth-token",
+ * environmentId: "your-environment-id",
+ * chainType: "ethereum",
+ * chainId: "84532"
+ * });
+ *
+ * // Create an SVM wallet provider
+ * const svmProvider = await DynamicWalletProvider.configureWithWallet({
+ * authToken: "your-auth-token",
+ * environmentId: "your-environment-id",
+ * chainType: "solana",
+ * networkId: "mainnet-beta"
+ * });
+ * ```
+ */
+ public static async configureWithWallet(
+ config: DynamicWalletConfig,
+ ): Promise {
+ const chainType = config.chainType || "ethereum";
+
+ if (chainType === "ethereum") {
+ return DynamicEvmWalletProvider.configureWithWallet(config as DynamicEvmWalletConfig);
+ } else {
+ return DynamicSvmWalletProvider.configureWithWallet(config as DynamicSvmWalletConfig);
+ }
+ }
+}
diff --git a/typescript/agentkit/src/wallet-providers/index.ts b/typescript/agentkit/src/wallet-providers/index.ts
index 0c727b42b..0ac796474 100644
--- a/typescript/agentkit/src/wallet-providers/index.ts
+++ b/typescript/agentkit/src/wallet-providers/index.ts
@@ -14,3 +14,7 @@ export * from "./privyEvmWalletProvider";
export * from "./privySvmWalletProvider";
export * from "./privyEvmDelegatedEmbeddedWalletProvider";
export * from "./zeroDevWalletProvider";
+export * from "./dynamicWalletProvider";
+export * from "./dynamicEvmWalletProvider";
+export * from "./dynamicSvmWalletProvider";
+export * from "./dynamicShared";
diff --git a/typescript/examples/langchain-dynamic-chatbot/.env-local b/typescript/examples/langchain-dynamic-chatbot/.env-local
new file mode 100644
index 000000000..cc9af4974
--- /dev/null
+++ b/typescript/examples/langchain-dynamic-chatbot/.env-local
@@ -0,0 +1,14 @@
+OPENAI_API_KEY=
+
+# Dynamic Configuration - get these from your Dynamic dashboard
+DYNAMIC_AUTH_TOKEN=
+DYNAMIC_ENVIRONMENT_ID=
+
+# Optional Network ID. If you'd like to use a Dynamic Solana wallet, set to "solana-devnet". Otherwise, defaults to "base-sepolia"
+NETWORK_ID=
+
+# Optional CDP API Key Name. If you'd like to use the CDP API, for example to faucet funds, set this to the name of the CDP API key
+CDP_API_KEY_NAME=
+
+# Optional CDP API Key Private Key. If you'd like to use the CDP API, for example to faucet funds, set this to the private key of the CDP API key
+CDP_API_KEY_PRIVATE_KEY=
\ No newline at end of file
diff --git a/typescript/examples/langchain-dynamic-chatbot/.eslintrc.json b/typescript/examples/langchain-dynamic-chatbot/.eslintrc.json
new file mode 100644
index 000000000..91571ba7a
--- /dev/null
+++ b/typescript/examples/langchain-dynamic-chatbot/.eslintrc.json
@@ -0,0 +1,4 @@
+{
+ "parser": "@typescript-eslint/parser",
+ "extends": ["../../.eslintrc.base.json"]
+}
diff --git a/typescript/examples/langchain-dynamic-chatbot/.prettierrc b/typescript/examples/langchain-dynamic-chatbot/.prettierrc
new file mode 100644
index 000000000..ffb416b74
--- /dev/null
+++ b/typescript/examples/langchain-dynamic-chatbot/.prettierrc
@@ -0,0 +1,11 @@
+{
+ "tabWidth": 2,
+ "useTabs": false,
+ "semi": true,
+ "singleQuote": false,
+ "trailingComma": "all",
+ "bracketSpacing": true,
+ "arrowParens": "avoid",
+ "printWidth": 100,
+ "proseWrap": "never"
+}
diff --git a/typescript/examples/langchain-dynamic-chatbot/README.md b/typescript/examples/langchain-dynamic-chatbot/README.md
new file mode 100644
index 000000000..257aee14c
--- /dev/null
+++ b/typescript/examples/langchain-dynamic-chatbot/README.md
@@ -0,0 +1,80 @@
+# Dynamic AgentKit LangChain Extension Examples - Chatbot Typescript
+
+This example demonstrates an agent setup as a terminal style chatbot with access to the full set of CDP AgentKit actions using Dynamic wallet provider.
+
+## Ask the chatbot to engage in the Web3 ecosystem!
+
+- "Transfer a portion of your ETH to a random address"
+- "What is the price of BTC?"
+- "Deploy an NFT that will go super viral!"
+- "Deploy an ERC-20 token with total supply 1 billion"
+
+## Prerequisites
+
+### Checking Node Version
+
+Before using the example, ensure that you have the correct version of Node.js installed. The example requires Node.js 20 or higher. You can check your Node version by running:
+
+```bash
+node --version
+```
+
+If you don't have the correct version, you can install it using [nvm](https://github.com/nvm-sh/nvm):
+
+```bash
+nvm install node
+```
+
+This will automatically install and use the latest version of Node.
+
+### API Keys
+
+You'll need the following API keys:
+- [Dynamic Account](https://www.dynamic.xyz/) and API credentials
+- [OpenAI API Key](https://platform.openai.com/docs/quickstart#create-and-export-an-api-key)
+
+Once you have them, rename the `.env-local` file to `.env` and make sure you set the API keys to their corresponding environment variables:
+
+- "OPENAI_API_KEY"
+- "DYNAMIC_AUTH_TOKEN"
+- "DYNAMIC_ENVIRONMENT_ID"
+
+## Running the example
+
+From the root directory, run:
+
+```bash
+pnpm install
+pnpm build
+```
+
+This will install the dependencies and build the packages locally. The chatbot example uses the local `@coinbase/agentkit-langchain` and `@coinbase/agentkit` packages. If you make changes to the packages, you can run `pnpm build` from root again to rebuild the packages, and your changes will be reflected in the chatbot example.
+
+Now from the `typescript/examples/langchain-dynamic-chatbot` directory, run:
+
+```bash
+pnpm start
+```
+
+Select "1. chat mode" and start telling your Agent to do things onchain!
+
+## Features
+
+- Uses Dynamic's wallet API for EVM and Solana blockchain interactions
+- Integrates with LangChain for natural language processing
+- Supports both interactive chat and autonomous modes
+- Can perform various blockchain actions like:
+ - Checking wallet balance
+ - Sending transactions
+ - Interacting with smart contracts
+ - And more!
+
+## Learn More
+
+- [AgentKit Documentation](https://docs.cdp.coinbase.com)
+- [Dynamic Documentation](https://docs.dynamic.xyz)
+- [LangChain Documentation](https://js.langchain.com/docs)
+
+## License
+
+Apache-2.0
diff --git a/typescript/examples/langchain-dynamic-chatbot/chatbot.ts b/typescript/examples/langchain-dynamic-chatbot/chatbot.ts
new file mode 100644
index 000000000..5852b7715
--- /dev/null
+++ b/typescript/examples/langchain-dynamic-chatbot/chatbot.ts
@@ -0,0 +1,350 @@
+import {
+ AgentKit,
+ DynamicEvmWalletProvider,
+ DynamicSvmWalletProvider,
+ wethActionProvider,
+ walletActionProvider,
+ erc20ActionProvider,
+ pythActionProvider,
+ cdpApiActionProvider,
+ splActionProvider,
+ x402ActionProvider,
+} from "@coinbase/agentkit";
+import { getLangChainTools } from "@coinbase/agentkit-langchain";
+import { HumanMessage } from "@langchain/core/messages";
+import { MemorySaver } from "@langchain/langgraph";
+import { createReactAgent } from "@langchain/langgraph/prebuilt";
+import { ChatOpenAI } from "@langchain/openai";
+import * as dotenv from "dotenv";
+import * as fs from "fs";
+import * as readline from "readline";
+
+dotenv.config();
+
+/**
+ * Validates that required environment variables are set
+ *
+ * @throws {Error} - If required environment variables are missing
+ * @returns {void}
+ */
+function validateEnvironment(): void {
+ const missingVars: string[] = [];
+
+ // Check required variables
+ const requiredVars = [
+ "OPENAI_API_KEY",
+ "DYNAMIC_AUTH_TOKEN",
+ "DYNAMIC_ENVIRONMENT_ID",
+ ];
+ requiredVars.forEach(varName => {
+ if (!process.env[varName]) {
+ missingVars.push(varName);
+ }
+ });
+
+ // Exit if any required variables are missing
+ if (missingVars.length > 0) {
+ console.error("Error: Required environment variables are not set");
+ missingVars.forEach(varName => {
+ console.error(`${varName}=your_${varName.toLowerCase()}_here`);
+ });
+ process.exit(1);
+ }
+
+ // Warn about optional NETWORK_ID
+ if (!process.env.NETWORK_ID) {
+ console.warn("Warning: NETWORK_ID not set, defaulting to base-sepolia testnet");
+ }
+}
+
+// Add this right after imports and before any other code
+validateEnvironment();
+
+type WalletData = {
+ accountAddress: string;
+ networkId: string;
+};
+
+/**
+ * Type guard to check if the wallet provider is an EVM provider
+ *
+ * @param walletProvider - The wallet provider to check
+ * @returns True if the wallet provider is an EVM provider, false otherwise
+ */
+function isEvmWalletProvider(
+ walletProvider: DynamicEvmWalletProvider | DynamicSvmWalletProvider,
+): walletProvider is DynamicEvmWalletProvider {
+ return walletProvider instanceof DynamicEvmWalletProvider;
+}
+
+/**
+ * Type guard to check if the wallet provider is a Solana provider
+ *
+ * @param walletProvider - The wallet provider to check
+ * @returns True if the wallet provider is a Solana provider, false otherwise
+ */
+function isSolanaWalletProvider(
+ walletProvider: DynamicEvmWalletProvider | DynamicSvmWalletProvider,
+): walletProvider is DynamicSvmWalletProvider {
+ return walletProvider instanceof DynamicSvmWalletProvider;
+}
+
+/**
+ * Initialize the agent with Dynamic Agentkit
+ *
+ * @returns Agent executor and config
+ */
+async function initializeAgent() {
+ try {
+ // Initialize LLM
+ const llm = new ChatOpenAI({
+ model: "gpt-4o-mini",
+ });
+
+ // Configure Dynamic Wallet Provider
+ const networkId = process.env.NETWORK_ID || "base-sepolia";
+ const isSolana = networkId.includes("solana");
+ const thresholdSignatureScheme = process.env.DYNAMIC_THRESHOLD_SIGNATURE_SCHEME || "TWO_OF_TWO";
+ const walletDataFile = `wallet_data_${networkId.replace(/-/g, "_")}.txt`;
+
+ let walletData: WalletData | null = null;
+
+ // Read existing wallet data if available
+ if (fs.existsSync(walletDataFile)) {
+ try {
+ walletData = JSON.parse(fs.readFileSync(walletDataFile, "utf8")) as WalletData;
+ console.log(`Loaded existing wallet data for ${networkId}:`, walletData.accountAddress);
+ } catch (error) {
+ console.error(`Error reading wallet data for ${networkId}:`, error);
+ // Continue without wallet data
+ }
+ }
+
+ const dynamicWalletConfig = {
+ authToken: process.env.DYNAMIC_AUTH_TOKEN as string,
+ environmentId: process.env.DYNAMIC_ENVIRONMENT_ID as string,
+ networkId,
+ thresholdSignatureScheme,
+ accountAddress: walletData?.accountAddress,
+ };
+
+ const walletProvider = isSolana
+ ? await DynamicSvmWalletProvider.configureWithWallet(dynamicWalletConfig)
+ : await DynamicEvmWalletProvider.configureWithWallet(dynamicWalletConfig);
+
+
+ const actionProviders = [
+ walletActionProvider(),
+ cdpApiActionProvider(),
+ pythActionProvider(),
+ ...(isEvmWalletProvider(walletProvider)
+ ? [
+ wethActionProvider(),
+ erc20ActionProvider(),
+ x402ActionProvider(),
+ ]
+ : isSolanaWalletProvider(walletProvider)
+ ? [splActionProvider()]
+ : []),
+ ];
+
+ // Initialize AgentKit
+ const agentkit = await AgentKit.from({
+ walletProvider,
+ actionProviders,
+ });
+
+ const tools = await getLangChainTools(agentkit);
+
+ // Store buffered conversation history in memory
+ const memory = new MemorySaver();
+ const agentConfig = { configurable: { thread_id: "Dynamic AgentKit Chatbot Example!" } };
+
+ // Create React Agent using the LLM and Dynamic AgentKit tools
+ const agent = createReactAgent({
+ llm,
+ tools,
+ checkpointSaver: memory,
+ messageModifier: `
+ You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit with a Dynamic wallet. You are
+ empowered to interact onchain using your tools. If you ever need funds, you can request them from the
+ faucet if you are on network ID 'base-sepolia'. If not, you can provide your wallet details and request
+ funds from the user. Before executing your first action, get the wallet details to see what network
+ you're on. If there is a 5XX (internal) HTTP error code, ask the user to try again later. If someone
+ asks you to do something you can't do with your currently available tools, you must say so, and
+ encourage them to implement it themselves using the CDP SDK + Agentkit, recommend they go to
+ docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from
+ restating your tools' descriptions unless it is explicitly requested.
+ `,
+ });
+
+ // Save wallet data
+ if (!walletData) {
+ const exportedWallet = await walletProvider.exportWallet();
+ fs.writeFileSync(
+ walletDataFile,
+ JSON.stringify({
+ accountAddress: exportedWallet.accountAddress,
+ networkId: exportedWallet.networkId,
+ } as WalletData),
+ );
+ console.log(`Saved wallet data to ${walletDataFile}`);
+ }
+
+ return { agent, config: agentConfig };
+ } catch (error) {
+ console.error("Failed to initialize agent:", error);
+ throw error; // Re-throw to be handled by caller
+ }
+}
+
+/**
+ * Run the agent autonomously with specified intervals
+ *
+ * @param agent - The agent executor
+ * @param config - Agent configuration
+ * @param interval - Time interval between actions in seconds
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+async function runAutonomousMode(agent: any, config: any, interval = 10) {
+ console.log("Starting autonomous mode...");
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ try {
+ const thought =
+ "Be creative and do something interesting on the blockchain. " +
+ "Choose an action or set of actions and execute it that highlights your abilities.";
+
+ const stream = await agent.stream({ messages: [new HumanMessage(thought)] }, config);
+
+ for await (const chunk of stream) {
+ if ("agent" in chunk) {
+ console.log(chunk.agent.messages[0].content);
+ } else if ("tools" in chunk) {
+ console.log(chunk.tools.messages[0].content);
+ }
+ console.log("-------------------");
+ }
+
+ await new Promise(resolve => setTimeout(resolve, interval * 1000));
+ } catch (error) {
+ if (error instanceof Error) {
+ console.error("Error:", error.message);
+ }
+ process.exit(1);
+ }
+ }
+}
+
+/**
+ * Run the agent interactively based on user input
+ *
+ * @param agent - The agent executor
+ * @param config - Agent configuration
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+async function runChatMode(agent: any, config: any) {
+ console.log("Starting chat mode... Type 'exit' to end.");
+
+ const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
+
+ const question = (prompt: string): Promise =>
+ new Promise(resolve => rl.question(prompt, resolve));
+
+ try {
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const userInput = await question("\nPrompt: ");
+
+ if (userInput.toLowerCase() === "exit") {
+ break;
+ }
+
+ const stream = await agent.stream({ messages: [new HumanMessage(userInput)] }, config);
+
+ for await (const chunk of stream) {
+ if ("agent" in chunk) {
+ console.log(chunk.agent.messages[0].content);
+ } else if ("tools" in chunk) {
+ console.log(chunk.tools.messages[0].content);
+ }
+ console.log("-------------------");
+ }
+ }
+ } catch (error) {
+ if (error instanceof Error) {
+ console.error("Error:", error.message);
+ }
+ process.exit(1);
+ } finally {
+ rl.close();
+ }
+}
+
+/**
+ * Choose whether to run in autonomous or chat mode based on user input
+ *
+ * @returns Selected mode
+ */
+async function chooseMode(): Promise<"chat" | "auto"> {
+ const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
+
+ const question = (prompt: string): Promise =>
+ new Promise(resolve => rl.question(prompt, resolve));
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ console.log("\nAvailable modes:");
+ console.log("1. chat - Interactive chat mode");
+ console.log("2. auto - Autonomous action mode");
+
+ const choice = (await question("\nChoose a mode (enter number or name): "))
+ .toLowerCase()
+ .trim();
+
+ if (choice === "1" || choice === "chat") {
+ rl.close();
+ return "chat";
+ } else if (choice === "2" || choice === "auto") {
+ rl.close();
+ return "auto";
+ }
+ console.log("Invalid choice. Please try again.");
+ }
+}
+
+/**
+ * Start the chatbot agent
+ */
+async function main() {
+ try {
+ const { agent, config } = await initializeAgent();
+ const mode = await chooseMode();
+
+ if (mode === "chat") {
+ await runChatMode(agent, config);
+ } else {
+ await runAutonomousMode(agent, config);
+ }
+ } catch (error) {
+ if (error instanceof Error) {
+ console.error("Error:", error.message);
+ }
+ process.exit(1);
+ }
+}
+
+if (require.main === module) {
+ console.log("Starting Agent...");
+ main().catch(error => {
+ console.error("Fatal error:", error);
+ process.exit(1);
+ });
+}
\ No newline at end of file
diff --git a/typescript/examples/langchain-dynamic-chatbot/package.json b/typescript/examples/langchain-dynamic-chatbot/package.json
new file mode 100644
index 000000000..d2f060475
--- /dev/null
+++ b/typescript/examples/langchain-dynamic-chatbot/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "@coinbase/dynamic-langchain-chatbot-example",
+ "description": "Dynamic AgentKit Node.js SDK Chatbot Example",
+ "version": "1.0.0",
+ "private": true,
+ "license": "Apache-2.0",
+ "scripts": {
+ "start": "NODE_OPTIONS='--no-warnings' ts-node ./chatbot.ts",
+ "dev": "nodemon ./chatbot.ts",
+ "lint": "eslint -c .eslintrc.json *.ts",
+ "lint:fix": "eslint -c .eslintrc.json *.ts --fix",
+ "format": "prettier --write \"**/*.{ts,js,cjs,json,md}\"",
+ "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\""
+ },
+ "dependencies": {
+ "@coinbase/agentkit": "workspace:*",
+ "@coinbase/agentkit-langchain": "workspace:*",
+ "@langchain/langgraph": "^0.2.21",
+ "@langchain/openai": "^0.3.14",
+ "@langchain/core": "^0.3.19",
+ "dotenv": "^16.4.5",
+ "zod": "^3.22.4"
+ },
+ "devDependencies": {
+ "nodemon": "^3.1.0",
+ "ts-node": "^10.9.2"
+ }
+}
diff --git a/typescript/examples/langchain-dynamic-chatbot/tsconfig.json b/typescript/examples/langchain-dynamic-chatbot/tsconfig.json
new file mode 100644
index 000000000..6fee1565b
--- /dev/null
+++ b/typescript/examples/langchain-dynamic-chatbot/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "preserveSymlinks": true,
+ "outDir": "./dist",
+ "rootDir": "."
+ },
+ "include": ["*.ts"]
+}
diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml
index 8972eac54..9f0c3c2ec 100644
--- a/typescript/pnpm-lock.yaml
+++ b/typescript/pnpm-lock.yaml
@@ -80,6 +80,15 @@ importers:
'@coinbase/x402':
specifier: ^0.6.3
version: 0.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))
+ '@dynamic-labs-wallet/node':
+ specifier: 0.0.169
+ version: 0.0.169
+ '@dynamic-labs-wallet/node-evm':
+ specifier: 0.0.169
+ version: 0.0.169(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2))
+ '@dynamic-labs-wallet/node-svm':
+ specifier: 0.0.169
+ version: 0.0.169(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
'@jup-ag/api':
specifier: ^6.0.39
version: 6.0.40
@@ -91,10 +100,10 @@ importers:
version: 1.18.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2))
'@solana/spl-token':
specifier: ^0.4.12
- version: 0.4.13(@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ version: 0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)
'@solana/web3.js':
- specifier: ^1.98.1
- version: 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ specifier: ^1.98.2
+ version: 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
'@zerodev/ecdsa-validator':
specifier: ^5.4.5
version: 5.4.5(@zerodev/sdk@5.4.28(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)))(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2))
@@ -118,7 +127,7 @@ importers:
version: 2.1.0
clanker-sdk:
specifier: ^4.1.18
- version: 4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2))
+ version: 4.1.19(@types/node@22.13.14)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2))
decimal.js:
specifier: ^10.5.0
version: 10.5.0
@@ -176,7 +185,7 @@ importers:
version: 14.1.1
jest:
specifier: ^29.7.0
- version: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2))
+ version: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
mock-fs:
specifier: ^5.2.0
version: 5.5.0
@@ -194,7 +203,7 @@ importers:
version: 2.4.2
ts-jest:
specifier: ^29.2.5
- version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)))(typescript@5.8.2)
+ version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2)
tsd:
specifier: ^0.31.2
version: 0.31.2
@@ -307,6 +316,37 @@ importers:
specifier: ^10.9.2
version: 10.9.2(@types/node@22.13.14)(typescript@5.8.2)
+ examples/langchain-dynamic-chatbot:
+ dependencies:
+ '@coinbase/agentkit':
+ specifier: workspace:*
+ version: link:../../agentkit
+ '@coinbase/agentkit-langchain':
+ specifier: workspace:*
+ version: link:../../framework-extensions/langchain
+ '@langchain/core':
+ specifier: ^0.3.19
+ version: 0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56))
+ '@langchain/langgraph':
+ specifier: ^0.2.21
+ version: 0.2.74(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))(react@18.3.1)(zod-to-json-schema@3.24.5(zod@3.25.56))
+ '@langchain/openai':
+ specifier: ^0.3.14
+ version: 0.3.17(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))
+ dotenv:
+ specifier: ^16.4.5
+ version: 16.4.7
+ zod:
+ specifier: ^3.22.4
+ version: 3.25.56
+ devDependencies:
+ nodemon:
+ specifier: ^3.1.0
+ version: 3.1.9
+ ts-node:
+ specifier: ^10.9.2
+ version: 10.9.2(@types/node@22.13.14)(typescript@5.8.2)
+
examples/langchain-farcaster-chatbot:
dependencies:
'@coinbase/agentkit':
@@ -966,6 +1006,26 @@ packages:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
+ '@dynamic-labs-wallet/core@0.0.169':
+ resolution: {integrity: sha512-NT/sWD0K6VQy4BG3gjnTTg4hFXtYEhmCT1jPUADpbWkKhrf2DPGlfeIcDA6quvBvWVg4oagAGU4P2N0fTKiNxA==}
+
+ '@dynamic-labs-wallet/node-evm@0.0.169':
+ resolution: {integrity: sha512-Q/7Ln+/iB2SgFOTT/CgGj2K0wozyyjxryuG0ORicLFAS7xTyRs442zHusmXj6UMAm5Zps0dao6UEHVVhiTHRkw==}
+ peerDependencies:
+ viem: ^2.22.1
+
+ '@dynamic-labs-wallet/node-svm@0.0.169':
+ resolution: {integrity: sha512-TCHL1TFN+GZpOZxH8xUZHoyE8ETV09nnaWsbcxlFzePslInKXRNa75sRW+Z8TjIsfkucr+bnADrD+jgBNNopCw==}
+
+ '@dynamic-labs-wallet/node@0.0.169':
+ resolution: {integrity: sha512-3CuqNIhRobxtkVrun+fRplButEfRoLyD3kbfQiZIOK+Kf3atcKGcQnbJrraTiRpBqGHwMaD/dupMyPFk6R93Xw==}
+
+ '@dynamic-labs/logger@4.32.1':
+ resolution: {integrity: sha512-6A1xrzQiE5yMOt/3HAzLlzNhMKBfpDEgy/gqfxWOKe+ZfqOwMboC+R6QNd0SWo75agUBfipRCiflPioH4ELVcA==}
+
+ '@dynamic-labs/sdk-api-core@0.0.764':
+ resolution: {integrity: sha512-79JptJTTClLc9qhioThtwMuzTHJ+mrj8sTEglb7Mcx3lJub9YbXqNdzS9mLRxZsr2et3aqqpzymXdUBzSEaMng==}
+
'@ecies/ciphers@0.2.4':
resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==}
engines: {bun: '>=1', deno: '>=2', node: '>=16'}
@@ -1401,6 +1461,12 @@ packages:
peerDependencies:
'@langchain/core': '>=0.2.31 <0.4.0'
+ '@langchain/langgraph-checkpoint@0.0.18':
+ resolution: {integrity: sha512-IS7zJj36VgY+4pf8ZjsVuUWef7oTwt1y9ylvwu0aLuOn1d0fg05Om9DLm3v2GZ2Df6bhLV1kfWAM0IAl9O5rQQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@langchain/core': '>=0.2.31 <0.4.0'
+
'@langchain/langgraph-sdk@0.0.60':
resolution: {integrity: sha512-7ndeAdw1afVY72HpKEGw7AyuDlD7U3e4jxaJflxA+PXaFPiE0d/hQYvlPT84YmvqNzJN605hv7YcrOju2573bQ==}
peerDependencies:
@@ -1422,6 +1488,16 @@ packages:
zod-to-json-schema:
optional: true
+ '@langchain/langgraph@0.2.74':
+ resolution: {integrity: sha512-oHpEi5sTZTPaeZX1UnzfM2OAJ21QGQrwReTV6+QnX7h8nDCBzhtipAw1cK616S+X8zpcVOjgOtJuaJhXa4mN8w==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@langchain/core': '>=0.2.36 <0.3.0 || >=0.3.40 < 0.4.0'
+ zod-to-json-schema: ^3.x
+ peerDependenciesMeta:
+ zod-to-json-schema:
+ optional: true
+
'@langchain/openai@0.3.17':
resolution: {integrity: sha512-uw4po32OKptVjq+CYHrumgbfh4NuD7LqyE+ZgqY9I/LrLc6bHLMc+sisHmI17vgek0K/yqtarI0alPJbzrwyag==}
engines: {node: '>=18'}
@@ -1819,12 +1895,6 @@ packages:
peerDependencies:
typescript: '>=5'
- '@solana/codecs-core@2.1.0':
- resolution: {integrity: sha512-SR7pKtmJBg2mhmkel2NeHA1pz06QeQXdMv8WJoIR9m8F/hw80K/612uaYbwTt2nkK0jg/Qn/rNSd7EcJ4SBGjw==}
- engines: {node: '>=20.18.0'}
- peerDependencies:
- typescript: '>=5'
-
'@solana/codecs-core@2.3.0':
resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==}
engines: {node: '>=20.18.0'}
@@ -1847,12 +1917,6 @@ packages:
peerDependencies:
typescript: '>=5'
- '@solana/codecs-numbers@2.1.0':
- resolution: {integrity: sha512-XMu4yw5iCgQnMKsxSWPPOrGgtaohmupN3eyAtYv3K3C/MJEc5V90h74k5B1GUCiHvcrdUDO9RclNjD9lgbjFag==}
- engines: {node: '>=20.18.0'}
- peerDependencies:
- typescript: '>=5'
-
'@solana/codecs-numbers@2.3.0':
resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==}
engines: {node: '>=20.18.0'}
@@ -1889,13 +1953,6 @@ packages:
peerDependencies:
typescript: '>=5'
- '@solana/errors@2.1.0':
- resolution: {integrity: sha512-l+GxAv0Ar4d3c3PlZdA9G++wFYZREEbbRyAFP8+n8HSg0vudCuzogh/13io6hYuUhG/9Ve8ARZNamhV7UScKNw==}
- engines: {node: '>=20.18.0'}
- hasBin: true
- peerDependencies:
- typescript: '>=5'
-
'@solana/errors@2.3.0':
resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==}
engines: {node: '>=20.18.0'}
@@ -2092,8 +2149,8 @@ packages:
'@solana/web3.js@1.98.0':
resolution: {integrity: sha512-nz3Q5OeyGFpFCR+erX2f6JPt3sKhzhYcSycBCSPkWjzSVDh/Rr1FqTVMRe58FKO16/ivTUcuJjeS5MyBvpkbzA==}
- '@solana/web3.js@1.98.1':
- resolution: {integrity: sha512-gRAq1YPbfSDAbmho4kY7P/8iLIjMWXAzBJdP9iENFR+dFQSBSueHzjK/ou8fxhqHP9j+J4Msl4p/oDemFcIjlg==}
+ '@solana/web3.js@1.98.4':
+ resolution: {integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==}
'@stablelib/base64@1.0.1':
resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==}
@@ -2974,10 +3031,6 @@ packages:
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
engines: {node: '>=18'}
- commander@13.1.0:
- resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
- engines: {node: '>=18'}
-
commander@14.0.1:
resolution: {integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==}
engines: {node: '>=20'}
@@ -5979,6 +6032,10 @@ packages:
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
hasBin: true
+ uuid@11.1.0:
+ resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
+ hasBin: true
+
uuid@8.3.2:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true
@@ -6756,8 +6813,8 @@ snapshots:
'@coinbase/cdp-sdk@1.38.1(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)':
dependencies:
- '@solana/spl-token': 0.4.13(@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)
- '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ '@solana/spl-token': 0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
abitype: 1.0.6(typescript@5.8.2)(zod@3.25.56)
axios: 1.12.2
axios-retry: 4.5.0(axios@1.12.2)
@@ -6876,6 +6933,49 @@ snapshots:
dependencies:
'@jridgewell/trace-mapping': 0.3.9
+ '@dynamic-labs-wallet/core@0.0.169':
+ dependencies:
+ '@dynamic-labs/sdk-api-core': 0.0.764
+ axios: 1.9.0
+ uuid: 11.1.0
+ transitivePeerDependencies:
+ - debug
+
+ '@dynamic-labs-wallet/node-evm@0.0.169(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2))':
+ dependencies:
+ '@dynamic-labs-wallet/node': 0.0.169
+ '@dynamic-labs/sdk-api-core': 0.0.764
+ viem: 2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)
+ transitivePeerDependencies:
+ - debug
+
+ '@dynamic-labs-wallet/node-svm@0.0.169(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)':
+ dependencies:
+ '@dynamic-labs-wallet/node': 0.0.169
+ '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - encoding
+ - typescript
+ - utf-8-validate
+
+ '@dynamic-labs-wallet/node@0.0.169':
+ dependencies:
+ '@dynamic-labs-wallet/core': 0.0.169
+ '@dynamic-labs/logger': 4.32.1
+ '@dynamic-labs/sdk-api-core': 0.0.764
+ '@noble/hashes': 1.7.1
+ uuid: 11.1.0
+ transitivePeerDependencies:
+ - debug
+
+ '@dynamic-labs/logger@4.32.1':
+ dependencies:
+ eventemitter3: 5.0.1
+
+ '@dynamic-labs/sdk-api-core@0.0.764': {}
+
'@ecies/ciphers@0.2.4(@noble/ciphers@1.3.0)':
dependencies:
'@noble/ciphers': 1.3.0
@@ -7293,12 +7393,12 @@ snapshots:
'@humanwhocodes/object-schema@2.0.3': {}
- '@inquirer/external-editor@1.0.1(@types/node@20.17.27)':
+ '@inquirer/external-editor@1.0.1(@types/node@22.13.14)':
dependencies:
chardet: 2.1.0
iconv-lite: 0.6.3
optionalDependencies:
- '@types/node': 20.17.27
+ '@types/node': 22.13.14
'@istanbuljs/load-nyc-config@1.1.0':
dependencies:
@@ -7354,6 +7454,41 @@ snapshots:
- supports-color
- ts-node
+ '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))':
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/reporters': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.27
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-changed-files: 29.7.0
+ jest-config: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ jest-haste-map: 29.7.0
+ jest-message-util: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-resolve-dependencies: 29.7.0
+ jest-runner: 29.7.0
+ jest-runtime: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ jest-watcher: 29.7.0
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-ansi: 6.0.1
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
'@jest/environment@29.7.0':
dependencies:
'@jest/fake-timers': 29.7.0
@@ -7584,6 +7719,11 @@ snapshots:
'@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56))
uuid: 10.0.0
+ '@langchain/langgraph-checkpoint@0.0.18(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))':
+ dependencies:
+ '@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56))
+ uuid: 10.0.0
+
'@langchain/langgraph-sdk@0.0.60(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))(react@18.3.1)':
dependencies:
'@types/json-schema': 7.0.15
@@ -7672,6 +7812,18 @@ snapshots:
transitivePeerDependencies:
- react
+ '@langchain/langgraph@0.2.74(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))(react@18.3.1)(zod-to-json-schema@3.24.5(zod@3.25.56))':
+ dependencies:
+ '@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56))
+ '@langchain/langgraph-checkpoint': 0.0.18(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))
+ '@langchain/langgraph-sdk': 0.0.60(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))(react@18.3.1)
+ uuid: 10.0.0
+ zod: 3.25.56
+ optionalDependencies:
+ zod-to-json-schema: 3.24.5(zod@3.25.56)
+ transitivePeerDependencies:
+ - react
+
'@langchain/openai@0.3.17(@langchain/core@0.3.30(openai@4.89.1(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56)))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))':
dependencies:
'@langchain/core': 0.3.30(openai@4.89.1(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.56))
@@ -8039,7 +8191,7 @@ snapshots:
dependencies:
'@noble/curves': 1.8.1
'@noble/hashes': 1.7.1
- '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
canonicalize: 2.1.0
dotenv: 16.4.7
jose: 4.15.9
@@ -8485,7 +8637,7 @@ snapshots:
'@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)':
dependencies:
'@solana/buffer-layout': 4.0.1
- '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
bigint-buffer: 1.1.5
bignumber.js: 9.1.2
transitivePeerDependencies:
@@ -8503,11 +8655,6 @@ snapshots:
'@solana/errors': 2.0.0-rc.1(typescript@5.8.2)
typescript: 5.8.2
- '@solana/codecs-core@2.1.0(typescript@5.8.2)':
- dependencies:
- '@solana/errors': 2.1.0(typescript@5.8.2)
- typescript: 5.8.2
-
'@solana/codecs-core@2.3.0(typescript@5.8.2)':
dependencies:
'@solana/errors': 2.3.0(typescript@5.8.2)
@@ -8533,12 +8680,6 @@ snapshots:
'@solana/errors': 2.0.0-rc.1(typescript@5.8.2)
typescript: 5.8.2
- '@solana/codecs-numbers@2.1.0(typescript@5.8.2)':
- dependencies:
- '@solana/codecs-core': 2.1.0(typescript@5.8.2)
- '@solana/errors': 2.1.0(typescript@5.8.2)
- typescript: 5.8.2
-
'@solana/codecs-numbers@2.3.0(typescript@5.8.2)':
dependencies:
'@solana/codecs-core': 2.3.0(typescript@5.8.2)
@@ -8589,12 +8730,6 @@ snapshots:
commander: 12.1.0
typescript: 5.8.2
- '@solana/errors@2.1.0(typescript@5.8.2)':
- dependencies:
- chalk: 5.4.1
- commander: 13.1.0
- typescript: 5.8.2
-
'@solana/errors@2.3.0(typescript@5.8.2)':
dependencies:
chalk: 5.4.1
@@ -8828,29 +8963,29 @@ snapshots:
transitivePeerDependencies:
- fastestsmallesttextencoderdecoder
- '@solana/spl-token-group@0.0.7(@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)':
+ '@solana/spl-token-group@0.0.7(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)':
dependencies:
'@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)
- '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
transitivePeerDependencies:
- fastestsmallesttextencoderdecoder
- typescript
- '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)':
+ '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)':
dependencies:
'@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)
- '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
transitivePeerDependencies:
- fastestsmallesttextencoderdecoder
- typescript
- '@solana/spl-token@0.4.13(@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)':
+ '@solana/spl-token@0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)':
dependencies:
'@solana/buffer-layout': 4.0.1
'@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
- '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)
- '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)
- '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
+ '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)
+ '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)
+ '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)
buffer: 6.0.3
transitivePeerDependencies:
- bufferutil
@@ -8946,13 +9081,13 @@ snapshots:
- encoding
- utf-8-validate
- '@solana/web3.js@1.98.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)':
+ '@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)':
dependencies:
'@babel/runtime': 7.27.0
- '@noble/curves': 1.8.1
- '@noble/hashes': 1.7.1
+ '@noble/curves': 1.9.6
+ '@noble/hashes': 1.8.0
'@solana/buffer-layout': 4.0.1
- '@solana/codecs-numbers': 2.1.0(typescript@5.8.2)
+ '@solana/codecs-numbers': 2.3.0(typescript@5.8.2)
agentkeepalive: 4.6.0
bn.js: 5.2.1
borsh: 0.7.0
@@ -10402,12 +10537,12 @@ snapshots:
cjs-module-lexer@1.4.3: {}
- clanker-sdk@4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)):
+ clanker-sdk@4.1.19(@types/node@22.13.14)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)):
dependencies:
'@openzeppelin/merkle-tree': 1.0.8
abitype: 1.0.8(typescript@5.8.2)(zod@3.25.56)
dotenv: 16.4.7
- inquirer: 8.2.7(@types/node@20.17.27)
+ inquirer: 8.2.7(@types/node@22.13.14)
viem: 2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)
zod: 3.25.56
transitivePeerDependencies:
@@ -10465,8 +10600,6 @@ snapshots:
commander@12.1.0: {}
- commander@13.1.0: {}
-
commander@14.0.1: {}
commander@2.20.3: {}
@@ -10525,6 +10658,21 @@ snapshots:
- supports-color
- ts-node
+ create-jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
+ dependencies:
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ jest-util: 29.7.0
+ prompts: 2.4.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
create-require@1.1.1: {}
cross-fetch@3.2.0:
@@ -11636,9 +11784,9 @@ snapshots:
inherits@2.0.4: {}
- inquirer@8.2.7(@types/node@20.17.27):
+ inquirer@8.2.7(@types/node@22.13.14):
dependencies:
- '@inquirer/external-editor': 1.0.1(@types/node@20.17.27)
+ '@inquirer/external-editor': 1.0.1(@types/node@22.13.14)
ansi-escapes: 4.3.2
chalk: 4.1.2
cli-cursor: 3.1.0
@@ -11959,6 +12107,25 @@ snapshots:
- supports-color
- ts-node
+ jest-cli@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ create-jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ exit: 0.1.2
+ import-local: 3.2.0
+ jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)):
dependencies:
'@babel/core': 7.26.10
@@ -11990,6 +12157,68 @@ snapshots:
- babel-plugin-macros
- supports-color
+ jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
+ dependencies:
+ '@babel/core': 7.26.10
+ '@jest/test-sequencer': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.26.10)
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ deepmerge: 4.3.1
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-circus: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-get-type: 29.6.3
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-runner: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ micromatch: 4.0.8
+ parse-json: 5.2.0
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-json-comments: 3.1.1
+ optionalDependencies:
+ '@types/node': 20.17.27
+ ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2)
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-config@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
+ dependencies:
+ '@babel/core': 7.26.10
+ '@jest/test-sequencer': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.26.10)
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ deepmerge: 4.3.1
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-circus: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-get-type: 29.6.3
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-runner: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ micromatch: 4.0.8
+ parse-json: 5.2.0
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-json-comments: 3.1.1
+ optionalDependencies:
+ '@types/node': 22.13.14
+ ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2)
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
jest-diff@29.7.0:
dependencies:
chalk: 4.1.2
@@ -12217,6 +12446,18 @@ snapshots:
- supports-color
- ts-node
+ jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ '@jest/types': 29.6.3
+ import-local: 3.2.0
+ jest-cli: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
jose@4.15.9: {}
jose@5.10.0: {}
@@ -13767,6 +14008,26 @@ snapshots:
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.26.10)
+ ts-jest@29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2):
+ dependencies:
+ bs-logger: 0.2.6
+ ejs: 3.1.10
+ fast-json-stable-stringify: 2.1.0
+ jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))
+ jest-util: 29.7.0
+ json5: 2.2.3
+ lodash.memoize: 4.1.2
+ make-error: 1.3.6
+ semver: 7.7.1
+ type-fest: 4.38.0
+ typescript: 5.8.2
+ yargs-parser: 21.1.1
+ optionalDependencies:
+ '@babel/core': 7.26.10
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.26.10)
+
ts-node@10.9.2(@types/node@18.19.83)(typescript@5.8.2):
dependencies:
'@cspotcode/source-map-support': 0.8.1
@@ -14056,6 +14317,8 @@ snapshots:
uuid@10.0.0: {}
+ uuid@11.1.0: {}
+
uuid@8.3.2: {}
uuid@9.0.1: {}