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,692 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PumpFun AMM (PumpSwap) — IDexAdapter Implementation
|
|
4
|
+
*
|
|
5
|
+
* Program ID: pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA
|
|
6
|
+
*
|
|
7
|
+
* A constant-product AMM that tokens graduate to after their bonding curve
|
|
8
|
+
* completes on pump.fun. Also supports user-created pools.
|
|
9
|
+
*
|
|
10
|
+
* Supports:
|
|
11
|
+
* - buy: Buy base tokens from a pool (SOL → token)
|
|
12
|
+
* - sell: Sell base tokens to a pool (token → SOL)
|
|
13
|
+
* - createPool: Create a new AMM pool with initial liquidity
|
|
14
|
+
* - getPrice: Read pool reserves to compute price
|
|
15
|
+
* - snipe: Competitive buy via landing layer
|
|
16
|
+
*
|
|
17
|
+
* Pool PDA: ["pool", index(u16 LE), creator, baseMint, quoteMint]
|
|
18
|
+
* LP Mint PDA: ["pool_lp_mint", pool]
|
|
19
|
+
*
|
|
20
|
+
* Fees: LP fee 20 bps + protocol fee 5 bps = 25 bps total.
|
|
21
|
+
* Protocol fee recipients (8) should be randomly selected per TX.
|
|
22
|
+
*
|
|
23
|
+
* IDL source: https://github.com/pump-fun/pump-public-docs/blob/main/idl/pump_amm.json
|
|
24
|
+
*/
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.PumpFunAmmAdapter = void 0;
|
|
30
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
31
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
32
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
33
|
+
const config_1 = require("../helpers/config");
|
|
34
|
+
const landing_1 = require("../transactions/landing");
|
|
35
|
+
const send_rpc_1 = require("../transactions/send-rpc");
|
|
36
|
+
const types_1 = require("./types");
|
|
37
|
+
const index_1 = require("./index");
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Program constants
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
const PUMP_AMM_PROGRAM_ID = new web3_js_1.PublicKey("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA");
|
|
42
|
+
const PUMP_AMM_GLOBAL_CONFIG = new web3_js_1.PublicKey("ADyA8hdefvWN2dbGGWFotbzWxrAvLW83WG6QCVXvJKqw");
|
|
43
|
+
const PUMP_FEE_PROGRAM = new web3_js_1.PublicKey("pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ");
|
|
44
|
+
const PUMP_PROGRAM_ID = new web3_js_1.PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");
|
|
45
|
+
// Protocol fee recipients — randomly pick one per TX
|
|
46
|
+
const PROTOCOL_FEE_RECIPIENTS = [
|
|
47
|
+
new web3_js_1.PublicKey("62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV"),
|
|
48
|
+
new web3_js_1.PublicKey("7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ"),
|
|
49
|
+
new web3_js_1.PublicKey("7hTckgnGnLQR6sdH7YkqFTAA7VwTfYFaZ6EhEsU3saCX"),
|
|
50
|
+
new web3_js_1.PublicKey("9rPYyANsfQZw3DnDmKE3YCQF5E8oD89UXoHn9JFEhJUz"),
|
|
51
|
+
new web3_js_1.PublicKey("AVmoTthdrX6tKt4nDjco2D775W2YK3sDhxPcMmzUAmTY"),
|
|
52
|
+
new web3_js_1.PublicKey("FWsW1xNtWscwNmKv6wVsU1iTzRN6wmmk3MjxRP5tT7hz"),
|
|
53
|
+
new web3_js_1.PublicKey("G5UZAVbAf46s7cKWoyKu8kYTip9DGTpbLZ2qa9Aq69dP"),
|
|
54
|
+
new web3_js_1.PublicKey("JCRGumoE9Qi5BBgULTgdgTLjSgkCMSbF62ZZfGs84JeU"),
|
|
55
|
+
];
|
|
56
|
+
// Instruction discriminators (from IDL)
|
|
57
|
+
const BUY_DISCRIMINATOR = Buffer.from([102, 6, 61, 18, 1, 218, 235, 234]);
|
|
58
|
+
const SELL_DISCRIMINATOR = Buffer.from([51, 230, 133, 164, 1, 127, 131, 173]);
|
|
59
|
+
const CREATE_POOL_DISCRIMINATOR = Buffer.from([233, 146, 209, 142, 207, 104, 64, 188]);
|
|
60
|
+
// Pool account discriminator
|
|
61
|
+
const POOL_DISCRIMINATOR = Buffer.from([241, 154, 109, 4, 17, 177, 109, 188]);
|
|
62
|
+
// All pump.fun tokens are 6 decimals. Quote (WSOL) is 9.
|
|
63
|
+
const PUMP_TOKEN_DECIMALS = 6;
|
|
64
|
+
function deserializePool(data) {
|
|
65
|
+
let offset = 8; // skip discriminator
|
|
66
|
+
const poolBump = data.readUInt8(offset);
|
|
67
|
+
offset += 1;
|
|
68
|
+
const index = data.readUInt16LE(offset);
|
|
69
|
+
offset += 2;
|
|
70
|
+
const creator = new web3_js_1.PublicKey(data.subarray(offset, offset + 32));
|
|
71
|
+
offset += 32;
|
|
72
|
+
const baseMint = new web3_js_1.PublicKey(data.subarray(offset, offset + 32));
|
|
73
|
+
offset += 32;
|
|
74
|
+
const quoteMint = new web3_js_1.PublicKey(data.subarray(offset, offset + 32));
|
|
75
|
+
offset += 32;
|
|
76
|
+
const lpMint = new web3_js_1.PublicKey(data.subarray(offset, offset + 32));
|
|
77
|
+
offset += 32;
|
|
78
|
+
const poolBaseTokenAccount = new web3_js_1.PublicKey(data.subarray(offset, offset + 32));
|
|
79
|
+
offset += 32;
|
|
80
|
+
const poolQuoteTokenAccount = new web3_js_1.PublicKey(data.subarray(offset, offset + 32));
|
|
81
|
+
offset += 32;
|
|
82
|
+
const lpSupply = data.readBigUInt64LE(offset);
|
|
83
|
+
offset += 8;
|
|
84
|
+
const coinCreator = new web3_js_1.PublicKey(data.subarray(offset, offset + 32));
|
|
85
|
+
offset += 32;
|
|
86
|
+
return {
|
|
87
|
+
poolBump, index, creator, baseMint, quoteMint, lpMint,
|
|
88
|
+
poolBaseTokenAccount, poolQuoteTokenAccount, lpSupply, coinCreator,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// PDA derivation helpers
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
function getEventAuthorityPda() {
|
|
95
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("__event_authority")], PUMP_AMM_PROGRAM_ID);
|
|
96
|
+
return pda;
|
|
97
|
+
}
|
|
98
|
+
function getCreatorVaultAuthorityPda(coinCreator) {
|
|
99
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("creator_vault"), coinCreator.toBuffer()], PUMP_AMM_PROGRAM_ID);
|
|
100
|
+
return pda;
|
|
101
|
+
}
|
|
102
|
+
function getGlobalVolumeAccumulatorPda() {
|
|
103
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("global_volume_accumulator")], PUMP_AMM_PROGRAM_ID);
|
|
104
|
+
return pda;
|
|
105
|
+
}
|
|
106
|
+
function getUserVolumeAccumulatorPda(user) {
|
|
107
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("user_volume_accumulator"), user.toBuffer()], PUMP_AMM_PROGRAM_ID);
|
|
108
|
+
return pda;
|
|
109
|
+
}
|
|
110
|
+
function getFeeConfigPda() {
|
|
111
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("fee_config"), PUMP_AMM_PROGRAM_ID.toBuffer()], PUMP_FEE_PROGRAM);
|
|
112
|
+
return pda;
|
|
113
|
+
}
|
|
114
|
+
function getPoolPda(index, creator, baseMint, quoteMint) {
|
|
115
|
+
const indexBuf = Buffer.alloc(2);
|
|
116
|
+
indexBuf.writeUInt16LE(index);
|
|
117
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("pool"), indexBuf, creator.toBuffer(), baseMint.toBuffer(), quoteMint.toBuffer()], PUMP_AMM_PROGRAM_ID);
|
|
118
|
+
return pda;
|
|
119
|
+
}
|
|
120
|
+
function getLpMintPda(pool) {
|
|
121
|
+
const [pda] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("pool_lp_mint"), pool.toBuffer()], PUMP_AMM_PROGRAM_ID);
|
|
122
|
+
return pda;
|
|
123
|
+
}
|
|
124
|
+
/** Pick a random protocol fee recipient */
|
|
125
|
+
function randomProtocolFeeRecipient() {
|
|
126
|
+
return PROTOCOL_FEE_RECIPIENTS[Math.floor(Math.random() * PROTOCOL_FEE_RECIPIENTS.length)];
|
|
127
|
+
}
|
|
128
|
+
/** Detect token program from on-chain account owner */
|
|
129
|
+
async function detectTokenProgram(mint) {
|
|
130
|
+
const connection = (0, config_1.getConnection)();
|
|
131
|
+
const accountInfo = await connection.getAccountInfo(mint);
|
|
132
|
+
if (!accountInfo)
|
|
133
|
+
throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
134
|
+
return accountInfo.owner.equals(spl_token_1.TOKEN_2022_PROGRAM_ID)
|
|
135
|
+
? spl_token_1.TOKEN_2022_PROGRAM_ID
|
|
136
|
+
: spl_token_1.TOKEN_PROGRAM_ID;
|
|
137
|
+
}
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Instruction builders
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
/**
|
|
142
|
+
* Build a PumpSwap AMM BUY instruction.
|
|
143
|
+
*
|
|
144
|
+
* buy(base_amount_out, max_quote_amount_in, track_volume)
|
|
145
|
+
*/
|
|
146
|
+
function buildBuyInstruction(pool, poolState, user, baseAmountOut, maxQuoteAmountIn, baseTokenProgram, quoteTokenProgram) {
|
|
147
|
+
const userBaseTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.baseMint, user, false, baseTokenProgram);
|
|
148
|
+
const userQuoteTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, user, false, quoteTokenProgram);
|
|
149
|
+
const protocolFeeRecipient = randomProtocolFeeRecipient();
|
|
150
|
+
const protocolFeeRecipientTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, protocolFeeRecipient, true, quoteTokenProgram);
|
|
151
|
+
const coinCreatorVaultAuthority = getCreatorVaultAuthorityPda(poolState.coinCreator);
|
|
152
|
+
const coinCreatorVaultAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, coinCreatorVaultAuthority, true, quoteTokenProgram);
|
|
153
|
+
const eventAuthority = getEventAuthorityPda();
|
|
154
|
+
const globalVolumeAccumulator = getGlobalVolumeAccumulatorPda();
|
|
155
|
+
const userVolumeAccumulator = getUserVolumeAccumulatorPda(user);
|
|
156
|
+
const feeConfig = getFeeConfigPda();
|
|
157
|
+
// Encode args: base_amount_out (u64) + max_quote_amount_in (u64)
|
|
158
|
+
const data = Buffer.alloc(8 + 8 + 8);
|
|
159
|
+
BUY_DISCRIMINATOR.copy(data, 0);
|
|
160
|
+
data.writeBigUInt64LE(BigInt(baseAmountOut.toString()), 8);
|
|
161
|
+
data.writeBigUInt64LE(BigInt(maxQuoteAmountIn.toString()), 16);
|
|
162
|
+
return new web3_js_1.TransactionInstruction({
|
|
163
|
+
programId: PUMP_AMM_PROGRAM_ID,
|
|
164
|
+
keys: [
|
|
165
|
+
{ pubkey: pool, isSigner: false, isWritable: true },
|
|
166
|
+
{ pubkey: user, isSigner: true, isWritable: true },
|
|
167
|
+
{ pubkey: PUMP_AMM_GLOBAL_CONFIG, isSigner: false, isWritable: false },
|
|
168
|
+
{ pubkey: poolState.baseMint, isSigner: false, isWritable: false },
|
|
169
|
+
{ pubkey: poolState.quoteMint, isSigner: false, isWritable: false },
|
|
170
|
+
{ pubkey: userBaseTokenAccount, isSigner: false, isWritable: true },
|
|
171
|
+
{ pubkey: userQuoteTokenAccount, isSigner: false, isWritable: true },
|
|
172
|
+
{ pubkey: poolState.poolBaseTokenAccount, isSigner: false, isWritable: true },
|
|
173
|
+
{ pubkey: poolState.poolQuoteTokenAccount, isSigner: false, isWritable: true },
|
|
174
|
+
{ pubkey: protocolFeeRecipient, isSigner: false, isWritable: false },
|
|
175
|
+
{ pubkey: protocolFeeRecipientTokenAccount, isSigner: false, isWritable: true },
|
|
176
|
+
{ pubkey: baseTokenProgram, isSigner: false, isWritable: false },
|
|
177
|
+
{ pubkey: quoteTokenProgram, isSigner: false, isWritable: false },
|
|
178
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
|
|
179
|
+
{ pubkey: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
180
|
+
{ pubkey: eventAuthority, isSigner: false, isWritable: false },
|
|
181
|
+
{ pubkey: PUMP_AMM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
182
|
+
{ pubkey: coinCreatorVaultAta, isSigner: false, isWritable: true },
|
|
183
|
+
{ pubkey: coinCreatorVaultAuthority, isSigner: false, isWritable: false },
|
|
184
|
+
{ pubkey: globalVolumeAccumulator, isSigner: false, isWritable: true },
|
|
185
|
+
{ pubkey: userVolumeAccumulator, isSigner: false, isWritable: true },
|
|
186
|
+
{ pubkey: feeConfig, isSigner: false, isWritable: false },
|
|
187
|
+
{ pubkey: PUMP_FEE_PROGRAM, isSigner: false, isWritable: false },
|
|
188
|
+
],
|
|
189
|
+
data,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Build a PumpSwap AMM SELL instruction.
|
|
194
|
+
*
|
|
195
|
+
* sell(base_amount_in, min_quote_amount_out)
|
|
196
|
+
*/
|
|
197
|
+
function buildSellInstruction(pool, poolState, user, baseAmountIn, minQuoteAmountOut, baseTokenProgram, quoteTokenProgram) {
|
|
198
|
+
const userBaseTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.baseMint, user, false, baseTokenProgram);
|
|
199
|
+
const userQuoteTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, user, false, quoteTokenProgram);
|
|
200
|
+
const protocolFeeRecipient = randomProtocolFeeRecipient();
|
|
201
|
+
const protocolFeeRecipientTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, protocolFeeRecipient, true, quoteTokenProgram);
|
|
202
|
+
const coinCreatorVaultAuthority = getCreatorVaultAuthorityPda(poolState.coinCreator);
|
|
203
|
+
const coinCreatorVaultAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, coinCreatorVaultAuthority, true, quoteTokenProgram);
|
|
204
|
+
const eventAuthority = getEventAuthorityPda();
|
|
205
|
+
const feeConfig = getFeeConfigPda();
|
|
206
|
+
// Encode args: base_amount_in (u64) + min_quote_amount_out (u64)
|
|
207
|
+
const data = Buffer.alloc(8 + 8 + 8);
|
|
208
|
+
SELL_DISCRIMINATOR.copy(data, 0);
|
|
209
|
+
data.writeBigUInt64LE(BigInt(baseAmountIn.toString()), 8);
|
|
210
|
+
data.writeBigUInt64LE(BigInt(minQuoteAmountOut.toString()), 16);
|
|
211
|
+
return new web3_js_1.TransactionInstruction({
|
|
212
|
+
programId: PUMP_AMM_PROGRAM_ID,
|
|
213
|
+
keys: [
|
|
214
|
+
{ pubkey: pool, isSigner: false, isWritable: true },
|
|
215
|
+
{ pubkey: user, isSigner: true, isWritable: true },
|
|
216
|
+
{ pubkey: PUMP_AMM_GLOBAL_CONFIG, isSigner: false, isWritable: false },
|
|
217
|
+
{ pubkey: poolState.baseMint, isSigner: false, isWritable: false },
|
|
218
|
+
{ pubkey: poolState.quoteMint, isSigner: false, isWritable: false },
|
|
219
|
+
{ pubkey: userBaseTokenAccount, isSigner: false, isWritable: true },
|
|
220
|
+
{ pubkey: userQuoteTokenAccount, isSigner: false, isWritable: true },
|
|
221
|
+
{ pubkey: poolState.poolBaseTokenAccount, isSigner: false, isWritable: true },
|
|
222
|
+
{ pubkey: poolState.poolQuoteTokenAccount, isSigner: false, isWritable: true },
|
|
223
|
+
{ pubkey: protocolFeeRecipient, isSigner: false, isWritable: false },
|
|
224
|
+
{ pubkey: protocolFeeRecipientTokenAccount, isSigner: false, isWritable: true },
|
|
225
|
+
{ pubkey: baseTokenProgram, isSigner: false, isWritable: false },
|
|
226
|
+
{ pubkey: quoteTokenProgram, isSigner: false, isWritable: false },
|
|
227
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
|
|
228
|
+
{ pubkey: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
229
|
+
{ pubkey: eventAuthority, isSigner: false, isWritable: false },
|
|
230
|
+
{ pubkey: PUMP_AMM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
231
|
+
{ pubkey: coinCreatorVaultAta, isSigner: false, isWritable: true },
|
|
232
|
+
{ pubkey: coinCreatorVaultAuthority, isSigner: false, isWritable: false },
|
|
233
|
+
{ pubkey: feeConfig, isSigner: false, isWritable: false },
|
|
234
|
+
{ pubkey: PUMP_FEE_PROGRAM, isSigner: false, isWritable: false },
|
|
235
|
+
],
|
|
236
|
+
data,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Build a PumpSwap AMM CREATE_POOL instruction.
|
|
241
|
+
*
|
|
242
|
+
* create_pool(index, base_amount_in, quote_amount_in, coin_creator, is_mayhem_mode, is_cashback_coin)
|
|
243
|
+
*/
|
|
244
|
+
function buildCreatePoolInstruction(creator, baseMint, quoteMint, index, baseAmountIn, quoteAmountIn, coinCreator, baseTokenProgram, quoteTokenProgram) {
|
|
245
|
+
const pool = getPoolPda(index, creator, baseMint, quoteMint);
|
|
246
|
+
const lpMint = getLpMintPda(pool);
|
|
247
|
+
const userBaseTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(baseMint, creator, false, baseTokenProgram);
|
|
248
|
+
const userQuoteTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(quoteMint, creator, false, quoteTokenProgram);
|
|
249
|
+
// LP mint uses Token-2022
|
|
250
|
+
const userPoolTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(lpMint, creator, false, spl_token_1.TOKEN_2022_PROGRAM_ID);
|
|
251
|
+
const poolBaseTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(baseMint, pool, true, baseTokenProgram);
|
|
252
|
+
const poolQuoteTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(quoteMint, pool, true, quoteTokenProgram);
|
|
253
|
+
const eventAuthority = getEventAuthorityPda();
|
|
254
|
+
// Encode args:
|
|
255
|
+
// index: u16
|
|
256
|
+
// base_amount_in: u64
|
|
257
|
+
// quote_amount_in: u64
|
|
258
|
+
// coin_creator: pubkey (32 bytes)
|
|
259
|
+
// is_mayhem_mode: bool (1 byte)
|
|
260
|
+
// is_cashback_coin: OptionBool (1 byte, None = 0)
|
|
261
|
+
const data = Buffer.alloc(8 + 2 + 8 + 8 + 32 + 1 + 1);
|
|
262
|
+
let offset = 0;
|
|
263
|
+
CREATE_POOL_DISCRIMINATOR.copy(data, offset);
|
|
264
|
+
offset += 8;
|
|
265
|
+
data.writeUInt16LE(index, offset);
|
|
266
|
+
offset += 2;
|
|
267
|
+
data.writeBigUInt64LE(BigInt(baseAmountIn.toString()), offset);
|
|
268
|
+
offset += 8;
|
|
269
|
+
data.writeBigUInt64LE(BigInt(quoteAmountIn.toString()), offset);
|
|
270
|
+
offset += 8;
|
|
271
|
+
coinCreator.toBuffer().copy(data, offset);
|
|
272
|
+
offset += 32;
|
|
273
|
+
data.writeUInt8(0, offset);
|
|
274
|
+
offset += 1; // is_mayhem_mode = false
|
|
275
|
+
data.writeUInt8(0, offset);
|
|
276
|
+
offset += 1; // is_cashback_coin = None
|
|
277
|
+
return new web3_js_1.TransactionInstruction({
|
|
278
|
+
programId: PUMP_AMM_PROGRAM_ID,
|
|
279
|
+
keys: [
|
|
280
|
+
{ pubkey: pool, isSigner: false, isWritable: true },
|
|
281
|
+
{ pubkey: PUMP_AMM_GLOBAL_CONFIG, isSigner: false, isWritable: false },
|
|
282
|
+
{ pubkey: creator, isSigner: true, isWritable: true },
|
|
283
|
+
{ pubkey: baseMint, isSigner: false, isWritable: false },
|
|
284
|
+
{ pubkey: quoteMint, isSigner: false, isWritable: false },
|
|
285
|
+
{ pubkey: lpMint, isSigner: false, isWritable: true },
|
|
286
|
+
{ pubkey: userBaseTokenAccount, isSigner: false, isWritable: true },
|
|
287
|
+
{ pubkey: userQuoteTokenAccount, isSigner: false, isWritable: true },
|
|
288
|
+
{ pubkey: userPoolTokenAccount, isSigner: false, isWritable: true },
|
|
289
|
+
{ pubkey: poolBaseTokenAccount, isSigner: false, isWritable: true },
|
|
290
|
+
{ pubkey: poolQuoteTokenAccount, isSigner: false, isWritable: true },
|
|
291
|
+
{ pubkey: web3_js_1.SystemProgram.programId, isSigner: false, isWritable: false },
|
|
292
|
+
{ pubkey: spl_token_1.TOKEN_2022_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
293
|
+
{ pubkey: baseTokenProgram, isSigner: false, isWritable: false },
|
|
294
|
+
{ pubkey: quoteTokenProgram, isSigner: false, isWritable: false },
|
|
295
|
+
{ pubkey: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
296
|
+
{ pubkey: eventAuthority, isSigner: false, isWritable: false },
|
|
297
|
+
{ pubkey: PUMP_AMM_PROGRAM_ID, isSigner: false, isWritable: false },
|
|
298
|
+
],
|
|
299
|
+
data,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
// AMM math (constant product)
|
|
304
|
+
// ---------------------------------------------------------------------------
|
|
305
|
+
/**
|
|
306
|
+
* Calculate base tokens out for a given quote input on AMM.
|
|
307
|
+
* Constant product: base_out = (base_reserves * quote_in) / (quote_reserves + quote_in)
|
|
308
|
+
* Fees: LP fee 20 bps + protocol fee 5 bps = 25 bps total.
|
|
309
|
+
* Fee is deducted from quote input before the swap.
|
|
310
|
+
*/
|
|
311
|
+
function calculateBuyBaseOut(baseReserves, quoteReserves, quoteAmountIn) {
|
|
312
|
+
// Total fee: 25 bps (0.25%)
|
|
313
|
+
const feeNumerator = 25n;
|
|
314
|
+
const feeDenominator = 10000n;
|
|
315
|
+
const fee = (quoteAmountIn * feeNumerator) / feeDenominator;
|
|
316
|
+
const netQuote = quoteAmountIn - fee;
|
|
317
|
+
return (baseReserves * netQuote) / (quoteReserves + netQuote);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Calculate quote output for a given base input on AMM.
|
|
321
|
+
*/
|
|
322
|
+
function calculateSellQuoteOut(baseReserves, quoteReserves, baseAmountIn) {
|
|
323
|
+
const grossQuote = (quoteReserves * baseAmountIn) / (baseReserves + baseAmountIn);
|
|
324
|
+
// Total fee: 25 bps deducted from quote output
|
|
325
|
+
const feeNumerator = 25n;
|
|
326
|
+
const feeDenominator = 10000n;
|
|
327
|
+
const fee = (grossQuote * feeNumerator) / feeDenominator;
|
|
328
|
+
return grossQuote - fee;
|
|
329
|
+
}
|
|
330
|
+
// ---------------------------------------------------------------------------
|
|
331
|
+
// Adapter
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
class PumpFunAmmAdapter {
|
|
334
|
+
name = "pumpfun-amm";
|
|
335
|
+
protocol = "pump-amm";
|
|
336
|
+
capabilities = (0, types_1.defaultCapabilities)({
|
|
337
|
+
canBuy: true,
|
|
338
|
+
canSell: true,
|
|
339
|
+
canSnipe: true,
|
|
340
|
+
canGetPrice: true,
|
|
341
|
+
});
|
|
342
|
+
// ----- Core: buy -----
|
|
343
|
+
async buy(params) {
|
|
344
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
345
|
+
const { amountSol, poolAddress, opts } = params;
|
|
346
|
+
const connection = (0, config_1.getConnection)();
|
|
347
|
+
const wallet = (0, config_1.getWallet)();
|
|
348
|
+
if (!poolAddress)
|
|
349
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, types_1.WSOL_MINT);
|
|
350
|
+
const poolPk = new web3_js_1.PublicKey(poolAddress);
|
|
351
|
+
// Fetch pool state
|
|
352
|
+
const accountInfo = await connection.getAccountInfo(poolPk);
|
|
353
|
+
if (!accountInfo)
|
|
354
|
+
throw new Error(`Pool not found: ${poolAddress}`);
|
|
355
|
+
const poolState = deserializePool(accountInfo.data);
|
|
356
|
+
// Detect token programs
|
|
357
|
+
const baseTokenProgram = await detectTokenProgram(poolState.baseMint);
|
|
358
|
+
const quoteTokenProgram = poolState.quoteMint.toBase58() === types_1.WSOL_MINT
|
|
359
|
+
? spl_token_1.TOKEN_PROGRAM_ID
|
|
360
|
+
: await detectTokenProgram(poolState.quoteMint);
|
|
361
|
+
// Read pool reserves
|
|
362
|
+
const [baseBalance, quoteBalance] = await Promise.all([
|
|
363
|
+
connection.getTokenAccountBalance(poolState.poolBaseTokenAccount),
|
|
364
|
+
connection.getTokenAccountBalance(poolState.poolQuoteTokenAccount),
|
|
365
|
+
]);
|
|
366
|
+
const baseReserves = BigInt(baseBalance.value.amount);
|
|
367
|
+
const quoteReserves = BigInt(quoteBalance.value.amount);
|
|
368
|
+
const quoteAmountIn = BigInt(Math.floor(amountSol * web3_js_1.LAMPORTS_PER_SOL));
|
|
369
|
+
const baseAmountOut = calculateBuyBaseOut(baseReserves, quoteReserves, quoteAmountIn);
|
|
370
|
+
if (baseAmountOut === 0n)
|
|
371
|
+
throw new Error("Buy amount too small — would receive 0 tokens");
|
|
372
|
+
const computeLimit = opts?.computeUnitLimit ?? types_1.DEFAULT_COMPUTE_UNIT_LIMIT;
|
|
373
|
+
const priorityFee = opts?.priorityFeeMicroLamports ?? types_1.DEFAULT_PRIORITY_FEE_MICRO_LAMPORTS;
|
|
374
|
+
// Ensure user has ATAs for both base and quote tokens
|
|
375
|
+
const userBaseAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.baseMint, wallet.publicKey, false, baseTokenProgram);
|
|
376
|
+
const userQuoteAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, wallet.publicKey, false, quoteTokenProgram);
|
|
377
|
+
const createBaseAta = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, userBaseAta, wallet.publicKey, poolState.baseMint, baseTokenProgram);
|
|
378
|
+
const createQuoteAta = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, userQuoteAta, wallet.publicKey, poolState.quoteMint, quoteTokenProgram);
|
|
379
|
+
// max_quote_amount_in with 30% slippage buffer (AMM fee rounding + price movement)
|
|
380
|
+
const maxQuoteAmountIn = quoteAmountIn + quoteAmountIn * 30n / 100n;
|
|
381
|
+
// For WSOL: need to wrap SOL into the WSOL ATA (wrap max to cover slippage buffer)
|
|
382
|
+
const wrapIxs = [];
|
|
383
|
+
if (poolState.quoteMint.toBase58() === types_1.WSOL_MINT) {
|
|
384
|
+
wrapIxs.push(web3_js_1.SystemProgram.transfer({
|
|
385
|
+
fromPubkey: wallet.publicKey,
|
|
386
|
+
toPubkey: userQuoteAta,
|
|
387
|
+
lamports: maxQuoteAmountIn,
|
|
388
|
+
}),
|
|
389
|
+
// syncNative to update WSOL balance
|
|
390
|
+
new web3_js_1.TransactionInstruction({
|
|
391
|
+
programId: spl_token_1.TOKEN_PROGRAM_ID,
|
|
392
|
+
keys: [{ pubkey: userQuoteAta, isSigner: false, isWritable: true }],
|
|
393
|
+
data: Buffer.from([17]), // SyncNative instruction
|
|
394
|
+
}));
|
|
395
|
+
}
|
|
396
|
+
const buyIx = buildBuyInstruction(poolPk, poolState, wallet.publicKey, new bn_js_1.default(baseAmountOut.toString()), new bn_js_1.default(maxQuoteAmountIn.toString()), baseTokenProgram, quoteTokenProgram);
|
|
397
|
+
// Close WSOL ATA after swap to recover SOL
|
|
398
|
+
const closeIxs = [];
|
|
399
|
+
if (poolState.quoteMint.toBase58() === types_1.WSOL_MINT) {
|
|
400
|
+
closeIxs.push(new web3_js_1.TransactionInstruction({
|
|
401
|
+
programId: spl_token_1.TOKEN_PROGRAM_ID,
|
|
402
|
+
keys: [
|
|
403
|
+
{ pubkey: userQuoteAta, isSigner: false, isWritable: true },
|
|
404
|
+
{ pubkey: wallet.publicKey, isSigner: false, isWritable: true },
|
|
405
|
+
{ pubkey: wallet.publicKey, isSigner: true, isWritable: false },
|
|
406
|
+
],
|
|
407
|
+
data: Buffer.from([9]), // CloseAccount instruction
|
|
408
|
+
}));
|
|
409
|
+
}
|
|
410
|
+
const ixs = [
|
|
411
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: computeLimit }),
|
|
412
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }),
|
|
413
|
+
createBaseAta,
|
|
414
|
+
createQuoteAta,
|
|
415
|
+
...wrapIxs,
|
|
416
|
+
buyIx,
|
|
417
|
+
...closeIxs,
|
|
418
|
+
];
|
|
419
|
+
const result = await (0, send_rpc_1.sendAndConfirmVtx)(connection, ixs, wallet);
|
|
420
|
+
const baseDecimals = baseBalance.value.decimals;
|
|
421
|
+
return {
|
|
422
|
+
txSignature: result.txSignature,
|
|
423
|
+
confirmed: result.confirmed,
|
|
424
|
+
amountIn: amountSol,
|
|
425
|
+
amountInToken: "SOL",
|
|
426
|
+
amountOut: Number(baseAmountOut) / Math.pow(10, baseDecimals),
|
|
427
|
+
amountOutToken: poolState.baseMint.toBase58(),
|
|
428
|
+
dex: this.name,
|
|
429
|
+
poolAddress,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
// ----- Core: sell -----
|
|
433
|
+
async sell(params) {
|
|
434
|
+
const tokenMint = (0, types_1.requireTokenMint)(params, this.name);
|
|
435
|
+
const { percentage, poolAddress, opts } = params;
|
|
436
|
+
const connection = (0, config_1.getConnection)();
|
|
437
|
+
const wallet = (0, config_1.getWallet)();
|
|
438
|
+
if (!poolAddress)
|
|
439
|
+
throw new types_1.PoolNotFoundError(this.name, tokenMint, types_1.WSOL_MINT);
|
|
440
|
+
const poolPk = new web3_js_1.PublicKey(poolAddress);
|
|
441
|
+
// Fetch pool state
|
|
442
|
+
const accountInfo = await connection.getAccountInfo(poolPk);
|
|
443
|
+
if (!accountInfo)
|
|
444
|
+
throw new Error(`Pool not found: ${poolAddress}`);
|
|
445
|
+
const poolState = deserializePool(accountInfo.data);
|
|
446
|
+
const baseTokenProgram = await detectTokenProgram(poolState.baseMint);
|
|
447
|
+
const quoteTokenProgram = poolState.quoteMint.toBase58() === types_1.WSOL_MINT
|
|
448
|
+
? spl_token_1.TOKEN_PROGRAM_ID
|
|
449
|
+
: await detectTokenProgram(poolState.quoteMint);
|
|
450
|
+
// Get user's base token balance
|
|
451
|
+
const userBaseAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.baseMint, wallet.publicKey, false, baseTokenProgram);
|
|
452
|
+
const tokenAccount = await (0, spl_token_1.getAccount)(connection, userBaseAta, "confirmed", baseTokenProgram);
|
|
453
|
+
const sellAmount = BigInt(Math.floor((Number(tokenAccount.amount) * percentage) / 100));
|
|
454
|
+
if (sellAmount === 0n)
|
|
455
|
+
throw new Error(`No balance to sell for ${tokenMint}`);
|
|
456
|
+
const computeLimit = opts?.computeUnitLimit ?? types_1.DEFAULT_COMPUTE_UNIT_LIMIT;
|
|
457
|
+
const priorityFee = opts?.priorityFeeMicroLamports ?? types_1.DEFAULT_PRIORITY_FEE_MICRO_LAMPORTS;
|
|
458
|
+
// Ensure user has quote ATA (for receiving SOL/WSOL)
|
|
459
|
+
const userQuoteAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, wallet.publicKey, false, quoteTokenProgram);
|
|
460
|
+
const createQuoteAta = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, userQuoteAta, wallet.publicKey, poolState.quoteMint, quoteTokenProgram);
|
|
461
|
+
const sellIx = buildSellInstruction(poolPk, poolState, wallet.publicKey, new bn_js_1.default(sellAmount.toString()), new bn_js_1.default(0), // min_quote_amount_out = 0 (no slippage protection)
|
|
462
|
+
baseTokenProgram, quoteTokenProgram);
|
|
463
|
+
// Close WSOL ATA to unwrap SOL
|
|
464
|
+
const closeIxs = [];
|
|
465
|
+
if (poolState.quoteMint.toBase58() === types_1.WSOL_MINT) {
|
|
466
|
+
closeIxs.push(new web3_js_1.TransactionInstruction({
|
|
467
|
+
programId: spl_token_1.TOKEN_PROGRAM_ID,
|
|
468
|
+
keys: [
|
|
469
|
+
{ pubkey: userQuoteAta, isSigner: false, isWritable: true },
|
|
470
|
+
{ pubkey: wallet.publicKey, isSigner: false, isWritable: true },
|
|
471
|
+
{ pubkey: wallet.publicKey, isSigner: true, isWritable: false },
|
|
472
|
+
],
|
|
473
|
+
data: Buffer.from([9]), // CloseAccount instruction
|
|
474
|
+
}));
|
|
475
|
+
}
|
|
476
|
+
const ixs = [
|
|
477
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: computeLimit }),
|
|
478
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }),
|
|
479
|
+
createQuoteAta,
|
|
480
|
+
sellIx,
|
|
481
|
+
...closeIxs,
|
|
482
|
+
];
|
|
483
|
+
const result = await (0, send_rpc_1.sendAndConfirmVtx)(connection, ixs, wallet);
|
|
484
|
+
// Human-readable sell amount
|
|
485
|
+
let tokenDecimals = PUMP_TOKEN_DECIMALS;
|
|
486
|
+
try {
|
|
487
|
+
const mintData = await connection.getTokenSupply(poolState.baseMint);
|
|
488
|
+
tokenDecimals = mintData.value.decimals;
|
|
489
|
+
}
|
|
490
|
+
catch { /* fallback to 6 */ }
|
|
491
|
+
const humanSellAmount = Number(sellAmount) / Math.pow(10, tokenDecimals);
|
|
492
|
+
return {
|
|
493
|
+
txSignature: result.txSignature,
|
|
494
|
+
confirmed: result.confirmed,
|
|
495
|
+
amountIn: humanSellAmount,
|
|
496
|
+
amountInToken: tokenMint,
|
|
497
|
+
dex: this.name,
|
|
498
|
+
poolAddress,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
// ----- Snipe -----
|
|
502
|
+
async snipe(params) {
|
|
503
|
+
const { tokenMint, amountSol, poolAddress, tipSol, opts } = params;
|
|
504
|
+
const connection = (0, config_1.getConnection)();
|
|
505
|
+
const wallet = (0, config_1.getWallet)();
|
|
506
|
+
const poolPk = new web3_js_1.PublicKey(poolAddress);
|
|
507
|
+
const accountInfo = await connection.getAccountInfo(poolPk);
|
|
508
|
+
if (!accountInfo)
|
|
509
|
+
throw new Error(`Pool not found: ${poolAddress}`);
|
|
510
|
+
const poolState = deserializePool(accountInfo.data);
|
|
511
|
+
const baseTokenProgram = await detectTokenProgram(poolState.baseMint);
|
|
512
|
+
const quoteTokenProgram = poolState.quoteMint.toBase58() === types_1.WSOL_MINT
|
|
513
|
+
? spl_token_1.TOKEN_PROGRAM_ID
|
|
514
|
+
: await detectTokenProgram(poolState.quoteMint);
|
|
515
|
+
// Read pool reserves
|
|
516
|
+
const [baseBalance, quoteBalance] = await Promise.all([
|
|
517
|
+
connection.getTokenAccountBalance(poolState.poolBaseTokenAccount),
|
|
518
|
+
connection.getTokenAccountBalance(poolState.poolQuoteTokenAccount),
|
|
519
|
+
]);
|
|
520
|
+
const baseReserves = BigInt(baseBalance.value.amount);
|
|
521
|
+
const quoteReserves = BigInt(quoteBalance.value.amount);
|
|
522
|
+
const quoteAmountIn = BigInt(Math.floor(amountSol * web3_js_1.LAMPORTS_PER_SOL));
|
|
523
|
+
const baseAmountOut = calculateBuyBaseOut(baseReserves, quoteReserves, quoteAmountIn);
|
|
524
|
+
const computeLimit = opts?.computeUnitLimit ?? types_1.DEFAULT_COMPUTE_UNIT_LIMIT;
|
|
525
|
+
const priorityFee = opts?.priorityFeeMicroLamports ?? 40_000_000;
|
|
526
|
+
const userBaseAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.baseMint, wallet.publicKey, false, baseTokenProgram);
|
|
527
|
+
const userQuoteAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.quoteMint, wallet.publicKey, false, quoteTokenProgram);
|
|
528
|
+
const createBaseAta = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, userBaseAta, wallet.publicKey, poolState.baseMint, baseTokenProgram);
|
|
529
|
+
const createQuoteAta = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(wallet.publicKey, userQuoteAta, wallet.publicKey, poolState.quoteMint, quoteTokenProgram);
|
|
530
|
+
// max_quote_amount_in with 30% slippage buffer
|
|
531
|
+
const maxQuoteAmountIn = quoteAmountIn + quoteAmountIn * 30n / 100n;
|
|
532
|
+
// WSOL wrapping
|
|
533
|
+
const wrapIxs = [];
|
|
534
|
+
if (poolState.quoteMint.toBase58() === types_1.WSOL_MINT) {
|
|
535
|
+
wrapIxs.push(web3_js_1.SystemProgram.transfer({
|
|
536
|
+
fromPubkey: wallet.publicKey,
|
|
537
|
+
toPubkey: userQuoteAta,
|
|
538
|
+
lamports: maxQuoteAmountIn,
|
|
539
|
+
}), new web3_js_1.TransactionInstruction({
|
|
540
|
+
programId: spl_token_1.TOKEN_PROGRAM_ID,
|
|
541
|
+
keys: [{ pubkey: userQuoteAta, isSigner: false, isWritable: true }],
|
|
542
|
+
data: Buffer.from([17]), // SyncNative
|
|
543
|
+
}));
|
|
544
|
+
}
|
|
545
|
+
const buyIx = buildBuyInstruction(poolPk, poolState, wallet.publicKey, new bn_js_1.default(baseAmountOut.toString()), new bn_js_1.default(maxQuoteAmountIn.toString()), baseTokenProgram, quoteTokenProgram);
|
|
546
|
+
const ixs = [
|
|
547
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: computeLimit }),
|
|
548
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }),
|
|
549
|
+
createBaseAta,
|
|
550
|
+
createQuoteAta,
|
|
551
|
+
...wrapIxs,
|
|
552
|
+
buyIx,
|
|
553
|
+
];
|
|
554
|
+
const blockhash = await connection.getLatestBlockhash();
|
|
555
|
+
const results = await (0, landing_1.landTransaction)(ixs, wallet, blockhash, {
|
|
556
|
+
dex: this.name,
|
|
557
|
+
operation: "snipe",
|
|
558
|
+
tipSol,
|
|
559
|
+
});
|
|
560
|
+
const accepted = results.find((r) => r.accepted);
|
|
561
|
+
return {
|
|
562
|
+
txSignature: accepted?.signature ?? "",
|
|
563
|
+
confirmed: !!accepted?.accepted,
|
|
564
|
+
amountIn: amountSol,
|
|
565
|
+
amountInToken: "SOL",
|
|
566
|
+
dex: this.name,
|
|
567
|
+
poolAddress,
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
// ----- buildSwapIxs -----
|
|
571
|
+
async buildSwapIxs(params) {
|
|
572
|
+
const connection = (0, config_1.getConnection)();
|
|
573
|
+
const wallet = (0, config_1.getWallet)();
|
|
574
|
+
if ("percentage" in params) {
|
|
575
|
+
const p = params;
|
|
576
|
+
if (!p.poolAddress)
|
|
577
|
+
throw new Error("poolAddress required for pumpfun-amm buildSwapIxs");
|
|
578
|
+
const poolPk = new web3_js_1.PublicKey(p.poolAddress);
|
|
579
|
+
const accountInfo = await connection.getAccountInfo(poolPk);
|
|
580
|
+
if (!accountInfo)
|
|
581
|
+
throw new Error("Pool not found");
|
|
582
|
+
const poolState = deserializePool(accountInfo.data);
|
|
583
|
+
const baseTokenProgram = await detectTokenProgram(poolState.baseMint);
|
|
584
|
+
const quoteTokenProgram = poolState.quoteMint.toBase58() === types_1.WSOL_MINT
|
|
585
|
+
? spl_token_1.TOKEN_PROGRAM_ID : await detectTokenProgram(poolState.quoteMint);
|
|
586
|
+
const userBaseAta = (0, spl_token_1.getAssociatedTokenAddressSync)(poolState.baseMint, wallet.publicKey, false, baseTokenProgram);
|
|
587
|
+
const tokenAccount = await (0, spl_token_1.getAccount)(connection, userBaseAta, "confirmed", baseTokenProgram);
|
|
588
|
+
const sellAmount = BigInt(Math.floor((Number(tokenAccount.amount) * p.percentage) / 100));
|
|
589
|
+
const sellIx = buildSellInstruction(poolPk, poolState, wallet.publicKey, new bn_js_1.default(sellAmount.toString()), new bn_js_1.default(0), baseTokenProgram, quoteTokenProgram);
|
|
590
|
+
return { instructions: [sellIx], signers: [] };
|
|
591
|
+
}
|
|
592
|
+
// Buy
|
|
593
|
+
const p = params;
|
|
594
|
+
if (!p.poolAddress)
|
|
595
|
+
throw new Error("poolAddress required for pumpfun-amm buildSwapIxs");
|
|
596
|
+
const poolPk = new web3_js_1.PublicKey(p.poolAddress);
|
|
597
|
+
const accountInfo = await connection.getAccountInfo(poolPk);
|
|
598
|
+
if (!accountInfo)
|
|
599
|
+
throw new Error("Pool not found");
|
|
600
|
+
const poolState = deserializePool(accountInfo.data);
|
|
601
|
+
const baseTokenProgram = await detectTokenProgram(poolState.baseMint);
|
|
602
|
+
const quoteTokenProgram = poolState.quoteMint.toBase58() === types_1.WSOL_MINT
|
|
603
|
+
? spl_token_1.TOKEN_PROGRAM_ID : await detectTokenProgram(poolState.quoteMint);
|
|
604
|
+
const [baseBalance, quoteBalance] = await Promise.all([
|
|
605
|
+
connection.getTokenAccountBalance(poolState.poolBaseTokenAccount),
|
|
606
|
+
connection.getTokenAccountBalance(poolState.poolQuoteTokenAccount),
|
|
607
|
+
]);
|
|
608
|
+
const quoteAmountIn = BigInt(Math.floor(p.amountSol * web3_js_1.LAMPORTS_PER_SOL));
|
|
609
|
+
const baseAmountOut = calculateBuyBaseOut(BigInt(baseBalance.value.amount), BigInt(quoteBalance.value.amount), quoteAmountIn);
|
|
610
|
+
// 30% slippage buffer on max_quote_amount_in
|
|
611
|
+
const maxQuoteIn = quoteAmountIn + quoteAmountIn * 30n / 100n;
|
|
612
|
+
const buyIx = buildBuyInstruction(poolPk, poolState, wallet.publicKey, new bn_js_1.default(baseAmountOut.toString()), new bn_js_1.default(maxQuoteIn.toString()), baseTokenProgram, quoteTokenProgram);
|
|
613
|
+
return { instructions: [buyIx], signers: [] };
|
|
614
|
+
}
|
|
615
|
+
// ----- getPrice -----
|
|
616
|
+
async getPrice(poolAddress) {
|
|
617
|
+
const connection = (0, config_1.getConnection)();
|
|
618
|
+
const poolPk = new web3_js_1.PublicKey(poolAddress);
|
|
619
|
+
const accountInfo = await connection.getAccountInfo(poolPk);
|
|
620
|
+
if (!accountInfo)
|
|
621
|
+
throw new Error(`Pool not found: ${poolAddress}`);
|
|
622
|
+
const poolState = deserializePool(accountInfo.data);
|
|
623
|
+
// Read pool reserves for price calculation
|
|
624
|
+
const [baseBalance, quoteBalance] = await Promise.all([
|
|
625
|
+
connection.getTokenAccountBalance(poolState.poolBaseTokenAccount),
|
|
626
|
+
connection.getTokenAccountBalance(poolState.poolQuoteTokenAccount),
|
|
627
|
+
]);
|
|
628
|
+
const baseReserves = Number(baseBalance.value.amount);
|
|
629
|
+
const quoteReserves = Number(quoteBalance.value.amount);
|
|
630
|
+
const baseDecimals = baseBalance.value.decimals;
|
|
631
|
+
const quoteDecimals = quoteBalance.value.decimals;
|
|
632
|
+
// Price = (quoteReserves / 10^quoteDecimals) / (baseReserves / 10^baseDecimals)
|
|
633
|
+
const price = (quoteReserves / Math.pow(10, quoteDecimals)) /
|
|
634
|
+
(baseReserves / Math.pow(10, baseDecimals));
|
|
635
|
+
return {
|
|
636
|
+
price,
|
|
637
|
+
baseMint: poolState.baseMint.toBase58(),
|
|
638
|
+
quoteMint: poolState.quoteMint.toBase58(),
|
|
639
|
+
source: "on-chain",
|
|
640
|
+
poolAddress,
|
|
641
|
+
timestamp: Date.now(),
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
// ----- Create pool -----
|
|
645
|
+
/**
|
|
646
|
+
* Create a new PumpSwap AMM pool with initial liquidity.
|
|
647
|
+
*
|
|
648
|
+
* @param baseMint - Base token mint address
|
|
649
|
+
* @param quoteMint - Quote token mint address (usually WSOL)
|
|
650
|
+
* @param baseAmountIn - Amount of base tokens to deposit (human-readable)
|
|
651
|
+
* @param quoteAmountIn - Amount of quote tokens to deposit (human-readable)
|
|
652
|
+
* @param index - Pool index (default: 1; 0 is reserved for canonical pump pools)
|
|
653
|
+
* @returns TxResult with pool address
|
|
654
|
+
*/
|
|
655
|
+
async createPool(baseMint, quoteMint, baseAmountIn, quoteAmountIn, index = 1) {
|
|
656
|
+
const connection = (0, config_1.getConnection)();
|
|
657
|
+
const wallet = (0, config_1.getWallet)();
|
|
658
|
+
const baseMintPk = new web3_js_1.PublicKey(baseMint);
|
|
659
|
+
const quoteMintPk = new web3_js_1.PublicKey(quoteMint);
|
|
660
|
+
const baseTokenProgram = await detectTokenProgram(baseMintPk);
|
|
661
|
+
const quoteTokenProgram = quoteMintPk.toBase58() === types_1.WSOL_MINT
|
|
662
|
+
? spl_token_1.TOKEN_PROGRAM_ID : await detectTokenProgram(quoteMintPk);
|
|
663
|
+
// Get decimals for amount conversion
|
|
664
|
+
const [baseMintInfo, quoteMintInfo] = await Promise.all([
|
|
665
|
+
connection.getTokenSupply(baseMintPk),
|
|
666
|
+
connection.getTokenSupply(quoteMintPk),
|
|
667
|
+
]);
|
|
668
|
+
const baseRaw = new bn_js_1.default(Math.floor(baseAmountIn * Math.pow(10, baseMintInfo.value.decimals)).toString());
|
|
669
|
+
const quoteRaw = new bn_js_1.default(Math.floor(quoteAmountIn * Math.pow(10, quoteMintInfo.value.decimals)).toString());
|
|
670
|
+
const createPoolIx = buildCreatePoolInstruction(wallet.publicKey, baseMintPk, quoteMintPk, index, baseRaw, quoteRaw, wallet.publicKey, // coin_creator = wallet
|
|
671
|
+
baseTokenProgram, quoteTokenProgram);
|
|
672
|
+
const ixs = [
|
|
673
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: types_1.DEFAULT_COMPUTE_UNIT_LIMIT }),
|
|
674
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: types_1.DEFAULT_PRIORITY_FEE_MICRO_LAMPORTS }),
|
|
675
|
+
createPoolIx,
|
|
676
|
+
];
|
|
677
|
+
const result = await (0, send_rpc_1.sendAndConfirmVtx)(connection, ixs, wallet);
|
|
678
|
+
const poolPda = getPoolPda(index, wallet.publicKey, baseMintPk, quoteMintPk);
|
|
679
|
+
return {
|
|
680
|
+
txSignature: result.txSignature,
|
|
681
|
+
confirmed: result.confirmed,
|
|
682
|
+
poolAddress: poolPda.toBase58(),
|
|
683
|
+
dex: this.name,
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
exports.PumpFunAmmAdapter = PumpFunAmmAdapter;
|
|
688
|
+
// ---------------------------------------------------------------------------
|
|
689
|
+
// Auto-register
|
|
690
|
+
// ---------------------------------------------------------------------------
|
|
691
|
+
(0, index_1.registerAdapter)(new PumpFunAmmAdapter());
|
|
692
|
+
//# sourceMappingURL=pumpfun-amm.js.map
|