diff --git a/README.md b/README.md index faeb9c28..2f7b8c70 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ -An open-source toolkit for connecting AI agents to Solana protocols. Now, any agent, using any model can autonomously perform 15+ Solana actions: +An open-source toolkit for connecting AI agents to Solana protocols. Now, any agent, using any model can autonomously perform 60+ Solana actions: - Trade tokens - Launch new tokens diff --git a/package.json b/package.json index 2e864e82..59ae0b88 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,8 @@ "@bonfida/spl-name-service": "^3.0.7", "@cks-systems/manifest-sdk": "0.1.59", "@coral-xyz/anchor": "0.29", - "@drift-labs/sdk": "2.107.0-beta.3", - "@drift-labs/vaults-sdk": "^0.2.49", + "@drift-labs/sdk": "2.108.0-beta.4", + "@drift-labs/vaults-sdk": "^0.3.2", "@langchain/core": "^0.3.26", "@langchain/groq": "^0.1.2", "@langchain/langgraph": "^0.2.36", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26aae15f..51e342d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,11 +27,11 @@ importers: specifier: '0.29' version: 0.29.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@drift-labs/sdk': - specifier: 2.107.0-beta.3 - version: 2.107.0-beta.3(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) + specifier: 2.108.0-beta.4 + version: 2.108.0-beta.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10) '@drift-labs/vaults-sdk': - specifier: ^0.2.49 - version: 0.2.49(@types/node@22.10.7)(arweave@1.15.5)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) + specifier: ^0.3.2 + version: 0.3.2(@types/node@22.10.7)(arweave@1.15.5)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10) '@langchain/core': specifier: ^0.3.26 version: 0.3.27(openai@4.77.3(zod@3.24.1)) @@ -344,12 +344,12 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@drift-labs/sdk@2.107.0-beta.3': - resolution: {integrity: sha512-pRWTRpAVYAhJZI+5WxrAzSMnU+1IiJXuTPanY9eNZZUn9S//RRc3CXigM/ogeGPaOolizBZDejwy2Igz7h22JQ==} + '@drift-labs/sdk@2.108.0-beta.4': + resolution: {integrity: sha512-P3pbBYV+CHanxI7ZAob3YOmQWE47v2J9dgdAtUL25qTee1fRAL8s/ESW8Fn7grkajb1v6Fq3QZOCY0qpqnuewA==} engines: {node: '>=20.18.0'} - '@drift-labs/vaults-sdk@0.2.49': - resolution: {integrity: sha512-Q4XFBlxdCN1J8nsQe3mmmEsgBFTEW3kGTe3yB3blzzMvdMa1ESYP4nlbZjaMv2pjYTn7u+mDLTye/xDgcYw2qg==} + '@drift-labs/vaults-sdk@0.3.2': + resolution: {integrity: sha512-wt4Rz4/o6ZGYZAr47fXpmMnmNpXESHe5BqxO5iCFGQibjCrcu1Sefko5xfwRH3eLUq//ue5EXpKbBXW7b8piYg==} engines: {node: '>=16'} '@ellipsis-labs/phoenix-sdk@1.4.5': @@ -5157,7 +5157,7 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@drift-labs/sdk@2.107.0-beta.3(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@drift-labs/sdk@2.108.0-beta.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@coral-xyz/anchor-30': '@coral-xyz/anchor@0.30.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)' @@ -5193,7 +5193,7 @@ snapshots: - typescript - utf-8-validate - '@drift-labs/sdk@2.107.0-beta.3(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': + '@drift-labs/sdk@2.108.0-beta.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@coral-xyz/anchor-30': '@coral-xyz/anchor@0.30.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)' @@ -5229,10 +5229,10 @@ snapshots: - typescript - utf-8-validate - '@drift-labs/vaults-sdk@0.2.49(@types/node@22.10.7)(arweave@1.15.5)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': + '@drift-labs/vaults-sdk@0.3.2(@types/node@22.10.7)(arweave@1.15.5)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(utf-8-validate@5.0.10)': dependencies: '@coral-xyz/anchor': 0.28.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@drift-labs/sdk': 2.107.0-beta.3(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@drift-labs/sdk': 2.108.0-beta.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) '@ledgerhq/hw-app-solana': 7.2.4 '@ledgerhq/hw-transport': 6.31.4 '@ledgerhq/hw-transport-node-hid': 6.29.5 @@ -5957,7 +5957,7 @@ snapshots: dependencies: '@ledgerhq/devices': 6.27.1 '@ledgerhq/errors': 6.19.1 - '@ledgerhq/hw-transport': 6.31.4 + '@ledgerhq/hw-transport': 6.27.1 '@ledgerhq/logs': 6.12.0 '@ledgerhq/hw-transport@6.27.1': @@ -6302,7 +6302,7 @@ snapshots: '@metaplex-foundation/mpl-candy-machine@5.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/beet': 0.7.2 '@metaplex-foundation/beet-solana': 0.4.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@metaplex-foundation/cusper': 0.0.2 '@solana/spl-token': 0.3.11(@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)(utf-8-validate@5.0.10) diff --git a/src/tools/drift/drift.ts b/src/tools/drift/drift.ts index a86fc5d9..713fcf9a 100644 --- a/src/tools/drift/drift.ts +++ b/src/tools/drift/drift.ts @@ -1,6 +1,7 @@ import { BASE_PRECISION, BigNum, + BulkAccountLoader, calculateDepositRate, calculateEstimatedEntryPriceWithL2, calculateInterestRate, @@ -14,7 +15,9 @@ import { getInsuranceFundStakeAccountPublicKey, getLimitOrderParams, getMarketOrderParams, + getTokenAmount, getUserAccountPublicKeySync, + isVariant, JupiterClient, MainnetPerpMarkets, MainnetSpotMarkets, @@ -71,6 +74,10 @@ export async function initClients( txParams: { computeUnitsPrice: MINIMUM_COMPUTE_PRICE_FOR_COMPLEX_ACTIONS, }, + accountSubscription: { + type: "polling", + accountLoader: new BulkAccountLoader(agent.connection, "processed", 10), + }, txSender: new FastSingleTxSender({ connection: agent.connection, wallet, @@ -439,12 +446,14 @@ export async function doesUserHaveDriftAccount(agent: SolanaAgentKit) { export async function driftUserAccountInfo(agent: SolanaAgentKit) { try { const { driftClient, cleanUp } = await initClients(agent); + const userPublicKey = getUserAccountPublicKeySync( + new PublicKey(DRIFT_PROGRAM_ID), + agent.wallet.publicKey, + ); + const user = new User({ driftClient, - userAccountPublicKey: getUserAccountPublicKeySync( - new PublicKey(DRIFT_PROGRAM_ID), - agent.wallet.publicKey, - ), + userAccountPublicKey: userPublicKey, }); const userAccountExists = await user.exists(); @@ -453,32 +462,80 @@ export async function driftUserAccountInfo(agent: SolanaAgentKit) { } await user.subscribe(); const account = user.getUserAccount(); - await user.unsubscribe(); - await cleanUp(); const perpPositions = account.perpPositions.map((pos) => ({ - ...pos, + market: MainnetPerpMarkets[pos.marketIndex].symbol, baseAssetAmount: convertToNumber(pos.baseAssetAmount, BASE_PRECISION), + quoteAssetAmount: convertToNumber( + pos.quoteAssetAmount.abs(), + QUOTE_PRECISION, + ), + quoteEntryAmount: convertToNumber( + pos.quoteEntryAmount.abs(), + QUOTE_PRECISION, + ), + quoteBreakEvenAmount: convertToNumber( + pos.quoteBreakEvenAmount.abs(), + QUOTE_PRECISION, + ), settledPnl: convertToNumber(pos.settledPnl, QUOTE_PRECISION), + openAsks: pos.openAsks.toNumber(), + openBids: pos.openBids.toNumber(), + openOrders: pos.openOrders, + positionType: + convertToNumber(pos.baseAssetAmount, BASE_PRECISION) > 0 + ? "long" + : "short", })); - const spotPositions = account.spotPositions.map((pos) => ({ - ...pos, - availableBalance: convertToNumber( + const spotPositions = account.spotPositions.map((pos) => { + const spotMarketAccount = driftClient.getSpotMarketAccount( + pos.marketIndex, + ); + + if (!spotMarketAccount) { + return; + } + + const tokenBalance = getTokenAmount( pos.scaledBalance, - MainnetSpotMarkets[pos.marketIndex].precision, - ), - symbol: MainnetSpotMarkets.find((v) => v.marketIndex === pos.marketIndex) - ?.symbol, - })); + spotMarketAccount, + pos.balanceType, + ); + + return { + availableBalance: + (isVariant(pos.balanceType, "borrow") ? -1 : 1) * + convertToNumber( + tokenBalance, + MainnetSpotMarkets[pos.marketIndex].precision, + ), + symbol: MainnetSpotMarkets[pos.marketIndex].symbol, + openAsks: pos.openAsks.toNumber(), + openBids: pos.openBids.toNumber(), + openOrders: pos.openOrders, + type: isVariant(pos.balanceType, "borrow") ? "borrow" : "deposit", + }; + }); + + const overallUserBalance = user.getNetSpotMarketValue(); + const unrealizedPnl = user.getUnrealizedPNL(true); + const netUSDValue = convertToNumber( + overallUserBalance.add(unrealizedPnl), + QUOTE_PRECISION, + ); + + await cleanUp(); + await user.unsubscribe(); return { - ...account, name: account.name, + accountAddress: userPublicKey.toBase58(), authority: account.authority, + overallBalance: netUSDValue, settledPerpPnl: `$${convertToNumber(account.settledPerpPnl, QUOTE_PRECISION)}`, lastActiveSlot: account.lastActiveSlot.toNumber(), - perpPositions, - spotPositions, + perpPositions: perpPositions.filter((pos) => pos.baseAssetAmount !== 0), + spotPositions: spotPositions.filter((pos) => pos?.availableBalance !== 0), }; } catch (e) { // @ts-expect-error - error message is a string diff --git a/src/utils/keypair.ts b/src/utils/keypair.ts index 1b62f1f4..f65f6d98 100644 --- a/src/utils/keypair.ts +++ b/src/utils/keypair.ts @@ -4,13 +4,9 @@ import { Transaction, VersionedTransaction, } from "@solana/web3.js"; -import bs58 from "bs58"; export const keypair = Keypair.generate(); -console.log(keypair.publicKey.toString()); -console.log(bs58.encode(keypair.secretKey)); - export class Wallet { private _signer: Keypair;