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