diff --git a/src/actions/index.ts b/src/actions/index.ts index b9ff530..290d021 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -62,6 +62,7 @@ import updateDriftVaultDelegateAction from "./drift/updateDriftVaultDelegate"; import getAssetAction from "./metaplex/getAsset"; import getAssetsByAuthorityAction from "./metaplex/getAssetsByAuthority"; import getAssetsByCreatorAction from "./metaplex/getAssetsByCreator"; +import searchAssetsAction from "./metaplex/searchAssets"; export const ACTIONS = { WALLET_ADDRESS_ACTION: getWalletAddressAction, @@ -129,6 +130,7 @@ export const ACTIONS = { GET_ASSET_ACTION: getAssetAction, GET_ASSETS_BY_AUTHORITY_ACTION: getAssetsByAuthorityAction, GET_ASSETS_BY_CREATOR_ACTION: getAssetsByCreatorAction, + SEARCH_ASSETS_ACTION: searchAssetsAction, }; export type { Action, ActionExample, Handler } from "../types/action"; diff --git a/src/actions/metaplex/searchAssets.ts b/src/actions/metaplex/searchAssets.ts new file mode 100644 index 0000000..e31b738 --- /dev/null +++ b/src/actions/metaplex/searchAssets.ts @@ -0,0 +1,113 @@ +import { Action } from "../../types/action"; +import { SolanaAgentKit } from "../../agent"; +import { z } from "zod"; +import { search_assets } from "../../tools/metaplex"; +import { publicKey } from "@metaplex-foundation/umi"; + +const searchAssetsAction: Action = { + name: "SEARCH_ASSETS", + similes: ["search assets", "find assets", "lookup assets", "query assets"], + description: `Search for assets using various criteria with the Metaplex DAS API.`, + examples: [ + [ + { + input: { + owner: publicKey("N4f6zftYsuu4yT7icsjLwh4i6pB1zvvKbseHj2NmSQw"), + jsonUri: + "https://arweave.net/c9aGs5fOk7gD4wWnSvmzeqgtfxAGRgtI1jYzvl8-IVs/chiaki-violet-azure-common.json", + }, + output: { + status: "success", + message: "Assets retrieved successfully", + result: { + total: 2, + limit: 10, + items: [ + { + interface: "V1_NFT", + id: "ExampleAssetId1", + content: { + json_uri: "https://example.com/asset1.json", + metadata: { + name: "Example Asset 1", + symbol: "EXA1", + }, + }, + authorities: [], + compression: {}, + grouping: [], + royalty: {}, + creators: [], + ownership: {}, + supply: {}, + mutable: true, + burnt: false, + }, + { + interface: "V1_NFT", + id: "ExampleAssetId2", + content: { + json_uri: "https://example.com/asset2.json", + metadata: { + name: "Example Asset 2", + symbol: "EXA2", + }, + }, + authorities: [], + compression: {}, + grouping: [], + royalty: {}, + creators: [], + ownership: {}, + supply: {}, + mutable: true, + burnt: false, + }, + ], + }, + }, + explanation: "Search for assets using various criteria", + }, + ], + ], + schema: z.object({ + negate: z.boolean().optional(), + conditionType: z.enum(["all", "any"]).optional(), + interface: z.string().optional(), + jsonUri: z.string().optional(), + owner: z.string().optional(), + ownerType: z.enum(["single", "token"]).optional(), + creator: z.string().optional(), + creatorVerified: z.boolean().optional(), + authority: z.string().optional(), + grouping: z.tuple([z.string(), z.string()]).optional(), + delegate: z.string().optional(), + frozen: z.boolean().optional(), + supply: z.number().optional(), + supplyMint: z.string().optional(), + compressed: z.boolean().optional(), + compressible: z.boolean().optional(), + royaltyModel: z.enum(["creators", "fanout", "single"]).optional(), + royaltyTarget: z.string().optional(), + royaltyAmount: z.number().optional(), + burnt: z.boolean().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 search_assets(agent, input); + + return { + status: "success", + message: "Assets retrieved successfully", + result, + }; + }, +}; + +export default searchAssetsAction; diff --git a/src/agent/index.ts b/src/agent/index.ts index 60a56b1..4bc5331 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -100,6 +100,8 @@ import { get_token_balance, get_asset, get_assets_by_authority, + get_assets_by_creator, + search_assets, } from "../tools"; import { Config, @@ -122,8 +124,8 @@ import { DasApiAssetList, GetAssetsByAuthorityRpcInput, GetAssetsByCreatorRpcInput, + SearchAssetsRpcInput, } from "@metaplex-foundation/digital-asset-standard-api"; -import { get_assets_by_creator } from "../tools/metaplex/get_assets_by_creator"; /** * Main class for interacting with Solana blockchain @@ -844,4 +846,7 @@ export class SolanaAgentKit { ): Promise { return get_assets_by_creator(this, params); } + async searchAssets(params: SearchAssetsRpcInput): Promise { + return search_assets(this, params); + } } diff --git a/src/langchain/metaplex/index.ts b/src/langchain/metaplex/index.ts index 41d11c7..d8ba77e 100644 --- a/src/langchain/metaplex/index.ts +++ b/src/langchain/metaplex/index.ts @@ -4,3 +4,4 @@ export * from "./deploy_token"; export * from "./get_asset"; export * from "./get_assets_by_authority"; export * from "./get_assets_by_creator"; +export * from "./search_assets"; diff --git a/src/langchain/metaplex/search_assets.ts b/src/langchain/metaplex/search_assets.ts new file mode 100644 index 0000000..10c3b44 --- /dev/null +++ b/src/langchain/metaplex/search_assets.ts @@ -0,0 +1,57 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; + +export class SolanaSearchAssetsTool extends Tool { + name = "solana_search_assets"; + description = `Search for assets using various criteria with the Metaplex DAS API. + + Inputs (input is a JSON string): + negate: boolean (optional) + conditionType: "all" | "any" (optional) + interface: string (optional) + jsonUri: string (optional) + owner: string (optional) + ownerType: "single" | "token" (optional) + creator: string (optional) + creatorVerified: boolean (optional) + authority: string (optional) + grouping: [string, string] (optional) + delegate: string (optional) + frozen: boolean (optional) + supply: number (optional) + supplyMint: string (optional) + compressed: boolean (optional) + compressible: boolean (optional) + royaltyModel: "creators" | "fanout" | "single" (optional) + royaltyTarget: string (optional) + royaltyAmount: number (optional) + burnt: boolean (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.searchAssets(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/tools/metaplex/get_assets_by_authority.ts b/src/tools/metaplex/get_assets_by_authority.ts index b6f1199..38ac3ee 100644 --- a/src/tools/metaplex/get_assets_by_authority.ts +++ b/src/tools/metaplex/get_assets_by_authority.ts @@ -5,6 +5,12 @@ import { GetAssetsByAuthorityRpcInput, } from "@metaplex-foundation/digital-asset-standard-api"; +/** + * Fetch assets by authority using the Metaplex DAS API + * @param agent SolanaAgentKit instance + * @param params Parameters for fetching assets by authority + * @returns List of assets associated with the given authority + */ export async function get_assets_by_authority( agent: SolanaAgentKit, params: GetAssetsByAuthorityRpcInput, diff --git a/src/tools/metaplex/get_assets_by_creator.ts b/src/tools/metaplex/get_assets_by_creator.ts index 64a4ed3..48eec44 100644 --- a/src/tools/metaplex/get_assets_by_creator.ts +++ b/src/tools/metaplex/get_assets_by_creator.ts @@ -5,6 +5,12 @@ import { GetAssetsByCreatorRpcInput, } from "@metaplex-foundation/digital-asset-standard-api"; +/** + * Fetch assets by creator using the Metaplex DAS API + * @param agent SolanaAgentKit instance + * @param params Parameters for fetching assets by creator + * @returns List of assets created by the specified creator + */ export async function get_assets_by_creator( agent: SolanaAgentKit, params: GetAssetsByCreatorRpcInput, diff --git a/src/tools/metaplex/index.ts b/src/tools/metaplex/index.ts index 41d11c7..d8ba77e 100644 --- a/src/tools/metaplex/index.ts +++ b/src/tools/metaplex/index.ts @@ -4,3 +4,4 @@ export * from "./deploy_token"; export * from "./get_asset"; export * from "./get_assets_by_authority"; export * from "./get_assets_by_creator"; +export * from "./search_assets"; diff --git a/src/tools/metaplex/search_assets.ts b/src/tools/metaplex/search_assets.ts new file mode 100644 index 0000000..9a74197 --- /dev/null +++ b/src/tools/metaplex/search_assets.ts @@ -0,0 +1,20 @@ +import { SolanaAgentKit } from "../../agent"; +import { createUmi } from "@metaplex-foundation/umi-bundle-defaults"; +import { + dasApi, + SearchAssetsRpcInput, +} from "@metaplex-foundation/digital-asset-standard-api"; + +/** + * Search for assets using the Metaplex DAS API + * @param agent SolanaAgentKit instance + * @param params Parameters for searching assets + * @returns List of assets matching the search criteria + */ +export async function search_assets( + agent: SolanaAgentKit, + params: SearchAssetsRpcInput, +) { + const umi = createUmi(agent.connection.rpcEndpoint).use(dasApi()); + return await umi.rpc.searchAssets(params); +}