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,585 +1,15 @@
|
|
|
1
|
-
// ==================== 多跳转账常量(使用统一常量) ====================
|
|
2
|
-
import { GAS_LIMITS, CHAINS } from '../../../shared/constants/index.js';
|
|
3
|
-
const NATIVE_TRANSFER_GAS_LIMIT = GAS_LIMITS.NATIVE_TRANSFER;
|
|
4
|
-
const ERC20_TRANSFER_GAS_LIMIT_HOP = GAS_LIMITS.ERC20_TRANSFER;
|
|
5
|
-
const BRIBE_GAS_LIMIT = GAS_LIMITS.BRIBE;
|
|
6
1
|
/**
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
function generateDisperseHopPaths(targetAddresses, hopCount, provider) {
|
|
10
|
-
if (hopCount <= 0) {
|
|
11
|
-
return targetAddresses.map(addr => ({
|
|
12
|
-
targetAddress: addr,
|
|
13
|
-
hopWallets: [],
|
|
14
|
-
hopWalletsInfo: []
|
|
15
|
-
}));
|
|
16
|
-
}
|
|
17
|
-
return targetAddresses.map(targetAddress => {
|
|
18
|
-
const hopWalletsInfo = generateWallets(hopCount);
|
|
19
|
-
const hopWallets = hopWalletsInfo.map(w => new Wallet(w.privateKey, provider));
|
|
20
|
-
return { targetAddress, hopWallets, hopWalletsInfo };
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* 构建原生代币多跳转账链
|
|
25
|
-
*/
|
|
26
|
-
async function buildNativeHopChain(payer, path, finalAmount, gasPrice, chainId, txType, payerNonce) {
|
|
27
|
-
const signedTxs = [];
|
|
28
|
-
const hopCount = path.hopWallets.length;
|
|
29
|
-
if (hopCount === 0) {
|
|
30
|
-
const tx = {
|
|
31
|
-
to: path.targetAddress,
|
|
32
|
-
value: finalAmount,
|
|
33
|
-
nonce: payerNonce,
|
|
34
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
35
|
-
chainId,
|
|
36
|
-
type: txType
|
|
37
|
-
};
|
|
38
|
-
if (txType === 2) {
|
|
39
|
-
tx.maxFeePerGas = gasPrice;
|
|
40
|
-
tx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
tx.gasPrice = gasPrice;
|
|
44
|
-
}
|
|
45
|
-
signedTxs.push(await payer.signTransaction(tx));
|
|
46
|
-
return signedTxs;
|
|
47
|
-
}
|
|
48
|
-
const hopGasCost = NATIVE_TRANSFER_GAS_LIMIT * gasPrice;
|
|
49
|
-
// 计算每跳需要的金额
|
|
50
|
-
const amountsPerHop = [];
|
|
51
|
-
for (let i = 0; i < hopCount; i++) {
|
|
52
|
-
const remainingHops = hopCount - i;
|
|
53
|
-
amountsPerHop.push(finalAmount + hopGasCost * BigInt(remainingHops));
|
|
54
|
-
}
|
|
55
|
-
// payer → hop1
|
|
56
|
-
const firstTx = {
|
|
57
|
-
to: path.hopWallets[0].address,
|
|
58
|
-
value: amountsPerHop[0],
|
|
59
|
-
nonce: payerNonce,
|
|
60
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
61
|
-
chainId,
|
|
62
|
-
type: txType
|
|
63
|
-
};
|
|
64
|
-
if (txType === 2) {
|
|
65
|
-
firstTx.maxFeePerGas = gasPrice;
|
|
66
|
-
firstTx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
firstTx.gasPrice = gasPrice;
|
|
70
|
-
}
|
|
71
|
-
signedTxs.push(await payer.signTransaction(firstTx));
|
|
72
|
-
// hop1 → hop2 → ... → target
|
|
73
|
-
for (let i = 0; i < hopCount; i++) {
|
|
74
|
-
const fromWallet = path.hopWallets[i];
|
|
75
|
-
const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
|
|
76
|
-
const amount = i === hopCount - 1 ? finalAmount : amountsPerHop[i + 1];
|
|
77
|
-
const tx = {
|
|
78
|
-
to: toAddress,
|
|
79
|
-
value: amount,
|
|
80
|
-
nonce: 0,
|
|
81
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
82
|
-
chainId,
|
|
83
|
-
type: txType
|
|
84
|
-
};
|
|
85
|
-
if (txType === 2) {
|
|
86
|
-
tx.maxFeePerGas = gasPrice;
|
|
87
|
-
tx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
tx.gasPrice = gasPrice;
|
|
91
|
-
}
|
|
92
|
-
signedTxs.push(await fromWallet.signTransaction(tx));
|
|
93
|
-
}
|
|
94
|
-
return signedTxs;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* 构建 ERC20 多跳转账链(需要配合 BNB 多跳使用)
|
|
98
|
-
*/
|
|
99
|
-
async function buildERC20HopChain(payer, path, erc20Address, erc20Amount, gasPrice, chainId, txType, payerNonce) {
|
|
100
|
-
const signedTxs = [];
|
|
101
|
-
const hopCount = path.hopWallets.length;
|
|
102
|
-
const erc20Interface = new ethers.Interface(ERC20_ABI);
|
|
103
|
-
if (hopCount === 0) {
|
|
104
|
-
const data = erc20Interface.encodeFunctionData('transfer', [path.targetAddress, erc20Amount]);
|
|
105
|
-
const tx = {
|
|
106
|
-
to: erc20Address,
|
|
107
|
-
data,
|
|
108
|
-
value: 0n,
|
|
109
|
-
nonce: payerNonce,
|
|
110
|
-
gasLimit: ERC20_TRANSFER_GAS_LIMIT_HOP,
|
|
111
|
-
chainId,
|
|
112
|
-
type: txType
|
|
113
|
-
};
|
|
114
|
-
if (txType === 2) {
|
|
115
|
-
tx.maxFeePerGas = gasPrice;
|
|
116
|
-
tx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
tx.gasPrice = gasPrice;
|
|
120
|
-
}
|
|
121
|
-
signedTxs.push(await payer.signTransaction(tx));
|
|
122
|
-
return signedTxs;
|
|
123
|
-
}
|
|
124
|
-
// payer → hop1
|
|
125
|
-
const firstData = erc20Interface.encodeFunctionData('transfer', [path.hopWallets[0].address, erc20Amount]);
|
|
126
|
-
const firstTx = {
|
|
127
|
-
to: erc20Address,
|
|
128
|
-
data: firstData,
|
|
129
|
-
value: 0n,
|
|
130
|
-
nonce: payerNonce,
|
|
131
|
-
gasLimit: ERC20_TRANSFER_GAS_LIMIT_HOP,
|
|
132
|
-
chainId,
|
|
133
|
-
type: txType
|
|
134
|
-
};
|
|
135
|
-
if (txType === 2) {
|
|
136
|
-
firstTx.maxFeePerGas = gasPrice;
|
|
137
|
-
firstTx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
firstTx.gasPrice = gasPrice;
|
|
141
|
-
}
|
|
142
|
-
signedTxs.push(await payer.signTransaction(firstTx));
|
|
143
|
-
// hop1 → hop2 → ... → target (nonce=1,nonce=0 用于 BNB 转发)
|
|
144
|
-
for (let i = 0; i < hopCount; i++) {
|
|
145
|
-
const fromWallet = path.hopWallets[i];
|
|
146
|
-
const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
|
|
147
|
-
const data = erc20Interface.encodeFunctionData('transfer', [toAddress, erc20Amount]);
|
|
148
|
-
const tx = {
|
|
149
|
-
to: erc20Address,
|
|
150
|
-
data,
|
|
151
|
-
value: 0n,
|
|
152
|
-
nonce: 1, // nonce=0 已用于 BNB 转发
|
|
153
|
-
gasLimit: ERC20_TRANSFER_GAS_LIMIT_HOP,
|
|
154
|
-
chainId,
|
|
155
|
-
type: txType
|
|
156
|
-
};
|
|
157
|
-
if (txType === 2) {
|
|
158
|
-
tx.maxFeePerGas = gasPrice;
|
|
159
|
-
tx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
tx.gasPrice = gasPrice;
|
|
163
|
-
}
|
|
164
|
-
signedTxs.push(await fromWallet.signTransaction(tx));
|
|
165
|
-
}
|
|
166
|
-
return signedTxs;
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* 构建 BNB 多跳转账链(为 ERC20 中间钱包预留 gas)
|
|
170
|
-
*/
|
|
171
|
-
async function buildBNBHopChainForERC20(payer, path, finalGasAmount, gasPrice, chainId, txType, payerNonce) {
|
|
172
|
-
const signedTxs = [];
|
|
173
|
-
const hopCount = path.hopWallets.length;
|
|
174
|
-
if (hopCount === 0) {
|
|
175
|
-
// 无多跳时不需要转 gas
|
|
176
|
-
return signedTxs;
|
|
177
|
-
}
|
|
178
|
-
const hopGasCost = NATIVE_TRANSFER_GAS_LIMIT * gasPrice;
|
|
179
|
-
const erc20GasCost = ERC20_TRANSFER_GAS_LIMIT_HOP * gasPrice;
|
|
180
|
-
// 每个中间钱包需要: BNB 转发 gas + ERC20 转发 gas
|
|
181
|
-
const gasPerHop = hopGasCost + erc20GasCost * 2n; // 2倍安全系数
|
|
182
|
-
// 计算每跳需要的金额
|
|
183
|
-
const amountsPerHop = [];
|
|
184
|
-
for (let i = 0; i < hopCount; i++) {
|
|
185
|
-
const remainingHops = hopCount - i;
|
|
186
|
-
amountsPerHop.push(finalGasAmount + gasPerHop * BigInt(remainingHops));
|
|
187
|
-
}
|
|
188
|
-
// payer → hop1
|
|
189
|
-
const firstTx = {
|
|
190
|
-
to: path.hopWallets[0].address,
|
|
191
|
-
value: amountsPerHop[0],
|
|
192
|
-
nonce: payerNonce,
|
|
193
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
194
|
-
chainId,
|
|
195
|
-
type: txType
|
|
196
|
-
};
|
|
197
|
-
if (txType === 2) {
|
|
198
|
-
firstTx.maxFeePerGas = gasPrice;
|
|
199
|
-
firstTx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
firstTx.gasPrice = gasPrice;
|
|
203
|
-
}
|
|
204
|
-
signedTxs.push(await payer.signTransaction(firstTx));
|
|
205
|
-
// hop1 → hop2 → ... → target (nonce=0)
|
|
206
|
-
for (let i = 0; i < hopCount; i++) {
|
|
207
|
-
const fromWallet = path.hopWallets[i];
|
|
208
|
-
const toAddress = i === hopCount - 1 ? path.targetAddress : path.hopWallets[i + 1].address;
|
|
209
|
-
const amount = i === hopCount - 1 ? finalGasAmount : amountsPerHop[i + 1];
|
|
210
|
-
const tx = {
|
|
211
|
-
to: toAddress,
|
|
212
|
-
value: amount,
|
|
213
|
-
nonce: 0,
|
|
214
|
-
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
215
|
-
chainId,
|
|
216
|
-
type: txType
|
|
217
|
-
};
|
|
218
|
-
if (txType === 2) {
|
|
219
|
-
tx.maxFeePerGas = gasPrice;
|
|
220
|
-
tx.maxPriorityFeePerGas = gasPrice / 10n || 1n;
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
tx.gasPrice = gasPrice;
|
|
224
|
-
}
|
|
225
|
-
signedTxs.push(await fromWallet.signTransaction(tx));
|
|
226
|
-
}
|
|
227
|
-
return signedTxs;
|
|
228
|
-
}
|
|
229
|
-
// ==================== 工具函数 ====================
|
|
230
|
-
function createPancakeContext(config) {
|
|
231
|
-
const chainId = config.chainId ?? 56;
|
|
232
|
-
const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
|
|
233
|
-
chainId,
|
|
234
|
-
name: 'BSC'
|
|
235
|
-
});
|
|
236
|
-
return { chainId, provider };
|
|
237
|
-
}
|
|
238
|
-
async function quoteSellOutput({ routeParams, sellAmountWei, provider, v2RouterAddress }) {
|
|
239
|
-
// ==================== V2 报价 ====================
|
|
240
|
-
if (routeParams.routeType === 'v2') {
|
|
241
|
-
const { v2Path } = routeParams;
|
|
242
|
-
const tokenIn = v2Path[0];
|
|
243
|
-
const tokenOut = v2Path[v2Path.length - 1];
|
|
244
|
-
const result = await quoteV2(provider, tokenIn, tokenOut, sellAmountWei, 'BSC', v2RouterAddress);
|
|
245
|
-
if (result.amountOut > 0n) {
|
|
246
|
-
return { estimatedBNBOut: result.amountOut };
|
|
247
|
-
}
|
|
248
|
-
throw new Error('V2 报价失败: 所有路径均无效');
|
|
249
|
-
}
|
|
250
|
-
// ==================== V3 单跳报价 ====================
|
|
251
|
-
if (routeParams.routeType === 'v3-single') {
|
|
252
|
-
const params = routeParams;
|
|
253
|
-
// ✅ 只用 V3 报价,不 fallback 到 V2
|
|
254
|
-
const result = await quoteV3(provider, params.v3TokenIn, params.v3TokenOut, sellAmountWei, 'BSC', params.v3Fee);
|
|
255
|
-
if (result.amountOut > 0n) {
|
|
256
|
-
return { estimatedBNBOut: result.amountOut };
|
|
257
|
-
}
|
|
258
|
-
// ❌ V3 报价失败时不再 fallback 到 V2,因为价格可能差异很大
|
|
259
|
-
throw new Error(`V3 单跳报价失败: tokenIn=${params.v3TokenIn}, tokenOut=${params.v3TokenOut}, fee=${params.v3Fee}`);
|
|
260
|
-
}
|
|
261
|
-
// ==================== V3 多跳报价 ====================
|
|
262
|
-
if (routeParams.routeType === 'v3-multi') {
|
|
263
|
-
const params = routeParams;
|
|
264
|
-
// ✅ V3 多跳:只用 V3 报价,不 fallback 到 V2
|
|
265
|
-
if (params.v3LpAddresses && params.v3LpAddresses.length > 0) {
|
|
266
|
-
const tokenIn = params.v3ExactTokenIn;
|
|
267
|
-
const WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
|
|
268
|
-
const result = await quoteV3(provider, tokenIn, WBNB, sellAmountWei, 'BSC');
|
|
269
|
-
if (result.amountOut > 0n) {
|
|
270
|
-
return { estimatedBNBOut: result.amountOut };
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
// ❌ V3 多跳报价失败时不再 fallback 到 V2,因为价格可能差异很大
|
|
274
|
-
throw new Error(`V3 多跳报价失败: LPs=${params.v3LpAddresses?.join(', ')}, tokenIn=${params.v3ExactTokenIn}`);
|
|
275
|
-
}
|
|
276
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
277
|
-
throw new Error(`不支持的路由类型: ${routeParams.routeType}`);
|
|
278
|
-
}
|
|
279
|
-
async function buildSwapTransactions({ routeParams, sellAmountWei, buyAmountBNB, buyer, seller, useNativeToken = true, v2RouterAddress }) {
|
|
280
|
-
const deadline = getDeadline();
|
|
281
|
-
const buyValue = useNativeToken ? buyAmountBNB + FLAT_FEE : 0n;
|
|
282
|
-
if (routeParams.routeType === 'v2') {
|
|
283
|
-
const { v2Path } = routeParams;
|
|
284
|
-
const reversePath = [...v2Path].reverse();
|
|
285
|
-
const routerAddr = v2RouterAddress || PANCAKE_V2_ROUTER_ADDRESS;
|
|
286
|
-
const v2RouterSeller = new Contract(routerAddr, PANCAKE_V2_ROUTER_ABI, seller);
|
|
287
|
-
const v2RouterBuyer = new Contract(routerAddr, PANCAKE_V2_ROUTER_ABI, buyer);
|
|
288
|
-
let sellUnsigned;
|
|
289
|
-
let buyUnsigned;
|
|
290
|
-
if (useNativeToken) {
|
|
291
|
-
// ✅ 原生代币模式(BNB)
|
|
292
|
-
// 卖出:Token → WBNB → BNB
|
|
293
|
-
sellUnsigned = await v2RouterSeller.swapExactTokensForETHSupportingFeeOnTransferTokens.populateTransaction(sellAmountWei, 0n, v2Path, seller.address, deadline);
|
|
294
|
-
// 买入:BNB → WBNB → Token
|
|
295
|
-
buyUnsigned = await v2RouterBuyer.swapExactETHForTokensSupportingFeeOnTransferTokens.populateTransaction(0n, reversePath, buyer.address, deadline, { value: buyValue });
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
// ✅ ERC20 模式(如 USDT)
|
|
299
|
-
// 卖出:Token → USDT
|
|
300
|
-
sellUnsigned = await v2RouterSeller.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(sellAmountWei, 0n, v2Path, seller.address, deadline);
|
|
301
|
-
// 买入:USDT → Token
|
|
302
|
-
buyUnsigned = await v2RouterBuyer.swapExactTokensForTokensSupportingFeeOnTransferTokens.populateTransaction(buyAmountBNB, // USDT 数量
|
|
303
|
-
0n, reversePath, buyer.address, deadline);
|
|
304
|
-
}
|
|
305
|
-
return { sellUnsigned, buyUnsigned };
|
|
306
|
-
}
|
|
307
|
-
if (routeParams.routeType === 'v3-single') {
|
|
308
|
-
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
309
|
-
const v3RouterIface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
|
|
310
|
-
const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
|
|
311
|
-
const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
|
|
312
|
-
// 卖出:Token → WBNB,需要 unwrapWETH9
|
|
313
|
-
const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
|
|
314
|
-
tokenIn: v3TokenIn,
|
|
315
|
-
tokenOut: v3TokenOut,
|
|
316
|
-
fee: v3Fee,
|
|
317
|
-
recipient: PANCAKE_V3_ROUTER_ADDRESS, // 先发给 Router
|
|
318
|
-
amountIn: sellAmountWei,
|
|
319
|
-
amountOutMinimum: 0n,
|
|
320
|
-
sqrtPriceLimitX96: 0n
|
|
321
|
-
}]);
|
|
322
|
-
const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
|
|
323
|
-
const sellUnsigned = await v3RouterSeller.multicall.populateTransaction(deadline, [sellSwapData, sellUnwrapData]);
|
|
324
|
-
// 买入:WBNB → Token
|
|
325
|
-
const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [{
|
|
326
|
-
tokenIn: v3TokenOut,
|
|
327
|
-
tokenOut: v3TokenIn,
|
|
328
|
-
fee: v3Fee,
|
|
329
|
-
recipient: buyer.address,
|
|
330
|
-
amountIn: buyAmountBNB,
|
|
331
|
-
amountOutMinimum: 0n,
|
|
332
|
-
sqrtPriceLimitX96: 0n
|
|
333
|
-
}]);
|
|
334
|
-
const buyUnsigned = await v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
|
|
335
|
-
return { sellUnsigned, buyUnsigned };
|
|
336
|
-
}
|
|
337
|
-
// V3 多跳暂不支持官方合约
|
|
338
|
-
throw new Error('V3 多跳路由暂不支持官方合约,请使用 V2 路由或 V3 单跳');
|
|
339
|
-
}
|
|
340
|
-
async function calculateBuyerBudget({ buyer, quotedBNBOut, reserveGasBNB, useNativeToken = true, quoteToken, quoteTokenDecimals = 18, provider }) {
|
|
341
|
-
const reserveGas = ethers.parseEther((reserveGasBNB ?? 0.0005).toString());
|
|
342
|
-
// ✅ 已移除滑点保护:直接使用报价金额
|
|
343
|
-
const buyAmountBNB = quotedBNBOut;
|
|
344
|
-
// ✅ 根据是否使用原生代币获取不同的余额
|
|
345
|
-
let buyerBalance;
|
|
346
|
-
if (useNativeToken) {
|
|
347
|
-
buyerBalance = await buyer.provider.getBalance(buyer.address);
|
|
348
|
-
const requiredBalance = buyAmountBNB + FLAT_FEE + reserveGas;
|
|
349
|
-
if (buyerBalance < requiredBalance) {
|
|
350
|
-
throw new Error(`买方余额不足: 需要 ${ethers.formatEther(requiredBalance)} BNB, 实际 ${ethers.formatEther(buyerBalance)} BNB`);
|
|
351
|
-
}
|
|
352
|
-
return { buyerBalance, reserveGas, requiredBalance, buyAmountBNB, useNativeToken };
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
// ERC20 代币余额
|
|
356
|
-
const erc20 = new Contract(quoteToken, ERC20_BALANCE_OF_ABI, provider || buyer.provider);
|
|
357
|
-
buyerBalance = await erc20.balanceOf(buyer.address);
|
|
358
|
-
const requiredBalance = buyAmountBNB + FLAT_FEE; // ERC20 不需要预留 Gas 在代币余额中
|
|
359
|
-
if (buyerBalance < requiredBalance) {
|
|
360
|
-
throw new Error(`买方代币余额不足: 需要 ${ethers.formatUnits(requiredBalance, quoteTokenDecimals)}, 实际 ${ethers.formatUnits(buyerBalance, quoteTokenDecimals)}`);
|
|
361
|
-
}
|
|
362
|
-
// ✅ ERC20 购买时,还需要检查买方是否有足够 BNB 支付 Gas
|
|
363
|
-
const buyerBnbBalance = await buyer.provider.getBalance(buyer.address);
|
|
364
|
-
if (buyerBnbBalance < reserveGas) {
|
|
365
|
-
throw new Error(`买方 BNB 余额不足 (用于支付 Gas): 需要 ${ethers.formatEther(reserveGas)} BNB, 实际 ${ethers.formatEther(buyerBnbBalance)} BNB`);
|
|
366
|
-
}
|
|
367
|
-
return { buyerBalance, reserveGas, requiredBalance, buyAmountBNB, useNativeToken };
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
/**
|
|
371
|
-
* ✅ 从前端传入的 startNonces 构建 NoncePlan(用于性能优化)
|
|
372
|
-
* 顺序:[sellerBaseNonce, buyerNonce]
|
|
373
|
-
*/
|
|
374
|
-
function buildNoncePlanFromNonces(startNonces, sameAddress, approvalExists, profitNeeded, needBribeTx) {
|
|
375
|
-
if (sameAddress) {
|
|
376
|
-
let idx = 0;
|
|
377
|
-
const bribeNonce = needBribeTx ? startNonces[0] + idx++ : undefined;
|
|
378
|
-
if (approvalExists)
|
|
379
|
-
idx++;
|
|
380
|
-
const sellerNonce = startNonces[0] + idx++;
|
|
381
|
-
const buyerNonce = startNonces[0] + idx++;
|
|
382
|
-
const profitNonce = profitNeeded ? startNonces[0] + idx : undefined;
|
|
383
|
-
return { sellerNonce, buyerNonce, bribeNonce, profitNonce };
|
|
384
|
-
}
|
|
385
|
-
let sellerIdx = 0;
|
|
386
|
-
const bribeNonce = needBribeTx ? startNonces[0] + sellerIdx++ : undefined;
|
|
387
|
-
if (approvalExists)
|
|
388
|
-
sellerIdx++;
|
|
389
|
-
const sellerNonce = startNonces[0] + sellerIdx++;
|
|
390
|
-
const profitNonce = profitNeeded ? startNonces[0] + sellerIdx : undefined;
|
|
391
|
-
const buyerNonce = startNonces[1];
|
|
392
|
-
return { sellerNonce, buyerNonce, bribeNonce, profitNonce };
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* ✅ 规划 nonce
|
|
396
|
-
* 交易顺序:贿赂 → 授权 → 卖出 → 买入 → 利润
|
|
397
|
-
* 贿赂和利润由卖方发送
|
|
398
|
-
*/
|
|
399
|
-
async function planNonces({ seller, buyer, sameAddress, approvalExists, profitNeeded, needBribeTx, nonceManager }) {
|
|
400
|
-
if (sameAddress) {
|
|
401
|
-
// 同一地址:贿赂(可选) + 授权(可选) + 卖出 + 买入 + 利润(可选)
|
|
402
|
-
const txCount = countTruthy([needBribeTx, approvalExists, true, true, profitNeeded]);
|
|
403
|
-
const nonces = await nonceManager.getNextNonceBatch(buyer, txCount);
|
|
404
|
-
let idx = 0;
|
|
405
|
-
const bribeNonce = needBribeTx ? nonces[idx++] : undefined;
|
|
406
|
-
if (approvalExists)
|
|
407
|
-
idx++;
|
|
408
|
-
const sellerNonce = nonces[idx++];
|
|
409
|
-
const buyerNonce = nonces[idx++];
|
|
410
|
-
const profitNonce = profitNeeded ? nonces[idx] : undefined;
|
|
411
|
-
return { sellerNonce, buyerNonce, bribeNonce, profitNonce };
|
|
412
|
-
}
|
|
413
|
-
if (needBribeTx || approvalExists || profitNeeded) {
|
|
414
|
-
// 卖方需要多个 nonce:贿赂(可选) + 授权(可选) + 卖出 + 利润(可选)
|
|
415
|
-
const sellerTxCount = countTruthy([needBribeTx, approvalExists, true, profitNeeded]);
|
|
416
|
-
// ✅ 并行获取 seller 和 buyer 的 nonce
|
|
417
|
-
const [sellerNonces, buyerNonce] = await Promise.all([
|
|
418
|
-
nonceManager.getNextNonceBatch(seller, sellerTxCount),
|
|
419
|
-
nonceManager.getNextNonce(buyer)
|
|
420
|
-
]);
|
|
421
|
-
let idx = 0;
|
|
422
|
-
const bribeNonce = needBribeTx ? sellerNonces[idx++] : undefined;
|
|
423
|
-
if (approvalExists)
|
|
424
|
-
idx++;
|
|
425
|
-
const sellerNonce = sellerNonces[idx++];
|
|
426
|
-
const profitNonce = profitNeeded ? sellerNonces[idx] : undefined;
|
|
427
|
-
return { sellerNonce, buyerNonce, bribeNonce, profitNonce };
|
|
428
|
-
}
|
|
429
|
-
// ✅ 并行获取 seller 和 buyer 的 nonce
|
|
430
|
-
const [sellerNonce, buyerNonce] = await Promise.all([
|
|
431
|
-
nonceManager.getNextNonce(seller),
|
|
432
|
-
nonceManager.getNextNonce(buyer)
|
|
433
|
-
]);
|
|
434
|
-
return { sellerNonce, buyerNonce };
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* 根据 userType 计算利润率
|
|
438
|
-
*/
|
|
439
|
-
function getProfitRateBps(userType) {
|
|
440
|
-
if (userType === 'v0') {
|
|
441
|
-
return getProfitRateBpsShared('v0Single'); // 0.06%
|
|
442
|
-
}
|
|
443
|
-
else if (userType === 'v1') {
|
|
444
|
-
return getProfitRateBpsShared('v1Single'); // 0.05%
|
|
445
|
-
}
|
|
446
|
-
return getProfitRateBpsShared('v0Single'); // 默认 0.06%
|
|
447
|
-
}
|
|
448
|
-
function calculateProfitAmount(estimatedBNBOut, userType) {
|
|
449
|
-
if (estimatedBNBOut <= 0n) {
|
|
450
|
-
return 0n;
|
|
451
|
-
}
|
|
452
|
-
const rateBps = getProfitRateBps(userType);
|
|
453
|
-
return (estimatedBNBOut * BigInt(rateBps)) / 10000n;
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* ✅ 获取 ERC20 代币 → 原生代币(BNB)的报价
|
|
457
|
-
* 用于将 ERC20 利润转换为 BNB
|
|
458
|
-
* 使用共享的报价函数
|
|
459
|
-
*/
|
|
460
|
-
async function getERC20ToNativeQuote(provider, tokenAddress, tokenAmount, version = 'v2', fee) {
|
|
461
|
-
if (tokenAmount <= 0n)
|
|
462
|
-
return 0n;
|
|
463
|
-
const tokenLower = tokenAddress.toLowerCase();
|
|
464
|
-
const wbnbLower = WBNB_ADDRESS.toLowerCase();
|
|
465
|
-
// 如果代币本身就是 WBNB,直接返回
|
|
466
|
-
if (tokenLower === wbnbLower) {
|
|
467
|
-
return tokenAmount;
|
|
468
|
-
}
|
|
469
|
-
// 使用共享的报价函数
|
|
470
|
-
if (version === 'v3') {
|
|
471
|
-
const result = await quoteV3(provider, tokenAddress, WBNB_ADDRESS, tokenAmount, 'BSC', fee);
|
|
472
|
-
if (result.amountOut > 0n) {
|
|
473
|
-
return result.amountOut;
|
|
474
|
-
}
|
|
475
|
-
console.warn(`[getERC20ToNativeQuote] V3 报价失败`);
|
|
476
|
-
return 0n;
|
|
477
|
-
}
|
|
478
|
-
// V2 报价
|
|
479
|
-
const result = await quoteV2(provider, tokenAddress, WBNB_ADDRESS, tokenAmount, 'BSC');
|
|
480
|
-
if (result.amountOut > 0n) {
|
|
481
|
-
return result.amountOut;
|
|
482
|
-
}
|
|
483
|
-
console.warn(`[getERC20ToNativeQuote] V2 报价失败`);
|
|
484
|
-
return 0n;
|
|
485
|
-
}
|
|
486
|
-
async function validateFinalBalances({ sameAddress, buyerBalance, buyAmountBNB, reserveGas, gasLimit, gasPrice, useNativeToken = true, quoteTokenDecimals = 18, provider, buyerAddress }) {
|
|
487
|
-
const gasCost = gasLimit * gasPrice;
|
|
488
|
-
if (sameAddress) {
|
|
489
|
-
// 同一地址:需要足够的余额支付两笔交易
|
|
490
|
-
if (useNativeToken) {
|
|
491
|
-
const requiredCombined = buyAmountBNB + FLAT_FEE * 2n + gasCost * 2n;
|
|
492
|
-
if (buyerBalance < requiredCombined) {
|
|
493
|
-
throw new Error(`账户余额不足:\n - 需要: ${ethers.formatEther(requiredCombined)} BNB(含两笔Gas与两笔手续费)\n - 实际: ${ethers.formatEther(buyerBalance)} BNB`);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
else {
|
|
497
|
-
// ERC20:检查代币余额 + BNB Gas 余额
|
|
498
|
-
const requiredToken = buyAmountBNB + FLAT_FEE * 2n;
|
|
499
|
-
if (buyerBalance < requiredToken) {
|
|
500
|
-
throw new Error(`账户代币余额不足:\n - 需要: ${ethers.formatUnits(requiredToken, quoteTokenDecimals)}\n - 实际: ${ethers.formatUnits(buyerBalance, quoteTokenDecimals)}`);
|
|
501
|
-
}
|
|
502
|
-
// 检查 BNB Gas
|
|
503
|
-
if (provider && buyerAddress) {
|
|
504
|
-
const bnbBalance = await provider.getBalance(buyerAddress);
|
|
505
|
-
const requiredGas = gasCost * 2n;
|
|
506
|
-
if (bnbBalance < requiredGas) {
|
|
507
|
-
throw new Error(`账户 BNB 余额不足 (用于支付 Gas):\n - 需要: ${ethers.formatEther(requiredGas)} BNB\n - 实际: ${ethers.formatEther(bnbBalance)} BNB`);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
// 不同地址
|
|
514
|
-
if (useNativeToken) {
|
|
515
|
-
const requiredBuyer = buyAmountBNB + FLAT_FEE + reserveGas;
|
|
516
|
-
if (buyerBalance < requiredBuyer) {
|
|
517
|
-
throw new Error(`买方余额不足:\n - 需要: ${ethers.formatEther(requiredBuyer)} BNB\n - 实际: ${ethers.formatEther(buyerBalance)} BNB`);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
// ERC20 余额已在 calculateBuyerBudget 中检查过
|
|
521
|
-
}
|
|
522
|
-
function countTruthy(values) {
|
|
523
|
-
return values.filter(Boolean).length;
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* PancakeSwap V2/V3 通用捆绑换手(Merkle Bundle)
|
|
527
|
-
*
|
|
528
|
-
* 功能:钱包A卖出代币 → 钱包B买入相同数量 → 原子执行
|
|
529
|
-
* 适用于所有已迁移到外盘的代币(不区分Four/Flap)
|
|
2
|
+
* bundle-swap - 主函数
|
|
530
3
|
*/
|
|
4
|
+
import { GAS_LIMITS, CHAINS, getProfitRecipient } from '../../../shared/constants/index.js';
|
|
531
5
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
532
6
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
533
|
-
import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../../utils/bundle-helpers.js';
|
|
534
|
-
import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA } from '../../../
|
|
535
|
-
import {
|
|
536
|
-
import {
|
|
537
|
-
import { V2_ROUTER_ABI, V3_ROUTER02_ABI, ERC20_BALANCE_ABI, ERC20_ABI } from '../../../shared/abis/common.js';
|
|
538
|
-
import { generateWallets } from '../../../utils/wallet.js';
|
|
539
|
-
/**
|
|
540
|
-
* 获取 Gas Limit
|
|
541
|
-
*/
|
|
542
|
-
function getGasLimit(config, defaultGas = 800000) {
|
|
543
|
-
if (config.gasLimit !== undefined) {
|
|
544
|
-
return typeof config.gasLimit === 'bigint' ? config.gasLimit : BigInt(config.gasLimit);
|
|
545
|
-
}
|
|
546
|
-
const multiplier = config.gasLimitMultiplier ?? 1.0;
|
|
547
|
-
const calculatedGas = Math.ceil(defaultGas * multiplier);
|
|
548
|
-
return BigInt(calculatedGas);
|
|
549
|
-
}
|
|
550
|
-
async function getGasPrice(provider, config) {
|
|
551
|
-
const feeData = await provider.getFeeData();
|
|
552
|
-
let gasPrice = feeData.gasPrice || ethers.parseUnits('3', 'gwei');
|
|
553
|
-
if (config.minGasPriceGwei) {
|
|
554
|
-
const minGas = ethers.parseUnits(config.minGasPriceGwei.toString(), 'gwei');
|
|
555
|
-
if (gasPrice < minGas)
|
|
556
|
-
gasPrice = minGas;
|
|
557
|
-
}
|
|
558
|
-
if (config.maxGasPriceGwei) {
|
|
559
|
-
const maxGas = ethers.parseUnits(config.maxGasPriceGwei.toString(), 'gwei');
|
|
560
|
-
if (gasPrice > maxGas)
|
|
561
|
-
gasPrice = maxGas;
|
|
562
|
-
}
|
|
563
|
-
return gasPrice;
|
|
564
|
-
}
|
|
565
|
-
// ✅ ABI 别名(从公共模块导入)
|
|
566
|
-
const PANCAKE_V2_ROUTER_ABI = V2_ROUTER_ABI;
|
|
567
|
-
const PANCAKE_V3_ROUTER_ABI = V3_ROUTER02_ABI;
|
|
568
|
-
const ERC20_BALANCE_OF_ABI = ERC20_BALANCE_ABI;
|
|
569
|
-
// ✅ 使用官方 PancakeSwap Router 地址
|
|
570
|
-
const PANCAKE_V2_ROUTER_ADDRESS = ADDRESSES.BSC.PancakeV2Router;
|
|
571
|
-
const PANCAKE_V3_ROUTER_ADDRESS = ADDRESSES.BSC.PancakeV3Router;
|
|
572
|
-
// 常量
|
|
573
|
-
const FLAT_FEE = 0n;
|
|
574
|
-
const WBNB_ADDRESS = ADDRESSES.BSC.WBNB;
|
|
575
|
-
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
576
|
-
// ✅ ERC20_BALANCE_OF_ABI 已在文件开头定义
|
|
577
|
-
/**
|
|
578
|
-
* PancakeSwap捆绑换手(V2/V3通用)
|
|
579
|
-
* ✅ 支持 quoteToken:传入 USDT 等地址时,卖出得到该代币,买入使用该代币
|
|
580
|
-
*/
|
|
7
|
+
import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
8
|
+
import { ADDRESSES, BLOCKRAZOR_BUILDER_EOA } from '../../../shared/constants/index.js';
|
|
9
|
+
import { ERC20_ABI } from '../../../abis/common.js';
|
|
10
|
+
import { BRIBE_GAS_LIMIT, ERC20_BALANCE_OF_ABI, FLAT_FEE, NATIVE_TRANSFER_GAS_LIMIT, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, ZERO_ADDRESS, buildBNBHopChainForERC20, buildERC20HopChain, buildNativeHopChain, buildNoncePlanFromNonces, buildSwapTransactions, calculateBuyerBudget, calculateProfitAmount, createPancakeContext, generateDisperseHopPaths, getERC20ToNativeQuote, getGasLimit, getGasPrice, planNonces, quoteSellOutput, validateFinalBalances, } from './bundle-swap-helpers.js';
|
|
581
11
|
export async function pancakeBundleSwapMerkle(params) {
|
|
582
|
-
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, startNonces // ✅ 可选:前端预获取的 nonces
|
|
12
|
+
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKey, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, startNonces, // ✅ 可选:前端预获取的 nonces
|
|
583
13
|
} = params;
|
|
584
14
|
// ✅ 判断是否使用原生代币(BNB)或 ERC20 代币(如 USDT)
|
|
585
15
|
const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
|
|
@@ -594,14 +24,14 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
594
24
|
// ✅ 并行获取 gasPrice 和卖出数量
|
|
595
25
|
const [gasPrice, sellAmountResult] = await Promise.all([
|
|
596
26
|
getGasPrice(context.provider, config),
|
|
597
|
-
calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage)
|
|
27
|
+
calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage),
|
|
598
28
|
]);
|
|
599
29
|
const { amount: sellAmountWei, decimals } = sellAmountResult;
|
|
600
30
|
const quoteResult = await quoteSellOutput({
|
|
601
31
|
routeParams,
|
|
602
32
|
sellAmountWei,
|
|
603
33
|
provider: context.provider,
|
|
604
|
-
v2RouterAddress: config.v2RouterAddress
|
|
34
|
+
v2RouterAddress: config.v2RouterAddress,
|
|
605
35
|
});
|
|
606
36
|
const buyerBudget = await calculateBuyerBudget({
|
|
607
37
|
buyer,
|
|
@@ -610,7 +40,7 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
610
40
|
useNativeToken,
|
|
611
41
|
quoteToken,
|
|
612
42
|
quoteTokenDecimals,
|
|
613
|
-
provider: context.provider
|
|
43
|
+
provider: context.provider,
|
|
614
44
|
});
|
|
615
45
|
const swapUnsigned = await buildSwapTransactions({
|
|
616
46
|
routeParams,
|
|
@@ -618,8 +48,9 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
618
48
|
buyAmountBNB: buyerBudget.buyAmountBNB,
|
|
619
49
|
buyer,
|
|
620
50
|
seller,
|
|
51
|
+
tokenAddress,
|
|
621
52
|
useNativeToken,
|
|
622
|
-
v2RouterAddress: config.v2RouterAddress
|
|
53
|
+
v2RouterAddress: config.v2RouterAddress,
|
|
623
54
|
});
|
|
624
55
|
// ✅ 修复:利润计算应基于 BNB 数量,不是 ERC20 数量
|
|
625
56
|
// 如果输出是原生代币(BNB),直接使用报价结果
|
|
@@ -640,9 +71,7 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
640
71
|
// ERC20→BNB 报价完成
|
|
641
72
|
}
|
|
642
73
|
// ✅ 获取贿赂金额
|
|
643
|
-
const bribeAmount = config.bribeAmount && config.bribeAmount > 0
|
|
644
|
-
? ethers.parseEther(String(config.bribeAmount))
|
|
645
|
-
: 0n;
|
|
74
|
+
const bribeAmount = config.bribeAmount && config.bribeAmount > 0 ? ethers.parseEther(String(config.bribeAmount)) : 0n;
|
|
646
75
|
const needBribeTx = bribeAmount > 0n;
|
|
647
76
|
// ✅ 使用共享的 NonceManager 规划 nonce
|
|
648
77
|
// 如果前端传入了 startNonces,直接使用(性能优化)
|
|
@@ -655,48 +84,54 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
655
84
|
approvalExists: false, // ✅ 已移除授权
|
|
656
85
|
profitNeeded: profitAmount > 0n,
|
|
657
86
|
needBribeTx,
|
|
658
|
-
nonceManager
|
|
87
|
+
nonceManager,
|
|
659
88
|
});
|
|
660
89
|
// ✅ 并行签名所有交易
|
|
661
90
|
const signPromises = [];
|
|
662
91
|
// 贿赂交易
|
|
663
92
|
if (needBribeTx && noncePlan.bribeNonce !== undefined) {
|
|
664
|
-
signPromises.push(seller
|
|
93
|
+
signPromises.push(seller
|
|
94
|
+
.signTransaction({
|
|
665
95
|
to: BLOCKRAZOR_BUILDER_EOA,
|
|
666
96
|
value: bribeAmount,
|
|
667
97
|
nonce: noncePlan.bribeNonce,
|
|
668
98
|
gasPrice,
|
|
669
99
|
gasLimit: BRIBE_GAS_LIMIT,
|
|
670
100
|
chainId: context.chainId,
|
|
671
|
-
type: txType
|
|
672
|
-
})
|
|
101
|
+
type: txType,
|
|
102
|
+
})
|
|
103
|
+
.then((tx) => ({ type: 'bribe', tx })));
|
|
673
104
|
}
|
|
674
105
|
// 卖出交易
|
|
675
|
-
signPromises.push(seller
|
|
106
|
+
signPromises.push(seller
|
|
107
|
+
.signTransaction({
|
|
676
108
|
...swapUnsigned.sellUnsigned,
|
|
677
109
|
from: seller.address,
|
|
678
110
|
nonce: noncePlan.sellerNonce,
|
|
679
111
|
gasLimit: finalGasLimit,
|
|
680
112
|
gasPrice,
|
|
681
113
|
chainId: context.chainId,
|
|
682
|
-
type: txType
|
|
683
|
-
})
|
|
114
|
+
type: txType,
|
|
115
|
+
})
|
|
116
|
+
.then((tx) => ({ type: 'sell', tx })));
|
|
684
117
|
// 买入交易
|
|
685
|
-
signPromises.push(buyer
|
|
118
|
+
signPromises.push(buyer
|
|
119
|
+
.signTransaction({
|
|
686
120
|
...swapUnsigned.buyUnsigned,
|
|
687
121
|
from: buyer.address,
|
|
688
122
|
nonce: noncePlan.buyerNonce,
|
|
689
123
|
gasLimit: finalGasLimit,
|
|
690
124
|
gasPrice,
|
|
691
125
|
chainId: context.chainId,
|
|
692
|
-
type: txType
|
|
693
|
-
})
|
|
126
|
+
type: txType,
|
|
127
|
+
})
|
|
128
|
+
.then((tx) => ({ type: 'buy', tx })));
|
|
694
129
|
// ✅ 并行执行所有签名
|
|
695
130
|
const signedResults = await Promise.all(signPromises);
|
|
696
131
|
// 按类型提取结果
|
|
697
|
-
const bribeTx = signedResults.find(r => r.type === 'bribe')?.tx || null;
|
|
698
|
-
const signedSell = signedResults.find(r => r.type === 'sell').tx;
|
|
699
|
-
const signedBuy = signedResults.find(r => r.type === 'buy').tx;
|
|
132
|
+
const bribeTx = signedResults.find((r) => r.type === 'bribe')?.tx || null;
|
|
133
|
+
const signedSell = signedResults.find((r) => r.type === 'sell').tx;
|
|
134
|
+
const signedBuy = signedResults.find((r) => r.type === 'buy').tx;
|
|
700
135
|
nonceManager.clearTemp();
|
|
701
136
|
validateFinalBalances({
|
|
702
137
|
sameAddress,
|
|
@@ -708,7 +143,7 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
708
143
|
useNativeToken,
|
|
709
144
|
quoteTokenDecimals,
|
|
710
145
|
provider: context.provider,
|
|
711
|
-
buyerAddress: buyer.address
|
|
146
|
+
buyerAddress: buyer.address,
|
|
712
147
|
});
|
|
713
148
|
// ✅ 组装顺序:贿赂 → 卖出 → 买入
|
|
714
149
|
const signedTransactions = [];
|
|
@@ -727,7 +162,7 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
727
162
|
gasPrice,
|
|
728
163
|
chainId: context.chainId,
|
|
729
164
|
txType,
|
|
730
|
-
startNonce: noncePlan.profitNonce
|
|
165
|
+
startNonce: noncePlan.profitNonce,
|
|
731
166
|
});
|
|
732
167
|
signedTransactions.push(...profitHopResult.signedTransactions);
|
|
733
168
|
profitHopWallets = profitHopResult.hopWallets; // ✅ 收集利润多跳钱包
|
|
@@ -742,8 +177,8 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
742
177
|
buyAmount: useNativeToken
|
|
743
178
|
? ethers.formatEther(buyerBudget.buyAmountBNB)
|
|
744
179
|
: ethers.formatUnits(buyerBudget.buyAmountBNB, quoteTokenDecimals),
|
|
745
|
-
profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined
|
|
746
|
-
}
|
|
180
|
+
profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined,
|
|
181
|
+
},
|
|
747
182
|
};
|
|
748
183
|
}
|
|
749
184
|
/**
|
|
@@ -755,7 +190,7 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
755
190
|
* 交易顺序:[授权(可选)] → [卖出] → [买入1, 买入2, ..., 买入N] → [利润]
|
|
756
191
|
*/
|
|
757
192
|
export async function pancakeBatchSwapMerkle(params) {
|
|
758
|
-
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerAmounts, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, startNonces // ✅ 可选:前端预获取的 nonces
|
|
193
|
+
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerAmounts, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, startNonces, // ✅ 可选:前端预获取的 nonces
|
|
759
194
|
} = params;
|
|
760
195
|
// ✅ 校验买方数量(最多 24 个)
|
|
761
196
|
const MAX_BUYERS = 24;
|
|
@@ -768,7 +203,7 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
768
203
|
const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
|
|
769
204
|
const context = createPancakeContext(config);
|
|
770
205
|
const seller = new Wallet(sellerPrivateKey, context.provider);
|
|
771
|
-
const buyers = buyerPrivateKeys.map(pk => new Wallet(pk, context.provider));
|
|
206
|
+
const buyers = buyerPrivateKeys.map((pk) => new Wallet(pk, context.provider));
|
|
772
207
|
// ✅ 创建共享资源
|
|
773
208
|
const nonceManager = new NonceManager(context.provider);
|
|
774
209
|
const finalGasLimit = getGasLimit(config);
|
|
@@ -776,14 +211,14 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
776
211
|
// ✅ 并行获取 gasPrice 和卖出数量
|
|
777
212
|
const [gasPrice, sellAmountResult] = await Promise.all([
|
|
778
213
|
getGasPrice(context.provider, config),
|
|
779
|
-
calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage)
|
|
214
|
+
calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage),
|
|
780
215
|
]);
|
|
781
216
|
const { amount: sellAmountWei, decimals } = sellAmountResult;
|
|
782
217
|
const quoteResult = await quoteSellOutput({
|
|
783
218
|
routeParams,
|
|
784
219
|
sellAmountWei,
|
|
785
220
|
provider: context.provider,
|
|
786
|
-
v2RouterAddress: config.v2RouterAddress
|
|
221
|
+
v2RouterAddress: config.v2RouterAddress,
|
|
787
222
|
});
|
|
788
223
|
const estimatedBNBOut = quoteResult.estimatedBNBOut;
|
|
789
224
|
// ✅ 计算每个买方的买入金额(已移除滑点保护:直接使用报价金额)
|
|
@@ -791,14 +226,12 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
791
226
|
const totalBuyAmount = estimatedBNBOut;
|
|
792
227
|
if (buyerAmounts && buyerAmounts.length === buyers.length) {
|
|
793
228
|
// 方式1:使用指定的买入金额(USDT)
|
|
794
|
-
buyAmountsWei = buyerAmounts.map(amt => useNativeToken
|
|
795
|
-
? ethers.parseEther(amt)
|
|
796
|
-
: ethers.parseUnits(amt, quoteTokenDecimals));
|
|
229
|
+
buyAmountsWei = buyerAmounts.map((amt) => useNativeToken ? ethers.parseEther(amt) : ethers.parseUnits(amt, quoteTokenDecimals));
|
|
797
230
|
}
|
|
798
231
|
else if (params.buyerRatios && params.buyerRatios.length === buyers.length) {
|
|
799
232
|
// ✅ 方式2:按比例分配卖出所得
|
|
800
233
|
// buyerRatios 如 [0.3, 0.5, 0.2] 表示第一个买方分 30%,第二个 50%,第三个 20%
|
|
801
|
-
buyAmountsWei = params.buyerRatios.map((ratio
|
|
234
|
+
buyAmountsWei = params.buyerRatios.map((ratio) => {
|
|
802
235
|
// 按比例计算每个买方的金额
|
|
803
236
|
const amount = (totalBuyAmount * BigInt(Math.round(ratio * 10000))) / 10000n;
|
|
804
237
|
return amount;
|
|
@@ -848,15 +281,17 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
848
281
|
else if (routeParams.routeType === 'v3-single') {
|
|
849
282
|
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
850
283
|
const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
|
|
851
|
-
const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [
|
|
284
|
+
const sellSwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [
|
|
285
|
+
{
|
|
852
286
|
tokenIn: v3TokenIn,
|
|
853
287
|
tokenOut: v3TokenOut,
|
|
854
288
|
fee: v3Fee,
|
|
855
289
|
recipient: useNativeToken ? PANCAKE_V3_ROUTER_ADDRESS : seller.address,
|
|
856
290
|
amountIn: sellAmountWei,
|
|
857
291
|
amountOutMinimum: 0n,
|
|
858
|
-
sqrtPriceLimitX96: 0n
|
|
859
|
-
}
|
|
292
|
+
sqrtPriceLimitX96: 0n,
|
|
293
|
+
},
|
|
294
|
+
]);
|
|
860
295
|
if (useNativeToken) {
|
|
861
296
|
// 原生代币:需要 unwrap WBNB
|
|
862
297
|
const sellUnwrapData = v3RouterIface.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
|
|
@@ -889,15 +324,17 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
889
324
|
else if (routeParams.routeType === 'v3-single') {
|
|
890
325
|
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
891
326
|
const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
|
|
892
|
-
const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [
|
|
327
|
+
const buySwapData = v3RouterIface.encodeFunctionData('exactInputSingle', [
|
|
328
|
+
{
|
|
893
329
|
tokenIn: v3TokenOut,
|
|
894
330
|
tokenOut: v3TokenIn,
|
|
895
331
|
fee: v3Fee,
|
|
896
332
|
recipient: buyer.address,
|
|
897
333
|
amountIn: buyAmount,
|
|
898
334
|
amountOutMinimum: 0n,
|
|
899
|
-
sqrtPriceLimitX96: 0n
|
|
900
|
-
}
|
|
335
|
+
sqrtPriceLimitX96: 0n,
|
|
336
|
+
},
|
|
337
|
+
]);
|
|
901
338
|
return await v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
|
|
902
339
|
}
|
|
903
340
|
else {
|
|
@@ -905,16 +342,14 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
905
342
|
}
|
|
906
343
|
}));
|
|
907
344
|
// ✅ 获取贿赂金额
|
|
908
|
-
const bribeAmount = config.bribeAmount && config.bribeAmount > 0
|
|
909
|
-
? ethers.parseEther(String(config.bribeAmount))
|
|
910
|
-
: 0n;
|
|
345
|
+
const bribeAmount = config.bribeAmount && config.bribeAmount > 0 ? ethers.parseEther(String(config.bribeAmount)) : 0n;
|
|
911
346
|
// ✅ 规划 Nonce(贿赂和利润都由卖方发送)
|
|
912
347
|
// 卖方: [贿赂(可选)] → [卖出] → [利润(可选)]
|
|
913
348
|
let bribeNonce;
|
|
914
349
|
let sellNonce;
|
|
915
350
|
let buyerNonces;
|
|
916
351
|
// ✅ 如果前端传入了 startNonces,直接使用(性能优化)
|
|
917
|
-
if (startNonces && startNonces.length >=
|
|
352
|
+
if (startNonces && startNonces.length >= 1 + buyers.length) {
|
|
918
353
|
let sellerIdx = 0;
|
|
919
354
|
if (bribeAmount > 0n) {
|
|
920
355
|
bribeNonce = startNonces[0] + sellerIdx++;
|
|
@@ -927,7 +362,7 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
927
362
|
bribeNonce = await nonceManager.getNextNonce(seller);
|
|
928
363
|
}
|
|
929
364
|
sellNonce = await nonceManager.getNextNonce(seller);
|
|
930
|
-
buyerNonces = await Promise.all(buyers.map(buyer => nonceManager.getNextNonce(buyer)));
|
|
365
|
+
buyerNonces = await Promise.all(buyers.map((buyer) => nonceManager.getNextNonce(buyer)));
|
|
931
366
|
}
|
|
932
367
|
// ✅ 贿赂交易放在首位(由卖方发送)
|
|
933
368
|
let bribeTx = null;
|
|
@@ -939,7 +374,7 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
939
374
|
gasPrice,
|
|
940
375
|
gasLimit: BRIBE_GAS_LIMIT,
|
|
941
376
|
chainId: context.chainId,
|
|
942
|
-
type: txType
|
|
377
|
+
type: txType,
|
|
943
378
|
});
|
|
944
379
|
}
|
|
945
380
|
// ✅ 修复:利润计算应基于 BNB 数量,不是 ERC20 数量
|
|
@@ -957,7 +392,9 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
957
392
|
}
|
|
958
393
|
// 计算利润 nonce
|
|
959
394
|
const profitNonce = profitAmount > 0n
|
|
960
|
-
?
|
|
395
|
+
? startNonces && startNonces.length >= 1
|
|
396
|
+
? sellNonce + 1
|
|
397
|
+
: await nonceManager.getNextNonce(seller)
|
|
961
398
|
: undefined;
|
|
962
399
|
nonceManager.clearTemp();
|
|
963
400
|
// ✅ 并行签名所有交易
|
|
@@ -969,7 +406,7 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
969
406
|
gasLimit: finalGasLimit,
|
|
970
407
|
gasPrice,
|
|
971
408
|
chainId: context.chainId,
|
|
972
|
-
type: txType
|
|
409
|
+
type: txType,
|
|
973
410
|
});
|
|
974
411
|
// 2. 并行签名所有买入交易
|
|
975
412
|
const signedBuyPromises = buyers.map((buyer, i) => buyer.signTransaction({
|
|
@@ -979,13 +416,10 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
979
416
|
gasLimit: finalGasLimit,
|
|
980
417
|
gasPrice,
|
|
981
418
|
chainId: context.chainId,
|
|
982
|
-
type: txType
|
|
419
|
+
type: txType,
|
|
983
420
|
}));
|
|
984
421
|
// 3. 等待所有签名完成
|
|
985
|
-
const [signedSell, ...signedBuys] = await Promise.all([
|
|
986
|
-
signedSellPromise,
|
|
987
|
-
...signedBuyPromises
|
|
988
|
-
]);
|
|
422
|
+
const [signedSell, ...signedBuys] = await Promise.all([signedSellPromise, ...signedBuyPromises]);
|
|
989
423
|
// 4. 按顺序组装交易数组:贿赂 → 卖出 → 买入
|
|
990
424
|
const signedTransactions = [];
|
|
991
425
|
if (bribeTx)
|
|
@@ -1004,7 +438,7 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
1004
438
|
gasPrice,
|
|
1005
439
|
chainId: context.chainId,
|
|
1006
440
|
txType,
|
|
1007
|
-
startNonce: profitNonce
|
|
441
|
+
startNonce: profitNonce,
|
|
1008
442
|
});
|
|
1009
443
|
signedTransactions.push(...profitHopResult.signedTransactions);
|
|
1010
444
|
profitHopWallets = profitHopResult.hopWallets; // ✅ 收集利润多跳钱包
|
|
@@ -1014,13 +448,11 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
1014
448
|
profitHopWallets, // ✅ 导出利润多跳钱包
|
|
1015
449
|
metadata: {
|
|
1016
450
|
sellerAddress: seller.address,
|
|
1017
|
-
buyerAddresses: buyers.map(b => b.address),
|
|
451
|
+
buyerAddresses: buyers.map((b) => b.address),
|
|
1018
452
|
sellAmount: ethers.formatUnits(sellAmountWei, decimals),
|
|
1019
|
-
buyAmounts: buyAmountsWei.map(amt => useNativeToken
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined
|
|
1023
|
-
}
|
|
453
|
+
buyAmounts: buyAmountsWei.map((amt) => useNativeToken ? ethers.formatEther(amt) : ethers.formatUnits(amt, quoteTokenDecimals)),
|
|
454
|
+
profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined,
|
|
455
|
+
},
|
|
1024
456
|
};
|
|
1025
457
|
}
|
|
1026
458
|
/**
|
|
@@ -1039,7 +471,7 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
1039
471
|
*/
|
|
1040
472
|
export async function pancakeQuickBatchSwapMerkle(params) {
|
|
1041
473
|
const { sellerPrivateKey, sellAmount, sellPercentage, buyerPrivateKeys, buyerRatios, buyerAmounts, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, disperseHopCount = 0, // ✅ 转账多跳数(默认0=直接转账)
|
|
1042
|
-
startNonces // ✅ 可选:前端预获取的 nonces
|
|
474
|
+
startNonces, // ✅ 可选:前端预获取的 nonces
|
|
1043
475
|
} = params;
|
|
1044
476
|
// ✅ 判断是否使用原生代币
|
|
1045
477
|
const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
|
|
@@ -1085,7 +517,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1085
517
|
}
|
|
1086
518
|
const context = createPancakeContext(config);
|
|
1087
519
|
const seller = new Wallet(sellerPrivateKey, context.provider);
|
|
1088
|
-
const buyers = buyerPrivateKeys.map(pk => new Wallet(pk, context.provider));
|
|
520
|
+
const buyers = buyerPrivateKeys.map((pk) => new Wallet(pk, context.provider));
|
|
1089
521
|
// ✅ 校验卖出路径输出代币是否匹配
|
|
1090
522
|
let sellOutputToken;
|
|
1091
523
|
if (routeParams.routeType === 'v2') {
|
|
@@ -1125,14 +557,14 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1125
557
|
// ✅ 并行获取 gasPrice 和卖出数量
|
|
1126
558
|
const [gasPrice, sellAmountResult] = await Promise.all([
|
|
1127
559
|
getGasPrice(context.provider, config),
|
|
1128
|
-
calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage)
|
|
560
|
+
calculateSellAmount(context.provider, tokenAddress, seller.address, sellAmount, sellPercentage),
|
|
1129
561
|
]);
|
|
1130
562
|
const { amount: sellAmountWei, decimals } = sellAmountResult;
|
|
1131
563
|
const quoteResult = await quoteSellOutput({
|
|
1132
564
|
routeParams,
|
|
1133
565
|
sellAmountWei,
|
|
1134
566
|
provider: context.provider,
|
|
1135
|
-
v2RouterAddress: config.v2RouterAddress
|
|
567
|
+
v2RouterAddress: config.v2RouterAddress,
|
|
1136
568
|
});
|
|
1137
569
|
const estimatedOutput = quoteResult.estimatedBNBOut;
|
|
1138
570
|
// ✅ 计算利润(万分之六)
|
|
@@ -1152,9 +584,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1152
584
|
let transferAmountsWei;
|
|
1153
585
|
if (buyerAmounts && buyerAmounts.length === buyers.length) {
|
|
1154
586
|
// 数量模式
|
|
1155
|
-
transferAmountsWei = buyerAmounts.map(amt => useNativeToken
|
|
1156
|
-
? ethers.parseEther(amt)
|
|
1157
|
-
: ethers.parseUnits(amt, quoteTokenDecimals));
|
|
587
|
+
transferAmountsWei = buyerAmounts.map((amt) => useNativeToken ? ethers.parseEther(amt) : ethers.parseUnits(amt, quoteTokenDecimals));
|
|
1158
588
|
const totalTransfer = transferAmountsWei.reduce((a, b) => a + b, 0n);
|
|
1159
589
|
if (totalTransfer > distributableAmount) {
|
|
1160
590
|
const formatted = useNativeToken
|
|
@@ -1165,7 +595,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1165
595
|
}
|
|
1166
596
|
else if (buyerRatios && buyerRatios.length === buyers.length) {
|
|
1167
597
|
// 比例模式
|
|
1168
|
-
transferAmountsWei = buyerRatios.map(ratio => {
|
|
598
|
+
transferAmountsWei = buyerRatios.map((ratio) => {
|
|
1169
599
|
return (distributableAmount * BigInt(Math.round(ratio * 10000))) / 10000n;
|
|
1170
600
|
});
|
|
1171
601
|
}
|
|
@@ -1173,22 +603,22 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1173
603
|
throw new Error('必须提供 buyerRatios 或 buyerAmounts');
|
|
1174
604
|
}
|
|
1175
605
|
// ✅ 获取贿赂金额
|
|
1176
|
-
const bribeAmount = config.bribeAmount && config.bribeAmount > 0
|
|
1177
|
-
? ethers.parseEther(String(config.bribeAmount))
|
|
1178
|
-
: 0n;
|
|
606
|
+
const bribeAmount = config.bribeAmount && config.bribeAmount > 0 ? ethers.parseEther(String(config.bribeAmount)) : 0n;
|
|
1179
607
|
// ✅ 验证主钱包余额
|
|
1180
608
|
const sellerBalance = await seller.provider.getBalance(seller.address);
|
|
1181
609
|
let sellerGasCost;
|
|
1182
610
|
let sellerRequired;
|
|
1183
611
|
if (useNativeToken) {
|
|
1184
612
|
// BNB 模式:贿赂(BRIBE) + 卖出(gasLimit) + N个原生转账(BRIBE each) + 利润(BRIBE)
|
|
1185
|
-
sellerGasCost =
|
|
613
|
+
sellerGasCost =
|
|
614
|
+
gasPrice * (BRIBE_GAS_LIMIT + finalGasLimit + BRIBE_GAS_LIMIT * BigInt(buyers.length) + BRIBE_GAS_LIMIT);
|
|
1186
615
|
sellerRequired = bribeAmount + sellerGasCost;
|
|
1187
616
|
}
|
|
1188
617
|
else {
|
|
1189
618
|
// ERC20 模式:子钱包已预留 BNB,不需要主钱包转 Gas
|
|
1190
619
|
// 卖方 Gas: 贿赂(BRIBE) + 卖出(gasLimit) + N个ERC20转账(65000 each) + 利润(BRIBE)
|
|
1191
|
-
sellerGasCost =
|
|
620
|
+
sellerGasCost =
|
|
621
|
+
gasPrice * (BRIBE_GAS_LIMIT + finalGasLimit + ERC20_TRANSFER_GAS * BigInt(buyers.length) + BRIBE_GAS_LIMIT);
|
|
1192
622
|
sellerRequired = bribeAmount + sellerGasCost;
|
|
1193
623
|
}
|
|
1194
624
|
if (sellerBalance < sellerRequired) {
|
|
@@ -1196,9 +626,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1196
626
|
}
|
|
1197
627
|
// ==================== 规划 Nonce ====================
|
|
1198
628
|
// ✅ 如果前端传入了 startNonces,直接使用(性能优化)
|
|
1199
|
-
let sellerNonce = startNonces && startNonces.length > 0
|
|
1200
|
-
? startNonces[0]
|
|
1201
|
-
: await nonceManager.getNextNonce(seller);
|
|
629
|
+
let sellerNonce = startNonces && startNonces.length > 0 ? startNonces[0] : await nonceManager.getNextNonce(seller);
|
|
1202
630
|
const deadline = Math.floor(Date.now() / 1000) + 600;
|
|
1203
631
|
// ==================== 1. 贿赂交易 ====================
|
|
1204
632
|
let bribeTx = null;
|
|
@@ -1210,7 +638,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1210
638
|
gasPrice,
|
|
1211
639
|
gasLimit: BRIBE_GAS_LIMIT,
|
|
1212
640
|
chainId: context.chainId,
|
|
1213
|
-
type: txType
|
|
641
|
+
type: txType,
|
|
1214
642
|
});
|
|
1215
643
|
}
|
|
1216
644
|
// ==================== 2. 卖出交易 ====================
|
|
@@ -1232,15 +660,17 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1232
660
|
else if (routeParams.routeType === 'v3-single') {
|
|
1233
661
|
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
1234
662
|
const v3RouterSeller = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, seller);
|
|
1235
|
-
const sellSwapData = v3RouterIface2.encodeFunctionData('exactInputSingle', [
|
|
663
|
+
const sellSwapData = v3RouterIface2.encodeFunctionData('exactInputSingle', [
|
|
664
|
+
{
|
|
1236
665
|
tokenIn: v3TokenIn,
|
|
1237
666
|
tokenOut: v3TokenOut,
|
|
1238
667
|
fee: v3Fee,
|
|
1239
668
|
recipient: useNativeToken ? PANCAKE_V3_ROUTER_ADDRESS : seller.address,
|
|
1240
669
|
amountIn: sellAmountWei,
|
|
1241
670
|
amountOutMinimum: 0n,
|
|
1242
|
-
sqrtPriceLimitX96: 0n
|
|
1243
|
-
}
|
|
671
|
+
sqrtPriceLimitX96: 0n,
|
|
672
|
+
},
|
|
673
|
+
]);
|
|
1244
674
|
if (useNativeToken) {
|
|
1245
675
|
// 原生代币:需要 unwrap WBNB
|
|
1246
676
|
const sellUnwrapData = v3RouterIface2.encodeFunctionData('unwrapWETH9', [0n, seller.address]);
|
|
@@ -1261,15 +691,15 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1261
691
|
gasLimit: finalGasLimit,
|
|
1262
692
|
gasPrice,
|
|
1263
693
|
chainId: context.chainId,
|
|
1264
|
-
type: txType
|
|
694
|
+
type: txType,
|
|
1265
695
|
});
|
|
1266
696
|
// ==================== 3. 转账交易(支持多跳)====================
|
|
1267
697
|
const buyerGasCost = gasPrice * finalGasLimit;
|
|
1268
698
|
// ✅ 生成多跳路径
|
|
1269
|
-
const hopPaths = generateDisperseHopPaths(buyers.map(b => b.address), disperseHopCount, context.provider);
|
|
699
|
+
const hopPaths = generateDisperseHopPaths(buyers.map((b) => b.address), disperseHopCount, context.provider);
|
|
1270
700
|
// 收集所有中间钱包信息
|
|
1271
701
|
const allHopWallets = [];
|
|
1272
|
-
hopPaths.forEach(path => {
|
|
702
|
+
hopPaths.forEach((path) => {
|
|
1273
703
|
allHopWallets.push(...path.hopWalletsInfo);
|
|
1274
704
|
});
|
|
1275
705
|
let transferTxs;
|
|
@@ -1287,17 +717,14 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1287
717
|
gasPrice,
|
|
1288
718
|
gasLimit: NATIVE_TRANSFER_GAS_LIMIT,
|
|
1289
719
|
chainId: context.chainId,
|
|
1290
|
-
type: txType
|
|
720
|
+
type: txType,
|
|
1291
721
|
});
|
|
1292
722
|
}));
|
|
1293
723
|
}
|
|
1294
724
|
else {
|
|
1295
725
|
const erc20Interface = new ethers.Interface(ERC20_ABI);
|
|
1296
726
|
transferTxs = await Promise.all(buyers.map((buyer, i) => {
|
|
1297
|
-
const transferData = erc20Interface.encodeFunctionData('transfer', [
|
|
1298
|
-
buyer.address,
|
|
1299
|
-
transferAmountsWei[i]
|
|
1300
|
-
]);
|
|
727
|
+
const transferData = erc20Interface.encodeFunctionData('transfer', [buyer.address, transferAmountsWei[i]]);
|
|
1301
728
|
return seller.signTransaction({
|
|
1302
729
|
to: quoteToken,
|
|
1303
730
|
data: transferData,
|
|
@@ -1306,7 +733,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1306
733
|
gasPrice,
|
|
1307
734
|
gasLimit: ERC20_TRANSFER_GAS,
|
|
1308
735
|
chainId: context.chainId,
|
|
1309
|
-
type: txType
|
|
736
|
+
type: txType,
|
|
1310
737
|
});
|
|
1311
738
|
}));
|
|
1312
739
|
}
|
|
@@ -1350,7 +777,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1350
777
|
// ✅ 如果前端传入了 startNonces,使用 buyer 部分(从索引 1 开始)
|
|
1351
778
|
const buyerNonces = startNonces && startNonces.length > 1
|
|
1352
779
|
? startNonces.slice(1)
|
|
1353
|
-
: await Promise.all(buyers.map(buyer => nonceManager.getNextNonce(buyer)));
|
|
780
|
+
: await Promise.all(buyers.map((buyer) => nonceManager.getNextNonce(buyer)));
|
|
1354
781
|
const signedBuys = await Promise.all(buyers.map(async (buyer, i) => {
|
|
1355
782
|
const buyAmount = transferAmountsWei[i];
|
|
1356
783
|
// ✅ ERC20 模式:value = 0(通过代币授权支付)
|
|
@@ -1370,15 +797,17 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1370
797
|
else if (routeParams.routeType === 'v3-single') {
|
|
1371
798
|
const { v3TokenIn, v3TokenOut, v3Fee } = routeParams;
|
|
1372
799
|
const v3RouterBuyer = new Contract(PANCAKE_V3_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, buyer);
|
|
1373
|
-
const buySwapData = v3RouterIface2.encodeFunctionData('exactInputSingle', [
|
|
800
|
+
const buySwapData = v3RouterIface2.encodeFunctionData('exactInputSingle', [
|
|
801
|
+
{
|
|
1374
802
|
tokenIn: v3TokenOut,
|
|
1375
803
|
tokenOut: v3TokenIn,
|
|
1376
804
|
fee: v3Fee,
|
|
1377
805
|
recipient: buyer.address,
|
|
1378
806
|
amountIn: buyAmount,
|
|
1379
807
|
amountOutMinimum: 0n,
|
|
1380
|
-
sqrtPriceLimitX96: 0n
|
|
1381
|
-
}
|
|
808
|
+
sqrtPriceLimitX96: 0n,
|
|
809
|
+
},
|
|
810
|
+
]);
|
|
1382
811
|
buyUnsigned = await v3RouterBuyer.multicall.populateTransaction(deadline, [buySwapData], { value: buyValue });
|
|
1383
812
|
}
|
|
1384
813
|
else {
|
|
@@ -1391,7 +820,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1391
820
|
gasLimit: finalGasLimit,
|
|
1392
821
|
gasPrice,
|
|
1393
822
|
chainId: context.chainId,
|
|
1394
|
-
type: txType
|
|
823
|
+
type: txType,
|
|
1395
824
|
});
|
|
1396
825
|
}));
|
|
1397
826
|
nonceManager.clearTemp();
|
|
@@ -1416,7 +845,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1416
845
|
gasPrice,
|
|
1417
846
|
chainId: context.chainId,
|
|
1418
847
|
txType,
|
|
1419
|
-
startNonce: sellerNonce
|
|
848
|
+
startNonce: sellerNonce++,
|
|
1420
849
|
});
|
|
1421
850
|
signedTransactions.push(...profitHopResult.signedTransactions);
|
|
1422
851
|
profitHopWallets = profitHopResult.hopWallets; // ✅ 收集利润多跳钱包
|
|
@@ -1428,18 +857,16 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1428
857
|
profitHopWallets, // ✅ 返回利润多跳钱包
|
|
1429
858
|
metadata: {
|
|
1430
859
|
sellerAddress: seller.address,
|
|
1431
|
-
buyerAddresses: buyers.map(b => b.address),
|
|
860
|
+
buyerAddresses: buyers.map((b) => b.address),
|
|
1432
861
|
sellAmount: ethers.formatUnits(sellAmountWei, decimals),
|
|
1433
862
|
estimatedOutput: useNativeToken
|
|
1434
863
|
? ethers.formatEther(estimatedOutput)
|
|
1435
864
|
: ethers.formatUnits(estimatedOutput, quoteTokenDecimals),
|
|
1436
|
-
transferAmounts: transferAmountsWei.map(amt => useNativeToken
|
|
1437
|
-
? ethers.formatEther(amt)
|
|
1438
|
-
: ethers.formatUnits(amt, quoteTokenDecimals)),
|
|
865
|
+
transferAmounts: transferAmountsWei.map((amt) => useNativeToken ? ethers.formatEther(amt) : ethers.formatUnits(amt, quoteTokenDecimals)),
|
|
1439
866
|
profitAmount: profitAmount > 0n ? ethers.formatEther(profitAmount) : undefined,
|
|
1440
867
|
useNativeToken,
|
|
1441
|
-
disperseHopCount: disperseHopCount > 0 ? disperseHopCount : undefined // ✅ 返回多跳数
|
|
1442
|
-
}
|
|
868
|
+
disperseHopCount: disperseHopCount > 0 ? disperseHopCount : undefined, // ✅ 返回多跳数
|
|
869
|
+
},
|
|
1443
870
|
};
|
|
1444
871
|
}
|
|
1445
872
|
/**
|
|
@@ -1450,7 +877,7 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
1450
877
|
* - ✅ 正确处理 nonce:同一钱包在多轮中使用时 nonce 自动递增
|
|
1451
878
|
*/
|
|
1452
879
|
export async function pancakeCrossSwapMerkle(params) {
|
|
1453
|
-
const { sellerPrivateKeys, sellAmounts, buyerPrivateKeys, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, buyersPerSell, disperseHopCount = 0 } = params;
|
|
880
|
+
const { sellerPrivateKeys, sellAmounts, buyerPrivateKeys, tokenAddress, routeParams, config, quoteToken, quoteTokenDecimals = 18, buyersPerSell, disperseHopCount = 0, } = params;
|
|
1454
881
|
if (sellerPrivateKeys.length === 0) {
|
|
1455
882
|
throw new Error('至少需要一个卖方');
|
|
1456
883
|
}
|
|
@@ -1464,8 +891,8 @@ export async function pancakeCrossSwapMerkle(params) {
|
|
|
1464
891
|
const context = createPancakeContext(config);
|
|
1465
892
|
const nonceManager = new NonceManager(context.provider);
|
|
1466
893
|
// ✅ 预先获取所有钱包的初始 nonce
|
|
1467
|
-
const allSellerWallets = sellerPrivateKeys.map(pk => new Wallet(pk, context.provider));
|
|
1468
|
-
const allBuyerWallets = buyerPrivateKeys.map(pk => new Wallet(pk, context.provider));
|
|
894
|
+
const allSellerWallets = sellerPrivateKeys.map((pk) => new Wallet(pk, context.provider));
|
|
895
|
+
const allBuyerWallets = buyerPrivateKeys.map((pk) => new Wallet(pk, context.provider));
|
|
1469
896
|
// 使用 Map 去重(同一私钥可能出现多次)
|
|
1470
897
|
const addressToNonce = new Map();
|
|
1471
898
|
// 获取所有卖方 nonce
|
|
@@ -1492,9 +919,7 @@ export async function pancakeCrossSwapMerkle(params) {
|
|
|
1492
919
|
// 判断是否使用原生代币
|
|
1493
920
|
const useNativeToken = !quoteToken || quoteToken === ZERO_ADDRESS;
|
|
1494
921
|
// 获取贿赂金额
|
|
1495
|
-
const bribeAmount = config.bribeAmount && config.bribeAmount > 0
|
|
1496
|
-
? ethers.parseEther(String(config.bribeAmount))
|
|
1497
|
-
: 0n;
|
|
922
|
+
const bribeAmount = config.bribeAmount && config.bribeAmount > 0 ? ethers.parseEther(String(config.bribeAmount)) : 0n;
|
|
1498
923
|
const hasBribe = bribeAmount > 0n;
|
|
1499
924
|
for (let i = 0; i < sellerPrivateKeys.length; i++) {
|
|
1500
925
|
const sellerPk = sellerPrivateKeys[i];
|
|
@@ -1512,7 +937,7 @@ export async function pancakeCrossSwapMerkle(params) {
|
|
|
1512
937
|
// ✅ 获取卖方当前 nonce
|
|
1513
938
|
const sellerNonce = addressToNonce.get(sellerWallet.address);
|
|
1514
939
|
// ✅ 获取并更新买方 nonces(每个买方本轮需要 1 个 nonce)
|
|
1515
|
-
const roundBuyerNonces = roundBuyerWallets.map(w => {
|
|
940
|
+
const roundBuyerNonces = roundBuyerWallets.map((w) => {
|
|
1516
941
|
const nonce = addressToNonce.get(w.address);
|
|
1517
942
|
addressToNonce.set(w.address, nonce + 1); // 每个买方用 1 个 nonce
|
|
1518
943
|
return nonce;
|
|
@@ -1552,7 +977,7 @@ export async function pancakeCrossSwapMerkle(params) {
|
|
|
1552
977
|
quoteToken,
|
|
1553
978
|
quoteTokenDecimals,
|
|
1554
979
|
disperseHopCount,
|
|
1555
|
-
startNonces // ✅ 传入预计算的 nonces
|
|
980
|
+
startNonces, // ✅ 传入预计算的 nonces
|
|
1556
981
|
});
|
|
1557
982
|
// ✅ 更新卖方 nonce(使用精确计算的值)
|
|
1558
983
|
addressToNonce.set(sellerWallet.address, sellerNonce + sellerNonceConsumed);
|
|
@@ -1566,7 +991,7 @@ export async function pancakeCrossSwapMerkle(params) {
|
|
|
1566
991
|
sellerAddress: res.metadata?.sellerAddress || '',
|
|
1567
992
|
buyerAddresses: res.metadata?.buyerAddresses || roundBuyerPks.map(() => ''),
|
|
1568
993
|
sellAmount,
|
|
1569
|
-
bundleHash: undefined
|
|
994
|
+
bundleHash: undefined,
|
|
1570
995
|
});
|
|
1571
996
|
}
|
|
1572
997
|
nonceManager.clearTemp();
|
|
@@ -1574,6 +999,6 @@ export async function pancakeCrossSwapMerkle(params) {
|
|
|
1574
999
|
signedTransactions: allSigned,
|
|
1575
1000
|
rounds,
|
|
1576
1001
|
disperseHopWallets: allDisperse.length > 0 ? allDisperse : undefined,
|
|
1577
|
-
profitHopWallets: allProfit.length > 0 ? allProfit : undefined
|
|
1002
|
+
profitHopWallets: allProfit.length > 0 ? allProfit : undefined,
|
|
1578
1003
|
};
|
|
1579
1004
|
}
|