From be0287c5a93822404e1938ebd9c95d32b26b38c5 Mon Sep 17 00:00:00 2001 From: Damjan Date: Thu, 16 Jan 2025 14:02:56 +0100 Subject: [PATCH] Implement getAssetsByAuthority tool --- src/actions/index.ts | 2 + src/actions/metaplex/getAssetByAuthority.ts | 70 +++++++++++++++++++ src/agent/index.ts | 11 ++- src/langchain/index.ts | 4 +- .../metaplex/get_asset_by_authority.ts | 39 +++++++++++ src/langchain/metaplex/index.ts | 2 + src/tools/metaplex/get_asset.ts | 5 +- src/tools/metaplex/get_assets_by_authority.ts | 15 ++++ src/tools/metaplex/index.ts | 1 + 9 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 src/actions/metaplex/getAssetByAuthority.ts create mode 100644 src/langchain/metaplex/get_asset_by_authority.ts create mode 100644 src/tools/metaplex/get_assets_by_authority.ts diff --git a/src/actions/index.ts b/src/actions/index.ts index ca260e1..32194c5 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -60,6 +60,7 @@ import driftUserAccountInfoAction from "./drift/driftUserAccountInfo"; import deriveDriftVaultAddressAction from "./drift/deriveVaultAddress"; import updateDriftVaultDelegateAction from "./drift/updateDriftVaultDelegate"; import getAssetAction from "./metaplex/getAsset"; +import getAssetByAuthorityAction from "./metaplex/getAssetByAuthority"; export const ACTIONS = { WALLET_ADDRESS_ACTION: getWalletAddressAction, @@ -125,6 +126,7 @@ export const ACTIONS = { DERIVE_DRIFT_VAULT_ADDRESS_ACTION: deriveDriftVaultAddressAction, UPDATE_DRIFT_VAULT_DELEGATE_ACTION: updateDriftVaultDelegateAction, GET_ASSET_ACTION: getAssetAction, + GET_ASSET_BY_AUTHORITY_ACTION: getAssetByAuthorityAction, }; export type { Action, ActionExample, Handler } from "../types/action"; diff --git a/src/actions/metaplex/getAssetByAuthority.ts b/src/actions/metaplex/getAssetByAuthority.ts new file mode 100644 index 0000000..1711c8f --- /dev/null +++ b/src/actions/metaplex/getAssetByAuthority.ts @@ -0,0 +1,70 @@ +import { Action } from "../../types/action"; +import { SolanaAgentKit } from "../../agent"; +import { z } from "zod"; +import { get_assets_by_authority } from "../../tools/metaplex"; + +const getAssetByAuthorityAction: Action = { + name: "GET_ASSET_BY_AUTHORITY", + similes: [ + "fetch assets by authority", + "retrieve assets by authority", + "get assets by authority address", + "fetch authority assets", + ], + description: `Fetch a list of assets owned by a specific address using the Metaplex DAS API.`, + examples: [ + [ + { + input: { + authorityAddress: "mRdta4rc2RtsxEUDYuvKLamMZAdW6qHcwuq866Skxxv", + limit: 10, + }, + output: { + status: "success", + message: "Assets retrieved successfully", + result: [ + // Example asset details + { + name: "Example Asset 1", + symbol: "EXA1", + uri: "https://example.com/asset1.json", + }, + { + name: "Example Asset 2", + symbol: "EXA2", + uri: "https://example.com/asset2.json", + }, + ], + }, + explanation: "Fetch a list of assets owned by a specific address", + }, + ], + ], + schema: z.object({ + authorityAddress: z.string().min(1, "Authority address is required"), + sortBy: z + .object({ + sortBy: z.enum(["created", "updated", "recentAction", "none"]), + sortDirection: z.enum(["asc", "desc"]), + }) + .optional(), + limit: z.number().optional(), + page: z.number().optional(), + before: z.string().optional(), + after: z.string().optional(), + }), + handler: async ( + agent: SolanaAgentKit, + input: z.infer, + ) => { + const result = await get_assets_by_authority(agent, input); + + return { + status: "success", + message: "Assets retrieved successfully", + result, + }; + }, +}; + +export default getAssetByAuthorityAction; diff --git a/src/agent/index.ts b/src/agent/index.ts index 1e42940..cbdd3b5 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -99,6 +99,7 @@ import { updateVaultDelegate, get_token_balance, get_asset, + get_assets_by_authority, } from "../tools"; import { Config, @@ -116,7 +117,10 @@ import { HeliusWebhookIdResponse, HeliusWebhookResponse, } from "../types"; -import { DasApiAsset } from "@metaplex-foundation/digital-asset-standard-api"; +import { + DasApiAsset, + GetAssetsByAuthorityRpcInput, +} from "@metaplex-foundation/digital-asset-standard-api"; /** * Main class for interacting with Solana blockchain @@ -827,4 +831,9 @@ export class SolanaAgentKit { async getAsset(assetId: string): Promise { return get_asset(this, assetId); } + async getAssetsByAuthority( + params: GetAssetsByAuthorityRpcInput, + ): Promise { + return get_assets_by_authority(this, params); + } } diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 0d9b9dd..78b8b11 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -114,8 +114,9 @@ import { SolanaUpdateDriftVaultTool, SolanaWithdrawFromDriftAccountTool, SolanaWithdrawFromDriftVaultTool, + SolanaGetAssetTool, + SolanaGetAssetsByAuthorityTool, } from "./index"; -import { SolanaGetAssetTool } from "./metaplex/get_asset"; export function createSolanaTools(solanaKit: SolanaAgentKit) { return [ @@ -210,5 +211,6 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) { new SolanaWithdrawFromDriftAccountTool(solanaKit), new SolanaWithdrawFromDriftVaultTool(solanaKit), new SolanaGetAssetTool(solanaKit), + new SolanaGetAssetsByAuthorityTool(solanaKit), ]; } diff --git a/src/langchain/metaplex/get_asset_by_authority.ts b/src/langchain/metaplex/get_asset_by_authority.ts new file mode 100644 index 0000000..17f1e8f --- /dev/null +++ b/src/langchain/metaplex/get_asset_by_authority.ts @@ -0,0 +1,39 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; + +export class SolanaGetAssetsByAuthorityTool extends Tool { + name = "solana_get_assets_by_authority"; + description = `Fetch a list of assets owned by a specific address using the Metaplex DAS API. + + Inputs (input is a JSON string): + authorityAddress: string, eg "N4f6zftYsuu4yT7icsjLwh4i6pB1zvvKbseHj2NmSQw" (required) + sortBy: { sortBy: "created" | "updated" | "recentAction" | "none", sortDirection: "asc" | "desc" } (optional) + limit: number (optional) + page: number (optional) + before: string (optional) + after: string (optional)`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + protected async _call(input: string): Promise { + try { + const parsedInput = JSON.parse(input); + + const result = await this.solanaKit.getAssetsByAuthority(parsedInput); + + return JSON.stringify({ + status: "success", + message: "Assets retrieved successfully", + result, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} diff --git a/src/langchain/metaplex/index.ts b/src/langchain/metaplex/index.ts index 7cdfe15..3635d03 100644 --- a/src/langchain/metaplex/index.ts +++ b/src/langchain/metaplex/index.ts @@ -1,3 +1,5 @@ export * from "./deploy_collection"; export * from "./mint_nft"; export * from "./deploy_token"; +export * from "./get_asset"; +export * from "./get_asset_by_authority"; diff --git a/src/tools/metaplex/get_asset.ts b/src/tools/metaplex/get_asset.ts index c701806..768caad 100644 --- a/src/tools/metaplex/get_asset.ts +++ b/src/tools/metaplex/get_asset.ts @@ -19,11 +19,8 @@ export async function get_asset( try { const endpoint = agent.connection.rpcEndpoint; const umi = createUmi(endpoint).use(dasApi()); - const assetPublicKey = publicKey(assetId); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return await umi.rpc.getAsset(assetPublicKey); + return await umi.rpc.getAsset(publicKey(assetId)); } catch (error: any) { console.error("Error retrieving asset: ", error.message); throw new Error(`Asset retrieval failed: ${error.message}`); diff --git a/src/tools/metaplex/get_assets_by_authority.ts b/src/tools/metaplex/get_assets_by_authority.ts new file mode 100644 index 0000000..1ddee15 --- /dev/null +++ b/src/tools/metaplex/get_assets_by_authority.ts @@ -0,0 +1,15 @@ +import { SolanaAgentKit } from "../../agent"; +import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; +import { + dasApi, + GetAssetsByAuthorityRpcInput, +} from "@metaplex-foundation/digital-asset-standard-api"; + +export async function get_assets_by_authority( + agent: SolanaAgentKit, + params: GetAssetsByAuthorityRpcInput, +) { + const umi = createUmi(agent.connection.rpcEndpoint).use(dasApi()); + const assets = await umi.rpc.getAssetsByAuthority(params); + return assets.items; +} diff --git a/src/tools/metaplex/index.ts b/src/tools/metaplex/index.ts index 92a3efa..0fc3fa7 100644 --- a/src/tools/metaplex/index.ts +++ b/src/tools/metaplex/index.ts @@ -2,3 +2,4 @@ export * from "./deploy_collection"; export * from "./mint_nft"; export * from "./deploy_token"; export * from "./get_asset"; +export * from "./get_assets_by_authority";