mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-13 23:16:55 +00:00
18
README.md
18
README.md
@@ -207,6 +207,19 @@ import { PublicKey } from "@solana/web3.js";
|
||||
})();
|
||||
```
|
||||
|
||||
### Fetch Price Data from Pyth
|
||||
|
||||
```typescript
|
||||
import { pythFetchPrice } from "solana-agent-kit";
|
||||
|
||||
const price = await pythFetchPrice(
|
||||
agent,
|
||||
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
|
||||
);
|
||||
|
||||
console.log("Price in BTC/USD:", price);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Functions
|
||||
@@ -247,6 +260,10 @@ Stake SOL with Jupiter to earn rewards.
|
||||
|
||||
Send an SPL token airdrop to many recipients at low cost via ZK Compression.
|
||||
|
||||
#### `pythFetchPrice(agent, priceFeedID)`
|
||||
|
||||
Fetch price data from Pyth's Hermes service.
|
||||
|
||||
## Dependencies
|
||||
|
||||
The toolkit relies on several key Solana and Metaplex libraries:
|
||||
@@ -258,6 +275,7 @@ The toolkit relies on several key Solana and Metaplex libraries:
|
||||
- @metaplex-foundation/umi
|
||||
- @lightprotocol/compressed-token
|
||||
- @lightprotocol/stateless.js
|
||||
- @pythnetwork/price-service-client
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Create a new TypeScript file in the `src/tools/` directory for your tool (e.g.,
|
||||
|
||||
### 2. Implement the Tool Class
|
||||
|
||||
```typescript:src/tools/custom_tool.ts
|
||||
```typescript:src/langchain/index.ts
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
|
||||
@@ -86,6 +86,8 @@ export function createSolanaTools(agent: SolanaAgentKit) {
|
||||
|
||||
### 6. Usage Example
|
||||
|
||||
Add a code example in the `README.md` file.
|
||||
|
||||
```typescript
|
||||
import { SolanaAgentKit, createSolanaTools } from "solana-agent-kit";
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@metaplex-foundation/umi-web3js-adapters": "^0.9.2",
|
||||
"@orca-so/common-sdk": "0.6.4",
|
||||
"@orca-so/whirlpools-sdk": "^0.13.12",
|
||||
"@pythnetwork/price-service-client": "^1.9.0",
|
||||
"@raydium-io/raydium-sdk-v2": "0.1.95-alpha",
|
||||
"@solana/spl-token": "^0.4.9",
|
||||
"@solana/web3.js": "^1.95.4",
|
||||
|
||||
54
pnpm-lock.yaml
generated
54
pnpm-lock.yaml
generated
@@ -38,6 +38,9 @@ importers:
|
||||
'@metaplex-foundation/mpl-token-metadata':
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0(@metaplex-foundation/umi@0.9.2)
|
||||
'@metaplex-foundation/mpl-toolbox':
|
||||
specifier: ^0.9.4
|
||||
version: 0.9.4(@metaplex-foundation/umi@0.9.2)
|
||||
'@metaplex-foundation/umi':
|
||||
specifier: ^0.9.2
|
||||
version: 0.9.2
|
||||
@@ -53,6 +56,9 @@ importers:
|
||||
'@orca-so/whirlpools-sdk':
|
||||
specifier: ^0.13.12
|
||||
version: 0.13.12(@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(@orca-so/common-sdk@0.6.4(@solana/spl-token@0.4.9(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3))(@solana/spl-token@0.4.9(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10))(@solana/web3.js@1.98.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(decimal.js@10.4.3)
|
||||
'@pythnetwork/price-service-client':
|
||||
specifier: ^1.9.0
|
||||
version: 1.9.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
|
||||
'@raydium-io/raydium-sdk-v2':
|
||||
specifier: 0.1.95-alpha
|
||||
version: 0.1.95-alpha(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)
|
||||
@@ -316,6 +322,13 @@ packages:
|
||||
'@solana/web3.js': ^1.90.0
|
||||
decimal.js: ^10.4.3
|
||||
|
||||
'@pythnetwork/price-service-client@1.9.0':
|
||||
resolution: {integrity: sha512-SLm3IFcfmy9iMqHeT4Ih6qMNZhJEefY14T9yTlpsH2D/FE5+BaGGnfcexUifVlfH6M7mwRC4hEFdNvZ6ebZjJg==}
|
||||
deprecated: This package is deprecated and is no longer maintained. Please use @pythnetwork/hermes-client instead.
|
||||
|
||||
'@pythnetwork/price-service-sdk@1.8.0':
|
||||
resolution: {integrity: sha512-tFZ1thj3Zja06DzPIX2dEWSi7kIfIyqreoywvw5NQ3Z1pl5OJHQGMEhxt6Li3UCGSp2ooYZS9wl8/8XfrfrNSA==}
|
||||
|
||||
'@raydium-io/raydium-sdk-v2@0.1.95-alpha':
|
||||
resolution: {integrity: sha512-+u7yxo/R1JDysTCzOuAlh90ioBe2DlM2Hbcz/tFsxP/YzmnYQzShvNjcmc0361a4zJhmlrEJfpFXW0J3kkX5vA==}
|
||||
|
||||
@@ -592,6 +605,9 @@ packages:
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
axios-retry@3.9.1:
|
||||
resolution: {integrity: sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==}
|
||||
|
||||
axios@1.7.9:
|
||||
resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
|
||||
|
||||
@@ -826,6 +842,10 @@ packages:
|
||||
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
is-retry-allowed@2.2.0:
|
||||
resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
isomorphic-ws@4.0.1:
|
||||
resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==}
|
||||
peerDependencies:
|
||||
@@ -1126,6 +1146,9 @@ packages:
|
||||
trim-lines@3.0.1:
|
||||
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
|
||||
|
||||
ts-log@2.2.7:
|
||||
resolution: {integrity: sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==}
|
||||
|
||||
ts-node@10.9.2:
|
||||
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
||||
hasBin: true
|
||||
@@ -1576,6 +1599,24 @@ snapshots:
|
||||
decimal.js: 10.4.3
|
||||
tiny-invariant: 1.3.3
|
||||
|
||||
'@pythnetwork/price-service-client@1.9.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)':
|
||||
dependencies:
|
||||
'@pythnetwork/price-service-sdk': 1.8.0
|
||||
'@types/ws': 8.5.13
|
||||
axios: 1.7.9
|
||||
axios-retry: 3.9.1
|
||||
isomorphic-ws: 4.0.1(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))
|
||||
ts-log: 2.2.7
|
||||
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- utf-8-validate
|
||||
|
||||
'@pythnetwork/price-service-sdk@1.8.0':
|
||||
dependencies:
|
||||
bn.js: 5.2.1
|
||||
|
||||
'@raydium-io/raydium-sdk-v2@0.1.95-alpha(bufferutil@4.0.8)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.7.2)(utf-8-validate@5.0.10)':
|
||||
dependencies:
|
||||
'@solana/buffer-layout': 4.0.1
|
||||
@@ -2016,6 +2057,11 @@ snapshots:
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
axios-retry@3.9.1:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
is-retry-allowed: 2.2.0
|
||||
|
||||
axios@1.7.9:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.9
|
||||
@@ -2235,10 +2281,16 @@ snapshots:
|
||||
|
||||
ipaddr.js@2.2.0: {}
|
||||
|
||||
is-retry-allowed@2.2.0: {}
|
||||
|
||||
isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10)):
|
||||
dependencies:
|
||||
ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10)
|
||||
|
||||
isomorphic-ws@4.0.1(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)):
|
||||
dependencies:
|
||||
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
|
||||
|
||||
jayson@4.1.3(bufferutil@4.0.8)(utf-8-validate@5.0.10):
|
||||
dependencies:
|
||||
'@types/connect': 3.4.38
|
||||
@@ -2522,6 +2574,8 @@ snapshots:
|
||||
|
||||
trim-lines@3.0.1: {}
|
||||
|
||||
ts-log@2.2.7: {}
|
||||
|
||||
ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
|
||||
@@ -25,7 +25,8 @@ import {
|
||||
stakeWithJup,
|
||||
sendCompressedAirdrop,
|
||||
createOrcaSingleSidedWhirlpool,
|
||||
FEE_TIERS
|
||||
FEE_TIERS,
|
||||
pythFetchPrice
|
||||
} from "../tools";
|
||||
import { CollectionOptions, PumpFunTokenOptions } from "../types";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
@@ -270,4 +271,8 @@ export class SolanaAgentKit {
|
||||
tickSize,
|
||||
)
|
||||
}
|
||||
|
||||
async pythFetchPrice(priceFeedID: string) {
|
||||
return pythFetchPrice(this, priceFeedID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 { fetchPrice } from "../tools/fetch_price";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
@@ -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),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@ export * from "./get_token_data";
|
||||
export * from "./stake_with_jup";
|
||||
export * from "./fetch_price";
|
||||
export * from "./send_compressed_airdrop";
|
||||
|
||||
export * from "./create_orca_single_sided_whirlpool";export * from "./raydium_create_ammV4";
|
||||
export * from "./create_orca_single_sided_whirlpool";
|
||||
export * from "./raydium_create_ammV4";
|
||||
export * from "./raydium_create_clmm";
|
||||
export * from "./raydium_create_cpmm";
|
||||
export * from "./openbook_create_market";
|
||||
export * from "./openbook_create_market";
|
||||
export * from "./pyth_fetch_price";
|
||||
48
src/tools/pyth_fetch_price.ts
Normal file
48
src/tools/pyth_fetch_price.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { Tool } from "langchain/tools";
|
||||
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(
|
||||
agent: SolanaAgentKit,
|
||||
priceFeedID: 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}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user