本文介绍了如何在Raydium上启动流动性池并采取保护措施以防止机器人操纵,核心策略是通过预先购买来迷惑交易机器人,使其认为代币价格过高而不敢轻易购买,从而增加价格稳定性。文章还提供了使用Solana CLI、Raydium SDK和Jito创建和发送Jito Bundle的具体步骤和代码示例。
Raydium 是一个建立在 Solana 上的去中心化交易所,提供高速的代币交换。通过利用自动化做市商(AMM),用户可以高效地交易各种代币,而无需依赖中心化中介机构。
然而,Raydium 上的新流动性池始终面临交易机器人操纵市场的威胁,导致人为的价格飙升,然后突然暴跌,这对投资者信心产生负面影响。为了防止这种情况,
在本文中,我们将探讨一种通过自己进行初始购买来应对此问题的策略。这将误导机器人认为代币已经太贵,购买风险太大,从而增加价格稳定性。
完整的代码可以在GitHub 上的这里找到,供你参考,欢迎克隆该项目并尝试一下。
在深入实施之前,必须安装以下工具和库:
虽然整个过程最初可能看起来很复杂,但以下步骤将使你清楚地了解每个阶段。
首先,创建一个新的 Node.js 项目并安装所需的依赖项:
npm install @solana/web3.js @raydium-io/raydium-sdk jito-solana typescript
为了有效地与 Solana 网络和 Raydium 交互,我们需要设置必要的配置参数。在你的项目目录中创建一个名为 config.ts
的文件,并添加以下代码:
import {
Connection,
Keypair,
PublicKey,
} from '@solana/web3.js';
import {
ENDPOINT as _ENDPOINT,
Currency,
LOOKUP_TABLE_CACHE,
MAINNET_PROGRAM_ID,
RAYDIUM_MAINNET,
Token,
TOKEN_PROGRAM_ID,
TxVersion,
} from '@raydium-io/raydium-sdk';
export const rpcUrl: string = '一个 Jito RPC 节点 URL'
export const rpcToken: string | undefined = undefined
export const wallet = Keypair.fromSecretKey(
new Uint8Array([\
...key here\
])
)
export const lpCreateWallet = new Keypair.fromSecretKey(new Uint8Array([...]));
export const connection = new Connection(
rpcUrl,
'confirmed'
)
export const PROGRAMIDS = MAINNET_PROGRAM_ID
export const ENDPOINT = _ENDPOINT
export const RAYDIUM_MAINNET_API = RAYDIUM_MAINNET
export const makeTxVersion = TxVersion.V0 // LEGACY
export const addLookupTableInfo = LOOKUP_TABLE_CACHE // only mainnet. other = undefined
这些主要只是运行项目所需的配置。rpcUrl
接受运行 Jito 的 RPC 节点的 URL。wallet
是你的 solana 钱包,你将使用它来发送交易,而 lpCreateWallet
是将创建流动性池的钱包。我们将在整个指南中根据需要添加更多配置详细信息。
注意: 出于安全原因,强烈建议使用环境变量或者安全的配置管理系统来存储私钥。避免将它们直接硬编码到你的代码中。
现在我们将继续定义代币信息。为了定义这些信息,有一些辅助对象可以从 Raydium SDK 导入:
//继续 config.ts
export const DEFAULT_TOKEN = {
SOL: new Currency(9, "USDC", "USDC"),
WSOL: new Token(
TOKEN_PROGRAM_ID,
new PublicKey("So11111111111111111111111111111111111111112"),
9,
"WSOL",
"WSOL"
),
USDC: new Token(
TOKEN_PROGRAM_ID,
new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
6,
"USDC",
"USDC"
),
};
从 Raydium SDK 导入的代币类已用于定义涉及的代币。SOL 是此示例中使用的报价 mint,它通常是平台上大多数交换的一部分。这里使用的基础 mint 代币是 USDC,但是你可以用你想交换的代币的详细信息替换它。成功初始化后,我们将转向交换过程。
一旦我们建立了运行该过程所需的全部配置,我们现在就可以继续进行实际的池创建和交换过程。
这将是实际过程的起点,为此,我们将在项目根目录中的 index.ts 文件中定义它。
import { TokenAmount } from "@raydium-io/raydium-sdk";
import { DEFAULT_TOKEN, connection, wallet } from "./config";
import { getWalletTokenAccount } from "./utils";
import BN from "bn.js";
import { createPoolIx } from "./lpCreate";
import { PublicKey } from "@solana/web3.js";
import createLookupTable from "./createLookupTable";
import createSwapIx from "./swapCreate";
import submitJitoBundle from "./submitJitoBundle";
async function main() {
.....//其余代码
代币和金额定义 在 main
函数中,定义流动性池的基础代币和报价代币:
const inputToken = DEFAULT_TOKEN.WSOL; // 替换为基础代币
const outputToken = DEFAULT_TOKEN.USDC; // 替换为报价代币
const createLpBaseAmount = new BN(100000000000000); //基础代币的数量
const createLpQuoteAmount = new BN(100000000000000); //报价代币的数量
这里的输入和输出代币在 config.ts 文件中定义,你可以根据需要使用自己的代币。
OpenBook 市场 ID 和交换金额
获取与你所需的代币对相对应的 OpenBook 市场 ID(本指南未涵盖)。使用 Raydium SDK 中的 TokenAmount
类指定初始交换金额:
// Openbook market ID
const marketId = "marketId";
const inputTokenAmount = new TokenAmount(inputToken, 10000); // 每次交换使用的 SOL 数量
在此示例中,我们将 10000(以 lamports 为单位)设置为用于前 N 次交换的任意帐户。
获取钱包代币账户
Raydium SDK 函数使用 TokenAccount 对象,因此我们需要一个工具将 Solana 钱包转换为 TokenAccount 对象。以下实用函数执行上述指定的任务(在 src/ 下的 utils.ts 中定义)
export async function getWalletTokenAccount(
connection: Connection,
wallet: PublicKey
): Promise<TokenAccount[]> {
const walletTokenAccount = await connection.getTokenAccountsByOwner(wallet, {
programId: TOKEN_PROGRAM_ID,
});
return walletTokenAccount.value.map((i) => ({
pubkey: i.pubkey,
programId: i.account.owner,
accountInfo: SPL_ACCOUNT_LAYOUT.decode(i.account.data),
}));
}
此函数检索与指定的钱包地址关联的代币帐户。
创建流动性池指令
由于我们已经设置了一个钱包代币帐户枚举器(在上一步中),我们现在可以深入研究 Create Pool 指令的代码:
createPoolIx
函数让我们扩展上一节中介绍的 createPoolIx
函数:
import {
LOOKUP_TABLE_CACHE,
Liquidity,
LiquidityPoolKeys,
MAINNET_PROGRAM_ID,
MARKET_STATE_LAYOUT_V3,
Percent,
TokenAccount,
TokenAmount,
TxVersion,
jsonInfo2PoolKeys,
InnerSimpleV0Transaction,
LiquidityPoolKeysV4,
} from "@raydium-io/raydium-sdk";
import { getComputeBudgetConfig, getWalletTokenAccount } from "./utils";
import { DEFAULT_TOKEN, connection } from "./config";
import {
Keypair,
PublicKey,
PublicKeyInitData,
TransactionMessage,
VersionedTransaction,
} from "@solana/web3.js";
import { unpackMint } from "@solana/spl-token";
import BN from "bn.js";
const inputToken = DEFAULT_TOKEN.WSOL; // USDC
const outputToken = DEFAULT_TOKEN.USDC; // RAY
interface createPoolIxReturnType {
poolKeys: LiquidityPoolKeysV4;
createPoolTx: VersionedTransaction;
}
// openbook market id
const marketId = "marketId here";
// raydium create pool instructions
export async function createPoolIx(
marketId: PublicKey,
wallet: Keypair,
tokenAccounts: TokenAccount[],
baseMint: PublicKey,
quoteMint: PublicKey,
baseAmount: BN,
quoteAmount: BN
): Promise<void | createPoolIxReturnType> {
createPoolIx
函数需要特定的输入:OpenBook 市场 ID、LP 创建者钱包、代币帐户信息、基础 mint 和报价 mint 详细信息以及所需的代币数量。它返回一组池密钥和一个交易,或者返回一个错误。为了构造必要的池密钥,我们必须执行链上查找。
const tokenAccountInfo = await getWalletTokenAccount(
connection,
wallet.publicKey
);
const marketBufferInfo = await connection.getAccountInfo(marketId);
if (!marketBufferInfo) throw Error("no marketBufferInfo");
const {
baseVault: marketBaseVault,
quoteVault: marketQuoteVault,
bids: marketBids,
asks: marketAsks,
eventQueue: marketEventQueue,
} = MARKET_STATE_LAYOUT_V3.decode(marketBufferInfo.data);
console.log("Base mint: ", baseMint.toString());
console.log("Quote mint: ", quoteMint.toString());
const accountInfo_base = await connection.getAccountInfo(baseMint);
if (!accountInfo_base) throw Error("no accountInfo_base");
const baseTokenProgramId = accountInfo_base.owner;
const baseDecimals = unpackMint(
baseMint,
accountInfo_base,
baseTokenProgramId
).decimals;
console.log("Base Decimals: ", baseDecimals);
我们使用 MARKET_STATE_LAYOUT_V3
解码器从 OpenBook 市场帐户中提取必要的数据。这基本上是一个帐户布局,它可以帮助我们解码 OpenBook 帐户数据。此信息与代币详细信息结合使用,以创建全面的池密钥对象。
这几乎是我们如何开始池创建过程和初始步骤的前几个步骤。请查看本文的下一部分,在那里我们将继续完成创建池函数并使用 Jito 包设置交换。
下一步:在 Raydium 上启动流动性池并采取保护策略以应对机器人操纵——第二部分
- 原文链接: blogs.shyft.to/launching...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!