four-flap-meme-sdk 2.2.7 → 2.2.10

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 (474) hide show
  1. package/README.en.md +6 -41
  2. package/README.md +0 -31
  3. package/README.zh-CN.md +6 -41
  4. package/dist/chains/bsc/four/approve-tokenmanager.d.ts +26 -1
  5. package/dist/chains/bsc/four/approve-tokenmanager.js +113 -1
  6. package/dist/chains/bsc/four/config.d.ts +67 -5
  7. package/dist/chains/bsc/four/config.js +114 -2
  8. package/dist/chains/bsc/four/core.d.ts +4 -1
  9. package/dist/chains/bsc/four/core.js +592 -1
  10. package/dist/chains/bsc/four/index.d.ts +6 -6
  11. package/dist/chains/bsc/four/index.js +6 -6
  12. package/dist/chains/bsc/four/internal.d.ts +46 -2
  13. package/dist/chains/bsc/four/internal.js +239 -2
  14. package/dist/chains/bsc/four/pancake-proxy.d.ts +28 -1
  15. package/dist/chains/bsc/four/pancake-proxy.js +687 -1
  16. package/dist/chains/bsc/four/private.d.ts +27 -1
  17. package/dist/chains/bsc/four/private.js +477 -1
  18. package/dist/chains/bsc/four/submit.d.ts +315 -2
  19. package/dist/chains/bsc/four/submit.js +752 -2
  20. package/dist/chains/bsc/four/swap-buy-first.d.ts +55 -2
  21. package/dist/chains/bsc/four/swap-buy-first.js +507 -2
  22. package/dist/chains/bsc/four/swap-internal.d.ts +3 -1
  23. package/dist/chains/bsc/four/swap-internal.js +18 -1
  24. package/dist/chains/bsc/four/swap.d.ts +144 -2
  25. package/dist/chains/bsc/four/swap.js +766 -2
  26. package/dist/chains/bsc/four/types.d.ts +476 -1
  27. package/dist/chains/bsc/four/utils.d.ts +18 -5
  28. package/dist/chains/bsc/four/utils.js +1552 -5
  29. package/dist/chains/bsc/pancake/bundle-buy-first.d.ts +91 -1
  30. package/dist/chains/bsc/pancake/bundle-buy-first.js +212 -97
  31. package/dist/chains/bsc/pancake/bundle-swap.d.ts +79 -1
  32. package/dist/chains/bsc/pancake/bundle-swap.js +726 -114
  33. package/dist/chains/bsc/pancake/index.d.ts +2 -4
  34. package/dist/chains/bsc/pancake/index.js +3 -1
  35. package/dist/chains/bsc/platforms/iro/factory.d.ts +2 -2
  36. package/dist/chains/bsc/platforms/iro/factory.js +1 -3
  37. package/dist/chains/bsc/platforms/iro/index.d.ts +5 -5
  38. package/dist/chains/bsc/platforms/iro/index.js +3 -3
  39. package/dist/chains/bsc/platforms/iro/pool.js +10 -31
  40. package/dist/chains/bsc/platforms/iro/token.js +1 -4
  41. package/dist/chains/eni/batch-router/bundle-approve.js +3 -4
  42. package/dist/chains/eni/batch-router/transfer.js +25 -55
  43. package/dist/chains/eni/batch-router/utils.js +6 -32
  44. package/dist/chains/eni/bundler/sign.js +6 -5
  45. package/dist/chains/eni/bundler/submit.js +4 -1
  46. package/dist/chains/eni/constants.js +1 -1
  47. package/dist/chains/eni/index.d.ts +1 -2
  48. package/dist/chains/eni/index.js +0 -1
  49. package/dist/chains/eni/platforms/daoaas/create.js +2 -2
  50. package/dist/chains/eni/platforms/daoaas/index.d.ts +3 -3
  51. package/dist/chains/eni/platforms/daoaas/index.js +3 -3
  52. package/dist/chains/eni/platforms/daoaas/meta.js +6 -9
  53. package/dist/chains/eni/platforms/daoaas/portal-direct.js +44 -28
  54. package/dist/chains/eni/platforms/daoaas/portal.js +6 -10
  55. package/dist/chains/eni/platforms/dswap/liquidity.js +26 -58
  56. package/dist/chains/eni/platforms/fair-launch/index.d.ts +2 -2
  57. package/dist/chains/eni/platforms/fair-launch/index.js +1 -1
  58. package/dist/chains/eni/platforms/fair-launch/launcher.js +46 -87
  59. package/dist/chains/eni/platforms/fair-launch/pool.js +1 -4
  60. package/dist/chains/eni/platforms/fair-launch/presets.js +2 -2
  61. package/dist/chains/eni/platforms/iro/factory.d.ts +2 -2
  62. package/dist/chains/eni/platforms/iro/factory.js +1 -3
  63. package/dist/chains/eni/platforms/iro/index.d.ts +6 -6
  64. package/dist/chains/eni/platforms/iro/index.js +4 -4
  65. package/dist/chains/eni/platforms/iro/pool.js +26 -90
  66. package/dist/chains/eni/platforms/iro/token.js +31 -107
  67. package/dist/chains/eni/platforms/iro/whitelist.js +18 -6
  68. package/dist/chains/index.d.ts +0 -13
  69. package/dist/chains/index.js +0 -13
  70. package/dist/chains/xlayer/eip7702/bundle-approve.d.ts +26 -2
  71. package/dist/chains/xlayer/eip7702/bundle-approve.js +21 -11
  72. package/dist/chains/xlayer/eip7702/bundle-buy.d.ts +6 -2
  73. package/dist/chains/xlayer/eip7702/bundle-buy.js +51 -13
  74. package/dist/chains/xlayer/eip7702/bundle-create.js +59 -93
  75. package/dist/chains/xlayer/eip7702/bundle-sell.d.ts +6 -2
  76. package/dist/chains/xlayer/eip7702/bundle-sell.js +111 -29
  77. package/dist/chains/xlayer/eip7702/bundle-swap.d.ts +65 -3
  78. package/dist/chains/xlayer/eip7702/bundle-swap.js +245 -51
  79. package/dist/chains/xlayer/eip7702/constants.d.ts +16 -1
  80. package/dist/chains/xlayer/eip7702/constants.js +21 -3
  81. package/dist/chains/xlayer/eip7702/index.d.ts +46 -28
  82. package/dist/chains/xlayer/eip7702/index.js +81 -28
  83. package/dist/chains/xlayer/eip7702/multi-hop-transfer.d.ts +203 -2
  84. package/dist/chains/xlayer/eip7702/multi-hop-transfer.js +307 -63
  85. package/dist/chains/xlayer/eip7702/types.d.ts +0 -88
  86. package/dist/chains/xlayer/eip7702/utils.d.ts +3 -0
  87. package/dist/chains/xlayer/eip7702/utils.js +28 -23
  88. package/dist/chains/xlayer/eip7702/volume.d.ts +184 -6
  89. package/dist/chains/xlayer/eip7702/volume.js +164 -89
  90. package/dist/chains/xlayer/eoa/constants.js +1 -1
  91. package/dist/chains/xlayer/eoa/dex-helpers.js +5 -5
  92. package/dist/chains/xlayer/eoa/eoa-bundle-swap.d.ts +95 -1
  93. package/dist/chains/xlayer/eoa/eoa-bundle-swap.js +299 -66
  94. package/dist/chains/xlayer/eoa/eoa-wash-volume.d.ts +1 -1
  95. package/dist/chains/xlayer/eoa/eoa-wash-volume.js +23 -18
  96. package/dist/chains/xlayer/eoa/index.d.ts +6 -10
  97. package/dist/chains/xlayer/eoa/index.js +23 -8
  98. package/dist/chains/xlayer/eoa/portal-ops.js +2 -7
  99. package/dist/chains/xlayer/eoa/router-manager.js +3 -3
  100. package/dist/chains/xlayer/eoa/types.d.ts +2 -2
  101. package/dist/chains/xlayer/eoa/types.js +3 -1
  102. package/dist/chains/xlayer/index.d.ts +2 -3
  103. package/dist/chains/xlayer/index.js +7 -4
  104. package/dist/contracts/helper3.d.ts +5 -20
  105. package/dist/contracts/helper3.js +20 -56
  106. package/dist/contracts/tm-bundle-merkle/approve-tokenmanager.d.ts +26 -1
  107. package/dist/contracts/tm-bundle-merkle/approve-tokenmanager.js +113 -1
  108. package/dist/contracts/tm-bundle-merkle/config.d.ts +67 -5
  109. package/dist/contracts/tm-bundle-merkle/config.js +114 -2
  110. package/dist/contracts/tm-bundle-merkle/core.d.ts +4 -1
  111. package/dist/contracts/tm-bundle-merkle/core.js +591 -1
  112. package/dist/contracts/tm-bundle-merkle/index.d.ts +5 -5
  113. package/dist/contracts/tm-bundle-merkle/index.js +5 -5
  114. package/dist/contracts/tm-bundle-merkle/internal.d.ts +46 -2
  115. package/dist/contracts/tm-bundle-merkle/internal.js +238 -2
  116. package/dist/contracts/tm-bundle-merkle/pancake-proxy.d.ts +28 -1
  117. package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +686 -1
  118. package/dist/contracts/tm-bundle-merkle/private.d.ts +27 -1
  119. package/dist/contracts/tm-bundle-merkle/private.js +476 -1
  120. package/dist/contracts/tm-bundle-merkle/submit.d.ts +314 -3
  121. package/dist/contracts/tm-bundle-merkle/submit.js +928 -3
  122. package/dist/contracts/tm-bundle-merkle/swap-buy-first.d.ts +55 -2
  123. package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +506 -2
  124. package/dist/contracts/tm-bundle-merkle/swap-internal.d.ts +3 -1
  125. package/dist/contracts/tm-bundle-merkle/swap-internal.js +18 -1
  126. package/dist/contracts/tm-bundle-merkle/swap.d.ts +144 -2
  127. package/dist/contracts/tm-bundle-merkle/swap.js +764 -2
  128. package/dist/contracts/tm-bundle-merkle/types.d.ts +476 -1
  129. package/dist/contracts/tm-bundle-merkle/utils.d.ts +18 -6
  130. package/dist/contracts/tm-bundle-merkle/utils.js +1501 -6
  131. package/dist/contracts/tm-bundle.d.ts +51 -3
  132. package/dist/contracts/tm-bundle.js +177 -108
  133. package/dist/contracts/tm.d.ts +2 -3
  134. package/dist/contracts/tm.js +32 -37
  135. package/dist/contracts/tm1.js +4 -9
  136. package/dist/contracts/tm2.js +4 -9
  137. package/dist/dex/direct-router.d.ts +125 -3
  138. package/dist/dex/direct-router.js +666 -237
  139. package/dist/flows/create.d.ts +1 -2
  140. package/dist/flows/create.js +6 -6
  141. package/dist/index.d.ts +86 -20
  142. package/dist/index.js +216 -20
  143. package/dist/shared/abis/TaxToken.json +105 -0
  144. package/dist/shared/abis/TokenManager2.json +60 -0
  145. package/dist/shared/abis/common.d.ts +83 -2
  146. package/dist/shared/abis/common.js +253 -2
  147. package/dist/shared/abis/index.d.ts +6 -5
  148. package/dist/shared/abis/index.js +7 -5
  149. package/dist/shared/clients/blockrazor.js +25 -39
  150. package/dist/shared/clients/club48.d.ts +2 -2
  151. package/dist/shared/clients/club48.js +29 -34
  152. package/dist/shared/clients/emitservice.js +0 -2
  153. package/dist/shared/clients/four.d.ts +6 -21
  154. package/dist/shared/clients/four.js +24 -29
  155. package/dist/shared/clients/merkle.js +34 -27
  156. package/dist/shared/constants/addresses.d.ts +1 -1
  157. package/dist/shared/constants/addresses.js +2 -11
  158. package/dist/shared/constants/chains.d.ts +1 -1
  159. package/dist/shared/constants/chains.js +1 -1
  160. package/dist/shared/constants/gas.d.ts +1 -1
  161. package/dist/shared/constants/gas.js +6 -2
  162. package/dist/shared/constants/index.d.ts +0 -3
  163. package/dist/shared/constants/index.js +0 -1
  164. package/dist/shared/flap/abi.js +1 -1
  165. package/dist/shared/flap/constants.d.ts +2 -1
  166. package/dist/shared/flap/constants.js +4 -3
  167. package/dist/shared/flap/curve.js +0 -3
  168. package/dist/shared/flap/errors.d.ts +4 -1
  169. package/dist/shared/flap/errors.js +1 -20
  170. package/dist/shared/flap/index.d.ts +5 -5
  171. package/dist/shared/flap/index.js +5 -5
  172. package/dist/shared/flap/launch-v6.d.ts +117 -0
  173. package/dist/shared/flap/launch-v6.js +111 -0
  174. package/dist/shared/flap/meta.d.ts +18 -22
  175. package/dist/shared/flap/meta.js +17 -12
  176. package/dist/shared/flap/permit.js +2 -5
  177. package/dist/shared/flap/pinata.d.ts +6 -22
  178. package/dist/shared/flap/pinata.js +26 -21
  179. package/dist/shared/flap/portal-bundle-merkle/config.d.ts +72 -3
  180. package/dist/shared/flap/portal-bundle-merkle/config.js +124 -4
  181. package/dist/shared/flap/portal-bundle-merkle/core.d.ts +4 -0
  182. package/dist/shared/flap/portal-bundle-merkle/core.js +267 -164
  183. package/dist/shared/flap/portal-bundle-merkle/create-to-dex.d.ts +4 -17
  184. package/dist/shared/flap/portal-bundle-merkle/create-to-dex.js +195 -107
  185. package/dist/shared/flap/portal-bundle-merkle/curve-to-dex.js +92 -100
  186. package/dist/shared/flap/portal-bundle-merkle/index.d.ts +7 -11
  187. package/dist/shared/flap/portal-bundle-merkle/index.js +7 -4
  188. package/dist/shared/flap/portal-bundle-merkle/pancake-proxy.js +68 -71
  189. package/dist/shared/flap/portal-bundle-merkle/private.js +114 -61
  190. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first.d.ts +64 -1
  191. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first.js +247 -66
  192. package/dist/shared/flap/portal-bundle-merkle/swap.d.ts +71 -2
  193. package/dist/shared/flap/portal-bundle-merkle/swap.js +410 -103
  194. package/dist/shared/flap/portal-bundle-merkle/types.d.ts +12 -88
  195. package/dist/shared/flap/portal-bundle-merkle/utils.d.ts +80 -1
  196. package/dist/shared/flap/portal-bundle-merkle/utils.js +265 -145
  197. package/dist/shared/flap/portal-bundle.js +56 -55
  198. package/dist/shared/flap/portal.d.ts +3 -14
  199. package/dist/shared/flap/portal.js +26 -49
  200. package/dist/shared/flap/vanity.d.ts +5 -4
  201. package/dist/shared/flap/vanity.js +20 -13
  202. package/dist/shared/flap/vault.d.ts +93 -25
  203. package/dist/shared/flap/vault.js +126 -75
  204. package/dist/shared/four/tax-token.d.ts +1 -1
  205. package/dist/shared/four/tax-token.js +7 -27
  206. package/dist/shared/index.d.ts +0 -6
  207. package/dist/shared/index.js +0 -4
  208. package/dist/utils/airdrop-sweep.d.ts +76 -4
  209. package/dist/utils/airdrop-sweep.js +55 -42
  210. package/dist/utils/bundle-helpers.d.ts +243 -9
  211. package/dist/utils/bundle-helpers.js +584 -10
  212. package/dist/utils/constants.d.ts +61 -5
  213. package/dist/utils/constants.js +80 -5
  214. package/dist/utils/contract-factory.d.ts +4 -2
  215. package/dist/utils/contract-factory.js +18 -25
  216. package/dist/utils/erc20.d.ts +89 -7
  217. package/dist/utils/erc20.js +125 -94
  218. package/dist/utils/errors.d.ts +1 -12
  219. package/dist/utils/errors.js +1 -60
  220. package/dist/utils/holders-maker.d.ts +138 -2
  221. package/dist/utils/holders-maker.js +661 -26
  222. package/dist/utils/lp-inspect.d.ts +112 -2
  223. package/dist/utils/lp-inspect.js +223 -73
  224. package/dist/utils/mpcExclusive.d.ts +5 -2
  225. package/dist/utils/mpcExclusive.js +3 -4
  226. package/dist/utils/private-sale.d.ts +58 -2
  227. package/dist/utils/private-sale.js +15 -4
  228. package/dist/utils/provider-factory.d.ts +0 -4
  229. package/dist/utils/provider-factory.js +0 -10
  230. package/dist/utils/quote-helpers.d.ts +45 -4
  231. package/dist/utils/quote-helpers.js +74 -17
  232. package/dist/utils/stealth-transfer.d.ts +28 -2
  233. package/dist/utils/stealth-transfer.js +15 -31
  234. package/dist/utils/swap-helpers.d.ts +15 -2
  235. package/dist/utils/swap-helpers.js +11 -6
  236. package/dist/utils/wallet.d.ts +25 -2
  237. package/dist/utils/wallet.js +10 -13
  238. package/package.json +4 -160
  239. package/dist/__tests__/subpath-exports.test.d.ts +0 -1
  240. package/dist/__tests__/subpath-exports.test.js +0 -64
  241. package/dist/abis/common.d.ts +0 -85
  242. package/dist/abis/common.js +0 -264
  243. package/dist/abis/contracts/TaxToken.json +0 -969
  244. package/dist/abis/contracts/TokenManager2.json +0 -136
  245. package/dist/abis/contracts/index.d.ts +0 -5
  246. package/dist/abis/contracts/index.js +0 -5
  247. package/dist/abis/flap/index.d.ts +0 -3
  248. package/dist/abis/flap/index.js +0 -3
  249. package/dist/abis/flap/portal-events.d.ts +0 -6
  250. package/dist/abis/flap/portal-events.js +0 -17
  251. package/dist/abis/flap/portal.d.ts +0 -6
  252. package/dist/abis/flap/portal.js +0 -37
  253. package/dist/abis/flap/vault.d.ts +0 -171
  254. package/dist/abis/flap/vault.js +0 -91
  255. package/dist/abis/index.d.ts +0 -8
  256. package/dist/abis/index.js +0 -11
  257. package/dist/bundle-core/__tests__/config-helpers.test.d.ts +0 -1
  258. package/dist/bundle-core/__tests__/config-helpers.test.js +0 -28
  259. package/dist/bundle-core/__tests__/facade-parity.test.d.ts +0 -1
  260. package/dist/bundle-core/__tests__/facade-parity.test.js +0 -33
  261. package/dist/bundle-core/__tests__/sign-context-helpers.test.d.ts +0 -1
  262. package/dist/bundle-core/__tests__/sign-context-helpers.test.js +0 -60
  263. package/dist/bundle-core/__tests__/sign-fixture.test.d.ts +0 -1
  264. package/dist/bundle-core/__tests__/sign-fixture.test.js +0 -220
  265. package/dist/bundle-core/__tests__/sign-fixtures.d.ts +0 -10
  266. package/dist/bundle-core/__tests__/sign-fixtures.js +0 -16
  267. package/dist/bundle-core/config-helpers.d.ts +0 -36
  268. package/dist/bundle-core/config-helpers.js +0 -57
  269. package/dist/bundle-core/errors.d.ts +0 -50
  270. package/dist/bundle-core/errors.js +0 -35
  271. package/dist/bundle-core/four-meme/approve-tokenmanager.d.ts +0 -7
  272. package/dist/bundle-core/four-meme/approve-tokenmanager.js +0 -99
  273. package/dist/bundle-core/four-meme/core-helpers.d.ts +0 -8
  274. package/dist/bundle-core/four-meme/core-helpers.js +0 -40
  275. package/dist/bundle-core/four-meme/core.d.ts +0 -4
  276. package/dist/bundle-core/four-meme/core.js +0 -515
  277. package/dist/bundle-core/four-meme/pancake-proxy.d.ts +0 -28
  278. package/dist/bundle-core/four-meme/pancake-proxy.js +0 -679
  279. package/dist/bundle-core/four-meme/private.d.ts +0 -27
  280. package/dist/bundle-core/four-meme/private.js +0 -465
  281. package/dist/bundle-core/four-meme/sign-context-helpers.d.ts +0 -2
  282. package/dist/bundle-core/four-meme/sign-context-helpers.js +0 -2
  283. package/dist/bundle-core/four-meme/swap-buy-first.d.ts +0 -8
  284. package/dist/bundle-core/four-meme/swap-buy-first.js +0 -493
  285. package/dist/bundle-core/four-meme/swap-hop-helpers.d.ts +0 -6
  286. package/dist/bundle-core/four-meme/swap-hop-helpers.js +0 -63
  287. package/dist/bundle-core/four-meme/swap-internal.d.ts +0 -3
  288. package/dist/bundle-core/four-meme/swap-internal.js +0 -18
  289. package/dist/bundle-core/four-meme/swap-sign-helpers.d.ts +0 -27
  290. package/dist/bundle-core/four-meme/swap-sign-helpers.js +0 -105
  291. package/dist/bundle-core/four-meme/swap.d.ts +0 -17
  292. package/dist/bundle-core/four-meme/swap.js +0 -505
  293. package/dist/bundle-core/four-meme/types/buy-first.d.ts +0 -50
  294. package/dist/bundle-core/four-meme/types/buy-first.js +0 -1
  295. package/dist/bundle-core/four-meme/types/core-flow.d.ts +0 -63
  296. package/dist/bundle-core/four-meme/types/core-flow.js +0 -1
  297. package/dist/bundle-core/four-meme/types/index.d.ts +0 -600
  298. package/dist/bundle-core/four-meme/types/index.js +0 -1
  299. package/dist/bundle-core/four-meme/types/swap-internal.d.ts +0 -19
  300. package/dist/bundle-core/four-meme/types/swap-internal.js +0 -1
  301. package/dist/bundle-core/four-meme/types.d.ts +0 -1
  302. package/dist/bundle-core/four-meme/types.js +0 -1
  303. package/dist/bundle-core/four-meme/utils-disperse.d.ts +0 -7
  304. package/dist/bundle-core/four-meme/utils-disperse.js +0 -396
  305. package/dist/bundle-core/four-meme/utils-pairwise.d.ts +0 -8
  306. package/dist/bundle-core/four-meme/utils-pairwise.js +0 -328
  307. package/dist/bundle-core/four-meme/utils-sweep.d.ts +0 -8
  308. package/dist/bundle-core/four-meme/utils-sweep.js +0 -744
  309. package/dist/bundle-core/index.d.ts +0 -8
  310. package/dist/bundle-core/index.js +0 -8
  311. package/dist/bundle-core/internal.d.ts +0 -21
  312. package/dist/bundle-core/internal.js +0 -182
  313. package/dist/bundle-core/sign-context-helpers.d.ts +0 -25
  314. package/dist/bundle-core/sign-context-helpers.js +0 -67
  315. package/dist/bundle-core/submit.d.ts +0 -293
  316. package/dist/bundle-core/submit.js +0 -727
  317. package/dist/bundle-core/types/index.d.ts +0 -8
  318. package/dist/bundle-core/types/index.js +0 -1
  319. package/dist/bundle-core/types.d.ts +0 -1
  320. package/dist/bundle-core/types.js +0 -1
  321. package/dist/chains/bsc/four/utils-disperse.d.ts +0 -1
  322. package/dist/chains/bsc/four/utils-disperse.js +0 -1
  323. package/dist/chains/bsc/four/utils-pairwise.d.ts +0 -1
  324. package/dist/chains/bsc/four/utils-pairwise.js +0 -1
  325. package/dist/chains/bsc/four/utils-sweep.d.ts +0 -1
  326. package/dist/chains/bsc/four/utils-sweep.js +0 -1
  327. package/dist/chains/bsc/iro.d.ts +0 -5
  328. package/dist/chains/bsc/iro.js +0 -4
  329. package/dist/chains/bsc/pancake/bundle-buy-first-helpers.d.ts +0 -159
  330. package/dist/chains/bsc/pancake/bundle-buy-first-helpers.js +0 -117
  331. package/dist/chains/bsc/pancake/bundle-swap-helpers.d.ts +0 -241
  332. package/dist/chains/bsc/pancake/bundle-swap-helpers.js +0 -565
  333. package/dist/chains/eni/flat-aliases.d.ts +0 -10
  334. package/dist/chains/eni/flat-aliases.js +0 -8
  335. package/dist/chains/eni/submit.d.ts +0 -43
  336. package/dist/chains/eni/submit.js +0 -286
  337. package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +0 -13
  338. package/dist/chains/xlayer/eip7702/flat-aliases.js +0 -10
  339. package/dist/chains/xlayer/eip7702/multi-hop-transfer-helpers.d.ts +0 -79
  340. package/dist/chains/xlayer/eip7702/multi-hop-transfer-helpers.js +0 -1
  341. package/dist/chains/xlayer/eip7702/transfer-context-helpers.d.ts +0 -26
  342. package/dist/chains/xlayer/eip7702/transfer-context-helpers.js +0 -57
  343. package/dist/chains/xlayer/eip7702/volume-helpers.d.ts +0 -148
  344. package/dist/chains/xlayer/eip7702/volume-helpers.js +0 -48
  345. package/dist/chains/xlayer/eoa/eoa-bundle-swap-helpers.d.ts +0 -126
  346. package/dist/chains/xlayer/eoa/eoa-bundle-swap-helpers.js +0 -228
  347. package/dist/contracts/tm-bundle-helpers.d.ts +0 -88
  348. package/dist/contracts/tm-bundle-helpers.js +0 -72
  349. package/dist/contracts/tm-bundle-merkle/utils-disperse.d.ts +0 -1
  350. package/dist/contracts/tm-bundle-merkle/utils-disperse.js +0 -1
  351. package/dist/contracts/tm-bundle-merkle/utils-pairwise.d.ts +0 -1
  352. package/dist/contracts/tm-bundle-merkle/utils-pairwise.js +0 -1
  353. package/dist/contracts/tm-bundle-merkle/utils-sweep.d.ts +0 -1
  354. package/dist/contracts/tm-bundle-merkle/utils-sweep.js +0 -1
  355. package/dist/dex/direct-router-helpers.d.ts +0 -264
  356. package/dist/dex/direct-router-helpers.js +0 -539
  357. package/dist/dex/types.d.ts +0 -81
  358. package/dist/dex/types.js +0 -1
  359. package/dist/exports/root-bundle-and-tooling.d.ts +0 -27
  360. package/dist/exports/root-bundle-and-tooling.js +0 -30
  361. package/dist/exports/root-eni-and-bsc-iro.d.ts +0 -26
  362. package/dist/exports/root-eni-and-bsc-iro.js +0 -66
  363. package/dist/exports/root-foundations.d.ts +0 -35
  364. package/dist/exports/root-foundations.js +0 -70
  365. package/dist/exports/root-swap-dex-and-xlayer.d.ts +0 -30
  366. package/dist/exports/root-swap-dex-and-xlayer.js +0 -78
  367. package/dist/flap/index.d.ts +0 -10
  368. package/dist/flap/index.js +0 -8
  369. package/dist/flows/index.d.ts +0 -1
  370. package/dist/flows/index.js +0 -1
  371. package/dist/merkle/index.d.ts +0 -12
  372. package/dist/merkle/index.js +0 -11
  373. package/dist/shared/clients/index.d.ts +0 -8
  374. package/dist/shared/clients/index.js +0 -8
  375. package/dist/shared/constants/quote.d.ts +0 -30
  376. package/dist/shared/constants/quote.js +0 -37
  377. package/dist/shared/flap/portal-bundle-merkle/core-helpers.d.ts +0 -32
  378. package/dist/shared/flap/portal-bundle-merkle/core-helpers.js +0 -83
  379. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first-helpers.d.ts +0 -125
  380. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first-helpers.js +0 -113
  381. package/dist/shared/flap/portal-bundle-merkle/swap-helpers.d.ts +0 -149
  382. package/dist/shared/flap/portal-bundle-merkle/swap-helpers.js +0 -259
  383. package/dist/shared/flap/portal-create-token.d.ts +0 -79
  384. package/dist/shared/flap/portal-create-token.js +0 -261
  385. package/dist/shared/foundation/dex/v3-path.d.ts +0 -6
  386. package/dist/shared/foundation/dex/v3-path.js +0 -35
  387. package/dist/shared/foundation/gas/bundle-gas.d.ts +0 -49
  388. package/dist/shared/foundation/gas/bundle-gas.js +0 -93
  389. package/dist/shared/foundation/gas/profit-hop.d.ts +0 -20
  390. package/dist/shared/foundation/gas/profit-hop.js +0 -72
  391. package/dist/shared/foundation/index.d.ts +0 -13
  392. package/dist/shared/foundation/index.js +0 -12
  393. package/dist/shared/foundation/nonce/nonce-manager.d.ts +0 -17
  394. package/dist/shared/foundation/nonce/nonce-manager.js +0 -183
  395. package/dist/shared/foundation/normalize-unknown.d.ts +0 -9
  396. package/dist/shared/foundation/normalize-unknown.js +0 -29
  397. package/dist/shared/foundation/sdk-logger.d.ts +0 -13
  398. package/dist/shared/foundation/sdk-logger.js +0 -12
  399. package/dist/shared/foundation/tx/build-request.d.ts +0 -17
  400. package/dist/shared/foundation/tx/build-request.js +0 -25
  401. package/dist/shared/foundation/tx/sign-batch.d.ts +0 -5
  402. package/dist/shared/foundation/tx/sign-batch.js +0 -26
  403. package/dist/shared/foundation/tx/wallet-sign-patch.d.ts +0 -1
  404. package/dist/shared/foundation/tx/wallet-sign-patch.js +0 -18
  405. package/dist/shared/foundation/types/airdrop-sweep.d.ts +0 -79
  406. package/dist/shared/foundation/types/airdrop-sweep.js +0 -1
  407. package/dist/shared/foundation/types/erc20.d.ts +0 -65
  408. package/dist/shared/foundation/types/erc20.js +0 -1
  409. package/dist/shared/foundation/types/holders-maker.d.ts +0 -64
  410. package/dist/shared/foundation/types/holders-maker.js +0 -1
  411. package/dist/shared/foundation/types/index.d.ts +0 -7
  412. package/dist/shared/foundation/types/index.js +0 -1
  413. package/dist/shared/foundation/types/lp-inspect.d.ts +0 -102
  414. package/dist/shared/foundation/types/lp-inspect.js +0 -1
  415. package/dist/shared/foundation/types/multicall.d.ts +0 -5
  416. package/dist/shared/foundation/types/multicall.js +0 -1
  417. package/dist/shared/foundation/types/private-sale.d.ts +0 -35
  418. package/dist/shared/foundation/types/private-sale.js +0 -1
  419. package/dist/shared/foundation/types/quote-helpers.d.ts +0 -17
  420. package/dist/shared/foundation/types/quote-helpers.js +0 -1
  421. package/dist/types/errors.d.ts +0 -27
  422. package/dist/types/errors.js +0 -34
  423. package/dist/utils/holders-maker/addresses.d.ts +0 -12
  424. package/dist/utils/holders-maker/addresses.js +0 -15
  425. package/dist/utils/holders-maker/buy-tx.d.ts +0 -44
  426. package/dist/utils/holders-maker/buy-tx.js +0 -278
  427. package/dist/utils/holders-maker/constants.d.ts +0 -6
  428. package/dist/utils/holders-maker/constants.js +0 -7
  429. package/dist/utils/holders-maker/disperse.d.ts +0 -18
  430. package/dist/utils/holders-maker/disperse.js +0 -90
  431. package/dist/utils/holders-maker/routing.d.ts +0 -4
  432. package/dist/utils/holders-maker/routing.js +0 -45
  433. package/dist/utils/holders-maker/transfer-tx.d.ts +0 -4
  434. package/dist/utils/holders-maker/transfer-tx.js +0 -67
  435. package/dist/utils/holders-maker-helpers.d.ts +0 -9
  436. package/dist/utils/holders-maker-helpers.js +0 -9
  437. package/dist/utils/hop-chains.d.ts +0 -35
  438. package/dist/utils/hop-chains.js +0 -215
  439. package/dist/utils/lp-inspect-helpers.d.ts +0 -9
  440. package/dist/utils/lp-inspect-helpers.js +0 -109
  441. package/dist/utils/types/airdrop-sweep.d.ts +0 -1
  442. package/dist/utils/types/airdrop-sweep.js +0 -1
  443. package/dist/utils/types/contract-factory.d.ts +0 -1
  444. package/dist/utils/types/contract-factory.js +0 -1
  445. package/dist/utils/types/erc20.d.ts +0 -1
  446. package/dist/utils/types/erc20.js +0 -1
  447. package/dist/utils/types/errors.d.ts +0 -1
  448. package/dist/utils/types/errors.js +0 -1
  449. package/dist/utils/types/holders-maker.d.ts +0 -1
  450. package/dist/utils/types/holders-maker.js +0 -1
  451. package/dist/utils/types/hop-chains.d.ts +0 -8
  452. package/dist/utils/types/hop-chains.js +0 -1
  453. package/dist/utils/types/index.d.ts +0 -13
  454. package/dist/utils/types/index.js +0 -1
  455. package/dist/utils/types/lp-inspect.d.ts +0 -1
  456. package/dist/utils/types/lp-inspect.js +0 -1
  457. package/dist/utils/types/mpc-exclusive.d.ts +0 -5
  458. package/dist/utils/types/mpc-exclusive.js +0 -1
  459. package/dist/utils/types/private-sale.d.ts +0 -1
  460. package/dist/utils/types/private-sale.js +0 -1
  461. package/dist/utils/types/quote-helpers.d.ts +0 -1
  462. package/dist/utils/types/quote-helpers.js +0 -1
  463. package/dist/utils/types/stealth-transfer.d.ts +0 -44
  464. package/dist/utils/types/stealth-transfer.js +0 -1
  465. package/dist/utils/types/wallet.d.ts +0 -25
  466. package/dist/utils/types/wallet.js +0 -1
  467. package/dist/vanity/index.d.ts +0 -5
  468. package/dist/vanity/index.js +0 -5
  469. package/src/abis/contracts/TaxToken.json +0 -969
  470. package/src/abis/contracts/TokenManager.json +0 -836
  471. package/src/abis/contracts/TokenManager2.json +0 -136
  472. package/src/abis/contracts/TokenManagerHelper3.json +0 -993
  473. /package/dist/{abis/contracts → shared/abis}/TokenManager.json +0 -0
  474. /package/dist/{abis/contracts → shared/abis}/TokenManagerHelper3.json +0 -0
@@ -1,14 +1,524 @@
1
1
  /**
2
- * direct-router - 主函数
2
+ * 直接 Router 交易(不走代理合约)
3
+ *
4
+ * 支持:
5
+ * - BSC: PancakeSwap V2/V3
6
+ * - Monad: PancakeSwap V2, Uniswap V2/V3
7
+ *
8
+ * 收费方式:交易末尾附加利润提取交易(和内盘一致)
3
9
  */
4
- import { ethers, Wallet, Contract } from 'ethers';
5
- import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, buildGasFields } from '../utils/bundle-helpers.js';
6
- import { getProfitRecipient } from '../shared/constants/index.js';
10
+ import { ethers, Wallet, JsonRpcProvider, Contract } from 'ethers';
11
+ import { NonceManager, getOptimizedGasPrice, getDeadline as _getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT, buildGasFields } from '../utils/bundle-helpers.js';
12
+ import { PROFIT_CONFIG, ZERO_ADDRESS, BLOCKRAZOR_BUILDER_EOA, ADDRESSES, getProfitRecipient } from '../utils/constants.js';
7
13
  import { GAS_LIMITS } from '../shared/constants/index.js';
8
- import { ERC20_ABI } from '../abis/common.js';
14
+ import { V2_ROUTER_ABI as _V2_ROUTER_ABI, V3_ROUTER02_ABI as _V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI as _V3_ROUTER_LEGACY_ABI, SWAP_ROUTER02_V2_ABI as _SWAP_ROUTER02_V2_ABI, ERC20_ABI } from '../shared/abis/common.js';
9
15
  import { getTokenToNativeQuote, quoteV2 } from '../utils/quote-helpers.js';
10
- import { CHAIN_IDS, DIRECT_ROUTERS, SWAP_ROUTER02_V2_ABI, V2_ROUTER_ABI, V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI, buildBribeTransaction, buildProfitTransactionWithHops, calculateProfitAmount, encodeDYORMulticall, encodeDYORRefundETH, encodeDYORSwapExactTokensForTokens, encodeDYORUnwrapWETH9, findMaxFlowIndex, filterEniNativeBuyIndices, getBribeAmount, getCachedProvider, getDeadline, getGasLimit, getGasPrice, getWrappedNative, isDYORSwap, isLegacySwapRouter, isNativeToken, isSwapRouter02, quoteXLayerV3TokenToNativeBySlot0, truncateDecimals, } from './direct-router-helpers.js';
11
- export { DIRECT_ROUTERS } from './direct-router-helpers.js';
16
+ // ============================================================================
17
+ // 方案 C:Provider 缓存(避免重复创建)
18
+ // ============================================================================
19
+ const providerCache = new Map();
20
+ const PROVIDER_CACHE_TTL = 60000; // 60秒后过期
21
+ const providerCacheTimestamps = new Map();
22
+ /**
23
+ * 获取缓存的 Provider 实例
24
+ * - 根据 rpcUrl + chainId 作为缓存 key
25
+ * - 60秒后自动失效,避免长连接问题
26
+ */
27
+ function getCachedProvider(rpcUrl, chainId, chainName) {
28
+ const cacheKey = `${rpcUrl}_${chainId}`;
29
+ const now = Date.now();
30
+ // 检查缓存是否存在且未过期
31
+ const cachedProvider = providerCache.get(cacheKey);
32
+ const timestamp = providerCacheTimestamps.get(cacheKey) || 0;
33
+ if (cachedProvider && (now - timestamp) < PROVIDER_CACHE_TTL) {
34
+ return cachedProvider;
35
+ }
36
+ // ✅ 禁用 ENS: 避免 "network does not support ENS" 错误
37
+ const provider = new JsonRpcProvider(rpcUrl, { chainId, name: chainName, ensAddress: undefined });
38
+ providerCache.set(cacheKey, provider);
39
+ providerCacheTimestamps.set(cacheKey, now);
40
+ return provider;
41
+ }
42
+ const DEFAULT_GAS_LIMIT = 300000;
43
+ const DEADLINE_MINUTES = 20;
44
+ // ✅ BLOCKRAZOR_BUILDER_EOA 从公共模块导入
45
+ /**
46
+ * 截断小数位数,避免超过代币精度导致 parseUnits 报错
47
+ * 例如:truncateDecimals("21906.025000000000000000", 1) => "21906.0"
48
+ */
49
+ function truncateDecimals(value, decimals) {
50
+ if (!value || decimals < 0)
51
+ return value;
52
+ const parts = value.split('.');
53
+ if (parts.length === 1)
54
+ return value; // 没有小数点
55
+ const integerPart = parts[0];
56
+ const decimalPart = parts[1];
57
+ if (decimals === 0)
58
+ return integerPart;
59
+ // 截断到指定小数位数
60
+ const truncatedDecimal = decimalPart.slice(0, decimals);
61
+ // 如果截断后没有小数部分,只返回整数部分
62
+ if (!truncatedDecimal || truncatedDecimal === '')
63
+ return integerPart;
64
+ return `${integerPart}.${truncatedDecimal}`;
65
+ }
66
+ /** Router 地址配置 - ✅ 使用公共模块中的地址 */
67
+ export const DIRECT_ROUTERS = {
68
+ BSC: {
69
+ PANCAKESWAP_V2: ADDRESSES.BSC.PancakeV2Router,
70
+ PANCAKESWAP_V3: ADDRESSES.BSC.PancakeV3Router,
71
+ IROSWAP_V2: ADDRESSES.BSC.IroSwapV2Router,
72
+ WBNB: ADDRESSES.BSC.WBNB,
73
+ },
74
+ MONAD: {
75
+ // PancakeSwap
76
+ PANCAKESWAP_V2: '0xB1Bc24c34e88f7D43D5923034E3a14B24DaACfF9',
77
+ PANCAKESWAP_V3: '0x1b81D678ffb9C0263b24A97847620C99d213eB14',
78
+ // Uniswap
79
+ UNISWAP_V2: '0x4b2ab38dbf28d31d467aa8993f6c2585981d6804',
80
+ UNISWAP_V3: '0xd6145b2d3f379919e8cdeda7b97e37c4b2ca9c40',
81
+ // Wrapped Native
82
+ WMON: ADDRESSES.MONAD.WMON,
83
+ },
84
+ // XLayer (PotatoSwap + DYORSwap)
85
+ XLAYER: {
86
+ POTATOSWAP_V2: '0x881fb2f98c13d521009464e7d1cbf16e1b394e8e',
87
+ POTATOSWAP_V3: '0xB45D0149249488333E3F3f9F359807F4b810C1FC',
88
+ DYORSWAP_ROUTER: '0xfb001fbbace32f09cb6d3c449b935183de53ee96',
89
+ DYORSWAP_FACTORY: '0x2CcaDb1e437AA9cDc741574bDa154686B1F04C09',
90
+ V3_ROUTER: '0xBB069e9465BcabC4F488d21e793BDEf0F2d41D41',
91
+ V3_FACTORY: '0xa1415fAe79c4B196d087F02b8aD5a622B8A827E5',
92
+ WOKB: '0xe538905cf8410324e03a5a23c1c177a474d59b2b',
93
+ },
94
+ ENI: {
95
+ DSWAP_V2: ADDRESSES.ENI.DswapV2Router,
96
+ DSWAP_V3: ADDRESSES.ENI.DswapV3Router02,
97
+ IROSWAP_V2: ADDRESSES.ENI.IroSwapV2Router,
98
+ WEGAS: ADDRESSES.ENI.WEGAS,
99
+ },
100
+ };
101
+ /** 链 ID 映射 */
102
+ const CHAIN_IDS = {
103
+ BSC: 56,
104
+ MONAD: 143,
105
+ XLAYER: 196,
106
+ ENI: 173,
107
+ };
108
+ /** 获取原生包装代币地址 */
109
+ function getWrappedNative(chain) {
110
+ const chainUpper = chain.toUpperCase();
111
+ if (chainUpper === 'BSC')
112
+ return DIRECT_ROUTERS.BSC.WBNB;
113
+ if (chainUpper === 'MONAD')
114
+ return DIRECT_ROUTERS.MONAD.WMON;
115
+ if (chainUpper === 'XLAYER')
116
+ return DIRECT_ROUTERS.XLAYER.WOKB;
117
+ if (chainUpper === 'ENI')
118
+ return DIRECT_ROUTERS.ENI.WEGAS;
119
+ throw new Error(`Unsupported chain: ${chain}`);
120
+ }
121
+ // ============================================================================
122
+ // ABI - ✅ 使用公共模块
123
+ // ============================================================================
124
+ /** V2 Router ABI */
125
+ const V2_ROUTER_ABI = _V2_ROUTER_ABI;
126
+ /** SwapRouter02 的 V2 方法 ABI - ✅ 从公共模块导入 */
127
+ const SWAP_ROUTER02_V2_ABI = _SWAP_ROUTER02_V2_ABI;
128
+ /**
129
+ * DYORSwap SwapRouter02 的 V2 方法
130
+ *
131
+ * ⚠️ 重要:DYORSwap 使用自定义的函数签名,无法通过标准 ABI 编码
132
+ * 必须手动构造 calldata
133
+ *
134
+ * swapExactTokensForTokens selector: 0x3234fe0d
135
+ * unwrapWETH9 selector: 0x7342292e
136
+ * refundETH selector: 0x6d29fcf4
137
+ */
138
+ const DYORSWAP_SELECTORS = {
139
+ swapExactTokensForTokens: '0x3234fe0d',
140
+ unwrapWETH9: '0x7342292e',
141
+ refundETH: '0x6d29fcf4',
142
+ multicall: '0x5ae401dc',
143
+ };
144
+ /**
145
+ * 手动编码 DYORSwap 的 swapExactTokensForTokens calldata
146
+ *
147
+ * 参数格式 (根据成功交易分析):
148
+ * - amountIn: uint256
149
+ * - amountOutMin: uint256
150
+ * - path: address[] (动态) - offset from start
151
+ * - pools: address[] (动态) - offset from start
152
+ * - to: uint256 (address(2) = 2)
153
+ * - flag: uint256 (1)
154
+ * - factory: address
155
+ *
156
+ * 成功交易的布局:
157
+ * [0] amountIn
158
+ * [1] amountOutMin
159
+ * [2] offset to path = 0xa0 = 160 = 5 * 32 (从参数区域开始)
160
+ * [3] offset to pools = 0xe0 = 224 = 7 * 32
161
+ * [4] to = 2
162
+ * [5] flag = 1
163
+ * [6] factory
164
+ * [7] path.length
165
+ * [8+] path elements
166
+ * [N] pools.length
167
+ * [N+1+] pools elements
168
+ */
169
+ function encodeDYORSwapExactTokensForTokens(amountIn, amountOutMin, path, pools, to, // 可以是地址 (string) 或 address(2) 这样的特殊值 (bigint)
170
+ flag, factory) {
171
+ const pathOffset = 5n * 32n; // 160
172
+ // poolsOffset = pathOffset + (1 + path.length) * 32 = 160 + 96 = 256?
173
+ // 不对,成功交易是 224 = 160 + 64 = pathOffset + path.length * 32
174
+ const poolsOffset = pathOffset + BigInt(path.length) * 32n; // 160 + 2*32 = 224
175
+ // 手动构建数据
176
+ const pad32 = (hex) => hex.replace('0x', '').padStart(64, '0');
177
+ const toHex = (n) => n.toString(16).padStart(64, '0');
178
+ // 处理 to 参数:可以是地址 (string) 或特殊值 (bigint)
179
+ const toValue = typeof to === 'string' ? pad32(to) : toHex(to);
180
+ let data = DYORSWAP_SELECTORS.swapExactTokensForTokens;
181
+ data += toHex(amountIn);
182
+ data += toHex(amountOutMin);
183
+ data += toHex(pathOffset);
184
+ data += toHex(poolsOffset);
185
+ data += toValue;
186
+ data += toHex(flag);
187
+ data += pad32(factory);
188
+ // path 数据
189
+ data += toHex(BigInt(path.length));
190
+ for (const addr of path) {
191
+ data += pad32(addr);
192
+ }
193
+ // ⚠️ 不包含 pools 数据!成功交易中 pools 是空的
194
+ // poolsOffset 指向的位置没有数据
195
+ return '0x' + data.replace('0x', '');
196
+ }
197
+ /**
198
+ * 手动编码 DYORSwap 的 unwrapWETH9 calldata
199
+ *
200
+ * 参数格式 (根据成功交易分析):
201
+ * - amountMinimum: uint256
202
+ * - recipient: address
203
+ * - pools: bytes (动态) - 包含特殊的 pool 数据
204
+ *
205
+ * 成功交易的布局:
206
+ * [0] amountMinimum
207
+ * [1] recipient
208
+ * [2] offset to pools = 0x60 = 96 = 3 * 32
209
+ * [3] pools 数据 (bytes)
210
+ */
211
+ function encodeDYORUnwrapWETH9(amountMinimum, recipient, poolsData = '' // hex bytes,可以为空
212
+ ) {
213
+ const pad32 = (hex) => hex.slice(2).padStart(64, '0');
214
+ const toHex = (n) => n.toString(16).padStart(64, '0');
215
+ const poolsOffset = 3n * 32n; // 96
216
+ const poolsBytes = poolsData.startsWith('0x') ? poolsData.slice(2) : poolsData;
217
+ const poolsLength = poolsBytes.length / 2;
218
+ let data = DYORSWAP_SELECTORS.unwrapWETH9;
219
+ data += toHex(amountMinimum);
220
+ data += pad32(recipient);
221
+ data += toHex(poolsOffset);
222
+ data += toHex(BigInt(poolsLength));
223
+ // pools 数据需要 padding 到 32 字节的倍数
224
+ if (poolsBytes.length > 0) {
225
+ const paddedLength = Math.ceil(poolsBytes.length / 64) * 64;
226
+ data += poolsBytes.padEnd(paddedLength, '0');
227
+ }
228
+ return '0x' + data.replace('0x', '');
229
+ }
230
+ /**
231
+ * DYORSwap 的 ETHBack_Dividend 合约地址
232
+ * 这是 refundETH 中使用的固定地址,不是 LP 池地址
233
+ */
234
+ const DYORSWAP_ETHBACK_DIVIDEND = '0x2e61b0b4410f6fb941d47205191cbb8963d44bcc';
235
+ /**
236
+ * 手动编码 DYORSwap 的 refundETH calldata
237
+ *
238
+ * 根据成功交易分析,refundETH 的格式是:
239
+ * refundETH(bytes pools)
240
+ *
241
+ * 成功交易的 refundETH (0x6d29fcf4):
242
+ * [0] offset to pools = 0x20 = 32
243
+ * [1] pools 数组长度 = 1
244
+ * [2] fee = 30 (0x1e)
245
+ * [3] ETHBack_Dividend 合约地址
246
+ */
247
+ function encodeDYORRefundETH(fee = 30 // 默认 fee = 30 (0x1e)
248
+ ) {
249
+ const toHex = (n) => n.toString(16).padStart(64, '0');
250
+ const pad32 = (hex) => hex.replace('0x', '').padStart(64, '0');
251
+ // 使用固定的 ETHBack_Dividend 合约地址
252
+ let data = DYORSWAP_SELECTORS.refundETH;
253
+ data += toHex(32n); // offset = 0x20
254
+ data += toHex(1n); // 数组长度 = 1
255
+ data += toHex(BigInt(fee)); // fee = 30
256
+ data += pad32(DYORSWAP_ETHBACK_DIVIDEND); // ETHBack_Dividend 地址
257
+ return '0x' + data.replace('0x', '');
258
+ }
259
+ /**
260
+ * 手动编码 DYORSwap 的 multicall calldata
261
+ *
262
+ * multicall(uint256 deadline, bytes[] data)
263
+ * 这个函数使用标准 ABI 编码
264
+ */
265
+ function encodeDYORMulticall(deadline, data) {
266
+ const abiCoder = ethers.AbiCoder.defaultAbiCoder();
267
+ // multicall(uint256 deadline, bytes[] data)
268
+ // 确保每个 data 元素都是正确的 hex 格式
269
+ const formattedData = data.map(d => d.startsWith('0x') ? d : '0x' + d);
270
+ const encoded = abiCoder.encode(['uint256', 'bytes[]'], [deadline, formattedData]).slice(2);
271
+ return '0x' + DYORSWAP_SELECTORS.multicall.slice(2) + encoded;
272
+ }
273
+ /** V3 SwapRouter02 ABI (PancakeSwap V3, 新版 Uniswap) */
274
+ const V3_ROUTER02_ABI = _V3_ROUTER02_ABI;
275
+ /** V3 SwapRouter(旧版)ABI (Monad Uniswap V3) */
276
+ const V3_ROUTER_LEGACY_ABI = _V3_ROUTER_LEGACY_ABI;
277
+ /**
278
+ * 判断是否使用旧版 SwapRouter
279
+ *
280
+ * 旧版特征:
281
+ * - exactInputSingle 包含 deadline 字段
282
+ * - multicall 只有 bytes[] 参数
283
+ *
284
+ * Monad 上的 V3 DEX 都使用旧版:
285
+ * - Uniswap V3: 0xd6145b2d3f379919e8cdeda7b97e37c4b2ca9c40
286
+ * - PancakeSwap V3: 0x1b81D678ffb9C0263b24A97847620C99d213eB14
287
+ *
288
+ * XLayer:
289
+ * - V3 Router (0xBB069e9465BcabC4F488d21e793BDEf0F2d41D41) - 旧版(exactInputSingle 包含 deadline)
290
+ * - SwapRouter02 (0xB45D0149249488333E3F3f9F359807F4b810C1FC) - 新版(V2+V3 混合)
291
+ *
292
+ * BSC PancakeSwap V3 使用新版 SwapRouter02
293
+ */
294
+ function isLegacySwapRouter(chain, routerAddress) {
295
+ const chainUpper = chain.toUpperCase();
296
+ const routerLower = routerAddress.toLowerCase();
297
+ // ✅ Monad 上的所有 V3 Router 都是旧版
298
+ if (chainUpper === 'MONAD') {
299
+ if (routerLower === DIRECT_ROUTERS.MONAD.UNISWAP_V3.toLowerCase()) {
300
+ return true;
301
+ }
302
+ if (routerLower === DIRECT_ROUTERS.MONAD.PANCAKESWAP_V3.toLowerCase()) {
303
+ return true;
304
+ }
305
+ }
306
+ // ✅ XLayer V3 专用 Router 是旧版(exactInputSingle 包含 deadline)
307
+ if (chainUpper === 'XLAYER') {
308
+ if (routerLower === DIRECT_ROUTERS.XLAYER.V3_ROUTER.toLowerCase()) {
309
+ return true; // V3 Router 是旧版
310
+ }
311
+ // SwapRouter02 是新版
312
+ return false;
313
+ }
314
+ // ✅ BSC PancakeSwap V3 使用新版 SwapRouter02
315
+ return false;
316
+ }
317
+ // ============================================================================
318
+ // 工具函数
319
+ // ============================================================================
320
+ // ✅ 使用公共模块的 getDeadline
321
+ function getDeadline(minutes = DEADLINE_MINUTES) {
322
+ return _getDeadline(minutes);
323
+ }
324
+ function getGasLimit(config, defaultGas = DEFAULT_GAS_LIMIT) {
325
+ if (config.gasLimit !== undefined) {
326
+ return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
327
+ }
328
+ const multiplier = config.gasLimitMultiplier ?? 1.2;
329
+ return BigInt(Math.ceil(defaultGas * multiplier));
330
+ }
331
+ async function getGasPrice(provider, config) {
332
+ if (config.gasPrice)
333
+ return config.gasPrice;
334
+ // 转换 Gwei 配置为 Wei
335
+ const gasPriceConfig = {};
336
+ if (config.minGasPriceGwei !== undefined) {
337
+ gasPriceConfig.minGasPrice = ethers.parseUnits(String(config.minGasPriceGwei), 'gwei');
338
+ }
339
+ if (config.maxGasPriceGwei !== undefined) {
340
+ gasPriceConfig.maxGasPrice = ethers.parseUnits(String(config.maxGasPriceGwei), 'gwei');
341
+ }
342
+ return getOptimizedGasPrice(provider, gasPriceConfig);
343
+ }
344
+ function isNativeToken(quoteToken) {
345
+ return !quoteToken || quoteToken === ZERO_ADDRESS;
346
+ }
347
+ // ============================================================================
348
+ // XLAYER V3 报价(slot0 现货价,纯 V3,不串 V2)
349
+ // - 只用于“利润换算”为原生币,避免 XLAYER 没有 v3Quoter 导致 profit=0
350
+ // - 不改 BSC 的任何配置/逻辑
351
+ // ============================================================================
352
+ const XLAYER_V3_FACTORY_ABI = [
353
+ 'function getPool(address tokenA, address tokenB, uint24 fee) view returns (address pool)',
354
+ ];
355
+ const XLAYER_V3_POOL_ABI = [
356
+ 'function slot0() view returns (uint160 sqrtPriceX96,int24 tick,uint16 observationIndex,uint16 observationCardinality,uint16 observationCardinalityNext,uint8 feeProtocol,bool unlocked)',
357
+ 'function token0() view returns (address)',
358
+ 'function token1() view returns (address)',
359
+ ];
360
+ const V3_FEE_DENOMINATOR = 1000000n; // UniswapV3 fee: X / 1e6
361
+ async function quoteXLayerV3TokenToNativeBySlot0(params) {
362
+ try {
363
+ const { provider, tokenIn, amountIn, fee } = params;
364
+ if (!tokenIn || amountIn <= 0n)
365
+ return 0n;
366
+ const chainFactory = DIRECT_ROUTERS.XLAYER.V3_FACTORY;
367
+ const wrappedNative = DIRECT_ROUTERS.XLAYER.WOKB;
368
+ if (!chainFactory || !wrappedNative)
369
+ return 0n;
370
+ const tokenInLower = tokenIn.toLowerCase();
371
+ const wrappedLower = wrappedNative.toLowerCase();
372
+ if (tokenInLower === wrappedLower)
373
+ return amountIn;
374
+ const factory = new Contract(chainFactory, XLAYER_V3_FACTORY_ABI, provider);
375
+ const poolAddr = await factory.getPool?.(tokenIn, wrappedNative, fee);
376
+ if (!poolAddr || poolAddr.toLowerCase() === ZERO_ADDRESS.toLowerCase())
377
+ return 0n;
378
+ const pool = new Contract(poolAddr, XLAYER_V3_POOL_ABI, provider);
379
+ const [t0, t1, slot0] = await Promise.all([pool.token0?.(), pool.token1?.(), pool.slot0?.()]);
380
+ if (!t0 || !t1 || !slot0)
381
+ return 0n;
382
+ const sqrtPriceX96 = BigInt(slot0[0]);
383
+ if (sqrtPriceX96 <= 0n)
384
+ return 0n;
385
+ const amountInLessFee = (amountIn * (V3_FEE_DENOMINATOR - BigInt(fee))) / V3_FEE_DENOMINATOR;
386
+ if (amountInLessFee <= 0n)
387
+ return 0n;
388
+ const Q192 = 2n ** 192n;
389
+ const num = sqrtPriceX96 * sqrtPriceX96;
390
+ const t0Lower = String(t0).toLowerCase();
391
+ const t1Lower = String(t1).toLowerCase();
392
+ // sqrtPriceX96 表示 token1/token0 的现货价(raw)
393
+ if (tokenInLower === t0Lower && wrappedLower === t1Lower) {
394
+ return (amountInLessFee * num) / Q192;
395
+ }
396
+ if (tokenInLower === t1Lower && wrappedLower === t0Lower) {
397
+ return (amountInLessFee * Q192) / num;
398
+ }
399
+ return 0n;
400
+ }
401
+ catch {
402
+ return 0n;
403
+ }
404
+ }
405
+ // ✅ getTokenToNativeQuote 函数已移至 ../utils/quote-helpers.ts
406
+ /**
407
+ * ✅ 找到金额最大的钱包索引(和 core.ts 逻辑一致)
408
+ */
409
+ function findMaxFlowIndex(amounts) {
410
+ if (amounts.length === 0)
411
+ return 0;
412
+ let maxIndex = 0;
413
+ let maxValue = amounts[0];
414
+ for (let i = 1; i < amounts.length; i++) {
415
+ if (amounts[i] > maxValue) {
416
+ maxValue = amounts[i];
417
+ maxIndex = i;
418
+ }
419
+ }
420
+ return maxIndex;
421
+ }
422
+ /** 计算利润金额 */
423
+ function calculateProfitAmount(totalFlowWei) {
424
+ return (totalFlowWei * BigInt(PROFIT_CONFIG.RATE_BPS)) / 10000n;
425
+ }
426
+ /**
427
+ * 构建利润多跳转账交易(强制 2 跳中转)
428
+ */
429
+ async function buildProfitTransactionWithHops(provider, wallet, profitAmountWei, nonce, gasPrice, chainId, txType = 0, profitRecipient) {
430
+ if (profitAmountWei <= 0n)
431
+ return { signedTransactions: [], hopWallets: undefined };
432
+ const profitHopResult = await buildProfitHopTransactions({
433
+ provider,
434
+ payerWallet: wallet,
435
+ profitAmount: profitAmountWei,
436
+ profitRecipient: profitRecipient || getProfitRecipient(),
437
+ hopCount: PROFIT_HOP_COUNT,
438
+ gasPrice,
439
+ chainId,
440
+ txType,
441
+ startNonce: nonce
442
+ });
443
+ return { signedTransactions: profitHopResult.signedTransactions, hopWallets: profitHopResult.hopWallets };
444
+ }
445
+ /**
446
+ * 获取贿赂金额(wei)
447
+ * ✅ 仅 BSC 链支持贿赂
448
+ */
449
+ function getBribeAmount(config, chain) {
450
+ // 只有 BSC 链支持贿赂
451
+ if (chain.toUpperCase() !== 'BSC')
452
+ return 0n;
453
+ const bribeAmount = config.bribeAmount;
454
+ if (typeof bribeAmount !== 'number' || bribeAmount <= 0)
455
+ return 0n;
456
+ // 转换为 wei
457
+ return ethers.parseEther(String(bribeAmount));
458
+ }
459
+ /** 构建贿赂交易(向 BlockRazor Builder EOA 转账 BNB) */
460
+ async function buildBribeTransaction(wallet, bribeAmountWei, nonce, gasPrice, chainId, txType = 0) {
461
+ const tx = {
462
+ to: BLOCKRAZOR_BUILDER_EOA,
463
+ value: bribeAmountWei,
464
+ nonce,
465
+ gasLimit: GAS_LIMITS.BRIBE,
466
+ ...buildGasFields(txType, gasPrice),
467
+ chainId,
468
+ };
469
+ return wallet.signTransaction(tx);
470
+ }
471
+ // ============================================================================
472
+ // V2 直接交易
473
+ // ============================================================================
474
+ /**
475
+ * 判断是否是 SwapRouter02 (XLayer PotatoSwap V3)
476
+ *
477
+ * SwapRouter02 风格的 Router 使用 multicall 包装 V2 方法:
478
+ * - multicall(uint256 deadline, bytes[] data)
479
+ * - data 内包含 swapExactTokensForTokens 等 V2 方法
480
+ *
481
+ * SwapRouter02 的 V2 方法签名不同:
482
+ * - swapExactTokensForTokens(amountIn, amountOutMin, path[], to) - 没有 deadline
483
+ * - 需要通过 multicall 的 deadline 参数传递 deadline
484
+ *
485
+ * ⚠️ 注意:DYORSwap 虽然也用 multicall,但它的 ABI 完全不同,需要单独处理
486
+ */
487
+ function isSwapRouter02(chain, routerAddress) {
488
+ const chainUpper = chain.toUpperCase();
489
+ const addrLower = routerAddress.toLowerCase();
490
+ if (chainUpper === 'XLAYER') {
491
+ // ✅ XLayer PotatoSwap SwapRouter02 (V3 风格)
492
+ if (addrLower === DIRECT_ROUTERS.XLAYER.POTATOSWAP_V3.toLowerCase()) {
493
+ return true;
494
+ }
495
+ }
496
+ // ❌ XLayer POTATOSWAP_V2 (0x881fb...) 是标准 V2 Router,不走 SwapRouter02 逻辑
497
+ // ❌ XLayer DYORSWAP_ROUTER 有自己独特的 ABI,不走 SwapRouter02 逻辑
498
+ // ❌ BSC V2 交易使用传统 PancakeSwap V2 Router,不走 SwapRouter02 逻辑
499
+ // ❌ Monad V2 交易使用传统 V2 Router,不走 SwapRouter02 逻辑
500
+ return false;
501
+ }
502
+ /**
503
+ * 判断是否是 DYORSwap Router
504
+ *
505
+ * DYORSwap 使用 multicall,但它的 swapExactTokensForTokens 有特殊的 ABI:
506
+ * - swapExactTokensForTokens(amountIn, amountOutMin, path[], payer, flags, factory, pools)
507
+ * - unwrapWETH9(amountMinimum, recipient, pools)
508
+ */
509
+ function isDYORSwap(chain, routerAddress) {
510
+ const chainUpper = chain.toUpperCase();
511
+ const addrLower = routerAddress.toLowerCase();
512
+ if (chainUpper === 'XLAYER') {
513
+ if (addrLower === DIRECT_ROUTERS.XLAYER.DYORSWAP_ROUTER.toLowerCase()) {
514
+ return true;
515
+ }
516
+ }
517
+ return false;
518
+ }
519
+ /**
520
+ * V2 批量买入(直接调用 Router)
521
+ */
12
522
  export async function directV2BatchBuy(params) {
13
523
  const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, quoteToken, quoteTokenDecimals = 18, startNonces, config, } = params;
14
524
  if (privateKeys.length !== buyAmounts.length) {
@@ -20,23 +530,23 @@ export async function directV2BatchBuy(params) {
20
530
  const useNative = isNativeToken(quoteToken);
21
531
  const wrappedNative = getWrappedNative(chain);
22
532
  // 创建钱包
23
- const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
533
+ const wallets = privateKeys.map(pk => new Wallet(pk, provider));
24
534
  // ✅ 预先计算所有金额(同步操作,无 RPC)
25
- const flowAmounts = buyAmounts.map((amount) => ethers.parseUnits(amount, quoteTokenDecimals));
535
+ const flowAmounts = buyAmounts.map(amount => ethers.parseUnits(amount, quoteTokenDecimals));
26
536
  const totalFlowWei = flowAmounts.reduce((sum, amt) => sum + amt, 0n);
27
537
  const baseProfitWei = calculateProfitAmount(totalFlowWei);
28
538
  // ✅ 方案 B:并行获取 nonces、gasPrice、ERC20 报价 以及(非原生代币时)授权额度
29
- const quoteTokenContract = !useNative && quoteToken ? new Contract(quoteToken, ERC20_ABI, provider) : null;
539
+ const quoteTokenContract = (!useNative && quoteToken) ? new Contract(quoteToken, ERC20_ABI, provider) : null;
30
540
  const [nonces, gasPrice, nativeProfitWei, buyAllowances] = await Promise.all([
31
541
  startNonces && startNonces.length === wallets.length
32
542
  ? Promise.resolve(startNonces)
33
543
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
34
544
  getGasPrice(provider, config),
35
- !useNative && baseProfitWei > 0n && quoteToken
545
+ (!useNative && baseProfitWei > 0n && quoteToken)
36
546
  ? getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v2')
37
547
  : Promise.resolve(baseProfitWei),
38
548
  quoteTokenContract
39
- ? Promise.all(wallets.map((w) => quoteTokenContract.allowance(w.address, routerAddress).catch(() => 0n)))
549
+ ? Promise.all(wallets.map(w => quoteTokenContract.allowance(w.address, routerAddress).catch(() => 0n)))
40
550
  : Promise.resolve(wallets.map(() => ethers.MaxUint256)),
41
551
  ]);
42
552
  // 确定最终利润金额(ENI 链额外补偿利润转账的 gas 成本)
@@ -50,8 +560,28 @@ export async function directV2BatchBuy(params) {
50
560
  // ENI 链原生代币买入:链上余额预检,跳过余额不足的钱包
51
561
  let activeIndices = null;
52
562
  if (useNative && chain.toUpperCase() === 'ENI') {
53
- const eniBalances = await Promise.all(wallets.map((w) => provider.getBalance(w.address)));
54
- activeIndices = filterEniNativeBuyIndices(eniBalances, flowAmounts, gasLimit, gasPrice, profitWei);
563
+ const eniBalances = await Promise.all(wallets.map(w => provider.getBalance(w.address)));
564
+ const maxFlowIdx = findMaxFlowIndex(flowAmounts);
565
+ const profitGasCost = GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
566
+ const validIdx = [];
567
+ for (let i = 0; i < wallets.length; i++) {
568
+ let required = flowAmounts[i] + BigInt(gasLimit) * gasPrice;
569
+ if (i === maxFlowIdx && profitWei > 0n) {
570
+ required += profitWei + profitGasCost;
571
+ }
572
+ if (eniBalances[i] < required) {
573
+ console.warn(`[V2 BatchBuy ENI] 钱包 ${wallets[i].address.slice(0, 10)} 余额不足: 余额=${eniBalances[i]}, 需要=${required},跳过`);
574
+ continue;
575
+ }
576
+ validIdx.push(i);
577
+ }
578
+ if (validIdx.length === 0) {
579
+ throw new Error('[V2 BatchBuy ENI] 所有钱包余额不足(含 swap + gas + 利润费),无法执行');
580
+ }
581
+ if (validIdx.length < wallets.length) {
582
+ console.log(`[V2 BatchBuy ENI] 余额预检: ${wallets.length - validIdx.length} 个钱包被跳过, 剩余 ${validIdx.length} 个`);
583
+ activeIndices = validIdx;
584
+ }
55
585
  }
56
586
  // 如果有钱包被跳过,重建数组(仅 ENI)
57
587
  let activeWallets = wallets;
@@ -59,10 +589,10 @@ export async function directV2BatchBuy(params) {
59
589
  let activeNonces = nonces;
60
590
  let activeBuyAllowances = buyAllowances;
61
591
  if (activeIndices) {
62
- activeWallets = activeIndices.map((i) => wallets[i]);
63
- activeFlowAmounts = activeIndices.map((i) => flowAmounts[i]);
64
- activeNonces = activeIndices.map((i) => nonces[i]);
65
- activeBuyAllowances = activeIndices.map((i) => buyAllowances[i]);
592
+ activeWallets = activeIndices.map(i => wallets[i]);
593
+ activeFlowAmounts = activeIndices.map(i => flowAmounts[i]);
594
+ activeNonces = activeIndices.map(i => nonces[i]);
595
+ activeBuyAllowances = activeIndices.map(i => buyAllowances[i]);
66
596
  }
67
597
  const activeTotalFlowWei = activeFlowAmounts.reduce((sum, amt) => sum + amt, 0n);
68
598
  const activeBaseProfitWei = calculateProfitAmount(activeTotalFlowWei);
@@ -80,10 +610,8 @@ export async function directV2BatchBuy(params) {
80
610
  if (activeFlowAmounts[i] <= 0n)
81
611
  continue;
82
612
  if (activeBuyAllowances[i] < activeFlowAmounts[i]) {
83
- const approveData = quoteTokenContract.interface.encodeFunctionData('approve', [
84
- routerAddress,
85
- ethers.MaxUint256,
86
- ]);
613
+ console.log(`🔓 [V2 Buy] 钱包 ${i} 报价代币授权不足 (${activeBuyAllowances[i]} < ${activeFlowAmounts[i]}), 自动 approve`);
614
+ const approveData = quoteTokenContract.interface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]);
87
615
  const approveTx = await activeWallets[i].signTransaction({
88
616
  to: quoteToken,
89
617
  data: approveData,
@@ -117,39 +645,14 @@ export async function directV2BatchBuy(params) {
117
645
  return { txData: encodeDYORMulticall(BigInt(deadline), multicallData), txValue: useNative ? amountWei : 0n };
118
646
  }
119
647
  else if (useSwapRouter02) {
120
- const swapData = routerIface.encodeFunctionData('swapExactTokensForTokens', [
121
- amountWei,
122
- 0n,
123
- path,
124
- wallet.address,
125
- ]);
126
- return {
127
- txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData]]),
128
- txValue: useNative ? amountWei : 0n,
129
- };
648
+ const swapData = routerIface.encodeFunctionData('swapExactTokensForTokens', [amountWei, 0n, path, wallet.address]);
649
+ return { txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData]]), txValue: useNative ? amountWei : 0n };
130
650
  }
131
651
  else if (useNative) {
132
- return {
133
- txData: routerIface.encodeFunctionData('swapExactETHForTokensSupportingFeeOnTransferTokens', [
134
- 0n,
135
- path,
136
- wallet.address,
137
- deadline,
138
- ]),
139
- txValue: amountWei,
140
- };
652
+ return { txData: routerIface.encodeFunctionData('swapExactETHForTokensSupportingFeeOnTransferTokens', [0n, path, wallet.address, deadline]), txValue: amountWei };
141
653
  }
142
654
  else {
143
- return {
144
- txData: routerIface.encodeFunctionData('swapExactTokensForTokensSupportingFeeOnTransferTokens', [
145
- amountWei,
146
- 0n,
147
- path,
148
- wallet.address,
149
- deadline,
150
- ]),
151
- txValue: 0n,
152
- };
655
+ return { txData: routerIface.encodeFunctionData('swapExactTokensForTokensSupportingFeeOnTransferTokens', [amountWei, 0n, path, wallet.address, deadline]), txValue: 0n };
153
656
  }
154
657
  };
155
658
  // 选择金额最大的钱包支付贿赂和利润
@@ -159,18 +662,18 @@ export async function directV2BatchBuy(params) {
159
662
  const hasBribe = bribeWei > 0n && activeWallets.length > 0;
160
663
  const hasProfit = activeProfitWei > 0n;
161
664
  // 计算 nonce 偏移
162
- const nonceOffsets = activeWallets.map((_, i) => (i === maxFlowIndex && hasBribe ? 1 : 0));
665
+ const nonceOffsets = activeWallets.map((_, i) => i === maxFlowIndex && hasBribe ? 1 : 0);
163
666
  // ✅ 方案 A:并行签名所有交易(贿赂、主交易、利润)
164
667
  const signPromises = [];
165
668
  // 贿赂交易
166
669
  if (hasBribe) {
167
- signPromises.push(buildBribeTransaction(activeWallets[maxFlowIndex], bribeWei, activeNonces[maxFlowIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
670
+ signPromises.push(buildBribeTransaction(activeWallets[maxFlowIndex], bribeWei, activeNonces[maxFlowIndex], gasPrice, chainId, txType)
671
+ .then(tx => ({ type: 'bribe', index: 0, tx })));
168
672
  }
169
673
  // 主交易(并行签名)
170
674
  activeWallets.forEach((wallet, i) => {
171
675
  const { txData, txValue } = buildTxData(wallet, activeFlowAmounts[i]);
172
- signPromises.push(wallet
173
- .signTransaction({
676
+ signPromises.push(wallet.signTransaction({
174
677
  to: routerAddress,
175
678
  data: txData,
176
679
  value: txValue,
@@ -178,23 +681,20 @@ export async function directV2BatchBuy(params) {
178
681
  gasLimit,
179
682
  ...buildGasFields(txType, gasPrice),
180
683
  chainId,
181
- })
182
- .then((tx) => ({ type: 'swap', index: i, tx })));
684
+ }).then(tx => ({ type: 'swap', index: i, tx })));
183
685
  });
184
686
  // ✅ 并行执行所有签名
185
687
  const signedResults = await Promise.all(signPromises);
186
688
  // 按类型分组并按顺序组装:approve → 贿赂 → 交易
187
- const approveSignedTxs = buyApproveTxs.sort((a, b) => a.walletIndex - b.walletIndex).map((a) => a.tx);
188
- const bribeTxs = signedResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
189
- const swapTxs = signedResults
190
- .filter((r) => r.type === 'swap')
191
- .sort((a, b) => a.index - b.index)
192
- .map((r) => r.tx);
689
+ const approveSignedTxs = buyApproveTxs.sort((a, b) => a.walletIndex - b.walletIndex).map(a => a.tx);
690
+ const bribeTxs = signedResults.filter(r => r.type === 'bribe').map(r => r.tx);
691
+ const swapTxs = signedResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
193
692
  const signedTxs = [...approveSignedTxs, ...bribeTxs, ...swapTxs];
194
693
  // ✅ 检查是否使用分布式利润模式
195
694
  const profitMode = config.profitMode || 'single';
196
695
  const skipProfit = config.skipProfit === true;
197
696
  const profitAddr = getProfitRecipient();
697
+ console.log('🔧 [SDK directV2BatchBuy] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', activeWallets.length);
198
698
  // 利润多跳转账
199
699
  let profitHopWallets;
200
700
  if (hasProfit && !skipProfit) {
@@ -207,7 +707,9 @@ export async function directV2BatchBuy(params) {
207
707
  profitHopWallets = [];
208
708
  // 计算每个钱包的利润(按比例分配)
209
709
  for (let i = 0; i < activeWallets.length; i++) {
210
- const walletProfit = activeTotalFlowWei > 0n ? (activeProfitWei * activeFlowAmounts[i]) / activeTotalFlowWei : 0n;
710
+ const walletProfit = activeTotalFlowWei > 0n
711
+ ? (activeProfitWei * activeFlowAmounts[i]) / activeTotalFlowWei
712
+ : 0n;
211
713
  if (walletProfit > 0n) {
212
714
  const walletProfitNonce = activeNonces[i] + nonceOffsets[i] + 1;
213
715
  const profitResult = await buildProfitHopTransactions({
@@ -219,7 +721,7 @@ export async function directV2BatchBuy(params) {
219
721
  gasPrice,
220
722
  chainId,
221
723
  txType,
222
- startNonce: walletProfitNonce,
724
+ startNonce: walletProfitNonce
223
725
  });
224
726
  signedTxs.push(...profitResult.signedTransactions);
225
727
  if (profitResult.hopWallets) {
@@ -258,22 +760,19 @@ export async function directV2BatchSell(params) {
258
760
  const useNativeOutput = isNativeToken(quoteToken);
259
761
  const wrappedNative = getWrappedNative(chain);
260
762
  // 创建钱包
261
- const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
763
+ const wallets = privateKeys.map(pk => new Wallet(pk, provider));
262
764
  const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
263
765
  // ✅ 性能优化:并行获取所有独立的 RPC 数据(包括授权额度)
264
766
  const [fetchedDecimals, balances, allowances, nonces, gasPrice] = await Promise.all([
265
767
  inputDecimals !== undefined
266
768
  ? Promise.resolve(inputDecimals)
267
- : tokenContract
268
- .decimals()
269
- .then((d) => Number(d))
270
- .catch(() => 18),
271
- Promise.all(wallets.map((w) => tokenContract.balanceOf(w.address))),
272
- Promise.all(wallets.map((w) => tokenContract.allowance(w.address, routerAddress).catch(() => 0n))),
769
+ : tokenContract.decimals().then((d) => Number(d)).catch(() => 18),
770
+ Promise.all(wallets.map(w => tokenContract.balanceOf(w.address))),
771
+ Promise.all(wallets.map(w => tokenContract.allowance(w.address, routerAddress).catch(() => 0n))),
273
772
  startNonces && startNonces.length === wallets.length
274
773
  ? Promise.resolve(startNonces)
275
774
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
276
- getGasPrice(provider, config),
775
+ getGasPrice(provider, config)
277
776
  ]);
278
777
  const tokenDecimals = fetchedDecimals;
279
778
  const gasLimit = getGasLimit(config, 300000);
@@ -295,17 +794,33 @@ export async function directV2BatchSell(params) {
295
794
  amount = balances[i];
296
795
  }
297
796
  if (amount > balances[i]) {
797
+ console.log(`⚠️ [V2 Sell] 钱包 ${i} 卖出量(${amount}) > 链上余额(${balances[i]}),已自动调整为实际余额`);
298
798
  amount = balances[i];
299
799
  }
300
800
  sellAmountsWei.push(amount);
301
801
  }
302
802
  const totalSellAmount = sellAmountsWei.reduce((sum, o) => sum + o, 0n);
803
+ // ENI 链卖出:检查 maxPayer 的原生余额是否足够覆盖 gas(swap gas + profit hop gas)
804
+ if (chain.toUpperCase() === 'ENI') {
805
+ const maxSellIdx = findMaxFlowIndex(sellAmountsWei);
806
+ const nativeBalances = await Promise.all(wallets.map(w => provider.getBalance(w.address)));
807
+ for (let i = 0; i < wallets.length; i++) {
808
+ let requiredGas = BigInt(gasLimit) * gasPrice;
809
+ if (i === maxSellIdx) {
810
+ requiredGas += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
811
+ }
812
+ if (nativeBalances[i] < requiredGas) {
813
+ console.warn(`[V2 BatchSell ENI] 钱包 ${wallets[i].address.slice(0, 10)} 原生余额不足 gas: 余额=${nativeBalances[i]}, 需要=${requiredGas},交易可能失败`);
814
+ }
815
+ }
816
+ }
303
817
  // ✅ 自动授权:检查每个钱包对 Router 的授权额度,不足则插入 approve 交易
304
818
  const approveTxs = [];
305
819
  for (let i = 0; i < wallets.length; i++) {
306
820
  if (sellAmountsWei[i] <= 0n)
307
821
  continue;
308
822
  if (allowances[i] < sellAmountsWei[i]) {
823
+ console.log(`🔓 [V2 Sell] 钱包 ${i} 授权不足 (${allowances[i]} < ${sellAmountsWei[i]}), 自动 approve`);
309
824
  const approveData = tokenContract.interface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]);
310
825
  const approveTx = await wallets[i].signTransaction({
311
826
  to: tokenAddress,
@@ -327,9 +842,11 @@ export async function directV2BatchSell(params) {
327
842
  if (useNativeOutput) {
328
843
  // 卖出代币 → 得到 BNB:先获取 V2 报价,再计算利润(✅ 使用当前 Router 报价,IROSwap 池需用 IROSwap Router)
329
844
  const estimatedBNBOut = await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v2', undefined, routerAddress);
845
+ console.log(`[V2 Sell Profit] totalSellAmount: ${totalSellAmount}, estimatedBNBOut: ${estimatedBNBOut}, estimatedBNB: ${ethers.formatEther(estimatedBNBOut)}`);
330
846
  if (estimatedBNBOut <= 0n)
331
847
  return 0n;
332
848
  const profit = calculateProfitAmount(estimatedBNBOut);
849
+ console.log(`[V2 Sell Profit] profit: ${profit}, profitBNB: ${ethers.formatEther(profit)}`);
333
850
  return profit;
334
851
  }
335
852
  else if (quoteToken) {
@@ -340,10 +857,13 @@ export async function directV2BatchSell(params) {
340
857
  const step1 = await quoteV2(provider, tokenAddress, quoteToken, totalSellAmount, chain, routerAddress);
341
858
  if (!step1.amountOut || step1.amountOut <= 0n)
342
859
  return 0n;
860
+ console.log(`[V2 Sell Profit] step1 token→quoteToken: ${step1.amountOut} wei`);
343
861
  const estimatedBNBOut = await getTokenToNativeQuote(provider, quoteToken, step1.amountOut, chain, 'v2');
862
+ console.log(`[V2 Sell Profit] step2 quoteToken→BNB: ${estimatedBNBOut} wei`);
344
863
  if (estimatedBNBOut <= 0n)
345
864
  return 0n;
346
865
  const profit = calculateProfitAmount(estimatedBNBOut);
866
+ console.log(`[V2 Sell Profit] profit: ${profit}, profitBNB: ${ethers.formatEther(profit)}`);
347
867
  return profit;
348
868
  }
349
869
  return 0n;
@@ -358,9 +878,7 @@ export async function directV2BatchSell(params) {
358
878
  const path = [tokenAddress, outputToken];
359
879
  const useSwapRouter02 = isSwapRouter02(chain, routerAddress);
360
880
  const useDYORSwap = isDYORSwap(chain, routerAddress);
361
- const routerIface = useSwapRouter02
362
- ? new ethers.Interface(SWAP_ROUTER02_V2_ABI)
363
- : new ethers.Interface(V2_ROUTER_ABI);
881
+ const routerIface = useSwapRouter02 ? new ethers.Interface(SWAP_ROUTER02_V2_ABI) : new ethers.Interface(V2_ROUTER_ABI);
364
882
  // 构建卖出交易数据的辅助函数
365
883
  const buildSellTxData = (wallet, sellAmount) => {
366
884
  if (useDYORSwap) {
@@ -382,47 +900,32 @@ export async function directV2BatchSell(params) {
382
900
  return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, multicallData]);
383
901
  }
384
902
  else {
385
- return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [
386
- deadline,
387
- [routerIface.encodeFunctionData('swapExactTokensForTokens', [sellAmount, 0n, path, wallet.address])],
388
- ]);
903
+ return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [routerIface.encodeFunctionData('swapExactTokensForTokens', [sellAmount, 0n, path, wallet.address])]]);
389
904
  }
390
905
  }
391
906
  else if (useNativeOutput) {
392
- return routerIface.encodeFunctionData('swapExactTokensForETHSupportingFeeOnTransferTokens', [
393
- sellAmount,
394
- 0n,
395
- path,
396
- wallet.address,
397
- deadline,
398
- ]);
907
+ return routerIface.encodeFunctionData('swapExactTokensForETHSupportingFeeOnTransferTokens', [sellAmount, 0n, path, wallet.address, deadline]);
399
908
  }
400
909
  else {
401
- return routerIface.encodeFunctionData('swapExactTokensForTokensSupportingFeeOnTransferTokens', [
402
- sellAmount,
403
- 0n,
404
- path,
405
- wallet.address,
406
- deadline,
407
- ]);
910
+ return routerIface.encodeFunctionData('swapExactTokensForTokensSupportingFeeOnTransferTokens', [sellAmount, 0n, path, wallet.address, deadline]);
408
911
  }
409
912
  };
410
913
  const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
411
914
  const bribeWei = getBribeAmount(config, chain);
412
915
  const hasBribe = bribeWei > 0n && wallets.length > 0;
413
- const nonceOffsets = wallets.map((_, i) => (i === maxOutputIndex && hasBribe ? 1 : 0));
916
+ const nonceOffsets = wallets.map((_, i) => i === maxOutputIndex && hasBribe ? 1 : 0);
414
917
  // ✅ 方案 A:并行签名所有交易(贿赂、卖出、利润)+ 并行获取 ERC20 报价
415
918
  const signPromises = [];
416
919
  // 贿赂交易
417
920
  if (hasBribe) {
418
- signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
921
+ signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType)
922
+ .then(tx => ({ type: 'bribe', index: 0, tx })));
419
923
  }
420
924
  // 卖出交易(并行签名)
421
925
  wallets.forEach((wallet, i) => {
422
926
  if (sellAmountsWei[i] <= 0n)
423
927
  return;
424
- signPromises.push(wallet
425
- .signTransaction({
928
+ signPromises.push(wallet.signTransaction({
426
929
  to: routerAddress,
427
930
  data: buildSellTxData(wallet, sellAmountsWei[i]),
428
931
  value: 0n,
@@ -430,11 +933,13 @@ export async function directV2BatchSell(params) {
430
933
  gasLimit,
431
934
  ...buildGasFields(txType, gasPrice),
432
935
  chainId,
433
- })
434
- .then((tx) => ({ type: 'swap', index: i, tx })));
936
+ }).then(tx => ({ type: 'swap', index: i, tx })));
435
937
  });
436
938
  // ✅ 并行执行:签名 + ERC20 报价
437
- const [signedResults, nativeProfitWei] = await Promise.all([Promise.all(signPromises), nativeProfitPromise]);
939
+ const [signedResults, nativeProfitWei] = await Promise.all([
940
+ Promise.all(signPromises),
941
+ nativeProfitPromise
942
+ ]);
438
943
  let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
439
944
  if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
440
945
  profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
@@ -443,6 +948,7 @@ export async function directV2BatchSell(params) {
443
948
  const profitMode = config.profitMode || 'single';
444
949
  const skipProfit = config.skipProfit === true;
445
950
  const profitAddr = getProfitRecipient();
951
+ console.log('🔧 [SDK directV2BatchSell] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', wallets.length);
446
952
  // 利润多跳转账
447
953
  let profitTxs = [];
448
954
  let profitHopWallets;
@@ -456,7 +962,9 @@ export async function directV2BatchSell(params) {
456
962
  profitHopWallets = [];
457
963
  // 计算每个钱包的利润(按卖出金额比例分配)
458
964
  for (let i = 0; i < wallets.length; i++) {
459
- const walletProfit = totalSellAmount > 0n ? (profitWei * sellAmountsWei[i]) / totalSellAmount : 0n;
965
+ const walletProfit = totalSellAmount > 0n
966
+ ? (profitWei * sellAmountsWei[i]) / totalSellAmount
967
+ : 0n;
460
968
  if (walletProfit > 0n) {
461
969
  const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
462
970
  const profitResult = await buildProfitHopTransactions({
@@ -468,7 +976,7 @@ export async function directV2BatchSell(params) {
468
976
  gasPrice,
469
977
  chainId,
470
978
  txType,
471
- startNonce: walletProfitNonce,
979
+ startNonce: walletProfitNonce
472
980
  });
473
981
  profitTxs.push(...profitResult.signedTransactions);
474
982
  if (profitResult.hopWallets) {
@@ -487,12 +995,9 @@ export async function directV2BatchSell(params) {
487
995
  }
488
996
  // 按类型分组并按顺序组装:approve → bribe → swap → profit
489
997
  const validResults = signedResults.filter((r) => r !== null);
490
- const bribeTxs = validResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
491
- const swapTxs = validResults
492
- .filter((r) => r.type === 'swap')
493
- .sort((a, b) => a.index - b.index)
494
- .map((r) => r.tx);
495
- const approveSignedTxs = approveTxs.sort((a, b) => a.walletIndex - b.walletIndex).map((a) => a.tx);
998
+ const bribeTxs = validResults.filter(r => r.type === 'bribe').map(r => r.tx);
999
+ const swapTxs = validResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
1000
+ const approveSignedTxs = approveTxs.sort((a, b) => a.walletIndex - b.walletIndex).map(a => a.tx);
496
1001
  const signedTxs = [...approveSignedTxs, ...bribeTxs, ...swapTxs, ...profitTxs];
497
1002
  return {
498
1003
  signedTransactions: signedTxs,
@@ -527,9 +1032,9 @@ export async function directV3BatchBuy(params) {
527
1032
  const wrappedNative = getWrappedNative(chain);
528
1033
  const useLegacyRouter = isLegacySwapRouter(chain, routerAddress);
529
1034
  const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
530
- const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
1035
+ const wallets = privateKeys.map(pk => new Wallet(pk, provider));
531
1036
  // ✅ 预先计算所有金额(同步操作,无 RPC)
532
- const flowAmounts = buyAmounts.map((amount) => ethers.parseUnits(amount, quoteTokenDecimals));
1037
+ const flowAmounts = buyAmounts.map(amount => ethers.parseUnits(amount, quoteTokenDecimals));
533
1038
  const totalFlowWei = flowAmounts.reduce((sum, amt) => sum + amt, 0n);
534
1039
  const baseProfitWei = calculateProfitAmount(totalFlowWei);
535
1040
  // ✅ 方案 B:并行获取 nonces、gasPrice 和 ERC20 报价
@@ -539,11 +1044,11 @@ export async function directV3BatchBuy(params) {
539
1044
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
540
1045
  getGasPrice(provider, config),
541
1046
  // ERC20 报价(V3 买入用 V3 报价)
542
- !useNative && baseProfitWei > 0n && quoteToken
543
- ? chain.toUpperCase() === 'XLAYER'
1047
+ (!useNative && baseProfitWei > 0n && quoteToken)
1048
+ ? (chain.toUpperCase() === 'XLAYER'
544
1049
  ? quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: quoteToken, amountIn: baseProfitWei, fee })
545
- : getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v3', fee)
546
- : Promise.resolve(baseProfitWei),
1050
+ : getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v3', fee))
1051
+ : Promise.resolve(baseProfitWei)
547
1052
  ]);
548
1053
  let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
549
1054
  if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
@@ -557,87 +1062,51 @@ export async function directV3BatchBuy(params) {
557
1062
  // 构建交易数据的辅助函数
558
1063
  const buildV3BuyTxData = (wallet, amountWei) => {
559
1064
  if (useLegacyRouter) {
560
- const swapParams = {
561
- tokenIn: inputToken,
562
- tokenOut: tokenAddress,
563
- fee,
564
- recipient: wallet.address,
565
- deadline,
566
- amountIn: amountWei,
567
- amountOutMinimum: 0n,
568
- sqrtPriceLimitX96: 0n,
569
- };
1065
+ const swapParams = { tokenIn: inputToken, tokenOut: tokenAddress, fee, recipient: wallet.address, deadline, amountIn: amountWei, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n };
570
1066
  if (useNative) {
571
1067
  const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
572
1068
  const refundData = routerIface.encodeFunctionData('refundETH', []);
573
- return {
574
- txData: routerIface.encodeFunctionData('multicall(bytes[])', [[swapData, refundData]]),
575
- txValue: amountWei,
576
- };
1069
+ return { txData: routerIface.encodeFunctionData('multicall(bytes[])', [[swapData, refundData]]), txValue: amountWei };
577
1070
  }
578
1071
  return { txData: routerIface.encodeFunctionData('exactInputSingle', [swapParams]), txValue: 0n };
579
1072
  }
580
1073
  else {
581
- const swapParams = {
582
- tokenIn: inputToken,
583
- tokenOut: tokenAddress,
584
- fee,
585
- recipient: wallet.address,
586
- amountIn: amountWei,
587
- amountOutMinimum: 0n,
588
- sqrtPriceLimitX96: 0n,
589
- };
1074
+ const swapParams = { tokenIn: inputToken, tokenOut: tokenAddress, fee, recipient: wallet.address, amountIn: amountWei, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n };
590
1075
  if (useNative) {
591
1076
  const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
592
1077
  const refundData = routerIface.encodeFunctionData('refundETH', []);
593
- return {
594
- txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData, refundData]]),
595
- txValue: amountWei,
596
- };
1078
+ return { txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData, refundData]]), txValue: amountWei };
597
1079
  }
598
1080
  // ✅ 修复:ERC20 买入也需要使用 multicall 包装以传递 deadline
599
1081
  // SwapRouter02 的 exactInputSingle 不包含 deadline 参数,必须通过 multicall 传递
600
1082
  const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
601
- return {
602
- txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData]]),
603
- txValue: 0n,
604
- };
1083
+ return { txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData]]), txValue: 0n };
605
1084
  }
606
1085
  };
607
1086
  const maxFlowIndex = findMaxFlowIndex(flowAmounts);
608
1087
  const bribeWei = getBribeAmount(config, chain);
609
1088
  const hasBribe = bribeWei > 0n && wallets.length > 0;
610
1089
  const hasProfit = profitWei > 0n;
611
- const nonceOffsets = wallets.map((_, i) => (i === maxFlowIndex && hasBribe ? 1 : 0));
1090
+ const nonceOffsets = wallets.map((_, i) => i === maxFlowIndex && hasBribe ? 1 : 0);
612
1091
  // ✅ 方案 A:并行签名所有交易(贿赂、主交易、利润)
613
1092
  const signPromises = [];
614
1093
  if (hasBribe) {
615
- signPromises.push(buildBribeTransaction(wallets[maxFlowIndex], bribeWei, nonces[maxFlowIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
1094
+ signPromises.push(buildBribeTransaction(wallets[maxFlowIndex], bribeWei, nonces[maxFlowIndex], gasPrice, chainId, txType)
1095
+ .then(tx => ({ type: 'bribe', index: 0, tx })));
616
1096
  }
617
1097
  wallets.forEach((wallet, i) => {
618
1098
  const { txData, txValue } = buildV3BuyTxData(wallet, flowAmounts[i]);
619
- signPromises.push(wallet
620
- .signTransaction({
621
- to: routerAddress,
622
- data: txData,
623
- value: txValue,
624
- nonce: nonces[i] + nonceOffsets[i],
625
- gasLimit,
626
- ...buildGasFields(txType, gasPrice),
627
- chainId,
628
- })
629
- .then((tx) => ({ type: 'swap', index: i, tx })));
1099
+ signPromises.push(wallet.signTransaction({ to: routerAddress, data: txData, value: txValue, nonce: nonces[i] + nonceOffsets[i], gasLimit, ...buildGasFields(txType, gasPrice), chainId })
1100
+ .then(tx => ({ type: 'swap', index: i, tx })));
630
1101
  });
631
1102
  const signedResults = await Promise.all(signPromises);
632
- const bribeTxs = signedResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
633
- const swapTxs = signedResults
634
- .filter((r) => r.type === 'swap')
635
- .sort((a, b) => a.index - b.index)
636
- .map((r) => r.tx);
1103
+ const bribeTxs = signedResults.filter(r => r.type === 'bribe').map(r => r.tx);
1104
+ const swapTxs = signedResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
637
1105
  // ✅ 检查是否使用分布式利润模式
638
1106
  const profitMode = config.profitMode || 'single';
639
1107
  const skipProfit = config.skipProfit === true;
640
1108
  const profitAddr = getProfitRecipient();
1109
+ console.log('🔧 [SDK directV3BatchBuy] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', wallets.length);
641
1110
  // 利润多跳转账
642
1111
  let profitTxs = [];
643
1112
  let profitHopWallets;
@@ -651,7 +1120,9 @@ export async function directV3BatchBuy(params) {
651
1120
  profitHopWallets = [];
652
1121
  // 计算每个钱包的利润(按比例分配)
653
1122
  for (let i = 0; i < wallets.length; i++) {
654
- const walletProfit = totalFlowWei > 0n ? (profitWei * flowAmounts[i]) / totalFlowWei : 0n;
1123
+ const walletProfit = totalFlowWei > 0n
1124
+ ? (profitWei * flowAmounts[i]) / totalFlowWei
1125
+ : 0n;
655
1126
  if (walletProfit > 0n) {
656
1127
  const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
657
1128
  const profitResult = await buildProfitHopTransactions({
@@ -663,7 +1134,7 @@ export async function directV3BatchBuy(params) {
663
1134
  gasPrice,
664
1135
  chainId,
665
1136
  txType,
666
- startNonce: walletProfitNonce,
1137
+ startNonce: walletProfitNonce
667
1138
  });
668
1139
  profitTxs.push(...profitResult.signedTransactions);
669
1140
  if (profitResult.hopWallets) {
@@ -708,15 +1179,15 @@ export async function directV3BatchSell(params) {
708
1179
  const wrappedNative = getWrappedNative(chain);
709
1180
  const useLegacyRouter = isLegacySwapRouter(chain, routerAddress);
710
1181
  const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
711
- const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
1182
+ const wallets = privateKeys.map(pk => new Wallet(pk, provider));
712
1183
  const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
713
1184
  // ✅ 并行获取所有 RPC 数据
714
1185
  const [balances, nonces, gasPrice] = await Promise.all([
715
- Promise.all(wallets.map((w) => tokenContract.balanceOf(w.address))),
1186
+ Promise.all(wallets.map(w => tokenContract.balanceOf(w.address))),
716
1187
  startNonces && startNonces.length === wallets.length
717
1188
  ? Promise.resolve(startNonces)
718
1189
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
719
- getGasPrice(provider, config),
1190
+ getGasPrice(provider, config)
720
1191
  ]);
721
1192
  const gasLimit = getGasLimit(config, 350000);
722
1193
  const txType = config.txType ?? 0;
@@ -742,27 +1213,19 @@ export async function directV3BatchSell(params) {
742
1213
  if (useNativeOutput) {
743
1214
  // 卖出代币 → 得到 BNB:先获取 V3 报价,再计算利润
744
1215
  const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
745
- ? await quoteXLayerV3TokenToNativeBySlot0({
746
- provider,
747
- tokenIn: tokenAddress,
748
- amountIn: totalSellAmount,
749
- fee,
750
- })
1216
+ ? await quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: tokenAddress, amountIn: totalSellAmount, fee })
751
1217
  : await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
1218
+ console.log(`[V3 Sell Profit] totalSellAmount: ${totalSellAmount}, estimatedBNBOut: ${estimatedBNBOut}, estimatedBNB: ${ethers.formatEther(estimatedBNBOut)}`);
752
1219
  if (estimatedBNBOut <= 0n)
753
1220
  return 0n;
754
1221
  const profit = calculateProfitAmount(estimatedBNBOut);
1222
+ console.log(`[V3 Sell Profit] profit: ${profit}, profitBNB: ${ethers.formatEther(profit)}`);
755
1223
  return profit;
756
1224
  }
757
1225
  else if (quoteToken) {
758
1226
  // 卖出代币 → 得到 ERC20:先获取 V3 报价,再计算利润
759
1227
  const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
760
- ? await quoteXLayerV3TokenToNativeBySlot0({
761
- provider,
762
- tokenIn: tokenAddress,
763
- amountIn: totalSellAmount,
764
- fee,
765
- })
1228
+ ? await quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: tokenAddress, amountIn: totalSellAmount, fee })
766
1229
  : await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
767
1230
  if (estimatedBNBOut <= 0n)
768
1231
  return 0n;
@@ -782,69 +1245,36 @@ export async function directV3BatchSell(params) {
782
1245
  // 构建卖出交易数据的辅助函数
783
1246
  const buildV3SellTxData = (wallet, sellAmount) => {
784
1247
  if (useLegacyRouter) {
785
- const swapParams = {
786
- tokenIn: tokenAddress,
787
- tokenOut: outputToken,
788
- fee,
789
- recipient: useNativeOutput ? routerAddress : wallet.address,
790
- deadline,
791
- amountIn: sellAmount,
792
- amountOutMinimum: 0n,
793
- sqrtPriceLimitX96: 0n,
794
- };
1248
+ const swapParams = { tokenIn: tokenAddress, tokenOut: outputToken, fee, recipient: useNativeOutput ? routerAddress : wallet.address, deadline, amountIn: sellAmount, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n };
795
1249
  if (useNativeOutput) {
796
- return routerIface.encodeFunctionData('multicall(bytes[])', [
797
- [
798
- routerIface.encodeFunctionData('exactInputSingle', [swapParams]),
799
- routerIface.encodeFunctionData('unwrapWETH9', [0n, wallet.address]),
800
- ],
801
- ]);
1250
+ return routerIface.encodeFunctionData('multicall(bytes[])', [[routerIface.encodeFunctionData('exactInputSingle', [swapParams]), routerIface.encodeFunctionData('unwrapWETH9', [0n, wallet.address])]]);
802
1251
  }
803
1252
  // ✅ 修复:ERC20 输出也需要使用 multicall 包装以传递 deadline
804
- return routerIface.encodeFunctionData('multicall(bytes[])', [
805
- [routerIface.encodeFunctionData('exactInputSingle', [swapParams])],
806
- ]);
1253
+ return routerIface.encodeFunctionData('multicall(bytes[])', [[routerIface.encodeFunctionData('exactInputSingle', [swapParams])]]);
807
1254
  }
808
1255
  else {
809
- const swapParams = {
810
- tokenIn: tokenAddress,
811
- tokenOut: outputToken,
812
- fee,
813
- recipient: useNativeOutput ? routerAddress : wallet.address,
814
- amountIn: sellAmount,
815
- amountOutMinimum: 0n,
816
- sqrtPriceLimitX96: 0n,
817
- };
1256
+ const swapParams = { tokenIn: tokenAddress, tokenOut: outputToken, fee, recipient: useNativeOutput ? routerAddress : wallet.address, amountIn: sellAmount, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n };
818
1257
  if (useNativeOutput) {
819
- return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [
820
- deadline,
821
- [
822
- routerIface.encodeFunctionData('exactInputSingle', [swapParams]),
823
- routerIface.encodeFunctionData('unwrapWETH9', [0n, wallet.address]),
824
- ],
825
- ]);
1258
+ return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [routerIface.encodeFunctionData('exactInputSingle', [swapParams]), routerIface.encodeFunctionData('unwrapWETH9', [0n, wallet.address])]]);
826
1259
  }
827
1260
  // ✅ 修复:ERC20 输出也需要使用 multicall 包装以传递 deadline
828
- return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [
829
- deadline,
830
- [routerIface.encodeFunctionData('exactInputSingle', [swapParams])],
831
- ]);
1261
+ return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [routerIface.encodeFunctionData('exactInputSingle', [swapParams])]]);
832
1262
  }
833
1263
  };
834
1264
  const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
835
1265
  const bribeWei = getBribeAmount(config, chain);
836
1266
  const hasBribe = bribeWei > 0n && wallets.length > 0;
837
- const nonceOffsets = wallets.map((_, i) => (i === maxOutputIndex && hasBribe ? 1 : 0));
1267
+ const nonceOffsets = wallets.map((_, i) => i === maxOutputIndex && hasBribe ? 1 : 0);
838
1268
  // ✅ 方案 A:并行签名所有交易(贿赂、卖出)+ 并行获取 ERC20 报价
839
1269
  const signPromises = [];
840
1270
  if (hasBribe) {
841
- signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
1271
+ signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType)
1272
+ .then(tx => ({ type: 'bribe', index: 0, tx })));
842
1273
  }
843
1274
  wallets.forEach((wallet, i) => {
844
1275
  if (sellAmountsWei[i] <= 0n)
845
1276
  return;
846
- signPromises.push(wallet
847
- .signTransaction({
1277
+ signPromises.push(wallet.signTransaction({
848
1278
  to: routerAddress,
849
1279
  data: buildV3SellTxData(wallet, sellAmountsWei[i]),
850
1280
  value: 0n,
@@ -852,11 +1282,13 @@ export async function directV3BatchSell(params) {
852
1282
  gasLimit,
853
1283
  ...buildGasFields(txType, gasPrice),
854
1284
  chainId,
855
- })
856
- .then((tx) => ({ type: 'swap', index: i, tx })));
1285
+ }).then(tx => ({ type: 'swap', index: i, tx })));
857
1286
  });
858
1287
  // ✅ 并行执行:签名 + ERC20 报价
859
- const [signedResults, nativeProfitWei] = await Promise.all([Promise.all(signPromises), nativeProfitPromise]);
1288
+ const [signedResults, nativeProfitWei] = await Promise.all([
1289
+ Promise.all(signPromises),
1290
+ nativeProfitPromise
1291
+ ]);
860
1292
  let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
861
1293
  if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
862
1294
  profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
@@ -865,6 +1297,7 @@ export async function directV3BatchSell(params) {
865
1297
  const profitMode = config.profitMode || 'single';
866
1298
  const skipProfit = config.skipProfit === true;
867
1299
  const profitAddr = getProfitRecipient();
1300
+ console.log('🔧 [SDK directV3BatchSell] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', wallets.length);
868
1301
  // 利润多跳转账
869
1302
  let profitTxs = [];
870
1303
  let profitHopWallets;
@@ -878,7 +1311,9 @@ export async function directV3BatchSell(params) {
878
1311
  profitHopWallets = [];
879
1312
  // 计算每个钱包的利润(按卖出金额比例分配)
880
1313
  for (let i = 0; i < wallets.length; i++) {
881
- const walletProfit = totalSellAmount > 0n ? (profitWei * sellAmountsWei[i]) / totalSellAmount : 0n;
1314
+ const walletProfit = totalSellAmount > 0n
1315
+ ? (profitWei * sellAmountsWei[i]) / totalSellAmount
1316
+ : 0n;
882
1317
  if (walletProfit > 0n) {
883
1318
  const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
884
1319
  const profitResult = await buildProfitHopTransactions({
@@ -890,7 +1325,7 @@ export async function directV3BatchSell(params) {
890
1325
  gasPrice,
891
1326
  chainId,
892
1327
  txType,
893
- startNonce: walletProfitNonce,
1328
+ startNonce: walletProfitNonce
894
1329
  });
895
1330
  profitTxs.push(...profitResult.signedTransactions);
896
1331
  if (profitResult.hopWallets) {
@@ -909,11 +1344,8 @@ export async function directV3BatchSell(params) {
909
1344
  }
910
1345
  // 按类型分组并按顺序组装
911
1346
  const validResults = signedResults.filter((r) => r !== null);
912
- const bribeTxs = validResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
913
- const swapTxs = validResults
914
- .filter((r) => r.type === 'swap')
915
- .sort((a, b) => a.index - b.index)
916
- .map((r) => r.tx);
1347
+ const bribeTxs = validResults.filter(r => r.type === 'bribe').map(r => r.tx);
1348
+ const swapTxs = validResults.filter(r => r.type === 'swap').sort((a, b) => a.index - b.index).map(r => r.tx);
917
1349
  const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
918
1350
  return {
919
1351
  signedTransactions: signedTxs,
@@ -926,9 +1358,6 @@ export async function directV3BatchSell(params) {
926
1358
  },
927
1359
  };
928
1360
  }
929
- // ============================================================================
930
- // 辅助函数:获取 Router 地址
931
- // ============================================================================
932
1361
  /**
933
1362
  * 根据链和 DEX 获取 Router 地址
934
1363
  */