four-flap-meme-sdk 1.9.49 → 2.0.0

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