four-flap-meme-sdk 2.0.0 → 2.2.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 (220) hide show
  1. package/dist/__tests__/subpath-exports.test.js +64 -0
  2. package/dist/chains/bsc/iro.d.ts +5 -0
  3. package/dist/chains/bsc/iro.js +4 -0
  4. package/dist/chains/eni/flat-aliases.d.ts +10 -0
  5. package/dist/chains/eni/flat-aliases.js +8 -0
  6. package/dist/chains/eni/index.d.ts +1 -0
  7. package/dist/chains/eni/index.js +1 -0
  8. package/dist/chains/index.d.ts +13 -0
  9. package/dist/chains/index.js +13 -0
  10. package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +13 -0
  11. package/dist/chains/xlayer/eip7702/flat-aliases.js +10 -0
  12. package/dist/chains/xlayer/eip7702/index.d.ts +1 -0
  13. package/dist/chains/xlayer/eip7702/index.js +1 -0
  14. package/dist/chains/xlayer/index.d.ts +3 -2
  15. package/dist/chains/xlayer/index.js +4 -7
  16. package/dist/flap/index.d.ts +10 -0
  17. package/dist/flap/index.js +8 -0
  18. package/dist/merkle/index.d.ts +12 -0
  19. package/dist/merkle/index.js +11 -0
  20. package/dist/shared/constants/index.d.ts +2 -0
  21. package/dist/shared/index.d.ts +2 -0
  22. package/dist/vanity/index.d.ts +5 -0
  23. package/dist/vanity/index.js +5 -0
  24. package/package.json +93 -2
  25. package/dist/chains/bsc/four/disperse.d.ts +0 -12
  26. package/dist/chains/bsc/four/disperse.js +0 -470
  27. package/dist/chains/bsc/four/pairwise.d.ts +0 -7
  28. package/dist/chains/bsc/four/pairwise.js +0 -308
  29. package/dist/chains/bsc/four/submit/blockrazor.d.ts +0 -18
  30. package/dist/chains/bsc/four/submit/blockrazor.js +0 -86
  31. package/dist/chains/bsc/four/submit/direct.d.ts +0 -66
  32. package/dist/chains/bsc/four/submit/direct.js +0 -452
  33. package/dist/chains/bsc/four/submit/helpers.d.ts +0 -18
  34. package/dist/chains/bsc/four/submit/helpers.js +0 -57
  35. package/dist/chains/bsc/four/submit/index.d.ts +0 -12
  36. package/dist/chains/bsc/four/submit/index.js +0 -11
  37. package/dist/chains/bsc/four/submit/merkle.d.ts +0 -18
  38. package/dist/chains/bsc/four/submit/merkle.js +0 -74
  39. package/dist/chains/bsc/four/submit/types.d.ts +0 -143
  40. package/dist/chains/bsc/four/swap/index.d.ts +0 -32
  41. package/dist/chains/bsc/four/swap/index.js +0 -829
  42. package/dist/chains/bsc/four/swap/types.d.ts +0 -70
  43. package/dist/chains/bsc/four/swap/types.js +0 -1
  44. package/dist/chains/bsc/four/sweep.d.ts +0 -13
  45. package/dist/chains/bsc/four/sweep.js +0 -788
  46. package/dist/chains/bsc/four/utils/index.d.ts +0 -20
  47. package/dist/chains/bsc/four/utils/index.js +0 -1558
  48. package/dist/chains/bsc/four/utils/types.d.ts +0 -1
  49. package/dist/chains/bsc/four/utils/types.js +0 -1
  50. package/dist/chains/bsc/pancake/bundle-buy-first/index.d.ts +0 -8
  51. package/dist/chains/bsc/pancake/bundle-buy-first/index.js +0 -907
  52. package/dist/chains/bsc/pancake/bundle-buy-first/types.d.ts +0 -73
  53. package/dist/chains/bsc/pancake/bundle-buy-first/types.js +0 -1
  54. package/dist/chains/bsc/pancake/bundle-swap/helpers.d.ts +0 -102
  55. package/dist/chains/bsc/pancake/bundle-swap/helpers.js +0 -572
  56. package/dist/chains/bsc/pancake/bundle-swap/index.d.ts +0 -50
  57. package/dist/chains/bsc/pancake/bundle-swap/index.js +0 -1066
  58. package/dist/chains/bsc/pancake/bundle-swap/types.d.ts +0 -202
  59. package/dist/chains/bsc/pancake/bundle-swap/types.js +0 -3
  60. package/dist/chains/xlayer/eip7702/bundle-swap/index.d.ts +0 -72
  61. package/dist/chains/xlayer/eip7702/bundle-swap/index.js +0 -921
  62. package/dist/chains/xlayer/eip7702/bundle-swap/types.d.ts +0 -65
  63. package/dist/chains/xlayer/eip7702/bundle-swap/types.js +0 -1
  64. package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.d.ts +0 -128
  65. package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.js +0 -857
  66. package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.d.ts +0 -85
  67. package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.js +0 -1
  68. package/dist/chains/xlayer/eip7702/volume/index.d.ts +0 -96
  69. package/dist/chains/xlayer/eip7702/volume/index.js +0 -793
  70. package/dist/chains/xlayer/eip7702/volume/types.d.ts +0 -124
  71. package/dist/chains/xlayer/eip7702/volume/types.js +0 -1
  72. package/dist/chains/xlayer/eoa/types-core.d.ts +0 -363
  73. package/dist/chains/xlayer/eoa/types-core.js +0 -53
  74. package/dist/chains/xlayer/eoa/types-create.d.ts +0 -413
  75. package/dist/chains/xlayer/eoa/types-create.js +0 -9
  76. package/dist/chains/xlayer/eoa/types-volume.d.ts +0 -209
  77. package/dist/chains/xlayer/eoa/types-volume.js +0 -13
  78. package/dist/dex/direct-router/index.d.ts +0 -70
  79. package/dist/dex/direct-router/index.js +0 -1410
  80. package/dist/dex/direct-router/types.d.ts +0 -81
  81. package/dist/dex/direct-router/types.js +0 -1
  82. package/dist/shared/abis/TaxToken.json +0 -969
  83. package/dist/shared/abis/TokenManager.json +0 -836
  84. package/dist/shared/abis/TokenManager2.json +0 -136
  85. package/dist/shared/abis/TokenManagerHelper3.json +0 -993
  86. package/dist/shared/abis 2/TaxToken.json +0 -105
  87. package/dist/shared/abis 2/TokenManager.json +0 -836
  88. package/dist/shared/abis 2/TokenManager2.json +0 -60
  89. package/dist/shared/abis 2/TokenManagerHelper3.json +0 -993
  90. package/dist/shared/abis 2/common.d.ts +0 -85
  91. package/dist/shared/abis 2/common.js +0 -254
  92. package/dist/shared/abis 2/index.d.ts +0 -8
  93. package/dist/shared/abis 2/index.js +0 -8
  94. package/dist/shared/clients 2/blockrazor.d.ts +0 -314
  95. package/dist/shared/clients 2/blockrazor.js +0 -596
  96. package/dist/shared/clients 2/club48.d.ts +0 -154
  97. package/dist/shared/clients 2/club48.js +0 -331
  98. package/dist/shared/clients 2/emitservice.d.ts +0 -47
  99. package/dist/shared/clients 2/emitservice.js +0 -44
  100. package/dist/shared/clients 2/four.d.ts +0 -132
  101. package/dist/shared/clients 2/four.js +0 -281
  102. package/dist/shared/clients 2/merkle.d.ts +0 -210
  103. package/dist/shared/clients 2/merkle.js +0 -400
  104. package/dist/shared/flap/__tests__/curve.test.d.ts +0 -1
  105. package/dist/shared/flap/__tests__/curve.test.js +0 -85
  106. package/dist/shared/flap/portal/index.d.ts +0 -12
  107. package/dist/shared/flap/portal/index.js +0 -11
  108. package/dist/shared/flap/portal/portal.d.ts +0 -47
  109. package/dist/shared/flap/portal/portal.js +0 -218
  110. package/dist/shared/flap/portal/types.d.ts +0 -227
  111. package/dist/shared/flap/portal/types.js +0 -80
  112. package/dist/shared/flap/portal/writer.d.ts +0 -121
  113. package/dist/shared/flap/portal/writer.js +0 -265
  114. package/dist/shared/flap/portal-bundle-merkle/core/index.d.ts +0 -18
  115. package/dist/shared/flap/portal-bundle-merkle/core/index.js +0 -938
  116. package/dist/shared/flap/portal-bundle-merkle/core/types.d.ts +0 -1
  117. package/dist/shared/flap/portal-bundle-merkle/core/types.js +0 -1
  118. package/dist/shared/flap/portal-bundle-merkle/swap/index.d.ts +0 -42
  119. package/dist/shared/flap/portal-bundle-merkle/swap/index.js +0 -1448
  120. package/dist/shared/flap/portal-bundle-merkle/swap/types.d.ts +0 -84
  121. package/dist/shared/flap/portal-bundle-merkle/swap/types.js +0 -1
  122. package/dist/shared/flap/portal-bundle-merkle/utils/index.d.ts +0 -17
  123. package/dist/shared/flap/portal-bundle-merkle/utils/index.js +0 -1024
  124. package/dist/shared/flap/portal-bundle-merkle/utils/types.d.ts +0 -16
  125. package/dist/shared/flap/portal-bundle-merkle/utils/types.js +0 -1
  126. package/dist/shared/flap/portal-bundle-merkle/utils-helpers.d.ts +0 -100
  127. package/dist/shared/flap/portal-bundle-merkle/utils-helpers.js +0 -133
  128. package/dist/shared/flap 2/__tests__/curve.test.d.ts +0 -1
  129. package/dist/shared/flap 2/__tests__/curve.test.js +0 -85
  130. package/dist/shared/flap 2/abi.d.ts +0 -4
  131. package/dist/shared/flap 2/abi.js +0 -4
  132. package/dist/shared/flap 2/constants.d.ts +0 -128
  133. package/dist/shared/flap 2/constants.js +0 -143
  134. package/dist/shared/flap 2/curve.d.ts +0 -33
  135. package/dist/shared/flap 2/curve.js +0 -84
  136. package/dist/shared/flap 2/errors.d.ts +0 -37
  137. package/dist/shared/flap 2/errors.js +0 -114
  138. package/dist/shared/flap 2/index.d.ts +0 -22
  139. package/dist/shared/flap 2/index.js +0 -33
  140. package/dist/shared/flap 2/ipfs.d.ts +0 -21
  141. package/dist/shared/flap 2/ipfs.js +0 -38
  142. package/dist/shared/flap 2/meta.d.ts +0 -30
  143. package/dist/shared/flap 2/meta.js +0 -195
  144. package/dist/shared/flap 2/permit.d.ts +0 -16
  145. package/dist/shared/flap 2/permit.js +0 -67
  146. package/dist/shared/flap 2/pinata.d.ts +0 -40
  147. package/dist/shared/flap 2/pinata.js +0 -106
  148. package/dist/shared/flap 2/portal-bundle-merkle/config.d.ts +0 -79
  149. package/dist/shared/flap 2/portal-bundle-merkle/config.js +0 -133
  150. package/dist/shared/flap 2/portal-bundle-merkle/core.d.ts +0 -18
  151. package/dist/shared/flap 2/portal-bundle-merkle/core.js +0 -938
  152. package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.d.ts +0 -125
  153. package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.js +0 -665
  154. package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.d.ts +0 -88
  155. package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.js +0 -446
  156. package/dist/shared/flap 2/portal-bundle-merkle/index.d.ts +0 -14
  157. package/dist/shared/flap 2/portal-bundle-merkle/index.js +0 -26
  158. package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.d.ts +0 -28
  159. package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.js +0 -701
  160. package/dist/shared/flap 2/portal-bundle-merkle/private.d.ts +0 -17
  161. package/dist/shared/flap 2/portal-bundle-merkle/private.js +0 -549
  162. package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.d.ts +0 -65
  163. package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.js +0 -831
  164. package/dist/shared/flap 2/portal-bundle-merkle/swap.d.ts +0 -201
  165. package/dist/shared/flap 2/portal-bundle-merkle/swap.js +0 -1359
  166. package/dist/shared/flap 2/portal-bundle-merkle/types.d.ts +0 -358
  167. package/dist/shared/flap 2/portal-bundle-merkle/types.js +0 -1
  168. package/dist/shared/flap 2/portal-bundle-merkle/utils.d.ts +0 -89
  169. package/dist/shared/flap 2/portal-bundle-merkle/utils.js +0 -963
  170. package/dist/shared/flap 2/portal-bundle.d.ts +0 -119
  171. package/dist/shared/flap 2/portal-bundle.js +0 -584
  172. package/dist/shared/flap 2/portal.d.ts +0 -392
  173. package/dist/shared/flap 2/portal.js +0 -559
  174. package/dist/shared/flap 2/vanity.d.ts +0 -48
  175. package/dist/shared/flap 2/vanity.js +0 -110
  176. package/dist/shared/flap 2/vault.d.ts +0 -240
  177. package/dist/shared/flap 2/vault.js +0 -366
  178. package/dist/shared/four 2/index.d.ts +0 -7
  179. package/dist/shared/four 2/index.js +0 -22
  180. package/dist/shared/four 2/tax-token.d.ts +0 -176
  181. package/dist/shared/four 2/tax-token.js +0 -302
  182. package/dist/shared/index 2.js +0 -10
  183. package/dist/shared/index.d 2.ts +0 -10
  184. package/dist/types/distribute.d.ts +0 -72
  185. package/dist/types/distribute.js +0 -1
  186. package/dist/types 2/errors.d.ts +0 -27
  187. package/dist/types 2/errors.js +0 -34
  188. package/dist/utils/__tests__/errors.test.d.ts +0 -1
  189. package/dist/utils/__tests__/errors.test.js +0 -76
  190. package/dist/utils/airdrop-sweep-types.d.ts +0 -1
  191. package/dist/utils/airdrop-sweep-types.js +0 -1
  192. package/dist/utils/erc20/index.d.ts +0 -242
  193. package/dist/utils/erc20/index.js +0 -645
  194. package/dist/utils/erc20/types.d.ts +0 -77
  195. package/dist/utils/erc20/types.js +0 -1
  196. package/dist/utils/erc20-types.d.ts +0 -1
  197. package/dist/utils/erc20-types.js +0 -1
  198. package/dist/utils/holders-maker/helpers.d.ts +0 -43
  199. package/dist/utils/holders-maker/helpers.js +0 -371
  200. package/dist/utils/holders-maker/index.d.ts +0 -26
  201. package/dist/utils/holders-maker/index.js +0 -218
  202. package/dist/utils/holders-maker/types.d.ts +0 -72
  203. package/dist/utils/holders-maker/types.js +0 -4
  204. package/dist/utils/holders-maker-types.d.ts +0 -1
  205. package/dist/utils/holders-maker-types.js +0 -1
  206. package/dist/utils/lp-inspect/index.d.ts +0 -44
  207. package/dist/utils/lp-inspect/index.js +0 -937
  208. package/dist/utils/lp-inspect/types.d.ts +0 -100
  209. package/dist/utils/lp-inspect/types.js +0 -1
  210. package/dist/utils/lp-inspect-types.d.ts +0 -1
  211. package/dist/utils/lp-inspect-types.js +0 -1
  212. package/dist/utils/private-sale-types.d.ts +0 -1
  213. package/dist/utils/private-sale-types.js +0 -1
  214. package/dist/utils/quote-helpers/index.d.ts +0 -107
  215. package/dist/utils/quote-helpers/index.js +0 -346
  216. package/dist/utils/quote-helpers/types.d.ts +0 -16
  217. package/dist/utils/quote-helpers/types.js +0 -1
  218. package/dist/utils/quote-helpers-types.d.ts +0 -1
  219. package/dist/utils/quote-helpers-types.js +0 -1
  220. /package/dist/{chains/bsc/four/submit/types.js → __tests__/subpath-exports.test.d.ts} +0 -0
@@ -1,665 +0,0 @@
1
- /**
2
- * Flap Protocol 发币 + 内盘买到外盘捆绑交易
3
- *
4
- * 功能:在一个 Bundle 中完成:
5
- * 1. 发币(创建新代币)
6
- * 2. 多个钱包在 Bonding Curve(内盘)买入代币
7
- * 3. 买到毕业(代币上 DEX)
8
- * 4. 多个钱包在 PancakeSwap(外盘)继续买入
9
- */
10
- import { ethers, Contract, Wallet } from 'ethers';
11
- import { NonceManager, getOptimizedGasPrice, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../../utils/bundle-helpers.js';
12
- import { FLAP_PORTAL_ADDRESSES, FLAP_ORIGINAL_PORTAL_ADDRESSES } from '../constants.js';
13
- import { buildVaultParams, VAULT_PORTAL_ADDRESSES, VAULT_PORTAL_ABI } from '../vault.js';
14
- import { PROFIT_CONFIG, ZERO_ADDRESS } from '../../../utils/constants.js';
15
- import { GAS_LIMITS } from '../../constants/index.js';
16
- import { getGasPriceConfig, getTxType, getProfitRecipient, getBribeAmount, BLOCKRAZOR_BUILDER_EOA, PORTAL_ABI } from './config.js';
17
- // ==================== ERC20 ABI ====================
18
- const ERC20_ABI = [
19
- {
20
- type: "function",
21
- name: "approve",
22
- inputs: [
23
- { name: "spender", type: "address" },
24
- { name: "amount", type: "uint256" }
25
- ],
26
- outputs: [{ name: "", type: "bool" }],
27
- stateMutability: "nonpayable"
28
- }
29
- ];
30
- // ==================== PancakeSwap Router ABI ====================
31
- const PANCAKE_ROUTER_ABI = [
32
- {
33
- type: "function",
34
- name: "exactInputSingle",
35
- inputs: [
36
- {
37
- name: "params",
38
- type: "tuple",
39
- components: [
40
- { name: "tokenIn", type: "address" },
41
- { name: "tokenOut", type: "address" },
42
- { name: "fee", type: "uint24" },
43
- { name: "recipient", type: "address" },
44
- { name: "amountIn", type: "uint256" },
45
- { name: "amountOutMinimum", type: "uint256" },
46
- { name: "sqrtPriceLimitX96", type: "uint160" }
47
- ]
48
- }
49
- ],
50
- outputs: [{ name: "amountOut", type: "uint256" }],
51
- stateMutability: "payable"
52
- },
53
- {
54
- type: "function",
55
- name: "multicall",
56
- inputs: [{ name: "data", type: "bytes[]" }],
57
- outputs: [{ name: "results", type: "bytes[]" }],
58
- stateMutability: "payable"
59
- },
60
- {
61
- type: "function",
62
- name: "swapExactTokensForTokens",
63
- inputs: [
64
- { name: "amountIn", type: "uint256" },
65
- { name: "amountOutMin", type: "uint256" },
66
- { name: "path", type: "address[]" },
67
- { name: "to", type: "address" }
68
- ],
69
- outputs: [{ name: "amountOut", type: "uint256" }],
70
- stateMutability: "payable"
71
- }
72
- ];
73
- // ==================== DEX 地址常量 ====================
74
- const DEX_ADDRESSES = {
75
- BSC: {
76
- PANCAKE_SMART_ROUTER: '0x13f4EA83D0bd40E75C8222255bc855a974568Dd4',
77
- WBNB: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c',
78
- },
79
- XLAYER: {
80
- // xLayer 使用 PotatoSwap
81
- PANCAKE_SMART_ROUTER: '0x0000000000000000000000000000000000000000', // TODO: 添加 xLayer DEX 地址
82
- WBNB: '0x0000000000000000000000000000000000000000',
83
- },
84
- BASE: {
85
- // ✅ Base 使用 Uniswap V3 SwapRouter02
86
- UNISWAP_SMART_ROUTER: '0x2626664c2603336E57B271c5C0b26F421741e481',
87
- WETH: '0x4200000000000000000000000000000000000006',
88
- }
89
- };
90
- // ==================== 链常量 ====================
91
- // 获取链配置
92
- function getChainConfig(chain) {
93
- switch (chain) {
94
- case 'xlayer':
95
- return { chainId: 196, nativeSymbol: 'OKB' };
96
- case 'base':
97
- return { chainId: 8453, nativeSymbol: 'ETH' };
98
- case 'bsc':
99
- default:
100
- return { chainId: 56, nativeSymbol: 'BNB' };
101
- }
102
- }
103
- // ==================== 工具函数 ====================
104
- /** 构建 ERC20 approve 交易 */
105
- async function buildApproveTransaction(wallet, tokenAddress, spenderAddress, amount, nonce, gasPrice, txType, chainId = 56 // ✅ 添加 chainId 参数
106
- ) {
107
- const erc20Interface = new ethers.Interface(ERC20_ABI);
108
- const data = erc20Interface.encodeFunctionData('approve', [spenderAddress, amount]);
109
- const tx = {
110
- to: tokenAddress,
111
- data,
112
- from: wallet.address,
113
- nonce,
114
- gasLimit: BigInt(100000), // approve 交易 gas 较低
115
- chainId,
116
- type: txType
117
- };
118
- if (txType === 2) {
119
- const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
120
- tx.maxFeePerGas = gasPrice;
121
- tx.maxPriorityFeePerGas = priorityFee;
122
- }
123
- else {
124
- tx.gasPrice = gasPrice;
125
- }
126
- return wallet.signTransaction(tx);
127
- }
128
- function getGasLimit(config, defaultGas = 800000) {
129
- if (config.gasLimit !== undefined) {
130
- return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
131
- }
132
- const multiplier = config.gasLimitMultiplier ?? 1.0;
133
- return BigInt(Math.ceil(defaultGas * multiplier));
134
- }
135
- /** 将金额拆分成多份(权重随机) */
136
- function splitAmount(totalAmount, count) {
137
- if (count <= 0)
138
- throw new Error('拆分份数必须大于 0');
139
- if (count === 1)
140
- return [totalAmount];
141
- const weights = [];
142
- for (let i = 0; i < count; i++) {
143
- weights.push(0.5 + Math.random());
144
- }
145
- const totalWeight = weights.reduce((a, b) => a + b, 0);
146
- const amounts = [];
147
- let allocated = 0n;
148
- for (let i = 0; i < count - 1; i++) {
149
- const ratio = weights[i] / totalWeight;
150
- const amount = BigInt(Math.floor(Number(totalAmount) * ratio));
151
- amounts.push(amount);
152
- allocated += amount;
153
- }
154
- amounts.push(totalAmount - allocated);
155
- return amounts;
156
- }
157
- /** 解析输入金额字符串为 bigint(按是否原生币选择 parseEther / parseUnits) */
158
- function parseQuoteAmount(amount, useNativeToken, quoteTokenDecimals) {
159
- const v = String(amount ?? '').trim();
160
- if (!v)
161
- return 0n;
162
- return useNativeToken ? ethers.parseEther(v) : ethers.parseUnits(v, quoteTokenDecimals);
163
- }
164
- /**
165
- * 计算每个买家的买入金额(优先使用 params 传入的 buyAmount;否则 fallback 到按总额随机拆分)
166
- * 说明:memeweb 前端已根据 average/random/custom 计算出每个钱包 buyAmount;
167
- * 若 SDK 这里再次 splitAmount,会导致实际 buyAmount 与 UI/预期不一致,并引发余额不足(insufficient funds)。
168
- */
169
- function resolveBuyerAmounts(buyers, totalAmountStr, useNativeToken, quoteTokenDecimals) {
170
- const provided = buyers.map(b => b?.buyAmount).filter(v => v != null && String(v).trim() !== '');
171
- const allProvided = provided.length === buyers.length;
172
- if (allProvided) {
173
- // ✅ 所有买家都显式提供了 buyAmount:按传入金额构建,但要修正“浮点/四舍五入导致总和偏差”
174
- const amounts = buyers.map(b => parseQuoteAmount(String(b.buyAmount), useNativeToken, quoteTokenDecimals));
175
- const totalWei = parseQuoteAmount(totalAmountStr, useNativeToken, quoteTokenDecimals);
176
- const sum = amounts.reduce((a, b) => a + b, 0n);
177
- const delta = totalWei - sum;
178
- if (delta !== 0n && amounts.length > 0) {
179
- // 优先修正最后一个金额(对应 create-to-dex 里“最后一单可能触发毕业”的假设)
180
- const lastIdx = amounts.length - 1;
181
- const next = amounts[lastIdx] + delta;
182
- if (next <= 0n) {
183
- throw new Error(`买入金额总和与总额不一致且无法修正:sum=${sum} total=${totalWei} delta=${delta}`);
184
- }
185
- amounts[lastIdx] = next;
186
- }
187
- return amounts;
188
- }
189
- const totalWei = parseQuoteAmount(totalAmountStr, useNativeToken, quoteTokenDecimals);
190
- return splitAmount(totalWei, buyers.length);
191
- }
192
- // ==================== 主函数 ====================
193
- /**
194
- * Flap 发币 + 一键买到外盘捆绑交易
195
- *
196
- * 交易顺序:
197
- * 1. 贿赂交易(BlockRazor)
198
- * 2. 发币交易(Dev 钱包创建代币)
199
- * 3. 内盘买入(多个钱包在 Bonding Curve 买入,买到毕业)
200
- * 4. 外盘买入(多个钱包在 PancakeSwap 买入)
201
- * 5. 利润多跳转账
202
- */
203
- export async function flapBundleCreateToDex(params) {
204
- const { chain, devPrivateKey, tokenInfo, tokenAddress, quoteToken, quoteTokenDecimals = 18, curveBuyers, curveTotalBuyAmount, enableDexBuy = false, dexBuyers = [], dexTotalBuyAmount, dexPoolType = 'v3', v3Fee = 2500, config } = params;
205
- // 验证参数
206
- if (curveBuyers.length === 0) {
207
- throw new Error('至少需要一个内盘买入钱包');
208
- }
209
- // 判断是否使用原生代币
210
- const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
211
- const inputToken = useNativeToken ? ZERO_ADDRESS : quoteToken;
212
- // ✅ 计算实际使用的 V3 费率
213
- // 优先级:lpFeeProfile > v3Fee > 默认 2500
214
- // lpFeeProfile: 0=STANDARD(0.25%), 1=LOW(0.01%), 2=HIGH(1%)
215
- let actualV3Fee;
216
- if (params.lpFeeProfile !== undefined) {
217
- switch (params.lpFeeProfile) {
218
- case 1:
219
- actualV3Fee = 100;
220
- break; // LOW: 0.01%
221
- case 2:
222
- actualV3Fee = 10000;
223
- break; // HIGH: 1%
224
- default:
225
- actualV3Fee = 2500;
226
- break; // STANDARD: 0.25%
227
- }
228
- }
229
- else {
230
- actualV3Fee = v3Fee ?? 2500;
231
- }
232
- // ✅ 获取链配置
233
- const chainConfig = getChainConfig(chain);
234
- const chainId = chainConfig.chainId;
235
- // 创建 Provider
236
- const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
237
- chainId,
238
- name: chain.toUpperCase()
239
- });
240
- const portalAddress = FLAP_PORTAL_ADDRESSES[chain.toUpperCase()];
241
- const originalPortalAddress = FLAP_ORIGINAL_PORTAL_ADDRESSES[chain.toUpperCase()];
242
- const nonceManager = new NonceManager(provider);
243
- // 创建钱包实例
244
- const devWallet = new Wallet(devPrivateKey, provider);
245
- const curveWallets = curveBuyers.map(b => ({
246
- wallet: new Wallet(b.privateKey, provider),
247
- buyAmount: b.buyAmount
248
- }));
249
- const dexWallets = (enableDexBuy ? dexBuyers : []).map(b => ({
250
- wallet: new Wallet(b.privateKey, provider),
251
- buyAmount: b.buyAmount
252
- }));
253
- // ✅ 并行获取 gasPrice + 所有钱包 nonces
254
- const allWallets = [
255
- devWallet,
256
- ...curveWallets.map(c => c.wallet),
257
- ...dexWallets.map(d => d.wallet)
258
- ];
259
- const uniqueWallets = allWallets.filter((w, i) => {
260
- const addr = w.address.toLowerCase();
261
- return allWallets.findIndex(x => x.address.toLowerCase() === addr) === i;
262
- });
263
- const [gasPrice, noncesArray] = await Promise.all([
264
- getOptimizedGasPrice(provider, getGasPriceConfig(config)),
265
- nonceManager.getNextNoncesForWallets(uniqueWallets)
266
- ]);
267
- // 构建 nonces Map
268
- const noncesMap = new Map();
269
- uniqueWallets.forEach((wallet, i) => {
270
- noncesMap.set(wallet.address.toLowerCase(), noncesArray[i]);
271
- });
272
- const finalGasLimit = getGasLimit(config);
273
- const txType = getTxType(config);
274
- const priorityFee = gasPrice / 10n === 0n ? 1n : gasPrice / 10n;
275
- const bribeAmount = getBribeAmount(config);
276
- const needBribeTx = bribeAmount > 0n;
277
- // ✅ 计算内盘买入金额
278
- const curveBuyAmounts = resolveBuyerAmounts(curveBuyers, curveTotalBuyAmount, useNativeToken, quoteTokenDecimals);
279
- // ✅ 计算外盘买入金额
280
- let dexBuyAmounts = [];
281
- if (enableDexBuy && dexBuyers.length > 0 && dexTotalBuyAmount) {
282
- dexBuyAmounts = resolveBuyerAmounts(dexBuyers, dexTotalBuyAmount, useNativeToken, quoteTokenDecimals);
283
- }
284
- // ✅ 计算利润
285
- const totalBuyAmount = curveBuyAmounts.reduce((a, b) => a + b, 0n)
286
- + dexBuyAmounts.reduce((a, b) => a + b, 0n);
287
- const profitAmount = (totalBuyAmount * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
288
- // ==================== 构建交易 ====================
289
- const allTransactions = [];
290
- // 使用第一个内盘买家作为贿赂支付者(提高 bundle 打包优先级)
291
- const mainBuyerWallet = curveWallets[0].wallet;
292
- // 1. 贿赂交易
293
- if (needBribeTx) {
294
- const mainAddr = mainBuyerWallet.address.toLowerCase();
295
- const bribeNonce = noncesMap.get(mainAddr);
296
- noncesMap.set(mainAddr, bribeNonce + 1);
297
- const bribeTx = await mainBuyerWallet.signTransaction({
298
- to: BLOCKRAZOR_BUILDER_EOA,
299
- value: bribeAmount,
300
- nonce: bribeNonce,
301
- gasPrice,
302
- gasLimit: GAS_LIMITS.BRIBE,
303
- chainId,
304
- type: txType
305
- });
306
- allTransactions.push(bribeTx);
307
- }
308
- // 2. 发币交易
309
- {
310
- const devAddr = devWallet.address.toLowerCase();
311
- const devNonce = noncesMap.get(devAddr);
312
- noncesMap.set(devAddr, devNonce + 1);
313
- const originalPortal = new Contract(originalPortalAddress, PORTAL_ABI, devWallet);
314
- // ✅ 判断使用哪个版本的 newToken
315
- // V5: 提供了 taxV2Config(Tax Token V2 高级税收分配)
316
- // V4: 提供了 dexId 或 lpFeeProfile(支持 DEX 选择和 LP 费率配置)
317
- // V3: 提供了 extensionID(支持扩展数据)
318
- // V2: 默认
319
- const useV5 = params.taxV2Config !== undefined && (params.taxRate ?? 0) > 0;
320
- const useV4 = !useV5 && (params.dexId !== undefined || params.lpFeeProfile !== undefined);
321
- const useV3 = !useV5 && !useV4 && !!params.extensionID;
322
- let createUnsigned;
323
- if (useV5) {
324
- // V5: Tax Token V2 高级税收分配
325
- const tv2 = params.taxV2Config;
326
- // 验证税收分配总计必须为 10000
327
- const total = tv2.mktBps + tv2.deflationBps + tv2.dividendBps + tv2.lpBps;
328
- if (total !== 10000) {
329
- throw new Error(`Tax distribution must sum to 10000 (100%), got ${total}`);
330
- }
331
- // ✅ 判断是否使用金库模式(VaultPortal.newTaxTokenWithVault)
332
- const hasVault = tv2.vaultConfig && tv2.vaultConfig.vaultType !== 'none';
333
- if (hasVault) {
334
- // ✅ 金库模式:通过 VaultPortal.newTaxTokenWithVault 创建代币
335
- const chainKey = chain.toUpperCase();
336
- const vaultPortalAddr = VAULT_PORTAL_ADDRESSES[chainKey];
337
- if (!vaultPortalAddr) {
338
- throw new Error(`链 "${chain}" 不支持 Tax Vault 金库功能`);
339
- }
340
- const vaultPortal = new Contract(vaultPortalAddr, VAULT_PORTAL_ABI, devWallet);
341
- const { vaultFactory, vaultData } = buildVaultParams(tv2.vaultConfig, chainKey);
342
- createUnsigned = await vaultPortal.newTaxTokenWithVault.populateTransaction({
343
- name: tokenInfo.name,
344
- symbol: tokenInfo.symbol,
345
- meta: tokenInfo.meta,
346
- dexThresh: (params.dexThresh ?? 1) & 0xff,
347
- salt: params.salt ?? '0x' + '00'.repeat(32),
348
- taxRate: (params.taxRate ?? 0) & 0xffff,
349
- migratorType: (params.migratorType ?? 0) & 0xff,
350
- quoteToken: inputToken,
351
- quoteAmt: 0n,
352
- permitData: '0x',
353
- extensionID: '0x' + '00'.repeat(32),
354
- extensionData: '0x',
355
- dexId: (params.dexId ?? 0) & 0xff,
356
- lpFeeProfile: (params.lpFeeProfile ?? 0) & 0xff,
357
- taxDuration: BigInt(tv2.taxDuration),
358
- antiFarmerDuration: BigInt(tv2.antiFarmerDuration),
359
- mktBps: tv2.mktBps & 0xffff,
360
- deflationBps: tv2.deflationBps & 0xffff,
361
- dividendBps: tv2.dividendBps & 0xffff,
362
- lpBps: tv2.lpBps & 0xffff,
363
- minimumShareBalance: BigInt(tv2.minimumShareBalance ?? 10000) * (10n ** 18n),
364
- vaultFactory,
365
- vaultData,
366
- });
367
- }
368
- else {
369
- // 标准 V5: Portal.newTokenV5(无金库)
370
- createUnsigned = await originalPortal.newTokenV5.populateTransaction({
371
- name: tokenInfo.name,
372
- symbol: tokenInfo.symbol,
373
- meta: tokenInfo.meta,
374
- dexThresh: (params.dexThresh ?? 1) & 0xff,
375
- salt: params.salt ?? '0x' + '00'.repeat(32),
376
- taxRate: (params.taxRate ?? 0) & 0xffff,
377
- migratorType: (params.migratorType ?? 0) & 0xff,
378
- quoteToken: inputToken,
379
- quoteAmt: 0n,
380
- beneficiary: devWallet.address,
381
- permitData: '0x',
382
- extensionID: params.extensionID ?? '0x' + '00'.repeat(32),
383
- extensionData: params.extensionData ?? '0x',
384
- dexId: (params.dexId ?? 0) & 0xff,
385
- lpFeeProfile: (params.lpFeeProfile ?? 0) & 0xff,
386
- taxDuration: BigInt(tv2.taxDuration),
387
- antiFarmerDuration: BigInt(tv2.antiFarmerDuration),
388
- mktBps: tv2.mktBps & 0xffff,
389
- deflationBps: tv2.deflationBps & 0xffff,
390
- dividendBps: tv2.dividendBps & 0xffff,
391
- lpBps: tv2.lpBps & 0xffff,
392
- minimumShareBalance: BigInt(tv2.minimumShareBalance ?? 10000) * (10n ** 18n),
393
- });
394
- }
395
- }
396
- else if (useV4) {
397
- // V4: 支持 DEX ID 和 LP 费率配置(用于选择池子费率)
398
- createUnsigned = await originalPortal.newTokenV4.populateTransaction({
399
- name: tokenInfo.name,
400
- symbol: tokenInfo.symbol,
401
- meta: tokenInfo.meta,
402
- dexThresh: (params.dexThresh ?? 1) & 0xff,
403
- salt: params.salt ?? '0x' + '00'.repeat(32),
404
- taxRate: (params.taxRate ?? 0) & 0xffff,
405
- migratorType: (params.migratorType ?? 0) & 0xff,
406
- quoteToken: inputToken,
407
- quoteAmt: 0n,
408
- beneficiary: devWallet.address,
409
- permitData: '0x',
410
- extensionID: params.extensionID ?? '0x' + '00'.repeat(32),
411
- extensionData: params.extensionData ?? '0x',
412
- dexId: (params.dexId ?? 0) & 0xff,
413
- lpFeeProfile: (params.lpFeeProfile ?? 0) & 0xff
414
- });
415
- }
416
- else if (useV3) {
417
- // V3: 支持扩展数据
418
- createUnsigned = await originalPortal.newTokenV3.populateTransaction({
419
- name: tokenInfo.name,
420
- symbol: tokenInfo.symbol,
421
- meta: tokenInfo.meta,
422
- dexThresh: (params.dexThresh ?? 1) & 0xff,
423
- salt: params.salt ?? '0x' + '00'.repeat(32),
424
- taxRate: (params.taxRate ?? 0) & 0xffff,
425
- migratorType: (params.migratorType ?? 0) & 0xff,
426
- quoteToken: inputToken,
427
- quoteAmt: 0n,
428
- beneficiary: devWallet.address,
429
- permitData: '0x',
430
- extensionID: params.extensionID,
431
- extensionData: params.extensionData ?? '0x'
432
- });
433
- }
434
- else {
435
- // V2: 基础版本
436
- createUnsigned = await originalPortal.newTokenV2.populateTransaction({
437
- name: tokenInfo.name,
438
- symbol: tokenInfo.symbol,
439
- meta: tokenInfo.meta,
440
- dexThresh: (params.dexThresh ?? 1) & 0xff,
441
- salt: params.salt ?? '0x' + '00'.repeat(32),
442
- taxRate: (params.taxRate ?? 0) & 0xffff,
443
- migratorType: (params.migratorType ?? 0) & 0xff,
444
- quoteToken: inputToken,
445
- quoteAmt: 0n,
446
- beneficiary: devWallet.address,
447
- permitData: '0x'
448
- });
449
- }
450
- const createTx = {
451
- ...createUnsigned,
452
- from: devWallet.address,
453
- nonce: devNonce,
454
- gasLimit: finalGasLimit,
455
- chainId,
456
- type: txType
457
- };
458
- if (txType === 2) {
459
- createTx.maxFeePerGas = gasPrice;
460
- createTx.maxPriorityFeePerGas = priorityFee;
461
- }
462
- else {
463
- createTx.gasPrice = gasPrice;
464
- }
465
- const signedCreate = await devWallet.signTransaction(createTx);
466
- allTransactions.push(signedCreate);
467
- }
468
- // 3. 内盘买入交易(包含毕业触发)
469
- // 最后一个买入交易会触发毕业,需要更多 gas
470
- // ✅ ERC20 需要先 approve,再买入
471
- const curveBuyTxPromises = curveWallets.map(async ({ wallet }, i) => {
472
- const addr = wallet.address.toLowerCase();
473
- const signedTxs = [];
474
- // ✅ ERC20: 先构建 approve 交易
475
- if (!useNativeToken) {
476
- const approveNonce = noncesMap.get(addr);
477
- noncesMap.set(addr, approveNonce + 1);
478
- const approveTx = await buildApproveTransaction(wallet, quoteToken, portalAddress, curveBuyAmounts[i], approveNonce, gasPrice, txType, chainId // ✅ 传递 chainId
479
- );
480
- signedTxs.push(approveTx);
481
- }
482
- // 构建买入交易
483
- const buyNonce = noncesMap.get(addr);
484
- noncesMap.set(addr, buyNonce + 1);
485
- const portal = new Contract(portalAddress, PORTAL_ABI, wallet);
486
- // ✅ 交易阶段统一优先使用 swapExactInputV3(支持 extensionData;无扩展时传 0x 即可)
487
- // 说明:这里的 V3 指“交易接口版本(扩展支持)”,不是“外盘 V3 池子”
488
- const extensionData = params.extensionData ?? '0x';
489
- const unsigned = await portal.swapExactInputV3.populateTransaction({
490
- inputToken,
491
- outputToken: tokenAddress,
492
- inputAmount: curveBuyAmounts[i],
493
- minOutputAmount: 0n,
494
- permitData: '0x', // 不使用 permit,使用链上 approve
495
- extensionData
496
- }, useNativeToken ? { value: curveBuyAmounts[i] } : {});
497
- // 最后一个买家触发毕业,需要更多 gas
498
- const isLastBuyer = i === curveWallets.length - 1;
499
- // ⚠️ 触发毕业(创建 Pancake V3 池 + Mint 初始流动性)会非常耗 gas。
500
- // 链上成功样例 0x29b173... 的 gasLimit=8,000,000,gasUsed≈6,647,149。
501
- // Flap 官方示例脚本也使用 last_buy=8_000_000。
502
- const LAST_BUY_GAS_LIMIT = BigInt(8000000);
503
- const buyGasLimit = isLastBuyer
504
- ? (finalGasLimit > LAST_BUY_GAS_LIMIT ? finalGasLimit : LAST_BUY_GAS_LIMIT)
505
- : finalGasLimit;
506
- const tx = {
507
- ...unsigned,
508
- from: wallet.address,
509
- nonce: buyNonce,
510
- gasLimit: buyGasLimit,
511
- chainId,
512
- type: txType,
513
- value: useNativeToken ? curveBuyAmounts[i] : 0n
514
- };
515
- if (txType === 2) {
516
- tx.maxFeePerGas = gasPrice;
517
- tx.maxPriorityFeePerGas = priorityFee;
518
- }
519
- else {
520
- tx.gasPrice = gasPrice;
521
- }
522
- const signedBuy = await wallet.signTransaction(tx);
523
- signedTxs.push(signedBuy);
524
- return signedTxs;
525
- });
526
- const curveBuyResults = await Promise.all(curveBuyTxPromises);
527
- // 展平数组:每个钱包可能有 [approve, buy] 或只有 [buy]
528
- curveBuyResults.forEach(txs => allTransactions.push(...txs));
529
- // 4. 外盘买入交易(直接调用 PancakeSwap Router)
530
- // ✅ 重要修改:直接调用 PancakeSwap SmartRouter
531
- // 参考官方代码: flap-bundle-release/app/v2/pvp/001_launch_buy.ts
532
- //
533
- // ⚠️ 关键:税代币(migratorType=1)毕业到 V2 池,必须用 swapExactTokensForTokens
534
- // 普通代币(migratorType=0)毕业到 V3 池,使用 exactInputSingle
535
- if (enableDexBuy && dexWallets.length > 0) {
536
- // 获取 DEX 地址(Base 使用 Uniswap V3 SwapRouter02,BSC 使用 PancakeSwap SmartRouter)
537
- let smartRouterAddress;
538
- let wrappedNativeAddress;
539
- if (chain === 'base') {
540
- smartRouterAddress = DEX_ADDRESSES.BASE.UNISWAP_SMART_ROUTER;
541
- wrappedNativeAddress = DEX_ADDRESSES.BASE.WETH;
542
- }
543
- else if (chain === 'xlayer') {
544
- smartRouterAddress = DEX_ADDRESSES.XLAYER.PANCAKE_SMART_ROUTER;
545
- wrappedNativeAddress = DEX_ADDRESSES.XLAYER.WBNB;
546
- }
547
- else {
548
- smartRouterAddress = DEX_ADDRESSES.BSC.PANCAKE_SMART_ROUTER;
549
- wrappedNativeAddress = DEX_ADDRESSES.BSC.WBNB;
550
- }
551
- // ✅ 根据 migratorType 确定实际的 DEX 池类型
552
- // migratorType === 1 (V2_MIGRATOR) → 毕业到 V2 池 → 必须使用 V2 买入
553
- // migratorType === 0 (V3_MIGRATOR) → 毕业到 V3 池 → 使用 V3 买入
554
- // 参考: flap-bundle-release 中税代币使用 PoolType.V2,普通代币使用 PoolType.V3
555
- const effectiveDexPoolType = (params.migratorType === 1) ? 'v2' : (dexPoolType || 'v3');
556
- // 获取 V3 费率(仅 V3 池使用)
557
- const dexV3Fee = actualV3Fee;
558
- const dexBuyTxPromises = dexWallets.map(async ({ wallet }, i) => {
559
- const addr = wallet.address.toLowerCase();
560
- const signedTxs = [];
561
- const buyAmount = dexBuyAmounts[i];
562
- // ✅ ERC20: 先构建 approve 交易(approve 给 PancakeSwap Router)
563
- if (!useNativeToken) {
564
- const approveNonce = noncesMap.get(addr);
565
- noncesMap.set(addr, approveNonce + 1);
566
- const approveTx = await buildApproveTransaction(wallet, quoteToken, smartRouterAddress, // ✅ approve 给 PancakeSwap SmartRouter
567
- buyAmount, approveNonce, gasPrice, txType, chainId);
568
- signedTxs.push(approveTx);
569
- }
570
- // 构建 PancakeSwap 买入交易(使用 multicall 方式,与官方一致)
571
- const buyNonce = noncesMap.get(addr);
572
- noncesMap.set(addr, buyNonce + 1);
573
- // 对于原生代币(BNB/ETH),使用 Wrapped 版本作为 tokenIn(Router 会自动 wrap)
574
- const tokenIn = useNativeToken ? wrappedNativeAddress : quoteToken;
575
- const routerInterface = new ethers.Interface(PANCAKE_ROUTER_ABI);
576
- let multicallData;
577
- if (effectiveDexPoolType === 'v2') {
578
- // ✅ V2 池:使用 swapExactTokensForTokens
579
- // 参考: flap-bundle-release/app/v2/pvp/001_launch_buy.ts (PoolType.V2 分支)
580
- const swapData = routerInterface.encodeFunctionData('swapExactTokensForTokens', [
581
- buyAmount,
582
- 0n, // amountOutMin: 不设置滑点保护(Bundle 中可以接受)
583
- [tokenIn, tokenAddress], // path: WBNB/QuoteToken → Token
584
- wallet.address // recipient
585
- ]);
586
- multicallData = routerInterface.encodeFunctionData('multicall', [[swapData]]);
587
- }
588
- else {
589
- // ✅ V3 池:使用 exactInputSingle
590
- const exactInputSingleParams = {
591
- tokenIn,
592
- tokenOut: tokenAddress,
593
- fee: dexV3Fee, // ✅ 使用与 newTokenV4 创建池子匹配的费率
594
- recipient: wallet.address,
595
- amountIn: buyAmount,
596
- amountOutMinimum: 0n, // 不设置滑点保护(Bundle 中可以接受)
597
- sqrtPriceLimitX96: 0n
598
- };
599
- const exactInputSingleData = routerInterface.encodeFunctionData('exactInputSingle', [exactInputSingleParams]);
600
- multicallData = routerInterface.encodeFunctionData('multicall', [[exactInputSingleData]]);
601
- }
602
- // ⚠️ Pancake SmartRouter 外盘买的 gas 不能太小,否则 bundle 预执行会直接失败。
603
- // Flap 官方示例配置 dex_buy=5_000_000(flap-bundle-release/app/configs/global.ts)。
604
- const DEX_BUY_GAS_LIMIT = BigInt(8000000);
605
- const tx = {
606
- to: smartRouterAddress,
607
- data: multicallData,
608
- nonce: buyNonce,
609
- gasLimit: DEX_BUY_GAS_LIMIT,
610
- chainId,
611
- type: txType,
612
- value: useNativeToken ? buyAmount : 0n
613
- };
614
- if (txType === 2) {
615
- tx.maxFeePerGas = gasPrice;
616
- tx.maxPriorityFeePerGas = priorityFee;
617
- }
618
- else {
619
- tx.gasPrice = gasPrice;
620
- }
621
- const signedBuy = await wallet.signTransaction(tx);
622
- signedTxs.push(signedBuy);
623
- return signedTxs;
624
- });
625
- const dexBuyResults = await Promise.all(dexBuyTxPromises);
626
- // 展平数组:每个钱包可能有 [approve, buy] 或只有 [buy]
627
- dexBuyResults.forEach(txs => allTransactions.push(...txs));
628
- }
629
- // 5. 利润多跳转账
630
- let profitHopWallets;
631
- if (profitAmount > 0n) {
632
- // ✅ 调整:利润从 Dev 钱包(devPrivateKey)支付,避免第一个内盘买家余额不足导致 want 过高
633
- // 注意:利润交易会额外消耗原生币(profitAmount + gas),请确保 Dev 钱包留足余额
634
- const devAddr = devWallet.address.toLowerCase();
635
- const profitNonce = noncesMap.get(devAddr);
636
- const profitResult = await buildProfitHopTransactions({
637
- provider,
638
- payerWallet: devWallet,
639
- profitAmount,
640
- profitRecipient: getProfitRecipient(),
641
- hopCount: PROFIT_HOP_COUNT,
642
- gasPrice,
643
- chainId,
644
- txType,
645
- startNonce: profitNonce
646
- });
647
- allTransactions.push(...profitResult.signedTransactions);
648
- profitHopWallets = profitResult.hopWallets;
649
- }
650
- nonceManager.clearTemp();
651
- // 返回结果
652
- return {
653
- signedTransactions: allTransactions,
654
- tokenAddress,
655
- profitHopWallets,
656
- metadata: {
657
- curveBuyerCount: curveBuyers.length,
658
- curveTotalBuy: ethers.formatEther(curveBuyAmounts.reduce((a, b) => a + b, 0n)),
659
- enableDexBuy,
660
- dexBuyerCount: dexBuyers.length,
661
- dexTotalBuy: dexBuyAmounts.length > 0 ? ethers.formatEther(dexBuyAmounts.reduce((a, b) => a + b, 0n)) : '0',
662
- profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined
663
- }
664
- };
665
- }