forgex-cli 1.0.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.
Files changed (275) hide show
  1. package/README.md +479 -0
  2. package/dist/bin/forgex.d.ts +12 -0
  3. package/dist/bin/forgex.d.ts.map +1 -0
  4. package/dist/bin/forgex.js +23 -0
  5. package/dist/bin/forgex.js.map +1 -0
  6. package/dist/src/adapters/codex-adapter.d.ts +238 -0
  7. package/dist/src/adapters/codex-adapter.d.ts.map +1 -0
  8. package/dist/src/adapters/codex-adapter.js +524 -0
  9. package/dist/src/adapters/codex-adapter.js.map +1 -0
  10. package/dist/src/adapters/connection.d.ts +20 -0
  11. package/dist/src/adapters/connection.d.ts.map +1 -0
  12. package/dist/src/adapters/connection.js +43 -0
  13. package/dist/src/adapters/connection.js.map +1 -0
  14. package/dist/src/adapters/ipfs.d.ts +17 -0
  15. package/dist/src/adapters/ipfs.d.ts.map +1 -0
  16. package/dist/src/adapters/ipfs.js +30 -0
  17. package/dist/src/adapters/ipfs.js.map +1 -0
  18. package/dist/src/adapters/jito-adapter.d.ts +194 -0
  19. package/dist/src/adapters/jito-adapter.d.ts.map +1 -0
  20. package/dist/src/adapters/jito-adapter.js +474 -0
  21. package/dist/src/adapters/jito-adapter.js.map +1 -0
  22. package/dist/src/adapters/rpc-adapter.d.ts +148 -0
  23. package/dist/src/adapters/rpc-adapter.d.ts.map +1 -0
  24. package/dist/src/adapters/rpc-adapter.js +410 -0
  25. package/dist/src/adapters/rpc-adapter.js.map +1 -0
  26. package/dist/src/adapters/sdk-adapter.d.ts +148 -0
  27. package/dist/src/adapters/sdk-adapter.d.ts.map +1 -0
  28. package/dist/src/adapters/sdk-adapter.js +554 -0
  29. package/dist/src/adapters/sdk-adapter.js.map +1 -0
  30. package/dist/src/commands/config/index.d.ts +8 -0
  31. package/dist/src/commands/config/index.d.ts.map +1 -0
  32. package/dist/src/commands/config/index.js +91 -0
  33. package/dist/src/commands/config/index.js.map +1 -0
  34. package/dist/src/commands/query/index.d.ts +10 -0
  35. package/dist/src/commands/query/index.d.ts.map +1 -0
  36. package/dist/src/commands/query/index.js +376 -0
  37. package/dist/src/commands/query/index.js.map +1 -0
  38. package/dist/src/commands/sniper/index.d.ts +16 -0
  39. package/dist/src/commands/sniper/index.d.ts.map +1 -0
  40. package/dist/src/commands/sniper/index.js +292 -0
  41. package/dist/src/commands/sniper/index.js.map +1 -0
  42. package/dist/src/commands/token/index.d.ts +16 -0
  43. package/dist/src/commands/token/index.d.ts.map +1 -0
  44. package/dist/src/commands/token/index.js +295 -0
  45. package/dist/src/commands/token/index.js.map +1 -0
  46. package/dist/src/commands/tools/index.d.ts +17 -0
  47. package/dist/src/commands/tools/index.d.ts.map +1 -0
  48. package/dist/src/commands/tools/index.js +626 -0
  49. package/dist/src/commands/tools/index.js.map +1 -0
  50. package/dist/src/commands/trade/index.d.ts +8 -0
  51. package/dist/src/commands/trade/index.d.ts.map +1 -0
  52. package/dist/src/commands/trade/index.js +531 -0
  53. package/dist/src/commands/trade/index.js.map +1 -0
  54. package/dist/src/commands/transfer/index.d.ts +16 -0
  55. package/dist/src/commands/transfer/index.d.ts.map +1 -0
  56. package/dist/src/commands/transfer/index.js +509 -0
  57. package/dist/src/commands/transfer/index.js.map +1 -0
  58. package/dist/src/commands/wallet/index.d.ts +10 -0
  59. package/dist/src/commands/wallet/index.d.ts.map +1 -0
  60. package/dist/src/commands/wallet/index.js +828 -0
  61. package/dist/src/commands/wallet/index.js.map +1 -0
  62. package/dist/src/config.d.ts +74 -0
  63. package/dist/src/config.d.ts.map +1 -0
  64. package/dist/src/config.js +190 -0
  65. package/dist/src/config.js.map +1 -0
  66. package/dist/src/const/IDL/index.d.ts +4 -0
  67. package/dist/src/const/IDL/index.d.ts.map +1 -0
  68. package/dist/src/const/IDL/index.js +2 -0
  69. package/dist/src/const/IDL/index.js.map +1 -0
  70. package/dist/src/const/IDL/meteora-DLMM.d.ts +10249 -0
  71. package/dist/src/const/IDL/meteora-DLMM.d.ts.map +1 -0
  72. package/dist/src/const/IDL/meteora-DLMM.js +4177 -0
  73. package/dist/src/const/IDL/meteora-DLMM.js.map +1 -0
  74. package/dist/src/const/IDL/pump-fun.d.ts +4811 -0
  75. package/dist/src/const/IDL/pump-fun.d.ts.map +1 -0
  76. package/dist/src/const/IDL/pump-fun.js +2954 -0
  77. package/dist/src/const/IDL/pump-fun.js.map +1 -0
  78. package/dist/src/const/IDL/pump-swap-IDL.d.ts +3119 -0
  79. package/dist/src/const/IDL/pump-swap-IDL.d.ts.map +1 -0
  80. package/dist/src/const/IDL/pump-swap-IDL.js +2095 -0
  81. package/dist/src/const/IDL/pump-swap-IDL.js.map +1 -0
  82. package/dist/src/const/IDL/raydium-launchlab-IDL.d.ts +4031 -0
  83. package/dist/src/const/IDL/raydium-launchlab-IDL.d.ts.map +1 -0
  84. package/dist/src/const/IDL/raydium-launchlab-IDL.js +2110 -0
  85. package/dist/src/const/IDL/raydium-launchlab-IDL.js.map +1 -0
  86. package/dist/src/const/index.d.ts +40 -0
  87. package/dist/src/const/index.d.ts.map +1 -0
  88. package/dist/src/const/index.js +57 -0
  89. package/dist/src/const/index.js.map +1 -0
  90. package/dist/src/data-source.d.ts +270 -0
  91. package/dist/src/data-source.d.ts.map +1 -0
  92. package/dist/src/data-source.js +628 -0
  93. package/dist/src/data-source.js.map +1 -0
  94. package/dist/src/data-store/index.d.ts +87 -0
  95. package/dist/src/data-store/index.d.ts.map +1 -0
  96. package/dist/src/data-store/index.js +561 -0
  97. package/dist/src/data-store/index.js.map +1 -0
  98. package/dist/src/data-store/types.d.ts +91 -0
  99. package/dist/src/data-store/types.d.ts.map +1 -0
  100. package/dist/src/data-store/types.js +8 -0
  101. package/dist/src/data-store/types.js.map +1 -0
  102. package/dist/src/index.d.ts +8 -0
  103. package/dist/src/index.d.ts.map +1 -0
  104. package/dist/src/index.js +36 -0
  105. package/dist/src/index.js.map +1 -0
  106. package/dist/src/output.d.ts +52 -0
  107. package/dist/src/output.d.ts.map +1 -0
  108. package/dist/src/output.js +218 -0
  109. package/dist/src/output.js.map +1 -0
  110. package/dist/src/shims/store.d.ts +58 -0
  111. package/dist/src/shims/store.d.ts.map +1 -0
  112. package/dist/src/shims/store.js +55 -0
  113. package/dist/src/shims/store.js.map +1 -0
  114. package/dist/src/sol-sdk/account/index.d.ts +13 -0
  115. package/dist/src/sol-sdk/account/index.d.ts.map +1 -0
  116. package/dist/src/sol-sdk/account/index.js +174 -0
  117. package/dist/src/sol-sdk/account/index.js.map +1 -0
  118. package/dist/src/sol-sdk/account/lookupTable.d.ts +24 -0
  119. package/dist/src/sol-sdk/account/lookupTable.d.ts.map +1 -0
  120. package/dist/src/sol-sdk/account/lookupTable.js +103 -0
  121. package/dist/src/sol-sdk/account/lookupTable.js.map +1 -0
  122. package/dist/src/sol-sdk/batch/create.d.ts +23 -0
  123. package/dist/src/sol-sdk/batch/create.d.ts.map +1 -0
  124. package/dist/src/sol-sdk/batch/create.js +580 -0
  125. package/dist/src/sol-sdk/batch/create.js.map +1 -0
  126. package/dist/src/sol-sdk/batch/external-sniper.d.ts +31 -0
  127. package/dist/src/sol-sdk/batch/external-sniper.d.ts.map +1 -0
  128. package/dist/src/sol-sdk/batch/external-sniper.js +163 -0
  129. package/dist/src/sol-sdk/batch/external-sniper.js.map +1 -0
  130. package/dist/src/sol-sdk/batch/index.d.ts +144 -0
  131. package/dist/src/sol-sdk/batch/index.d.ts.map +1 -0
  132. package/dist/src/sol-sdk/batch/index.js +1573 -0
  133. package/dist/src/sol-sdk/batch/index.js.map +1 -0
  134. package/dist/src/sol-sdk/calc.d.ts +277 -0
  135. package/dist/src/sol-sdk/calc.d.ts.map +1 -0
  136. package/dist/src/sol-sdk/calc.js +590 -0
  137. package/dist/src/sol-sdk/calc.js.map +1 -0
  138. package/dist/src/sol-sdk/index.d.ts +1 -0
  139. package/dist/src/sol-sdk/index.d.ts.map +1 -0
  140. package/dist/src/sol-sdk/index.js +1 -0
  141. package/dist/src/sol-sdk/index.js.map +1 -0
  142. package/dist/src/sol-sdk/jito/index.d.ts +50 -0
  143. package/dist/src/sol-sdk/jito/index.d.ts.map +1 -0
  144. package/dist/src/sol-sdk/jito/index.js +225 -0
  145. package/dist/src/sol-sdk/jito/index.js.map +1 -0
  146. package/dist/src/sol-sdk/launchlab/index.d.ts +32 -0
  147. package/dist/src/sol-sdk/launchlab/index.d.ts.map +1 -0
  148. package/dist/src/sol-sdk/launchlab/index.js +78 -0
  149. package/dist/src/sol-sdk/launchlab/index.js.map +1 -0
  150. package/dist/src/sol-sdk/launchlab/instructions/buy.d.ts +27 -0
  151. package/dist/src/sol-sdk/launchlab/instructions/buy.d.ts.map +1 -0
  152. package/dist/src/sol-sdk/launchlab/instructions/buy.js +124 -0
  153. package/dist/src/sol-sdk/launchlab/instructions/buy.js.map +1 -0
  154. package/dist/src/sol-sdk/launchlab/instructions/create.d.ts +27 -0
  155. package/dist/src/sol-sdk/launchlab/instructions/create.d.ts.map +1 -0
  156. package/dist/src/sol-sdk/launchlab/instructions/create.js +125 -0
  157. package/dist/src/sol-sdk/launchlab/instructions/create.js.map +1 -0
  158. package/dist/src/sol-sdk/launchlab/instructions/sell.d.ts +15 -0
  159. package/dist/src/sol-sdk/launchlab/instructions/sell.d.ts.map +1 -0
  160. package/dist/src/sol-sdk/launchlab/instructions/sell.js +65 -0
  161. package/dist/src/sol-sdk/launchlab/instructions/sell.js.map +1 -0
  162. package/dist/src/sol-sdk/meteora/index.d.ts +32 -0
  163. package/dist/src/sol-sdk/meteora/index.d.ts.map +1 -0
  164. package/dist/src/sol-sdk/meteora/index.js +72 -0
  165. package/dist/src/sol-sdk/meteora/index.js.map +1 -0
  166. package/dist/src/sol-sdk/meteora/instructions/buy.d.ts +46 -0
  167. package/dist/src/sol-sdk/meteora/instructions/buy.d.ts.map +1 -0
  168. package/dist/src/sol-sdk/meteora/instructions/buy.js +153 -0
  169. package/dist/src/sol-sdk/meteora/instructions/buy.js.map +1 -0
  170. package/dist/src/sol-sdk/meteora/instructions/sell.d.ts +24 -0
  171. package/dist/src/sol-sdk/meteora/instructions/sell.d.ts.map +1 -0
  172. package/dist/src/sol-sdk/meteora/instructions/sell.js +98 -0
  173. package/dist/src/sol-sdk/meteora/instructions/sell.js.map +1 -0
  174. package/dist/src/sol-sdk/pump/index.d.ts +22 -0
  175. package/dist/src/sol-sdk/pump/index.d.ts.map +1 -0
  176. package/dist/src/sol-sdk/pump/index.js +101 -0
  177. package/dist/src/sol-sdk/pump/index.js.map +1 -0
  178. package/dist/src/sol-sdk/pump/instructions/buy.d.ts +29 -0
  179. package/dist/src/sol-sdk/pump/instructions/buy.d.ts.map +1 -0
  180. package/dist/src/sol-sdk/pump/instructions/buy.js +131 -0
  181. package/dist/src/sol-sdk/pump/instructions/buy.js.map +1 -0
  182. package/dist/src/sol-sdk/pump/instructions/createAndBuy.d.ts +36 -0
  183. package/dist/src/sol-sdk/pump/instructions/createAndBuy.d.ts.map +1 -0
  184. package/dist/src/sol-sdk/pump/instructions/createAndBuy.js +77 -0
  185. package/dist/src/sol-sdk/pump/instructions/createAndBuy.js.map +1 -0
  186. package/dist/src/sol-sdk/pump/instructions/sell.d.ts +7 -0
  187. package/dist/src/sol-sdk/pump/instructions/sell.d.ts.map +1 -0
  188. package/dist/src/sol-sdk/pump/instructions/sell.js +38 -0
  189. package/dist/src/sol-sdk/pump/instructions/sell.js.map +1 -0
  190. package/dist/src/sol-sdk/pumpswap/index.d.ts +9 -0
  191. package/dist/src/sol-sdk/pumpswap/index.d.ts.map +1 -0
  192. package/dist/src/sol-sdk/pumpswap/index.js +27 -0
  193. package/dist/src/sol-sdk/pumpswap/index.js.map +1 -0
  194. package/dist/src/sol-sdk/pumpswap/instructions/buy.d.ts +61 -0
  195. package/dist/src/sol-sdk/pumpswap/instructions/buy.d.ts.map +1 -0
  196. package/dist/src/sol-sdk/pumpswap/instructions/buy.js +215 -0
  197. package/dist/src/sol-sdk/pumpswap/instructions/buy.js.map +1 -0
  198. package/dist/src/sol-sdk/pumpswap/instructions/migrate.d.ts +3 -0
  199. package/dist/src/sol-sdk/pumpswap/instructions/migrate.d.ts.map +1 -0
  200. package/dist/src/sol-sdk/pumpswap/instructions/migrate.js +33 -0
  201. package/dist/src/sol-sdk/pumpswap/instructions/migrate.js.map +1 -0
  202. package/dist/src/sol-sdk/pumpswap/instructions/sell.d.ts +20 -0
  203. package/dist/src/sol-sdk/pumpswap/instructions/sell.d.ts.map +1 -0
  204. package/dist/src/sol-sdk/pumpswap/instructions/sell.js +107 -0
  205. package/dist/src/sol-sdk/pumpswap/instructions/sell.js.map +1 -0
  206. package/dist/src/sol-sdk/pumpswap/rpc/index.d.ts +28 -0
  207. package/dist/src/sol-sdk/pumpswap/rpc/index.d.ts.map +1 -0
  208. package/dist/src/sol-sdk/pumpswap/rpc/index.js +63 -0
  209. package/dist/src/sol-sdk/pumpswap/rpc/index.js.map +1 -0
  210. package/dist/src/sol-sdk/raydium/index.d.ts +16 -0
  211. package/dist/src/sol-sdk/raydium/index.d.ts.map +1 -0
  212. package/dist/src/sol-sdk/raydium/index.js +47 -0
  213. package/dist/src/sol-sdk/raydium/index.js.map +1 -0
  214. package/dist/src/sol-sdk/raydium/instructions/buy.d.ts +29 -0
  215. package/dist/src/sol-sdk/raydium/instructions/buy.d.ts.map +1 -0
  216. package/dist/src/sol-sdk/raydium/instructions/buy.js +106 -0
  217. package/dist/src/sol-sdk/raydium/instructions/buy.js.map +1 -0
  218. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.d.ts +29 -0
  219. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.d.ts.map +1 -0
  220. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.js +80 -0
  221. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.js.map +1 -0
  222. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.d.ts +17 -0
  223. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.d.ts.map +1 -0
  224. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js +56 -0
  225. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js.map +1 -0
  226. package/dist/src/sol-sdk/raydium/instructions/sell.d.ts +8558 -0
  227. package/dist/src/sol-sdk/raydium/instructions/sell.d.ts.map +1 -0
  228. package/dist/src/sol-sdk/raydium/instructions/sell.js +70 -0
  229. package/dist/src/sol-sdk/raydium/instructions/sell.js.map +1 -0
  230. package/dist/src/sol-sdk/raydium/rpc/index.d.ts +39 -0
  231. package/dist/src/sol-sdk/raydium/rpc/index.d.ts.map +1 -0
  232. package/dist/src/sol-sdk/raydium/rpc/index.js +82 -0
  233. package/dist/src/sol-sdk/raydium/rpc/index.js.map +1 -0
  234. package/dist/src/sol-sdk/raydium/rpc/raydium.d.ts +5 -0
  235. package/dist/src/sol-sdk/raydium/rpc/raydium.d.ts.map +1 -0
  236. package/dist/src/sol-sdk/raydium/rpc/raydium.js +18 -0
  237. package/dist/src/sol-sdk/raydium/rpc/raydium.js.map +1 -0
  238. package/dist/src/sol-sdk/rpc/index.d.ts +33 -0
  239. package/dist/src/sol-sdk/rpc/index.d.ts.map +1 -0
  240. package/dist/src/sol-sdk/rpc/index.js +128 -0
  241. package/dist/src/sol-sdk/rpc/index.js.map +1 -0
  242. package/dist/src/sol-sdk/transfer/index.d.ts +24 -0
  243. package/dist/src/sol-sdk/transfer/index.d.ts.map +1 -0
  244. package/dist/src/sol-sdk/transfer/index.js +65 -0
  245. package/dist/src/sol-sdk/transfer/index.js.map +1 -0
  246. package/dist/src/sol-sdk/turnover/index.d.ts +84 -0
  247. package/dist/src/sol-sdk/turnover/index.d.ts.map +1 -0
  248. package/dist/src/sol-sdk/turnover/index.js +569 -0
  249. package/dist/src/sol-sdk/turnover/index.js.map +1 -0
  250. package/dist/src/tx-tracker/detail-adapter.d.ts +100 -0
  251. package/dist/src/tx-tracker/detail-adapter.d.ts.map +1 -0
  252. package/dist/src/tx-tracker/detail-adapter.js +215 -0
  253. package/dist/src/tx-tracker/detail-adapter.js.map +1 -0
  254. package/dist/src/tx-tracker/index.d.ts +142 -0
  255. package/dist/src/tx-tracker/index.d.ts.map +1 -0
  256. package/dist/src/tx-tracker/index.js +447 -0
  257. package/dist/src/tx-tracker/index.js.map +1 -0
  258. package/dist/src/types/index.d.ts +76 -0
  259. package/dist/src/types/index.d.ts.map +1 -0
  260. package/dist/src/types/index.js +69 -0
  261. package/dist/src/types/index.js.map +1 -0
  262. package/dist/src/types/websocket.d.ts +15 -0
  263. package/dist/src/types/websocket.d.ts.map +1 -0
  264. package/dist/src/types/websocket.js +18 -0
  265. package/dist/src/types/websocket.js.map +1 -0
  266. package/dist/src/utils/index.d.ts +13 -0
  267. package/dist/src/utils/index.d.ts.map +1 -0
  268. package/dist/src/utils/index.js +174 -0
  269. package/dist/src/utils/index.js.map +1 -0
  270. package/dist/src/wallet-store.d.ts +124 -0
  271. package/dist/src/wallet-store.d.ts.map +1 -0
  272. package/dist/src/wallet-store.js +524 -0
  273. package/dist/src/wallet-store.js.map +1 -0
  274. package/package.json +86 -0
  275. package/scripts/postinstall.js +88 -0
@@ -0,0 +1,1573 @@
1
+ import { AnchorProvider } from '@coral-xyz/anchor';
2
+ import { PublicKey, Keypair, Transaction, TransactionMessage, VersionedTransaction, LAMPORTS_PER_SOL, } from '@solana/web3.js';
3
+ import { pumpBuySPLInstructions, pumpSellSPLInstructions, getPumpCurveState } from '../pump/index.js';
4
+ import { raydiumBuyInstruction, raydiumSellInstruction, raydiumGetPoolInfo, raydiumGetCpmmPoolInfo, raydiumCpmmSwapBaseOutBuyInstruction, raydiumCpmmSwapBaseInBuyInstruction, raydiumCpmmSellInstruction, } from '../raydium/index.js';
5
+ import { meteoraDlmmBuyInstructions, meteoraDlmmBuyExactOutInstructions, meteoraDlmmSellInstructions, getBinArray, } from '../meteora/index.js';
6
+ import { pumpSwapBuyInstruction, pumpSwapSellInstruction, pumpSwapGetPoolInfo } from '../pumpswap/index.js';
7
+ import { getLaunchlabReverseInfo, launchlabBuyExactInInstruction, launchlabBuyExactOutInstruction, launchlabSellExactInInstruction, } from '../launchlab/index.js';
8
+ import { getNewWsolAccount } from '../account/index.js';
9
+ import AmmCalc, { PumpAmmCalc, LaunchlabAmmCalc } from '../calc.js';
10
+ import BigNumber from 'bignumber.js';
11
+ import BN from 'bn.js';
12
+ import { getCU } from '../rpc/index.js';
13
+ import JitoJsonRpcClient from '../jito/index.js';
14
+ import { NATIVE_MINT } from '@solana/spl-token';
15
+ import { getWalletAddress, getWalletKeypair } from '../../utils/index.js';
16
+ import { addCommission } from '../transfer/index.js';
17
+ import { BundleBuyTime, VolumeType } from '../../types/index.js';
18
+ import { METEORA_DLMM_PROGRAM } from '../../const/index.js';
19
+ import MeteoraDLMM from '@meteora-ag/dlmm';
20
+ let redis = {
21
+ pumpCache: {},
22
+ pumpAtaCache: {},
23
+ pumpSwapCache: {},
24
+ pumpSwapAtaCache: {},
25
+ };
26
+ export const batchTrade = async ({ connection, exchangeName, // dex名称
27
+ tokenAddress, // 代币地址
28
+ poolId, // 池子ID
29
+ tradeType, // 交易类型
30
+ slippage, // 滑点
31
+ priorityFee, // 优先费
32
+ priceInSol, // 价格
33
+ decimals, // 小数位
34
+ poolInfo, // 池子信息
35
+ ammReverseInfo = undefined, // 深度信息
36
+ launchlabReverseInfo = undefined, // 深度信息
37
+ meteoraDLMMReverseInfo = undefined, // meteora 池子信息
38
+ commissionWallet, // 佣金钱包
39
+ commissionAmount, // 佣金数量
40
+ creatorAddress, // 创建者地址
41
+ walletAmounts, pumpfunReverseInfo, raydiumV4Keys = undefined, raydiumCpmmKeys = undefined, volumeType = VolumeType.ONE_BUY_ONE_SELL, // 刷量方式
42
+ simulate = false, // 模拟交易
43
+ }) => {
44
+ slippage = slippage / 100;
45
+ if (!poolId || !tokenAddress || !priceInSol || !walletAmounts.length) {
46
+ console.log('参数错误', {
47
+ poolId,
48
+ tokenAddress,
49
+ priceInSol,
50
+ walletAmounts,
51
+ });
52
+ return undefined;
53
+ }
54
+ if (exchangeName === 'PumpSwap') {
55
+ return pumpswapBatchTrade({
56
+ connection,
57
+ poolInfo,
58
+ tradeType,
59
+ slippage,
60
+ priorityFee,
61
+ decimals,
62
+ reverseInfo: ammReverseInfo,
63
+ commissionWallet,
64
+ commissionAmount,
65
+ creator: new PublicKey(creatorAddress),
66
+ walletAmounts,
67
+ volumeType,
68
+ simulate,
69
+ });
70
+ }
71
+ else if (exchangeName === 'Pump') {
72
+ return pumpBatchTrade({
73
+ connection,
74
+ tokenAddress,
75
+ poolId: poolInfo.pairAddress,
76
+ tradeType,
77
+ slippage,
78
+ priorityFee,
79
+ priceInSol,
80
+ commissionWallet,
81
+ commissionAmount,
82
+ creator: new PublicKey(creatorAddress),
83
+ walletAmounts,
84
+ initialPoolData: pumpfunReverseInfo,
85
+ volumeType,
86
+ simulate,
87
+ });
88
+ }
89
+ else if (exchangeName === 'Raydium') {
90
+ if (!raydiumV4Keys)
91
+ return [];
92
+ return raydiumBatchTrade({
93
+ connection,
94
+ tokenAddress,
95
+ poolId,
96
+ tradeType: tradeType,
97
+ slippage,
98
+ priorityFee,
99
+ priceInSol,
100
+ commissionWallet,
101
+ commissionAmount,
102
+ walletAmounts,
103
+ decimals,
104
+ reverseInfo: ammReverseInfo,
105
+ raydiumV4Keys,
106
+ poolInfo,
107
+ volumeType,
108
+ simulate,
109
+ });
110
+ }
111
+ else if (exchangeName === 'Raydium CPMM') {
112
+ console.log('ammReverseInfo', ammReverseInfo);
113
+ console.log('raydiumCpmmKeys', raydiumCpmmKeys);
114
+ if (!raydiumCpmmKeys)
115
+ return [];
116
+ return raydiumCpmmBatchTrade({
117
+ connection,
118
+ tokenAddress,
119
+ poolId,
120
+ tradeType: tradeType,
121
+ slippage,
122
+ priorityFee,
123
+ priceInSol,
124
+ commissionWallet,
125
+ commissionAmount,
126
+ walletAmounts,
127
+ decimals,
128
+ raydiumCpmmKeys,
129
+ poolInfo,
130
+ volumeType,
131
+ simulate,
132
+ reverseInfo: ammReverseInfo,
133
+ });
134
+ }
135
+ else if (exchangeName === 'LaunchLab') {
136
+ return launchlabBatchTrade({
137
+ connection,
138
+ tokenAddress,
139
+ poolId,
140
+ tradeType,
141
+ slippage,
142
+ priorityFee,
143
+ decimals,
144
+ reverseInfo: launchlabReverseInfo,
145
+ commissionWallet,
146
+ commissionAmount,
147
+ creator: new PublicKey(creatorAddress),
148
+ walletAmounts,
149
+ volumeType,
150
+ simulate,
151
+ });
152
+ }
153
+ else if (exchangeName === 'Meteora') {
154
+ return meteoraDlmmBatchTrade({
155
+ connection,
156
+ tokenAddress,
157
+ poolId,
158
+ tradeType,
159
+ slippage,
160
+ priorityFee,
161
+ decimals,
162
+ reverseInfo: meteoraDLMMReverseInfo,
163
+ commissionWallet,
164
+ commissionAmount,
165
+ creator: new PublicKey(creatorAddress),
166
+ walletAmounts,
167
+ volumeType,
168
+ simulate,
169
+ });
170
+ }
171
+ console.log('exchangeName', exchangeName);
172
+ return [];
173
+ };
174
+ export const launchlabBatchTrade = async ({ connection, snipers, tokenAddress, poolId, tradeType, slippage, priorityFee, decimals, reverseInfo, commissionWallet, commissionAmount, lutAccount, creator, walletAmounts, bundleBuyTime, volumeType = VolumeType.ONE_BUY_ONE_SELL, simulate = false, }) => {
175
+ const provider = new AnchorProvider(connection, {
176
+ publicKey: Keypair.generate().publicKey,
177
+ signTransaction: async () => {
178
+ throw new Error('不支持签名');
179
+ },
180
+ signAllTransactions: async () => {
181
+ throw new Error('不支持签名');
182
+ },
183
+ }, {});
184
+ // 使用getPumpCurveState方法解析池子数据
185
+ const poolData = reverseInfo || (await getLaunchlabReverseInfo({ connection, poolId }));
186
+ console.log('poolData: ', poolData);
187
+ const parsedPoolData = {
188
+ supply: poolData.supply.toString(),
189
+ baseDecimals: poolData.baseDecimals,
190
+ quoteDecimals: poolData.quoteDecimals,
191
+ migrateType: poolData.migrateType,
192
+ totalBaseSell: poolData.totalBaseSell.toString(),
193
+ virtualBase: poolData.virtualBase.toString(),
194
+ virtualQuote: poolData.virtualQuote.toString(),
195
+ realBase: poolData.realBase.toString(),
196
+ realQuote: poolData.realQuote.toString(),
197
+ };
198
+ // 创建计算器实例
199
+ const launchlabCalc = new LaunchlabAmmCalc({
200
+ baseDecimals: parsedPoolData.baseDecimals,
201
+ quoteDecimals: parsedPoolData.quoteDecimals,
202
+ migrateType: parsedPoolData.migrateType,
203
+ supply: new BN(parsedPoolData.supply),
204
+ totalBaseSell: new BN(parsedPoolData.totalBaseSell),
205
+ virtualBase: new BN(parsedPoolData.virtualBase),
206
+ virtualQuote: new BN(parsedPoolData.virtualQuote),
207
+ realBase: new BN(parsedPoolData.realBase),
208
+ realQuote: new BN(parsedPoolData.realQuote),
209
+ });
210
+ const payers = walletAmounts.map(item => getWalletKeypair(item.privateKey));
211
+ const jito = new JitoJsonRpcClient();
212
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
213
+ const base64Txs = [];
214
+ // 处理交易逻辑
215
+ if (tradeType === 'buy') {
216
+ try {
217
+ for (const payer of walletAmounts) {
218
+ const currentPayer = getWalletKeypair(payer.privateKey);
219
+ const currentAmount = new BigNumber(payer.amount).times(LAMPORTS_PER_SOL).toFixed(0);
220
+ // let receiveAmount;
221
+ // try {
222
+ // receiveAmount = launchlabCalc.calculateBuyAmountOut(currentAmount);
223
+ // } catch (err) {
224
+ // console.log('err: ', err);
225
+ // break;
226
+ // }
227
+ const buyTx = await launchlabBuyExactInInstruction({
228
+ provider,
229
+ owner: currentPayer.publicKey,
230
+ baseMint: new PublicKey(tokenAddress),
231
+ quoteMint: NATIVE_MINT,
232
+ amountIn: BigInt(currentAmount),
233
+ minAmountOut: BigInt(0),
234
+ needCreateAtaAccount: true,
235
+ needCloseTokenAccount: true,
236
+ });
237
+ const tx = getTx(buyTx, currentPayer, priorityFee, jito);
238
+ // addPriorityFee(tx, cu);
239
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
240
+ const base64Tx = await getBase64Tx({
241
+ tx,
242
+ payer: currentPayer,
243
+ signers: [currentPayer],
244
+ blockhash,
245
+ connection,
246
+ lutAccount,
247
+ simulate,
248
+ });
249
+ base64Txs.push(base64Tx);
250
+ }
251
+ return base64Txs;
252
+ }
253
+ catch (error) {
254
+ throw new Error(`构造交易指令失败: ${error.message}`);
255
+ }
256
+ }
257
+ else if (tradeType === 'sell') {
258
+ try {
259
+ for (const payer of walletAmounts) {
260
+ const currentPayer = getWalletKeypair(payer.privateKey);
261
+ const currentAmount = new BigNumber(payer.amount).times(10 ** decimals).toFixed(0);
262
+ const receiveAmount = launchlabCalc.calculateSellAmountOut(currentAmount);
263
+ const sellTx = await launchlabSellExactInInstruction({
264
+ provider,
265
+ owner: currentPayer.publicKey,
266
+ baseMint: new PublicKey(tokenAddress),
267
+ quoteMint: NATIVE_MINT,
268
+ amountIn: BigInt(currentAmount),
269
+ minAmountOut: BigInt(new BigNumber(receiveAmount).times(1 - slippage).toFixed(0)),
270
+ needCreateAtaAccount: true,
271
+ needCloseTokenAccount: true,
272
+ });
273
+ const tx = getTx(sellTx, currentPayer, priorityFee, jito);
274
+ // addPriorityFee(tx, cu);
275
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(receiveAmount).times(commissionAmount).toFixed(0));
276
+ const base64Tx = await getBase64Tx({
277
+ tx,
278
+ payer: currentPayer,
279
+ signers: [currentPayer],
280
+ blockhash,
281
+ connection,
282
+ simulate,
283
+ });
284
+ base64Txs.push(base64Tx);
285
+ }
286
+ return base64Txs;
287
+ }
288
+ catch (error) {
289
+ throw new Error(`构造交易指令失败: ${error.message}`);
290
+ }
291
+ }
292
+ else if (tradeType === 'buyWithSell') {
293
+ // 实现 Pump 的多买多卖逻辑
294
+ try {
295
+ for (const payer of walletAmounts) {
296
+ const currentPayer = getWalletKeypair(payer.privateKey);
297
+ const currentAmount = new BigNumber(payer.amount).times(LAMPORTS_PER_SOL).toFixed(0);
298
+ // 提前创建 wsolAccount
299
+ const { wsolAccount, createWsolAccount } = await getNewWsolAccount(currentPayer.publicKey, new BigNumber(currentAmount).times(1 + slippage).toFixed(0));
300
+ // 创建组合交易
301
+ const tx = new Transaction();
302
+ let totalBuyReceiveAmount = new BN(0);
303
+ // 根据 volumeType 确定买入和卖出次数
304
+ const { buyCount, sellCount } = getVolumeTypeConfig(volumeType);
305
+ // 执行多次买入
306
+ let remainingAmount = new BigNumber(currentAmount);
307
+ for (let i = 0; i < buyCount; i++) {
308
+ let buyAmount;
309
+ if (i === buyCount - 1) {
310
+ // 最后一次买入时,使用所有剩余资金
311
+ buyAmount = remainingAmount.toFixed(0);
312
+ }
313
+ else {
314
+ // 前面几次按平均分配
315
+ buyAmount = new BigNumber(currentAmount).div(buyCount).toFixed(0);
316
+ remainingAmount = remainingAmount.minus(buyAmount);
317
+ }
318
+ let buyReceiveAmount;
319
+ try {
320
+ buyReceiveAmount = launchlabCalc.calculateBuyAmountOut(buyAmount);
321
+ }
322
+ catch (err) {
323
+ console.log('err: ', err);
324
+ break;
325
+ }
326
+ totalBuyReceiveAmount = totalBuyReceiveAmount.add(new BN(buyReceiveAmount.toString()));
327
+ // 添加买入指令
328
+ const buyTx = await launchlabBuyExactOutInstruction({
329
+ provider,
330
+ owner: currentPayer.publicKey,
331
+ baseMint: new PublicKey(tokenAddress),
332
+ quoteMint: NATIVE_MINT,
333
+ amount: BigInt(buyReceiveAmount.toString()),
334
+ maxSolCost: BigInt(new BigNumber(currentAmount).times(1 + slippage).toFixed(0)),
335
+ needCreateAtaAccount: i === 0,
336
+ needCloseTokenAccount: false,
337
+ initialWsolAccount: wsolAccount,
338
+ createWsolAccountInstruction: createWsolAccount,
339
+ });
340
+ tx.add(buyTx);
341
+ }
342
+ // 执行多次卖出
343
+ let remainingTokenAmount = totalBuyReceiveAmount;
344
+ for (let i = 0; i < sellCount; i++) {
345
+ let sellTokenAmount;
346
+ if (i === sellCount - 1) {
347
+ // 最后一次卖出时,卖出所有剩余代币
348
+ sellTokenAmount = remainingTokenAmount.toString();
349
+ }
350
+ else {
351
+ // 前面几次按平均分配
352
+ sellTokenAmount = totalBuyReceiveAmount.div(new BN(sellCount)).toString();
353
+ remainingTokenAmount = remainingTokenAmount.sub(new BN(sellTokenAmount));
354
+ }
355
+ const sellReceiveAmount = launchlabCalc.calculateSellAmountOut(sellTokenAmount);
356
+ // 添加卖出指令
357
+ const sellTx = await launchlabSellExactInInstruction({
358
+ provider,
359
+ owner: currentPayer.publicKey,
360
+ baseMint: new PublicKey(tokenAddress),
361
+ quoteMint: NATIVE_MINT,
362
+ amountIn: BigInt(sellTokenAmount),
363
+ minAmountOut: BigInt(new BigNumber(sellReceiveAmount).times(1 - slippage).toFixed(0)),
364
+ needCreateAtaAccount: false,
365
+ needCloseTokenAccount: i === sellCount - 1,
366
+ initialWsolAccount: wsolAccount,
367
+ createWsolAccountInstruction: createWsolAccount,
368
+ });
369
+ tx.add(sellTx);
370
+ }
371
+ const finalTx = getTx(tx, currentPayer, priorityFee, jito);
372
+ addCommission(finalTx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
373
+ const base64Tx = await getBase64Tx({
374
+ tx: finalTx,
375
+ payer: currentPayer,
376
+ signers: [currentPayer],
377
+ blockhash,
378
+ connection,
379
+ lutAccount,
380
+ simulate,
381
+ });
382
+ base64Txs.push(base64Tx);
383
+ }
384
+ return base64Txs;
385
+ }
386
+ catch (error) {
387
+ throw new Error(`构造交易指令失败: ${error.message}`);
388
+ }
389
+ }
390
+ else if (tradeType === 'sniperBuy') {
391
+ if (snipers) {
392
+ let txs = [];
393
+ let signers = [];
394
+ for (const [index, sniper] of snipers.entries()) {
395
+ const currentPayer = getWalletKeypair(sniper.wallet);
396
+ const currentAmount = new BigNumber(sniper.amount).times(10 ** 9).toString(10);
397
+ console.log('currentAmount: ', currentAmount);
398
+ let receiveAmount;
399
+ try {
400
+ receiveAmount = launchlabCalc.calculateBuyAmountOut(currentAmount);
401
+ console.log('receiveAmount: ', receiveAmount.toString());
402
+ }
403
+ catch (err) {
404
+ console.log('err: ', err);
405
+ break;
406
+ }
407
+ const buyTx = await launchlabBuyExactOutInstruction({
408
+ provider,
409
+ owner: currentPayer.publicKey,
410
+ baseMint: new PublicKey(tokenAddress),
411
+ quoteMint: NATIVE_MINT,
412
+ amount: BigInt(receiveAmount.toString()),
413
+ maxSolCost: BigInt(new BigNumber(currentAmount).times(1 + slippage).toFixed(0)),
414
+ initialWsolAccount: undefined,
415
+ needCreateAtaAccount: true,
416
+ needCloseTokenAccount: true,
417
+ });
418
+ if (index % (lutAccount ? 5 : 2) === 0) {
419
+ txs.push(new Transaction());
420
+ signers.push([]);
421
+ }
422
+ txs[txs.length - 1].add(buyTx);
423
+ signers[signers.length - 1].push(currentPayer);
424
+ }
425
+ const tipTx = new Transaction();
426
+ tipTx.add(jito.getTipInstruction(new PublicKey(getWalletAddress(snipers[0].wallet)), priorityFee));
427
+ txs.push(tipTx);
428
+ signers.push([getWalletKeypair(snipers[0].wallet)]);
429
+ addCommission(txs[txs.length - 1], getWalletKeypair(snipers[0].wallet), commissionWallet, new BigNumber(snipers.length).times(commissionAmount).times(LAMPORTS_PER_SOL).toString(10));
430
+ for (const [index, tx] of txs.entries()) {
431
+ const base64Tx = await getBase64Tx({
432
+ tx,
433
+ payer: signers[0][0], // 第一个交易者作为 fee payer
434
+ signers: [...signers[index]], // 当前交易的所有签名者
435
+ blockhash,
436
+ connection,
437
+ lutAccount,
438
+ simulate,
439
+ });
440
+ base64Txs.push(base64Tx);
441
+ }
442
+ return base64Txs;
443
+ }
444
+ else {
445
+ throw new Error('snipers 不能为空');
446
+ }
447
+ }
448
+ };
449
+ export const pumpswapBatchTrade = async ({ connection, poolInfo, tradeType, slippage, priorityFee, decimals, reverseInfo, commissionWallet, commissionAmount, creator, walletAmounts, volumeType = VolumeType.ONE_BUY_ONE_SELL, simulate = false, }) => {
450
+ let info = reverseInfo;
451
+ if (!info) {
452
+ info = await pumpSwapGetPoolInfo(connection, poolInfo.pairAddress);
453
+ }
454
+ const mintA = new PublicKey(info.mintA);
455
+ const mintB = new PublicKey(info.mintB);
456
+ const basereverse = info.poolBaseTokenInfo.amount.toString();
457
+ const quoteReserve = info.poolQuoteTokenInfo.amount.toString();
458
+ const pumpswapCalc = new AmmCalc({
459
+ baseReserve: basereverse,
460
+ quoteReserve: quoteReserve,
461
+ baseDecimals: mintA.toBase58() === NATIVE_MINT.toBase58() ? 9 : decimals,
462
+ quoteDecimals: mintB.toBase58() === NATIVE_MINT.toBase58() ? 9 : decimals,
463
+ });
464
+ const base64Txs = [];
465
+ const jito = new JitoJsonRpcClient();
466
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
467
+ if (tradeType === 'buy' || tradeType === 'sniperBuy') {
468
+ for (const [index, payer] of walletAmounts.entries()) {
469
+ const currentPayer = getWalletKeypair(payer.privateKey);
470
+ const currentAmount = new BigNumber(payer.amount).times(10 ** 9).toFixed(0);
471
+ if (Number(currentAmount) <= 0) {
472
+ continue;
473
+ }
474
+ let receiveAmount;
475
+ try {
476
+ receiveAmount = pumpswapCalc.swap(currentAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? true : false);
477
+ }
478
+ catch (err) {
479
+ console.log('err: ', err);
480
+ break;
481
+ }
482
+ const buyTx = await pumpSwapBuyInstruction({
483
+ owner: currentPayer,
484
+ poolInfo: {
485
+ poolId: poolInfo.pairAddress,
486
+ mintA: mintA.toBase58(),
487
+ mintB: mintB.toBase58(),
488
+ },
489
+ wsolAmount: new BN(currentAmount),
490
+ tokenAmount: new BN(receiveAmount),
491
+ slippage,
492
+ creator,
493
+ });
494
+ let tx = getTx(buyTx, currentPayer, priorityFee, jito);
495
+ if (tradeType === 'sniperBuy' && index === 0) {
496
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(commissionAmount).times(LAMPORTS_PER_SOL).toFixed(0));
497
+ }
498
+ else {
499
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
500
+ }
501
+ // console.log('tx: ', tx);
502
+ const base64Tx = await getBase64Tx({
503
+ tx,
504
+ payer: currentPayer,
505
+ signers: [currentPayer],
506
+ blockhash,
507
+ connection,
508
+ simulate,
509
+ });
510
+ base64Txs.push(base64Tx);
511
+ }
512
+ }
513
+ else if (tradeType === 'sell') {
514
+ for (const payer of walletAmounts) {
515
+ const currentPayer = getWalletKeypair(payer.privateKey);
516
+ const currentAmount = new BigNumber(payer.amount).times(10 ** decimals).toFixed(0);
517
+ let receiveAmount;
518
+ if (Number(currentAmount) <= 0) {
519
+ continue;
520
+ }
521
+ try {
522
+ receiveAmount = pumpswapCalc.swap(currentAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? false : true);
523
+ }
524
+ catch (err) {
525
+ console.log('err: ', err);
526
+ break;
527
+ }
528
+ const sellTx = await pumpSwapSellInstruction({
529
+ owner: currentPayer,
530
+ poolInfo: {
531
+ poolId: poolInfo.pairAddress,
532
+ mintA: mintA.toBase58(),
533
+ mintB: mintB.toBase58(),
534
+ },
535
+ tokenAmount: new BN(currentAmount),
536
+ wsolAmount: new BN(receiveAmount),
537
+ slippage,
538
+ creator,
539
+ });
540
+ let tx = getTx(sellTx, currentPayer, priorityFee, jito);
541
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(receiveAmount).times(commissionAmount).toFixed(0));
542
+ const base64Tx = await getBase64Tx({
543
+ tx,
544
+ payer: currentPayer,
545
+ signers: [currentPayer],
546
+ blockhash,
547
+ connection,
548
+ simulate,
549
+ });
550
+ base64Txs.push(base64Tx);
551
+ }
552
+ }
553
+ else if (tradeType === 'buyWithSell') {
554
+ // 实现多买多卖逻辑
555
+ for (const payer of walletAmounts) {
556
+ const currentPayer = getWalletKeypair(payer.privateKey);
557
+ const currentAmount = new BigNumber(payer.amount).times(10 ** 9).toFixed(0);
558
+ if (Number(currentAmount) <= 0) {
559
+ continue;
560
+ }
561
+ // 提前创建 wsolAccount
562
+ const { wsolAccount, createWsolAccount } = await getNewWsolAccount(currentPayer.publicKey, new BigNumber(currentAmount).times(1 + slippage).toFixed(0));
563
+ try {
564
+ // 创建组合交易
565
+ const tx = new Transaction();
566
+ let totalBuyReceiveAmount = new BN(0);
567
+ // 根据 volumeType 确定买入和卖出次数
568
+ const { buyCount, sellCount } = getVolumeTypeConfig(volumeType);
569
+ // 执行多次买入
570
+ let remainingAmount = new BigNumber(currentAmount);
571
+ for (let i = 0; i < buyCount; i++) {
572
+ let buyAmount;
573
+ if (i === buyCount - 1) {
574
+ // 最后一次买入时,使用所有剩余资金
575
+ buyAmount = remainingAmount.toFixed(0);
576
+ }
577
+ else {
578
+ // 前面几次按平均分配
579
+ buyAmount = new BigNumber(currentAmount).div(buyCount).toFixed(0);
580
+ remainingAmount = remainingAmount.minus(buyAmount);
581
+ }
582
+ let buyReceiveAmount = pumpswapCalc.swap(buyAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? true : false);
583
+ totalBuyReceiveAmount = totalBuyReceiveAmount.add(new BN(buyReceiveAmount.toString()));
584
+ const buyTx = await pumpSwapBuyInstruction({
585
+ owner: currentPayer,
586
+ poolInfo: {
587
+ poolId: poolInfo.pairAddress,
588
+ mintA: mintA.toBase58(),
589
+ mintB: mintB.toBase58(),
590
+ },
591
+ wsolAmount: new BN(buyAmount),
592
+ tokenAmount: new BN(buyReceiveAmount),
593
+ slippage,
594
+ creator,
595
+ needCreateAtaAccount: i === 0,
596
+ needCloseTokenAccount: false,
597
+ needCloseWsolAccount: false,
598
+ initialWsolAccount: wsolAccount,
599
+ createWsolAccountInstruction: createWsolAccount,
600
+ });
601
+ tx.add(buyTx);
602
+ }
603
+ // 执行多次卖出
604
+ let remainingTokenAmount = totalBuyReceiveAmount;
605
+ for (let i = 0; i < sellCount; i++) {
606
+ let sellTokenAmount;
607
+ if (i === sellCount - 1) {
608
+ // 最后一次卖出时,卖出所有剩余代币
609
+ sellTokenAmount = remainingTokenAmount;
610
+ }
611
+ else {
612
+ // 前面几次按平均分配
613
+ sellTokenAmount = totalBuyReceiveAmount.div(new BN(sellCount));
614
+ remainingTokenAmount = remainingTokenAmount.sub(sellTokenAmount);
615
+ }
616
+ let sellReceiveAmount = pumpswapCalc.swap(sellTokenAmount.toString(), mintA.toBase58() === NATIVE_MINT.toBase58() ? false : true);
617
+ const sellTx = await pumpSwapSellInstruction({
618
+ owner: currentPayer,
619
+ poolInfo: {
620
+ poolId: poolInfo.pairAddress,
621
+ mintA: mintA.toBase58(),
622
+ mintB: mintB.toBase58(),
623
+ },
624
+ tokenAmount: sellTokenAmount,
625
+ wsolAmount: new BN(sellReceiveAmount),
626
+ slippage,
627
+ creator,
628
+ needCreateAtaAccount: false,
629
+ needCloseTokenAccount: i === sellCount - 1,
630
+ needCloseWsolAccount: i === sellCount - 1,
631
+ initialWsolAccount: wsolAccount,
632
+ });
633
+ tx.add(sellTx);
634
+ }
635
+ let finalTx = getTx(tx, currentPayer, priorityFee, jito, 400_000);
636
+ addCommission(finalTx, currentPayer, commissionWallet, commissionAmount);
637
+ const base64Tx = await getBase64Tx({
638
+ tx: finalTx,
639
+ payer: currentPayer,
640
+ signers: [currentPayer],
641
+ blockhash,
642
+ connection,
643
+ simulate,
644
+ });
645
+ base64Txs.push(base64Tx);
646
+ }
647
+ catch (err) {
648
+ console.log('buyWithSell err: ', err);
649
+ break;
650
+ }
651
+ }
652
+ }
653
+ return base64Txs;
654
+ };
655
+ export const pumpBatchTrade = async ({ connection, walletAmounts, snipers, tokenAddress, poolId, tradeType, slippage, priorityFee, priceInSol, initialPoolData, lutAccount, commissionWallet, commissionAmount, creator, bundleBuyTime, volumeType = VolumeType.ONE_BUY_ONE_SELL, simulate = false, }) => {
656
+ const provider = new AnchorProvider(connection, {
657
+ publicKey: Keypair.generate().publicKey,
658
+ signTransaction: async () => {
659
+ throw new Error('不支持签名');
660
+ },
661
+ signAllTransactions: async () => {
662
+ throw new Error('不支持签名');
663
+ },
664
+ }, {});
665
+ // 使用getPumpCurveState方法解析池子数据
666
+ const poolData = initialPoolData || (await getPumpCurveState(connection, poolId));
667
+ const parsedPoolData = {
668
+ virtual_sol_reserves: poolData.virtualSolReserves.toString(),
669
+ virtual_token_reserves: poolData.virtualTokenReserves.toString(),
670
+ real_token_reserves: poolData.realTokenReserves.toString(),
671
+ real_sol_reserves: poolData.realSolReserves.toString(),
672
+ token_total_supply: poolData.tokenTotalSupply.toString(),
673
+ complete: poolData.complete,
674
+ };
675
+ console.log('parsedPoolData: ', parsedPoolData);
676
+ // 创建计算器实例
677
+ const pumpCalc = new PumpAmmCalc({
678
+ initialVirtualSolReserves: new BN(parsedPoolData.virtual_sol_reserves),
679
+ tokenTotalSupply: new BN(parsedPoolData.token_total_supply),
680
+ initialRealSolReserves: new BN(parsedPoolData.real_sol_reserves),
681
+ initialVirtualTokenReserves: new BN(parsedPoolData.virtual_token_reserves),
682
+ initialRealTokenReserves: new BN(parsedPoolData.real_token_reserves),
683
+ });
684
+ const payers = walletAmounts.map(item => getWalletKeypair(item.privateKey));
685
+ const jito = new JitoJsonRpcClient();
686
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
687
+ const base64Txs = [];
688
+ // 处理交易逻辑
689
+ if (tradeType === 'buy') {
690
+ try {
691
+ for (const payer of walletAmounts) {
692
+ const currentPayer = getWalletKeypair(payer.privateKey);
693
+ const currentAmount = new BigNumber(payer.amount).times(LAMPORTS_PER_SOL).toFixed(0);
694
+ let receiveAmount;
695
+ try {
696
+ receiveAmount = pumpCalc.calculateBuyAmountOut(currentAmount);
697
+ }
698
+ catch (err) {
699
+ console.log('err: ', err);
700
+ continue;
701
+ }
702
+ const [_, buyTx] = await pumpBuySPLInstructions(provider, currentPayer.publicKey, tokenAddress, currentAmount, slippage, new BigNumber(priceInSol).toString(10), creator, receiveAmount.toString());
703
+ const tx = getTx(buyTx, currentPayer, priorityFee, jito);
704
+ // addPriorityFee(tx, cu);
705
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
706
+ const base64Tx = await getBase64Tx({
707
+ tx,
708
+ payer: currentPayer,
709
+ signers: [currentPayer],
710
+ blockhash,
711
+ connection,
712
+ lutAccount,
713
+ simulate,
714
+ });
715
+ base64Txs.push(base64Tx);
716
+ }
717
+ return base64Txs;
718
+ }
719
+ catch (error) {
720
+ throw new Error(`构造交易指令失败: ${error.message}`);
721
+ }
722
+ }
723
+ else if (tradeType === 'sell') {
724
+ try {
725
+ for (const payer of walletAmounts) {
726
+ const currentPayer = getWalletKeypair(payer.privateKey);
727
+ const currentAmount = new BigNumber(payer.amount).times(10 ** 6).toFixed(0);
728
+ let receiveAmount;
729
+ try {
730
+ receiveAmount = pumpCalc.calculateSellAmountOut(currentAmount);
731
+ }
732
+ catch (err) {
733
+ console.log('err: ', err);
734
+ continue;
735
+ }
736
+ const sellTx = await pumpSellSPLInstructions(provider, currentPayer, tokenAddress, new BigNumber(currentAmount).toString(10), slippage, receiveAmount, creator);
737
+ const tx = getTx(sellTx, currentPayer, priorityFee, jito);
738
+ // addPriorityFee(tx, cu);
739
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(receiveAmount).times(commissionAmount).toFixed(0));
740
+ const base64Tx = await getBase64Tx({
741
+ tx,
742
+ payer: currentPayer,
743
+ signers: [currentPayer],
744
+ blockhash,
745
+ connection,
746
+ simulate,
747
+ });
748
+ base64Txs.push(base64Tx);
749
+ }
750
+ return base64Txs;
751
+ }
752
+ catch (error) {
753
+ throw new Error(`构造交易指令失败: ${error.message}`);
754
+ }
755
+ }
756
+ else if (tradeType === 'buyWithSell') {
757
+ // 实现 Pump 的多买多卖逻辑
758
+ try {
759
+ for (const payer of walletAmounts) {
760
+ const currentPayer = getWalletKeypair(payer.privateKey);
761
+ const currentAmount = new BigNumber(payer.amount).times(LAMPORTS_PER_SOL).toFixed(0);
762
+ // 创建组合交易
763
+ const tx = new Transaction();
764
+ let totalBuyReceiveAmount = new BN(0);
765
+ // 根据 volumeType 确定买入和卖出次数
766
+ const { buyCount, sellCount } = getVolumeTypeConfig(volumeType);
767
+ // 执行多次买入
768
+ let remainingAmount = new BigNumber(currentAmount);
769
+ for (let i = 0; i < buyCount; i++) {
770
+ let buyAmount;
771
+ if (i === buyCount - 1) {
772
+ // 最后一次买入时,使用所有剩余资金
773
+ buyAmount = remainingAmount.toFixed(0);
774
+ }
775
+ else {
776
+ // 前面几次按平均分配
777
+ buyAmount = new BigNumber(currentAmount).div(buyCount).toFixed(0);
778
+ remainingAmount = remainingAmount.minus(buyAmount);
779
+ }
780
+ let buyReceiveAmount;
781
+ try {
782
+ buyReceiveAmount = pumpCalc.calculateBuyAmountOut(buyAmount);
783
+ }
784
+ catch (err) {
785
+ console.log('err: ', err);
786
+ break;
787
+ }
788
+ totalBuyReceiveAmount = totalBuyReceiveAmount.add(new BN(buyReceiveAmount.toString()));
789
+ // 添加买入指令
790
+ const [_, buyTx] = await pumpBuySPLInstructions(provider, currentPayer.publicKey, tokenAddress, buyAmount, slippage, new BigNumber(priceInSol).toString(10), creator, buyReceiveAmount.toString());
791
+ tx.add(buyTx);
792
+ }
793
+ // 执行多次卖出
794
+ let remainingTokenAmount = totalBuyReceiveAmount;
795
+ for (let i = 0; i < sellCount; i++) {
796
+ let sellTokenAmount;
797
+ if (i === sellCount - 1) {
798
+ // 最后一次卖出时,卖出所有剩余代币
799
+ sellTokenAmount = remainingTokenAmount.toString();
800
+ }
801
+ else {
802
+ // 前面几次按平均分配
803
+ sellTokenAmount = totalBuyReceiveAmount.div(new BN(sellCount)).toString();
804
+ remainingTokenAmount = remainingTokenAmount.sub(new BN(sellTokenAmount));
805
+ }
806
+ let sellReceiveAmount;
807
+ try {
808
+ sellReceiveAmount = pumpCalc.calculateSellAmountOut(sellTokenAmount);
809
+ }
810
+ catch (err) {
811
+ console.log('err: ', err);
812
+ break;
813
+ }
814
+ // 添加卖出指令
815
+ const sellTx = await pumpSellSPLInstructions(provider, currentPayer, tokenAddress, sellTokenAmount, slippage, sellReceiveAmount, creator);
816
+ tx.add(sellTx);
817
+ }
818
+ const finalTx = getTx(tx, currentPayer, priorityFee, jito);
819
+ addCommission(finalTx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
820
+ const base64Tx = await getBase64Tx({
821
+ tx: finalTx,
822
+ payer: currentPayer,
823
+ signers: [currentPayer],
824
+ blockhash,
825
+ connection,
826
+ lutAccount,
827
+ simulate,
828
+ });
829
+ base64Txs.push(base64Tx);
830
+ }
831
+ return base64Txs;
832
+ }
833
+ catch (error) {
834
+ throw new Error(`构造交易指令失败: ${error.message}`);
835
+ }
836
+ }
837
+ else if (tradeType === 'sniperBuy') {
838
+ if (snipers) {
839
+ let txs = [];
840
+ let signers = [];
841
+ for (const [index, sniper] of snipers.entries()) {
842
+ const currentPayer = getWalletKeypair(sniper.wallet);
843
+ const currentAmount = new BigNumber(sniper.amount).times(10 ** 9).toString(10);
844
+ console.log('currentAmount: ', currentAmount);
845
+ let receiveAmount;
846
+ try {
847
+ receiveAmount = pumpCalc.calculateBuyAmountOut(currentAmount);
848
+ console.log('receiveAmount: ', receiveAmount.toString());
849
+ }
850
+ catch (err) {
851
+ continue;
852
+ }
853
+ const [_, buyTx] = await pumpBuySPLInstructions(provider, currentPayer.publicKey, tokenAddress, currentAmount, slippage, new BigNumber(priceInSol).toString(10), creator, receiveAmount.toString());
854
+ if (index % (lutAccount ? 4 : 3) === 0) {
855
+ txs.push(new Transaction());
856
+ signers.push([]);
857
+ }
858
+ txs[txs.length - 1].add(buyTx);
859
+ if (bundleBuyTime === BundleBuyTime.T1_T5 && index === 0) {
860
+ txs[txs.length - 1].add(jito.getTipInstruction(currentPayer.publicKey, priorityFee));
861
+ addCommission(txs[txs.length - 1], currentPayer, commissionWallet, new BigNumber(snipers.length)
862
+ .times(commissionAmount)
863
+ .times(LAMPORTS_PER_SOL)
864
+ .toString(10));
865
+ }
866
+ signers[signers.length - 1].push(currentPayer);
867
+ }
868
+ for (const [index, tx] of txs.entries()) {
869
+ const base64Tx = await getBase64Tx({
870
+ tx,
871
+ payer: signers[0][0], // 第一个交易者作为 fee payer
872
+ signers: [...signers[index]], // 当前交易的所有签名者
873
+ blockhash,
874
+ connection,
875
+ lutAccount,
876
+ simulate,
877
+ });
878
+ base64Txs.push(base64Tx);
879
+ }
880
+ return base64Txs;
881
+ }
882
+ else {
883
+ throw new Error('snipers 不能为空');
884
+ }
885
+ }
886
+ };
887
+ export const raydiumBatchTrade = async ({ connection, tokenAddress, poolId, tradeType, slippage, priorityFee, priceInSol, commissionWallet, commissionAmount, walletAmounts, reverseInfo, decimals, raydiumV4Keys, poolInfo, volumeType = VolumeType.ONE_BUY_ONE_SELL, simulate = false, }) => {
888
+ let info = reverseInfo;
889
+ if (!info) {
890
+ const { poolBaseTokenInfo, poolQuoteTokenInfo } = await raydiumGetPoolInfo(connection, poolId);
891
+ info = {
892
+ mintA: poolInfo.tokenA,
893
+ mintB: poolInfo.tokenB,
894
+ poolBaseTokenInfo: {
895
+ amount: poolBaseTokenInfo.amount.toString(),
896
+ },
897
+ poolQuoteTokenInfo: {
898
+ amount: poolQuoteTokenInfo.amount.toString(),
899
+ },
900
+ };
901
+ }
902
+ const mintA = new PublicKey(info.mintA);
903
+ const mintB = new PublicKey(info.mintB);
904
+ const basereverse = info.poolBaseTokenInfo.amount.toString();
905
+ const quoteReserve = info.poolQuoteTokenInfo.amount.toString();
906
+ const raydiumCalc = new AmmCalc({
907
+ baseReserve: basereverse,
908
+ quoteReserve: quoteReserve,
909
+ baseDecimals: mintA.toBase58() === NATIVE_MINT.toBase58() ? 9 : decimals,
910
+ quoteDecimals: mintB.toBase58() === NATIVE_MINT.toBase58() ? 9 : decimals,
911
+ });
912
+ const base64Txs = [];
913
+ const jito = new JitoJsonRpcClient();
914
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
915
+ if (tradeType === 'buy') {
916
+ for (const payer of walletAmounts) {
917
+ const currentPayer = getWalletKeypair(payer.privateKey);
918
+ const currentAmount = new BigNumber(payer.amount).times(10 ** 9).toFixed(0);
919
+ if (Number(currentAmount) <= 0) {
920
+ continue;
921
+ }
922
+ let receiveAmount;
923
+ try {
924
+ receiveAmount = raydiumCalc.swap(currentAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? true : false);
925
+ }
926
+ catch (err) {
927
+ console.log('err: ', err);
928
+ break;
929
+ }
930
+ const buyTx = await raydiumBuyInstruction({
931
+ amount: currentAmount,
932
+ owner: currentPayer.publicKey,
933
+ poolKeys: raydiumV4Keys,
934
+ mintA: mintA.toBase58(),
935
+ mintB: mintB.toBase58(),
936
+ minAmountOut: new BigNumber(receiveAmount).times(1 - slippage).toFixed(0),
937
+ });
938
+ let tx = getTx(buyTx, currentPayer, priorityFee, jito);
939
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
940
+ // console.log('tx: ', tx);
941
+ const base64Tx = await getBase64Tx({
942
+ tx,
943
+ payer: currentPayer,
944
+ signers: [currentPayer],
945
+ blockhash,
946
+ connection,
947
+ simulate,
948
+ });
949
+ base64Txs.push(base64Tx);
950
+ }
951
+ }
952
+ else if (tradeType === 'sell') {
953
+ for (const payer of walletAmounts) {
954
+ const currentPayer = getWalletKeypair(payer.privateKey);
955
+ const currentAmount = new BigNumber(payer.amount).times(10 ** decimals).toFixed(0);
956
+ let receiveAmount;
957
+ if (Number(currentAmount) <= 0) {
958
+ continue;
959
+ }
960
+ try {
961
+ receiveAmount = raydiumCalc.swap(currentAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? false : true);
962
+ }
963
+ catch (err) {
964
+ console.log('err: ', err);
965
+ break;
966
+ }
967
+ const sellTx = await raydiumSellInstruction({
968
+ amount: currentAmount,
969
+ owner: currentPayer.publicKey,
970
+ poolKeys: raydiumV4Keys,
971
+ mintA: mintA.toBase58(),
972
+ mintB: mintB.toBase58(),
973
+ minAmountOut: new BigNumber(receiveAmount).times(1 - slippage).toFixed(0),
974
+ });
975
+ let tx = getTx(sellTx, currentPayer, priorityFee, jito);
976
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(receiveAmount).times(commissionAmount).toFixed(0));
977
+ const base64Tx = await getBase64Tx({
978
+ tx,
979
+ payer: currentPayer,
980
+ signers: [currentPayer],
981
+ blockhash,
982
+ connection,
983
+ simulate,
984
+ });
985
+ base64Txs.push(base64Tx);
986
+ }
987
+ }
988
+ else if (tradeType === 'buyWithSell') {
989
+ // 实现 Raydium 的多买多卖逻辑
990
+ for (const payer of walletAmounts) {
991
+ const currentPayer = getWalletKeypair(payer.privateKey);
992
+ const currentAmount = new BigNumber(payer.amount).times(10 ** 9).toFixed(0);
993
+ if (Number(currentAmount) <= 0) {
994
+ continue;
995
+ }
996
+ // 提前创建 wsolAccount
997
+ const { wsolAccount, createWsolAccount } = await getNewWsolAccount(currentPayer.publicKey, new BigNumber(currentAmount).times(1 + slippage).toFixed(0));
998
+ try {
999
+ // 创建组合交易
1000
+ const tx = new Transaction();
1001
+ let totalBuyReceiveAmount = new BigNumber(0);
1002
+ // 根据 volumeType 确定买入和卖出次数
1003
+ const { buyCount, sellCount } = getVolumeTypeConfig(volumeType);
1004
+ // 执行多次买入
1005
+ let remainingAmount = new BigNumber(currentAmount);
1006
+ for (let i = 0; i < buyCount; i++) {
1007
+ let buyAmount;
1008
+ if (i === buyCount - 1) {
1009
+ // 最后一次买入时,使用所有剩余资金
1010
+ buyAmount = remainingAmount.toFixed(0);
1011
+ }
1012
+ else {
1013
+ // 前面几次按平均分配
1014
+ buyAmount = new BigNumber(currentAmount).div(buyCount).toFixed(0);
1015
+ remainingAmount = remainingAmount.minus(buyAmount);
1016
+ }
1017
+ let buyReceiveAmount = raydiumCalc.swap(buyAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? true : false);
1018
+ totalBuyReceiveAmount = totalBuyReceiveAmount.plus(buyReceiveAmount);
1019
+ // 添加买入指令
1020
+ const buyTx = await raydiumBuyInstruction({
1021
+ amount: buyAmount,
1022
+ owner: currentPayer.publicKey,
1023
+ poolKeys: raydiumV4Keys,
1024
+ mintA: mintA.toBase58(),
1025
+ mintB: mintB.toBase58(),
1026
+ minAmountOut: new BigNumber(buyReceiveAmount).times(1 - slippage).toFixed(0),
1027
+ needCreateAtaAccount: i === 0,
1028
+ needCloseTokenAccount: false,
1029
+ needCloseWsolAccount: false,
1030
+ initialWsolAccount: wsolAccount,
1031
+ createWsolAccountInstruction: createWsolAccount,
1032
+ });
1033
+ tx.add(buyTx);
1034
+ }
1035
+ // 执行多次卖出
1036
+ let remainingTokenAmount = totalBuyReceiveAmount;
1037
+ for (let i = 0; i < sellCount; i++) {
1038
+ let sellTokenAmount;
1039
+ if (i === sellCount - 1) {
1040
+ // 最后一次卖出时,卖出所有剩余代币
1041
+ sellTokenAmount = remainingTokenAmount.toFixed(0);
1042
+ }
1043
+ else {
1044
+ // 前面几次按平均分配
1045
+ sellTokenAmount = totalBuyReceiveAmount.div(sellCount).toFixed(0);
1046
+ remainingTokenAmount = remainingTokenAmount.minus(sellTokenAmount);
1047
+ }
1048
+ let sellReceiveAmount = raydiumCalc.swap(sellTokenAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? false : true);
1049
+ // 添加卖出指令
1050
+ const sellTx = await raydiumSellInstruction({
1051
+ amount: sellTokenAmount,
1052
+ owner: currentPayer.publicKey,
1053
+ poolKeys: raydiumV4Keys,
1054
+ mintA: mintA.toBase58(),
1055
+ mintB: mintB.toBase58(),
1056
+ minAmountOut: new BigNumber(sellReceiveAmount).times(1 - slippage).toFixed(0),
1057
+ needCreateAtaAccount: false,
1058
+ needCloseTokenAccount: i === sellCount - 1,
1059
+ needCloseWsolAccount: i === sellCount - 1,
1060
+ initialWsolAccount: wsolAccount,
1061
+ });
1062
+ tx.add(sellTx);
1063
+ }
1064
+ let finalTx = getTx(tx, currentPayer, priorityFee, jito);
1065
+ addCommission(finalTx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
1066
+ const base64Tx = await getBase64Tx({
1067
+ tx: finalTx,
1068
+ payer: currentPayer,
1069
+ signers: [currentPayer],
1070
+ blockhash,
1071
+ connection,
1072
+ simulate,
1073
+ });
1074
+ base64Txs.push(base64Tx);
1075
+ }
1076
+ catch (err) {
1077
+ console.log('raydium buyWithSell err: ', err);
1078
+ break;
1079
+ }
1080
+ }
1081
+ }
1082
+ return base64Txs;
1083
+ };
1084
+ export const raydiumCpmmBatchTrade = async ({ connection, tokenAddress, poolId, tradeType, slippage, priorityFee, priceInSol, commissionWallet, commissionAmount, walletAmounts, reverseInfo, decimals, raydiumCpmmKeys, poolInfo, volumeType = VolumeType.ONE_BUY_ONE_SELL, simulate = false, }) => {
1085
+ let info = reverseInfo;
1086
+ if (!info) {
1087
+ const { poolBaseTokenInfo, poolQuoteTokenInfo } = await raydiumGetCpmmPoolInfo(connection, poolId);
1088
+ info = {
1089
+ mintA: poolInfo.tokenA,
1090
+ mintB: poolInfo.tokenB,
1091
+ poolBaseTokenInfo: {
1092
+ amount: poolBaseTokenInfo.amount.toString(),
1093
+ },
1094
+ poolQuoteTokenInfo: {
1095
+ amount: poolQuoteTokenInfo.amount.toString(),
1096
+ },
1097
+ };
1098
+ }
1099
+ const mintA = new PublicKey(info.mintA);
1100
+ const mintB = new PublicKey(info.mintB);
1101
+ const basereverse = info.poolBaseTokenInfo.amount.toString();
1102
+ const quoteReserve = info.poolQuoteTokenInfo.amount.toString();
1103
+ const raydiumCalc = new AmmCalc({
1104
+ baseReserve: basereverse,
1105
+ quoteReserve: quoteReserve,
1106
+ baseDecimals: mintA.toBase58() === NATIVE_MINT.toBase58() ? 9 : decimals,
1107
+ quoteDecimals: mintB.toBase58() === NATIVE_MINT.toBase58() ? 9 : decimals,
1108
+ });
1109
+ const base64Txs = [];
1110
+ const jito = new JitoJsonRpcClient();
1111
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
1112
+ if (tradeType === 'buy' || tradeType === 'sniperBuy') {
1113
+ for (const payer of walletAmounts) {
1114
+ const currentPayer = getWalletKeypair(payer.privateKey);
1115
+ const currentAmount = new BigNumber(payer.amount).times(10 ** 9).toFixed(0);
1116
+ if (Number(currentAmount) <= 0) {
1117
+ continue;
1118
+ }
1119
+ let receiveAmount;
1120
+ try {
1121
+ receiveAmount = raydiumCalc.swap(currentAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? true : false);
1122
+ }
1123
+ catch (err) {
1124
+ console.log('err: ', err);
1125
+ break;
1126
+ }
1127
+ const buyTx = await raydiumCpmmSwapBaseInBuyInstruction({
1128
+ amountInMax: currentAmount,
1129
+ owner: currentPayer.publicKey,
1130
+ poolKeys: raydiumCpmmKeys,
1131
+ poolId,
1132
+ mintA: mintA.toBase58(),
1133
+ mintB: mintB.toBase58(),
1134
+ amountOutMin: new BigNumber(receiveAmount).times(1 - slippage).toFixed(0),
1135
+ needCreateAtaAccount: true,
1136
+ needCloseTokenAccount: true,
1137
+ });
1138
+ let tx = getTx(buyTx, currentPayer, priorityFee, jito);
1139
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
1140
+ // console.log('tx: ', tx);
1141
+ const base64Tx = await getBase64Tx({
1142
+ tx,
1143
+ payer: currentPayer,
1144
+ signers: [currentPayer],
1145
+ blockhash,
1146
+ connection,
1147
+ simulate,
1148
+ });
1149
+ base64Txs.push(base64Tx);
1150
+ }
1151
+ }
1152
+ else if (tradeType === 'sell') {
1153
+ for (const payer of walletAmounts) {
1154
+ const currentPayer = getWalletKeypair(payer.privateKey);
1155
+ const currentAmount = new BigNumber(payer.amount).times(10 ** decimals).toFixed(0);
1156
+ let receiveAmount;
1157
+ if (Number(currentAmount) <= 0) {
1158
+ continue;
1159
+ }
1160
+ try {
1161
+ receiveAmount = raydiumCalc.swap(currentAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? false : true);
1162
+ }
1163
+ catch (err) {
1164
+ console.log('err: ', err);
1165
+ break;
1166
+ }
1167
+ const sellTx = await raydiumCpmmSellInstruction({
1168
+ amount: currentAmount,
1169
+ owner: currentPayer.publicKey,
1170
+ poolKeys: raydiumCpmmKeys,
1171
+ poolId,
1172
+ mintA: mintA.toBase58(),
1173
+ mintB: mintB.toBase58(),
1174
+ minAmountOut: new BigNumber(receiveAmount).times(1 - slippage).toFixed(0),
1175
+ connection,
1176
+ needCreateAtaAccount: true,
1177
+ needCloseTokenAccount: false,
1178
+ needCloseWsolAccount: true,
1179
+ });
1180
+ let tx = getTx(sellTx, currentPayer, priorityFee, jito);
1181
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(receiveAmount).times(commissionAmount).toFixed(0));
1182
+ const base64Tx = await getBase64Tx({
1183
+ tx,
1184
+ payer: currentPayer,
1185
+ signers: [currentPayer],
1186
+ blockhash,
1187
+ connection,
1188
+ simulate,
1189
+ });
1190
+ base64Txs.push(base64Tx);
1191
+ }
1192
+ }
1193
+ else if (tradeType === 'buyWithSell') {
1194
+ // 实现 Raydium 的多买多卖逻辑
1195
+ for (const payer of walletAmounts) {
1196
+ const currentPayer = getWalletKeypair(payer.privateKey);
1197
+ const currentAmount = new BigNumber(payer.amount).times(10 ** 9).toFixed(0);
1198
+ if (Number(currentAmount) <= 0) {
1199
+ continue;
1200
+ }
1201
+ // 提前创建 wsolAccount
1202
+ const { wsolAccount, createWsolAccount } = await getNewWsolAccount(currentPayer.publicKey, new BigNumber(currentAmount).times(1 + slippage).toFixed(0));
1203
+ try {
1204
+ // 创建组合交易
1205
+ const tx = new Transaction();
1206
+ let totalBuyReceiveAmount = new BigNumber(0);
1207
+ // 根据 volumeType 确定买入和卖出次数
1208
+ const { buyCount, sellCount } = getVolumeTypeConfig(volumeType);
1209
+ // 执行多次买入
1210
+ let remainingAmount = new BigNumber(currentAmount);
1211
+ for (let i = 0; i < buyCount; i++) {
1212
+ let buyAmount;
1213
+ if (i === buyCount - 1) {
1214
+ // 最后一次买入时,使用所有剩余资金
1215
+ buyAmount = remainingAmount.toFixed(0);
1216
+ }
1217
+ else {
1218
+ // 前面几次按平均分配
1219
+ buyAmount = new BigNumber(currentAmount).div(buyCount).toFixed(0);
1220
+ remainingAmount = remainingAmount.minus(buyAmount);
1221
+ }
1222
+ let buyReceiveAmount = raydiumCalc.swap(buyAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? true : false);
1223
+ totalBuyReceiveAmount = totalBuyReceiveAmount.plus(buyReceiveAmount);
1224
+ // 添加买入指令
1225
+ const buyTx = await raydiumCpmmSwapBaseOutBuyInstruction({
1226
+ amountInMax: new BigNumber(buyAmount).times(1 + slippage).toFixed(0),
1227
+ owner: currentPayer.publicKey,
1228
+ poolKeys: raydiumCpmmKeys,
1229
+ poolId,
1230
+ mintA: mintA.toBase58(),
1231
+ mintB: mintB.toBase58(),
1232
+ amountOut: buyReceiveAmount,
1233
+ needCreateAtaAccount: i === 0,
1234
+ needCloseTokenAccount: false,
1235
+ initialWsolAccount: wsolAccount,
1236
+ createWsolAccountInstruction: createWsolAccount,
1237
+ });
1238
+ tx.add(buyTx);
1239
+ }
1240
+ // 执行多次卖出
1241
+ let remainingTokenAmount = totalBuyReceiveAmount;
1242
+ for (let i = 0; i < sellCount; i++) {
1243
+ let sellTokenAmount;
1244
+ if (i === sellCount - 1) {
1245
+ // 最后一次卖出时,卖出所有剩余代币
1246
+ sellTokenAmount = remainingTokenAmount.toFixed(0);
1247
+ }
1248
+ else {
1249
+ // 前面几次按平均分配
1250
+ sellTokenAmount = totalBuyReceiveAmount.div(sellCount).toFixed(0);
1251
+ remainingTokenAmount = remainingTokenAmount.minus(sellTokenAmount);
1252
+ }
1253
+ let sellReceiveAmount = raydiumCalc.swap(sellTokenAmount, mintA.toBase58() === NATIVE_MINT.toBase58() ? false : true);
1254
+ // 添加卖出指令
1255
+ const sellTx = await raydiumCpmmSellInstruction({
1256
+ amount: sellTokenAmount,
1257
+ owner: currentPayer.publicKey,
1258
+ poolKeys: raydiumCpmmKeys,
1259
+ poolId,
1260
+ mintA: mintA.toBase58(),
1261
+ mintB: mintB.toBase58(),
1262
+ minAmountOut: new BigNumber(sellReceiveAmount).times(1 - slippage).toFixed(0),
1263
+ connection,
1264
+ needCreateAtaAccount: false,
1265
+ needCloseTokenAccount: i === sellCount - 1,
1266
+ needCloseWsolAccount: i === sellCount - 1,
1267
+ initialWsolAccount: wsolAccount,
1268
+ });
1269
+ tx.add(sellTx);
1270
+ }
1271
+ let finalTx = getTx(tx, currentPayer, priorityFee, jito);
1272
+ addCommission(finalTx, currentPayer, commissionWallet, commissionAmount);
1273
+ const base64Tx = await getBase64Tx({
1274
+ tx: finalTx,
1275
+ payer: currentPayer,
1276
+ signers: [currentPayer],
1277
+ blockhash,
1278
+ connection,
1279
+ simulate,
1280
+ });
1281
+ base64Txs.push(base64Tx);
1282
+ }
1283
+ catch (err) {
1284
+ console.log('raydium buyWithSell err: ', err);
1285
+ break;
1286
+ }
1287
+ }
1288
+ }
1289
+ return base64Txs;
1290
+ };
1291
+ // 获取刷量类型配置
1292
+ const getVolumeTypeConfig = (volumeType) => {
1293
+ switch (volumeType) {
1294
+ case VolumeType.ONE_BUY_ONE_SELL:
1295
+ return { buyCount: 1, sellCount: 1 };
1296
+ case VolumeType.ONE_BUY_TWO_SELL:
1297
+ return { buyCount: 1, sellCount: 2 };
1298
+ case VolumeType.ONE_BUY_THREE_SELL:
1299
+ return { buyCount: 1, sellCount: 3 };
1300
+ case VolumeType.TWO_BUY_ONE_SELL:
1301
+ return { buyCount: 2, sellCount: 1 };
1302
+ case VolumeType.THREE_BUY_ONE_SELL:
1303
+ return { buyCount: 3, sellCount: 1 };
1304
+ default:
1305
+ return { buyCount: 1, sellCount: 1 };
1306
+ }
1307
+ };
1308
+ export const meteoraDlmmBatchTrade = async ({ connection, tokenAddress, poolId, tradeType, slippage, priorityFee, decimals, reverseInfo, commissionWallet, commissionAmount, creator, walletAmounts, bundleBuyTime, volumeType = VolumeType.ONE_BUY_ONE_SELL, simulate = false, }) => {
1309
+ const provider = new AnchorProvider(connection, {
1310
+ publicKey: Keypair.generate().publicKey,
1311
+ signTransaction: async () => {
1312
+ throw new Error('不支持签名');
1313
+ },
1314
+ signAllTransactions: async () => {
1315
+ throw new Error('不支持签名');
1316
+ },
1317
+ }, {});
1318
+ const binArray = await getBinArray({
1319
+ connection,
1320
+ poolId,
1321
+ });
1322
+ const dlmmPool = await MeteoraDLMM.create(connection, new PublicKey(poolId), {
1323
+ programId: METEORA_DLMM_PROGRAM,
1324
+ });
1325
+ // 使用传入的reverseInfo或获取池子数据
1326
+ if (!reverseInfo) {
1327
+ throw new Error('缺少 Meteora DLMM 池子信息');
1328
+ }
1329
+ console.log(' binStep:', typeof reverseInfo.binStep, reverseInfo.binStep);
1330
+ console.log(' activeId:', typeof reverseInfo.activeId, reverseInfo.activeId);
1331
+ const payers = walletAmounts.map(item => getWalletKeypair(item.privateKey));
1332
+ const jito = new JitoJsonRpcClient();
1333
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
1334
+ const base64Txs = [];
1335
+ // 处理交易逻辑
1336
+ if (tradeType === 'buy') {
1337
+ // try {
1338
+ for (const payer of walletAmounts) {
1339
+ const currentPayer = getWalletKeypair(payer.privateKey);
1340
+ const currentAmount = new BigNumber(payer.amount).times(LAMPORTS_PER_SOL).toFixed(0);
1341
+ // 计算预期获得的代币数量
1342
+ const swapQuote = dlmmPool.swapQuote(new BN(currentAmount), reverseInfo.reserveY == NATIVE_MINT.toBase58(), new BN(slippage), binArray);
1343
+ const buyTx = await meteoraDlmmBuyInstructions({
1344
+ provider,
1345
+ owner: currentPayer,
1346
+ mint: new PublicKey(tokenAddress),
1347
+ poolInfo: {
1348
+ poolId: poolId,
1349
+ mintA: reverseInfo.mintA,
1350
+ mintB: reverseInfo.mintB,
1351
+ reverseX: reverseInfo.reserveX,
1352
+ reverseY: reverseInfo.reserveY,
1353
+ oracle: reverseInfo.oracle,
1354
+ },
1355
+ amount: BigInt(currentAmount),
1356
+ tokenAmount: BigInt(swapQuote.minOutAmount.toString()),
1357
+ slippage,
1358
+ needCreateAtaAccount: true,
1359
+ needCloseTokenAccount: false,
1360
+ binArraysPubkey: swapQuote.binArraysPubkey,
1361
+ });
1362
+ const tx = getTx(buyTx, currentPayer, priorityFee, jito);
1363
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
1364
+ const base64Tx = await getBase64Tx({
1365
+ tx,
1366
+ payer: currentPayer,
1367
+ signers: [currentPayer],
1368
+ blockhash,
1369
+ connection,
1370
+ simulate,
1371
+ });
1372
+ base64Txs.push(base64Tx);
1373
+ }
1374
+ return base64Txs;
1375
+ // } catch (error: any) {
1376
+ // throw new Error(`构造买入交易指令失败: ${error.message}`);
1377
+ // }
1378
+ }
1379
+ else if (tradeType === 'sell') {
1380
+ try {
1381
+ for (const payer of walletAmounts) {
1382
+ const currentPayer = getWalletKeypair(payer.privateKey);
1383
+ const currentAmount = new BigNumber(payer.amount).times(10 ** decimals).toFixed(0);
1384
+ // 计算预期获得的SOL数量
1385
+ const swapQuote = dlmmPool.swapQuote(new BN(currentAmount), reverseInfo.mintA == NATIVE_MINT.toBase58(), new BN(slippage), binArray);
1386
+ const swapQuote2 = dlmmPool.swapQuote(new BN(currentAmount), reverseInfo.mintA == NATIVE_MINT.toBase58(), new BN(10), binArray);
1387
+ const sellTx = await meteoraDlmmSellInstructions({
1388
+ provider,
1389
+ owner: currentPayer,
1390
+ mint: new PublicKey(tokenAddress),
1391
+ poolInfo: {
1392
+ poolId: poolId,
1393
+ mintA: reverseInfo.mintA,
1394
+ mintB: reverseInfo.mintB,
1395
+ reverseX: reverseInfo.reserveX,
1396
+ reverseY: reverseInfo.reserveY,
1397
+ oracle: reverseInfo.oracle,
1398
+ },
1399
+ amount: BigInt(currentAmount),
1400
+ minAmountOut: BigInt(new BigNumber(swapQuote.minOutAmount.toString()).toFixed(0)),
1401
+ needCreateAtaAccount: true,
1402
+ needCloseTokenAccount: true,
1403
+ binArraysPubkey: swapQuote.binArraysPubkey,
1404
+ });
1405
+ const tx = getTx(sellTx, currentPayer, priorityFee, jito);
1406
+ addCommission(tx, currentPayer, commissionWallet, new BigNumber(swapQuote2.minOutAmount.toString()).times(commissionAmount).toFixed(0));
1407
+ const base64Tx = await getBase64Tx({
1408
+ tx,
1409
+ payer: currentPayer,
1410
+ signers: [currentPayer],
1411
+ blockhash,
1412
+ connection,
1413
+ simulate: true,
1414
+ });
1415
+ base64Txs.push(base64Tx);
1416
+ }
1417
+ return base64Txs;
1418
+ }
1419
+ catch (error) {
1420
+ throw new Error(`构造卖出交易指令失败: ${error.message}`);
1421
+ }
1422
+ }
1423
+ else if (tradeType === 'buyWithSell') {
1424
+ // 实现 Meteora DLMM 的多买多卖逻辑
1425
+ try {
1426
+ for (const payer of walletAmounts) {
1427
+ const currentPayer = getWalletKeypair(payer.privateKey);
1428
+ const currentAmount = new BigNumber(payer.amount).times(LAMPORTS_PER_SOL).toFixed(0);
1429
+ // 提前创建 wsolAccount
1430
+ const { wsolAccount, createWsolAccount } = await getNewWsolAccount(currentPayer.publicKey, new BigNumber(currentAmount).times(1 + slippage).toFixed(0));
1431
+ // 创建组合交易
1432
+ const tx = new Transaction();
1433
+ let totalBuyReceiveAmount = new BN(0);
1434
+ // 根据 volumeType 确定买入和卖出次数
1435
+ const { buyCount, sellCount } = getVolumeTypeConfig(volumeType);
1436
+ // 执行多次买入
1437
+ let remainingAmount = new BigNumber(currentAmount);
1438
+ for (let i = 0; i < buyCount; i++) {
1439
+ let buyAmount;
1440
+ if (i === buyCount - 1) {
1441
+ // 最后一次买入时,使用所有剩余资金
1442
+ buyAmount = remainingAmount.toFixed(0);
1443
+ }
1444
+ else {
1445
+ // 前面几次按平均分配
1446
+ buyAmount = new BigNumber(currentAmount).div(buyCount).toFixed(0);
1447
+ remainingAmount = remainingAmount.minus(buyAmount);
1448
+ }
1449
+ const swapQuote = dlmmPool.swapQuote(new BN(buyAmount), reverseInfo.reserveY == NATIVE_MINT.toBase58(), new BN(slippage), binArray);
1450
+ totalBuyReceiveAmount = totalBuyReceiveAmount.add(new BN(swapQuote.minOutAmount.toString()));
1451
+ // 添加买入指令
1452
+ const buyTx = await meteoraDlmmBuyExactOutInstructions({
1453
+ provider,
1454
+ owner: currentPayer,
1455
+ mint: new PublicKey(tokenAddress),
1456
+ poolInfo: {
1457
+ poolId: poolId,
1458
+ mintA: reverseInfo.mintA,
1459
+ mintB: reverseInfo.mintB,
1460
+ reverseX: reverseInfo.reserveX,
1461
+ reverseY: reverseInfo.reserveY,
1462
+ oracle: reverseInfo.oracle,
1463
+ },
1464
+ amountInMax: BigInt(buyAmount),
1465
+ tokenAmount: BigInt(swapQuote.minOutAmount.toString()),
1466
+ needCreateAtaAccount: i === 0, // 只在第一次创建ATA
1467
+ needCloseTokenAccount: false,
1468
+ needCloseWsolAccount: false,
1469
+ initialWsolAccount: wsolAccount,
1470
+ createWsolAccountInstruction: i === 0 ? createWsolAccount : undefined,
1471
+ binArraysPubkey: swapQuote.binArraysPubkey,
1472
+ });
1473
+ // 添加买入交易指令
1474
+ tx.add(...buyTx.instructions);
1475
+ }
1476
+ // 执行多次卖出
1477
+ const avgSellAmount = totalBuyReceiveAmount.div(new BN(sellCount));
1478
+ for (let i = 0; i < sellCount; i++) {
1479
+ let sellAmount;
1480
+ if (i === sellCount - 1) {
1481
+ // 最后一次卖出时,卖出所有剩余代币
1482
+ sellAmount = totalBuyReceiveAmount;
1483
+ }
1484
+ else {
1485
+ sellAmount = avgSellAmount;
1486
+ totalBuyReceiveAmount = totalBuyReceiveAmount.sub(avgSellAmount);
1487
+ }
1488
+ const swapQuote = dlmmPool.swapQuote(new BN(sellAmount), reverseInfo.mintA == NATIVE_MINT.toBase58(), new BN(10), binArray);
1489
+ // 添加卖出指令
1490
+ const sellTx = await meteoraDlmmSellInstructions({
1491
+ provider,
1492
+ owner: currentPayer,
1493
+ mint: new PublicKey(tokenAddress),
1494
+ poolInfo: {
1495
+ poolId: poolId,
1496
+ mintA: reverseInfo.mintA,
1497
+ mintB: reverseInfo.mintB,
1498
+ reverseX: reverseInfo.reserveX,
1499
+ reverseY: reverseInfo.reserveY,
1500
+ oracle: reverseInfo.oracle,
1501
+ },
1502
+ amount: BigInt(sellAmount.toString()),
1503
+ minAmountOut: BigInt(0),
1504
+ needCreateAtaAccount: false,
1505
+ needCloseTokenAccount: i === sellCount - 1, // 只在最后一次关闭Token账户
1506
+ needCloseWsolAccount: i === sellCount - 1, // 只在最后一次关闭WSOL账户
1507
+ initialWsolAccount: wsolAccount,
1508
+ binArraysPubkey: swapQuote.binArraysPubkey,
1509
+ });
1510
+ // 添加卖出交易指令
1511
+ tx.add(...sellTx.instructions);
1512
+ }
1513
+ const finalTx = getTx(tx, currentPayer, priorityFee, jito);
1514
+ addCommission(finalTx, currentPayer, commissionWallet, new BigNumber(currentAmount).times(commissionAmount).toFixed(0));
1515
+ const base64Tx = await getBase64Tx({
1516
+ tx: finalTx,
1517
+ payer: currentPayer,
1518
+ signers: [currentPayer],
1519
+ blockhash,
1520
+ connection,
1521
+ simulate,
1522
+ });
1523
+ base64Txs.push(base64Tx);
1524
+ }
1525
+ return base64Txs;
1526
+ }
1527
+ catch (error) {
1528
+ throw new Error(`构造买卖组合交易指令失败: ${error.message}`);
1529
+ }
1530
+ }
1531
+ throw new Error(`不支持的交易类型: ${tradeType}`);
1532
+ };
1533
+ const getBase64Tx = async ({ tx, payer, signers, blockhash, connection, lutAccount, simulate = false, }) => {
1534
+ console.log('tx.instructions: ', tx.instructions);
1535
+ const messageV0 = new TransactionMessage({
1536
+ payerKey: signers[0].publicKey,
1537
+ recentBlockhash: blockhash,
1538
+ instructions: tx.instructions,
1539
+ }).compileToV0Message(lutAccount ? [lutAccount] : []);
1540
+ const versionedTx = new VersionedTransaction(messageV0);
1541
+ versionedTx.sign(signers);
1542
+ if (simulate) {
1543
+ try {
1544
+ const log = await connection.simulateTransaction(versionedTx);
1545
+ console.log('simulate log: ', log);
1546
+ if (log.value.logs?.includes('insufficient')) {
1547
+ throw new Error('Insufficient funds');
1548
+ }
1549
+ if (log.value.err) {
1550
+ throw new Error(log.value.err.toString());
1551
+ }
1552
+ }
1553
+ catch (err) {
1554
+ console.log('simulate err: ', err);
1555
+ throw err;
1556
+ }
1557
+ }
1558
+ const serializedTx = versionedTx.serialize();
1559
+ const base64Tx = Buffer.from(serializedTx).toString('base64');
1560
+ return base64Tx;
1561
+ };
1562
+ const getTx = (tx, payer, priorityFee, jito, cuLimit) => {
1563
+ const transaction = new Transaction();
1564
+ transaction.add(tx);
1565
+ const cu = getCU(priorityFee, cuLimit);
1566
+ transaction.add(cu.limitIx);
1567
+ transaction.add(cu.priceIx);
1568
+ if (jito) {
1569
+ transaction.add(jito.getTipInstruction(payer.publicKey, priorityFee));
1570
+ }
1571
+ return transaction;
1572
+ };
1573
+ //# sourceMappingURL=index.js.map