Skip to content

Commit 6712547

Browse files
committed
feat: enable swapping via aftermath and domain name conversion
1 parent af8c322 commit 6712547

File tree

4 files changed

+460
-1
lines changed

4 files changed

+460
-1
lines changed

packages/plugin-sui/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
"@elizaos/core": "workspace:*",
2323
"@elizaos/plugin-trustdb": "workspace:*",
2424
"@mysten/sui": "^1.16.0",
25+
"@mysten/sui.js": "^0.54.1",
26+
"@mysten/suins": "^0.4.2",
27+
"aftermath-ts-sdk": "^1.2.45",
2528
"bignumber": "1.1.0",
2629
"bignumber.js": "9.1.2",
2730
"node-cache": "5.1.2",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import {
2+
ActionExample,
3+
Content,
4+
HandlerCallback,
5+
IAgentRuntime,
6+
Memory,
7+
ModelClass,
8+
State,
9+
composeContext,
10+
elizaLogger,
11+
generateObject,
12+
type Action,
13+
} from "@elizaos/core";
14+
import { z } from "zod";
15+
16+
import { SuiClient, getFullnodeUrl } from "@mysten/sui/client";
17+
import { SuinsClient } from "@mysten/suins";
18+
19+
import { walletProvider } from "../providers/wallet";
20+
21+
type SuiNetwork = "mainnet" | "testnet" | "devnet" | "localnet";
22+
23+
export interface NameToAddressContent extends Content {
24+
recipientName: string;
25+
}
26+
27+
function isNameToAddressContent(
28+
content: Content
29+
): content is NameToAddressContent {
30+
console.log("Content for show address", content);
31+
return typeof content.recipientName === "string";
32+
}
33+
34+
const nameToAddressTemplate = `Extract the SUI domain name from the recent messages and return it in a JSON format.
35+
36+
Example input: "Convert adeniyi.sui to address" or "What's the address for adeniyi.sui"
37+
Example output:
38+
\`\`\`json
39+
{
40+
"recipientName": "adeniyi.sui"
41+
}
42+
\`\`\`
43+
44+
{{recentMessages}}
45+
46+
Extract the SUI domain name (ending in .sui) that needs to be converted to an address.
47+
If no valid .sui domain is found, return null.`;
48+
49+
export default {
50+
name: "CONVERT_SUINS_TO_ADDRESS",
51+
similes: [
52+
"CONVERT_SUI_NAME_TO_ADDRESS",
53+
"CONVERT_DOMAIN_TO_ADDRESS",
54+
"SHOW_ADDRESS_BY_NAME",
55+
"SHOW_ADDRESS_BY_DOMAIN",
56+
],
57+
validate: async (runtime: IAgentRuntime, message: Memory) => {
58+
console.log(
59+
"Validating sui name to address from user:",
60+
message.userId
61+
);
62+
//add custom validate logic here
63+
/*
64+
const adminIds = runtime.getSetting("ADMIN_USER_IDS")?.split(",") || [];
65+
//console.log("Admin IDs from settings:", adminIds);
66+
67+
const isAdmin = adminIds.includes(message.userId);
68+
69+
if (isAdmin) {
70+
//console.log(`Authorized transfer from user: ${message.userId}`);
71+
return true;
72+
}
73+
else
74+
{
75+
//console.log(`Unauthorized transfer attempt from user: ${message.userId}`);
76+
return false;
77+
}
78+
*/
79+
return true;
80+
},
81+
description: "Convert a name service domain to an sui address",
82+
handler: async (
83+
runtime: IAgentRuntime,
84+
message: Memory,
85+
state: State,
86+
_options: { [key: string]: unknown },
87+
callback?: HandlerCallback
88+
): Promise<boolean> => {
89+
elizaLogger.log("Starting CONVERT_SUINS_TO_ADDRESS handler...");
90+
const walletInfo = await walletProvider.get(runtime, message, state);
91+
state.walletInfo = walletInfo;
92+
93+
// Initialize or update state
94+
if (!state) {
95+
state = (await runtime.composeState(message)) as State;
96+
} else {
97+
state = await runtime.updateRecentMessageState(state);
98+
}
99+
100+
// Define the schema for the expected output
101+
const nameToAddressSchema = z.object({
102+
recipientName: z.string(),
103+
});
104+
105+
// Compose transfer context
106+
const nameToAddressContext = composeContext({
107+
state,
108+
template: nameToAddressTemplate,
109+
});
110+
111+
// Generate transfer content with the schema
112+
const content = await generateObject({
113+
runtime,
114+
context: nameToAddressContext,
115+
schema: nameToAddressSchema,
116+
modelClass: ModelClass.SMALL,
117+
});
118+
119+
const nameToAddressContent = content.object as NameToAddressContent;
120+
121+
// Validate transfer content
122+
if (!isNameToAddressContent(nameToAddressContent)) {
123+
console.error(
124+
"Invalid content for CONVERT_SUINS_TO_ADDRESS action."
125+
);
126+
if (callback) {
127+
callback({
128+
text: "Unable to process name to address request. Invalid content provided.",
129+
content: { error: "Invalid name to address content" },
130+
});
131+
}
132+
return false;
133+
}
134+
135+
try {
136+
const network = runtime.getSetting("SUI_NETWORK");
137+
const suiClient = new SuiClient({
138+
url: getFullnodeUrl(network as SuiNetwork),
139+
});
140+
const suinsClient = new SuinsClient({
141+
client: suiClient,
142+
network: network as Exclude<SuiNetwork, "devnet" | "localnet">,
143+
});
144+
145+
console.log(
146+
"Getting address for name:",
147+
nameToAddressContent.recipientName
148+
);
149+
150+
const address = await suinsClient.getNameRecord(
151+
nameToAddressContent.recipientName
152+
);
153+
console.log("Address:", address);
154+
155+
if (callback) {
156+
callback({
157+
text: `Successfully convert ${nameToAddressContent.recipientName} to ${address.targetAddress}`,
158+
content: {
159+
success: true,
160+
address: address.targetAddress,
161+
},
162+
});
163+
}
164+
165+
return true;
166+
} catch (error) {
167+
console.error("Error during name to address conversion:", error);
168+
if (callback) {
169+
callback({
170+
text: `Error during name to address conversion: ${error.message}`,
171+
content: { error: error.message },
172+
});
173+
}
174+
return false;
175+
}
176+
},
177+
178+
examples: [
179+
[
180+
{
181+
user: "{{user1}}",
182+
content: {
183+
text: "Convert adeniyi.sui to address",
184+
},
185+
},
186+
{
187+
user: "{{user2}}",
188+
content: {
189+
text: "Converting adeniyi.sui to address...",
190+
action: "CONVERT_SUINS_TO_ADDRESS",
191+
},
192+
},
193+
{
194+
user: "{{user2}}",
195+
content: {
196+
text: "Successfully convert adeniyi.sui to 0x1eb7c57e3f2bd0fc6cb9dcffd143ea957e4d98f805c358733f76dee0667fe0b1",
197+
},
198+
},
199+
],
200+
[
201+
{
202+
user: "{{user1}}",
203+
content: {
204+
text: "Convert @adeniyi to address",
205+
},
206+
},
207+
{
208+
user: "{{user2}}",
209+
content: {
210+
text: "Convert @adeniyi to address",
211+
action: "CONVERT_NAME_TO_ADDRESS",
212+
},
213+
},
214+
{
215+
user: "{{user2}}",
216+
content: {
217+
text: "Successfully convert @adeniyi to 0x1eb7c57e3f2bd0fc6cb9dcffd143ea957e4d98f805c358733f76dee0667fe0b1",
218+
},
219+
},
220+
],
221+
] as ActionExample[][],
222+
} as Action;

0 commit comments

Comments
 (0)