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,675 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Raydium CLMM (Concentrated Liquidity Market Maker) DEX Adapter
|
|
4
|
+
*
|
|
5
|
+
* Implements IDexAdapter for Raydium's CLMM program (CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK).
|
|
6
|
+
* Supports buy, sell, snipe, findPool, getPrice, and buildSwapIxs.
|
|
7
|
+
*
|
|
8
|
+
* Uses the native IX path (buy-v2.ts) for snipe and the SDK path for regular buy/sell.
|
|
9
|
+
*
|
|
10
|
+
* Ported from: 100x-algo-bots/trading-modules/raydium-clmm/
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
+
};
|
|
48
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
50
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
51
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
52
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
53
|
+
const types_1 = require("./types");
|
|
54
|
+
const index_1 = require("./index");
|
|
55
|
+
const config_1 = require("../helpers/config");
|
|
56
|
+
const landing_1 = require("../transactions/landing");
|
|
57
|
+
const send_rpc_1 = require("../transactions/send-rpc");
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Program constants
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
const RAYDIUM_CLMM_PROGRAM_ID = new web3_js_1.PublicKey("CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK");
|
|
62
|
+
const TOKEN_PROGRAM_ID_PK = new web3_js_1.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
63
|
+
const MEMO_PROGRAM_ID = new web3_js_1.PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
|
|
64
|
+
const WSOL_MINT_PK = new web3_js_1.PublicKey(types_1.WSOL_MINT);
|
|
65
|
+
const USDC_MINT_PK = new web3_js_1.PublicKey(types_1.USDC_MINT);
|
|
66
|
+
const USDT_MINT_PK = new web3_js_1.PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");
|
|
67
|
+
const USD1_MINT_PK = new web3_js_1.PublicKey("USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB");
|
|
68
|
+
// Swap V2 discriminator
|
|
69
|
+
const SWAP_V2_DISCRIMINATOR = Buffer.from([43, 4, 237, 11, 26, 201, 30, 98]);
|
|
70
|
+
// Tick array constants
|
|
71
|
+
const TICK_ARRAY_SIZE = 60;
|
|
72
|
+
const MIN_SQRT_PRICE_X64 = new bn_js_1.default("4295048016");
|
|
73
|
+
const MAX_SQRT_PRICE_X64 = new bn_js_1.default("79226673515401279992447579055");
|
|
74
|
+
// PDA seeds
|
|
75
|
+
const POOL_SEED = Buffer.from("pool", "utf8");
|
|
76
|
+
const POOL_VAULT_SEED = Buffer.from("pool_vault", "utf8");
|
|
77
|
+
const OBSERVATION_SEED = Buffer.from("observation", "utf8");
|
|
78
|
+
const TICK_ARRAY_SEED = Buffer.from("tick_array", "utf8");
|
|
79
|
+
const POOL_TICK_ARRAY_BITMAP_SEED = Buffer.from("pool_tick_array_bitmap_extension", "utf8");
|
|
80
|
+
const AMM_CONFIG_SEED = Buffer.from("amm_config", "utf8");
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// PDA helpers (ported from raydium-clmm/utils/pda-native.ts)
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
function i32ToBytes(value) {
|
|
85
|
+
const buf = Buffer.alloc(4);
|
|
86
|
+
buf.writeInt32BE(value, 0);
|
|
87
|
+
return buf;
|
|
88
|
+
}
|
|
89
|
+
function u16ToBytes(value) {
|
|
90
|
+
const buf = Buffer.alloc(2);
|
|
91
|
+
buf.writeUInt16LE(value, 0);
|
|
92
|
+
return buf;
|
|
93
|
+
}
|
|
94
|
+
function derivePda(seeds) {
|
|
95
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync(seeds, RAYDIUM_CLMM_PROGRAM_ID);
|
|
96
|
+
return pda;
|
|
97
|
+
}
|
|
98
|
+
function derivePoolVault(poolId, vaultMint) {
|
|
99
|
+
return derivePda([POOL_VAULT_SEED, poolId.toBuffer(), vaultMint.toBuffer()]);
|
|
100
|
+
}
|
|
101
|
+
function deriveObservationState(poolId) {
|
|
102
|
+
return derivePda([OBSERVATION_SEED, poolId.toBuffer()]);
|
|
103
|
+
}
|
|
104
|
+
function deriveTickArray(poolId, startIndex) {
|
|
105
|
+
return derivePda([TICK_ARRAY_SEED, poolId.toBuffer(), i32ToBytes(startIndex)]);
|
|
106
|
+
}
|
|
107
|
+
function deriveTickArrayBitmapExtension(poolId) {
|
|
108
|
+
return derivePda([POOL_TICK_ARRAY_BITMAP_SEED, poolId.toBuffer()]);
|
|
109
|
+
}
|
|
110
|
+
function deriveAmmConfig(index) {
|
|
111
|
+
return derivePda([AMM_CONFIG_SEED, u16ToBytes(index)]);
|
|
112
|
+
}
|
|
113
|
+
function derivePoolId(ammConfig, mintA, mintB) {
|
|
114
|
+
return derivePda([POOL_SEED, ammConfig.toBuffer(), mintA.toBuffer(), mintB.toBuffer()]);
|
|
115
|
+
}
|
|
116
|
+
function decodeClmmPoolState(data) {
|
|
117
|
+
let offset = 8; // skip discriminator
|
|
118
|
+
const bump = data.readUInt8(offset);
|
|
119
|
+
offset += 1;
|
|
120
|
+
const ammConfig = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
|
|
121
|
+
offset += 32;
|
|
122
|
+
const owner = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
|
|
123
|
+
offset += 32;
|
|
124
|
+
const tokenMint0 = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
|
|
125
|
+
offset += 32;
|
|
126
|
+
const tokenMint1 = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
|
|
127
|
+
offset += 32;
|
|
128
|
+
const tokenVault0 = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
|
|
129
|
+
offset += 32;
|
|
130
|
+
const tokenVault1 = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
|
|
131
|
+
offset += 32;
|
|
132
|
+
const observationKey = new web3_js_1.PublicKey(data.slice(offset, offset + 32));
|
|
133
|
+
offset += 32;
|
|
134
|
+
const mintDecimals0 = data.readUInt8(offset);
|
|
135
|
+
offset += 1;
|
|
136
|
+
const mintDecimals1 = data.readUInt8(offset);
|
|
137
|
+
offset += 1;
|
|
138
|
+
const tickSpacing = data.readUInt16LE(offset);
|
|
139
|
+
offset += 2;
|
|
140
|
+
const liquidity = new bn_js_1.default(data.slice(offset, offset + 16), "le");
|
|
141
|
+
offset += 16;
|
|
142
|
+
const sqrtPriceX64 = new bn_js_1.default(data.slice(offset, offset + 16), "le");
|
|
143
|
+
offset += 16;
|
|
144
|
+
const tickCurrent = data.readInt32LE(offset);
|
|
145
|
+
offset += 4;
|
|
146
|
+
// Skip padding3 (u16), padding4 (u16)
|
|
147
|
+
offset += 4;
|
|
148
|
+
// Skip fee_growth_global_0_x64 (u128), fee_growth_global_1_x64 (u128)
|
|
149
|
+
offset += 32;
|
|
150
|
+
// Skip protocol_fees_token_0 (u64), protocol_fees_token_1 (u64)
|
|
151
|
+
offset += 16;
|
|
152
|
+
// Skip swap_in_amount_token_0 (u128), swap_out_amount_token_1 (u128), swap_in_amount_token_1 (u128), swap_out_amount_token_0 (u128)
|
|
153
|
+
offset += 64;
|
|
154
|
+
const status = data.readUInt8(offset);
|
|
155
|
+
offset += 1;
|
|
156
|
+
// Skip padding (7 bytes)
|
|
157
|
+
offset += 7;
|
|
158
|
+
// Skip rewardInfos: 3 * 169 = 507 bytes
|
|
159
|
+
offset += 507;
|
|
160
|
+
// tickArrayBitmap: 16 u64 values
|
|
161
|
+
const tickArrayBitmap = [];
|
|
162
|
+
for (let i = 0; i < 16; i++) {
|
|
163
|
+
tickArrayBitmap.push(new bn_js_1.default(data.slice(offset, offset + 8), "le"));
|
|
164
|
+
offset += 8;
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
bump, ammConfig, owner, tokenMint0, tokenMint1, tokenVault0, tokenVault1,
|
|
168
|
+
observationKey, mintDecimals0, mintDecimals1, tickSpacing, liquidity,
|
|
169
|
+
sqrtPriceX64, tickCurrent, status, tickArrayBitmap,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async function fetchClmmPoolState(connection, poolId) {
|
|
173
|
+
const accountInfo = await connection.getAccountInfo(poolId);
|
|
174
|
+
if (!accountInfo)
|
|
175
|
+
throw new Error(`Pool state account not found: ${poolId.toBase58()}`);
|
|
176
|
+
if (!accountInfo.owner.equals(RAYDIUM_CLMM_PROGRAM_ID)) {
|
|
177
|
+
throw new Error(`Invalid account owner for pool state: ${accountInfo.owner.toBase58()}`);
|
|
178
|
+
}
|
|
179
|
+
return decodeClmmPoolState(accountInfo.data);
|
|
180
|
+
}
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// Tick array helpers
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
function tickToStartIndex(tick, tickSpacing) {
|
|
185
|
+
const ticksInArray = tickSpacing * TICK_ARRAY_SIZE;
|
|
186
|
+
// For both positive and negative ticks, floor division gives the correct start index.
|
|
187
|
+
// Math.floor(-20456 / 600) = -35, so startIndex = -35 * 600 = -21000.
|
|
188
|
+
// The tick -20456 is in range [-21000, -20400), which is correct.
|
|
189
|
+
// No special negative handling needed — Math.floor already rounds toward -∞.
|
|
190
|
+
return Math.floor(tick / ticksInArray) * ticksInArray;
|
|
191
|
+
}
|
|
192
|
+
function getNextTickArrayStartIndex(currentStartIndex, tickSpacing, zeroForOne) {
|
|
193
|
+
const ticksInArray = tickSpacing * TICK_ARRAY_SIZE;
|
|
194
|
+
return zeroForOne ? currentStartIndex - ticksInArray : currentStartIndex + ticksInArray;
|
|
195
|
+
}
|
|
196
|
+
async function getTickArraysForSwap(connection, poolId, tickCurrent, tickSpacing, zeroForOne, maxArrays = 3) {
|
|
197
|
+
const startIndex = tickToStartIndex(tickCurrent, tickSpacing);
|
|
198
|
+
const tickArrays = [];
|
|
199
|
+
let currentStart = startIndex;
|
|
200
|
+
for (let i = 0; i < maxArrays; i++) {
|
|
201
|
+
const tickArrayAddress = deriveTickArray(poolId, currentStart);
|
|
202
|
+
try {
|
|
203
|
+
const info = await connection.getAccountInfo(tickArrayAddress);
|
|
204
|
+
if (info && info.owner.equals(RAYDIUM_CLMM_PROGRAM_ID)) {
|
|
205
|
+
tickArrays.push(tickArrayAddress);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Skip
|
|
210
|
+
}
|
|
211
|
+
currentStart = getNextTickArrayStartIndex(currentStart, tickSpacing, zeroForOne);
|
|
212
|
+
}
|
|
213
|
+
// Must have at least one tick array
|
|
214
|
+
if (tickArrays.length === 0) {
|
|
215
|
+
// Use the start index tick array anyway (it may get created)
|
|
216
|
+
tickArrays.push(deriveTickArray(poolId, startIndex));
|
|
217
|
+
}
|
|
218
|
+
return tickArrays;
|
|
219
|
+
}
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
// Token program detection
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
async function getTokenProgramForMint(connection, mint) {
|
|
224
|
+
const mintInfo = await connection.getAccountInfo(mint);
|
|
225
|
+
if (!mintInfo)
|
|
226
|
+
throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
227
|
+
if (mintInfo.owner.equals(spl_token_1.TOKEN_2022_PROGRAM_ID))
|
|
228
|
+
return spl_token_1.TOKEN_2022_PROGRAM_ID;
|
|
229
|
+
return TOKEN_PROGRAM_ID_PK;
|
|
230
|
+
}
|
|
231
|
+
function isStablecoin(mint) {
|
|
232
|
+
return mint.equals(USDC_MINT_PK) || mint.equals(USDT_MINT_PK) || mint.equals(USD1_MINT_PK);
|
|
233
|
+
}
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
// Price calculation
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
function sqrtPriceX64ToPrice(sqrtPriceX64, decimalsA, decimalsB) {
|
|
238
|
+
try {
|
|
239
|
+
const { MathUtil } = require("@raydium-io/raydium-sdk-v2");
|
|
240
|
+
const price = MathUtil.x64ToDecimal(sqrtPriceX64)
|
|
241
|
+
.pow(2)
|
|
242
|
+
.mul(new decimal_js_1.default(10).pow(decimalsA - decimalsB));
|
|
243
|
+
return Number(price.toString());
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// Fallback manual calculation
|
|
247
|
+
const sqrtPrice = Number(sqrtPriceX64.toString()) / 2 ** 64;
|
|
248
|
+
const price = sqrtPrice * sqrtPrice;
|
|
249
|
+
const decimalAdj = 10 ** (decimalsA - decimalsB);
|
|
250
|
+
return price * decimalAdj;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function createClmmSwapV2Ix(poolParams, payer, inputTokenAccount, outputTokenAccount, amount, otherAmountThreshold, sqrtPriceLimitX64, isBaseInput, tickArrays, inputVaultMint, outputVaultMint, tickArrayBitmapExtension, zeroForOne) {
|
|
254
|
+
// Use zeroForOne for vault direction (falls back to isBaseInput for backward compat)
|
|
255
|
+
const directionZeroForOne = zeroForOne ?? isBaseInput;
|
|
256
|
+
const inputVault = directionZeroForOne ? poolParams.tokenVault0 : poolParams.tokenVault1;
|
|
257
|
+
const outputVault = directionZeroForOne ? poolParams.tokenVault1 : poolParams.tokenVault0;
|
|
258
|
+
const accounts = [
|
|
259
|
+
{ pubkey: payer, isSigner: true, isWritable: true },
|
|
260
|
+
{ pubkey: poolParams.ammConfig, isSigner: false, isWritable: false },
|
|
261
|
+
{ pubkey: poolParams.poolId, isSigner: false, isWritable: true },
|
|
262
|
+
{ pubkey: inputTokenAccount, isSigner: false, isWritable: true },
|
|
263
|
+
{ pubkey: outputTokenAccount, isSigner: false, isWritable: true },
|
|
264
|
+
{ pubkey: inputVault, isSigner: false, isWritable: true },
|
|
265
|
+
{ pubkey: outputVault, isSigner: false, isWritable: true },
|
|
266
|
+
{ pubkey: poolParams.observationState, isSigner: false, isWritable: true },
|
|
267
|
+
{ pubkey: TOKEN_PROGRAM_ID_PK, isSigner: false, isWritable: false },
|
|
268
|
+
{ pubkey: spl_token_1.TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
269
|
+
{ pubkey: MEMO_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
270
|
+
{ pubkey: inputVaultMint, isSigner: false, isWritable: false },
|
|
271
|
+
{ pubkey: outputVaultMint, isSigner: false, isWritable: false },
|
|
272
|
+
{ pubkey: tickArrayBitmapExtension, isSigner: false, isWritable: true },
|
|
273
|
+
{ pubkey: tickArrays[0], isSigner: false, isWritable: true },
|
|
274
|
+
];
|
|
275
|
+
// Additional tick arrays as remaining accounts
|
|
276
|
+
const remainingAccounts = tickArrays.slice(1).map((ta) => ({
|
|
277
|
+
pubkey: ta,
|
|
278
|
+
isSigner: false,
|
|
279
|
+
isWritable: true,
|
|
280
|
+
}));
|
|
281
|
+
// Data: discriminator (8) + amount (8) + threshold (8) + sqrtPriceLimit (16) + isBaseInput (1) = 41 bytes
|
|
282
|
+
const data = Buffer.alloc(41);
|
|
283
|
+
let offset = 0;
|
|
284
|
+
SWAP_V2_DISCRIMINATOR.copy(data, offset);
|
|
285
|
+
offset += 8;
|
|
286
|
+
data.writeBigUInt64LE(amount, offset);
|
|
287
|
+
offset += 8;
|
|
288
|
+
data.writeBigUInt64LE(otherAmountThreshold, offset);
|
|
289
|
+
offset += 8;
|
|
290
|
+
const sqrtPriceBytes = sqrtPriceLimitX64.toArrayLike(Buffer, "le", 16);
|
|
291
|
+
sqrtPriceBytes.copy(data, offset);
|
|
292
|
+
offset += 16;
|
|
293
|
+
data.writeUInt8(isBaseInput ? 1 : 0, offset);
|
|
294
|
+
return new web3_js_1.TransactionInstruction({
|
|
295
|
+
keys: [...accounts, ...remainingAccounts],
|
|
296
|
+
programId: RAYDIUM_CLMM_PROGRAM_ID,
|
|
297
|
+
data,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
// Pool discovery
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
const COMMON_AMM_CONFIG = new web3_js_1.PublicKey("E64NGkDLLCdQ2yFNPcavaKptrEgmiQaNykUuLC1Qgwyp");
|
|
304
|
+
async function discoverClmmPool(connection, baseMint, quoteMint) {
|
|
305
|
+
// Try the common AMM config with both mint orderings
|
|
306
|
+
const candidates = [
|
|
307
|
+
derivePoolId(COMMON_AMM_CONFIG, baseMint, quoteMint),
|
|
308
|
+
derivePoolId(COMMON_AMM_CONFIG, quoteMint, baseMint),
|
|
309
|
+
];
|
|
310
|
+
for (const poolId of candidates) {
|
|
311
|
+
try {
|
|
312
|
+
const info = await connection.getAccountInfo(poolId);
|
|
313
|
+
if (info && info.owner.equals(RAYDIUM_CLMM_PROGRAM_ID)) {
|
|
314
|
+
return poolId;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
// skip
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Try via Raydium API as fallback
|
|
322
|
+
try {
|
|
323
|
+
const { Raydium } = await Promise.resolve().then(() => __importStar(require("@raydium-io/raydium-sdk-v2")));
|
|
324
|
+
const raydium = await Raydium.load({
|
|
325
|
+
connection,
|
|
326
|
+
disableLoadToken: true,
|
|
327
|
+
});
|
|
328
|
+
const pools = await raydium.api.fetchPoolByMints({
|
|
329
|
+
mint1: quoteMint.toBase58(),
|
|
330
|
+
mint2: baseMint.toBase58(),
|
|
331
|
+
});
|
|
332
|
+
for (const obj of pools) {
|
|
333
|
+
if (obj.type === "Concentrated") {
|
|
334
|
+
return new web3_js_1.PublicKey(obj.id);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
// API unavailable
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
// ---------------------------------------------------------------------------
|
|
344
|
+
// Token balance helper
|
|
345
|
+
// ---------------------------------------------------------------------------
|
|
346
|
+
async function getTokenBalance(connection, mint, owner) {
|
|
347
|
+
const tokenProgram = await getTokenProgramForMint(connection, mint);
|
|
348
|
+
const ata = await (0, spl_token_1.getAssociatedTokenAddress)(mint, owner, tokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), tokenProgram);
|
|
349
|
+
try {
|
|
350
|
+
const res = await connection.getTokenAccountBalance(ata);
|
|
351
|
+
return { amount: BigInt(res.value.amount), decimals: res.value.decimals };
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
return { amount: 0n, decimals: 0 };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
358
|
+
// Build swap instructions (shared between snipe and buildSwapIxs)
|
|
359
|
+
// ---------------------------------------------------------------------------
|
|
360
|
+
async function buildClmmSwapInstructions(connection, wallet, tokenMint, quoteMintPk, poolId, amountIn, minOut, priorityFee, includeComputeBudget) {
|
|
361
|
+
const poolState = await fetchClmmPoolState(connection, poolId);
|
|
362
|
+
// Detect base token program
|
|
363
|
+
const baseTokenProgram = await getTokenProgramForMint(connection, tokenMint);
|
|
364
|
+
// Determine swap direction
|
|
365
|
+
// We're buying tokenMint with quoteMint, so input is quoteMint
|
|
366
|
+
const isBaseInput = poolState.tokenMint0.equals(quoteMintPk);
|
|
367
|
+
const zeroForOne = isBaseInput;
|
|
368
|
+
// Calculate sqrt price limit
|
|
369
|
+
let sqrtPriceLimitX64;
|
|
370
|
+
if (isBaseInput) {
|
|
371
|
+
sqrtPriceLimitX64 = MIN_SQRT_PRICE_X64.add(new bn_js_1.default(1));
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
sqrtPriceLimitX64 = MAX_SQRT_PRICE_X64.sub(new bn_js_1.default(1));
|
|
375
|
+
}
|
|
376
|
+
// Get tick arrays
|
|
377
|
+
const tickArrays = await getTickArraysForSwap(connection, poolId, poolState.tickCurrent, poolState.tickSpacing, zeroForOne);
|
|
378
|
+
// Build ATAs
|
|
379
|
+
const inputMintTokenProgram = await getTokenProgramForMint(connection, quoteMintPk);
|
|
380
|
+
const inputAta = await (0, spl_token_1.getAssociatedTokenAddress)(quoteMintPk, wallet.publicKey, inputMintTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), inputMintTokenProgram);
|
|
381
|
+
const outputAta = await (0, spl_token_1.getAssociatedTokenAddress)(tokenMint, wallet.publicKey, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), baseTokenProgram);
|
|
382
|
+
const tickArrayBitmapExt = deriveTickArrayBitmapExtension(poolId);
|
|
383
|
+
// Determine input/output vault mints
|
|
384
|
+
const inputVaultMint = isBaseInput ? poolState.tokenMint0 : poolState.tokenMint1;
|
|
385
|
+
const outputVaultMint = isBaseInput ? poolState.tokenMint1 : poolState.tokenMint0;
|
|
386
|
+
const poolParams = {
|
|
387
|
+
poolId,
|
|
388
|
+
ammConfig: poolState.ammConfig,
|
|
389
|
+
observationState: poolState.observationKey,
|
|
390
|
+
tokenVault0: poolState.tokenVault0,
|
|
391
|
+
tokenVault1: poolState.tokenVault1,
|
|
392
|
+
tokenMint0: poolState.tokenMint0,
|
|
393
|
+
tokenMint1: poolState.tokenMint1,
|
|
394
|
+
};
|
|
395
|
+
const swapIx = createClmmSwapV2Ix(poolParams, wallet.publicKey, inputAta, outputAta, amountIn, minOut, sqrtPriceLimitX64, true, // isBaseInput — always exact input swap
|
|
396
|
+
tickArrays, inputVaultMint, outputVaultMint, tickArrayBitmapExt, zeroForOne);
|
|
397
|
+
// Build instruction list
|
|
398
|
+
const ixs = [];
|
|
399
|
+
if (includeComputeBudget) {
|
|
400
|
+
ixs.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }));
|
|
401
|
+
}
|
|
402
|
+
ixs.push((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, inputAta, wallet.publicKey, quoteMintPk, inputMintTokenProgram), (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_PK));
|
|
403
|
+
// WSOL wrapping
|
|
404
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
405
|
+
const lamports = Number(amountIn);
|
|
406
|
+
ixs.push(web3_js_1.SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: inputAta, lamports }), (0, spl_token_1.createSyncNativeInstruction)(inputAta, TOKEN_PROGRAM_ID_PK));
|
|
407
|
+
}
|
|
408
|
+
ixs.push(swapIx);
|
|
409
|
+
// Close WSOL ATA
|
|
410
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
411
|
+
ixs.push((0, spl_token_1.createCloseAccountInstruction)(inputAta, wallet.publicKey, wallet.publicKey, [], TOKEN_PROGRAM_ID_PK));
|
|
412
|
+
}
|
|
413
|
+
return ixs;
|
|
414
|
+
}
|
|
415
|
+
// ---------------------------------------------------------------------------
|
|
416
|
+
// Build sell instructions
|
|
417
|
+
// ---------------------------------------------------------------------------
|
|
418
|
+
async function buildClmmSellInstructions(connection, wallet, tokenMint, quoteMintPk, poolId, sellAmount, minOut, priorityFee, includeComputeBudget) {
|
|
419
|
+
const poolState = await fetchClmmPoolState(connection, poolId);
|
|
420
|
+
const baseTokenProgram = await getTokenProgramForMint(connection, tokenMint);
|
|
421
|
+
// For sell: input is tokenMint, output is quoteMint.
|
|
422
|
+
// zeroForOne = true if tokenMint is token0 (selling token0 for token1).
|
|
423
|
+
// isBaseInput is ALWAYS true — we specify exact input amount, not exact output.
|
|
424
|
+
const zeroForOne = poolState.tokenMint0.equals(tokenMint);
|
|
425
|
+
let sqrtPriceLimitX64;
|
|
426
|
+
if (zeroForOne) {
|
|
427
|
+
sqrtPriceLimitX64 = MIN_SQRT_PRICE_X64.add(new bn_js_1.default(1));
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
sqrtPriceLimitX64 = MAX_SQRT_PRICE_X64.sub(new bn_js_1.default(1));
|
|
431
|
+
}
|
|
432
|
+
const tickArrays = await getTickArraysForSwap(connection, poolId, poolState.tickCurrent, poolState.tickSpacing, zeroForOne);
|
|
433
|
+
const inputAta = await (0, spl_token_1.getAssociatedTokenAddress)(tokenMint, wallet.publicKey, baseTokenProgram.equals(spl_token_1.TOKEN_2022_PROGRAM_ID), baseTokenProgram);
|
|
434
|
+
const quoteMintTokenProgram = await getTokenProgramForMint(connection, quoteMintPk);
|
|
435
|
+
const outputAta = await (0, spl_token_1.getAssociatedTokenAddress)(quoteMintPk, wallet.publicKey);
|
|
436
|
+
const tickArrayBitmapExt = deriveTickArrayBitmapExtension(poolId);
|
|
437
|
+
const inputVaultMint = zeroForOne ? poolState.tokenMint0 : poolState.tokenMint1;
|
|
438
|
+
const outputVaultMint = zeroForOne ? poolState.tokenMint1 : poolState.tokenMint0;
|
|
439
|
+
const poolParams = {
|
|
440
|
+
poolId,
|
|
441
|
+
ammConfig: poolState.ammConfig,
|
|
442
|
+
observationState: poolState.observationKey,
|
|
443
|
+
tokenVault0: poolState.tokenVault0,
|
|
444
|
+
tokenVault1: poolState.tokenVault1,
|
|
445
|
+
tokenMint0: poolState.tokenMint0,
|
|
446
|
+
tokenMint1: poolState.tokenMint1,
|
|
447
|
+
};
|
|
448
|
+
// isBaseInput = true: we always specify exact input amount
|
|
449
|
+
// zeroForOne: direction flag for vault selection
|
|
450
|
+
const swapIx = createClmmSwapV2Ix(poolParams, wallet.publicKey, inputAta, outputAta, sellAmount, minOut, sqrtPriceLimitX64, true, // isBaseInput — exact input swap
|
|
451
|
+
tickArrays, inputVaultMint, outputVaultMint, tickArrayBitmapExt, zeroForOne);
|
|
452
|
+
const ixs = [];
|
|
453
|
+
if (includeComputeBudget) {
|
|
454
|
+
ixs.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }));
|
|
455
|
+
}
|
|
456
|
+
// Create output ATA (WSOL) and ensure input ATA exists
|
|
457
|
+
ixs.push((0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, outputAta, wallet.publicKey, quoteMintPk), swapIx);
|
|
458
|
+
// Close WSOL ATA to unwrap SOL proceeds
|
|
459
|
+
if (quoteMintPk.equals(WSOL_MINT_PK)) {
|
|
460
|
+
ixs.push((0, spl_token_1.createCloseAccountInstruction)(outputAta, wallet.publicKey, wallet.publicKey, [], TOKEN_PROGRAM_ID_PK));
|
|
461
|
+
}
|
|
462
|
+
return ixs;
|
|
463
|
+
}
|
|
464
|
+
// ---------------------------------------------------------------------------
|
|
465
|
+
// Adapter class
|
|
466
|
+
// ---------------------------------------------------------------------------
|
|
467
|
+
class RaydiumClmmAdapter {
|
|
468
|
+
name = "raydium-clmm";
|
|
469
|
+
protocol = "clmm";
|
|
470
|
+
capabilities = (0, types_1.defaultCapabilities)({
|
|
471
|
+
canBuy: true,
|
|
472
|
+
canSell: true,
|
|
473
|
+
canSnipe: true,
|
|
474
|
+
canFindPool: true,
|
|
475
|
+
canGetPrice: true,
|
|
476
|
+
});
|
|
477
|
+
// ----- Core: buy -----
|
|
478
|
+
async buy(params) {
|
|
479
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
480
|
+
const connection = (0, config_1.getConnection)();
|
|
481
|
+
const wallet = (0, config_1.getWallet)();
|
|
482
|
+
const tokenMintPk = new web3_js_1.PublicKey(tokenMint);
|
|
483
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
484
|
+
const priorityFee = params.opts?.priorityFeeMicroLamports ?? types_1.DEFAULT_PRIORITY_FEE_MICRO_LAMPORTS;
|
|
485
|
+
const computeUnits = params.opts?.computeUnitLimit ?? 300_000;
|
|
486
|
+
// Discover or use provided pool
|
|
487
|
+
let poolId;
|
|
488
|
+
if (params.poolAddress) {
|
|
489
|
+
poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
const found = await discoverClmmPool(connection, tokenMintPk, quoteMintPk);
|
|
493
|
+
if (!found)
|
|
494
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
495
|
+
poolId = found;
|
|
496
|
+
}
|
|
497
|
+
// Calculate amounts
|
|
498
|
+
const quoteDecimals = quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6;
|
|
499
|
+
const amountIn = BigInt(Math.floor(params.amountSol * 10 ** quoteDecimals));
|
|
500
|
+
const ixs = await buildClmmSwapInstructions(connection, wallet, tokenMintPk, quoteMintPk, poolId, amountIn, 0n, priorityFee, true);
|
|
501
|
+
// Prepend compute unit limit
|
|
502
|
+
ixs.unshift(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits }));
|
|
503
|
+
// Submit via RPC send+confirm
|
|
504
|
+
const result = await (0, send_rpc_1.sendAndConfirmVtx)(connection, ixs, wallet);
|
|
505
|
+
return {
|
|
506
|
+
txSignature: result.txSignature,
|
|
507
|
+
confirmed: result.confirmed,
|
|
508
|
+
amountIn: params.amountSol,
|
|
509
|
+
amountInToken: quoteMintPk.equals(WSOL_MINT_PK) ? "SOL" : quoteMintPk.toBase58(),
|
|
510
|
+
dex: this.name,
|
|
511
|
+
poolAddress: poolId.toBase58(),
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
// ----- Core: sell -----
|
|
515
|
+
async sell(params) {
|
|
516
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
517
|
+
const connection = (0, config_1.getConnection)();
|
|
518
|
+
const wallet = (0, config_1.getWallet)();
|
|
519
|
+
const tokenMintPk = new web3_js_1.PublicKey(tokenMint);
|
|
520
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
521
|
+
const priorityFee = params.opts?.priorityFeeMicroLamports ?? types_1.DEFAULT_PRIORITY_FEE_MICRO_LAMPORTS;
|
|
522
|
+
const computeUnits = params.opts?.computeUnitLimit ?? 300_000;
|
|
523
|
+
// Discover pool
|
|
524
|
+
let poolId;
|
|
525
|
+
if (params.poolAddress) {
|
|
526
|
+
poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
const found = await discoverClmmPool(connection, tokenMintPk, quoteMintPk);
|
|
530
|
+
if (!found)
|
|
531
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
532
|
+
poolId = found;
|
|
533
|
+
}
|
|
534
|
+
// Get token balance
|
|
535
|
+
const balance = await getTokenBalance(connection, tokenMintPk, wallet.publicKey);
|
|
536
|
+
const sellAmount = (balance.amount * BigInt(Math.floor(params.percentage))) / 100n;
|
|
537
|
+
if (sellAmount === 0n) {
|
|
538
|
+
return {
|
|
539
|
+
txSignature: "",
|
|
540
|
+
confirmed: false,
|
|
541
|
+
amountIn: 0,
|
|
542
|
+
amountInToken: tokenMint,
|
|
543
|
+
dex: this.name,
|
|
544
|
+
poolAddress: poolId.toBase58(),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
const ixs = await buildClmmSellInstructions(connection, wallet, tokenMintPk, quoteMintPk, poolId, sellAmount, 0n, priorityFee, true);
|
|
548
|
+
ixs.unshift(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits }));
|
|
549
|
+
// Submit via RPC send+confirm
|
|
550
|
+
const result = await (0, send_rpc_1.sendAndConfirmVtx)(connection, ixs, wallet);
|
|
551
|
+
const humanSellAmount = Number(sellAmount) / 10 ** balance.decimals;
|
|
552
|
+
return {
|
|
553
|
+
txSignature: result.txSignature,
|
|
554
|
+
confirmed: result.confirmed,
|
|
555
|
+
amountIn: humanSellAmount,
|
|
556
|
+
amountInToken: tokenMint,
|
|
557
|
+
dex: this.name,
|
|
558
|
+
poolAddress: poolId.toBase58(),
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
// ----- Snipe (uses native IX path from buy-v2.ts) -----
|
|
562
|
+
async snipe(params) {
|
|
563
|
+
const connection = (0, config_1.getConnection)();
|
|
564
|
+
const wallet = (0, config_1.getWallet)();
|
|
565
|
+
const tokenMint = new web3_js_1.PublicKey(params.tokenMint);
|
|
566
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
567
|
+
const poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
568
|
+
const priorityFee = params.opts?.priorityFeeMicroLamports ?? 1_000_000;
|
|
569
|
+
const quoteDecimals = quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6;
|
|
570
|
+
const amountIn = BigInt(Math.floor(params.amountSol * 10 ** quoteDecimals));
|
|
571
|
+
const ixs = await buildClmmSwapInstructions(connection, wallet, tokenMint, quoteMintPk, poolId, amountIn, 0n, priorityFee, true);
|
|
572
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
573
|
+
const results = await (0, landing_1.landTransaction)(ixs, wallet, blockhash, {
|
|
574
|
+
dex: this.name,
|
|
575
|
+
operation: "snipe",
|
|
576
|
+
tipSol: params.tipSol,
|
|
577
|
+
});
|
|
578
|
+
const firstAccepted = results.find((r) => r.accepted);
|
|
579
|
+
return {
|
|
580
|
+
txSignature: firstAccepted?.signature ?? "",
|
|
581
|
+
confirmed: !!firstAccepted?.accepted,
|
|
582
|
+
amountIn: params.amountSol,
|
|
583
|
+
amountInToken: quoteMintPk.equals(WSOL_MINT_PK) ? "SOL" : quoteMintPk.toBase58(),
|
|
584
|
+
dex: this.name,
|
|
585
|
+
poolAddress: poolId.toBase58(),
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
// ----- Build swap IXs -----
|
|
589
|
+
async buildSwapIxs(params) {
|
|
590
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
591
|
+
const connection = (0, config_1.getConnection)();
|
|
592
|
+
const wallet = (0, config_1.getWallet)();
|
|
593
|
+
const isBuy = "amountSol" in params;
|
|
594
|
+
const tokenMintPk = new web3_js_1.PublicKey(tokenMint);
|
|
595
|
+
const quoteMintPk = params.quoteMint ? new web3_js_1.PublicKey(params.quoteMint) : WSOL_MINT_PK;
|
|
596
|
+
let poolId;
|
|
597
|
+
if (params.poolAddress) {
|
|
598
|
+
poolId = new web3_js_1.PublicKey(params.poolAddress);
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
const found = await discoverClmmPool(connection, tokenMintPk, quoteMintPk);
|
|
602
|
+
if (!found)
|
|
603
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, params.quoteMint);
|
|
604
|
+
poolId = found;
|
|
605
|
+
}
|
|
606
|
+
let instructions;
|
|
607
|
+
if (isBuy) {
|
|
608
|
+
const buyParams = params;
|
|
609
|
+
const quoteDecimals = quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6;
|
|
610
|
+
const amountIn = BigInt(Math.floor(buyParams.amountSol * 10 ** quoteDecimals));
|
|
611
|
+
instructions = await buildClmmSwapInstructions(connection, wallet, tokenMintPk, quoteMintPk, poolId, amountIn, 0n, 0, false);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
const sellParams = params;
|
|
615
|
+
const balance = await getTokenBalance(connection, tokenMintPk, wallet.publicKey);
|
|
616
|
+
const sellAmount = (balance.amount * BigInt(Math.floor(sellParams.percentage))) / 100n;
|
|
617
|
+
instructions = await buildClmmSellInstructions(connection, wallet, tokenMintPk, quoteMintPk, poolId, sellAmount, 0n, 0, false);
|
|
618
|
+
}
|
|
619
|
+
return { instructions, signers: [] };
|
|
620
|
+
}
|
|
621
|
+
// ----- Pool discovery -----
|
|
622
|
+
async findPool(baseMint, quoteMint) {
|
|
623
|
+
const connection = (0, config_1.getConnection)();
|
|
624
|
+
const baseMintPk = new web3_js_1.PublicKey(baseMint);
|
|
625
|
+
const quoteMintPk = quoteMint ? new web3_js_1.PublicKey(quoteMint) : WSOL_MINT_PK;
|
|
626
|
+
const poolId = await discoverClmmPool(connection, baseMintPk, quoteMintPk);
|
|
627
|
+
if (!poolId)
|
|
628
|
+
return null;
|
|
629
|
+
try {
|
|
630
|
+
const poolState = await fetchClmmPoolState(connection, poolId);
|
|
631
|
+
const price = sqrtPriceX64ToPrice(poolState.sqrtPriceX64, poolState.mintDecimals0, poolState.mintDecimals1);
|
|
632
|
+
return {
|
|
633
|
+
address: poolId.toBase58(),
|
|
634
|
+
dex: this.name,
|
|
635
|
+
protocol: this.protocol,
|
|
636
|
+
baseMint: poolState.tokenMint0.toBase58(),
|
|
637
|
+
quoteMint: poolState.tokenMint1.toBase58(),
|
|
638
|
+
baseDecimals: poolState.mintDecimals0,
|
|
639
|
+
quoteDecimals: poolState.mintDecimals1,
|
|
640
|
+
price,
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
catch {
|
|
644
|
+
return {
|
|
645
|
+
address: poolId.toBase58(),
|
|
646
|
+
dex: this.name,
|
|
647
|
+
protocol: this.protocol,
|
|
648
|
+
baseMint,
|
|
649
|
+
quoteMint: quoteMintPk.toBase58(),
|
|
650
|
+
baseDecimals: 6,
|
|
651
|
+
quoteDecimals: quoteMintPk.equals(WSOL_MINT_PK) ? 9 : 6,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
// ----- Price -----
|
|
656
|
+
async getPrice(poolAddress) {
|
|
657
|
+
const connection = (0, config_1.getConnection)();
|
|
658
|
+
const poolId = new web3_js_1.PublicKey(poolAddress);
|
|
659
|
+
const poolState = await fetchClmmPoolState(connection, poolId);
|
|
660
|
+
let price = sqrtPriceX64ToPrice(poolState.sqrtPriceX64, poolState.mintDecimals0, poolState.mintDecimals1);
|
|
661
|
+
return {
|
|
662
|
+
price,
|
|
663
|
+
baseMint: poolState.tokenMint0.toBase58(),
|
|
664
|
+
quoteMint: poolState.tokenMint1.toBase58(),
|
|
665
|
+
source: "on-chain",
|
|
666
|
+
poolAddress,
|
|
667
|
+
timestamp: Date.now(),
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
// ---------------------------------------------------------------------------
|
|
672
|
+
// Register adapter
|
|
673
|
+
// ---------------------------------------------------------------------------
|
|
674
|
+
(0, index_1.registerAdapter)(new RaydiumClmmAdapter());
|
|
675
|
+
//# sourceMappingURL=raydium-clmm.js.map
|