four-flap-meme-sdk 2.2.2 → 2.2.4

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 (472) 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/__tests__/subpath-exports.test.d.ts +1 -0
  5. package/dist/__tests__/subpath-exports.test.js +64 -0
  6. package/dist/abis/common.d.ts +85 -0
  7. package/dist/abis/common.js +264 -0
  8. package/dist/abis/contracts/TaxToken.json +969 -0
  9. package/dist/abis/contracts/TokenManager2.json +136 -0
  10. package/dist/abis/contracts/index.d.ts +5 -0
  11. package/dist/abis/contracts/index.js +5 -0
  12. package/dist/abis/flap/index.d.ts +3 -0
  13. package/dist/abis/flap/index.js +3 -0
  14. package/dist/abis/flap/portal-events.d.ts +6 -0
  15. package/dist/abis/flap/portal-events.js +17 -0
  16. package/dist/abis/flap/portal.d.ts +6 -0
  17. package/dist/abis/flap/portal.js +37 -0
  18. package/dist/abis/flap/vault.d.ts +171 -0
  19. package/dist/abis/flap/vault.js +91 -0
  20. package/dist/abis/index.d.ts +8 -0
  21. package/dist/abis/index.js +11 -0
  22. package/dist/bundle-core/__tests__/config-helpers.test.d.ts +1 -0
  23. package/dist/bundle-core/__tests__/config-helpers.test.js +28 -0
  24. package/dist/bundle-core/__tests__/facade-parity.test.d.ts +1 -0
  25. package/dist/bundle-core/__tests__/facade-parity.test.js +33 -0
  26. package/dist/bundle-core/__tests__/sign-context-helpers.test.d.ts +1 -0
  27. package/dist/bundle-core/__tests__/sign-context-helpers.test.js +60 -0
  28. package/dist/bundle-core/__tests__/sign-fixture.test.d.ts +1 -0
  29. package/dist/bundle-core/__tests__/sign-fixture.test.js +220 -0
  30. package/dist/bundle-core/__tests__/sign-fixtures.d.ts +10 -0
  31. package/dist/bundle-core/__tests__/sign-fixtures.js +16 -0
  32. package/dist/bundle-core/config-helpers.d.ts +36 -0
  33. package/dist/bundle-core/config-helpers.js +57 -0
  34. package/dist/bundle-core/errors.d.ts +50 -0
  35. package/dist/bundle-core/errors.js +35 -0
  36. package/dist/bundle-core/four-meme/approve-tokenmanager.d.ts +7 -0
  37. package/dist/bundle-core/four-meme/approve-tokenmanager.js +99 -0
  38. package/dist/bundle-core/four-meme/core-helpers.d.ts +8 -0
  39. package/dist/bundle-core/four-meme/core-helpers.js +40 -0
  40. package/dist/bundle-core/four-meme/core.d.ts +4 -0
  41. package/dist/bundle-core/four-meme/core.js +515 -0
  42. package/dist/bundle-core/four-meme/pancake-proxy.d.ts +28 -0
  43. package/dist/bundle-core/four-meme/pancake-proxy.js +679 -0
  44. package/dist/bundle-core/four-meme/private.d.ts +27 -0
  45. package/dist/bundle-core/four-meme/private.js +465 -0
  46. package/dist/bundle-core/four-meme/sign-context-helpers.d.ts +2 -0
  47. package/dist/bundle-core/four-meme/sign-context-helpers.js +2 -0
  48. package/dist/bundle-core/four-meme/swap-buy-first.d.ts +8 -0
  49. package/dist/bundle-core/four-meme/swap-buy-first.js +493 -0
  50. package/dist/bundle-core/four-meme/swap-hop-helpers.d.ts +6 -0
  51. package/dist/bundle-core/four-meme/swap-hop-helpers.js +63 -0
  52. package/dist/bundle-core/four-meme/swap-internal.d.ts +3 -0
  53. package/dist/bundle-core/four-meme/swap-internal.js +18 -0
  54. package/dist/bundle-core/four-meme/swap-sign-helpers.d.ts +27 -0
  55. package/dist/bundle-core/four-meme/swap-sign-helpers.js +105 -0
  56. package/dist/bundle-core/four-meme/swap.d.ts +17 -0
  57. package/dist/bundle-core/four-meme/swap.js +505 -0
  58. package/dist/bundle-core/four-meme/types/buy-first.d.ts +50 -0
  59. package/dist/bundle-core/four-meme/types/buy-first.js +1 -0
  60. package/dist/bundle-core/four-meme/types/core-flow.d.ts +63 -0
  61. package/dist/bundle-core/four-meme/types/core-flow.js +1 -0
  62. package/dist/bundle-core/four-meme/types/index.d.ts +600 -0
  63. package/dist/bundle-core/four-meme/types/index.js +1 -0
  64. package/dist/bundle-core/four-meme/types/swap-internal.d.ts +19 -0
  65. package/dist/bundle-core/four-meme/types/swap-internal.js +1 -0
  66. package/dist/bundle-core/four-meme/types.d.ts +1 -0
  67. package/dist/bundle-core/four-meme/types.js +1 -0
  68. package/dist/bundle-core/four-meme/utils-disperse.d.ts +7 -0
  69. package/dist/bundle-core/four-meme/utils-disperse.js +396 -0
  70. package/dist/bundle-core/four-meme/utils-pairwise.d.ts +8 -0
  71. package/dist/bundle-core/four-meme/utils-pairwise.js +328 -0
  72. package/dist/bundle-core/four-meme/utils-sweep.d.ts +8 -0
  73. package/dist/bundle-core/four-meme/utils-sweep.js +744 -0
  74. package/dist/bundle-core/index.d.ts +8 -0
  75. package/dist/bundle-core/index.js +8 -0
  76. package/dist/bundle-core/internal.d.ts +21 -0
  77. package/dist/bundle-core/internal.js +182 -0
  78. package/dist/bundle-core/sign-context-helpers.d.ts +25 -0
  79. package/dist/bundle-core/sign-context-helpers.js +67 -0
  80. package/dist/bundle-core/submit.d.ts +293 -0
  81. package/dist/bundle-core/submit.js +727 -0
  82. package/dist/bundle-core/types/index.d.ts +8 -0
  83. package/dist/bundle-core/types/index.js +1 -0
  84. package/dist/bundle-core/types.d.ts +1 -0
  85. package/dist/bundle-core/types.js +1 -0
  86. package/dist/chains/bsc/four/approve-tokenmanager.d.ts +1 -26
  87. package/dist/chains/bsc/four/approve-tokenmanager.js +1 -113
  88. package/dist/chains/bsc/four/config.d.ts +5 -67
  89. package/dist/chains/bsc/four/config.js +2 -114
  90. package/dist/chains/bsc/four/core.d.ts +1 -4
  91. package/dist/chains/bsc/four/core.js +1 -592
  92. package/dist/chains/bsc/four/index.d.ts +6 -6
  93. package/dist/chains/bsc/four/index.js +6 -6
  94. package/dist/chains/bsc/four/internal.d.ts +2 -46
  95. package/dist/chains/bsc/four/internal.js +2 -239
  96. package/dist/chains/bsc/four/pancake-proxy.d.ts +1 -28
  97. package/dist/chains/bsc/four/pancake-proxy.js +1 -687
  98. package/dist/chains/bsc/four/private.d.ts +1 -27
  99. package/dist/chains/bsc/four/private.js +1 -477
  100. package/dist/chains/bsc/four/submit.d.ts +2 -315
  101. package/dist/chains/bsc/four/submit.js +2 -752
  102. package/dist/chains/bsc/four/swap-buy-first.d.ts +2 -55
  103. package/dist/chains/bsc/four/swap-buy-first.js +2 -507
  104. package/dist/chains/bsc/four/swap-internal.d.ts +1 -3
  105. package/dist/chains/bsc/four/swap-internal.js +1 -18
  106. package/dist/chains/bsc/four/swap.d.ts +2 -144
  107. package/dist/chains/bsc/four/swap.js +2 -766
  108. package/dist/chains/bsc/four/types.d.ts +1 -476
  109. package/dist/chains/bsc/four/utils-disperse.d.ts +1 -0
  110. package/dist/chains/bsc/four/utils-disperse.js +1 -0
  111. package/dist/chains/bsc/four/utils-pairwise.d.ts +1 -0
  112. package/dist/chains/bsc/four/utils-pairwise.js +1 -0
  113. package/dist/chains/bsc/four/utils-sweep.d.ts +1 -0
  114. package/dist/chains/bsc/four/utils-sweep.js +1 -0
  115. package/dist/chains/bsc/four/utils.d.ts +5 -18
  116. package/dist/chains/bsc/four/utils.js +5 -1552
  117. package/dist/chains/bsc/iro.d.ts +5 -0
  118. package/dist/chains/bsc/iro.js +4 -0
  119. package/dist/chains/bsc/pancake/bundle-buy-first-helpers.d.ts +159 -0
  120. package/dist/chains/bsc/pancake/bundle-buy-first-helpers.js +117 -0
  121. package/dist/chains/bsc/pancake/bundle-buy-first.d.ts +1 -91
  122. package/dist/chains/bsc/pancake/bundle-buy-first.js +97 -212
  123. package/dist/chains/bsc/pancake/bundle-swap-helpers.d.ts +241 -0
  124. package/dist/chains/bsc/pancake/bundle-swap-helpers.js +565 -0
  125. package/dist/chains/bsc/pancake/bundle-swap.d.ts +1 -79
  126. package/dist/chains/bsc/pancake/bundle-swap.js +114 -726
  127. package/dist/chains/bsc/pancake/index.d.ts +4 -2
  128. package/dist/chains/bsc/pancake/index.js +1 -3
  129. package/dist/chains/bsc/platforms/iro/factory.d.ts +2 -2
  130. package/dist/chains/bsc/platforms/iro/factory.js +3 -1
  131. package/dist/chains/bsc/platforms/iro/index.d.ts +5 -5
  132. package/dist/chains/bsc/platforms/iro/index.js +3 -3
  133. package/dist/chains/bsc/platforms/iro/pool.js +31 -10
  134. package/dist/chains/bsc/platforms/iro/token.js +4 -1
  135. package/dist/chains/eni/batch-router/bundle-approve.js +4 -3
  136. package/dist/chains/eni/batch-router/transfer.js +55 -25
  137. package/dist/chains/eni/batch-router/utils.js +32 -6
  138. package/dist/chains/eni/bundler/sign.js +5 -6
  139. package/dist/chains/eni/bundler/submit.js +1 -4
  140. package/dist/chains/eni/constants.js +1 -1
  141. package/dist/chains/eni/flat-aliases.d.ts +10 -0
  142. package/dist/chains/eni/flat-aliases.js +8 -0
  143. package/dist/chains/eni/index.d.ts +2 -1
  144. package/dist/chains/eni/index.js +1 -0
  145. package/dist/chains/eni/platforms/daoaas/create.js +2 -2
  146. package/dist/chains/eni/platforms/daoaas/index.d.ts +3 -3
  147. package/dist/chains/eni/platforms/daoaas/index.js +3 -3
  148. package/dist/chains/eni/platforms/daoaas/meta.js +9 -6
  149. package/dist/chains/eni/platforms/daoaas/portal-direct.js +28 -44
  150. package/dist/chains/eni/platforms/daoaas/portal.js +10 -6
  151. package/dist/chains/eni/platforms/dswap/liquidity.js +58 -26
  152. package/dist/chains/eni/platforms/fair-launch/index.d.ts +2 -2
  153. package/dist/chains/eni/platforms/fair-launch/index.js +1 -1
  154. package/dist/chains/eni/platforms/fair-launch/launcher.js +87 -46
  155. package/dist/chains/eni/platforms/fair-launch/pool.js +4 -1
  156. package/dist/chains/eni/platforms/fair-launch/presets.js +2 -2
  157. package/dist/chains/eni/platforms/iro/factory.d.ts +2 -2
  158. package/dist/chains/eni/platforms/iro/factory.js +3 -1
  159. package/dist/chains/eni/platforms/iro/index.d.ts +6 -6
  160. package/dist/chains/eni/platforms/iro/index.js +4 -4
  161. package/dist/chains/eni/platforms/iro/pool.js +90 -26
  162. package/dist/chains/eni/platforms/iro/token.js +107 -31
  163. package/dist/chains/eni/platforms/iro/whitelist.js +6 -18
  164. package/dist/chains/eni/submit.d.ts +43 -0
  165. package/dist/chains/eni/submit.js +286 -0
  166. package/dist/chains/index.d.ts +13 -0
  167. package/dist/chains/index.js +13 -0
  168. package/dist/chains/xlayer/eip7702/bundle-approve.d.ts +2 -26
  169. package/dist/chains/xlayer/eip7702/bundle-approve.js +11 -21
  170. package/dist/chains/xlayer/eip7702/bundle-buy.d.ts +2 -6
  171. package/dist/chains/xlayer/eip7702/bundle-buy.js +13 -51
  172. package/dist/chains/xlayer/eip7702/bundle-create.js +93 -59
  173. package/dist/chains/xlayer/eip7702/bundle-sell.d.ts +2 -6
  174. package/dist/chains/xlayer/eip7702/bundle-sell.js +29 -111
  175. package/dist/chains/xlayer/eip7702/bundle-swap.d.ts +3 -65
  176. package/dist/chains/xlayer/eip7702/bundle-swap.js +51 -245
  177. package/dist/chains/xlayer/eip7702/constants.d.ts +1 -16
  178. package/dist/chains/xlayer/eip7702/constants.js +3 -21
  179. package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +13 -0
  180. package/dist/chains/xlayer/eip7702/flat-aliases.js +10 -0
  181. package/dist/chains/xlayer/eip7702/index.d.ts +28 -46
  182. package/dist/chains/xlayer/eip7702/index.js +28 -81
  183. package/dist/chains/xlayer/eip7702/multi-hop-transfer-helpers.d.ts +79 -0
  184. package/dist/chains/xlayer/eip7702/multi-hop-transfer-helpers.js +1 -0
  185. package/dist/chains/xlayer/eip7702/multi-hop-transfer.d.ts +2 -203
  186. package/dist/chains/xlayer/eip7702/multi-hop-transfer.js +63 -307
  187. package/dist/chains/xlayer/eip7702/transfer-context-helpers.d.ts +26 -0
  188. package/dist/chains/xlayer/eip7702/transfer-context-helpers.js +57 -0
  189. package/dist/chains/xlayer/eip7702/types.d.ts +88 -0
  190. package/dist/chains/xlayer/eip7702/utils.d.ts +0 -3
  191. package/dist/chains/xlayer/eip7702/utils.js +23 -28
  192. package/dist/chains/xlayer/eip7702/volume-helpers.d.ts +148 -0
  193. package/dist/chains/xlayer/eip7702/volume-helpers.js +48 -0
  194. package/dist/chains/xlayer/eip7702/volume.d.ts +6 -184
  195. package/dist/chains/xlayer/eip7702/volume.js +89 -164
  196. package/dist/chains/xlayer/eoa/constants.js +1 -1
  197. package/dist/chains/xlayer/eoa/dex-helpers.js +5 -5
  198. package/dist/chains/xlayer/eoa/eoa-bundle-swap-helpers.d.ts +126 -0
  199. package/dist/chains/xlayer/eoa/eoa-bundle-swap-helpers.js +228 -0
  200. package/dist/chains/xlayer/eoa/eoa-bundle-swap.d.ts +1 -95
  201. package/dist/chains/xlayer/eoa/eoa-bundle-swap.js +66 -299
  202. package/dist/chains/xlayer/eoa/eoa-wash-volume.d.ts +1 -1
  203. package/dist/chains/xlayer/eoa/eoa-wash-volume.js +18 -23
  204. package/dist/chains/xlayer/eoa/index.d.ts +10 -6
  205. package/dist/chains/xlayer/eoa/index.js +8 -23
  206. package/dist/chains/xlayer/eoa/portal-ops.js +7 -2
  207. package/dist/chains/xlayer/eoa/router-manager.js +3 -3
  208. package/dist/chains/xlayer/eoa/types.d.ts +2 -2
  209. package/dist/chains/xlayer/eoa/types.js +1 -3
  210. package/dist/chains/xlayer/index.d.ts +3 -2
  211. package/dist/chains/xlayer/index.js +4 -7
  212. package/dist/contracts/helper3.d.ts +20 -5
  213. package/dist/contracts/helper3.js +56 -20
  214. package/dist/contracts/tm-bundle-helpers.d.ts +88 -0
  215. package/dist/contracts/tm-bundle-helpers.js +72 -0
  216. package/dist/contracts/tm-bundle-merkle/approve-tokenmanager.d.ts +1 -26
  217. package/dist/contracts/tm-bundle-merkle/approve-tokenmanager.js +1 -113
  218. package/dist/contracts/tm-bundle-merkle/config.d.ts +5 -67
  219. package/dist/contracts/tm-bundle-merkle/config.js +2 -114
  220. package/dist/contracts/tm-bundle-merkle/core.d.ts +1 -4
  221. package/dist/contracts/tm-bundle-merkle/core.js +1 -591
  222. package/dist/contracts/tm-bundle-merkle/index.d.ts +5 -5
  223. package/dist/contracts/tm-bundle-merkle/index.js +5 -5
  224. package/dist/contracts/tm-bundle-merkle/internal.d.ts +2 -46
  225. package/dist/contracts/tm-bundle-merkle/internal.js +2 -238
  226. package/dist/contracts/tm-bundle-merkle/pancake-proxy.d.ts +1 -28
  227. package/dist/contracts/tm-bundle-merkle/pancake-proxy.js +1 -686
  228. package/dist/contracts/tm-bundle-merkle/private.d.ts +1 -27
  229. package/dist/contracts/tm-bundle-merkle/private.js +1 -476
  230. package/dist/contracts/tm-bundle-merkle/submit.d.ts +3 -314
  231. package/dist/contracts/tm-bundle-merkle/submit.js +3 -928
  232. package/dist/contracts/tm-bundle-merkle/swap-buy-first.d.ts +2 -55
  233. package/dist/contracts/tm-bundle-merkle/swap-buy-first.js +2 -506
  234. package/dist/contracts/tm-bundle-merkle/swap-internal.d.ts +1 -3
  235. package/dist/contracts/tm-bundle-merkle/swap-internal.js +1 -18
  236. package/dist/contracts/tm-bundle-merkle/swap.d.ts +2 -144
  237. package/dist/contracts/tm-bundle-merkle/swap.js +2 -764
  238. package/dist/contracts/tm-bundle-merkle/types.d.ts +1 -476
  239. package/dist/contracts/tm-bundle-merkle/utils-disperse.d.ts +1 -0
  240. package/dist/contracts/tm-bundle-merkle/utils-disperse.js +1 -0
  241. package/dist/contracts/tm-bundle-merkle/utils-pairwise.d.ts +1 -0
  242. package/dist/contracts/tm-bundle-merkle/utils-pairwise.js +1 -0
  243. package/dist/contracts/tm-bundle-merkle/utils-sweep.d.ts +1 -0
  244. package/dist/contracts/tm-bundle-merkle/utils-sweep.js +1 -0
  245. package/dist/contracts/tm-bundle-merkle/utils.d.ts +6 -18
  246. package/dist/contracts/tm-bundle-merkle/utils.js +6 -1501
  247. package/dist/contracts/tm-bundle.d.ts +3 -51
  248. package/dist/contracts/tm-bundle.js +108 -177
  249. package/dist/contracts/tm.d.ts +3 -2
  250. package/dist/contracts/tm.js +37 -32
  251. package/dist/contracts/tm1.js +9 -4
  252. package/dist/contracts/tm2.js +9 -4
  253. package/dist/dex/direct-router-helpers.d.ts +264 -0
  254. package/dist/dex/direct-router-helpers.js +539 -0
  255. package/dist/dex/direct-router.d.ts +3 -125
  256. package/dist/dex/direct-router.js +237 -666
  257. package/dist/dex/types.d.ts +81 -0
  258. package/dist/dex/types.js +1 -0
  259. package/dist/exports/root-bundle-and-tooling.d.ts +27 -0
  260. package/dist/exports/root-bundle-and-tooling.js +30 -0
  261. package/dist/exports/root-eni-and-bsc-iro.d.ts +26 -0
  262. package/dist/exports/root-eni-and-bsc-iro.js +66 -0
  263. package/dist/exports/root-foundations.d.ts +35 -0
  264. package/dist/exports/root-foundations.js +70 -0
  265. package/dist/exports/root-swap-dex-and-xlayer.d.ts +30 -0
  266. package/dist/exports/root-swap-dex-and-xlayer.js +78 -0
  267. package/dist/flap/index.d.ts +10 -0
  268. package/dist/flap/index.js +8 -0
  269. package/dist/flows/create.d.ts +2 -1
  270. package/dist/flows/create.js +6 -6
  271. package/dist/flows/index.d.ts +1 -0
  272. package/dist/flows/index.js +1 -0
  273. package/dist/index.d.ts +20 -85
  274. package/dist/index.js +20 -215
  275. package/dist/merkle/index.d.ts +12 -0
  276. package/dist/merkle/index.js +11 -0
  277. package/dist/shared/abis/common.d.ts +2 -83
  278. package/dist/shared/abis/common.js +2 -252
  279. package/dist/shared/abis/index.d.ts +5 -6
  280. package/dist/shared/abis/index.js +5 -7
  281. package/dist/shared/clients/blockrazor.js +39 -25
  282. package/dist/shared/clients/club48.d.ts +2 -2
  283. package/dist/shared/clients/club48.js +34 -29
  284. package/dist/shared/clients/emitservice.js +2 -0
  285. package/dist/shared/clients/four.d.ts +21 -6
  286. package/dist/shared/clients/four.js +29 -24
  287. package/dist/shared/clients/index.d.ts +8 -0
  288. package/dist/shared/clients/index.js +8 -0
  289. package/dist/shared/clients/merkle.js +27 -34
  290. package/dist/shared/constants/addresses.d.ts +1 -1
  291. package/dist/shared/constants/addresses.js +11 -2
  292. package/dist/shared/constants/chains.d.ts +1 -1
  293. package/dist/shared/constants/chains.js +1 -1
  294. package/dist/shared/constants/gas.d.ts +1 -1
  295. package/dist/shared/constants/gas.js +2 -6
  296. package/dist/shared/constants/index.d.ts +3 -0
  297. package/dist/shared/constants/index.js +1 -0
  298. package/dist/shared/constants/quote.d.ts +30 -0
  299. package/dist/shared/constants/quote.js +37 -0
  300. package/dist/shared/flap/abi.js +1 -1
  301. package/dist/shared/flap/constants.d.ts +1 -2
  302. package/dist/shared/flap/constants.js +2 -3
  303. package/dist/shared/flap/curve.js +3 -0
  304. package/dist/shared/flap/errors.d.ts +1 -4
  305. package/dist/shared/flap/errors.js +20 -1
  306. package/dist/shared/flap/index.d.ts +5 -4
  307. package/dist/shared/flap/index.js +5 -4
  308. package/dist/shared/flap/meta.d.ts +22 -18
  309. package/dist/shared/flap/meta.js +12 -17
  310. package/dist/shared/flap/permit.js +5 -2
  311. package/dist/shared/flap/pinata.d.ts +22 -6
  312. package/dist/shared/flap/pinata.js +21 -26
  313. package/dist/shared/flap/portal-bundle-merkle/config.d.ts +3 -72
  314. package/dist/shared/flap/portal-bundle-merkle/config.js +4 -124
  315. package/dist/shared/flap/portal-bundle-merkle/core-helpers.d.ts +32 -0
  316. package/dist/shared/flap/portal-bundle-merkle/core-helpers.js +83 -0
  317. package/dist/shared/flap/portal-bundle-merkle/core.d.ts +0 -4
  318. package/dist/shared/flap/portal-bundle-merkle/core.js +96 -277
  319. package/dist/shared/flap/portal-bundle-merkle/create-to-dex.d.ts +7 -2
  320. package/dist/shared/flap/portal-bundle-merkle/create-to-dex.js +107 -206
  321. package/dist/shared/flap/portal-bundle-merkle/curve-to-dex.js +100 -92
  322. package/dist/shared/flap/portal-bundle-merkle/index.d.ts +11 -7
  323. package/dist/shared/flap/portal-bundle-merkle/index.js +4 -7
  324. package/dist/shared/flap/portal-bundle-merkle/pancake-proxy.js +71 -68
  325. package/dist/shared/flap/portal-bundle-merkle/private.js +61 -114
  326. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first-helpers.d.ts +125 -0
  327. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first-helpers.js +113 -0
  328. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first.d.ts +1 -64
  329. package/dist/shared/flap/portal-bundle-merkle/swap-buy-first.js +66 -247
  330. package/dist/shared/flap/portal-bundle-merkle/swap-helpers.d.ts +149 -0
  331. package/dist/shared/flap/portal-bundle-merkle/swap-helpers.js +259 -0
  332. package/dist/shared/flap/portal-bundle-merkle/swap.d.ts +2 -71
  333. package/dist/shared/flap/portal-bundle-merkle/swap.js +103 -410
  334. package/dist/shared/flap/portal-bundle-merkle/types.d.ts +88 -9
  335. package/dist/shared/flap/portal-bundle-merkle/utils.d.ts +1 -80
  336. package/dist/shared/flap/portal-bundle-merkle/utils.js +145 -265
  337. package/dist/shared/flap/portal-bundle.js +55 -56
  338. package/dist/shared/flap/portal-create-token.d.ts +80 -0
  339. package/dist/shared/flap/portal-create-token.js +257 -0
  340. package/dist/shared/flap/portal.d.ts +14 -3
  341. package/dist/shared/flap/portal.js +50 -25
  342. package/dist/shared/flap/vanity.d.ts +1 -5
  343. package/dist/shared/flap/vanity.js +6 -17
  344. package/dist/shared/flap/vault.d.ts +17 -124
  345. package/dist/shared/flap/vault.js +67 -148
  346. package/dist/shared/foundation/dex/v3-path.d.ts +6 -0
  347. package/dist/shared/foundation/dex/v3-path.js +35 -0
  348. package/dist/shared/foundation/gas/bundle-gas.d.ts +49 -0
  349. package/dist/shared/foundation/gas/bundle-gas.js +93 -0
  350. package/dist/shared/foundation/gas/profit-hop.d.ts +20 -0
  351. package/dist/shared/foundation/gas/profit-hop.js +72 -0
  352. package/dist/shared/foundation/index.d.ts +13 -0
  353. package/dist/shared/foundation/index.js +12 -0
  354. package/dist/shared/foundation/nonce/nonce-manager.d.ts +17 -0
  355. package/dist/shared/foundation/nonce/nonce-manager.js +183 -0
  356. package/dist/shared/foundation/normalize-unknown.d.ts +9 -0
  357. package/dist/shared/foundation/normalize-unknown.js +29 -0
  358. package/dist/shared/foundation/sdk-logger.d.ts +13 -0
  359. package/dist/shared/foundation/sdk-logger.js +12 -0
  360. package/dist/shared/foundation/tx/build-request.d.ts +17 -0
  361. package/dist/shared/foundation/tx/build-request.js +25 -0
  362. package/dist/shared/foundation/tx/sign-batch.d.ts +5 -0
  363. package/dist/shared/foundation/tx/sign-batch.js +26 -0
  364. package/dist/shared/foundation/tx/wallet-sign-patch.d.ts +1 -0
  365. package/dist/shared/foundation/tx/wallet-sign-patch.js +18 -0
  366. package/dist/shared/foundation/types/airdrop-sweep.d.ts +79 -0
  367. package/dist/shared/foundation/types/airdrop-sweep.js +1 -0
  368. package/dist/shared/foundation/types/erc20.d.ts +65 -0
  369. package/dist/shared/foundation/types/erc20.js +1 -0
  370. package/dist/shared/foundation/types/holders-maker.d.ts +64 -0
  371. package/dist/shared/foundation/types/holders-maker.js +1 -0
  372. package/dist/shared/foundation/types/index.d.ts +7 -0
  373. package/dist/shared/foundation/types/index.js +1 -0
  374. package/dist/shared/foundation/types/lp-inspect.d.ts +102 -0
  375. package/dist/shared/foundation/types/lp-inspect.js +1 -0
  376. package/dist/shared/foundation/types/multicall.d.ts +5 -0
  377. package/dist/shared/foundation/types/multicall.js +1 -0
  378. package/dist/shared/foundation/types/private-sale.d.ts +35 -0
  379. package/dist/shared/foundation/types/private-sale.js +1 -0
  380. package/dist/shared/foundation/types/quote-helpers.d.ts +17 -0
  381. package/dist/shared/foundation/types/quote-helpers.js +1 -0
  382. package/dist/shared/four/tax-token.d.ts +1 -1
  383. package/dist/shared/four/tax-token.js +27 -7
  384. package/dist/shared/index.d.ts +6 -0
  385. package/dist/shared/index.js +4 -0
  386. package/dist/types/errors.d.ts +27 -0
  387. package/dist/types/errors.js +34 -0
  388. package/dist/utils/airdrop-sweep.d.ts +4 -76
  389. package/dist/utils/airdrop-sweep.js +42 -55
  390. package/dist/utils/bundle-helpers.d.ts +9 -243
  391. package/dist/utils/bundle-helpers.js +10 -584
  392. package/dist/utils/constants.d.ts +5 -61
  393. package/dist/utils/constants.js +5 -80
  394. package/dist/utils/contract-factory.d.ts +2 -4
  395. package/dist/utils/contract-factory.js +25 -18
  396. package/dist/utils/erc20.d.ts +7 -89
  397. package/dist/utils/erc20.js +94 -125
  398. package/dist/utils/errors.d.ts +12 -1
  399. package/dist/utils/errors.js +60 -1
  400. package/dist/utils/holders-maker/addresses.d.ts +12 -0
  401. package/dist/utils/holders-maker/addresses.js +15 -0
  402. package/dist/utils/holders-maker/buy-tx.d.ts +44 -0
  403. package/dist/utils/holders-maker/buy-tx.js +278 -0
  404. package/dist/utils/holders-maker/constants.d.ts +6 -0
  405. package/dist/utils/holders-maker/constants.js +7 -0
  406. package/dist/utils/holders-maker/disperse.d.ts +18 -0
  407. package/dist/utils/holders-maker/disperse.js +90 -0
  408. package/dist/utils/holders-maker/routing.d.ts +4 -0
  409. package/dist/utils/holders-maker/routing.js +45 -0
  410. package/dist/utils/holders-maker/transfer-tx.d.ts +4 -0
  411. package/dist/utils/holders-maker/transfer-tx.js +67 -0
  412. package/dist/utils/holders-maker-helpers.d.ts +9 -0
  413. package/dist/utils/holders-maker-helpers.js +9 -0
  414. package/dist/utils/holders-maker.d.ts +2 -138
  415. package/dist/utils/holders-maker.js +26 -661
  416. package/dist/utils/hop-chains.d.ts +35 -0
  417. package/dist/utils/hop-chains.js +215 -0
  418. package/dist/utils/lp-inspect-helpers.d.ts +9 -0
  419. package/dist/utils/lp-inspect-helpers.js +109 -0
  420. package/dist/utils/lp-inspect.d.ts +2 -112
  421. package/dist/utils/lp-inspect.js +73 -223
  422. package/dist/utils/mpcExclusive.d.ts +2 -5
  423. package/dist/utils/mpcExclusive.js +4 -3
  424. package/dist/utils/private-sale.d.ts +2 -58
  425. package/dist/utils/private-sale.js +4 -15
  426. package/dist/utils/provider-factory.d.ts +4 -0
  427. package/dist/utils/provider-factory.js +10 -0
  428. package/dist/utils/quote-helpers.d.ts +4 -45
  429. package/dist/utils/quote-helpers.js +17 -74
  430. package/dist/utils/stealth-transfer.d.ts +2 -28
  431. package/dist/utils/stealth-transfer.js +31 -15
  432. package/dist/utils/swap-helpers.d.ts +2 -15
  433. package/dist/utils/swap-helpers.js +6 -11
  434. package/dist/utils/types/airdrop-sweep.d.ts +1 -0
  435. package/dist/utils/types/airdrop-sweep.js +1 -0
  436. package/dist/utils/types/contract-factory.d.ts +1 -0
  437. package/dist/utils/types/contract-factory.js +1 -0
  438. package/dist/utils/types/erc20.d.ts +1 -0
  439. package/dist/utils/types/erc20.js +1 -0
  440. package/dist/utils/types/errors.d.ts +1 -0
  441. package/dist/utils/types/errors.js +1 -0
  442. package/dist/utils/types/holders-maker.d.ts +1 -0
  443. package/dist/utils/types/holders-maker.js +1 -0
  444. package/dist/utils/types/hop-chains.d.ts +8 -0
  445. package/dist/utils/types/hop-chains.js +1 -0
  446. package/dist/utils/types/index.d.ts +13 -0
  447. package/dist/utils/types/index.js +1 -0
  448. package/dist/utils/types/lp-inspect.d.ts +1 -0
  449. package/dist/utils/types/lp-inspect.js +1 -0
  450. package/dist/utils/types/mpc-exclusive.d.ts +5 -0
  451. package/dist/utils/types/mpc-exclusive.js +1 -0
  452. package/dist/utils/types/private-sale.d.ts +1 -0
  453. package/dist/utils/types/private-sale.js +1 -0
  454. package/dist/utils/types/quote-helpers.d.ts +1 -0
  455. package/dist/utils/types/quote-helpers.js +1 -0
  456. package/dist/utils/types/stealth-transfer.d.ts +44 -0
  457. package/dist/utils/types/stealth-transfer.js +1 -0
  458. package/dist/utils/types/wallet.d.ts +25 -0
  459. package/dist/utils/types/wallet.js +1 -0
  460. package/dist/utils/wallet.d.ts +2 -25
  461. package/dist/utils/wallet.js +13 -10
  462. package/dist/vanity/index.d.ts +5 -0
  463. package/dist/vanity/index.js +5 -0
  464. package/package.json +160 -4
  465. package/src/abis/contracts/TaxToken.json +969 -0
  466. package/src/abis/contracts/TokenManager.json +836 -0
  467. package/src/abis/contracts/TokenManager2.json +136 -0
  468. package/src/abis/contracts/TokenManagerHelper3.json +993 -0
  469. package/dist/shared/abis/TaxToken.json +0 -105
  470. package/dist/shared/abis/TokenManager2.json +0 -60
  471. /package/dist/{shared/abis → abis/contracts}/TokenManager.json +0 -0
  472. /package/dist/{shared/abis → abis/contracts}/TokenManagerHelper3.json +0 -0
@@ -1,524 +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 { PROFIT_CONFIG, ZERO_ADDRESS, BLOCKRAZOR_BUILDER_EOA, ADDRESSES, getProfitRecipient } from '../utils/constants.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';
13
7
  import { GAS_LIMITS } from '../shared/constants/index.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';
8
+ import { ERC20_ABI } from '../abis/common.js';
15
9
  import { getTokenToNativeQuote, quoteV2 } from '../utils/quote-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
- */
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';
522
12
  export async function directV2BatchBuy(params) {
523
13
  const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, quoteToken, quoteTokenDecimals = 18, startNonces, config, } = params;
524
14
  if (privateKeys.length !== buyAmounts.length) {
@@ -530,23 +20,23 @@ export async function directV2BatchBuy(params) {
530
20
  const useNative = isNativeToken(quoteToken);
531
21
  const wrappedNative = getWrappedNative(chain);
532
22
  // 创建钱包
533
- const wallets = privateKeys.map(pk => new Wallet(pk, provider));
23
+ const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
534
24
  // ✅ 预先计算所有金额(同步操作,无 RPC)
535
- const flowAmounts = buyAmounts.map(amount => ethers.parseUnits(amount, quoteTokenDecimals));
25
+ const flowAmounts = buyAmounts.map((amount) => ethers.parseUnits(amount, quoteTokenDecimals));
536
26
  const totalFlowWei = flowAmounts.reduce((sum, amt) => sum + amt, 0n);
537
27
  const baseProfitWei = calculateProfitAmount(totalFlowWei);
538
28
  // ✅ 方案 B:并行获取 nonces、gasPrice、ERC20 报价 以及(非原生代币时)授权额度
539
- const quoteTokenContract = (!useNative && quoteToken) ? new Contract(quoteToken, ERC20_ABI, provider) : null;
29
+ const quoteTokenContract = !useNative && quoteToken ? new Contract(quoteToken, ERC20_ABI, provider) : null;
540
30
  const [nonces, gasPrice, nativeProfitWei, buyAllowances] = await Promise.all([
541
31
  startNonces && startNonces.length === wallets.length
542
32
  ? Promise.resolve(startNonces)
543
33
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
544
34
  getGasPrice(provider, config),
545
- (!useNative && baseProfitWei > 0n && quoteToken)
35
+ !useNative && baseProfitWei > 0n && quoteToken
546
36
  ? getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v2')
547
37
  : Promise.resolve(baseProfitWei),
548
38
  quoteTokenContract
549
- ? 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)))
550
40
  : Promise.resolve(wallets.map(() => ethers.MaxUint256)),
551
41
  ]);
552
42
  // 确定最终利润金额(ENI 链额外补偿利润转账的 gas 成本)
@@ -560,28 +50,8 @@ export async function directV2BatchBuy(params) {
560
50
  // ENI 链原生代币买入:链上余额预检,跳过余额不足的钱包
561
51
  let activeIndices = null;
562
52
  if (useNative && chain.toUpperCase() === 'ENI') {
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
- }
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,8 +80,10 @@ export async function directV2BatchBuy(params) {
610
80
  if (activeFlowAmounts[i] <= 0n)
611
81
  continue;
612
82
  if (activeBuyAllowances[i] < activeFlowAmounts[i]) {
613
- console.log(`🔓 [V2 Buy] 钱包 ${i} 报价代币授权不足 (${activeBuyAllowances[i]} < ${activeFlowAmounts[i]}), 自动 approve`);
614
- const approveData = quoteTokenContract.interface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]);
83
+ const approveData = quoteTokenContract.interface.encodeFunctionData('approve', [
84
+ routerAddress,
85
+ ethers.MaxUint256,
86
+ ]);
615
87
  const approveTx = await activeWallets[i].signTransaction({
616
88
  to: quoteToken,
617
89
  data: approveData,
@@ -645,14 +117,39 @@ export async function directV2BatchBuy(params) {
645
117
  return { txData: encodeDYORMulticall(BigInt(deadline), multicallData), txValue: useNative ? amountWei : 0n };
646
118
  }
647
119
  else if (useSwapRouter02) {
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 };
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
+ };
650
130
  }
651
131
  else if (useNative) {
652
- 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
+ };
653
141
  }
654
142
  else {
655
- 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
+ };
656
153
  }
657
154
  };
658
155
  // 选择金额最大的钱包支付贿赂和利润
@@ -662,18 +159,18 @@ export async function directV2BatchBuy(params) {
662
159
  const hasBribe = bribeWei > 0n && activeWallets.length > 0;
663
160
  const hasProfit = activeProfitWei > 0n;
664
161
  // 计算 nonce 偏移
665
- const nonceOffsets = activeWallets.map((_, i) => i === maxFlowIndex && hasBribe ? 1 : 0);
162
+ const nonceOffsets = activeWallets.map((_, i) => (i === maxFlowIndex && hasBribe ? 1 : 0));
666
163
  // ✅ 方案 A:并行签名所有交易(贿赂、主交易、利润)
667
164
  const signPromises = [];
668
165
  // 贿赂交易
669
166
  if (hasBribe) {
670
- signPromises.push(buildBribeTransaction(activeWallets[maxFlowIndex], bribeWei, activeNonces[maxFlowIndex], gasPrice, chainId, txType)
671
- .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 })));
672
168
  }
673
169
  // 主交易(并行签名)
674
170
  activeWallets.forEach((wallet, i) => {
675
171
  const { txData, txValue } = buildTxData(wallet, activeFlowAmounts[i]);
676
- signPromises.push(wallet.signTransaction({
172
+ signPromises.push(wallet
173
+ .signTransaction({
677
174
  to: routerAddress,
678
175
  data: txData,
679
176
  value: txValue,
@@ -681,20 +178,23 @@ export async function directV2BatchBuy(params) {
681
178
  gasLimit,
682
179
  ...buildGasFields(txType, gasPrice),
683
180
  chainId,
684
- }).then(tx => ({ type: 'swap', index: i, tx })));
181
+ })
182
+ .then((tx) => ({ type: 'swap', index: i, tx })));
685
183
  });
686
184
  // ✅ 并行执行所有签名
687
185
  const signedResults = await Promise.all(signPromises);
688
186
  // 按类型分组并按顺序组装:approve → 贿赂 → 交易
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);
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);
692
193
  const signedTxs = [...approveSignedTxs, ...bribeTxs, ...swapTxs];
693
194
  // ✅ 检查是否使用分布式利润模式
694
195
  const profitMode = config.profitMode || 'single';
695
196
  const skipProfit = config.skipProfit === true;
696
197
  const profitAddr = getProfitRecipient();
697
- console.log('🔧 [SDK directV2BatchBuy] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', activeWallets.length);
698
198
  // 利润多跳转账
699
199
  let profitHopWallets;
700
200
  if (hasProfit && !skipProfit) {
@@ -707,9 +207,7 @@ export async function directV2BatchBuy(params) {
707
207
  profitHopWallets = [];
708
208
  // 计算每个钱包的利润(按比例分配)
709
209
  for (let i = 0; i < activeWallets.length; i++) {
710
- const walletProfit = activeTotalFlowWei > 0n
711
- ? (activeProfitWei * activeFlowAmounts[i]) / activeTotalFlowWei
712
- : 0n;
210
+ const walletProfit = activeTotalFlowWei > 0n ? (activeProfitWei * activeFlowAmounts[i]) / activeTotalFlowWei : 0n;
713
211
  if (walletProfit > 0n) {
714
212
  const walletProfitNonce = activeNonces[i] + nonceOffsets[i] + 1;
715
213
  const profitResult = await buildProfitHopTransactions({
@@ -721,7 +219,7 @@ export async function directV2BatchBuy(params) {
721
219
  gasPrice,
722
220
  chainId,
723
221
  txType,
724
- startNonce: walletProfitNonce
222
+ startNonce: walletProfitNonce,
725
223
  });
726
224
  signedTxs.push(...profitResult.signedTransactions);
727
225
  if (profitResult.hopWallets) {
@@ -760,19 +258,22 @@ export async function directV2BatchSell(params) {
760
258
  const useNativeOutput = isNativeToken(quoteToken);
761
259
  const wrappedNative = getWrappedNative(chain);
762
260
  // 创建钱包
763
- const wallets = privateKeys.map(pk => new Wallet(pk, provider));
261
+ const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
764
262
  const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
765
263
  // ✅ 性能优化:并行获取所有独立的 RPC 数据(包括授权额度)
766
264
  const [fetchedDecimals, balances, allowances, nonces, gasPrice] = await Promise.all([
767
265
  inputDecimals !== undefined
768
266
  ? Promise.resolve(inputDecimals)
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))),
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))),
772
273
  startNonces && startNonces.length === wallets.length
773
274
  ? Promise.resolve(startNonces)
774
275
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
775
- getGasPrice(provider, config)
276
+ getGasPrice(provider, config),
776
277
  ]);
777
278
  const tokenDecimals = fetchedDecimals;
778
279
  const gasLimit = getGasLimit(config, 300000);
@@ -794,33 +295,17 @@ export async function directV2BatchSell(params) {
794
295
  amount = balances[i];
795
296
  }
796
297
  if (amount > balances[i]) {
797
- console.log(`⚠️ [V2 Sell] 钱包 ${i} 卖出量(${amount}) > 链上余额(${balances[i]}),已自动调整为实际余额`);
798
298
  amount = balances[i];
799
299
  }
800
300
  sellAmountsWei.push(amount);
801
301
  }
802
302
  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
- }
817
303
  // ✅ 自动授权:检查每个钱包对 Router 的授权额度,不足则插入 approve 交易
818
304
  const approveTxs = [];
819
305
  for (let i = 0; i < wallets.length; i++) {
820
306
  if (sellAmountsWei[i] <= 0n)
821
307
  continue;
822
308
  if (allowances[i] < sellAmountsWei[i]) {
823
- console.log(`🔓 [V2 Sell] 钱包 ${i} 授权不足 (${allowances[i]} < ${sellAmountsWei[i]}), 自动 approve`);
824
309
  const approveData = tokenContract.interface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]);
825
310
  const approveTx = await wallets[i].signTransaction({
826
311
  to: tokenAddress,
@@ -842,11 +327,9 @@ export async function directV2BatchSell(params) {
842
327
  if (useNativeOutput) {
843
328
  // 卖出代币 → 得到 BNB:先获取 V2 报价,再计算利润(✅ 使用当前 Router 报价,IROSwap 池需用 IROSwap Router)
844
329
  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)}`);
846
330
  if (estimatedBNBOut <= 0n)
847
331
  return 0n;
848
332
  const profit = calculateProfitAmount(estimatedBNBOut);
849
- console.log(`[V2 Sell Profit] profit: ${profit}, profitBNB: ${ethers.formatEther(profit)}`);
850
333
  return profit;
851
334
  }
852
335
  else if (quoteToken) {
@@ -857,13 +340,10 @@ export async function directV2BatchSell(params) {
857
340
  const step1 = await quoteV2(provider, tokenAddress, quoteToken, totalSellAmount, chain, routerAddress);
858
341
  if (!step1.amountOut || step1.amountOut <= 0n)
859
342
  return 0n;
860
- console.log(`[V2 Sell Profit] step1 token→quoteToken: ${step1.amountOut} wei`);
861
343
  const estimatedBNBOut = await getTokenToNativeQuote(provider, quoteToken, step1.amountOut, chain, 'v2');
862
- console.log(`[V2 Sell Profit] step2 quoteToken→BNB: ${estimatedBNBOut} wei`);
863
344
  if (estimatedBNBOut <= 0n)
864
345
  return 0n;
865
346
  const profit = calculateProfitAmount(estimatedBNBOut);
866
- console.log(`[V2 Sell Profit] profit: ${profit}, profitBNB: ${ethers.formatEther(profit)}`);
867
347
  return profit;
868
348
  }
869
349
  return 0n;
@@ -878,7 +358,9 @@ export async function directV2BatchSell(params) {
878
358
  const path = [tokenAddress, outputToken];
879
359
  const useSwapRouter02 = isSwapRouter02(chain, routerAddress);
880
360
  const useDYORSwap = isDYORSwap(chain, routerAddress);
881
- 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);
882
364
  // 构建卖出交易数据的辅助函数
883
365
  const buildSellTxData = (wallet, sellAmount) => {
884
366
  if (useDYORSwap) {
@@ -900,32 +382,47 @@ export async function directV2BatchSell(params) {
900
382
  return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, multicallData]);
901
383
  }
902
384
  else {
903
- 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
+ ]);
904
389
  }
905
390
  }
906
391
  else if (useNativeOutput) {
907
- 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
+ ]);
908
399
  }
909
400
  else {
910
- 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
+ ]);
911
408
  }
912
409
  };
913
410
  const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
914
411
  const bribeWei = getBribeAmount(config, chain);
915
412
  const hasBribe = bribeWei > 0n && wallets.length > 0;
916
- const nonceOffsets = wallets.map((_, i) => i === maxOutputIndex && hasBribe ? 1 : 0);
413
+ const nonceOffsets = wallets.map((_, i) => (i === maxOutputIndex && hasBribe ? 1 : 0));
917
414
  // ✅ 方案 A:并行签名所有交易(贿赂、卖出、利润)+ 并行获取 ERC20 报价
918
415
  const signPromises = [];
919
416
  // 贿赂交易
920
417
  if (hasBribe) {
921
- signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType)
922
- .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 })));
923
419
  }
924
420
  // 卖出交易(并行签名)
925
421
  wallets.forEach((wallet, i) => {
926
422
  if (sellAmountsWei[i] <= 0n)
927
423
  return;
928
- signPromises.push(wallet.signTransaction({
424
+ signPromises.push(wallet
425
+ .signTransaction({
929
426
  to: routerAddress,
930
427
  data: buildSellTxData(wallet, sellAmountsWei[i]),
931
428
  value: 0n,
@@ -933,13 +430,11 @@ export async function directV2BatchSell(params) {
933
430
  gasLimit,
934
431
  ...buildGasFields(txType, gasPrice),
935
432
  chainId,
936
- }).then(tx => ({ type: 'swap', index: i, tx })));
433
+ })
434
+ .then((tx) => ({ type: 'swap', index: i, tx })));
937
435
  });
938
436
  // ✅ 并行执行:签名 + ERC20 报价
939
- const [signedResults, nativeProfitWei] = await Promise.all([
940
- Promise.all(signPromises),
941
- nativeProfitPromise
942
- ]);
437
+ const [signedResults, nativeProfitWei] = await Promise.all([Promise.all(signPromises), nativeProfitPromise]);
943
438
  let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
944
439
  if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
945
440
  profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
@@ -948,7 +443,6 @@ export async function directV2BatchSell(params) {
948
443
  const profitMode = config.profitMode || 'single';
949
444
  const skipProfit = config.skipProfit === true;
950
445
  const profitAddr = getProfitRecipient();
951
- console.log('🔧 [SDK directV2BatchSell] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', wallets.length);
952
446
  // 利润多跳转账
953
447
  let profitTxs = [];
954
448
  let profitHopWallets;
@@ -962,9 +456,7 @@ export async function directV2BatchSell(params) {
962
456
  profitHopWallets = [];
963
457
  // 计算每个钱包的利润(按卖出金额比例分配)
964
458
  for (let i = 0; i < wallets.length; i++) {
965
- const walletProfit = totalSellAmount > 0n
966
- ? (profitWei * sellAmountsWei[i]) / totalSellAmount
967
- : 0n;
459
+ const walletProfit = totalSellAmount > 0n ? (profitWei * sellAmountsWei[i]) / totalSellAmount : 0n;
968
460
  if (walletProfit > 0n) {
969
461
  const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
970
462
  const profitResult = await buildProfitHopTransactions({
@@ -976,7 +468,7 @@ export async function directV2BatchSell(params) {
976
468
  gasPrice,
977
469
  chainId,
978
470
  txType,
979
- startNonce: walletProfitNonce
471
+ startNonce: walletProfitNonce,
980
472
  });
981
473
  profitTxs.push(...profitResult.signedTransactions);
982
474
  if (profitResult.hopWallets) {
@@ -995,9 +487,12 @@ export async function directV2BatchSell(params) {
995
487
  }
996
488
  // 按类型分组并按顺序组装:approve → bribe → swap → profit
997
489
  const validResults = signedResults.filter((r) => r !== null);
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);
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);
1001
496
  const signedTxs = [...approveSignedTxs, ...bribeTxs, ...swapTxs, ...profitTxs];
1002
497
  return {
1003
498
  signedTransactions: signedTxs,
@@ -1032,9 +527,9 @@ export async function directV3BatchBuy(params) {
1032
527
  const wrappedNative = getWrappedNative(chain);
1033
528
  const useLegacyRouter = isLegacySwapRouter(chain, routerAddress);
1034
529
  const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
1035
- const wallets = privateKeys.map(pk => new Wallet(pk, provider));
530
+ const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
1036
531
  // ✅ 预先计算所有金额(同步操作,无 RPC)
1037
- const flowAmounts = buyAmounts.map(amount => ethers.parseUnits(amount, quoteTokenDecimals));
532
+ const flowAmounts = buyAmounts.map((amount) => ethers.parseUnits(amount, quoteTokenDecimals));
1038
533
  const totalFlowWei = flowAmounts.reduce((sum, amt) => sum + amt, 0n);
1039
534
  const baseProfitWei = calculateProfitAmount(totalFlowWei);
1040
535
  // ✅ 方案 B:并行获取 nonces、gasPrice 和 ERC20 报价
@@ -1044,11 +539,11 @@ export async function directV3BatchBuy(params) {
1044
539
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
1045
540
  getGasPrice(provider, config),
1046
541
  // ERC20 报价(V3 买入用 V3 报价)
1047
- (!useNative && baseProfitWei > 0n && quoteToken)
1048
- ? (chain.toUpperCase() === 'XLAYER'
542
+ !useNative && baseProfitWei > 0n && quoteToken
543
+ ? chain.toUpperCase() === 'XLAYER'
1049
544
  ? quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: quoteToken, amountIn: baseProfitWei, fee })
1050
- : getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v3', fee))
1051
- : Promise.resolve(baseProfitWei)
545
+ : getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v3', fee)
546
+ : Promise.resolve(baseProfitWei),
1052
547
  ]);
1053
548
  let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
1054
549
  if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
@@ -1062,51 +557,87 @@ export async function directV3BatchBuy(params) {
1062
557
  // 构建交易数据的辅助函数
1063
558
  const buildV3BuyTxData = (wallet, amountWei) => {
1064
559
  if (useLegacyRouter) {
1065
- 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
+ };
1066
570
  if (useNative) {
1067
571
  const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
1068
572
  const refundData = routerIface.encodeFunctionData('refundETH', []);
1069
- return { txData: routerIface.encodeFunctionData('multicall(bytes[])', [[swapData, refundData]]), txValue: amountWei };
573
+ return {
574
+ txData: routerIface.encodeFunctionData('multicall(bytes[])', [[swapData, refundData]]),
575
+ txValue: amountWei,
576
+ };
1070
577
  }
1071
578
  return { txData: routerIface.encodeFunctionData('exactInputSingle', [swapParams]), txValue: 0n };
1072
579
  }
1073
580
  else {
1074
- 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
+ };
1075
590
  if (useNative) {
1076
591
  const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
1077
592
  const refundData = routerIface.encodeFunctionData('refundETH', []);
1078
- 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
+ };
1079
597
  }
1080
598
  // ✅ 修复:ERC20 买入也需要使用 multicall 包装以传递 deadline
1081
599
  // SwapRouter02 的 exactInputSingle 不包含 deadline 参数,必须通过 multicall 传递
1082
600
  const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
1083
- 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
+ };
1084
605
  }
1085
606
  };
1086
607
  const maxFlowIndex = findMaxFlowIndex(flowAmounts);
1087
608
  const bribeWei = getBribeAmount(config, chain);
1088
609
  const hasBribe = bribeWei > 0n && wallets.length > 0;
1089
610
  const hasProfit = profitWei > 0n;
1090
- const nonceOffsets = wallets.map((_, i) => i === maxFlowIndex && hasBribe ? 1 : 0);
611
+ const nonceOffsets = wallets.map((_, i) => (i === maxFlowIndex && hasBribe ? 1 : 0));
1091
612
  // ✅ 方案 A:并行签名所有交易(贿赂、主交易、利润)
1092
613
  const signPromises = [];
1093
614
  if (hasBribe) {
1094
- signPromises.push(buildBribeTransaction(wallets[maxFlowIndex], bribeWei, nonces[maxFlowIndex], gasPrice, chainId, txType)
1095
- .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 })));
1096
616
  }
1097
617
  wallets.forEach((wallet, i) => {
1098
618
  const { txData, txValue } = buildV3BuyTxData(wallet, flowAmounts[i]);
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 })));
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 })));
1101
630
  });
1102
631
  const signedResults = await Promise.all(signPromises);
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);
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);
1105
637
  // ✅ 检查是否使用分布式利润模式
1106
638
  const profitMode = config.profitMode || 'single';
1107
639
  const skipProfit = config.skipProfit === true;
1108
640
  const profitAddr = getProfitRecipient();
1109
- console.log('🔧 [SDK directV3BatchBuy] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', wallets.length);
1110
641
  // 利润多跳转账
1111
642
  let profitTxs = [];
1112
643
  let profitHopWallets;
@@ -1120,9 +651,7 @@ export async function directV3BatchBuy(params) {
1120
651
  profitHopWallets = [];
1121
652
  // 计算每个钱包的利润(按比例分配)
1122
653
  for (let i = 0; i < wallets.length; i++) {
1123
- const walletProfit = totalFlowWei > 0n
1124
- ? (profitWei * flowAmounts[i]) / totalFlowWei
1125
- : 0n;
654
+ const walletProfit = totalFlowWei > 0n ? (profitWei * flowAmounts[i]) / totalFlowWei : 0n;
1126
655
  if (walletProfit > 0n) {
1127
656
  const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
1128
657
  const profitResult = await buildProfitHopTransactions({
@@ -1134,7 +663,7 @@ export async function directV3BatchBuy(params) {
1134
663
  gasPrice,
1135
664
  chainId,
1136
665
  txType,
1137
- startNonce: walletProfitNonce
666
+ startNonce: walletProfitNonce,
1138
667
  });
1139
668
  profitTxs.push(...profitResult.signedTransactions);
1140
669
  if (profitResult.hopWallets) {
@@ -1179,15 +708,15 @@ export async function directV3BatchSell(params) {
1179
708
  const wrappedNative = getWrappedNative(chain);
1180
709
  const useLegacyRouter = isLegacySwapRouter(chain, routerAddress);
1181
710
  const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
1182
- const wallets = privateKeys.map(pk => new Wallet(pk, provider));
711
+ const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
1183
712
  const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
1184
713
  // ✅ 并行获取所有 RPC 数据
1185
714
  const [balances, nonces, gasPrice] = await Promise.all([
1186
- Promise.all(wallets.map(w => tokenContract.balanceOf(w.address))),
715
+ Promise.all(wallets.map((w) => tokenContract.balanceOf(w.address))),
1187
716
  startNonces && startNonces.length === wallets.length
1188
717
  ? Promise.resolve(startNonces)
1189
718
  : new NonceManager(provider).getNextNoncesForWallets(wallets),
1190
- getGasPrice(provider, config)
719
+ getGasPrice(provider, config),
1191
720
  ]);
1192
721
  const gasLimit = getGasLimit(config, 350000);
1193
722
  const txType = config.txType ?? 0;
@@ -1213,19 +742,27 @@ export async function directV3BatchSell(params) {
1213
742
  if (useNativeOutput) {
1214
743
  // 卖出代币 → 得到 BNB:先获取 V3 报价,再计算利润
1215
744
  const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
1216
- ? await quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: tokenAddress, amountIn: totalSellAmount, fee })
745
+ ? await quoteXLayerV3TokenToNativeBySlot0({
746
+ provider,
747
+ tokenIn: tokenAddress,
748
+ amountIn: totalSellAmount,
749
+ fee,
750
+ })
1217
751
  : await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
1218
- console.log(`[V3 Sell Profit] totalSellAmount: ${totalSellAmount}, estimatedBNBOut: ${estimatedBNBOut}, estimatedBNB: ${ethers.formatEther(estimatedBNBOut)}`);
1219
752
  if (estimatedBNBOut <= 0n)
1220
753
  return 0n;
1221
754
  const profit = calculateProfitAmount(estimatedBNBOut);
1222
- console.log(`[V3 Sell Profit] profit: ${profit}, profitBNB: ${ethers.formatEther(profit)}`);
1223
755
  return profit;
1224
756
  }
1225
757
  else if (quoteToken) {
1226
758
  // 卖出代币 → 得到 ERC20:先获取 V3 报价,再计算利润
1227
759
  const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
1228
- ? await quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: tokenAddress, amountIn: totalSellAmount, fee })
760
+ ? await quoteXLayerV3TokenToNativeBySlot0({
761
+ provider,
762
+ tokenIn: tokenAddress,
763
+ amountIn: totalSellAmount,
764
+ fee,
765
+ })
1229
766
  : await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
1230
767
  if (estimatedBNBOut <= 0n)
1231
768
  return 0n;
@@ -1245,36 +782,69 @@ export async function directV3BatchSell(params) {
1245
782
  // 构建卖出交易数据的辅助函数
1246
783
  const buildV3SellTxData = (wallet, sellAmount) => {
1247
784
  if (useLegacyRouter) {
1248
- 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
+ };
1249
795
  if (useNativeOutput) {
1250
- 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
+ ]);
1251
802
  }
1252
803
  // ✅ 修复:ERC20 输出也需要使用 multicall 包装以传递 deadline
1253
- return routerIface.encodeFunctionData('multicall(bytes[])', [[routerIface.encodeFunctionData('exactInputSingle', [swapParams])]]);
804
+ return routerIface.encodeFunctionData('multicall(bytes[])', [
805
+ [routerIface.encodeFunctionData('exactInputSingle', [swapParams])],
806
+ ]);
1254
807
  }
1255
808
  else {
1256
- 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
+ };
1257
818
  if (useNativeOutput) {
1258
- 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
+ ]);
1259
826
  }
1260
827
  // ✅ 修复:ERC20 输出也需要使用 multicall 包装以传递 deadline
1261
- 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
+ ]);
1262
832
  }
1263
833
  };
1264
834
  const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
1265
835
  const bribeWei = getBribeAmount(config, chain);
1266
836
  const hasBribe = bribeWei > 0n && wallets.length > 0;
1267
- const nonceOffsets = wallets.map((_, i) => i === maxOutputIndex && hasBribe ? 1 : 0);
837
+ const nonceOffsets = wallets.map((_, i) => (i === maxOutputIndex && hasBribe ? 1 : 0));
1268
838
  // ✅ 方案 A:并行签名所有交易(贿赂、卖出)+ 并行获取 ERC20 报价
1269
839
  const signPromises = [];
1270
840
  if (hasBribe) {
1271
- signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType)
1272
- .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 })));
1273
842
  }
1274
843
  wallets.forEach((wallet, i) => {
1275
844
  if (sellAmountsWei[i] <= 0n)
1276
845
  return;
1277
- signPromises.push(wallet.signTransaction({
846
+ signPromises.push(wallet
847
+ .signTransaction({
1278
848
  to: routerAddress,
1279
849
  data: buildV3SellTxData(wallet, sellAmountsWei[i]),
1280
850
  value: 0n,
@@ -1282,13 +852,11 @@ export async function directV3BatchSell(params) {
1282
852
  gasLimit,
1283
853
  ...buildGasFields(txType, gasPrice),
1284
854
  chainId,
1285
- }).then(tx => ({ type: 'swap', index: i, tx })));
855
+ })
856
+ .then((tx) => ({ type: 'swap', index: i, tx })));
1286
857
  });
1287
858
  // ✅ 并行执行:签名 + ERC20 报价
1288
- const [signedResults, nativeProfitWei] = await Promise.all([
1289
- Promise.all(signPromises),
1290
- nativeProfitPromise
1291
- ]);
859
+ const [signedResults, nativeProfitWei] = await Promise.all([Promise.all(signPromises), nativeProfitPromise]);
1292
860
  let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
1293
861
  if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
1294
862
  profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
@@ -1297,7 +865,6 @@ export async function directV3BatchSell(params) {
1297
865
  const profitMode = config.profitMode || 'single';
1298
866
  const skipProfit = config.skipProfit === true;
1299
867
  const profitAddr = getProfitRecipient();
1300
- console.log('🔧 [SDK directV3BatchSell] profitMode:', profitMode, 'skipProfit:', skipProfit, 'wallets:', wallets.length);
1301
868
  // 利润多跳转账
1302
869
  let profitTxs = [];
1303
870
  let profitHopWallets;
@@ -1311,9 +878,7 @@ export async function directV3BatchSell(params) {
1311
878
  profitHopWallets = [];
1312
879
  // 计算每个钱包的利润(按卖出金额比例分配)
1313
880
  for (let i = 0; i < wallets.length; i++) {
1314
- const walletProfit = totalSellAmount > 0n
1315
- ? (profitWei * sellAmountsWei[i]) / totalSellAmount
1316
- : 0n;
881
+ const walletProfit = totalSellAmount > 0n ? (profitWei * sellAmountsWei[i]) / totalSellAmount : 0n;
1317
882
  if (walletProfit > 0n) {
1318
883
  const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
1319
884
  const profitResult = await buildProfitHopTransactions({
@@ -1325,7 +890,7 @@ export async function directV3BatchSell(params) {
1325
890
  gasPrice,
1326
891
  chainId,
1327
892
  txType,
1328
- startNonce: walletProfitNonce
893
+ startNonce: walletProfitNonce,
1329
894
  });
1330
895
  profitTxs.push(...profitResult.signedTransactions);
1331
896
  if (profitResult.hopWallets) {
@@ -1344,8 +909,11 @@ export async function directV3BatchSell(params) {
1344
909
  }
1345
910
  // 按类型分组并按顺序组装
1346
911
  const validResults = signedResults.filter((r) => r !== null);
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);
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);
1349
917
  const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
1350
918
  return {
1351
919
  signedTransactions: signedTxs,
@@ -1358,6 +926,9 @@ export async function directV3BatchSell(params) {
1358
926
  },
1359
927
  };
1360
928
  }
929
+ // ============================================================================
930
+ // 辅助函数:获取 Router 地址
931
+ // ============================================================================
1361
932
  /**
1362
933
  * 根据链和 DEX 获取 Router 地址
1363
934
  */