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

@@ -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}`);
}
}
}