fixes and renames

This commit is contained in:
Arihant Bansal
2024-12-22 01:20:29 +05:30
parent f84a618c6c
commit ed689f5efd
31 changed files with 510 additions and 440 deletions

View File

@@ -26,6 +26,7 @@ import {
sendCompressedAirdrop,
createOrcaSingleSidedWhirlpool,
FEE_TIERS,
fetchPrice,
} from "../tools";
import {
CollectionDeployment,
@@ -39,14 +40,14 @@ import { BN } from "@coral-xyz/anchor";
/**
* Main class for interacting with Solana blockchain
* Provides a unified interface for token operations, NFT management, and trading
* Provides a unified interface for token operations, NFT management, trading and more
*
* @class SolanaAgentKit
* @class SolanaAgent
* @property {Connection} connection - Solana RPC connection
* @property {Keypair} wallet - Wallet keypair for signing transactions
* @property {PublicKey} wallet_address - Public key of the wallet
*/
export class SolanaAgentKit {
export class SolanaAgent {
public connection: Connection;
public wallet: Keypair;
public wallet_address: PublicKey;
@@ -145,6 +146,10 @@ export class SolanaAgentKit {
return getTokenDataByTicker(ticker);
}
async fetchTokenPrice(mint: string) {
return fetchPrice(new PublicKey(mint));
}
async launchPumpFunToken(
tokenName: string,
tokenTicker: string,

View File

@@ -1,7 +1,7 @@
import { SolanaAgentKit } from './agent'; // Move the SolanaAgentKit class to src/agent.ts
import { createSolanaTools } from './langchain';
import { SolanaAgent } from "./agent";
import { createSolanaTools } from "./langchain";
export { SolanaAgentKit, createSolanaTools };
export { SolanaAgent, createSolanaTools };
// Optional: Export types that users might need
export * from './types';
export * from "./types";

View File

@@ -1,9 +1,8 @@
import { PublicKey } from "@solana/web3.js";
import Decimal from "decimal.js";
import { Tool } from "langchain/tools";
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
import { create_image } from "../tools/create_image";
import { fetchPrice } from "../tools/fetch_price";
import { BN } from "@coral-xyz/anchor";
import { FEE_TIERS } from "../tools";
import { toJSON } from "../utils/toJSON";
@@ -18,14 +17,14 @@ export class SolanaBalanceTool extends Tool {
Inputs:
tokenAddress: string, eg "So11111111111111111111111111111111111111112" (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const tokenAddress = input ? new PublicKey(input) : undefined;
const balance = await this.solanaKit.getBalance(tokenAddress);
const balance = await this.solanaAgent.getBalance(tokenAddress);
return JSON.stringify({
status: "success",
@@ -51,7 +50,7 @@ export class SolanaTransferTool extends Tool {
amount: number, eg 1 (required)
mint?: string, eg "So11111111111111111111111111111111111111112" or "SENDdRQtYMWaQrBroBrJ2Q53fgVuq95CV9UPGEvpCxa" (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -64,10 +63,10 @@ export class SolanaTransferTool extends Tool {
? new PublicKey(parsedInput.mint)
: undefined;
const tx = await this.solanaKit.transfer(
const tx = await this.solanaAgent.transfer(
recipient,
parsedInput.amount,
mintAddress
mintAddress,
);
return JSON.stringify({
@@ -94,12 +93,12 @@ export class SolanaDeployTokenTool extends Tool {
Inputs (input is a JSON string):
name: string, eg "My Token" (required)
uri: string, eg "https://example.com/token.json" (required)
uri: string, eg "https://example.com/token.json" (required)
symbol: string, eg "MTK" (required)
decimals?: number, eg 9 (optional, defaults to 9)
initialSupply?: number, eg 1000000 (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -107,12 +106,12 @@ export class SolanaDeployTokenTool extends Tool {
try {
const parsedInput = JSON.parse(input);
const result = await this.solanaKit.deployToken(
const result = await this.solanaAgent.deployToken(
parsedInput.name,
parsedInput.uri,
parsedInput.symbol,
parsedInput.decimals,
parsedInput.initialSupply
parsedInput.initialSupply,
);
return JSON.stringify({
@@ -140,7 +139,7 @@ export class SolanaDeployCollectionTool extends Tool {
uri: string, eg "https://example.com/collection.json" (required)
royaltyBasisPoints?: number, eg 500 for 5% (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -148,7 +147,7 @@ export class SolanaDeployCollectionTool extends Tool {
try {
const parsedInput = JSON.parse(input);
const result = await this.solanaKit.deployCollection(parsedInput);
const result = await this.solanaAgent.deployCollection(parsedInput);
return JSON.stringify({
status: "success",
@@ -174,9 +173,9 @@ export class SolanaMintNFTTool extends Tool {
collectionMint: string, eg "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w" (required) - The address of the collection to mint into
name: string, eg "My NFT" (required)
uri: string, eg "https://example.com/nft.json" (required)
recipient?: string, eg "9aUn5swQzUTRanaaTwmszxiv89cvFwUCjEBv1vZCoT1u" (optional) - The wallet to receive the NFT, defaults to agent's wallet which is ${this.solanaKit.wallet_address.toString()}`;
recipient?: string, eg "9aUn5swQzUTRanaaTwmszxiv89cvFwUCjEBv1vZCoT1u" (optional) - The wallet to receive the NFT, defaults to agent's wallet which is ${this.solanaAgent.wallet_address.toString()}`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -184,7 +183,7 @@ export class SolanaMintNFTTool extends Tool {
try {
const parsedInput = JSON.parse(input);
const result = await this.solanaKit.mintNFT(
const result = await this.solanaAgent.mintNFT(
new PublicKey(parsedInput.collectionMint),
{
name: parsedInput.name,
@@ -192,7 +191,7 @@ export class SolanaMintNFTTool extends Tool {
},
parsedInput.recipient
? new PublicKey(parsedInput.recipient)
: this.solanaKit.wallet_address
: this.solanaAgent.wallet_address,
);
return JSON.stringify({
@@ -226,7 +225,7 @@ export class SolanaTradeTool extends Tool {
inputMint?: string, eg "So11111111111111111111111111111111111111112" (optional)
slippageBps?: number, eg 100 (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -234,13 +233,13 @@ export class SolanaTradeTool extends Tool {
try {
const parsedInput = JSON.parse(input);
const tx = await this.solanaKit.trade(
const tx = await this.solanaAgent.trade(
new PublicKey(parsedInput.outputMint),
parsedInput.inputAmount,
parsedInput.inputMint
? new PublicKey(parsedInput.inputMint)
: new PublicKey("So11111111111111111111111111111111111111112"),
parsedInput.slippageBps
parsedInput.slippageBps,
);
return JSON.stringify({
@@ -265,18 +264,18 @@ export class SolanaRequestFundsTool extends Tool {
name = "solana_request_funds";
description = "Request SOL from Solana faucet (devnet/testnet only)";
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
protected async _call(_input: string): Promise<string> {
try {
await this.solanaKit.requestFaucetFunds();
await this.solanaAgent.requestFaucetFunds();
return JSON.stringify({
status: "success",
message: "Successfully requested faucet funds",
network: this.solanaKit.connection.rpcEndpoint.split("/")[2],
network: this.solanaAgent.connection.rpcEndpoint.split("/")[2],
});
} catch (error: any) {
return JSON.stringify({
@@ -297,7 +296,7 @@ export class SolanaRegisterDomainTool extends Tool {
spaceKB: number, eg 1 (optional, default is 1)
`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -318,9 +317,9 @@ export class SolanaRegisterDomainTool extends Tool {
const parsedInput = toJSON(input);
this.validateInput(parsedInput);
const tx = await this.solanaKit.registerDomain(
const tx = await this.solanaAgent.registerDomain(
parsedInput.name,
parsedInput.spaceKB || 1
parsedInput.spaceKB || 1,
);
return JSON.stringify({
@@ -348,14 +347,14 @@ export class SolanaResolveDomainTool extends Tool {
domain: string, eg "pumpfun.sol" or "pumpfun"(required)
`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const domain = input.trim();
const publicKey = await this.solanaKit.resolveSolDomain(domain);
const publicKey = await this.solanaAgent.resolveSolDomain(domain);
return JSON.stringify({
status: "success",
@@ -380,14 +379,14 @@ export class SolanaGetDomainTool extends Tool {
account: string, eg "4Be9CvxqHW6BYiRAxW9Q3xu1ycTMWaL5z8NX4HR3ha7t" (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const account = new PublicKey(input.trim());
const domain = await this.solanaKit.getPrimaryDomain(account);
const domain = await this.solanaAgent.getPrimaryDomain(account);
return JSON.stringify({
status: "success",
@@ -408,12 +407,12 @@ export class SolanaGetWalletAddressTool extends Tool {
name = "solana_get_wallet_address";
description = `Get the wallet address of the agent`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
async _call(_input: string): Promise<string> {
return this.solanaKit.wallet_address.toString();
return this.solanaAgent.wallet_address.toString();
}
}
@@ -431,7 +430,7 @@ export class SolanaPumpfunTokenLaunchTool extends Tool {
description: string, eg "PumpFun Token is a token on the Solana blockchain",
imageUrl: string, eg "https://i.imgur.com/UFm07Np_d.png`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -465,7 +464,7 @@ export class SolanaPumpfunTokenLaunchTool extends Tool {
this.validateInput(parsedInput);
// Launch token with validated input
await this.solanaKit.launchPumpFunToken(
await this.solanaAgent.launchPumpFunToken(
parsedInput.tokenName,
parsedInput.tokenTicker,
parsedInput.description,
@@ -475,7 +474,7 @@ export class SolanaPumpfunTokenLaunchTool extends Tool {
telegram: parsedInput.telegram,
website: parsedInput.website,
initialLiquiditySOL: parsedInput.initialLiquiditySOL,
}
},
);
return JSON.stringify({
@@ -499,7 +498,7 @@ export class SolanaCreateImageTool extends Tool {
description =
"Create an image using OpenAI's DALL-E. Input should be a string prompt for the image.";
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -512,7 +511,7 @@ export class SolanaCreateImageTool extends Tool {
protected async _call(input: string): Promise<string> {
try {
this.validateInput(input);
const result = await create_image(this.solanaKit, input.trim());
const result = await create_image(this.solanaAgent, input.trim());
return JSON.stringify({
status: "success",
@@ -536,7 +535,7 @@ export class SolanaLendAssetTool extends Tool {
Inputs (input is a json string):
amount: number, eg 1, 0.01 (required)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -544,7 +543,7 @@ export class SolanaLendAssetTool extends Tool {
try {
let amount = JSON.parse(input).amount || input;
const tx = await this.solanaKit.lendAssets(amount);
const tx = await this.solanaAgent.lendAssets(amount);
return JSON.stringify({
status: "success",
@@ -566,13 +565,13 @@ export class SolanaTPSCalculatorTool extends Tool {
name = "solana_get_tps";
description = "Get the current TPS of the Solana network";
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
async _call(_input: string): Promise<string> {
try {
const tps = await this.solanaKit.getTPS();
const tps = await this.solanaAgent.getTPS();
return `Solana (mainnet-beta) current transactions per second: ${tps}`;
} catch (error: any) {
return `Error fetching TPS: ${error.message}`;
@@ -587,7 +586,7 @@ export class SolanaStakeTool extends Tool {
Inputs ( input is a JSON string ):
amount: number, eg 1 or 0.01 (required)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -595,7 +594,7 @@ export class SolanaStakeTool extends Tool {
try {
const parsedInput = JSON.parse(input) || Number(input);
const tx = await this.solanaKit.stake(parsedInput.amount);
const tx = await this.solanaAgent.stake(parsedInput.amount);
return JSON.stringify({
status: "success",
@@ -619,17 +618,17 @@ export class SolanaStakeTool extends Tool {
export class SolanaFetchPriceTool extends Tool {
name = "solana_fetch_price";
description = `Fetch the price of a given token in USDC.
Inputs:
- tokenId: string, the mint address of the token, e.g., "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
async _call(input: string): Promise<string> {
try {
const price = await fetchPrice(this.solanaKit, input.trim());
const price = await this.solanaAgent.fetchTokenPrice(input.trim());
return JSON.stringify({
status: "success",
tokenId: input.trim(),
@@ -652,7 +651,7 @@ export class SolanaTokenDataTool extends Tool {
Inputs: mintAddress is required.
mintAddress: string, eg "So11111111111111111111111111111111111111112" (required)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -660,7 +659,8 @@ export class SolanaTokenDataTool extends Tool {
try {
const parsedInput = input.trim();
const tokenData = await this.solanaKit.getTokenDataByAddress(parsedInput);
const tokenData =
await this.solanaAgent.getTokenDataByAddress(parsedInput);
return JSON.stringify({
status: "success",
@@ -683,14 +683,14 @@ export class SolanaTokenDataByTickerTool extends Tool {
Inputs: ticker is required.
ticker: string, eg "USDC" (required)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const ticker = input.trim();
const tokenData = await this.solanaKit.getTokenDataByTicker(ticker);
const tokenData = await this.solanaAgent.getTokenDataByTicker(ticker);
return JSON.stringify({
status: "success",
tokenData: tokenData,
@@ -708,7 +708,7 @@ export class SolanaTokenDataByTickerTool extends Tool {
export class SolanaCompressedAirdropTool extends Tool {
name = "solana_compressed_airdrop";
description = `Airdrop SPL tokens with ZK Compression (also called as airdropping tokens)
Inputs (input is a JSON string):
mintAddress: string, the mint address of the token, e.g., "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN" (required)
amount: number, the amount of tokens to airdrop per recipient, e.g., 42 (required)
@@ -717,7 +717,7 @@ export class SolanaCompressedAirdropTool extends Tool {
priorityFeeInLamports: number, the priority fee in lamports. Default is 30_000. (optional)
shouldLog: boolean, whether to log progress to stdout. Default is false. (optional)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -725,13 +725,13 @@ export class SolanaCompressedAirdropTool extends Tool {
try {
const parsedInput = JSON.parse(input);
const txs = await this.solanaKit.sendCompressedAirdrop(
const txs = await this.solanaAgent.sendCompressedAirdrop(
parsedInput.mintAddress,
parsedInput.amount,
parsedInput.decimals,
parsedInput.recipients,
parsedInput.priorityFeeInLamports || 30_000,
parsedInput.shouldLog || false
parsedInput.shouldLog || false,
);
return JSON.stringify({
@@ -761,7 +761,7 @@ export class SolanaCreateSingleSidedWhirlpoolTool extends Tool {
- maxPrice: number, eg: 5.0 (required, maximum price at which liquidity is added)
- feeTier: number, eg: 0.30 (required, fee tier for the pool)`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
@@ -776,10 +776,12 @@ export class SolanaCreateSingleSidedWhirlpoolTool extends Tool {
const feeTier = inputFormat.feeTier;
if (!feeTier || !(feeTier in FEE_TIERS)) {
throw new Error(`Invalid feeTier. Available options: ${Object.keys(FEE_TIERS).join(", ")}`);
throw new Error(
`Invalid feeTier. Available options: ${Object.keys(FEE_TIERS).join(", ")}`,
);
}
const txId = await this.solanaKit.createOrcaSingleSidedWhirlpool(
const txId = await this.solanaAgent.createOrcaSingleSidedWhirlpool(
depositTokenAmount,
depositTokenMint,
otherTokenMint,
@@ -803,7 +805,6 @@ export class SolanaCreateSingleSidedWhirlpoolTool extends Tool {
}
}
export class SolanaRaydiumCreateAmmV4 extends Tool {
name = "raydium_create_ammV4";
description = `Raydium's Legacy AMM that requiers an OpenBook marketID
@@ -815,15 +816,15 @@ export class SolanaRaydiumCreateAmmV4 extends Tool {
startTime: number(seconds), eg: now number or zero (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
async _call(input: string): Promise<string> {
try {
let inputFormat = JSON.parse(input)
let inputFormat = JSON.parse(input);
const tx = await this.solanaKit.raydiumCreateAmmV4(
const tx = await this.solanaAgent.raydiumCreateAmmV4(
new PublicKey(inputFormat.marketId),
new BN(inputFormat.baseAmount),
new BN(inputFormat.quoteAmount),
@@ -857,15 +858,15 @@ export class SolanaRaydiumCreateClmm extends Tool {
startTime: number(seconds), eg: now number or zero (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
async _call(input: string): Promise<string> {
try {
let inputFormat = JSON.parse(input)
let inputFormat = JSON.parse(input);
const tx = await this.solanaKit.raydiumCreateClmm(
const tx = await this.solanaAgent.raydiumCreateClmm(
new PublicKey(inputFormat.mint1),
new PublicKey(inputFormat.mint2),
@@ -892,7 +893,7 @@ export class SolanaRaydiumCreateClmm extends Tool {
export class SolanaRaydiumCreateCpmm extends Tool {
name = "raydium_create_cpmm";
description = `Raydium's newest CPMM, does not require marketID, supports Token 2022 standard
description = `Raydium's newest CPMM, does not require marketID, supports Token 2022 standard
Inputs (input is a json string):
mint1: string (required)
@@ -903,15 +904,15 @@ export class SolanaRaydiumCreateCpmm extends Tool {
startTime: number(seconds), eg: now number or zero (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
async _call(input: string): Promise<string> {
try {
let inputFormat = JSON.parse(input)
let inputFormat = JSON.parse(input);
const tx = await this.solanaKit.raydiumCreateCpmm(
const tx = await this.solanaAgent.raydiumCreateCpmm(
new PublicKey(inputFormat.mint1),
new PublicKey(inputFormat.mint2),
@@ -940,7 +941,7 @@ export class SolanaRaydiumCreateCpmm extends Tool {
export class SolanaOpenbookCreateMarket extends Tool {
name = "solana_openbook_create_market";
description = `Openbook marketId, required for ammv4
description = `Openbook marketId, required for ammv4
Inputs (input is a json string):
baseMint: string (required)
@@ -949,15 +950,15 @@ export class SolanaOpenbookCreateMarket extends Tool {
tickSize: number (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
constructor(private solanaAgent: SolanaAgent) {
super();
}
async _call(input: string): Promise<string> {
try {
let inputFormat = JSON.parse(input)
let inputFormat = JSON.parse(input);
const tx = await this.solanaKit.openbookCreateMarket(
const tx = await this.solanaAgent.openbookCreateMarket(
new PublicKey(inputFormat.baseMint),
new PublicKey(inputFormat.quoteMint),
@@ -980,32 +981,32 @@ export class SolanaOpenbookCreateMarket extends Tool {
}
}
export function createSolanaTools(solanaKit: SolanaAgentKit) {
export function createSolanaTools(solanaAgent: SolanaAgent) {
return [
new SolanaBalanceTool(solanaKit),
new SolanaTransferTool(solanaKit),
new SolanaDeployTokenTool(solanaKit),
new SolanaDeployCollectionTool(solanaKit),
new SolanaMintNFTTool(solanaKit),
new SolanaTradeTool(solanaKit),
new SolanaRequestFundsTool(solanaKit),
new SolanaRegisterDomainTool(solanaKit),
new SolanaGetWalletAddressTool(solanaKit),
new SolanaPumpfunTokenLaunchTool(solanaKit),
new SolanaCreateImageTool(solanaKit),
new SolanaLendAssetTool(solanaKit),
new SolanaTPSCalculatorTool(solanaKit),
new SolanaStakeTool(solanaKit),
new SolanaFetchPriceTool(solanaKit),
new SolanaResolveDomainTool(solanaKit),
new SolanaGetDomainTool(solanaKit),
new SolanaTokenDataTool(solanaKit),
new SolanaTokenDataByTickerTool(solanaKit),
new SolanaCompressedAirdropTool(solanaKit),
new SolanaRaydiumCreateAmmV4(solanaKit),
new SolanaRaydiumCreateClmm(solanaKit),
new SolanaRaydiumCreateCpmm(solanaKit),
new SolanaOpenbookCreateMarket(solanaKit),
new SolanaCreateSingleSidedWhirlpoolTool(solanaKit),
new SolanaBalanceTool(solanaAgent),
new SolanaTransferTool(solanaAgent),
new SolanaDeployTokenTool(solanaAgent),
new SolanaDeployCollectionTool(solanaAgent),
new SolanaMintNFTTool(solanaAgent),
new SolanaTradeTool(solanaAgent),
new SolanaRequestFundsTool(solanaAgent),
new SolanaRegisterDomainTool(solanaAgent),
new SolanaGetWalletAddressTool(solanaAgent),
new SolanaPumpfunTokenLaunchTool(solanaAgent),
new SolanaCreateImageTool(solanaAgent),
new SolanaLendAssetTool(solanaAgent),
new SolanaTPSCalculatorTool(solanaAgent),
new SolanaStakeTool(solanaAgent),
new SolanaFetchPriceTool(solanaAgent),
new SolanaResolveDomainTool(solanaAgent),
new SolanaGetDomainTool(solanaAgent),
new SolanaTokenDataTool(solanaAgent),
new SolanaTokenDataByTickerTool(solanaAgent),
new SolanaCompressedAirdropTool(solanaAgent),
new SolanaRaydiumCreateAmmV4(solanaAgent),
new SolanaRaydiumCreateClmm(solanaAgent),
new SolanaRaydiumCreateCpmm(solanaAgent),
new SolanaOpenbookCreateMarket(solanaAgent),
new SolanaCreateSingleSidedWhirlpoolTool(solanaAgent),
];
}

View File

@@ -1,16 +1,16 @@
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
import OpenAI from "openai";
/**
* Generate an image using OpenAI's DALL-E
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param prompt Text description of the image to generate
* @param size Image size ('256x256', '512x512', or '1024x1024') (default: '1024x1024')
* @param n Number of images to generate (default: 1)
* @returns Object containing the generated image URLs
*/
export async function create_image(
agent: SolanaAgentKit,
agent: SolanaAgent,
prompt: string,
size: "256x256" | "512x512" | "1024x1024" = "1024x1024",
n: number = 1,

View File

@@ -1,5 +1,5 @@
import { Keypair, PublicKey, Transaction } from "@solana/web3.js";
import { SolanaAgentKit } from "../agent";
import { SolanaAgent } from "../index";
import { BN, Wallet } from "@coral-xyz/anchor";
import { Decimal } from "decimal.js";
import {
@@ -40,7 +40,7 @@ import { sendTx } from "../utils/send_tx";
* @remarks
* Fee tiers determine the percentage of fees collected on swaps, while tick spacing affects
* the granularity of price ranges for liquidity positions.
*
*
* For more details, refer to:
* - [Whirlpool Fees](https://orca-so.github.io/whirlpools/Architecture%20Overview/Whirlpool%20Fees)
* - [Whirlpool Parameters](https://orca-so.github.io/whirlpools/Architecture%20Overview/Whirlpool%20Parameters)
@@ -54,17 +54,17 @@ export const FEE_TIERS = {
0.04: 4,
0.05: 8,
0.16: 16,
0.30: 64,
0.3: 64,
0.65: 96,
1.00: 128,
2.00: 256,
1.0: 128,
2.0: 256,
} as const;
/**
* # Creates a single-sided Whirlpool.
*
* This function initializes a new Whirlpool (liquidity pool) on Orca and seeds it with liquidity from a single token.
*
*
* ## Example Usage:
* You created a new token called SHARK, and you want to set the initial price to 0.001 USDC.
* You set `depositTokenMint` to SHARK's mint address and `otherTokenMint` to USDC's mint address.
@@ -72,7 +72,7 @@ export const FEE_TIERS = {
* 1. Increase the amount of tokens you deposit
* 2. Set the initial price very low
* 3. Set the maximum price closer to the initial price
*
*
* ### Note for experts:
* The Wrhirlpool program initializes the Whirlpool with the in a specific order. This might not be
* the order you expect, so the function checks the order and adjusts the inverts the prices. This means that
@@ -86,13 +86,13 @@ export const FEE_TIERS = {
* @param initialPrice - The initial price of the deposit token in terms of the other token.
* @param maxPrice - The maximum price at which liquidity is added.
* @param feeTier - The fee tier percentage for the pool, determining tick spacing and fee collection rates.
*
*
* @returns A promise that resolves to a transaction ID (`string`) of the transaction creating the pool.
*
*
* @throws Will throw an error if:
* - Mint accounts for the tokens cannot be fetched.
* - Prices are out of bounds.
*
*
* @remarks
* This function is designed for single-sided deposits where users only contribute one type of token,
* and the function manages mint order and necessary calculations.
@@ -103,7 +103,7 @@ export const FEE_TIERS = {
* import { PublicKey } from "@solana/web3.js";
* import { BN } from "@coral-xyz/anchor";
* import Decimal from "decimal.js";
*
*
* const agent = new SolanaAgentKit(wallet, connection);
* const depositAmount = new BN(1_000_000_000_000); // 1 million SHARK if SHARK has 6 decimals
* const depositTokenMint = new PublicKey("DEPOSTI_TOKEN_ADDRESS");
@@ -111,7 +111,7 @@ export const FEE_TIERS = {
* const initialPrice = new Decimal(0.001);
* const maxPrice = new Decimal(5.0);
* const feeTier = 0.30;
*
*
* const txId = await createOrcaSingleSidedWhirlpool(
* agent,
* depositAmount,
@@ -125,7 +125,7 @@ export const FEE_TIERS = {
* ```
*/
export async function createOrcaSingleSidedWhirlpool(
agent: SolanaAgentKit,
agent: SolanaAgent,
depositTokenAmount: BN,
depositTokenMint: PublicKey,
otherTokenMint: PublicKey,
@@ -134,13 +134,19 @@ export async function createOrcaSingleSidedWhirlpool(
feeTier: keyof typeof FEE_TIERS,
): Promise<string> {
const wallet = new Wallet(agent.wallet);
const ctx = WhirlpoolContext.from(agent.connection, wallet, ORCA_WHIRLPOOL_PROGRAM_ID);
const ctx = WhirlpoolContext.from(
agent.connection,
wallet,
ORCA_WHIRLPOOL_PROGRAM_ID,
);
const fetcher = ctx.fetcher;
const correctTokenOrder = PoolUtil.orderMints(otherTokenMint, depositTokenMint).map(
(addr) => addr.toString(),
);
const isCorrectMintOrder = correctTokenOrder[0] === depositTokenMint.toString();
const correctTokenOrder = PoolUtil.orderMints(
otherTokenMint,
depositTokenMint,
).map((addr) => addr.toString());
const isCorrectMintOrder =
correctTokenOrder[0] === depositTokenMint.toString();
let mintA, mintB;
if (isCorrectMintOrder) {
[mintA, mintB] = [depositTokenMint, otherTokenMint];
@@ -151,10 +157,18 @@ export async function createOrcaSingleSidedWhirlpool(
}
const mintAAccount = await fetcher.getMintInfo(mintA);
const mintBAccount = await fetcher.getMintInfo(mintB);
if (mintAAccount === null || mintBAccount === null) throw Error('Mint account not found');
if (mintAAccount === null || mintBAccount === null)
throw Error("Mint account not found");
const tickSpacing = FEE_TIERS[feeTier];
const tickIndex = PriceMath.priceToTickIndex(initialPrice, mintAAccount.decimals, mintBAccount.decimals);
const initialTick = TickUtil.getInitializableTickIndex(tickIndex, tickSpacing);
const tickIndex = PriceMath.priceToTickIndex(
initialPrice,
mintAAccount.decimals,
mintBAccount.decimals,
);
const initialTick = TickUtil.getInitializableTickIndex(
tickIndex,
tickSpacing,
);
const tokenExtensionCtx: TokenExtensionContextForPool = {
...NO_TOKEN_EXTENSION_CONTEXT,
@@ -196,17 +210,17 @@ export async function createOrcaSingleSidedWhirlpool(
tokenVaultBKeypair,
feeTierKey,
tickSpacing: tickSpacing,
funder: wallet.publicKey
funder: wallet.publicKey,
};
const initPoolIx = !TokenExtensionUtil.isV2IxRequiredPool(tokenExtensionCtx)
? WhirlpoolIx.initializePoolIx(ctx.program, baseParamsPool)
: WhirlpoolIx.initializePoolV2Ix(ctx.program, {
...baseParamsPool,
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
tokenBadgeA,
tokenBadgeB,
});
...baseParamsPool,
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
tokenBadgeA,
tokenBadgeB,
});
const initialTickArrayStartTick = TickUtil.getStartTickIndex(
initialTick,
tickSpacing,
@@ -235,14 +249,32 @@ export async function createOrcaSingleSidedWhirlpool(
let tickLowerIndex, tickUpperIndex;
if (isCorrectMintOrder) {
tickLowerIndex = initialTick;
tickUpperIndex = PriceMath.priceToTickIndex(maxPrice, mintAAccount.decimals, mintBAccount.decimals);
tickUpperIndex = PriceMath.priceToTickIndex(
maxPrice,
mintAAccount.decimals,
mintBAccount.decimals,
);
} else {
tickLowerIndex = PriceMath.priceToTickIndex(maxPrice, mintAAccount.decimals, mintBAccount.decimals);
tickLowerIndex = PriceMath.priceToTickIndex(
maxPrice,
mintAAccount.decimals,
mintBAccount.decimals,
);
tickUpperIndex = initialTick;
}
const tickLowerInitializableIndex = TickUtil.getInitializableTickIndex(tickLowerIndex, tickSpacing);
const tickUpperInitializableIndex = TickUtil.getInitializableTickIndex(tickUpperIndex, tickSpacing);
if (!TickUtil.checkTickInBounds(tickLowerInitializableIndex) || !TickUtil.checkTickInBounds(tickUpperInitializableIndex)) throw Error('Prices out of bounds');
const tickLowerInitializableIndex = TickUtil.getInitializableTickIndex(
tickLowerIndex,
tickSpacing,
);
const tickUpperInitializableIndex = TickUtil.getInitializableTickIndex(
tickUpperIndex,
tickSpacing,
);
if (
!TickUtil.checkTickInBounds(tickLowerInitializableIndex) ||
!TickUtil.checkTickInBounds(tickUpperInitializableIndex)
)
throw Error("Prices out of bounds");
const increasLiquidityQuoteParam: IncreaseLiquidityQuoteParam = {
inputTokenAmount: new BN(depositTokenAmount),
inputTokenMint: depositTokenMint,
@@ -253,11 +285,11 @@ export async function createOrcaSingleSidedWhirlpool(
tickLowerIndex: tickLowerInitializableIndex,
tickUpperIndex: tickUpperInitializableIndex,
tokenExtensionCtx: tokenExtensionCtx,
slippageTolerance: Percentage.fromFraction(0, 100)
}
slippageTolerance: Percentage.fromFraction(0, 100),
};
const liquidityInput = increaseLiquidityQuoteByInputTokenWithParams(
increasLiquidityQuoteParam
)
increasLiquidityQuoteParam,
);
const { liquidityAmount: liquidity, tokenMaxA, tokenMaxB } = liquidityInput;
const positionMintKeypair = Keypair.generate();
@@ -285,7 +317,7 @@ export async function createOrcaSingleSidedWhirlpool(
...params,
positionMint: positionMintPubkey,
withTokenMetadataExtension: true,
})
});
txBuilder.addInstruction(positionIx);
txBuilder.addSigner(positionMintKeypair);
@@ -365,35 +397,33 @@ export async function createOrcaSingleSidedWhirlpool(
tickArrayUpper: tickArrayUpperPda.publicKey,
};
const liquidityIx = !TokenExtensionUtil.isV2IxRequiredPool(
tokenExtensionCtx,
)
const liquidityIx = !TokenExtensionUtil.isV2IxRequiredPool(tokenExtensionCtx)
? increaseLiquidityIx(ctx.program, baseParamsLiquidity)
: increaseLiquidityV2Ix(ctx.program, {
...baseParamsLiquidity,
tokenMintA: mintA,
tokenMintB: mintB,
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
});
...baseParamsLiquidity,
tokenMintA: mintA,
tokenMintB: mintB,
tokenProgramA: tokenExtensionCtx.tokenMintWithProgramA.tokenProgram,
tokenProgramB: tokenExtensionCtx.tokenMintWithProgramB.tokenProgram,
});
txBuilder.addInstruction(liquidityIx);
const txPayload = await txBuilder.build({
maxSupportedTransactionVersion: "legacy"
maxSupportedTransactionVersion: "legacy",
});
if (txPayload.transaction instanceof Transaction) {
try {
const txId = await sendTx(
agent,
txPayload.transaction,
[positionMintKeypair, tokenVaultAKeypair, tokenVaultBKeypair],
);
const txId = await sendTx(agent, txPayload.transaction, [
positionMintKeypair,
tokenVaultAKeypair,
tokenVaultBKeypair,
]);
return txId;
} catch (error) {
throw new Error(`Failed to create pool: ${JSON.stringify(error)}`);
throw new Error(`Failed to create pool: ${JSON.stringify(error)}`);
}
} else {
throw new Error('Failed to create pool: Transaction not created');
throw new Error("Failed to create pool: Transaction not created");
}
}

View File

@@ -1,18 +1,29 @@
import { SolanaAgentKit } from "../index";
import { generateSigner, keypairIdentity, publicKey } from "@metaplex-foundation/umi";
import { createCollection, mplCore, ruleSet } from "@metaplex-foundation/mpl-core";
import { SolanaAgent } from "../index";
import {
generateSigner,
keypairIdentity,
publicKey,
} from "@metaplex-foundation/umi";
import {
createCollection,
mplCore,
ruleSet,
} from "@metaplex-foundation/mpl-core";
import { CollectionOptions, CollectionDeployment } from "../types";
import { fromWeb3JsKeypair, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
import {
fromWeb3JsKeypair,
toWeb3JsPublicKey,
} from "@metaplex-foundation/umi-web3js-adapters";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
/**
* Deploy a new NFT collection
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param options Collection options including name, URI, royalties, and creators
* @returns Object containing collection address and metadata
*/
export async function deploy_collection(
agent: SolanaAgentKit,
agent: SolanaAgent,
options: CollectionOptions,
): Promise<CollectionDeployment> {
try {
@@ -28,11 +39,11 @@ export async function deploy_collection(
address: publicKey(creator.address),
percentage: creator.percentage,
})) || [
{
address: publicKey(agent.wallet_address.toString()),
percentage: 100,
},
];
{
address: publicKey(agent.wallet_address.toString()),
percentage: 100,
},
];
// Create collection
const tx = await createCollection(umi, {

View File

@@ -1,13 +1,21 @@
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
import { PublicKey } from "@solana/web3.js";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { generateSigner, keypairIdentity } from "@metaplex-foundation/umi";
import { createFungible, mintV1, TokenStandard } from "@metaplex-foundation/mpl-token-metadata";
import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
import {
createFungible,
mintV1,
TokenStandard,
} from "@metaplex-foundation/mpl-token-metadata";
import {
fromWeb3JsKeypair,
fromWeb3JsPublicKey,
toWeb3JsPublicKey,
} from "@metaplex-foundation/umi-web3js-adapters";
/**
* Deploy a new SPL token
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param name Name of the token
* @param uri URI for the token metadata
* @param symbol Symbol of the token
@@ -16,16 +24,16 @@ import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@meta
* @returns Object containing token mint address and initial account (if supply was minted)
*/
export async function deploy_token(
agent: SolanaAgentKit,
agent: SolanaAgent,
name: string,
uri: string,
symbol: string,
decimals: number = 9,
initialSupply?: number
initialSupply?: number,
): Promise<{ mint: PublicKey }> {
try {
// Create UMI instance from agent
const umi = createUmi(agent.connection.rpcEndpoint)
const umi = createUmi(agent.connection.rpcEndpoint);
umi.use(keypairIdentity(fromWeb3JsKeypair(agent.wallet)));
// Create new token mint
@@ -51,11 +59,11 @@ export async function deploy_token(
tokenStandard: TokenStandard.Fungible,
tokenOwner: fromWeb3JsPublicKey(agent.wallet_address),
amount: initialSupply,
})
}),
);
}
builder.sendAndConfirm(umi, { confirm: { commitment: 'finalized' } });
builder.sendAndConfirm(umi, { confirm: { commitment: "finalized" } });
return {
mint: toWeb3JsPublicKey(mint.publicKey),

View File

@@ -1,20 +1,13 @@
import { SolanaAgentKit } from "../index";
import { Tool } from "langchain/tools";
import { PublicKey } from "@solana/web3.js";
/**
* Fetch the price of a given token in USDC using Jupiter API
* @param agent SolanaAgentKit instance
* Fetch the price of a given token quoted in USDC using Jupiter API
* @param tokenId The token mint address
* @returns The price of the token in USDC
* @returns The price of the token quoted in USDC
*/
export async function fetchPrice(
agent: SolanaAgentKit,
tokenId: string
): Promise<string> {
export async function fetchPrice(tokenId: PublicKey): Promise<string> {
try {
const response = await fetch(
`https://api.jup.ag/price/v2?ids=${tokenId}`
);
const response = await fetch(`https://api.jup.ag/price/v2?ids=${tokenId}`);
if (!response.ok) {
throw new Error(`Failed to fetch price: ${response.statusText}`);
@@ -22,7 +15,7 @@ export async function fetchPrice(
const data = await response.json();
const price = data.data[tokenId]?.price;
const price = data.data[tokenId.toBase58()]?.price;
if (!price) {
throw new Error("Price data not available for the given token.");
@@ -32,4 +25,4 @@ export async function fetchPrice(
} catch (error: any) {
throw new Error(`Price fetch failed: ${error.message}`);
}
}
}

View File

@@ -1,14 +1,14 @@
import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
/**
* Get the balance of SOL or an SPL token for the agent's wallet
* @param agent - SolanaAgentKit instance
* @param agent - SolanaAgent instance
* @param token_address - Optional SPL token mint address. If not provided, returns SOL balance
* @returns Promise resolving to the balance as a number (in UI units) or null if account doesn't exist
*/
export async function get_balance(
agent: SolanaAgentKit,
agent: SolanaAgent,
token_address?: PublicKey,
): Promise<number | null> {
if (!token_address)

View File

@@ -1,6 +1,6 @@
import { getPrimaryDomain as _getPrimaryDomain } from "@bonfida/spl-name-service";
import { PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
/**
* Retrieves the primary .sol domain associated with a given Solana public key.
@@ -9,29 +9,29 @@ import { SolanaAgentKit } from "../index";
* a specified Solana public key. If the primary domain is stale or an error occurs during
* the resolution, it throws an error.
*
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param account The Solana public key for which to retrieve the primary domain
* @returns A promise that resolves to the primary .sol domain as a string
* @throws Error if the domain is stale or if the domain resolution fails
*/
export async function getPrimaryDomain(
agent: SolanaAgentKit,
account: PublicKey
agent: SolanaAgent,
account: PublicKey,
): Promise<string> {
try {
const { reverse, stale } = await _getPrimaryDomain(
agent.connection,
account
account,
);
if (stale) {
throw new Error(
`Primary domain is stale for account: ${account.toBase58()}`
`Primary domain is stale for account: ${account.toBase58()}`,
);
}
return reverse;
} catch (error) {
throw new Error(
`Failed to get primary domain for account: ${account.toBase58()}`
`Failed to get primary domain for account: ${account.toBase58()}`,
);
}
}

View File

@@ -1,4 +1,4 @@
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
export async function getTPS(agent: SolanaAgentKit): Promise<number> {
const perfSamples = await agent.connection.getRecentPerformanceSamples();

View File

@@ -15,8 +15,8 @@ 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";

View File

@@ -55,7 +55,7 @@ async function uploadMetadata(
}
async function createTokenTransaction(
agent: SolanaAgentKit,
agent: SolanaAgent,
mintKeypair: Keypair,
metadataResponse: any,
options?: PumpFunTokenOptions,
@@ -140,7 +140,7 @@ async function signAndSendTransaction(
/**
* Launch a token on Pump.fun
* @param agent - SolanaAgentKit instance
* @param agent - SolanaAgent instance
* @param tokenName - Name of the token
* @param tokenTicker - Ticker of the token
* @param description - Description of the token
@@ -149,7 +149,7 @@ async function signAndSendTransaction(
* @returns - Signature of the transaction, mint address and metadata URI, if successful, else error
*/
export async function launchPumpFunToken(
agent: SolanaAgentKit,
agent: SolanaAgent,
tokenName: string,
tokenTicker: string,
description: string,

View File

@@ -1,16 +1,15 @@
import { VersionedTransaction } from "@solana/web3.js";
import { LuloAccountDetailsResponse } from "../types";
import { SolanaAgentKit } from "../agent";
import { SolanaAgent } from "../index";
/**
* Lend tokens for yields using Lulo
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param amount Amount of USDC to lend
* @returns Transaction signature
*/
export async function lendAsset(
agent: SolanaAgentKit,
amount: number
agent: SolanaAgent,
amount: number,
): Promise<string> {
try {
const response = await fetch(
@@ -23,14 +22,14 @@ export async function lendAsset(
body: JSON.stringify({
account: agent.wallet.publicKey.toBase58(),
}),
}
},
);
const data = await response.json();
// Deserialize the transaction
const luloTxn = VersionedTransaction.deserialize(
Buffer.from(data.transaction, "base64")
Buffer.from(data.transaction, "base64"),
);
// Get a recent blockhash and set it

View File

@@ -1,22 +1,26 @@
import { SolanaAgentKit } from "../index";
import { generateSigner, keypairIdentity } from '@metaplex-foundation/umi';
import { create, mplCore } from '@metaplex-foundation/mpl-core';
import { fetchCollection } from '@metaplex-foundation/mpl-core';
import { SolanaAgent } from "../index";
import { generateSigner, keypairIdentity } from "@metaplex-foundation/umi";
import { create, mplCore } from "@metaplex-foundation/mpl-core";
import { fetchCollection } from "@metaplex-foundation/mpl-core";
import { PublicKey } from "@solana/web3.js";
import { fromWeb3JsKeypair, fromWeb3JsPublicKey, toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import { MintCollectionNFTResponse } from '../types';
import {
fromWeb3JsKeypair,
fromWeb3JsPublicKey,
toWeb3JsPublicKey,
} from "@metaplex-foundation/umi-web3js-adapters";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { MintCollectionNFTResponse } from "../types";
/**
* Mint a new NFT as part of an existing collection
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param collectionMint Address of the collection's master NFT
* @param metadata NFT metadata object
* @param recipient Optional recipient address (defaults to wallet address)
* @returns Object containing NFT mint address and token account
*/
export async function mintCollectionNFT(
agent: SolanaAgentKit,
agent: SolanaAgent,
collectionMint: PublicKey,
metadata: {
name: string;
@@ -27,7 +31,7 @@ export async function mintCollectionNFT(
share: number;
}>;
},
recipient?: PublicKey
recipient?: PublicKey,
): Promise<MintCollectionNFTResponse> {
try {
// Create UMI instance from agent
@@ -49,15 +53,15 @@ export async function mintCollectionNFT(
collection: collection,
name: metadata.name,
uri: metadata.uri,
owner: fromWeb3JsPublicKey(recipient ?? agent.wallet.publicKey)
owner: fromWeb3JsPublicKey(recipient ?? agent.wallet.publicKey),
}).sendAndConfirm(umi);
return {
mint: toWeb3JsPublicKey(assetSigner.publicKey),
// Note: Token account is now handled automatically by the create instruction
metadata: toWeb3JsPublicKey(assetSigner.publicKey)
metadata: toWeb3JsPublicKey(assetSigner.publicKey),
};
} catch (error: any) {
throw new Error(`Collection NFT minting failed: ${error.message}`);
}
}
}

View File

@@ -1,33 +1,34 @@
import { OPEN_BOOK_PROGRAM, Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import {
OPEN_BOOK_PROGRAM,
Raydium,
TxVersion,
} from "@raydium-io/raydium-sdk-v2";
import { MintLayout, TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../agent";
import { SolanaAgent } from "../index";
export async function openbookCreateMarket(
agent: SolanaAgentKit,
agent: SolanaAgent,
baseMint: PublicKey,
quoteMint: PublicKey,
lotSize: number = 1,
tickSize: number = 0.01,
): Promise<string[]> {
const raydium = await Raydium.load({
owner: agent.wallet,
connection: agent.connection,
})
});
const baseMintInfo = await agent.connection.getAccountInfo(baseMint)
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint)
const baseMintInfo = await agent.connection.getAccountInfo(baseMint);
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint);
if (
baseMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58() ||
quoteMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58()
) {
throw new Error(
'openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create raydium cpmm pool instead'
)
"openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create raydium cpmm pool instead",
);
}
const { execute } = await raydium.marketV2.create({
@@ -44,9 +45,9 @@ export async function openbookCreateMarket(
dexProgramId: OPEN_BOOK_PROGRAM,
txVersion: TxVersion.V0,
})
});
const { txIds } = await execute({ sequentially: true, })
const { txIds } = await execute({ sequentially: true });
return txIds
return txIds;
}

View File

@@ -1,42 +1,59 @@
import { AMM_V4, FEE_DESTINATION_ID, MARKET_STATE_LAYOUT_V3, OPEN_BOOK_PROGRAM, Raydium, TxVersion } from "@raydium-io/raydium-sdk-v2";
import {
AMM_V4,
FEE_DESTINATION_ID,
MARKET_STATE_LAYOUT_V3,
OPEN_BOOK_PROGRAM,
Raydium,
TxVersion,
} from "@raydium-io/raydium-sdk-v2";
import { MintLayout, TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { PublicKey } from "@solana/web3.js";
import BN from 'bn.js';
import { SolanaAgentKit } from "../agent";
import BN from "bn.js";
import { SolanaAgent } from "../index";
export async function raydiumCreateAmmV4(
agent: SolanaAgentKit,
agent: SolanaAgent,
marketId: PublicKey,
baseAmount: BN,
quoteAmount: BN,
startTime: BN,
): Promise<string> {
const raydium = await Raydium.load({
owner: agent.wallet,
connection: agent.connection,
})
});
const marketBufferInfo = await agent.connection.getAccountInfo(new PublicKey(marketId))
const { baseMint, quoteMint } = MARKET_STATE_LAYOUT_V3.decode(marketBufferInfo!.data)
const marketBufferInfo = await agent.connection.getAccountInfo(
new PublicKey(marketId),
);
const { baseMint, quoteMint } = MARKET_STATE_LAYOUT_V3.decode(
marketBufferInfo!.data,
);
const baseMintInfo = await agent.connection.getAccountInfo(baseMint)
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint)
const baseMintInfo = await agent.connection.getAccountInfo(baseMint);
const quoteMintInfo = await agent.connection.getAccountInfo(quoteMint);
if (
baseMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58() ||
quoteMintInfo?.owner.toString() !== TOKEN_PROGRAM_ID.toBase58()
) {
throw new Error(
'amm pools with openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create cpmm pool instead'
)
"amm pools with openbook market only support TOKEN_PROGRAM_ID mints, if you want to create pool with token-2022, please create cpmm pool instead",
);
}
if (baseAmount.mul(quoteAmount).lte(new BN(1).mul(new BN(10 ** MintLayout.decode(baseMintInfo.data).decimals)).pow(new BN(2)))) {
throw new Error('initial liquidity too low, try adding more baseAmount/quoteAmount')
if (
baseAmount
.mul(quoteAmount)
.lte(
new BN(1)
.mul(new BN(10 ** MintLayout.decode(baseMintInfo.data).decimals))
.pow(new BN(2)),
)
) {
throw new Error(
"initial liquidity too low, try adding more baseAmount/quoteAmount",
);
}
const { execute } = await raydium.liquidity.createPoolV4({
@@ -63,9 +80,9 @@ export async function raydiumCreateAmmV4(
associatedOnly: false,
txVersion: TxVersion.V0,
feeDestinationId: FEE_DESTINATION_ID,
})
});
const { txId } = await execute({ sendAndConfirm: true })
const { txId } = await execute({ sendAndConfirm: true });
return txId
}
return txId;
}

View File

@@ -1,55 +1,58 @@
import { CLMM_PROGRAM_ID, Raydium, TxVersion } from '@raydium-io/raydium-sdk-v2'
import { MintLayout } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
import Decimal from 'decimal.js'
import { SolanaAgentKit } from '../agent'
import {
CLMM_PROGRAM_ID,
Raydium,
TxVersion,
} from "@raydium-io/raydium-sdk-v2";
import { MintLayout } from "@solana/spl-token";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import Decimal from "decimal.js";
import { SolanaAgent } from "../index";
export async function raydiumCreateClmm(
agent: SolanaAgentKit,
agent: SolanaAgent,
mint1: PublicKey,
mint2: PublicKey,
configId: PublicKey,
initialPrice: Decimal,
startTime: BN,
): Promise<string> {
const raydium = await Raydium.load({
owner: agent.wallet,
connection: agent.connection,
})
});
const [mintInfo1, mintInfo2] = await agent.connection.getMultipleAccountsInfo([mint1, mint2])
if (mintInfo1 === null || mintInfo2 === null) throw Error('fetch mint info error')
const [mintInfo1, mintInfo2] = await agent.connection.getMultipleAccountsInfo(
[mint1, mint2],
);
if (mintInfo1 === null || mintInfo2 === null)
throw Error("fetch mint info error");
const mintDecodeInfo1 = MintLayout.decode(mintInfo1.data)
const mintDecodeInfo2 = MintLayout.decode(mintInfo2.data)
const mintDecodeInfo1 = MintLayout.decode(mintInfo1.data);
const mintDecodeInfo2 = MintLayout.decode(mintInfo2.data);
const mintFormatInfo1 = {
chainId: 101,
address: mint1.toString(),
programId: mintInfo1.owner.toString(),
logoURI: '',
symbol: '',
name: '',
logoURI: "",
symbol: "",
name: "",
decimals: mintDecodeInfo1.decimals,
tags: [],
extensions: {}
}
extensions: {},
};
const mintFormatInfo2 = {
chainId: 101,
address: mint2.toString(),
programId: mintInfo2.owner.toString(),
logoURI: '',
symbol: '',
name: '',
logoURI: "",
symbol: "",
name: "",
decimals: mintDecodeInfo2.decimals,
tags: [],
extensions: {}
}
extensions: {},
};
const { execute } = await raydium.clmm.createPool({
programId: CLMM_PROGRAM_ID,
@@ -65,9 +68,9 @@ export async function raydiumCreateClmm(
// units: 600000,
// microLamports: 46591500,
// },
})
});
const { txId } = await execute({ sendAndConfirm: true })
const { txId } = await execute({ sendAndConfirm: true });
return txId
return txId;
}

View File

@@ -2,60 +2,58 @@ import {
CREATE_CPMM_POOL_FEE_ACC,
CREATE_CPMM_POOL_PROGRAM,
Raydium,
TxVersion
} from '@raydium-io/raydium-sdk-v2'
import { MintLayout } from '@solana/spl-token'
import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
import { SolanaAgentKit } from '../agent'
TxVersion,
} from "@raydium-io/raydium-sdk-v2";
import { MintLayout } from "@solana/spl-token";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import { SolanaAgent } from "../index";
export async function raydiumCreateCpmm(
agent: SolanaAgentKit,
agent: SolanaAgent,
mintA: PublicKey,
mintB: PublicKey,
configId: PublicKey,
mintAAmount: BN,
mintBAmount: BN,
startTime: BN,
): Promise<string> {
const raydium = await Raydium.load({
owner: agent.wallet,
connection: agent.connection,
})
});
const [mintInfoA, mintInfoB] = await agent.connection.getMultipleAccountsInfo([mintA, mintB])
if (mintInfoA === null || mintInfoB === null) throw Error('fetch mint info error')
const [mintInfoA, mintInfoB] = await agent.connection.getMultipleAccountsInfo(
[mintA, mintB],
);
if (mintInfoA === null || mintInfoB === null)
throw Error("fetch mint info error");
const mintDecodeInfoA = MintLayout.decode(mintInfoA.data)
const mintDecodeInfoB = MintLayout.decode(mintInfoB.data)
const mintDecodeInfoA = MintLayout.decode(mintInfoA.data);
const mintDecodeInfoB = MintLayout.decode(mintInfoB.data);
const mintFormatInfoA = {
chainId: 101,
address: mintA.toString(),
programId: mintInfoA.owner.toString(),
logoURI: '',
symbol: '',
name: '',
logoURI: "",
symbol: "",
name: "",
decimals: mintDecodeInfoA.decimals,
tags: [],
extensions: {}
}
extensions: {},
};
const mintFormatInfoB = {
chainId: 101,
address: mintB.toString(),
programId: mintInfoB.owner.toString(),
logoURI: '',
symbol: '',
name: '',
logoURI: "",
symbol: "",
name: "",
decimals: mintDecodeInfoB.decimals,
tags: [],
extensions: {}
}
extensions: {},
};
const { execute, extInfo } = await raydium.cpmm.createPool({
programId: CREATE_CPMM_POOL_PROGRAM,
@@ -76,9 +74,9 @@ export async function raydiumCreateCpmm(
// units: 600000,
// microLamports: 46591500,
// },
})
});
const { txId } = await execute({ sendAndConfirm: true })
const { txId } = await execute({ sendAndConfirm: true });
return txId
return txId;
}

View File

@@ -1,18 +1,18 @@
import { registerDomainNameV2 } from "@bonfida/spl-name-service";
import { Transaction } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
import { TOKENS } from "../constants";
/**
* Register a .sol domain name using Bonfida Name Service
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param name Domain name to register (without .sol)
* @param spaceKB Space allocation in KB (max 10KB)
* @returns Transaction signature
*/
export async function registerDomain(
agent: SolanaAgentKit,
agent: SolanaAgent,
name: string,
spaceKB: number = 1,
): Promise<string> {

View File

@@ -1,14 +1,14 @@
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
/**
* Request SOL from the Solana faucet (devnet/testnet only)
* @param agent - SolanaAgentKit instance
* @param agent - SolanaAgent instance
* @returns Transaction signature
* @throws Error if the request fails or times out
*/
export async function request_faucet_funds(
agent: SolanaAgentKit,
agent: SolanaAgent,
): Promise<string> {
const tx = await agent.connection.requestAirdrop(
agent.wallet_address,

View File

@@ -1,6 +1,6 @@
import { resolve } from "@bonfida/spl-name-service";
import { PublicKey } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { SolanaAgent } from "../index";
/**
* Resolves a .sol domain to a Solana PublicKey.
@@ -9,14 +9,14 @@ import { SolanaAgentKit } from "../index";
* to the corresponding Solana PublicKey. The domain can be provided with or without
* the .sol suffix.
*
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param domain The .sol domain to resolve. This can be provided with or without the .sol TLD suffix
* @returns A promise that resolves to the corresponding Solana PublicKey
* @throws Error if the domain resolution fails
*/
export async function resolveSolDomain(
agent: SolanaAgentKit,
domain: string
agent: SolanaAgent,
domain: string,
): Promise<PublicKey> {
if (!domain || typeof domain !== "string") {
throw new Error("Invalid domain. Expected a non-empty string.");

View File

@@ -1,12 +1,11 @@
import {
AddressLookupTableAccount,
ComputeBudgetProgram,
Connection,
Keypair,
PublicKey,
TransactionInstruction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../agent/index.js";
import { SolanaAgent } from "../index";
import {
buildAndSignTx,
calculateComputeUnitPrice,
@@ -33,7 +32,7 @@ const MAX_CONCURRENT_TXS = 30;
*/
export const getAirdropCostEstimate = (
numberOfRecipients: number,
priorityFeeInLamports: number
priorityFeeInLamports: number,
) => {
const baseFee = 5000;
const perRecipientCompressedStateFee = 300;
@@ -57,28 +56,27 @@ export const getAirdropCostEstimate = (
* @param shouldLog Whether to log progress to stdout. Defaults to false.
*/
export async function sendCompressedAirdrop(
agent: SolanaAgentKit,
agent: SolanaAgent,
mintAddress: PublicKey,
amount: number,
decimals: number,
recipients: PublicKey[],
priorityFeeInLamports: number,
shouldLog: boolean = false
shouldLog: boolean = false,
): Promise<string[]> {
if (recipients.length > MAX_AIRDROP_RECIPIENTS) {
throw new Error(
`Max airdrop can be ${MAX_AIRDROP_RECIPIENTS} recipients at a time. For more scale, use open source ZK Compression airdrop tools such as https://github.com/helius-labs/airship.`
`Max airdrop can be ${MAX_AIRDROP_RECIPIENTS} recipients at a time. For more scale, use open source ZK Compression airdrop tools such as https://github.com/helius-labs/airship.`,
);
}
const url = agent.connection.rpcEndpoint;
if (url.includes("devnet")) {
throw new Error("Devnet is not supported for airdrop. Please use mainnet.");
}
if (!url.includes("helius")) {
console.warn(
"Warning: Must use RPC with ZK Compression support. Double check with your RPC provider if in doubt."
"Warning: Must use RPC with ZK Compression support. Double check with your RPC provider if in doubt.",
);
}
@@ -88,11 +86,11 @@ export async function sendCompressedAirdrop(
agent.connection,
agent.wallet,
mintAddress,
agent.wallet.publicKey
agent.wallet.publicKey,
);
} catch (error) {
throw new Error(
"Source token account not found and failed to create it. Please add funds to your wallet and try again."
"Source token account not found and failed to create it. Please add funds to your wallet and try again.",
);
}
@@ -100,7 +98,7 @@ export async function sendCompressedAirdrop(
await createTokenPool(
agent.connection as unknown as Rpc,
agent.wallet,
mintAddress
mintAddress,
);
} catch (error: any) {
if (error.message.includes("already in use")) {
@@ -116,17 +114,17 @@ export async function sendCompressedAirdrop(
mintAddress,
recipients,
priorityFeeInLamports,
shouldLog
shouldLog,
);
}
async function processAll(
agent: SolanaAgentKit,
agent: SolanaAgent,
amount: number,
mint: PublicKey,
recipients: PublicKey[],
priorityFeeInLamports: number,
shouldLog: boolean
shouldLog: boolean,
): Promise<string[]> {
const mintAddress = mint;
const payer = agent.wallet;
@@ -135,13 +133,13 @@ async function processAll(
agent.connection,
agent.wallet,
mintAddress,
agent.wallet.publicKey
agent.wallet.publicKey,
);
const maxRecipientsPerInstruction = 5;
const maxIxs = 3; // empirically determined (as of 12/15/2024)
const lookupTableAddress = new PublicKey(
"9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ"
"9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ",
);
const lookupTableAccount = (
@@ -164,7 +162,7 @@ async function processAll(
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: calculateComputeUnitPrice(
priorityFeeInLamports,
500_000
500_000,
),
}),
];
@@ -184,13 +182,13 @@ async function processAll(
toAddress: batch,
amount: batch.map(() => amount),
mint: mintAddress,
})
}),
);
}
const compressIxs = await Promise.all(compressIxPromises);
return [...instructions, ...compressIxs];
})
}),
);
const url = agent.connection.rpcEndpoint;
@@ -225,12 +223,12 @@ async function processAll(
instructions,
payer,
lookupTableAccount,
i + idx
i + idx,
).then((signature) => {
confirmedCount++;
log("\r" + renderProgressBar(confirmedCount, totalBatches));
return signature;
})
}),
);
const batchResults = await Promise.allSettled(batchPromises);
@@ -250,7 +248,7 @@ async function processAll(
throw new Error(
`Failed to process ${failures.length} batches: ${failures
.map((f) => f.error)
.join(", ")}`
.join(", ")}`,
);
}
@@ -262,7 +260,7 @@ async function sendTransactionWithRetry(
instructions: TransactionInstruction[],
payer: Keypair,
lookupTableAccount: AddressLookupTableAccount,
batchIndex: number
batchIndex: number,
): Promise<string> {
const MAX_RETRIES = 3;
const INITIAL_BACKOFF = 500; // ms
@@ -275,7 +273,7 @@ async function sendTransactionWithRetry(
payer,
blockhash,
[],
[lookupTableAccount]
[lookupTableAccount],
);
const signature = await sendAndConfirmTx(connection, tx);
@@ -292,7 +290,7 @@ async function sendTransactionWithRetry(
throw new Error(
`Batch ${batchIndex} failed after ${attempt + 1} attempts: ${
error.message
}`
}`,
);
}

View File

@@ -1,14 +1,14 @@
import { VersionedTransaction } from "@solana/web3.js";
import { SolanaAgentKit } from "../agent";
import { SolanaAgent } from "../index";
/**
* Stake SOL with Jup validator
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param amount Amount of SOL to stake
* @returns Transaction signature
*/
export async function stakeWithJup(
agent: SolanaAgentKit,
agent: SolanaAgent,
amount: number,
): Promise<string> {
try {

View File

@@ -1,10 +1,14 @@
import { VersionedTransaction, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import {
VersionedTransaction,
PublicKey,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
import { SolanaAgent } from "../index";
import { TOKENS, DEFAULT_OPTIONS, JUP_API } from "../constants";
/**
* Swap tokens using Jupiter Exchange
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param outputMint Target token mint address
* @param inputAmount Amount to swap (in token decimals)
* @param inputMint Source token mint address (defaults to USDC)
@@ -12,7 +16,7 @@ import { TOKENS, DEFAULT_OPTIONS, JUP_API } from "../constants";
* @returns Transaction signature
*/
export async function trade(
agent: SolanaAgentKit,
agent: SolanaAgent,
outputMint: PublicKey,
inputAmount: number,
inputMint: PublicKey = TOKENS.USDC,

View File

@@ -1,29 +1,25 @@
import { SolanaAgentKit } from "../index";
import {
PublicKey,
SystemProgram,
Transaction
} from "@solana/web3.js";
import { SolanaAgent } from "../index";
import { PublicKey, SystemProgram, Transaction } from "@solana/web3.js";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
import {
getAssociatedTokenAddress,
import {
getAssociatedTokenAddress,
createTransferInstruction,
getMint
getMint,
} from "@solana/spl-token";
/**
* Transfer SOL or SPL tokens to a recipient
* @param agent SolanaAgentKit instance
* @param agent SolanaAgent instance
* @param to Recipient's public key
* @param amount Amount to transfer
* @param mint Optional mint address for SPL tokens
* @returns Transaction signature
*/
export async function transfer(
agent: SolanaAgentKit,
agent: SolanaAgent,
to: PublicKey,
amount: number,
mint?: PublicKey
mint?: PublicKey,
): Promise<string> {
try {
let tx: string;
@@ -34,19 +30,19 @@ export async function transfer(
SystemProgram.transfer({
fromPubkey: agent.wallet_address,
toPubkey: to,
lamports: amount * LAMPORTS_PER_SOL
})
lamports: amount * LAMPORTS_PER_SOL,
}),
);
tx = await agent.connection.sendTransaction(
transaction,
[agent.wallet]
);
tx = await agent.connection.sendTransaction(transaction, [agent.wallet]);
} else {
// Transfer SPL token
const fromAta = await getAssociatedTokenAddress(mint, agent.wallet_address);
const fromAta = await getAssociatedTokenAddress(
mint,
agent.wallet_address,
);
const toAta = await getAssociatedTokenAddress(mint, to);
// Get mint info to determine decimals
const mintInfo = await getMint(agent.connection, mint);
const adjustedAmount = amount * Math.pow(10, mintInfo.decimals);
@@ -56,18 +52,15 @@ export async function transfer(
fromAta,
toAta,
agent.wallet_address,
adjustedAmount
)
adjustedAmount,
),
);
tx = await agent.connection.sendTransaction(
transaction,
[agent.wallet]
);
tx = await agent.connection.sendTransaction(transaction, [agent.wallet]);
}
return tx;
} catch (error: any) {
throw new Error(`Transfer failed: ${error.message}`);
}
}
}

View File

@@ -1,4 +1,4 @@
import { SolanaAgentKit } from "../agent";
import { SolanaAgent } from "../agent";
import { Transaction, Keypair, TransactionInstruction } from "@solana/web3.js";
import { Connection, ComputeBudgetProgram } from "@solana/web3.js";
@@ -41,7 +41,7 @@ export async function getPriorityFees(connection: Connection): Promise<{
const median =
sortedFees.length % 2 === 0
? ((sortedFees[mid - 1] ?? 0) + (sortedFees[mid] ?? 0)) / 2
: sortedFees[mid] ?? 0;
: (sortedFees[mid] ?? 0);
// Helper to create priority fee IX based on chosen strategy
const createPriorityFeeIx = (fee: number) => {
@@ -69,14 +69,14 @@ export async function getPriorityFees(connection: Connection): Promise<{
/**
* Send a transaction with priority fees
* @param agent - SolanaAgentKit instance
* @param agent - SolanaAgent instance
* @param tx - Transaction to send
* @returns Transaction ID
*/
export async function sendTx(
agent: SolanaAgentKit,
agent: SolanaAgent,
tx: Transaction,
otherKeypairs?: Keypair[]
otherKeypairs?: Keypair[],
) {
tx.recentBlockhash = (await agent.connection.getLatestBlockhash()).blockhash;
tx.feePayer = agent.wallet_address;
@@ -90,9 +90,8 @@ export async function sendTx(
await agent.connection.confirmTransaction({
signature: txid,
blockhash: (await agent.connection.getLatestBlockhash()).blockhash,
lastValidBlockHeight: (
await agent.connection.getLatestBlockhash()
).lastValidBlockHeight,
lastValidBlockHeight: (await agent.connection.getLatestBlockhash())
.lastValidBlockHeight,
});
return txid;
}