Skip to content

Commit db49a68

Browse files
committed
feat(plugin-nft-generation): add mint NFT with collection address action
1 parent 81d0273 commit db49a68

File tree

4 files changed

+679
-187
lines changed

4 files changed

+679
-187
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
import {
2+
Action,
3+
composeContext,
4+
Content,
5+
elizaLogger,
6+
generateObjectDeprecated,
7+
getEmbeddingZeroVector,
8+
HandlerCallback,
9+
IAgentRuntime,
10+
Memory,
11+
ModelClass,
12+
State,
13+
stringToUuid,
14+
} from "@ai16z/eliza";
15+
import { createNFT } from "../handlers/createNFT.ts";
16+
import { verifyNFT } from "../handlers/verifyNFT.ts";
17+
import { sleep } from "../index.ts";
18+
import WalletSolana from "../provider/wallet/walletSolana.ts";
19+
import { PublicKey } from "@solana/web3.js";
20+
21+
const mintTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
22+
23+
Example response:
24+
\`\`\`json
25+
{
26+
"collectionAddress": "D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS",
27+
}
28+
\`\`\`
29+
30+
{{message}}
31+
32+
Given the recent messages, extract the following information about the requested mint nft:
33+
- collection contract address
34+
35+
Respond with a JSON markdown block containing only the extracted values.`;
36+
37+
export interface MintContent extends Content {
38+
collectionAddress: string;
39+
}
40+
41+
function isMintNFTContent(
42+
runtime: IAgentRuntime,
43+
content: any
44+
): content is MintContent {
45+
console.log("Content for mint", content);
46+
return typeof content.collectionAddress === "string";
47+
}
48+
49+
const mintNFTAction: Action = {
50+
name: "MINT_NFT",
51+
similes: [
52+
"NFT_MINTING",
53+
"NFT_CREATION",
54+
"CREATE_NFT",
55+
"GENERATE_NFT",
56+
"MINT_TOKEN",
57+
"CREATE_TOKEN",
58+
"MAKE_NFT",
59+
"TOKEN_GENERATION",
60+
],
61+
description: "Mint NFTs for the collection",
62+
validate: async (runtime: IAgentRuntime, _message: Memory) => {
63+
const AwsAccessKeyIdOk = !!runtime.getSetting("AWS_ACCESS_KEY_ID");
64+
const AwsSecretAccessKeyOk = !!runtime.getSetting(
65+
"AWS_SECRET_ACCESS_KEY"
66+
);
67+
const AwsRegionOk = !!runtime.getSetting("AWS_REGION");
68+
const AwsS3BucketOk = !!runtime.getSetting("AWS_S3_BUCKET");
69+
70+
return (
71+
AwsAccessKeyIdOk ||
72+
AwsSecretAccessKeyOk ||
73+
AwsRegionOk ||
74+
AwsS3BucketOk
75+
);
76+
},
77+
handler: async (
78+
runtime: IAgentRuntime,
79+
message: Memory,
80+
state: State,
81+
options: { [key: string]: unknown },
82+
callback: HandlerCallback
83+
) => {
84+
try {
85+
elizaLogger.log("Composing state for message:", message);
86+
const userId = runtime.agentId;
87+
const agentName = runtime.character.name;
88+
const roomId = stringToUuid("nft_generate_room-" + agentName);
89+
90+
const memory: Memory = {
91+
agentId: userId,
92+
userId,
93+
roomId,
94+
content: {
95+
text: message.content.text,
96+
source: "nft-generator",
97+
},
98+
createdAt: Date.now(),
99+
embedding: getEmbeddingZeroVector(),
100+
};
101+
const state = await runtime.composeState(memory, {
102+
message: message.content.text,
103+
});
104+
105+
elizaLogger.log("state:", state);
106+
107+
// Compose transfer context
108+
const transferContext = composeContext({
109+
state,
110+
template: mintTemplate,
111+
});
112+
113+
const content = await generateObjectDeprecated({
114+
runtime,
115+
context: transferContext,
116+
modelClass: ModelClass.LARGE,
117+
});
118+
119+
elizaLogger.log("generateObjectDeprecated:", transferContext);
120+
121+
if (!isMintNFTContent(runtime, content)) {
122+
elizaLogger.error("Invalid content for MINT_NFT action.");
123+
if (callback) {
124+
callback({
125+
text: "Unable to process mint request. Invalid content provided.",
126+
content: { error: "Invalid mint content" },
127+
});
128+
}
129+
return false;
130+
}
131+
132+
elizaLogger.log("mint content", content);
133+
134+
const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY");
135+
const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY");
136+
137+
const wallet = new WalletSolana(
138+
new PublicKey(publicKey),
139+
privateKey
140+
);
141+
142+
const collectionInfo = await wallet.fetchDigitalAsset(
143+
content.collectionAddress
144+
);
145+
elizaLogger.log("Collection Info", collectionInfo);
146+
const metadata = collectionInfo.metadata;
147+
if (metadata.collection?.["value"]) {
148+
callback({
149+
text: `Unable to process mint request. Invalid collection address ${content.collectionAddress}.`,
150+
content: { error: "Invalid collection address." },
151+
});
152+
return false;
153+
}
154+
if (metadata) {
155+
elizaLogger.log("nft params", {});
156+
const nftRes = await createNFT({
157+
runtime,
158+
collectionName: metadata.name,
159+
collectionAddress: content.collectionAddress,
160+
collectionAdminPublicKey: metadata.updateAuthority,
161+
collectionFee: metadata.sellerFeeBasisPoints,
162+
tokenId: 1,
163+
});
164+
165+
elizaLogger.log("NFT Address:", nftRes);
166+
167+
if (nftRes) {
168+
callback({
169+
text: `Congratulations to you! 🎉🎉🎉 \nCollection Address: ${content.collectionAddress}\n NFT Address: ${nftRes.address}\n NFT Link: ${nftRes.link}`, //caption.description,
170+
attachments: [],
171+
});
172+
await sleep(15000);
173+
await verifyNFT({
174+
runtime,
175+
collectionAddress: content.collectionAddress,
176+
NFTAddress: nftRes.address,
177+
});
178+
} else {
179+
callback({
180+
text: `Mint NFT Error in ${content.collectionAddress}.`,
181+
content: { error: "Mint NFT Error." },
182+
});
183+
return false;
184+
}
185+
} else {
186+
callback({
187+
text: "Unable to process mint request. Invalid collection address.",
188+
content: { error: "Invalid collection address." },
189+
});
190+
return false;
191+
}
192+
193+
//
194+
// const userId = runtime.agentId;
195+
// elizaLogger.log("User ID:", userId);
196+
//
197+
// const collectionAddressRes = await createCollection({
198+
// runtime,
199+
// collectionName: runtime.character.name,
200+
// });
201+
//
202+
// const collectionInfo = collectionAddressRes.collectionInfo;
203+
//
204+
// elizaLogger.log("Collection Address:", collectionAddressRes);
205+
206+
//
207+
// elizaLogger.log("NFT Address:", nftRes);
208+
//
209+
//
210+
// callback({
211+
// text: `Congratulations to you! 🎉🎉🎉 \nCollection : ${collectionAddressRes.link}\n NFT: ${nftRes.link}`, //caption.description,
212+
// attachments: [],
213+
// });
214+
// await sleep(15000);
215+
// await verifyNFT({
216+
// runtime,
217+
// collectionAddress: collectionAddressRes.address,
218+
// NFTAddress: nftRes.address,
219+
// });
220+
return [];
221+
} catch (e: any) {
222+
console.log(e);
223+
}
224+
225+
// callback();
226+
},
227+
examples: [
228+
[
229+
{
230+
user: "{{user1}}",
231+
content: {
232+
text: "mint nft for collection: D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS",
233+
},
234+
},
235+
{
236+
user: "{{agentName}}",
237+
content: {
238+
text: "I've minted a new NFT in your specified collection.",
239+
action: "MINT_NFT",
240+
},
241+
},
242+
],
243+
[
244+
{
245+
user: "{{user1}}",
246+
content: {
247+
text: "Could you create an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS?",
248+
},
249+
},
250+
{
251+
user: "{{agentName}}",
252+
content: {
253+
text: "Successfully minted your NFT in the specified collection.",
254+
action: "MINT_NFT",
255+
},
256+
},
257+
],
258+
[
259+
{
260+
user: "{{user1}}",
261+
content: {
262+
text: "Please mint a new token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection",
263+
},
264+
},
265+
{
266+
user: "{{agentName}}",
267+
content: {
268+
text: "Your NFT has been minted in the collection successfully.",
269+
action: "MINT_NFT",
270+
},
271+
},
272+
],
273+
[
274+
{
275+
user: "{{user1}}",
276+
content: {
277+
text: "Generate NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS",
278+
},
279+
},
280+
{
281+
user: "{{agentName}}",
282+
content: {
283+
text: "I've generated and minted your NFT in the collection.",
284+
action: "MINT_NFT",
285+
},
286+
},
287+
],
288+
[
289+
{
290+
user: "{{user1}}",
291+
content: {
292+
text: "I want to mint an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS",
293+
},
294+
},
295+
{
296+
user: "{{agentName}}",
297+
content: {
298+
text: "Your NFT has been successfully minted in the collection.",
299+
action: "MINT_NFT",
300+
},
301+
},
302+
],
303+
[
304+
{
305+
user: "{{user1}}",
306+
content: {
307+
text: "Create a new NFT token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection",
308+
},
309+
},
310+
{
311+
user: "{{agentName}}",
312+
content: {
313+
text: "The NFT has been created in your specified collection.",
314+
action: "MINT_NFT",
315+
},
316+
},
317+
],
318+
[
319+
{
320+
user: "{{user1}}",
321+
content: {
322+
text: "Issue an NFT for collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS",
323+
},
324+
},
325+
{
326+
user: "{{agentName}}",
327+
content: {
328+
text: "I've issued your NFT in the requested collection.",
329+
action: "MINT_NFT",
330+
},
331+
},
332+
],
333+
[
334+
{
335+
user: "{{user1}}",
336+
content: {
337+
text: "Make a new NFT in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS",
338+
},
339+
},
340+
{
341+
user: "{{agentName}}",
342+
content: {
343+
text: "Your new NFT has been minted in the collection.",
344+
action: "MINT_NFT",
345+
},
346+
},
347+
],
348+
[
349+
{
350+
user: "{{user1}}",
351+
content: {
352+
text: "Can you mint an NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection?",
353+
},
354+
},
355+
{
356+
user: "{{agentName}}",
357+
content: {
358+
text: "I've completed minting your NFT in the collection.",
359+
action: "MINT_NFT",
360+
},
361+
},
362+
],
363+
[
364+
{
365+
user: "{{user1}}",
366+
content: {
367+
text: "Add a new NFT to collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS",
368+
},
369+
},
370+
{
371+
user: "{{agentName}}",
372+
content: {
373+
text: "A new NFT has been added to your collection.",
374+
action: "MINT_NFT",
375+
},
376+
},
377+
],
378+
],
379+
} as Action;
380+
381+
export default mintNFTAction;

0 commit comments

Comments
 (0)