UNPKG

@symmetry-hq/agents-sdk

Version:

Symmetry Agents SDK

219 lines (201 loc) 7.19 kB
// Core dependencies import { AnchorProvider, Program } from "@coral-xyz/anchor"; import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; import { getAssociatedTokenAddressSync } from "@solana/spl-token"; import { AccountInfo, Connection, GetProgramAccountsFilter, GetProgramAccountsResponse, Keypair, PublicKey, TransactionSignature } from "@solana/web3.js"; import { Metaplex } from "@metaplex-foundation/js"; // Local imports import { IDL } from "../idl/idl"; import { AgentsProgram } from "../idl/types"; import { parse, stringify, v4 } from "uuid"; import { AGENTS_PROGRAM_ID, EVENT_AUTHORITY_SEED, FEES_VAULT_SEED } from "../constants"; import { AGENTS_STATE_SIZE, AgentState, parseAgentState, ParsedAgentState } from "../state/agent"; import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; export function getAgentsProgram( connection: Connection, ): Program<AgentsProgram> { const program: Program<AgentsProgram> = new Program( IDL, new AnchorProvider( connection, new NodeWallet(Keypair.generate()) ) ); return program; } export function getAgentStateAccount( agent: PublicKey, ): PublicKey { return PublicKey.findProgramAddressSync( [Uint8Array.from(agent.toBuffer())], AGENTS_PROGRAM_ID, )[0]; } export function getAgent( agentUuid: number[], ): PublicKey { return PublicKey.findProgramAddressSync( [Uint8Array.from(agentUuid)], AGENTS_PROGRAM_ID, )[0]; } export function getEventAuthority(program: Program<AgentsProgram>) { const [eventAuthority] = PublicKey.findProgramAddressSync( [Buffer.from(EVENT_AUTHORITY_SEED)], program.programId ); return eventAuthority; } export function getFeesVault(program: Program<AgentsProgram>) { const [feeVault] = PublicKey.findProgramAddressSync( [Buffer.from(FEES_VAULT_SEED)], program.programId ); return feeVault; } export function getMetadataAccount( tokenMint: PublicKey ): PublicKey { const metaplex = Metaplex.make(new Connection("https://api.devnet.solana.com")); return metaplex.nfts().pdas().metadata({ mint: tokenMint }); } export function getAta( wallet: PublicKey, tokenMint: PublicKey, ): PublicKey { return getAssociatedTokenAddressSync(tokenMint, wallet, true); } export function getRandomSeed(): number[] { return Array.from(parse(v4())); } export function getStringFromSeed( seed: number[], ): string { return stringify(Uint8Array.from(seed)); } export async function getAccountInfos( connection: Connection, keys: PublicKey[], ): Promise<(AccountInfo<Buffer> | null)[]> { const allAccounts: (AccountInfo<Buffer>|null)[] = []; const batchSize = 100; for (let i = 0; i < keys.length; i += batchSize) { const batch = keys.slice(i, i + batchSize); const batchAccounts = await connection.getMultipleAccountsInfo(batch); allAccounts.push(...batchAccounts); } return allAccounts; } export async function getAllAgents( program: Program<AgentsProgram>, ): Promise<ParsedAgentState[]> { const accounts: AgentState[] = (await program.account.agent.all()).map(account => account.account); return accounts.map(account => parseAgentState(account)); } export async function getAgentsByCreator( program: Program<AgentsProgram>, creator: PublicKey, ): Promise<ParsedAgentState[]> { const accountFilters: GetProgramAccountsFilter[] = [ { dataSize: AGENTS_STATE_SIZE + 8, }, { memcmp: { offset: 8 + 32 + 16, bytes: creator.toBase58(), }, } ] const accounts: GetProgramAccountsResponse = await program.provider.connection .getProgramAccounts( AGENTS_PROGRAM_ID, { commitment: "confirmed", filters: accountFilters, encoding: 'base64' } ); const agents: AgentState[] = accounts.map(account => program.coder.accounts.decode("agent", account.account.data) ); return await Promise.all(agents.map(agent => parseAgentState(agent))); } export async function getEventsFromTx( connection: Connection, program: Program<AgentsProgram>, txId: TransactionSignature, ): Promise<any[]> { const parsed = await connection.getParsedTransaction( txId, { maxSupportedTransactionVersion: 0, commitment: "confirmed"} ).catch((_) => null); if (!parsed || !parsed.meta || parsed.meta.err || !parsed.meta.innerInstructions) throw new Error("Transaction is invalid"); const eventAuthority = getEventAuthority(program); let rawEvents: any[] = []; for (let i = 0; i < parsed.meta.innerInstructions.length; i++) { for (let j = 0; j < parsed.meta.innerInstructions[i].instructions.length; j++) { let ix = parsed.meta.innerInstructions[i].instructions[j]; if (!ix.programId.equals(program.programId)) continue; //@ts-ignore let accounts = ix.accounts; //@ts-ignore let data = ix.data; if (!accounts || !data || accounts.length != 1) continue; if (!accounts[0].equals(eventAuthority)) continue; let buffer = bs58.decode(data); let str64 = buffer.subarray(8, buffer.length).toString("base64"); const rawEvent = program.coder.events.decode(str64); if (!rawEvent) continue; rawEvents.push(rawEvent); } } return rawEvents; } export async function getTopUpBalanceEventFromTx( connection: Connection, program: Program<AgentsProgram>, txId: TransactionSignature, ): Promise<{ user: string, mint: string, amount: number, }> { const rawEvents = await getEventsFromTx(connection, program, txId); for (let i = 0; i < rawEvents.length; i++) { let rawEvent = rawEvents[i]; if (rawEvent.name !== "topUpBalanceEvent") continue; let parsedEvent = { user: rawEvent.data.user.toBase58(), amount: parseInt(rawEvent.data.amount.toString()), mint: rawEvent.data.mint.toBase58(), }; return parsedEvent; } throw new Error("Top up balance event not found"); } export async function getCreateAgentEventFromTx( connection: Connection, program: Program<AgentsProgram>, txId: TransactionSignature, ): Promise<{ agent: string, agentState: string, agentUuid: string, creator: string, }> { const rawEvents = await getEventsFromTx(connection, program, txId); for (let i = 0; i < rawEvents.length; i++) { let rawEvent = rawEvents[i]; if (rawEvent.name !== "createAgentEvent") continue; let parsedEvent = { agent: rawEvent.data.agent.toBase58(), agentState: rawEvent.data.stateAddress.toBase58(), agentUuid: getStringFromSeed(rawEvent.data.agentUuid), creator: rawEvent.data.creator.toBase58(), }; return parsedEvent; } throw new Error("Create agent event not found"); }