mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-13 23:16:55 +00:00
Merge branch 'gib-bounty-sol033188' of github.com:adpthegreat/solana-agent-kit into gib-bounty-sol033188
This commit is contained in:
69
README.md
69
README.md
@@ -9,7 +9,7 @@
|
||||
An open-source toolkit for connecting AI agents to Solana protocols. Now, any agent, using any model can autonomously perform 15+ Solana actions:
|
||||
|
||||
- Trade tokens
|
||||
- Launch new tokens
|
||||
- Launch new tokens
|
||||
- Lend assets
|
||||
- Send compressed airdrops
|
||||
- Execute blinks
|
||||
@@ -96,10 +96,10 @@ const tools = createSolanaTools(agent);
|
||||
### Deploy a New Token
|
||||
|
||||
```typescript
|
||||
import { deploy_token } from "solana-agent-kit";
|
||||
|
||||
const result = await deploy_token(
|
||||
agent,
|
||||
const result = await agent.deployToken(
|
||||
"my ai token", // name
|
||||
"uri", // uri
|
||||
"token", // symbol
|
||||
9, // decimals
|
||||
1000000 // initial supply
|
||||
);
|
||||
@@ -110,9 +110,7 @@ console.log("Token Mint Address:", result.mint.toString());
|
||||
### Create NFT Collection
|
||||
|
||||
```typescript
|
||||
import { deploy_collection } from "solana-agent-kit";
|
||||
|
||||
const collection = await deploy_collection(agent, {
|
||||
const collection = await agent.deployCollection({
|
||||
name: "My NFT Collection",
|
||||
uri: "https://arweave.net/metadata.json",
|
||||
royaltyBasisPoints: 500, // 5%
|
||||
@@ -128,11 +126,9 @@ const collection = await deploy_collection(agent, {
|
||||
### Swap Tokens
|
||||
|
||||
```typescript
|
||||
import { trade } from "solana-agent-kit";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const signature = await trade(
|
||||
agent,
|
||||
const signature = await agent.trade(
|
||||
new PublicKey("target-token-mint"),
|
||||
100, // amount
|
||||
new PublicKey("source-token-mint"),
|
||||
@@ -143,46 +139,24 @@ const signature = await trade(
|
||||
### Lend Tokens
|
||||
|
||||
```typescript
|
||||
import { lendAsset } from "solana-agent-kit";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const signature = await lendAsset(
|
||||
agent,
|
||||
100 // amount
|
||||
const signature = await agent.lendAssets(
|
||||
100 // amount of USDC to lend
|
||||
);
|
||||
```
|
||||
|
||||
### Stake SOL
|
||||
|
||||
```typescript
|
||||
import { stakeWithJup } from "solana-agent-kit";
|
||||
|
||||
const signature = await stakeWithJup(
|
||||
agent,
|
||||
1 // amount in SOL
|
||||
const signature = await agent.stake(
|
||||
1 // amount in SOL to stake
|
||||
);
|
||||
```
|
||||
|
||||
### Fetch Token Price
|
||||
|
||||
```typescript
|
||||
import { fetchPrice } from "solana-agent-kit";
|
||||
|
||||
const price = await fetchPrice(
|
||||
agent,
|
||||
"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN" // Token mint address
|
||||
);
|
||||
|
||||
console.log("Price in USDC:", price);
|
||||
```
|
||||
|
||||
### Send an SPL Token Airdrop via ZK Compression
|
||||
|
||||
```typescript
|
||||
import {
|
||||
sendCompressedAirdrop,
|
||||
getAirdropCostEstimate,
|
||||
} from "solana-agent-kit";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
(async () => {
|
||||
@@ -194,8 +168,7 @@ import { PublicKey } from "@solana/web3.js";
|
||||
)
|
||||
);
|
||||
|
||||
const signature = await sendCompressedAirdrop(
|
||||
agent,
|
||||
const signature = await agent.sendCompressedAirdrop(
|
||||
new PublicKey("JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"), // mint
|
||||
42, // amount per recipient
|
||||
[
|
||||
@@ -207,6 +180,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 +233,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 +248,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";
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"docs": "typedoc src --out docs",
|
||||
"test": "ts-node test/index.ts",
|
||||
"test": "ts-node test/**/*.ts",
|
||||
"generate": "ts-node src/utils/keypair.ts"
|
||||
},
|
||||
"engines": {
|
||||
@@ -35,6 +35,7 @@
|
||||
"@onsol/tldparser": "^0.6.7",
|
||||
"@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",
|
||||
|
||||
51
pnpm-lock.yaml
generated
51
pnpm-lock.yaml
generated
@@ -59,6 +59,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)
|
||||
@@ -352,6 +355,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==}
|
||||
|
||||
@@ -648,6 +658,9 @@ packages:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
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==}
|
||||
|
||||
@@ -990,6 +1003,10 @@ packages:
|
||||
resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-retry-allowed@2.2.0:
|
||||
resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
is-typed-array@1.1.15:
|
||||
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1328,6 +1345,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
|
||||
@@ -1832,6 +1852,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
|
||||
@@ -2294,6 +2332,11 @@ snapshots:
|
||||
dependencies:
|
||||
possible-typed-array-names: 1.0.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
|
||||
@@ -2630,6 +2673,8 @@ snapshots:
|
||||
call-bind: 1.0.8
|
||||
define-properties: 1.2.1
|
||||
|
||||
is-retry-allowed@2.2.0: {}
|
||||
|
||||
is-typed-array@1.1.15:
|
||||
dependencies:
|
||||
which-typed-array: 1.1.18
|
||||
@@ -2638,6 +2683,10 @@ snapshots:
|
||||
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
|
||||
@@ -2956,6 +3005,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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Connection, Keypair, PublicKey } from "@solana/web3.js";;
|
||||
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
||||
import bs58 from "bs58";
|
||||
import Decimal from "decimal.js";
|
||||
import { DEFAULT_OPTIONS } from "../constants";
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
sendCompressedAirdrop,
|
||||
createOrcaSingleSidedWhirlpool,
|
||||
FEE_TIERS,
|
||||
pythFetchPrice,
|
||||
getAllDomainsTLDs,
|
||||
getAllRegisteredAllDomains,
|
||||
getOwnedDomainsForTLD,
|
||||
@@ -33,7 +34,14 @@ import {
|
||||
getOwnedAllDomains,
|
||||
resolveAllDomains,
|
||||
} from "../tools";
|
||||
import { CollectionOptions, PumpFunTokenOptions } from "../types";
|
||||
import {
|
||||
CollectionDeployment,
|
||||
CollectionOptions,
|
||||
JupiterTokenData,
|
||||
MintCollectionNFTResponse,
|
||||
PumpfunLaunchResponse,
|
||||
PumpFunTokenOptions,
|
||||
} from "../types";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
import { NameAccountAndDomain } from "@onsol/tldparser";
|
||||
|
||||
@@ -55,7 +63,7 @@ export class SolanaAgentKit {
|
||||
constructor(
|
||||
private_key: string,
|
||||
rpc_url = "https://api.mainnet-beta.solana.com",
|
||||
openai_api_key: string
|
||||
openai_api_key: string,
|
||||
) {
|
||||
this.connection = new Connection(rpc_url);
|
||||
this.wallet = Keypair.fromSecretKey(bs58.decode(private_key));
|
||||
@@ -73,40 +81,46 @@ export class SolanaAgentKit {
|
||||
uri: string,
|
||||
symbol: string,
|
||||
decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS,
|
||||
initialSupply?: number
|
||||
) {
|
||||
initialSupply?: number,
|
||||
): Promise<{ mint: PublicKey }> {
|
||||
return deploy_token(this, name, uri, symbol, decimals, initialSupply);
|
||||
}
|
||||
|
||||
async deployCollection(options: CollectionOptions) {
|
||||
async deployCollection(
|
||||
options: CollectionOptions,
|
||||
): Promise<CollectionDeployment> {
|
||||
return deploy_collection(this, options);
|
||||
}
|
||||
|
||||
async getBalance(token_address?: PublicKey) {
|
||||
async getBalance(token_address?: PublicKey): Promise<number> {
|
||||
return get_balance(this, token_address);
|
||||
}
|
||||
|
||||
async mintNFT(
|
||||
collectionMint: PublicKey,
|
||||
metadata: Parameters<typeof mintCollectionNFT>[2],
|
||||
recipient?: PublicKey
|
||||
) {
|
||||
recipient?: PublicKey,
|
||||
): Promise<MintCollectionNFTResponse> {
|
||||
return mintCollectionNFT(this, collectionMint, metadata, recipient);
|
||||
}
|
||||
|
||||
async transfer(to: PublicKey, amount: number, mint?: PublicKey) {
|
||||
async transfer(
|
||||
to: PublicKey,
|
||||
amount: number,
|
||||
mint?: PublicKey,
|
||||
): Promise<string> {
|
||||
return transfer(this, to, amount, mint);
|
||||
}
|
||||
|
||||
async registerDomain(name: string, spaceKB?: number) {
|
||||
async registerDomain(name: string, spaceKB?: number): Promise<string> {
|
||||
return registerDomain(this, name, spaceKB);
|
||||
}
|
||||
|
||||
async resolveSolDomain(domain: string) {
|
||||
async resolveSolDomain(domain: string): Promise<PublicKey> {
|
||||
return resolveSolDomain(this, domain);
|
||||
}
|
||||
|
||||
async getPrimaryDomain(account: PublicKey) {
|
||||
async getPrimaryDomain(account: PublicKey): Promise<string> {
|
||||
return getPrimaryDomain(this, account);
|
||||
}
|
||||
|
||||
@@ -114,24 +128,28 @@ export class SolanaAgentKit {
|
||||
outputMint: PublicKey,
|
||||
inputAmount: number,
|
||||
inputMint?: PublicKey,
|
||||
slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS
|
||||
) {
|
||||
slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS,
|
||||
): Promise<string> {
|
||||
return trade(this, outputMint, inputAmount, inputMint, slippageBps);
|
||||
}
|
||||
|
||||
async lendAssets(amount: number) {
|
||||
async lendAssets(amount: number): Promise<string> {
|
||||
return lendAsset(this, amount);
|
||||
}
|
||||
|
||||
async getTPS() {
|
||||
async getTPS(): Promise<number> {
|
||||
return getTPS(this);
|
||||
}
|
||||
|
||||
async getTokenDataByAddress(mint: string) {
|
||||
async getTokenDataByAddress(
|
||||
mint: string,
|
||||
): Promise<JupiterTokenData | undefined> {
|
||||
return getTokenDataByAddress(new PublicKey(mint));
|
||||
}
|
||||
|
||||
async getTokenDataByTicker(ticker: string) {
|
||||
async getTokenDataByTicker(
|
||||
ticker: string,
|
||||
): Promise<JupiterTokenData | undefined> {
|
||||
return getTokenDataByTicker(ticker);
|
||||
}
|
||||
|
||||
@@ -140,19 +158,19 @@ export class SolanaAgentKit {
|
||||
tokenTicker: string,
|
||||
description: string,
|
||||
imageUrl: string,
|
||||
options?: PumpFunTokenOptions
|
||||
) {
|
||||
options?: PumpFunTokenOptions,
|
||||
): Promise<PumpfunLaunchResponse> {
|
||||
return launchPumpFunToken(
|
||||
this,
|
||||
tokenName,
|
||||
tokenTicker,
|
||||
description,
|
||||
imageUrl,
|
||||
options
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
async stake(amount: number) {
|
||||
async stake(amount: number): Promise<string> {
|
||||
return stakeWithJup(this, amount);
|
||||
}
|
||||
|
||||
@@ -162,7 +180,7 @@ export class SolanaAgentKit {
|
||||
decimals: number,
|
||||
recipients: string[],
|
||||
priorityFeeInLamports: number,
|
||||
shouldLog: boolean
|
||||
shouldLog: boolean,
|
||||
): Promise<string[]> {
|
||||
return await sendCompressedAirdrop(
|
||||
this,
|
||||
@@ -171,7 +189,7 @@ export class SolanaAgentKit {
|
||||
decimals,
|
||||
recipients.map((recipient) => new PublicKey(recipient)),
|
||||
priorityFeeInLamports,
|
||||
shouldLog
|
||||
shouldLog,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,12 +245,10 @@ export class SolanaAgentKit {
|
||||
|
||||
async raydiumCreateAmmV4(
|
||||
marketId: PublicKey,
|
||||
|
||||
baseAmount: BN,
|
||||
quoteAmount: BN,
|
||||
|
||||
startTime: BN
|
||||
) {
|
||||
): Promise<string> {
|
||||
return raydiumCreateAmmV4(
|
||||
this,
|
||||
marketId,
|
||||
@@ -241,50 +257,39 @@ export class SolanaAgentKit {
|
||||
quoteAmount,
|
||||
|
||||
startTime
|
||||
);
|
||||
);;
|
||||
}
|
||||
|
||||
async raydiumCreateClmm(
|
||||
mint1: PublicKey,
|
||||
mint2: PublicKey,
|
||||
|
||||
configId: PublicKey,
|
||||
|
||||
initialPrice: Decimal,
|
||||
startTime: BN
|
||||
) {
|
||||
): Promise<string> {
|
||||
return raydiumCreateClmm(
|
||||
this,
|
||||
|
||||
mint1,
|
||||
mint2,
|
||||
|
||||
configId,
|
||||
|
||||
initialPrice,
|
||||
startTime
|
||||
startTime,
|
||||
);
|
||||
}
|
||||
|
||||
async raydiumCreateCpmm(
|
||||
mint1: PublicKey,
|
||||
mint2: PublicKey,
|
||||
|
||||
configId: PublicKey,
|
||||
|
||||
mintAAmount: BN,
|
||||
mintBAmount: BN,
|
||||
|
||||
startTime: BN
|
||||
) {
|
||||
): Promise<string> {
|
||||
return raydiumCreateCpmm(
|
||||
this,
|
||||
|
||||
mint1,
|
||||
mint2,
|
||||
|
||||
configId,
|
||||
|
||||
mintAAmount,
|
||||
mintBAmount,
|
||||
|
||||
@@ -295,17 +300,20 @@ export class SolanaAgentKit {
|
||||
async openbookCreateMarket(
|
||||
baseMint: PublicKey,
|
||||
quoteMint: PublicKey,
|
||||
|
||||
lotSize: number = 1,
|
||||
tickSize: number = 0.01
|
||||
) {
|
||||
): Promise<string[]> {
|
||||
return openbookCreateMarket(
|
||||
this,
|
||||
baseMint,
|
||||
quoteMint,
|
||||
|
||||
lotSize,
|
||||
tickSize
|
||||
);
|
||||
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";
|
||||
@@ -981,6 +981,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 class SolanaResolveAllDomainsTool extends Tool {
|
||||
name = "solana_resolve_all_domains";
|
||||
description = `Resolve a domain name to a public key.
|
||||
@@ -1190,6 +1222,13 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaRaydiumCreateCpmm(solanaKit),
|
||||
new SolanaOpenbookCreateMarket(solanaKit),
|
||||
new SolanaCreateSingleSidedWhirlpoolTool(solanaKit),
|
||||
new SolanaPythFetchPrice(solanaKit),
|
||||
new SolanaResolveDomainTool(solanaKit),
|
||||
new SolanaGetOwnedDomains(solanaKit),
|
||||
new SolanaGetOwnedTldDomains(solanaKit),
|
||||
new SolanaGetAllTlds(solanaKit),
|
||||
new SolanaGetAllRegisteredDomains(solanaKit),
|
||||
new SolanaGetMainDomain(solanaKit),
|
||||
new SolanaResolveAllDomainsTool(solanaKit),
|
||||
new SolanaGetOwnedDomains(solanaKit),
|
||||
new SolanaGetOwnedTldDomains(solanaKit),
|
||||
@@ -1198,3 +1237,4 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaGetMainDomain(solanaKit),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,15 @@ import { SolanaAgentKit } from "../index";
|
||||
*/
|
||||
export async function get_balance(
|
||||
agent: SolanaAgentKit,
|
||||
token_address?: PublicKey
|
||||
) {
|
||||
token_address?: PublicKey,
|
||||
): Promise<number> {
|
||||
if (!token_address)
|
||||
return await agent.connection.getBalance(agent.wallet_address) / LAMPORTS_PER_SOL
|
||||
return (
|
||||
(await agent.connection.getBalance(agent.wallet_address)) /
|
||||
LAMPORTS_PER_SOL
|
||||
);
|
||||
|
||||
const token_account = await agent.connection.getTokenAccountBalance(token_address);
|
||||
return token_account.value.uiAmount;
|
||||
const token_account =
|
||||
await agent.connection.getTokenAccountBalance(token_address);
|
||||
return token_account.value.uiAmount || 0;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ 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 "./get_all_domains_tlds";
|
||||
export * from "./get_all_registered_all_domains";
|
||||
@@ -24,7 +23,16 @@ 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 "./raydium_create_ammV4";
|
||||
export * from "./raydium_create_clmm";
|
||||
export * from "./raydium_create_cpmm";
|
||||
export * from "./openbook_create_market";
|
||||
export * from "./pyth_fetch_price";
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
// src/tools/launch_pumpfun_token.ts
|
||||
import { VersionedTransaction, Keypair } from "@solana/web3.js";
|
||||
import { PumpFunTokenOptions, SolanaAgentKit } from "../index";
|
||||
import {
|
||||
PumpfunLaunchResponse,
|
||||
PumpFunTokenOptions,
|
||||
SolanaAgentKit,
|
||||
} from "../index";
|
||||
|
||||
async function uploadMetadata(
|
||||
tokenName: string,
|
||||
tokenName: string,
|
||||
tokenTicker: string,
|
||||
description: string,
|
||||
imageUrl: string,
|
||||
options?: PumpFunTokenOptions
|
||||
options?: PumpFunTokenOptions,
|
||||
): Promise<any> {
|
||||
// Create metadata object
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('name', tokenName);
|
||||
formData.append("name", tokenName);
|
||||
formData.append("symbol", tokenTicker);
|
||||
formData.append("description", description);
|
||||
|
||||
formData.append("showName", "true");
|
||||
|
||||
if (options?.twitter) formData.append('twitter', options.twitter);
|
||||
if (options?.twitter) formData.append("twitter", options.twitter);
|
||||
if (options?.telegram) formData.append("telegram", options.telegram);
|
||||
if (options?.website) formData.append("website", options.website);
|
||||
|
||||
@@ -35,13 +39,12 @@ async function uploadMetadata(
|
||||
}
|
||||
// Add file if exists
|
||||
if (files?.file) {
|
||||
finalFormData.append('file', files.file);
|
||||
finalFormData.append("file", files.file);
|
||||
}
|
||||
|
||||
|
||||
const metadataResponse = await fetch("https://pump.fun/api/ipfs", {
|
||||
method: "POST",
|
||||
body: finalFormData
|
||||
body: finalFormData,
|
||||
});
|
||||
|
||||
if (!metadataResponse.ok) {
|
||||
@@ -55,7 +58,7 @@ async function createTokenTransaction(
|
||||
agent: SolanaAgentKit,
|
||||
mintKeypair: Keypair,
|
||||
metadataResponse: any,
|
||||
options?: PumpFunTokenOptions
|
||||
options?: PumpFunTokenOptions,
|
||||
) {
|
||||
const payload = {
|
||||
publicKey: agent.wallet_address.toBase58(),
|
||||
@@ -78,12 +81,14 @@ async function createTokenTransaction(
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Transaction creation failed: ${response.status} - ${errorText}`);
|
||||
throw new Error(
|
||||
`Transaction creation failed: ${response.status} - ${errorText}`,
|
||||
);
|
||||
}
|
||||
|
||||
return response;
|
||||
@@ -92,12 +97,13 @@ async function createTokenTransaction(
|
||||
async function signAndSendTransaction(
|
||||
kit: SolanaAgentKit,
|
||||
tx: VersionedTransaction,
|
||||
mintKeypair: Keypair
|
||||
mintKeypair: Keypair,
|
||||
) {
|
||||
try {
|
||||
// Get the latest blockhash
|
||||
const { blockhash, lastValidBlockHeight } = await kit.connection.getLatestBlockhash();
|
||||
|
||||
const { blockhash, lastValidBlockHeight } =
|
||||
await kit.connection.getLatestBlockhash();
|
||||
|
||||
// Update transaction with latest blockhash
|
||||
tx.message.recentBlockhash = blockhash;
|
||||
|
||||
@@ -107,15 +113,15 @@ async function signAndSendTransaction(
|
||||
// Send and confirm transaction with options
|
||||
const signature = await kit.connection.sendTransaction(tx, {
|
||||
skipPreflight: false,
|
||||
preflightCommitment: 'confirmed',
|
||||
maxRetries: 5
|
||||
preflightCommitment: "confirmed",
|
||||
maxRetries: 5,
|
||||
});
|
||||
|
||||
// Wait for confirmation
|
||||
const confirmation = await kit.connection.confirmTransaction({
|
||||
signature,
|
||||
blockhash,
|
||||
lastValidBlockHeight
|
||||
lastValidBlockHeight,
|
||||
});
|
||||
|
||||
if (confirmation.value.err) {
|
||||
@@ -124,9 +130,9 @@ async function signAndSendTransaction(
|
||||
|
||||
return signature;
|
||||
} catch (error) {
|
||||
console.error('Transaction send error:', error);
|
||||
if (error instanceof Error && 'logs' in error) {
|
||||
console.error('Transaction logs:', error.logs);
|
||||
console.error("Transaction send error:", error);
|
||||
if (error instanceof Error && "logs" in error) {
|
||||
console.error("Transaction logs:", error.logs);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
@@ -140,6 +146,7 @@ async function signAndSendTransaction(
|
||||
* @param description - Description of the token
|
||||
* @param imageUrl - URL of the token image
|
||||
* @param options - Optional token options (twitter, telegram, website, initialLiquiditySOL, slippageBps, priorityFee)
|
||||
* @returns - Signature of the transaction, mint address and metadata URI, if successful, else error
|
||||
*/
|
||||
export async function launchPumpFunToken(
|
||||
agent: SolanaAgentKit,
|
||||
@@ -147,15 +154,27 @@ export async function launchPumpFunToken(
|
||||
tokenTicker: string,
|
||||
description: string,
|
||||
imageUrl: string,
|
||||
options?: PumpFunTokenOptions
|
||||
) {
|
||||
options?: PumpFunTokenOptions,
|
||||
): Promise<PumpfunLaunchResponse> {
|
||||
try {
|
||||
|
||||
const mintKeypair = Keypair.generate();
|
||||
const metadataResponse = await uploadMetadata(tokenName, tokenTicker, description, imageUrl, options);
|
||||
const response = await createTokenTransaction(agent, mintKeypair, metadataResponse, options);
|
||||
const metadataResponse = await uploadMetadata(
|
||||
tokenName,
|
||||
tokenTicker,
|
||||
description,
|
||||
imageUrl,
|
||||
options,
|
||||
);
|
||||
const response = await createTokenTransaction(
|
||||
agent,
|
||||
mintKeypair,
|
||||
metadataResponse,
|
||||
options,
|
||||
);
|
||||
const transactionData = await response.arrayBuffer();
|
||||
const tx = VersionedTransaction.deserialize(new Uint8Array(transactionData));
|
||||
const tx = VersionedTransaction.deserialize(
|
||||
new Uint8Array(transactionData),
|
||||
);
|
||||
const signature = await signAndSendTransaction(agent, tx, mintKeypair);
|
||||
|
||||
return {
|
||||
@@ -163,12 +182,11 @@ export async function launchPumpFunToken(
|
||||
mint: mintKeypair.publicKey.toBase58(),
|
||||
metadataUri: metadataResponse.metadataUri,
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error in launchpumpfuntoken:", error);
|
||||
if (error instanceof Error && 'logs' in error) {
|
||||
console.error('Transaction logs:', (error as any).logs);
|
||||
if (error instanceof Error && "logs" in error) {
|
||||
console.error("Transaction logs:", (error as any).logs);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ async function initializeAgent() {
|
||||
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
|
||||
(internal) HTTP error code, ask the user to try again later. If someone asks you to do something you
|
||||
can't do with your currently available tools, you must say so, and encourage them to implement it
|
||||
themselves using the Solana Agent Kit, recommend they go to https://sendai.fun/kit for more information. Be
|
||||
themselves using the Solana Agent Kit, recommend they go to https://www.solanaagentkit.xyz for more information. Be
|
||||
concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is
|
||||
explicitly requested.
|
||||
`,
|
||||
|
||||
Reference in New Issue
Block a user