This commit is contained in:
Arihant Bansal
2024-12-23 11:50:14 +05:30
12 changed files with 167 additions and 10 deletions

View File

@@ -25,8 +25,9 @@ import {
stakeWithJup,
sendCompressedAirdrop,
createOrcaSingleSidedWhirlpool,
FEE_TIERS,
fetchPrice,
pythFetchPrice,
FEE_TIERS,
} from "../tools";
import {
CollectionDeployment,
@@ -85,7 +86,7 @@ export class SolanaAgentKit {
return deploy_collection(this, options);
}
async getBalance(token_address?: PublicKey): Promise<number | null> {
async getBalance(token_address?: PublicKey): Promise<number> {
return get_balance(this, token_address);
}
@@ -277,4 +278,8 @@ export class SolanaAgentKit {
tickSize,
);
}
async pythFetchPrice(priceFeedID: string): Promise<string> {
return pythFetchPrice(priceFeedID);
}
}

View File

@@ -1,7 +1,7 @@
import { PublicKey } from "@solana/web3.js";
import Decimal from "decimal.js";
import { Tool } from "langchain/tools";
import { SolanaAgentKit } from "../index";
import { PythFetchPriceResponse, SolanaAgentKit } from "../index";
import { create_image } from "../tools/create_image";
import { BN } from "@coral-xyz/anchor";
import { FEE_TIERS } from "../tools";
@@ -980,6 +980,38 @@ export class SolanaOpenbookCreateMarket extends Tool {
}
}
export class SolanaPythFetchPrice extends Tool {
name = "solana_pyth_fetch_price";
description = `Fetch the price of a given price feed from Pyth's Hermes service
Inputs:
priceFeedID: string, the price feed ID, e.g., "0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" for BTC/USD`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
async _call(input: string): Promise<string> {
try {
const price = await this.solanaKit.pythFetchPrice(input);
let response: PythFetchPriceResponse = {
status: "success",
priceFeedID: input,
price: price,
};
return JSON.stringify(response);
} catch (error: any) {
let response: PythFetchPriceResponse = {
status: "error",
priceFeedID: input,
message: error.message,
code: error.code || "UNKNOWN_ERROR",
};
return JSON.stringify(response);
}
}
}
export function createSolanaTools(solanaKit: SolanaAgentKit) {
return [
new SolanaBalanceTool(solanaKit),
@@ -1007,5 +1039,7 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
new SolanaRaydiumCreateCpmm(solanaKit),
new SolanaOpenbookCreateMarket(solanaKit),
new SolanaCreateSingleSidedWhirlpoolTool(solanaKit),
new SolanaPythFetchPrice(solanaKit),
];
}

View File

@@ -12,6 +12,7 @@ import {
fromWeb3JsPublicKey,
toWeb3JsPublicKey,
} from "@metaplex-foundation/umi-web3js-adapters";
import { mplToolbox } from "@metaplex-foundation/mpl-toolbox";
/**
* Deploy a new SPL token
@@ -33,7 +34,7 @@ export async function deploy_token(
): Promise<{ mint: PublicKey }> {
try {
// Create UMI instance from agent
const umi = createUmi(agent.connection.rpcEndpoint);
const umi = createUmi(agent.connection.rpcEndpoint).use(mplToolbox());
umi.use(keypairIdentity(fromWeb3JsKeypair(agent.wallet)));
// Create new token mint

View File

@@ -10,7 +10,7 @@ import { SolanaAgentKit } from "../index";
export async function get_balance(
agent: SolanaAgentKit,
token_address?: PublicKey,
): Promise<number | null> {
): Promise<number> {
if (!token_address)
return (
(await agent.connection.getBalance(agent.wallet_address)) /
@@ -19,5 +19,5 @@ export async function get_balance(
const token_account =
await agent.connection.getTokenAccountBalance(token_address);
return token_account.value.uiAmount;
return token_account.value.uiAmount || 0;
}

View File

@@ -20,3 +20,4 @@ export * from "./raydium_create_ammV4";
export * from "./raydium_create_clmm";
export * from "./raydium_create_cpmm";
export * from "./openbook_create_market";
export * from "./pyth_fetch_price";

View File

@@ -0,0 +1,40 @@
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
import BN from "bn.js";
/**
* Fetch the price of a given price feed from Pyth
* @param agent SolanaAgentKit instance
* @param priceFeedID Price feed ID
* @returns Latest price value from feed
*
* You can find priceFeedIDs here: https://www.pyth.network/developers/price-feed-ids#stable
*/
export async function pythFetchPrice(priceFeedID: string): Promise<string> {
// get Hermes service URL from https://docs.pyth.network/price-feeds/api-instances-and-providers/hermes
const stableHermesServiceUrl: string = "https://hermes.pyth.network";
const connection = new PriceServiceConnection(stableHermesServiceUrl);
const feeds = [priceFeedID];
try {
const currentPrice = await connection.getLatestPriceFeeds(feeds);
if (currentPrice === undefined) {
throw new Error("Price data not available for the given token.");
}
if (currentPrice.length === 0) {
throw new Error("Price data not available for the given token.");
}
// get price and exponent from price feed
let price = new BN(currentPrice[0].getPriceUnchecked().price);
let exponent = new BN(currentPrice[0].getPriceUnchecked().expo);
// convert to scaled price
let scaledPrice = price.div(new BN(10).pow(exponent));
return scaledPrice.toString();
} catch (error: any) {
throw new Error(`Fetching price from Pyth failed: ${error.message}`);
}
}

View File

@@ -77,3 +77,11 @@ export interface FetchPriceResponse {
message?: string;
code?: string;
}
export interface PythFetchPriceResponse {
status: "success" | "error";
priceFeedID: string;
price?: string;
message?: string;
code?: string;
}