mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-18 15:10:33 +00:00
133 lines
4.5 KiB
TypeScript
133 lines
4.5 KiB
TypeScript
import {
|
|
Keypair,
|
|
PublicKey,
|
|
TransactionMessage,
|
|
VersionedTransaction,
|
|
} from "@solana/web3.js";
|
|
import { SolanaAgentKit } from "../agent";
|
|
import { Wallet } from "@coral-xyz/anchor";
|
|
import { Decimal } from "decimal.js";
|
|
import {
|
|
ORCA_WHIRLPOOL_PROGRAM_ID,
|
|
WhirlpoolContext,
|
|
PriceMath,
|
|
PoolUtil,
|
|
buildWhirlpoolClient,
|
|
} from "@orca-so/whirlpools-sdk";
|
|
import { sendTx } from "../utils/send_tx";
|
|
import { FEE_TIERS } from "./orca_create_single_sided_liquidity_pool";
|
|
|
|
/**
|
|
* # Creates a CLMM Pool (Concentrated Liquidity Market Maker Pool).
|
|
*
|
|
* This function initializes a new Whirlpool (CLMM Pool) on Orca. It only sets up the pool and does not seed it with liquidity.
|
|
*
|
|
* ## Example Usage:
|
|
* Suppose you want to create a CLMM pool with two tokens, SHARK and USDC, and set the initial price of SHARK to 0.001 USDC.
|
|
* You would call this function with `mintA` as SHARK's mint address and `mintB` as USDC's mint address. The pool is created
|
|
* with the specified fee tier and tick spacing associated with that fee tier.
|
|
*
|
|
* ### Note for Experts:
|
|
* The Whirlpool program determines the token mint order, which might not match your expectation. This function
|
|
* adjusts the input order as needed and inverts the initial price accordingly.
|
|
*
|
|
* @param agent - The `SolanaAgentKit` instance representing the wallet and connection details.
|
|
* @param mintDeploy - The mint of the token you want to deploy (e.g., SHARK).
|
|
* @param mintPair - The mint of the token you want to pair the deployed mint with (e.g., USDC).
|
|
* @param initialPrice - The initial price of `mintDeploy` in terms of `mintPair`.
|
|
* @param feeTier - The fee tier bps 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.
|
|
* - The network is unsupported.
|
|
*
|
|
* @remarks
|
|
* This function only initializes the CLMM pool and does not add liquidity. For adding liquidity, you can use
|
|
* a separate function after the pool is successfully created.
|
|
* ```
|
|
*/
|
|
export async function orcaCreateCLMM(
|
|
agent: SolanaAgentKit,
|
|
mintDeploy: PublicKey,
|
|
mintPair: PublicKey,
|
|
initialPrice: Decimal,
|
|
feeTier: keyof typeof FEE_TIERS,
|
|
): Promise<string> {
|
|
try {
|
|
let whirlpoolsConfigAddress: PublicKey;
|
|
if (agent.connection.rpcEndpoint.includes("mainnet")) {
|
|
whirlpoolsConfigAddress = new PublicKey(
|
|
"2LecshUwdy9xi7meFgHtFJQNSKk4KdTrcpvaB56dP2NQ",
|
|
);
|
|
} else if (agent.connection.rpcEndpoint.includes("devnet")) {
|
|
whirlpoolsConfigAddress = new PublicKey(
|
|
"FcrweFY1G9HJAHG5inkGB6pKg1HZ6x9UC2WioAfWrGkR",
|
|
);
|
|
} else {
|
|
throw new Error("Unsupported network");
|
|
}
|
|
const wallet = new Wallet(agent.wallet);
|
|
const ctx = WhirlpoolContext.from(
|
|
agent.connection,
|
|
wallet,
|
|
ORCA_WHIRLPOOL_PROGRAM_ID,
|
|
);
|
|
const fetcher = ctx.fetcher;
|
|
const client = buildWhirlpoolClient(ctx);
|
|
|
|
const correctTokenOrder = PoolUtil.orderMints(mintDeploy, mintPair).map(
|
|
(addr) => addr.toString(),
|
|
);
|
|
const isCorrectMintOrder = correctTokenOrder[0] === mintDeploy.toString();
|
|
let mintA;
|
|
let mintB;
|
|
if (!isCorrectMintOrder) {
|
|
[mintA, mintB] = [mintPair, mintDeploy];
|
|
initialPrice = new Decimal(1 / initialPrice.toNumber());
|
|
} else {
|
|
[mintA, mintB] = [mintDeploy, mintPair];
|
|
}
|
|
const mintAAccount = await fetcher.getMintInfo(mintA);
|
|
const mintBAccount = await fetcher.getMintInfo(mintB);
|
|
if (mintAAccount === null || mintBAccount === null) {
|
|
throw Error("Mint account not found");
|
|
}
|
|
|
|
const tickSpacing = FEE_TIERS[feeTier];
|
|
const initialTick = PriceMath.priceToInitializableTickIndex(
|
|
initialPrice,
|
|
mintAAccount.decimals,
|
|
mintBAccount.decimals,
|
|
tickSpacing,
|
|
);
|
|
const { poolKey, tx: txBuilder } = await client.createPool(
|
|
whirlpoolsConfigAddress,
|
|
mintA,
|
|
mintB,
|
|
tickSpacing,
|
|
initialTick,
|
|
wallet.publicKey,
|
|
);
|
|
|
|
const txPayload = await txBuilder.build();
|
|
const txPayloadDecompiled = TransactionMessage.decompile(
|
|
(txPayload.transaction as VersionedTransaction).message,
|
|
);
|
|
const instructions = txPayloadDecompiled.instructions;
|
|
|
|
const txId = await sendTx(
|
|
agent,
|
|
instructions,
|
|
txPayload.signers as Keypair[],
|
|
);
|
|
return JSON.stringify({
|
|
transactionId: txId,
|
|
whirlpoolAddress: poolKey.toString(),
|
|
});
|
|
} catch (error) {
|
|
throw new Error(`${error}`);
|
|
}
|
|
}
|