Skip to content

Commit

Permalink
feat: enable swapping via aftermath and domain name conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
Vakurin committed Jan 10, 2025
1 parent af8c322 commit 6712547
Show file tree
Hide file tree
Showing 4 changed files with 460 additions and 1 deletion.
3 changes: 3 additions & 0 deletions packages/plugin-sui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
"@elizaos/core": "workspace:*",
"@elizaos/plugin-trustdb": "workspace:*",
"@mysten/sui": "^1.16.0",
"@mysten/sui.js": "^0.54.1",
"@mysten/suins": "^0.4.2",
"aftermath-ts-sdk": "^1.2.45",
"bignumber": "1.1.0",
"bignumber.js": "9.1.2",
"node-cache": "5.1.2",
Expand Down
222 changes: 222 additions & 0 deletions packages/plugin-sui/src/actions/convertNameToAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import {
ActionExample,
Content,
HandlerCallback,
IAgentRuntime,
Memory,
ModelClass,
State,
composeContext,
elizaLogger,
generateObject,
type Action,
} from "@elizaos/core";
import { z } from "zod";

import { SuiClient, getFullnodeUrl } from "@mysten/sui/client";
import { SuinsClient } from "@mysten/suins";

import { walletProvider } from "../providers/wallet";

type SuiNetwork = "mainnet" | "testnet" | "devnet" | "localnet";

export interface NameToAddressContent extends Content {
recipientName: string;
}

function isNameToAddressContent(
content: Content
): content is NameToAddressContent {
console.log("Content for show address", content);
return typeof content.recipientName === "string";
}

const nameToAddressTemplate = `Extract the SUI domain name from the recent messages and return it in a JSON format.
Example input: "Convert adeniyi.sui to address" or "What's the address for adeniyi.sui"
Example output:
\`\`\`json
{
"recipientName": "adeniyi.sui"
}
\`\`\`
{{recentMessages}}
Extract the SUI domain name (ending in .sui) that needs to be converted to an address.
If no valid .sui domain is found, return null.`;

export default {
name: "CONVERT_SUINS_TO_ADDRESS",
similes: [
"CONVERT_SUI_NAME_TO_ADDRESS",
"CONVERT_DOMAIN_TO_ADDRESS",
"SHOW_ADDRESS_BY_NAME",
"SHOW_ADDRESS_BY_DOMAIN",
],
validate: async (runtime: IAgentRuntime, message: Memory) => {
console.log(
"Validating sui name to address from user:",
message.userId
);
//add custom validate logic here
/*
const adminIds = runtime.getSetting("ADMIN_USER_IDS")?.split(",") || [];
//console.log("Admin IDs from settings:", adminIds);
const isAdmin = adminIds.includes(message.userId);
if (isAdmin) {
//console.log(`Authorized transfer from user: ${message.userId}`);
return true;
}
else
{
//console.log(`Unauthorized transfer attempt from user: ${message.userId}`);
return false;
}
*/
return true;
},
description: "Convert a name service domain to an sui address",
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
_options: { [key: string]: unknown },
callback?: HandlerCallback
): Promise<boolean> => {
elizaLogger.log("Starting CONVERT_SUINS_TO_ADDRESS handler...");
const walletInfo = await walletProvider.get(runtime, message, state);
state.walletInfo = walletInfo;

// Initialize or update state
if (!state) {
state = (await runtime.composeState(message)) as State;
} else {
state = await runtime.updateRecentMessageState(state);
}

// Define the schema for the expected output
const nameToAddressSchema = z.object({
recipientName: z.string(),
});

// Compose transfer context
const nameToAddressContext = composeContext({
state,
template: nameToAddressTemplate,
});

// Generate transfer content with the schema
const content = await generateObject({
runtime,
context: nameToAddressContext,
schema: nameToAddressSchema,
modelClass: ModelClass.SMALL,
});

const nameToAddressContent = content.object as NameToAddressContent;

// Validate transfer content
if (!isNameToAddressContent(nameToAddressContent)) {
console.error(
"Invalid content for CONVERT_SUINS_TO_ADDRESS action."
);
if (callback) {
callback({
text: "Unable to process name to address request. Invalid content provided.",
content: { error: "Invalid name to address content" },
});
}
return false;
}

try {
const network = runtime.getSetting("SUI_NETWORK");
const suiClient = new SuiClient({
url: getFullnodeUrl(network as SuiNetwork),
});
const suinsClient = new SuinsClient({
client: suiClient,
network: network as Exclude<SuiNetwork, "devnet" | "localnet">,
});

console.log(
"Getting address for name:",
nameToAddressContent.recipientName
);

const address = await suinsClient.getNameRecord(
nameToAddressContent.recipientName
);
console.log("Address:", address);

if (callback) {
callback({
text: `Successfully convert ${nameToAddressContent.recipientName} to ${address.targetAddress}`,
content: {
success: true,
address: address.targetAddress,
},
});
}

return true;
} catch (error) {
console.error("Error during name to address conversion:", error);
if (callback) {
callback({
text: `Error during name to address conversion: ${error.message}`,
content: { error: error.message },
});
}
return false;
}
},

examples: [
[
{
user: "{{user1}}",
content: {
text: "Convert adeniyi.sui to address",
},
},
{
user: "{{user2}}",
content: {
text: "Converting adeniyi.sui to address...",
action: "CONVERT_SUINS_TO_ADDRESS",
},
},
{
user: "{{user2}}",
content: {
text: "Successfully convert adeniyi.sui to 0x1eb7c57e3f2bd0fc6cb9dcffd143ea957e4d98f805c358733f76dee0667fe0b1",
},
},
],
[
{
user: "{{user1}}",
content: {
text: "Convert @adeniyi to address",
},
},
{
user: "{{user2}}",
content: {
text: "Convert @adeniyi to address",
action: "CONVERT_NAME_TO_ADDRESS",
},
},
{
user: "{{user2}}",
content: {
text: "Successfully convert @adeniyi to 0x1eb7c57e3f2bd0fc6cb9dcffd143ea957e4d98f805c358733f76dee0667fe0b1",
},
},
],
] as ActionExample[][],
} as Action;
Loading

0 comments on commit 6712547

Please sign in to comment.