feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: added Clanker typescript action support - #825

Merged
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module
Sep 5, 2025
Merged

feat: added Clanker typescript action support#825
CarsonRoscoe merged 4 commits into
coinbase:mainfrom
gtspencer:feat/clanker-action-module

Conversation

@gtspencer

Copy link
Copy Markdown
Contributor

Clanker Action Provider

Description

This action adds Clanker token deployment support to the typescript implementation of AgentKit.

Although Clanker already has an agent that deploys tokens, their open library and protocol allows anyone to launch a "Clank" token and be recognized by their ecosystem.

Tests

Chatbot: langchain-cdp-chatbot
Network: Base Mainnet
Setup: Add ClankerActionProvider to the chatbot
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
Response:
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------

Checklist

A couple of things to include in your PR for completeness:

  • Added documentation to all relevant README.md files
  • Added a changelog entry

@cb-heimdall

cb-heimdall commented Aug 14, 2025

Copy link
Copy Markdown

✅ Heimdall Review Status

RequirementStatusMore Info
Reviews1/1
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified0
Sum1

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 14, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch 3 times, most recently from be629f1 to 97da2b1CompareAugust 15, 2025 15:17
CarsonRoscoe
CarsonRoscoe previously approved these changes Aug 15, 2025
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 94e3d49 to cc79e82CompareAugust 20, 2025 18:14
@gtspencer
gtspencerforce-pushed the feat/clanker-action-module branch from 28d2442 to c059efcCompareAugust 21, 2025 17:26
Comment on lines +1 to +9
/**
* Clanker Action Provider
*
* This file contains the implementation of the ClankerActionProvider,
* which provides actions for clanker operations.
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove in accordance with code style elsewhere

* @returns True if the network is supported
*/
supportsNetwork(network: Network): boolean {
// all protocol networks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Comment on lines +1 to +6
/**
* Exports for clanker action provider
*
* @module clanker
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

Comment on lines +9 to +11

// depending on usage, you might export the factory like this:
// export { clankerActionProviderFactory } from "./clankerActionProvider";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this too

Comment on lines +14 to +19
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced by me, happy to remove it!

* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)
* @returns The Clanker implementation
*/
export async function makeClanker(walletProvider: EvmWalletProvider, networkId: string) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rename makeClanker -> createClankerClient

The "clankerBridge" notation is also misleading, please move the file utils/clankerBridge.ts -> utils.ts

const wallet = createWalletClient({
account,
chain: NETWORK_ID_TO_VIEM_CHAIN[networkId],
transport: http(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use transport as configured in walletProvider:

Suggested change
transport: http(),
transport: http(publicClient.transport.url)


expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String));
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dedicated supportsNetwork test block like other providers

describe("supportsNetwork", () => {
it("should return true for base-mainnet with evm protocol", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe(true);
});
it("should return false for non-base networks", () => {
expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum-mainnet" })).toBe(false);
});
});

Comment on lines +46 to +49
description: `
This tool will launch a token (called a Clanker, named after the token launch protocol).
Clanker tokens can only be launched when your network ID is 'base-mainnet'.
`,

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description is too brief and misses important details. Suggestion:

Suggested change
description: `
Thistoolwilllaunchatoken(calledaClanker,namedafterthetokenlaunchprotocol).
ClankertokenscanonlybelaunchedwhenyournetworkIDis'base-mainnet'.
`,
description: `
ThistoolwilllaunchaClankertoken using theClankerSDK.
Ittakesthefollowinginputs:
-tokenName: Thenameofthedeployedtoken
-tokenSymbol: The symbol ofthedeployedtoken
-image: AnormaloripfsURLpointingtotheimageofthetoken
-vaultPercentage: Thepercentageofthetokensupplytoallocatetoavaultaccessibletothedeployedafterthelockupperiodwithoptionalvesting
-lockDuration_Days: Thelockdurationofthetokensinthevault(indays)(minimum7days)
-vestingDuration_Days: Theduration(indays)thatthetokenshouldvestafterlockupperiod,vestingislinear.
`,

Comment on lines +85 to +96
const res = await clanker.deploy(tokenConfig);

if ("error" in res) {
return `There was an error deploying the clanker token: ${res}`;
}

const { txHash } = res;

const confirmed = await res.waitForTransaction();
if ("error" in confirmed) {
return `There was an error confirming the clanker token deployment: ${confirmed}`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap main logic in try-catch


const { address } = confirmed;

return `Clanker token deployed at ${address}! View the transaction at ${txHash}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add link to deployed coin here, https://clanker.world/clanker/

Comment on lines +10 to +27
export const ClankTokenSchema = z.object({
/**
* Name of token
*/
tokenName: z.string().min(1).max(100),

/**
* Symbol of token (lets keep it short <= 10)
*/
tokenSymbol: z.string().min(1).max(10),

/**
* String URL pointing to image
*/
image: z.string().url(),

/**
* Percentage of token for deployer initially locked

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:

Suggested change
exportconstClankTokenSchema=z.object({
/**
*Nameoftoken
*/
tokenName: z.string().min(1).max(100),
/**
*Symboloftoken(letskeepitshort<=10)
*/
tokenSymbol: z.string().min(1).max(10),
/**
*StringURLpointingtoimage
*/
image: z.string().url(),
/**
*Percentageoftokenfordeployerinitiallylocked
exportconstClankTokenSchema=z
.object({
tokenName: z.string().min(1).max(100).describe("The name of the token (max 100 characters)"),
tokenSymbol: z.string().min(1).max(10).describe("The symbol of the token (max 10 characters)"),
image: z.string().url().describe("Normal or ipfs URL pointing to the token image"),
vaultPercentage: z.number().min(0).max(99).describe("Percentage of token supply allocated to a vault that can be claimed by deployer after lockup period with optional vesting"),
lockDuration_Days: z.number().min(7).describe("Lockup duration of token (in days), minimum 7 days"),
vestingDuration_Days: z.number().min(0).describe("Vesting duration of token after lockup has passed (in days). Vesting is linear over the duration"),
})
.strip()
.describe("Instructions for deploying a Clanker token");

/**
* Percentage of token for deployer initially locked
*/
vestingPercentage: z.number().min(0).max(99),

@phdargenphdargenSep 1, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems max percentage for vault is 90%, not 99%. See: https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/config/clankerTokenV4.ts#L125C1-L126C1.

Notation "vestingPercentage" also misleading, should be vaultPercentage

* Creates the client Clanker expects from the EvmWalletProvider
*
* @param walletProvider - The wallet provider instance for blockchain interactions
* @param networkId - The network to Clank on (this will most likely be Base, unless the action implementation is extended to include other networks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove "(this will most likely be Base, unless the action implementation is extended to include other networks)"

const tokenConfig = {
name: args.tokenName,
symbol: args.tokenSymbol,
image: args.image,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symbol: args.tokenSymbol,
image: args.image,
context: {
interface: "Clanker SDK",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add optional arg to shemas to set interface, should default to "CDP AgentKit"

Comment on lines +73 to +75
platform: "Clanker",
messageId: "Deploy Example",
id: "TKN-1",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also be optional args, not hardcoded. Can default to "".

@phdargen

phdargen commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for your contribution. That's a great addition! Please have a look at my comments above, hope we can get this in soon

Note: Please avoid force-pushing all your code changes into the same commit. Instead, push new commits so I can review what changed more easily.

├── schemas.ts # Action schemas and types
├── index.ts # Package exports
├── utils/
│ ├── clankerBridge.ts # Helprs to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helprs -> Helpers

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

hey @phdargen , just made those requested changes! let me know if there's anything else!

Comment on lines +20 to +21
├── utils/
│ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> utils.ts

tokenName: "Test Token",
tokenSymbol: "TT",
image: "https://test.com/image.png",
vestingPercentage: 10,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> vaultPercentage

Comment on lines +112 to +114
supportsNetwork(network: Network): boolean {
return network.protocolFamily === "evm" && network.networkId == "base-mainnet";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets include all supported networks:

Suggested change
supportsNetwork(network: Network): boolean {
returnnetwork.protocolFamily==="evm"&&network.networkId=="base-mainnet";
}
supportsNetwork=(network: Network)=>
network.networkId==="base-mainnet"||network.networkId==="base-sepolia"||network.networkId==="arbitrum-mainnet";

Comment on lines +70 to +71
description: args.description,
socialMediaUrls: args.socialMediaUrls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be wrapped in metadata field:

Suggested change
description: args.description,
socialMediaUrls: args.socialMediaUrls,
metadata: {
description: args.description,
socialMediaUrls: args.socialMediaUrls,
},

percentage: args.vaultPercentage,
lockupDuration: lockDuration,
vestingDuration: vestingDuration,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,

Comment on lines +57 to +59
if (!networkId || networkId !== "base-mainnet") {
return `Can't Clank token; network must be Base Mainnet`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please change to:

Suggested change
if(!networkId||networkId!=="base-mainnet"){
return`Can't Clank token; network must be Base Mainnet`;
}
if(!this.supportsNetwork(network)){
return`Can't Clank token; network ${networkId} is not supported`;
}

Comment on lines +90 to +102
#### Example
```
Prompt: Can you clank a token with name [CDP Clanker], and symbol [CDPC] and image hosted at [https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQF6hcTTU1A8Ymi2VldXqCsPkBu_ltAhIKiRg&s]? vest 10%, locked for 30 days, and then vested for 30 days. do this on base-mainnet
```

```
-------------------
Internal address: 0xE8D165388b13c460F02f4dC922309450a9bF6f22
Clanker token deployed at 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb! View the transaction at 0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa
-------------------
The Clanker token has been successfully deployed with the name "CDP Clanker" and symbol "CDPC." You can view the transaction [here](https://etherscan.io/tx/0xf67befc5da942288a7bb4baee2cbbc1a09853e62552e736aa272b91e09f918fa). The token address is 0x15E91EAF0848c8FEfE8c287923B5A78E254A76eb.
-------------------
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed here, please remove

@phdargen

Copy link
Copy Markdown
Contributor

Hi @gtspencer, thanks for the update!

The action failed in my test as the tokenConfig format is wrong, see above.
Otherwise, lets add some more supported networks (see above), then this should be good to go

@gtspencer

Copy link
Copy Markdown
ContributorAuthor

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@phdargen

Copy link
Copy Markdown
Contributor

No worries @gtspencer, thanks for the quick fixes!

This is reviewed and tested @CarsonRoscoe

@phdargen apologies, should have caught those sooner! Just updated and think its good to go!

@CarsonRoscoeCarsonRoscoe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @gtspencer for the contribution! And thanks @phdargen for the review.

This looks good to me!

@CarsonRoscoe
CarsonRoscoe merged commit c55cefa into coinbase:mainSep 5, 2025
26 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

4 participants

@gtspencer@cb-heimdall@phdargen@CarsonRoscoe