four-flap-meme-sdk 2.2.19 → 2.2.20

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