From 196337994a3e2949ce0e4fe7a13e2b63cd92b9de Mon Sep 17 00:00:00 2001 From: Philippe d'Argent Date: Wed, 1 Oct 2025 17:50:02 +0900 Subject: [PATCH] change tx signing for clanker and fix optional metadata --- typescript/agentkit/package.json | 2 +- .../clanker/clankerActionProvider.ts | 102 +++++++--- .../src/action-providers/clanker/schemas.ts | 4 +- .../cdpSmartWalletProvider.ts | 2 +- .../examples/langchain-cdp-chatbot/chatbot.ts | 2 + .../chatbot.ts | 2 + typescript/pnpm-lock.yaml | 190 ++++++++++++++++-- 7 files changed, 258 insertions(+), 46 deletions(-) diff --git a/typescript/agentkit/package.json b/typescript/agentkit/package.json index 537907c06..1b031110a 100644 --- a/typescript/agentkit/package.json +++ b/typescript/agentkit/package.json @@ -57,7 +57,7 @@ "axios": "^1.9.0", "bs58": "^4.0.1", "canonicalize": "^2.1.0", - "clanker-sdk": "^4.1.18", + "clanker-sdk": "^4.1.23", "decimal.js": "^10.5.0", "ethers": "^6.13.5", "graphql-request": "^7.2.0", diff --git a/typescript/agentkit/src/action-providers/clanker/clankerActionProvider.ts b/typescript/agentkit/src/action-providers/clanker/clankerActionProvider.ts index d149c8125..b930e7590 100644 --- a/typescript/agentkit/src/action-providers/clanker/clankerActionProvider.ts +++ b/typescript/agentkit/src/action-providers/clanker/clankerActionProvider.ts @@ -4,7 +4,7 @@ import { Network } from "../../network"; import { CreateAction } from "../actionDecorator"; import { EvmWalletProvider } from "../../wallet-providers"; import { ClankTokenSchema } from "./schemas"; -import { createClankerClient } from "./utils"; +import { encodeFunctionData } from "viem"; /** * ClankerActionProvider provides actions for clanker operations. @@ -25,8 +25,7 @@ export class ClankerActionProvider extends ActionProvider { * Clanker action provider * * @description - * This action deploys a clanker token using the Clanker sdk - * It automatically includes the coin in the Clanker ecosystem + * This action deploys a clanker token using the Clanker SDK * * @param walletProvider - The wallet provider instance for blockchain interactions * @param args - Clanker arguments (modify these to fine tune token deployment, like initial quote token and rewards config) @@ -35,7 +34,7 @@ export class ClankerActionProvider extends ActionProvider { @CreateAction({ name: "clank_token", description: ` -his tool will launch a Clanker token using the Clanker SDK. +This action deploys a clanker token using the Clanker SDK. It takes the following inputs: - tokenName: The name of the deployed token - tokenSymbol: The symbol of the deployed token @@ -58,7 +57,8 @@ It takes the following inputs: return `Can't Clank token; network ${networkId} is not supported`; } - const clanker = await createClankerClient(walletProvider, networkId); + const { Clanker } = await import("clanker-sdk/v4"); + const clanker = new Clanker({ publicClient: walletProvider.getPublicClient() }); const lockDuration = args.lockDuration_Days * 24 * 60 * 60; const vestingDuration = args.vestingDuration_Days * 24 * 60 * 60; @@ -67,13 +67,17 @@ It takes the following inputs: name: args.tokenName, symbol: args.tokenSymbol, image: args.image, - metadata: { - socialMediaUrls: args.socialMediaUrls, - description: args.description, - }, + ...(args.socialMediaUrls || args.description + ? { + metadata: { + ...(args.socialMediaUrls && { socialMediaUrls: args.socialMediaUrls }), + ...(args.description && { description: args.description }), + }, + } + : {}), context: { interface: args.interface, - id: args.id, + ...(args.id && { id: args.id }), }, tokenAdmin: walletProvider.getAddress() as `0x${string}`, vault: { @@ -84,23 +88,68 @@ It takes the following inputs: chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined, }; + const deployTransaction = await clanker.getDeployTransaction(tokenConfig); + console.log("deployTransaction", deployTransaction); + console.log("tokenConfig", deployTransaction.args[0].tokenConfig); + + // Encode the function data properly for sendTransaction + const data = encodeFunctionData({ + abi: deployTransaction.abi, + functionName: deployTransaction.functionName, + args: deployTransaction.args, + }); + try { - const res = await clanker.deploy(tokenConfig); + const gas = await walletProvider.getPublicClient().estimateContractGas({ + ...deployTransaction, + account: walletProvider.getAddress() as `0x${string}`, + }); + console.log("estimateContractGas:", gas); + } catch (error) { + console.log("error in estimateContractGas", error); + } - if ("error" in res) { - return `There was an error deploying the clanker token: ${res}`; - } + try { + const gas = await walletProvider.getPublicClient().estimateGas({ + account: walletProvider.getAddress() as `0x${string}`, + to: deployTransaction.address, + value: deployTransaction.value, + data: data, + }); + console.log("estimateGas:", gas); + } catch (error) { + console.log("error in estimateGas", error); + } + + try { + const txHash = await walletProvider.sendTransaction({ + to: deployTransaction.address, + data, + value: deployTransaction.value, + }); - const { txHash } = res; + const receipt = await walletProvider.waitForTransactionReceipt(txHash); + console.log("receipt", receipt); - const confirmed = await res.waitForTransaction(); - if ("error" in confirmed) { - return `There was an error confirming the clanker token deployment: ${confirmed}`; - } + if (receipt.status === "reverted" || receipt.status === "failed") + return `The transaction reverted: ${receipt.status}`; - const { address } = confirmed; + // Extract token address from logs + // The token address is in the first Transfer event from null address (token minting) + const transferEventSignature = + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; + const nullAddress = "0x0000000000000000000000000000000000000000000000000000000000000000"; - return `Clanker token deployed at ${address}! View the transaction at ${txHash}, or view the token page at https://clanker.world/clanker/${address}`; + const tokenLog = receipt.logs.find( + log => log.topics[0] === transferEventSignature && log.topics[1] === nullAddress, + ); + + const tokenAddress = tokenLog?.address; + if (tokenAddress) { + return `Clanker token deployed at address ${tokenAddress}! View the transaction at ${txHash}. View the token page at https://clanker.world/clanker/${tokenAddress}`; + } + + return `Clanker token deployed! View the transaction at ${txHash}`; } catch (error) { return `There was an error deploying the clanker token: ${error}`; } @@ -112,13 +161,10 @@ It takes the following inputs: * @param network - The network to check support for * @returns True if the network is supported */ - supportsNetwork(network: Network): boolean { - return ( - network.networkId === "base-mainnet" || - network.networkId === "base-sepolia" || - network.networkId === "arbitrum-mainnet" - ); - } + supportsNetwork = (network: Network) => + network.networkId === "base-mainnet" || + network.networkId === "base-sepolia" || + network.networkId === "arbitrum-mainnet"; } /** diff --git a/typescript/agentkit/src/action-providers/clanker/schemas.ts b/typescript/agentkit/src/action-providers/clanker/schemas.ts index 4640c2877..ff819a7eb 100644 --- a/typescript/agentkit/src/action-providers/clanker/schemas.ts +++ b/typescript/agentkit/src/action-providers/clanker/schemas.ts @@ -43,9 +43,9 @@ export const ClankTokenSchema = z .describe('System the token was deployed via. Defaults to "CDP AgentKit".'), id: z .string() - .default("") + .optional() .describe( - "User id of the poster on the social platform the token was deployed from. Used for provenance and will be verified by aggregators.", + "User id of the poster on the social platform the token was deployed from (optional). Used for provenance and will be verified by aggregators.", ), }) .strip() diff --git a/typescript/agentkit/src/wallet-providers/cdpSmartWalletProvider.ts b/typescript/agentkit/src/wallet-providers/cdpSmartWalletProvider.ts index 84887d4f7..c0c28aa2c 100644 --- a/typescript/agentkit/src/wallet-providers/cdpSmartWalletProvider.ts +++ b/typescript/agentkit/src/wallet-providers/cdpSmartWalletProvider.ts @@ -342,7 +342,7 @@ export class CdpSmartWalletProvider extends EvmWalletProvider implements WalletP // Append transaction logs if available if (receipt.status === "complete") { - const receiptTx = await this.#publicClient.getTransactionReceipt({ + const receiptTx = await this.#publicClient.waitForTransactionReceipt({ hash: receipt.transactionHash as Hex, }); if (receiptTx.logs) return { ...receipt, logs: receiptTx.logs }; diff --git a/typescript/examples/langchain-cdp-chatbot/chatbot.ts b/typescript/examples/langchain-cdp-chatbot/chatbot.ts index ac27cd942..2f77c557f 100644 --- a/typescript/examples/langchain-cdp-chatbot/chatbot.ts +++ b/typescript/examples/langchain-cdp-chatbot/chatbot.ts @@ -10,6 +10,7 @@ import { CdpSolanaWalletProvider, splActionProvider, x402ActionProvider, + clankerActionProvider, } from "@coinbase/agentkit"; import { getLangChainTools } from "@coinbase/agentkit-langchain"; import { HumanMessage } from "@langchain/core/messages"; @@ -124,6 +125,7 @@ async function initializeAgent() { erc20ActionProvider(), erc721ActionProvider(), x402ActionProvider(), + clankerActionProvider(), ] : isSolanaWalletProvider(walletProvider) ? [splActionProvider()] diff --git a/typescript/examples/langchain-cdp-smart-wallet-chatbot/chatbot.ts b/typescript/examples/langchain-cdp-smart-wallet-chatbot/chatbot.ts index 2f54f5326..92988b3c7 100644 --- a/typescript/examples/langchain-cdp-smart-wallet-chatbot/chatbot.ts +++ b/typescript/examples/langchain-cdp-smart-wallet-chatbot/chatbot.ts @@ -8,6 +8,7 @@ import { walletActionProvider, wethActionProvider, x402ActionProvider, + clankerActionProvider, } from "@coinbase/agentkit"; import { getLangChainTools } from "@coinbase/agentkit-langchain"; import { HumanMessage } from "@langchain/core/messages"; @@ -119,6 +120,7 @@ async function initializeAgent() { cdpApiActionProvider(), cdpSmartWalletActionProvider(), x402ActionProvider(), + clankerActionProvider(), ], }); diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index 8972eac54..649db84e9 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -117,8 +117,8 @@ importers: specifier: ^2.1.0 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)) + specifier: ^4.1.23 + version: 4.1.23(@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 +176,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 +194,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 @@ -2907,8 +2907,8 @@ packages: cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} - clanker-sdk@4.1.19: - resolution: {integrity: sha512-oyDKnMW+ZZqeKZJnA2BZMoOR3QNOSX/5yf8s61NrmDx/HhEZJpqrxgHexDLQkbUi9pLle1bjAIZ8srQR7ZJEyQ==} + clanker-sdk@4.1.23: + resolution: {integrity: sha512-aoGfD6j4dQYazYkukcoNQcTd6sUfpftf+gZNjgJX9sVEqF/Occ4HbVPk1uBH17h4A6doXGhL/XZgb9FF+kbOjg==} hasBin: true peerDependencies: viem: ^2.7.9 @@ -7293,12 +7293,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 +7354,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 @@ -10402,12 +10437,11 @@ 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.23(@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) + abitype: 1.1.0(typescript@5.8.2)(zod@3.25.56) + 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: @@ -10525,6 +10559,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 +11685,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 +12008,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 +12058,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 +12347,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 +13909,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