Skip to content

Commit 66afaa1

Browse files
authored
Merge pull request elizaOS#757 from asDNSk/main
fix: follow-up improvements for ICP token creation (PR elizaOS#357)
2 parents e9eac3e + c1190a3 commit 66afaa1

File tree

18 files changed

+292
-170
lines changed

18 files changed

+292
-170
lines changed

agent/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"@ai16z/plugin-solana": "workspace:*",
3434
"@ai16z/plugin-0g": "workspace:*",
3535
"@ai16z/plugin-starknet": "workspace:*",
36+
"@ai16z/plugin-icp": "workspace:*",
3637
"@ai16z/plugin-tee": "workspace:*",
3738
"@ai16z/plugin-coinbase": "workspace:*",
3839
"readline": "1.3.0",

packages/plugin-icp/src/actions/createToken.ts

+135-70
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import { composeContext } from "@ai16z/eliza/src/context";
2-
import { generateObject } from "@ai16z/eliza/src/generation";
1+
import {
2+
composeContext,
3+
generateImage,
4+
generateText,
5+
generateObject,
6+
} from "@ai16z/eliza";
37
import {
48
ActionExample,
59
HandlerCallback,
@@ -8,56 +12,31 @@ import {
812
ModelClass,
913
State,
1014
type Action,
11-
} from "@ai16z/eliza/src/types";
15+
} from "@ai16z/eliza";
1216
import { idlFactory } from "../canisters/pick-pump/index.did";
1317
import { _SERVICE } from "../canisters/pick-pump/index.did.d";
1418
import { ActorCreator, CreateMemeTokenArg } from "../types";
1519
import { unwrapOption, wrapOption } from "../utils/common/types/options";
1620
import { unwrapRustResultMap } from "../utils/common/types/results";
1721
import { icpWalletProvider } from "../providers/wallet";
18-
19-
const createTokenTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
20-
21-
Based on the user's description, generate appropriate values for a new token:
22-
- Create a suitable token name
23-
- Generate a 3-4 letter symbol based on the name
24-
- Write a clear description
25-
- Use "https://icptoken.default.logo" as default logo URL
26-
- Set other fields to null
27-
28-
Example response:
29-
\`\`\`json
30-
{
31-
"name": "My ICP Token",
32-
"symbol": "MIT",
33-
"description": "A fun meme token on ICP",
34-
"logo": "https://icptoken.default.logo",
35-
"website": null,
36-
"twitter": null,
37-
"telegram": null
38-
}
39-
\`\`\`
40-
41-
{{recentMessages}}
42-
43-
Generate appropriate token information based on the user's description.
44-
Respond with a JSON markdown block containing only the generated values.`;
22+
import { uploadFileToWeb3Storage } from "../apis/uploadFile";
23+
import { createTokenTemplate, logoPromptTemplate } from './prompts/token';
24+
import { CANISTER_IDS } from '../constants/canisters';
4525

4626
async function createTokenTransaction(
4727
creator: ActorCreator,
4828
tokenInfo: CreateMemeTokenArg
49-
): Promise<any> {
29+
) {
5030
const actor: _SERVICE = await creator(
5131
idlFactory,
52-
"bn4fo-iyaaa-aaaap-akp6a-cai"
32+
CANISTER_IDS.PICK_PUMP
5333
);
54-
5534
const result = await actor.create_token({
5635
...tokenInfo,
57-
name: tokenInfo.name ?? "My ICP Token",
58-
symbol: tokenInfo.symbol ?? "MIT",
59-
description: tokenInfo.description ?? "A fun meme token on ICP",
60-
logo: "https://icptoken.default.logo",
36+
name: tokenInfo.name,
37+
symbol: tokenInfo.symbol,
38+
description: tokenInfo.description,
39+
logo: tokenInfo.logo,
6140
twitter: wrapOption(tokenInfo.twitter),
6241
website: wrapOption(tokenInfo.website),
6342
telegram: wrapOption(tokenInfo.telegram),
@@ -67,6 +46,12 @@ async function createTokenTransaction(
6746
result,
6847
(ok) => ({
6948
...ok,
49+
id: ok.id.toString(),
50+
created_at: ok.created_at.toString(),
51+
available_token: ok.available_token.toString(),
52+
volume_24h: ok.volume_24h.toString(),
53+
last_tx_time: ok.last_tx_time.toString(),
54+
market_cap_icp: ok.market_cap_icp.toString(),
7055
twitter: unwrapOption(ok.twitter),
7156
website: unwrapOption(ok.website),
7257
telegram: unwrapOption(ok.telegram),
@@ -77,21 +62,82 @@ async function createTokenTransaction(
7762
);
7863
}
7964

65+
async function generateTokenLogo(
66+
description: string,
67+
runtime: IAgentRuntime
68+
): Promise<string | null> {
69+
const logoPrompt = `Create a fun and memorable logo for a cryptocurrency token with these characteristics: ${description}. The logo should be simple, iconic, and suitable for a meme token. Style: minimal, bold colors, crypto-themed.`;
70+
71+
const result = await generateImage(
72+
{
73+
prompt: logoPrompt,
74+
width: 512,
75+
height: 512,
76+
count: 1,
77+
},
78+
runtime as any
79+
);
80+
81+
if (result.success && result.data && result.data.length > 0) {
82+
return result.data[0];
83+
}
84+
85+
return null;
86+
}
87+
8088
export const executeCreateToken: Action = {
8189
name: "CREATE_TOKEN",
82-
similes: ["CREATE_COIN", "MINT_TOKEN", "DEPLOY_TOKEN", "CREATE_ICP_TOKEN"],
90+
similes: [
91+
"CREATE_PICKPUMP_TOKEN",
92+
"MINT_PICKPUMP",
93+
"PICKPUMP_TOKEN",
94+
"PP_TOKEN",
95+
"PICKPUMP发币",
96+
"PP发币",
97+
"在PICKPUMP上发币",
98+
"PICKPUMP代币",
99+
],
100+
description:
101+
"Create a new meme token on PickPump platform (Internet Computer). This action helps users create and launch tokens specifically on the PickPump platform.",
83102
validate: async (runtime: IAgentRuntime, message: Memory) => {
84-
console.log("Message:", message);
85-
return true;
103+
const keywords = [
104+
"pickpump",
105+
"pp",
106+
"皮克帮",
107+
"token",
108+
"coin",
109+
"代币",
110+
"币",
111+
"create",
112+
"mint",
113+
"launch",
114+
"deploy",
115+
"创建",
116+
"发行",
117+
"铸造",
118+
];
119+
120+
const messageText = (
121+
typeof message.content === "string"
122+
? message.content
123+
: message.content.text || ""
124+
).toLowerCase();
125+
126+
return keywords.some((keyword) => messageText.includes(keyword.toLowerCase()));
86127
},
87-
description: "Create a new token on Internet Computer.",
88128
handler: async (
89129
runtime: IAgentRuntime,
90130
message: Memory,
91-
state: State,
92-
_options: { [key: string]: unknown },
131+
state: State | undefined,
132+
_options: { [key: string]: unknown } | undefined,
93133
callback?: HandlerCallback
94-
): Promise<boolean> => {
134+
): Promise<void> => {
135+
callback?.({
136+
text: "🔄 Creating meme token...",
137+
action: "CREATE_TOKEN",
138+
type: "processing",
139+
});
140+
95141
if (!state) {
96142
state = (await runtime.composeState(message)) as State;
97143
} else {
@@ -109,20 +155,28 @@ export const executeCreateToken: Action = {
109155
modelClass: ModelClass.LARGE,
110156
});
111157

112-
console.log("Response:", response);
158+
const logoPromptContext = composeContext({
159+
state,
160+
template: logoPromptTemplate.replace(
161+
"{{description}}",
162+
response.description
163+
),
164+
});
113165

114-
// Validate required fields
115-
if (
116-
!response.name ||
117-
!response.symbol ||
118-
!response.description ||
119-
!response.logo
120-
) {
121-
const responseMsg = {
122-
text: "I need the token name, symbol, description, and logo URL to create a token",
123-
};
124-
callback?.(responseMsg);
125-
return true;
166+
const logoPrompt = await generateText({
167+
runtime,
168+
context: logoPromptContext,
169+
modelClass: ModelClass.SMALL,
170+
});
171+
172+
const logo = await generateTokenLogo(logoPrompt, runtime);
173+
if (!logo) {
174+
throw new Error("Failed to generate token logo");
175+
}
176+
177+
const logoUploadResult = await uploadFileToWeb3Storage(logo);
178+
if (!logoUploadResult.urls?.gateway) {
179+
throw new Error("Failed to upload logo to Web3Storage");
126180
}
127181

128182
try {
@@ -131,50 +185,61 @@ export const executeCreateToken: Action = {
131185
message,
132186
state
133187
);
188+
134189
const creator = wallet.createActor;
135190
const createTokenResult = await createTokenTransaction(creator, {
136191
name: response.name,
137192
symbol: response.symbol,
138193
description: response.description,
139-
website: response.website,
140-
twitter: response.twitter,
141-
telegram: response.telegram,
194+
logo: logoUploadResult.urls.gateway,
142195
});
143196

144-
console.log("Token created successfully:", createTokenResult);
145197
const responseMsg = {
146-
text: `Token ${response.name} (${response.symbol}) created successfully on ICP!`,
198+
text: `✨ Created new meme token:\n🪙 ${response.name} (${response.symbol})\n📝 ${response.description}`,
147199
data: createTokenResult,
200+
action: "CREATE_TOKEN",
201+
type: "success",
148202
};
149-
150203
callback?.(responseMsg);
151-
return true;
152-
} catch (error) {
153-
console.error("Error creating token:", error);
204+
} catch (error: any) {
154205
const responseMsg = {
155206
text: `Failed to create token: ${error.message}`,
207+
action: "CREATE_TOKEN",
208+
type: "error",
156209
};
157210
callback?.(responseMsg);
158-
return false;
159211
}
160212
},
161213
examples: [
162214
[
163215
{
164216
user: "{{user1}}",
165-
content: "I want to create a token for dog lovers",
217+
content: "I want to create a space cat token on PickPump",
166218
},
167219
{
168220
user: "{{user2}}",
169221
content: {
170-
text: "Creating new ICP token WOOF...",
222+
text: "Creating space cat token on PickPump...",
171223
action: "CREATE_TOKEN",
172224
},
173225
},
174226
{
175227
user: "{{user2}}",
176228
content: {
177-
text: "Token created successfully on Internet Computer!",
229+
text: "✨ Token created successfully!",
230+
},
231+
},
232+
],
233+
[
234+
{
235+
user: "{{user1}}",
236+
content: "Help me create a pizza-themed funny token on PP",
237+
},
238+
{
239+
user: "{{user2}}",
240+
content: {
241+
text: "Creating pizza token on PickPump...",
242+
action: "CREATE_TOKEN",
178243
},
179244
},
180245
],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export const createTokenTemplate = `Based on the user's description, generate creative and memorable values for a new meme token on PickPump:
2+
3+
User's idea: "{{recentMessages}}"
4+
5+
Please generate:
6+
1. A catchy and fun token name that reflects the theme
7+
2. A 3-4 letter symbol based on the name (all caps)
8+
3. An engaging and humorous description (include emojis)
9+
4. Set other fields to null
10+
11+
Example response:
12+
\`\`\`json
13+
{
14+
"name": "CatLaser",
15+
"symbol": "PAWS",
16+
"description": "The first meme token powered by feline laser-chasing energy! Watch your investment zoom around like a red dot! 😺🔴✨",
17+
"logo": null,
18+
"website": null,
19+
"twitter": null,
20+
"telegram": null
21+
}
22+
\`\`\`
23+
24+
Generate appropriate meme token information based on the user's description.
25+
Respond with a JSON markdown block containing only the generated values.`;
26+
27+
export const logoPromptTemplate = `Based on this token idea: "{{description}}", create a detailed prompt for generating a logo image.
28+
The prompt should describe visual elements, style, and mood for the logo.
29+
Focus on making it memorable and suitable for a cryptocurrency token.
30+
Keep the response short and specific.
31+
Respond with only the prompt text, no additional formatting.
32+
33+
Example for a dog-themed token:
34+
"A playful cartoon dog face with a cryptocurrency symbol on its collar, using vibrant colors and bold outlines, crypto-themed minimal style"`;

0 commit comments

Comments
 (0)