outsmart 2.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +568 -0
- package/dist/cli.d.ts +44 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1251 -0
- package/dist/cli.js.map +1 -0
- package/dist/dex/byreal-clmm.d.ts +16 -0
- package/dist/dex/byreal-clmm.d.ts.map +1 -0
- package/dist/dex/byreal-clmm.js +39 -0
- package/dist/dex/byreal-clmm.js.map +1 -0
- package/dist/dex/dflow.d.ts +27 -0
- package/dist/dex/dflow.d.ts.map +1 -0
- package/dist/dex/dflow.js +200 -0
- package/dist/dex/dflow.js.map +1 -0
- package/dist/dex/fusion-amm.d.ts +44 -0
- package/dist/dex/fusion-amm.d.ts.map +1 -0
- package/dist/dex/fusion-amm.js +546 -0
- package/dist/dex/fusion-amm.js.map +1 -0
- package/dist/dex/futarchy-amm.d.ts +32 -0
- package/dist/dex/futarchy-amm.d.ts.map +1 -0
- package/dist/dex/futarchy-amm.js +443 -0
- package/dist/dex/futarchy-amm.js.map +1 -0
- package/dist/dex/futarchy-idl.d.ts +2568 -0
- package/dist/dex/futarchy-idl.d.ts.map +1 -0
- package/dist/dex/futarchy-idl.js +2570 -0
- package/dist/dex/futarchy-idl.js.map +1 -0
- package/dist/dex/futarchy-launchpad.d.ts +68 -0
- package/dist/dex/futarchy-launchpad.d.ts.map +1 -0
- package/dist/dex/futarchy-launchpad.js +377 -0
- package/dist/dex/futarchy-launchpad.js.map +1 -0
- package/dist/dex/index.d.ts +88 -0
- package/dist/dex/index.d.ts.map +1 -0
- package/dist/dex/index.js +159 -0
- package/dist/dex/index.js.map +1 -0
- package/dist/dex/jupiter-ultra.d.ts +27 -0
- package/dist/dex/jupiter-ultra.d.ts.map +1 -0
- package/dist/dex/jupiter-ultra.js +369 -0
- package/dist/dex/jupiter-ultra.js.map +1 -0
- package/dist/dex/meteora-damm-v1.d.ts +36 -0
- package/dist/dex/meteora-damm-v1.d.ts.map +1 -0
- package/dist/dex/meteora-damm-v1.js +314 -0
- package/dist/dex/meteora-damm-v1.js.map +1 -0
- package/dist/dex/meteora-damm-v2.d.ts +103 -0
- package/dist/dex/meteora-damm-v2.d.ts.map +1 -0
- package/dist/dex/meteora-damm-v2.js +1146 -0
- package/dist/dex/meteora-damm-v2.js.map +1 -0
- package/dist/dex/meteora-dbc.d.ts +38 -0
- package/dist/dex/meteora-dbc.d.ts.map +1 -0
- package/dist/dex/meteora-dbc.js +374 -0
- package/dist/dex/meteora-dbc.js.map +1 -0
- package/dist/dex/meteora-dlmm.d.ts +79 -0
- package/dist/dex/meteora-dlmm.d.ts.map +1 -0
- package/dist/dex/meteora-dlmm.js +735 -0
- package/dist/dex/meteora-dlmm.js.map +1 -0
- package/dist/dex/orca.d.ts +31 -0
- package/dist/dex/orca.d.ts.map +1 -0
- package/dist/dex/orca.js +536 -0
- package/dist/dex/orca.js.map +1 -0
- package/dist/dex/pancakeswap-clmm.d.ts +16 -0
- package/dist/dex/pancakeswap-clmm.d.ts.map +1 -0
- package/dist/dex/pancakeswap-clmm.js +39 -0
- package/dist/dex/pancakeswap-clmm.js.map +1 -0
- package/dist/dex/pumpfun-amm.d.ts +46 -0
- package/dist/dex/pumpfun-amm.d.ts.map +1 -0
- package/dist/dex/pumpfun-amm.js +692 -0
- package/dist/dex/pumpfun-amm.js.map +1 -0
- package/dist/dex/pumpfun.d.ts +41 -0
- package/dist/dex/pumpfun.d.ts.map +1 -0
- package/dist/dex/pumpfun.js +555 -0
- package/dist/dex/pumpfun.js.map +1 -0
- package/dist/dex/raydium-amm-v4.d.ts +11 -0
- package/dist/dex/raydium-amm-v4.d.ts.map +1 -0
- package/dist/dex/raydium-amm-v4.js +649 -0
- package/dist/dex/raydium-amm-v4.js.map +1 -0
- package/dist/dex/raydium-clmm.d.ts +12 -0
- package/dist/dex/raydium-clmm.d.ts.map +1 -0
- package/dist/dex/raydium-clmm.js +675 -0
- package/dist/dex/raydium-clmm.js.map +1 -0
- package/dist/dex/raydium-cpmm.d.ts +10 -0
- package/dist/dex/raydium-cpmm.d.ts.map +1 -0
- package/dist/dex/raydium-cpmm.js +613 -0
- package/dist/dex/raydium-cpmm.js.map +1 -0
- package/dist/dex/raydium-launchlab.d.ts +12 -0
- package/dist/dex/raydium-launchlab.d.ts.map +1 -0
- package/dist/dex/raydium-launchlab.js +530 -0
- package/dist/dex/raydium-launchlab.js.map +1 -0
- package/dist/dex/shared/clmm-base.d.ts +58 -0
- package/dist/dex/shared/clmm-base.d.ts.map +1 -0
- package/dist/dex/shared/clmm-base.js +891 -0
- package/dist/dex/shared/clmm-base.js.map +1 -0
- package/dist/dex/types.d.ts +601 -0
- package/dist/dex/types.d.ts.map +1 -0
- package/dist/dex/types.js +137 -0
- package/dist/dex/types.js.map +1 -0
- package/dist/dexscreener/index.d.ts +2 -0
- package/dist/dexscreener/index.d.ts.map +1 -0
- package/dist/dexscreener/index.js +18 -0
- package/dist/dexscreener/index.js.map +1 -0
- package/dist/dexscreener/info.d.ts +22 -0
- package/dist/dexscreener/info.d.ts.map +1 -0
- package/dist/dexscreener/info.js +104 -0
- package/dist/dexscreener/info.js.map +1 -0
- package/dist/helpers/check_balance.d.ts +10 -0
- package/dist/helpers/check_balance.d.ts.map +1 -0
- package/dist/helpers/check_balance.js +34 -0
- package/dist/helpers/check_balance.js.map +1 -0
- package/dist/helpers/config.d.ts +51 -0
- package/dist/helpers/config.d.ts.map +1 -0
- package/dist/helpers/config.js +118 -0
- package/dist/helpers/config.js.map +1 -0
- package/dist/helpers/index.d.ts +8 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +29 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/logger.d.ts +27 -0
- package/dist/helpers/logger.d.ts.map +1 -0
- package/dist/helpers/logger.js +39 -0
- package/dist/helpers/logger.js.map +1 -0
- package/dist/helpers/token-2022.d.ts +32 -0
- package/dist/helpers/token-2022.d.ts.map +1 -0
- package/dist/helpers/token-2022.js +48 -0
- package/dist/helpers/token-2022.js.map +1 -0
- package/dist/helpers/unwrap_sol.d.ts +2 -0
- package/dist/helpers/unwrap_sol.d.ts.map +1 -0
- package/dist/helpers/unwrap_sol.js +67 -0
- package/dist/helpers/unwrap_sol.js.map +1 -0
- package/dist/helpers/util.d.ts +698 -0
- package/dist/helpers/util.d.ts.map +1 -0
- package/dist/helpers/util.js +181 -0
- package/dist/helpers/util.js.map +1 -0
- package/dist/helpers/utils.d.ts +10 -0
- package/dist/helpers/utils.d.ts.map +1 -0
- package/dist/helpers/utils.js +97 -0
- package/dist/helpers/utils.js.map +1 -0
- package/dist/helpers/wrap_sol.d.ts +3 -0
- package/dist/helpers/wrap_sol.d.ts.map +1 -0
- package/dist/helpers/wrap_sol.js +88 -0
- package/dist/helpers/wrap_sol.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/transactions/bloXroute_tips_tx_executor.d.ts +4 -0
- package/dist/transactions/bloXroute_tips_tx_executor.d.ts.map +1 -0
- package/dist/transactions/bloXroute_tips_tx_executor.js +70 -0
- package/dist/transactions/bloXroute_tips_tx_executor.js.map +1 -0
- package/dist/transactions/index.d.ts +6 -0
- package/dist/transactions/index.d.ts.map +1 -0
- package/dist/transactions/index.js +30 -0
- package/dist/transactions/index.js.map +1 -0
- package/dist/transactions/jito_tips_tx_executor.d.ts +15 -0
- package/dist/transactions/jito_tips_tx_executor.d.ts.map +1 -0
- package/dist/transactions/jito_tips_tx_executor.js +99 -0
- package/dist/transactions/jito_tips_tx_executor.js.map +1 -0
- package/dist/transactions/landing/index.d.ts +30 -0
- package/dist/transactions/landing/index.d.ts.map +1 -0
- package/dist/transactions/landing/index.js +60 -0
- package/dist/transactions/landing/index.js.map +1 -0
- package/dist/transactions/landing/nonce-manager.d.ts +116 -0
- package/dist/transactions/landing/nonce-manager.d.ts.map +1 -0
- package/dist/transactions/landing/nonce-manager.js +393 -0
- package/dist/transactions/landing/nonce-manager.js.map +1 -0
- package/dist/transactions/landing/orchestrator.d.ts +104 -0
- package/dist/transactions/landing/orchestrator.d.ts.map +1 -0
- package/dist/transactions/landing/orchestrator.js +329 -0
- package/dist/transactions/landing/orchestrator.js.map +1 -0
- package/dist/transactions/landing/providers/astralane.d.ts +12 -0
- package/dist/transactions/landing/providers/astralane.d.ts.map +1 -0
- package/dist/transactions/landing/providers/astralane.js +132 -0
- package/dist/transactions/landing/providers/astralane.js.map +1 -0
- package/dist/transactions/landing/providers/blockrazor.d.ts +11 -0
- package/dist/transactions/landing/providers/blockrazor.d.ts.map +1 -0
- package/dist/transactions/landing/providers/blockrazor.js +134 -0
- package/dist/transactions/landing/providers/blockrazor.js.map +1 -0
- package/dist/transactions/landing/providers/bloxroute.d.ts +12 -0
- package/dist/transactions/landing/providers/bloxroute.d.ts.map +1 -0
- package/dist/transactions/landing/providers/bloxroute.js +102 -0
- package/dist/transactions/landing/providers/bloxroute.js.map +1 -0
- package/dist/transactions/landing/providers/flashblock.d.ts +10 -0
- package/dist/transactions/landing/providers/flashblock.d.ts.map +1 -0
- package/dist/transactions/landing/providers/flashblock.js +102 -0
- package/dist/transactions/landing/providers/flashblock.js.map +1 -0
- package/dist/transactions/landing/providers/helius-sender.d.ts +11 -0
- package/dist/transactions/landing/providers/helius-sender.d.ts.map +1 -0
- package/dist/transactions/landing/providers/helius-sender.js +101 -0
- package/dist/transactions/landing/providers/helius-sender.js.map +1 -0
- package/dist/transactions/landing/providers/jito.d.ts +16 -0
- package/dist/transactions/landing/providers/jito.d.ts.map +1 -0
- package/dist/transactions/landing/providers/jito.js +110 -0
- package/dist/transactions/landing/providers/jito.js.map +1 -0
- package/dist/transactions/landing/providers/nextblock.d.ts +11 -0
- package/dist/transactions/landing/providers/nextblock.d.ts.map +1 -0
- package/dist/transactions/landing/providers/nextblock.js +109 -0
- package/dist/transactions/landing/providers/nextblock.js.map +1 -0
- package/dist/transactions/landing/providers/node1.d.ts +11 -0
- package/dist/transactions/landing/providers/node1.d.ts.map +1 -0
- package/dist/transactions/landing/providers/node1.js +101 -0
- package/dist/transactions/landing/providers/node1.js.map +1 -0
- package/dist/transactions/landing/providers/nozomi.d.ts +11 -0
- package/dist/transactions/landing/providers/nozomi.d.ts.map +1 -0
- package/dist/transactions/landing/providers/nozomi.js +124 -0
- package/dist/transactions/landing/providers/nozomi.js.map +1 -0
- package/dist/transactions/landing/providers/soyas.d.ts +16 -0
- package/dist/transactions/landing/providers/soyas.d.ts.map +1 -0
- package/dist/transactions/landing/providers/soyas.js +192 -0
- package/dist/transactions/landing/providers/soyas.js.map +1 -0
- package/dist/transactions/landing/providers/stellium.d.ts +11 -0
- package/dist/transactions/landing/providers/stellium.d.ts.map +1 -0
- package/dist/transactions/landing/providers/stellium.js +102 -0
- package/dist/transactions/landing/providers/stellium.js.map +1 -0
- package/dist/transactions/landing/providers/zero-slot.d.ts +10 -0
- package/dist/transactions/landing/providers/zero-slot.d.ts.map +1 -0
- package/dist/transactions/landing/providers/zero-slot.js +92 -0
- package/dist/transactions/landing/providers/zero-slot.js.map +1 -0
- package/dist/transactions/landing/tip-accounts.d.ts +22 -0
- package/dist/transactions/landing/tip-accounts.d.ts.map +1 -0
- package/dist/transactions/landing/tip-accounts.js +140 -0
- package/dist/transactions/landing/tip-accounts.js.map +1 -0
- package/dist/transactions/landing/types.d.ts +98 -0
- package/dist/transactions/landing/types.d.ts.map +1 -0
- package/dist/transactions/landing/types.js +30 -0
- package/dist/transactions/landing/types.js.map +1 -0
- package/dist/transactions/nozomi/tx-submission.d.ts +14 -0
- package/dist/transactions/nozomi/tx-submission.d.ts.map +1 -0
- package/dist/transactions/nozomi/tx-submission.js +107 -0
- package/dist/transactions/nozomi/tx-submission.js.map +1 -0
- package/dist/transactions/send-rpc.d.ts +54 -0
- package/dist/transactions/send-rpc.d.ts.map +1 -0
- package/dist/transactions/send-rpc.js +126 -0
- package/dist/transactions/send-rpc.js.map +1 -0
- package/dist/transactions/simple_tx_executor.d.ts +10 -0
- package/dist/transactions/simple_tx_executor.d.ts.map +1 -0
- package/dist/transactions/simple_tx_executor.js +33 -0
- package/dist/transactions/simple_tx_executor.js.map +1 -0
- package/package.json +112 -0
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Raydium CPMM (Constant Product AMM) DEX Adapter
|
|
4
|
+
*
|
|
5
|
+
* Implements IDexAdapter for Raydium's CPMM program (CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C).
|
|
6
|
+
* Supports buy, sell, snipe, findPool, getPrice, and buildSwapIxs.
|
|
7
|
+
*
|
|
8
|
+
* Ported from: 100x-algo-bots/trading-modules/raydium-cpmm/
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
12
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
13
|
+
const types_1 = require("./types");
|
|
14
|
+
const index_1 = require("./index");
|
|
15
|
+
const config_1 = require("../helpers/config");
|
|
16
|
+
const landing_1 = require("../transactions/landing");
|
|
17
|
+
const send_rpc_1 = require("../transactions/send-rpc");
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Program constants
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
const RAYDIUM_CPMM_PROGRAM_ID = new web3_js_1.PublicKey("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C");
|
|
22
|
+
const TOKEN_PROGRAM_ID = new web3_js_1.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
23
|
+
const WSOL_MINT_PK = new web3_js_1.PublicKey(types_1.WSOL_MINT);
|
|
24
|
+
const USDC_MINT_PK = new web3_js_1.PublicKey(types_1.USDC_MINT);
|
|
25
|
+
// Discriminators from on-chain program
|
|
26
|
+
const SWAP_BASE_IN_DISCRIMINATOR = Uint8Array.from([143, 190, 90, 218, 196, 30, 51, 222]);
|
|
27
|
+
// PDA seeds
|
|
28
|
+
const AUTH_SEED = Buffer.from("vault_and_lp_mint_auth_seed", "utf8");
|
|
29
|
+
const AMM_CONFIG_SEED = Buffer.from("amm_config", "utf8");
|
|
30
|
+
const POOL_SEED = Buffer.from("pool", "utf8");
|
|
31
|
+
const POOL_VAULT_SEED = Buffer.from("pool_vault", "utf8");
|
|
32
|
+
const OBSERVATION_STATE_SEED = Buffer.from("observation", "utf8");
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// PDA helpers
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
function u16ToBytes(num) {
|
|
37
|
+
const arr = new ArrayBuffer(2);
|
|
38
|
+
const view = new DataView(arr);
|
|
39
|
+
view.setUint16(0, num, false);
|
|
40
|
+
return new Uint8Array(arr);
|
|
41
|
+
}
|
|
42
|
+
function getPoolAuthorityPda() {
|
|
43
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([AUTH_SEED], RAYDIUM_CPMM_PROGRAM_ID);
|
|
44
|
+
return pda;
|
|
45
|
+
}
|
|
46
|
+
function getAmmConfigPdaByIndex(index) {
|
|
47
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([AMM_CONFIG_SEED, Buffer.from(u16ToBytes(index))], RAYDIUM_CPMM_PROGRAM_ID);
|
|
48
|
+
return pda;
|
|
49
|
+
}
|
|
50
|
+
function getPoolPda(ammConfig, mintA, mintB) {
|
|
51
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([POOL_SEED, ammConfig.toBuffer(), mintA.toBuffer(), mintB.toBuffer()], RAYDIUM_CPMM_PROGRAM_ID);
|
|
52
|
+
return pda;
|
|
53
|
+
}
|
|
54
|
+
function getPoolPdaSorted(ammConfig, mintA, mintB) {
|
|
55
|
+
const [token0, token1] = [mintA, mintB].sort((a, b) => a.toBase58().localeCompare(b.toBase58()));
|
|
56
|
+
return getPoolPda(ammConfig, token0, token1);
|
|
57
|
+
}
|
|
58
|
+
function getVaultPda(poolState, mint) {
|
|
59
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([POOL_VAULT_SEED, poolState.toBuffer(), mint.toBuffer()], RAYDIUM_CPMM_PROGRAM_ID);
|
|
60
|
+
return pda;
|
|
61
|
+
}
|
|
62
|
+
function getObservationStatePda(poolState) {
|
|
63
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([OBSERVATION_STATE_SEED, poolState.toBuffer()], RAYDIUM_CPMM_PROGRAM_ID);
|
|
64
|
+
return pda;
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Pool helpers
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
async function getTokenAccountAmount(connection, tokenAccount) {
|
|
70
|
+
const res = await connection.getTokenAccountBalance(tokenAccount);
|
|
71
|
+
return BigInt(res.value.amount);
|
|
72
|
+
}
|
|
73
|
+
async function getPoolReserves(connection, poolState, baseMint, quoteMint) {
|
|
74
|
+
const baseVault = getVaultPda(poolState, baseMint);
|
|
75
|
+
const quoteVault = getVaultPda(poolState, quoteMint);
|
|
76
|
+
const [base, quote] = await Promise.all([
|
|
77
|
+
getTokenAccountAmount(connection, baseVault),
|
|
78
|
+
getTokenAccountAmount(connection, quoteVault),
|
|
79
|
+
]);
|
|
80
|
+
return { base, quote };
|
|
81
|
+
}
|
|
82
|
+
function computeSwapOutAmount(xReserve, yReserve, xIn, feeBps = 25n) {
|
|
83
|
+
const feeDen = 10000n;
|
|
84
|
+
const xInAfterFee = (xIn * (feeDen - feeBps)) / feeDen;
|
|
85
|
+
const k = xReserve * yReserve;
|
|
86
|
+
const newX = xReserve + xInAfterFee;
|
|
87
|
+
const newY = k / newX;
|
|
88
|
+
return yReserve - newY;
|
|
89
|
+
}
|
|
90
|
+
async function getTokenProgramForMint(connection, mint) {
|
|
91
|
+
const mintInfo = await connection.getAccountInfo(mint);
|
|
92
|
+
if (!mintInfo)
|
|
93
|
+
throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
94
|
+
if (mintInfo.owner.equals(spl_token_1.TOKEN_2022_PROGRAM_ID))
|
|
95
|
+
return spl_token_1.TOKEN_2022_PROGRAM_ID;
|
|
96
|
+
return TOKEN_PROGRAM_ID;
|
|
97
|
+
}
|
|
98
|
+
async function getTokenBalance(connection, mint, owner) {
|
|
99
|
+
const tokenProgram = await getTokenProgramForMint(connection, mint);
|
|
100
|
+
const ata = await (0, spl_token_1.getAssociatedTokenAddress)(mint, owner, tokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), tokenProgram);
|
|
101
|
+
try {
|
|
102
|
+
const res = await connection.getTokenAccountBalance(ata);
|
|
103
|
+
return {
|
|
104
|
+
amount: BigInt(res.value.amount),
|
|
105
|
+
decimals: res.value.decimals,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return { amount: 0n, decimals: 0 };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function createCpmmBuyIx(cfg, payer, outputMint, userInputAta, userOutputAta, amountIn, minOut) {
|
|
113
|
+
const obs = getObservationStatePda(cfg.poolState);
|
|
114
|
+
const authority = getPoolAuthorityPda();
|
|
115
|
+
const accounts = [
|
|
116
|
+
{ pubkey: payer, isSigner: true, isWritable: true },
|
|
117
|
+
{ pubkey: authority, isSigner: false, isWritable: false },
|
|
118
|
+
{ pubkey: cfg.ammConfig, isSigner: false, isWritable: false },
|
|
119
|
+
{ pubkey: cfg.poolState, isSigner: false, isWritable: true },
|
|
120
|
+
{ pubkey: userInputAta, isSigner: false, isWritable: true },
|
|
121
|
+
{ pubkey: userOutputAta, isSigner: false, isWritable: true },
|
|
122
|
+
{ pubkey: cfg.quoteVault, isSigner: false, isWritable: true },
|
|
123
|
+
{ pubkey: cfg.baseVault, isSigner: false, isWritable: true },
|
|
124
|
+
{ pubkey: cfg.quoteTokenProgram, isSigner: false, isWritable: false },
|
|
125
|
+
{ pubkey: cfg.baseTokenProgram, isSigner: false, isWritable: false },
|
|
126
|
+
{ pubkey: cfg.quoteMint, isSigner: false, isWritable: false },
|
|
127
|
+
{ pubkey: outputMint, isSigner: false, isWritable: false },
|
|
128
|
+
{ pubkey: obs, isSigner: false, isWritable: true },
|
|
129
|
+
];
|
|
130
|
+
const data = Buffer.alloc(24);
|
|
131
|
+
data.set(SWAP_BASE_IN_DISCRIMINATOR, 0);
|
|
132
|
+
data.writeBigUInt64LE(amountIn, 8);
|
|
133
|
+
data.writeBigUInt64LE(minOut, 16);
|
|
134
|
+
return new web3_js_1.TransactionInstruction({ keys: accounts, programId: RAYDIUM_CPMM_PROGRAM_ID, data });
|
|
135
|
+
}
|
|
136
|
+
function createCpmmSellIx(cfg, payer, inputMint, userInputAta, userOutputAta, amountIn, minOut) {
|
|
137
|
+
const obs = getObservationStatePda(cfg.poolState);
|
|
138
|
+
const authority = getPoolAuthorityPda();
|
|
139
|
+
const accounts = [
|
|
140
|
+
{ pubkey: payer, isSigner: true, isWritable: true },
|
|
141
|
+
{ pubkey: authority, isSigner: false, isWritable: false },
|
|
142
|
+
{ pubkey: cfg.ammConfig, isSigner: false, isWritable: false },
|
|
143
|
+
{ pubkey: cfg.poolState, isSigner: false, isWritable: true },
|
|
144
|
+
{ pubkey: userInputAta, isSigner: false, isWritable: true },
|
|
145
|
+
{ pubkey: userOutputAta, isSigner: false, isWritable: true },
|
|
146
|
+
{ pubkey: cfg.baseVault, isSigner: false, isWritable: true },
|
|
147
|
+
{ pubkey: cfg.quoteVault, isSigner: false, isWritable: true },
|
|
148
|
+
{ pubkey: cfg.baseTokenProgram, isSigner: false, isWritable: false },
|
|
149
|
+
{ pubkey: cfg.quoteTokenProgram, isSigner: false, isWritable: false },
|
|
150
|
+
{ pubkey: inputMint, isSigner: false, isWritable: false },
|
|
151
|
+
{ pubkey: cfg.quoteMint, isSigner: false, isWritable: false },
|
|
152
|
+
{ pubkey: obs, isSigner: false, isWritable: true },
|
|
153
|
+
];
|
|
154
|
+
const data = Buffer.alloc(24);
|
|
155
|
+
data.set(SWAP_BASE_IN_DISCRIMINATOR, 0);
|
|
156
|
+
data.writeBigUInt64LE(amountIn, 8);
|
|
157
|
+
data.writeBigUInt64LE(minOut, 16);
|
|
158
|
+
return new web3_js_1.TransactionInstruction({ keys: accounts, programId: RAYDIUM_CPMM_PROGRAM_ID, data });
|
|
159
|
+
}
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
// Pool discovery helpers
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
/** Try known AMM config indices (0 is most common, try others as fallback) */
|
|
164
|
+
const KNOWN_AMM_CONFIG_INDICES = [0, 1, 2, 3];
|
|
165
|
+
async function discoverCpmmPool(connection, baseMint, quoteMint) {
|
|
166
|
+
for (const idx of KNOWN_AMM_CONFIG_INDICES) {
|
|
167
|
+
const ammConfig = getAmmConfigPdaByIndex(idx);
|
|
168
|
+
const candidates = [
|
|
169
|
+
getPoolPda(ammConfig, baseMint, quoteMint),
|
|
170
|
+
getPoolPda(ammConfig, quoteMint, baseMint),
|
|
171
|
+
getPoolPdaSorted(ammConfig, baseMint, quoteMint),
|
|
172
|
+
];
|
|
173
|
+
for (const poolId of candidates) {
|
|
174
|
+
try {
|
|
175
|
+
const info = await connection.getAccountInfo(poolId);
|
|
176
|
+
if (info && info.owner.equals(RAYDIUM_CPMM_PROGRAM_ID)) {
|
|
177
|
+
return { poolId, ammConfig };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// skip
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
// Decode pool state to get AMM config
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
/**
|
|
191
|
+
* Decode the ammConfig pubkey from CPMM pool account data.
|
|
192
|
+
* CPMM pool layout: 8-byte discriminator, then amm_config pubkey at offset 8.
|
|
193
|
+
*/
|
|
194
|
+
function decodePoolAmmConfig(data) {
|
|
195
|
+
// Skip 8-byte discriminator, ammConfig is at offset 8
|
|
196
|
+
return new web3_js_1.PublicKey(data.slice(8, 40));
|
|
197
|
+
}
|
|
198
|
+
function decodeCpmmPool(data) {
|
|
199
|
+
return {
|
|
200
|
+
ammConfig: new web3_js_1.PublicKey(data.slice(8, 40)),
|
|
201
|
+
token0Mint: new web3_js_1.PublicKey(data.slice(168, 200)),
|
|
202
|
+
token1Mint: new web3_js_1.PublicKey(data.slice(200, 232)),
|
|
203
|
+
token0Program: new web3_js_1.PublicKey(data.slice(232, 264)),
|
|
204
|
+
token1Program: new web3_js_1.PublicKey(data.slice(264, 296)),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
// Adapter class
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
class RaydiumCpmmAdapter {
|
|
211
|
+
name = "raydium-cpmm";
|
|
212
|
+
protocol = "cpmm";
|
|
213
|
+
capabilities = (0, types_1.defaultCapabilities)({
|
|
214
|
+
canBuy: true,
|
|
215
|
+
canSell: true,
|
|
216
|
+
canSnipe: true,
|
|
217
|
+
canFindPool: true,
|
|
218
|
+
canGetPrice: true,
|
|
219
|
+
});
|
|
220
|
+
// ----- Core: buy -----
|
|
221
|
+
async buy(params) {
|
|
222
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
223
|
+
const connection = (0, config_1.getConnection)();
|
|
224
|
+
const wallet = (0, config_1.getWallet)();
|
|
225
|
+
const tokenMintPk = new web3_js_1.PublicKey(tokenMint);
|
|
226
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
227
|
+
const slippageBps = params.opts?.slippageBps ?? types_1.DEFAULT_SLIPPAGE_BPS;
|
|
228
|
+
const priorityFee = params.opts?.priorityFeeMicroLamports ?? types_1.DEFAULT_PRIORITY_FEE_MICRO_LAMPORTS;
|
|
229
|
+
const computeUnits = params.opts?.computeUnitLimit ?? 300_000;
|
|
230
|
+
// Discover or use provided pool
|
|
231
|
+
let poolId;
|
|
232
|
+
let ammConfig;
|
|
233
|
+
if (params.poolAddress) {
|
|
234
|
+
poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
235
|
+
const poolInfo = await connection.getAccountInfo(poolId);
|
|
236
|
+
if (!poolInfo)
|
|
237
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
238
|
+
ammConfig = decodePoolAmmConfig(poolInfo.data);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
const result = await discoverCpmmPool(connection, tokenMintPk, quoteMintPk);
|
|
242
|
+
if (!result)
|
|
243
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
244
|
+
poolId = result.poolId;
|
|
245
|
+
ammConfig = result.ammConfig;
|
|
246
|
+
}
|
|
247
|
+
// Detect base token program
|
|
248
|
+
const baseTokenProgram = await getTokenProgramForMint(connection, tokenMintPk);
|
|
249
|
+
// Build SDK config
|
|
250
|
+
const cfg = {
|
|
251
|
+
ammConfig,
|
|
252
|
+
poolState: poolId,
|
|
253
|
+
baseMint: tokenMintPk,
|
|
254
|
+
quoteMint: quoteMintPk,
|
|
255
|
+
baseVault: getVaultPda(poolId, tokenMintPk),
|
|
256
|
+
quoteVault: getVaultPda(poolId, quoteMintPk),
|
|
257
|
+
baseTokenProgram,
|
|
258
|
+
quoteTokenProgram: TOKEN_PROGRAM_ID,
|
|
259
|
+
};
|
|
260
|
+
// Calculate amounts
|
|
261
|
+
const quoteDecimals = quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6;
|
|
262
|
+
const amountIn = BigInt(Math.floor(params.amountSol * 10 ** quoteDecimals));
|
|
263
|
+
// Get reserves for slippage calculation
|
|
264
|
+
let minOut = 0n;
|
|
265
|
+
try {
|
|
266
|
+
const reserves = await getPoolReserves(connection, poolId, tokenMintPk, quoteMintPk);
|
|
267
|
+
const estOut = computeSwapOutAmount(reserves.quote, reserves.base, amountIn);
|
|
268
|
+
minOut = (estOut * BigInt(10000 - slippageBps)) / 10000n;
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// If reserves fail, use zero slippage protection
|
|
272
|
+
}
|
|
273
|
+
// Build ATAs
|
|
274
|
+
const inputAta = await (0, spl_token_1.getAssociatedTokenAddress)(quoteMintPk, wallet.publicKey);
|
|
275
|
+
const outputAta = await (0, spl_token_1.getAssociatedTokenAddress)(tokenMintPk, wallet.publicKey, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), baseTokenProgram);
|
|
276
|
+
// Build instructions
|
|
277
|
+
const ixs = [
|
|
278
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits }),
|
|
279
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }),
|
|
280
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, inputAta, wallet.publicKey, quoteMintPk),
|
|
281
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, outputAta, wallet.publicKey, tokenMintPk, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID) ? spl_token_1.TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID),
|
|
282
|
+
];
|
|
283
|
+
// WSOL wrapping
|
|
284
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
285
|
+
const lamports = Math.floor(params.amountSol * web3_js_1.LAMPORTS_PER_SOL);
|
|
286
|
+
ixs.push(web3_js_1.SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: inputAta, lamports }), (0, spl_token_1.createSyncNativeInstruction)(inputAta, TOKEN_PROGRAM_ID));
|
|
287
|
+
}
|
|
288
|
+
// Swap instruction
|
|
289
|
+
ixs.push(createCpmmBuyIx(cfg, wallet.publicKey, tokenMintPk, inputAta, outputAta, amountIn, minOut));
|
|
290
|
+
// Close WSOL ATA after swap
|
|
291
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
292
|
+
ixs.push((0, spl_token_1.createCloseAccountInstruction)(inputAta, wallet.publicKey, wallet.publicKey, [], TOKEN_PROGRAM_ID));
|
|
293
|
+
}
|
|
294
|
+
// Submit via RPC send+confirm
|
|
295
|
+
const result = await (0, send_rpc_1.sendAndConfirmVtx)(connection, ixs, wallet);
|
|
296
|
+
return {
|
|
297
|
+
txSignature: result.txSignature,
|
|
298
|
+
confirmed: result.confirmed,
|
|
299
|
+
amountIn: params.amountSol,
|
|
300
|
+
amountInToken: quoteMintPk.equals(WSOL_MINT_PK) ? "SOL" : quoteMintPk.toBase58(),
|
|
301
|
+
dex: this.name,
|
|
302
|
+
poolAddress: poolId.toBase58(),
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
// ----- Core: sell -----
|
|
306
|
+
async sell(params) {
|
|
307
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
308
|
+
const connection = (0, config_1.getConnection)();
|
|
309
|
+
const wallet = (0, config_1.getWallet)();
|
|
310
|
+
const tokenMintPk = new web3_js_1.PublicKey(tokenMint);
|
|
311
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
312
|
+
const slippageBps = params.opts?.slippageBps ?? types_1.DEFAULT_SLIPPAGE_BPS;
|
|
313
|
+
const priorityFee = params.opts?.priorityFeeMicroLamports ?? types_1.DEFAULT_PRIORITY_FEE_MICRO_LAMPORTS;
|
|
314
|
+
const computeUnits = params.opts?.computeUnitLimit ?? 300_000;
|
|
315
|
+
// Discover pool
|
|
316
|
+
let poolId;
|
|
317
|
+
let ammConfig;
|
|
318
|
+
if (params.poolAddress) {
|
|
319
|
+
poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
320
|
+
const poolInfo = await connection.getAccountInfo(poolId);
|
|
321
|
+
if (!poolInfo)
|
|
322
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
323
|
+
ammConfig = decodePoolAmmConfig(poolInfo.data);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const result = await discoverCpmmPool(connection, tokenMintPk, quoteMintPk);
|
|
327
|
+
if (!result)
|
|
328
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
329
|
+
poolId = result.poolId;
|
|
330
|
+
ammConfig = result.ammConfig;
|
|
331
|
+
}
|
|
332
|
+
// Get token balance and compute sell amount
|
|
333
|
+
const baseTokenProgram = await getTokenProgramForMint(connection, tokenMintPk);
|
|
334
|
+
const balance = await getTokenBalance(connection, tokenMintPk, wallet.publicKey);
|
|
335
|
+
const sellAmount = (balance.amount * BigInt(Math.floor(params.percentage))) / 100n;
|
|
336
|
+
if (sellAmount === 0n) {
|
|
337
|
+
return {
|
|
338
|
+
txSignature: "",
|
|
339
|
+
confirmed: false,
|
|
340
|
+
amountIn: 0,
|
|
341
|
+
amountInToken: tokenMint,
|
|
342
|
+
dex: this.name,
|
|
343
|
+
poolAddress: poolId.toBase58(),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
// Compute min out
|
|
347
|
+
let minOut = 0n;
|
|
348
|
+
try {
|
|
349
|
+
const reserves = await getPoolReserves(connection, poolId, tokenMintPk, quoteMintPk);
|
|
350
|
+
const estOut = computeSwapOutAmount(reserves.base, reserves.quote, sellAmount);
|
|
351
|
+
minOut = (estOut * BigInt(10000 - slippageBps)) / 10000n;
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// zero floor
|
|
355
|
+
}
|
|
356
|
+
// Build SDK config
|
|
357
|
+
const cfg = {
|
|
358
|
+
ammConfig,
|
|
359
|
+
poolState: poolId,
|
|
360
|
+
baseMint: tokenMintPk,
|
|
361
|
+
quoteMint: quoteMintPk,
|
|
362
|
+
baseVault: getVaultPda(poolId, tokenMintPk),
|
|
363
|
+
quoteVault: getVaultPda(poolId, quoteMintPk),
|
|
364
|
+
baseTokenProgram,
|
|
365
|
+
quoteTokenProgram: TOKEN_PROGRAM_ID,
|
|
366
|
+
};
|
|
367
|
+
// Build ATAs
|
|
368
|
+
const inputAta = await (0, spl_token_1.getAssociatedTokenAddress)(tokenMintPk, wallet.publicKey, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), baseTokenProgram);
|
|
369
|
+
const outputAta = await (0, spl_token_1.getAssociatedTokenAddress)(quoteMintPk, wallet.publicKey);
|
|
370
|
+
// Build instructions
|
|
371
|
+
const ixs = [
|
|
372
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits }),
|
|
373
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }),
|
|
374
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, outputAta, wallet.publicKey, quoteMintPk),
|
|
375
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, inputAta, wallet.publicKey, tokenMintPk, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID) ? spl_token_1.TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID),
|
|
376
|
+
createCpmmSellIx(cfg, wallet.publicKey, tokenMintPk, inputAta, outputAta, sellAmount, minOut),
|
|
377
|
+
];
|
|
378
|
+
// Submit via RPC send+confirm
|
|
379
|
+
const result = await (0, send_rpc_1.sendAndConfirmVtx)(connection, ixs, wallet);
|
|
380
|
+
const humanSellAmount = Number(sellAmount) / 10 ** balance.decimals;
|
|
381
|
+
return {
|
|
382
|
+
txSignature: result.txSignature,
|
|
383
|
+
confirmed: result.confirmed,
|
|
384
|
+
amountIn: humanSellAmount,
|
|
385
|
+
amountInToken: tokenMint,
|
|
386
|
+
dex: this.name,
|
|
387
|
+
poolAddress: poolId.toBase58(),
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
// ----- Snipe -----
|
|
391
|
+
async snipe(params) {
|
|
392
|
+
const connection = (0, config_1.getConnection)();
|
|
393
|
+
const wallet = (0, config_1.getWallet)();
|
|
394
|
+
const tokenMint = new web3_js_1.PublicKey(params.tokenMint);
|
|
395
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
396
|
+
const poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
397
|
+
const priorityFee = params.opts?.priorityFeeMicroLamports ?? 12_000_000; // Higher for snipe
|
|
398
|
+
// Fetch pool on-chain to determine ammConfig
|
|
399
|
+
const poolInfo = await connection.getAccountInfo(poolId);
|
|
400
|
+
if (!poolInfo || !poolInfo.owner.equals(RAYDIUM_CPMM_PROGRAM_ID)) {
|
|
401
|
+
throw new types_1.PoolNotFoundError(this.name, params.tokenMint, params.quoteMint);
|
|
402
|
+
}
|
|
403
|
+
const poolData = decodeCpmmPool(poolInfo.data);
|
|
404
|
+
const ammConfig = poolData.ammConfig;
|
|
405
|
+
// Detect base token program
|
|
406
|
+
const baseTokenProgram = await getTokenProgramForMint(connection, tokenMint);
|
|
407
|
+
// Build SDK config
|
|
408
|
+
const cfg = {
|
|
409
|
+
ammConfig,
|
|
410
|
+
poolState: poolId,
|
|
411
|
+
baseMint: tokenMint,
|
|
412
|
+
quoteMint: quoteMintPk,
|
|
413
|
+
baseVault: getVaultPda(poolId, tokenMint),
|
|
414
|
+
quoteVault: getVaultPda(poolId, quoteMintPk),
|
|
415
|
+
baseTokenProgram,
|
|
416
|
+
quoteTokenProgram: TOKEN_PROGRAM_ID,
|
|
417
|
+
};
|
|
418
|
+
// Calculate amounts (zero slippage for snipe)
|
|
419
|
+
const quoteDecimals = quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6;
|
|
420
|
+
const amountIn = BigInt(Math.floor(params.amountSol * 10 ** quoteDecimals));
|
|
421
|
+
const minOut = 0n; // Unlimited slippage for sniping
|
|
422
|
+
// Build ATAs
|
|
423
|
+
const inputAta = await (0, spl_token_1.getAssociatedTokenAddress)(quoteMintPk, wallet.publicKey);
|
|
424
|
+
const outputAta = await (0, spl_token_1.getAssociatedTokenAddress)(tokenMint, wallet.publicKey, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), baseTokenProgram);
|
|
425
|
+
// Build instruction list
|
|
426
|
+
const ixs = [
|
|
427
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }),
|
|
428
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, inputAta, wallet.publicKey, quoteMintPk),
|
|
429
|
+
(0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, outputAta, wallet.publicKey, tokenMint, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID) ? spl_token_1.TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID),
|
|
430
|
+
];
|
|
431
|
+
// WSOL wrapping for snipe
|
|
432
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
433
|
+
const lamports = Math.floor(params.amountSol * web3_js_1.LAMPORTS_PER_SOL);
|
|
434
|
+
ixs.push(web3_js_1.SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: inputAta, lamports }), (0, spl_token_1.createSyncNativeInstruction)(inputAta, TOKEN_PROGRAM_ID));
|
|
435
|
+
}
|
|
436
|
+
// Swap
|
|
437
|
+
ixs.push(createCpmmBuyIx(cfg, wallet.publicKey, tokenMint, inputAta, outputAta, amountIn, minOut));
|
|
438
|
+
// Close WSOL
|
|
439
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
440
|
+
ixs.push((0, spl_token_1.createCloseAccountInstruction)(inputAta, wallet.publicKey, wallet.publicKey, [], TOKEN_PROGRAM_ID));
|
|
441
|
+
}
|
|
442
|
+
// Submit via landing layer (concurrent for snipe)
|
|
443
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
444
|
+
const results = await (0, landing_1.landTransaction)(ixs, wallet, blockhash, {
|
|
445
|
+
dex: this.name,
|
|
446
|
+
operation: "snipe",
|
|
447
|
+
tipSol: params.tipSol,
|
|
448
|
+
});
|
|
449
|
+
const firstAccepted = results.find((r) => r.accepted);
|
|
450
|
+
return {
|
|
451
|
+
txSignature: firstAccepted?.signature ?? "",
|
|
452
|
+
confirmed: !!firstAccepted?.accepted,
|
|
453
|
+
amountIn: params.amountSol,
|
|
454
|
+
amountInToken: quoteMintPk.equals(WSOL_MINT_PK) ? "SOL" : quoteMintPk.toBase58(),
|
|
455
|
+
dex: this.name,
|
|
456
|
+
poolAddress: poolId.toBase58(),
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
// ----- Build swap instructions (for nonce/orchestrator integration) -----
|
|
460
|
+
async buildSwapIxs(params) {
|
|
461
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
462
|
+
const connection = (0, config_1.getConnection)();
|
|
463
|
+
const wallet = (0, config_1.getWallet)();
|
|
464
|
+
const isBuy = "amountSol" in params;
|
|
465
|
+
const tokenMintPk = new web3_js_1.PublicKey(tokenMint);
|
|
466
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
467
|
+
// Discover pool
|
|
468
|
+
let poolId;
|
|
469
|
+
let ammConfig;
|
|
470
|
+
if (params.poolAddress) {
|
|
471
|
+
poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
472
|
+
const poolInfo = await connection.getAccountInfo(poolId);
|
|
473
|
+
if (!poolInfo)
|
|
474
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
475
|
+
ammConfig = decodePoolAmmConfig(poolInfo.data);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
const result = await discoverCpmmPool(connection, tokenMintPk, quoteMintPk);
|
|
479
|
+
if (!result)
|
|
480
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
481
|
+
poolId = result.poolId;
|
|
482
|
+
ammConfig = result.ammConfig;
|
|
483
|
+
}
|
|
484
|
+
const baseTokenProgram = await getTokenProgramForMint(connection, tokenMintPk);
|
|
485
|
+
const cfg = {
|
|
486
|
+
ammConfig,
|
|
487
|
+
poolState: poolId,
|
|
488
|
+
baseMint: tokenMintPk,
|
|
489
|
+
quoteMint: quoteMintPk,
|
|
490
|
+
baseVault: getVaultPda(poolId, tokenMintPk),
|
|
491
|
+
quoteVault: getVaultPda(poolId, quoteMintPk),
|
|
492
|
+
baseTokenProgram,
|
|
493
|
+
quoteTokenProgram: TOKEN_PROGRAM_ID,
|
|
494
|
+
};
|
|
495
|
+
const instructions = [];
|
|
496
|
+
if (isBuy) {
|
|
497
|
+
const buyParams = params;
|
|
498
|
+
const quoteDecimals = quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6;
|
|
499
|
+
const amountIn = BigInt(Math.floor(buyParams.amountSol * 10 ** quoteDecimals));
|
|
500
|
+
const inputAta = await (0, spl_token_1.getAssociatedTokenAddress)(quoteMintPk, wallet.publicKey);
|
|
501
|
+
const outputAta = await (0, spl_token_1.getAssociatedTokenAddress)(tokenMintPk, wallet.publicKey, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), baseTokenProgram);
|
|
502
|
+
instructions.push((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, inputAta, wallet.publicKey, quoteMintPk), (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, outputAta, wallet.publicKey, tokenMintPk, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID) ? spl_token_1.TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID));
|
|
503
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
504
|
+
const lamports = Math.floor(buyParams.amountSol * web3_js_1.LAMPORTS_PER_SOL);
|
|
505
|
+
instructions.push(web3_js_1.SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: inputAta, lamports }), (0, spl_token_1.createSyncNativeInstruction)(inputAta, TOKEN_PROGRAM_ID));
|
|
506
|
+
}
|
|
507
|
+
instructions.push(createCpmmBuyIx(cfg, wallet.publicKey, tokenMintPk, inputAta, outputAta, amountIn, 0n));
|
|
508
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
509
|
+
instructions.push((0, spl_token_1.createCloseAccountInstruction)(inputAta, wallet.publicKey, wallet.publicKey, [], TOKEN_PROGRAM_ID));
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
const sellParams = params;
|
|
514
|
+
const balance = await getTokenBalance(connection, tokenMintPk, wallet.publicKey);
|
|
515
|
+
const sellAmount = (balance.amount * BigInt(Math.floor(sellParams.percentage))) / 100n;
|
|
516
|
+
const inputAta = await (0, spl_token_1.getAssociatedTokenAddress)(tokenMintPk, wallet.publicKey, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), baseTokenProgram);
|
|
517
|
+
const outputAta = await (0, spl_token_1.getAssociatedTokenAddress)(quoteMintPk, wallet.publicKey);
|
|
518
|
+
instructions.push((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, outputAta, wallet.publicKey, quoteMintPk), createCpmmSellIx(cfg, wallet.publicKey, tokenMintPk, inputAta, outputAta, sellAmount, 0n));
|
|
519
|
+
}
|
|
520
|
+
return { instructions, signers: [] };
|
|
521
|
+
}
|
|
522
|
+
// ----- Pool discovery -----
|
|
523
|
+
async findPool(baseMint, quoteMint) {
|
|
524
|
+
const connection = (0, config_1.getConnection)();
|
|
525
|
+
const baseMintPk = new web3_js_1.PublicKey(baseMint);
|
|
526
|
+
const quoteMintPk = quoteMint ? new web3_js_1.PublicKey(quoteMint) : WSOL_MINT_PK;
|
|
527
|
+
const result = await discoverCpmmPool(connection, baseMintPk, quoteMintPk);
|
|
528
|
+
if (!result)
|
|
529
|
+
return null;
|
|
530
|
+
// Get reserves for price
|
|
531
|
+
try {
|
|
532
|
+
const reserves = await getPoolReserves(connection, result.poolId, baseMintPk, quoteMintPk);
|
|
533
|
+
const quoteDecimals = quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6;
|
|
534
|
+
// Estimate base decimals from reserves (fallback to 6)
|
|
535
|
+
const baseDecimals = 6;
|
|
536
|
+
const baseReserveHuman = Number(reserves.base) / 10 ** baseDecimals;
|
|
537
|
+
const quoteReserveHuman = Number(reserves.quote) / 10 ** quoteDecimals;
|
|
538
|
+
const price = baseReserveHuman > 0 ? quoteReserveHuman / baseReserveHuman : 0;
|
|
539
|
+
return {
|
|
540
|
+
address: result.poolId.toBase58(),
|
|
541
|
+
dex: this.name,
|
|
542
|
+
protocol: this.protocol,
|
|
543
|
+
baseMint,
|
|
544
|
+
quoteMint: quoteMintPk.toBase58(),
|
|
545
|
+
baseDecimals,
|
|
546
|
+
quoteDecimals,
|
|
547
|
+
price,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
catch {
|
|
551
|
+
return {
|
|
552
|
+
address: result.poolId.toBase58(),
|
|
553
|
+
dex: this.name,
|
|
554
|
+
protocol: this.protocol,
|
|
555
|
+
baseMint,
|
|
556
|
+
quoteMint: quoteMintPk.toBase58(),
|
|
557
|
+
baseDecimals: 6,
|
|
558
|
+
quoteDecimals: quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
// ----- Price -----
|
|
563
|
+
async getPrice(poolAddress) {
|
|
564
|
+
const connection = (0, config_1.getConnection)();
|
|
565
|
+
const poolId = new web3_js_1.PublicKey(poolAddress);
|
|
566
|
+
const poolInfo = await connection.getAccountInfo(poolId);
|
|
567
|
+
if (!poolInfo || !poolInfo.owner.equals(RAYDIUM_CPMM_PROGRAM_ID)) {
|
|
568
|
+
throw new Error(`Pool not found or not a CPMM pool: ${poolAddress}`);
|
|
569
|
+
}
|
|
570
|
+
const poolData = decodeCpmmPool(poolInfo.data);
|
|
571
|
+
const baseMint = poolData.token0Mint;
|
|
572
|
+
const quoteMint = poolData.token1Mint;
|
|
573
|
+
// Determine which is quote (WSOL/USDC) vs base
|
|
574
|
+
let actualBase;
|
|
575
|
+
let actualQuote;
|
|
576
|
+
if (quoteMint.equals(WSOL_MINT_PK) || quoteMint.equals(USDC_MINT_PK)) {
|
|
577
|
+
actualBase = baseMint;
|
|
578
|
+
actualQuote = quoteMint;
|
|
579
|
+
}
|
|
580
|
+
else if (baseMint.equals(WSOL_MINT_PK) || baseMint.equals(USDC_MINT_PK)) {
|
|
581
|
+
actualBase = quoteMint;
|
|
582
|
+
actualQuote = baseMint;
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
actualBase = baseMint;
|
|
586
|
+
actualQuote = quoteMint;
|
|
587
|
+
}
|
|
588
|
+
const reserves = await getPoolReserves(connection, poolId, actualBase, actualQuote);
|
|
589
|
+
// Fetch actual decimals from mint accounts
|
|
590
|
+
const [baseMintInfo, quoteMintInfo] = await Promise.all([
|
|
591
|
+
connection.getAccountInfo(actualBase),
|
|
592
|
+
connection.getAccountInfo(actualQuote),
|
|
593
|
+
]);
|
|
594
|
+
const baseDecimals = baseMintInfo ? baseMintInfo.data.readUInt8(44) : 9;
|
|
595
|
+
const quoteDecimals = quoteMintInfo ? quoteMintInfo.data.readUInt8(44) : 9;
|
|
596
|
+
const baseReserveHuman = Number(reserves.base) / 10 ** baseDecimals;
|
|
597
|
+
const quoteReserveHuman = Number(reserves.quote) / 10 ** quoteDecimals;
|
|
598
|
+
const price = baseReserveHuman > 0 ? quoteReserveHuman / baseReserveHuman : 0;
|
|
599
|
+
return {
|
|
600
|
+
price,
|
|
601
|
+
baseMint: actualBase.toBase58(),
|
|
602
|
+
quoteMint: actualQuote.toBase58(),
|
|
603
|
+
source: "on-chain",
|
|
604
|
+
poolAddress,
|
|
605
|
+
timestamp: Date.now(),
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
// ---------------------------------------------------------------------------
|
|
610
|
+
// Register adapter
|
|
611
|
+
// ---------------------------------------------------------------------------
|
|
612
|
+
(0, index_1.registerAdapter)(new RaydiumCpmmAdapter());
|
|
613
|
+
//# sourceMappingURL=raydium-cpmm.js.map
|