resolve conflicts

This commit is contained in:
UjjwalGupta49
2025-01-05 17:21:25 +05:30
47 changed files with 1130 additions and 269 deletions

View File

@@ -1,7 +1,7 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { pythFetchPrice } from "../tools";
import { fetchPythPrice, fetchPythPriceFeedID } from "../tools";
const pythFetchPriceAction: Action = {
name: "PYTH_FETCH_PRICE",
@@ -18,7 +18,7 @@ const pythFetchPriceAction: Action = {
[
{
input: {
priceFeedId: "Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD", // SOL/USD price feed
tokenSymbol: "SOL", // SOL/USD price feed
},
output: {
status: "success",
@@ -30,15 +30,19 @@ const pythFetchPriceAction: Action = {
],
],
schema: z.object({
priceFeedId: z
tokenSymbol: z
.string()
.min(1)
.describe("The Pyth price feed ID to fetch the price from"),
.describe("The token symbol to fetch the price for"),
}),
handler: async (_agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const priceFeedId = input.tokenId as string;
const priceStr = await pythFetchPrice(priceFeedId);
const priceFeedId = await fetchPythPriceFeedID(
input.tokenSymbol as string,
);
const priceStr = await fetchPythPrice(priceFeedId);
return {
status: "success",
price: priceStr,

View File

@@ -1,4 +1,5 @@
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { BN } from "@coral-xyz/anchor";
import bs58 from "bs58";
import Decimal from "decimal.js";
import { DEFAULT_OPTIONS } from "../constants";
@@ -42,7 +43,6 @@ import {
orcaOpenSingleSidedPosition,
FEE_TIERS,
fetchPrice,
pythFetchPrice,
getAllDomainsTLDs,
getAllRegisteredAllDomains,
getOwnedDomainsForTLD,
@@ -58,13 +58,13 @@ import {
cancelListing,
fetchTokenReportSummary,
fetchTokenDetailedReport,
OrderParams,
fetchPythPrice,
fetchPythPriceFeedID,
FlashTradeParams,
FlashCloseTradeParams,
flashOpenTrade,
flashCloseTrade,
} from "../tools";
import {
CollectionDeployment,
CollectionOptions,
@@ -73,8 +73,8 @@ import {
MintCollectionNFTResponse,
PumpfunLaunchResponse,
PumpFunTokenOptions,
OrderParams,
} from "../types";
import { BN } from "@coral-xyz/anchor";
/**
* Main class for interacting with Solana blockchain
@@ -491,8 +491,12 @@ export class SolanaAgentKit {
return manifestCreateMarket(this, baseMint, quoteMint);
}
async pythFetchPrice(priceFeedID: string): Promise<string> {
return pythFetchPrice(priceFeedID);
async getPythPriceFeedID(tokenSymbol: string): Promise<string> {
return fetchPythPriceFeedID(tokenSymbol);
}
async getPythPrice(priceFeedID: string): Promise<string> {
return fetchPythPrice(priceFeedID);
}
async createGibworkTask(

View File

@@ -1,14 +1,14 @@
import { PublicKey } from "@solana/web3.js";
import { BN } from "@coral-xyz/anchor";
import Decimal from "decimal.js";
import { Tool } from "langchain/tools";
import {
GibworkCreateTaskReponse,
OrderParams,
PythFetchPriceResponse,
SolanaAgentKit,
} from "../index";
import { create_image } from "../tools/create_image";
import { BN } from "@coral-xyz/anchor";
import { FEE_TIERS, generateOrdersfromPattern, OrderParams } from "../tools";
import { create_image, FEE_TIERS, generateOrdersfromPattern } from "../tools";
export class SolanaBalanceTool extends Tool {
name = "solana_balance";
@@ -1763,7 +1763,7 @@ export class SolanaPythFetchPrice extends Tool {
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`;
tokenSymbol: string, e.g., BTC for bitcoin`;
constructor(private solanaKit: SolanaAgentKit) {
super();
@@ -1771,17 +1771,21 @@ export class SolanaPythFetchPrice extends Tool {
async _call(input: string): Promise<string> {
try {
const price = await this.solanaKit.pythFetchPrice(input);
const priceFeedID = await this.solanaKit.getPythPriceFeedID(input);
const price = await this.solanaKit.getPythPrice(priceFeedID);
const response: PythFetchPriceResponse = {
status: "success",
priceFeedID: input,
tokenSymbol: input,
priceFeedID,
price,
};
return JSON.stringify(response);
} catch (error: any) {
const response: PythFetchPriceResponse = {
status: "error",
priceFeedID: input,
tokenSymbol: input,
message: error.message,
code: error.code || "UNKNOWN_ERROR",
};

View File

@@ -4,33 +4,13 @@ import {
sendAndConfirmTransaction,
TransactionInstruction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import {
ManifestClient,
WrapperPlaceOrderParamsExternal,
OrderType,
} from "@cks-systems/manifest-sdk";
import { OrderType } from "@cks-systems/manifest-sdk/client/ts/src/wrapper/types/OrderType";
export interface OrderParams {
quantity: number;
side: string;
price: number;
}
interface BatchOrderPattern {
side: string;
totalQuantity?: number;
priceRange?: {
min?: number;
max?: number;
};
spacing?: {
type: "percentage" | "fixed";
value: number;
};
numberOfOrders?: number;
individualQuantity?: number;
}
import { SolanaAgentKit } from "../index";
import { BatchOrderPattern, OrderParams } from "../types";
/**
* Generates an array of orders based on the specified pattern

View File

@@ -1,4 +1,4 @@
import { SolanaAgentKit } from "..";
import { SolanaAgentKit } from "../agent";
/**
* Get the agents wallet address

View File

@@ -1,64 +1,52 @@
export * from "./get_wallet_address";
export * from "./request_faucet_funds";
export * from "./get_wallet_address";
export * from "./request_faucet_funds";
export * from "./deploy_token";
export * from "./deploy_collection";
export * from "./get_balance";
export * from "./get_balance_other";
export * from "./mint_nft";
export * from "./transfer";
export * from "./trade";
export * from "./limit_order";
export * from "./adrena_perp_trading";
export * from "./batch_order";
export * from "./cancel_all_orders";
export * from "./withdraw_all";
export * from "./adrena_perp_trading";
export * from "./register_domain";
export * from "./resolve_sol_domain";
export * from "./create_gibwork_task";
export * from "./create_image";
export * from "./create_tiplinks";
export * from "./deploy_collection";
export * from "./deploy_token";
export * from "./fetch_price";
export * from "./get_all_domains_tlds";
export * from "./get_all_registered_all_domains";
export * from "./get_balance";
export * from "./get_balance_other";
export * from "./get_main_all_domains_domain";
export * from "./get_owned_all_domains";
export * from "./get_owned_domains_for_tld";
export * from "./get_primary_domain";
export * from "./get_token_data";
export * from "./get_tps";
export * from "./get_wallet_address";
export * from "./launch_pumpfun_token";
export * from "./lend";
export * from "./get_tps";
export * from "./get_token_data";
export * from "./stake_with_jup";
export * from "./stake_with_solayer";
export * from "./fetch_price";
export * from "./send_compressed_airdrop";
export * from "./limit_order";
export * from "./manifest_create_market";
export * from "./mint_nft";
export * from "./openbook_create_market";
export * from "./orca_close_position";
export * from "./orca_create_clmm";
export * from "./orca_create_single_sided_liquidity_pool";
export * from "./orca_fetch_positions";
export * from "./orca_open_centered_position_with_liquidity";
export * from "./orca_open_single_sided_position";
export * from "./get_all_domains_tlds";
export * from "./get_all_registered_all_domains";
export * from "./get_owned_domains_for_tld";
export * from "./get_main_all_domains_domain";
export * from "./get_owned_all_domains";
export * from "./resolve_domain";
export * from "./get_all_domains_tlds";
export * from "./get_all_registered_all_domains";
export * from "./get_owned_domains_for_tld";
export * from "./get_main_all_domains_domain";
export * from "./get_owned_all_domains";
export * from "./resolve_domain";
export * from "./pyth_fetch_price";
export * from "./raydium_create_ammV4";
export * from "./raydium_create_clmm";
export * from "./raydium_create_cpmm";
export * from "./openbook_create_market";
export * from "./manifest_create_market";
export * from "./pyth_fetch_price";
export * from "./create_gibwork_task";
export * from "./register_domain";
export * from "./request_faucet_funds";
export * from "./resolve_domain";
export * from "./resolve_sol_domain";
export * from "./rock_paper_scissor";
export * from "./create_tiplinks";
export * from "./tensor_trade";
export * from "./rugcheck";
export * from "./send_compressed_airdrop";
export * from "./stake_with_jup";
export * from "./stake_with_solayer";
export * from "./tensor_trade";
export * from "./trade";
export * from "./transfer";
export * from "./withdraw_all";
export * from "./flash_open_trade";
export * from "./flash_close_trade";

View File

@@ -8,8 +8,8 @@ import { SolanaAgentKit } from "../index";
import {
ManifestClient,
WrapperPlaceOrderParamsExternal,
OrderType,
} from "@cks-systems/manifest-sdk";
import { OrderType } from "@cks-systems/manifest-sdk/client/ts/src/wrapper/types/OrderType";
/**
* Place limit orders using Manifest

View File

@@ -26,7 +26,7 @@ import { TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
* # Opens a Centered Liquidity Position in an Orca Whirlpool
*
* This function opens a centered liquidity position in a specified Orca Whirlpool. The user defines
* a basis point (bps) offset from the cuurent price of the pool to set the lower and upper bounds of the position.
* a basis point (bps) offset from the current price of the pool to set the lower and upper bounds of the position.
* The user also specifies the token mint and the amount to deposit. The required amount of the other token
* is calculated automatically.
*

View File

@@ -1,38 +1,91 @@
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
import BN from "bn.js";
import { PythPriceFeedIDItem } from "../types";
/**
* Fetch the price feed ID for a given token symbol from Pyth
* @param tokenSymbol Token symbol
* @returns Price feed ID
*/
export async function fetchPythPriceFeedID(
tokenSymbol: string,
): Promise<string> {
try {
const stableHermesServiceUrl: string = "https://hermes.pyth.network";
const response = await fetch(
`${stableHermesServiceUrl}/v2/price_feeds?query=${tokenSymbol}&asset_type=crypto`,
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.length === 0) {
throw new Error(`No price feed found for ${tokenSymbol}`);
}
if (data.length > 1) {
const filteredData = data.filter(
(item: PythPriceFeedIDItem) =>
item.attributes.base.toLowerCase() === tokenSymbol.toLowerCase(),
);
if (filteredData.length === 0) {
throw new Error(`No price feed found for ${tokenSymbol}`);
}
return filteredData[0].id;
}
return data[0].id;
} catch (error: any) {
throw new Error(
`Fetching price feed ID from Pyth failed: ${error.message}`,
);
}
}
/**
* 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];
export async function fetchPythPrice(feedID: string): Promise<string> {
try {
const currentPrice = await connection.getLatestPriceFeeds(feeds);
const stableHermesServiceUrl: string = "https://hermes.pyth.network";
if (currentPrice === undefined) {
throw new Error("Price data not available for the given token.");
const response = await fetch(
`${stableHermesServiceUrl}/v2/updates/price/latest?ids[]=${feedID}`,
);
const data = await response.json();
const parsedData = data.parsed;
if (parsedData.length === 0) {
throw new Error(`No price data found for ${feedID}`);
}
if (currentPrice.length === 0) {
throw new Error("Price data not available for the given token.");
const price = new BN(parsedData[0].price.price);
const exponent = parsedData[0].price.expo;
if (exponent < 0) {
const adjustedPrice = price.mul(new BN(100));
const divisor = new BN(10).pow(new BN(-exponent));
const scaledPrice = adjustedPrice.div(divisor);
const priceStr = scaledPrice.toString();
const formattedPrice = `${priceStr.slice(0, -2)}.${priceStr.slice(-2)}`;
return formattedPrice.startsWith(".")
? `0${formattedPrice}`
: formattedPrice;
}
// get price and exponent from price feed
const price = new BN(currentPrice[0].getPriceUnchecked().price);
const exponent = new BN(currentPrice[0].getPriceUnchecked().expo);
// convert to scaled price
const scaledPrice = price.div(new BN(10).pow(exponent));
const scaledPrice = price.div(new BN(10).pow(new BN(exponent)));
return scaledPrice.toString();
} catch (error: any) {
throw new Error(`Fetching price from Pyth failed: ${error.message}`);

View File

@@ -88,7 +88,8 @@ export interface FetchPriceResponse {
export interface PythFetchPriceResponse {
status: "success" | "error";
priceFeedID: string;
tokenSymbol: string;
priceFeedID?: string;
price?: string;
message?: string;
code?: string;
@@ -165,3 +166,61 @@ export interface TokenCheck {
}>;
score: number;
}
export interface PythPriceFeedIDItem {
id: string;
attributes: {
asset_type: string;
base: string;
};
}
export interface PythPriceItem {
binary: {
data: string[];
encoding: string;
};
parsed: [
Array<{
id: string;
price: {
price: string;
conf: string;
expo: number;
publish_time: number;
};
ema_price: {
price: string;
conf: string;
expo: number;
publish_time: number;
};
metadata: {
slot: number;
proof_available_time: number;
prev_publish_time: number;
};
}>,
];
}
export interface OrderParams {
quantity: number;
side: string;
price: number;
}
export interface BatchOrderPattern {
side: string;
totalQuantity?: number;
priceRange?: {
min?: number;
max?: number;
};
spacing?: {
type: "percentage" | "fixed";
value: number;
};
numberOfOrders?: number;
individualQuantity?: number;
}