Repository navigation
feat: added Clanker typescript action support - #825
Conversation
✅ Heimdall Review Status
|
be629f1 to
97da2b1
Compare
94e3d49 to
cc79e82
Compare
28d2442 to
c059efc
Compare
| /** | ||
| * Clanker Action Provider | ||
| * | ||
| * This file contains the implementation of the ClankerActionProvider, | ||
| * which provides actions for clanker operations. | ||
| * | ||
| * @module clanker | ||
| */ | ||
|
|
There was a problem hiding this comment.
Please remove in accordance with code style elsewhere
| * @returns True if the network is supported | ||
| */ | ||
| supportsNetwork(network: Network): boolean { | ||
| // all protocol networks |
| /** | ||
| * Exports for clanker action provider | ||
| * | ||
| * @module clanker | ||
| */ | ||
|
|
|
|
||
| // depending on usage, you might export the factory like this: | ||
| // export { clankerActionProviderFactory } from "./clankerActionProvider"; |
| tokenName: z.string().min(1).max(100), | ||
|
|
||
| /** | ||
| * Symbol of token (lets keep it short <= 10) | ||
| */ | ||
| tokenSymbol: z.string().min(1).max(10), |
There was a problem hiding this comment.
out of curiosity, are the max character limits enforced by the protocol/sdk or a choice by you?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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(), |
There was a problem hiding this comment.
This should use transport as configured in walletProvider:
| transport: http(), | |
| transport: http(publicClient.transport.url) |
|
|
||
| expect(makeClankerMock).toHaveBeenCalledWith(expect.any(Object), expect.any(String)); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
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);
});
});
| 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'. | ||
| `, |
There was a problem hiding this comment.
Description is too brief and misses important details. Suggestion:
| 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'. | |
| `, | |
| description: ` | |
| This tool will launch a Clanker token using the Clanker SDK. | |
| It takes the following inputs: | |
| - tokenName: The name of the deployed token | |
| - tokenSymbol: The symbol of the deployed token | |
| - image: A normal or ipfs URL pointing to the image of the token | |
| - vaultPercentage: The percentage of the token supply to allocate to a vault accessible to the deployed after the lockup period with optional vesting | |
| - lockDuration_Days: The lock duration of the tokens in the vault (in days) (minimum 7 days) | |
| - vestingDuration_Days: The duration (in days) that the token should vest after lockup period, vesting is linear. | |
| `, |
| 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}`; | ||
| } |
There was a problem hiding this comment.
Please wrap main logic in try-catch
|
|
||
| const { address } = confirmed; | ||
|
|
||
| return `Clanker token deployed at ${address}! View the transaction at ${txHash}`; |
There was a problem hiding this comment.
Could add link to deployed coin here, https://clanker.world/clanker/
| 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 |
There was a problem hiding this comment.
Please remove all the TSDoc comments and use describe() on the Zod fields instead. Suggestion:
| 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 | |
| export const ClankTokenSchema = 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), |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
Please add optional metadata field with description and socialMediaUrls, see https://www.npmjs.com/package/clanker-sdk and https://github.com/clanker-devco/clanker-sdk/blob/e82ee2af17301012a1d32c21e215068a84fba590/src/utils/zod-onchain.ts#L7.
| symbol: args.tokenSymbol, | ||
| image: args.image, | ||
| context: { | ||
| interface: "Clanker SDK", |
There was a problem hiding this comment.
add optional arg to shemas to set interface, should default to "CDP AgentKit"
| platform: "Clanker", | ||
| messageId: "Deploy Example", | ||
| id: "TKN-1", |
There was a problem hiding this comment.
should also be optional args, not hardcoded. Can default to "".
|
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 |
|
hey @phdargen , just made those requested changes! let me know if there's anything else! |
| ├── utils/ | ||
| │ ├── clankerBridge.ts # Helpers to wrap the EVMWalletProvider in the type the Clanker SDK expects |
| tokenName: "Test Token", | ||
| tokenSymbol: "TT", | ||
| image: "https://test.com/image.png", | ||
| vestingPercentage: 10, |
| supportsNetwork(network: Network): boolean { | ||
| return network.protocolFamily === "evm" && network.networkId == "base-mainnet"; | ||
| } |
There was a problem hiding this comment.
Lets include all supported networks:
| supportsNetwork(network: Network): boolean { | |
| return network.protocolFamily === "evm" && network.networkId == "base-mainnet"; | |
| } | |
| supportsNetwork = (network: Network) => | |
| network.networkId === "base-mainnet" || network.networkId === "base-sepolia" || network.networkId === "arbitrum-mainnet"; |
| description: args.description, | ||
| socialMediaUrls: args.socialMediaUrls, |
There was a problem hiding this comment.
needs to be wrapped in metadata field:
| description: args.description, | |
| socialMediaUrls: args.socialMediaUrls, | |
| metadata: { | |
| description: args.description, | |
| socialMediaUrls: args.socialMediaUrls, | |
| }, |
| percentage: args.vaultPercentage, | ||
| lockupDuration: lockDuration, | ||
| vestingDuration: vestingDuration, | ||
| }, |
There was a problem hiding this comment.
add:
chainId: Number(network.chainId) as 8453 | 84532 | 42161 | undefined,
| if (!networkId || networkId !== "base-mainnet") { | ||
| return `Can't Clank token; network must be Base Mainnet`; | ||
| } |
There was a problem hiding this comment.
please change to:
| 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`; | |
| } |
| #### 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. | ||
| ------------------- | ||
| ``` |
There was a problem hiding this comment.
not needed here, please remove
|
Hi @gtspencer, thanks for the update! The action failed in my test as the |
|
@phdargen apologies, should have caught those sooner! Just updated and think its good to go! |
|
No worries @gtspencer, thanks for the quick fixes! This is reviewed and tested @CarsonRoscoe
|
CarsonRoscoe
left a comment
There was a problem hiding this comment.
Thank you @gtspencer for the contribution! And thanks @phdargen for the review.
This looks good to me!
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
Checklist
A couple of things to include in your PR for completeness: