four-flap-meme-sdk 3.0.0 → 4.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/dist/bundle/four-meme/approve-tokenmanager.d.ts +2 -2
- package/dist/bundle/four-meme/approve-tokenmanager.js +3 -3
- package/dist/bundle/four-meme/core/buy-flow.d.ts +5 -0
- package/dist/bundle/four-meme/core/buy-flow.js +147 -0
- package/dist/bundle/four-meme/core/constants.d.ts +6 -0
- package/dist/bundle/four-meme/core/constants.js +15 -0
- package/dist/bundle/four-meme/core/create-token.d.ts +5 -0
- package/dist/bundle/four-meme/core/create-token.js +137 -0
- package/dist/bundle/four-meme/core/index.d.ts +14 -0
- package/dist/bundle/four-meme/core/index.js +14 -0
- package/dist/bundle/four-meme/core/sell-flow.d.ts +5 -0
- package/dist/bundle/four-meme/core/sell-flow.js +240 -0
- package/dist/bundle/four-meme/core-helpers.js +1 -1
- package/dist/bundle/four-meme/core.d.ts +7 -4
- package/dist/bundle/four-meme/core.js +5 -513
- package/dist/bundle/four-meme/pancake-proxy/approve.d.ts +15 -0
- package/dist/bundle/four-meme/pancake-proxy/approve.js +113 -0
- package/dist/bundle/four-meme/pancake-proxy/buy.d.ts +8 -0
- package/dist/bundle/four-meme/pancake-proxy/buy.js +143 -0
- package/dist/bundle/four-meme/pancake-proxy/constants.d.ts +25 -0
- package/dist/bundle/four-meme/pancake-proxy/constants.js +14 -0
- package/dist/bundle/four-meme/pancake-proxy/helpers.d.ts +45 -0
- package/dist/bundle/four-meme/pancake-proxy/helpers.js +232 -0
- package/dist/bundle/four-meme/pancake-proxy/index.d.ts +15 -0
- package/dist/bundle/four-meme/pancake-proxy/index.js +15 -0
- package/dist/bundle/four-meme/pancake-proxy/sell.d.ts +8 -0
- package/dist/bundle/four-meme/pancake-proxy/sell.js +194 -0
- package/dist/bundle/four-meme/pancake-proxy.d.ts +4 -20
- package/dist/bundle/four-meme/pancake-proxy.js +3 -670
- package/dist/bundle/four-meme/private/buy.d.ts +16 -0
- package/dist/bundle/four-meme/private/buy.js +225 -0
- package/dist/bundle/four-meme/private/index.d.ts +11 -0
- package/dist/bundle/four-meme/private/index.js +11 -0
- package/dist/bundle/four-meme/private/sell.d.ts +18 -0
- package/dist/bundle/four-meme/private/sell.js +245 -0
- package/dist/bundle/four-meme/private.d.ts +5 -25
- package/dist/bundle/four-meme/private.js +5 -463
- package/dist/bundle/four-meme/swap/batch.d.ts +8 -0
- package/dist/bundle/four-meme/swap/batch.js +170 -0
- package/dist/bundle/four-meme/swap/bundle.d.ts +8 -0
- package/dist/bundle/four-meme/swap/bundle.js +147 -0
- package/dist/bundle/four-meme/swap/index.d.ts +14 -0
- package/dist/bundle/four-meme/swap/index.js +13 -0
- package/dist/bundle/four-meme/swap/quick-batch.d.ts +8 -0
- package/dist/bundle/four-meme/swap/quick-batch.js +206 -0
- package/dist/bundle/four-meme/swap-buy-first/helpers.d.ts +20 -0
- package/dist/bundle/four-meme/swap-buy-first/helpers.js +39 -0
- package/dist/bundle/four-meme/swap-buy-first/index.d.ts +12 -0
- package/dist/bundle/four-meme/swap-buy-first/index.js +11 -0
- package/dist/bundle/four-meme/swap-buy-first/multi-wallet.d.ts +20 -0
- package/dist/bundle/four-meme/swap-buy-first/multi-wallet.js +198 -0
- package/dist/bundle/four-meme/swap-buy-first/single.d.ts +7 -0
- package/dist/bundle/four-meme/swap-buy-first/single.js +232 -0
- package/dist/bundle/four-meme/swap-buy-first.d.ts +4 -3
- package/dist/bundle/four-meme/swap-buy-first.js +4 -451
- package/dist/bundle/four-meme/swap-hop-helpers.d.ts +2 -2
- package/dist/bundle/four-meme/swap-sign-helpers.d.ts +2 -2
- package/dist/bundle/four-meme/swap-sign-helpers.js +1 -1
- package/dist/bundle/four-meme/swap.d.ts +4 -14
- package/dist/bundle/four-meme/swap.js +4 -502
- package/dist/bundle/four-meme/types/index.d.ts +1 -1
- package/dist/bundle/four-meme/utils-disperse.d.ts +1 -1
- package/dist/bundle/four-meme/utils-disperse.js +1 -1
- package/dist/bundle/four-meme/utils-pairwise.d.ts +1 -1
- package/dist/bundle/four-meme/utils-pairwise.js +1 -1
- package/dist/bundle/four-meme/utils-sweep/context.d.ts +39 -0
- package/dist/bundle/four-meme/utils-sweep/context.js +7 -0
- package/dist/bundle/four-meme/utils-sweep/erc20-no-hop.d.ts +5 -0
- package/dist/bundle/four-meme/utils-sweep/erc20-no-hop.js +162 -0
- package/dist/bundle/four-meme/utils-sweep/index.d.ts +13 -0
- package/dist/bundle/four-meme/utils-sweep/index.js +13 -0
- package/dist/bundle/four-meme/utils-sweep/main.d.ts +8 -0
- package/dist/bundle/four-meme/utils-sweep/main.js +114 -0
- package/dist/bundle/four-meme/utils-sweep/native-no-hop.d.ts +5 -0
- package/dist/bundle/four-meme/utils-sweep/native-no-hop.js +156 -0
- package/dist/bundle/four-meme/utils-sweep/with-hops.d.ts +6 -0
- package/dist/bundle/four-meme/utils-sweep/with-hops.js +382 -0
- package/dist/bundle/four-meme/utils-sweep.d.ts +3 -4
- package/dist/bundle/four-meme/utils-sweep.js +3 -740
- package/dist/bundle/internal.d.ts +2 -2
- package/dist/bundle/sign-context-helpers.d.ts +1 -26
- package/dist/bundle/sign-context-helpers.js +1 -63
- package/dist/bundle/submit/blockrazor.d.ts +94 -0
- package/dist/bundle/submit/blockrazor.js +122 -0
- package/dist/bundle/submit/direct.d.ts +118 -0
- package/dist/bundle/submit/direct.js +484 -0
- package/dist/bundle/submit/helpers.d.ts +7 -0
- package/dist/bundle/submit/helpers.js +15 -0
- package/dist/bundle/submit/index.d.ts +14 -0
- package/dist/bundle/submit/index.js +14 -0
- package/dist/bundle/submit/merkle.d.ts +84 -0
- package/dist/bundle/submit/merkle.js +121 -0
- package/dist/bundle/submit.d.ts +3 -286
- package/dist/bundle/submit.js +3 -724
- package/dist/chains/bsc/four/types.d.ts +1 -1
- package/dist/chains/bsc/index.d.ts +1 -1
- package/dist/chains/bsc/index.js +2 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-build.d.ts +25 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-build.js +177 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-constants.d.ts +30 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-constants.js +24 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-helpers.d.ts +11 -149
- package/dist/chains/bsc/pancake/bundle-buy-first-helpers.js +12 -74
- package/dist/chains/bsc/pancake/bundle-buy-first-multi-wallet.d.ts +9 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-multi-wallet.js +225 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-plan.d.ts +14 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-plan.js +64 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-profit.d.ts +12 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-profit.js +22 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-quote.d.ts +15 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-quote.js +122 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-types.d.ts +179 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-types.js +1 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-validate.d.ts +2 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-validate.js +41 -0
- package/dist/chains/bsc/pancake/bundle-buy-first.d.ts +1 -1
- package/dist/chains/bsc/pancake/bundle-buy-first.js +8 -578
- package/dist/chains/bsc/pancake/bundle-swap-helpers.d.ts +11 -239
- package/dist/chains/bsc/pancake/bundle-swap-helpers.js +12 -564
- package/dist/chains/bsc/pancake/bundle-swap-types.d.ts +183 -0
- package/dist/chains/bsc/pancake/bundle-swap-types.js +17 -0
- package/dist/chains/bsc/pancake/bundle-swap.d.ts +10 -132
- package/dist/chains/bsc/pancake/bundle-swap.js +12 -1003
- package/dist/chains/bsc/pancake/hop-chain.d.ts +18 -0
- package/dist/chains/bsc/pancake/hop-chain.js +227 -0
- package/dist/chains/bsc/pancake/quote.d.ts +14 -0
- package/dist/chains/bsc/pancake/quote.js +84 -0
- package/dist/chains/bsc/pancake/swap-batch.d.ts +42 -0
- package/dist/chains/bsc/pancake/swap-batch.js +283 -0
- package/dist/chains/bsc/pancake/swap-build.d.ts +19 -0
- package/dist/chains/bsc/pancake/swap-build.js +226 -0
- package/dist/chains/bsc/pancake/swap-cross.d.ts +42 -0
- package/dist/chains/bsc/pancake/swap-cross.js +140 -0
- package/dist/chains/bsc/pancake/swap-quick.d.ts +54 -0
- package/dist/chains/bsc/pancake/swap-quick.js +424 -0
- package/dist/chains/bsc/pancake/swap-single.d.ts +2 -0
- package/dist/chains/bsc/pancake/swap-single.js +182 -0
- package/dist/chains/bsc/platforms/four/index.d.ts +21 -3
- package/dist/chains/bsc/platforms/four/index.js +28 -3
- package/dist/chains/eni/batch-router/transfer-disperse.d.ts +37 -0
- package/dist/chains/eni/batch-router/transfer-disperse.js +302 -0
- package/dist/chains/eni/batch-router/transfer-shared.d.ts +9 -0
- package/dist/chains/eni/batch-router/transfer-shared.js +10 -0
- package/dist/chains/eni/batch-router/transfer-sweep.d.ts +51 -0
- package/dist/chains/eni/batch-router/transfer-sweep.js +364 -0
- package/dist/chains/eni/batch-router/transfer.d.ts +4 -74
- package/dist/chains/eni/batch-router/transfer.js +2 -647
- package/dist/chains/eni/index.d.ts +2 -0
- package/dist/chains/eni/index.js +4 -0
- package/dist/chains/eni/platforms/daoaas/portal-direct-profit.d.ts +17 -0
- package/dist/chains/eni/platforms/daoaas/portal-direct-profit.js +30 -0
- package/dist/chains/eni/platforms/daoaas/portal-direct-submit.d.ts +12 -0
- package/dist/chains/eni/platforms/daoaas/portal-direct-submit.js +396 -0
- package/dist/chains/eni/platforms/daoaas/portal-direct-tx.d.ts +20 -0
- package/dist/chains/eni/platforms/daoaas/portal-direct-tx.js +165 -0
- package/dist/chains/eni/platforms/daoaas/portal-direct.d.ts +3 -32
- package/dist/chains/eni/platforms/daoaas/portal-direct.js +3 -571
- package/dist/chains/eni/submit.js +1 -1
- package/dist/chains/xlayer/constants.d.ts +0 -2
- package/dist/chains/xlayer/constants.js +0 -2
- package/dist/chains/xlayer/eip7702/auth.d.ts +16 -0
- package/dist/chains/xlayer/eip7702/auth.js +81 -0
- package/dist/chains/xlayer/eip7702/bundle-create-buy.d.ts +22 -0
- package/dist/chains/xlayer/eip7702/bundle-create-buy.js +201 -0
- package/dist/chains/xlayer/eip7702/bundle-create-helpers.d.ts +114 -0
- package/dist/chains/xlayer/eip7702/bundle-create-helpers.js +139 -0
- package/dist/chains/xlayer/eip7702/bundle-create-to-dex.d.ts +24 -0
- package/dist/chains/xlayer/eip7702/bundle-create-to-dex.js +233 -0
- package/dist/chains/xlayer/eip7702/bundle-create.d.ts +3 -35
- package/dist/chains/xlayer/eip7702/bundle-create.js +3 -746
- package/dist/chains/xlayer/eip7702/bundle-graduate-buy.d.ts +22 -0
- package/dist/chains/xlayer/eip7702/bundle-graduate-buy.js +214 -0
- package/dist/chains/xlayer/eip7702/bundle-sell.js +1 -1
- package/dist/chains/xlayer/eip7702/bundle-swap-batch.d.ts +31 -0
- package/dist/chains/xlayer/eip7702/bundle-swap-batch.js +216 -0
- package/dist/chains/xlayer/eip7702/bundle-swap-helpers.d.ts +21 -0
- package/dist/chains/xlayer/eip7702/bundle-swap-helpers.js +206 -0
- package/dist/chains/xlayer/eip7702/bundle-swap-multi.d.ts +33 -0
- package/dist/chains/xlayer/eip7702/bundle-swap-multi.js +146 -0
- package/dist/chains/xlayer/eip7702/bundle-swap-single.d.ts +31 -0
- package/dist/chains/xlayer/eip7702/bundle-swap-single.js +177 -0
- package/dist/chains/xlayer/eip7702/bundle-swap.d.ts +6 -61
- package/dist/chains/xlayer/eip7702/bundle-swap.js +3 -712
- package/dist/chains/xlayer/eip7702/bytes.d.ts +4 -0
- package/dist/chains/xlayer/eip7702/bytes.js +31 -0
- package/dist/chains/xlayer/eip7702/gas.d.ts +19 -0
- package/dist/chains/xlayer/eip7702/gas.js +152 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-disperse.d.ts +5 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-disperse.js +196 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-pairwise.d.ts +5 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-pairwise.js +188 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-sweep.d.ts +5 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-sweep.js +220 -0
- package/dist/chains/xlayer/eip7702/multi-hop-transfer.d.ts +8 -4
- package/dist/chains/xlayer/eip7702/multi-hop-transfer.js +5 -591
- package/dist/chains/xlayer/eip7702/profit.d.ts +32 -0
- package/dist/chains/xlayer/eip7702/profit.js +59 -0
- package/dist/chains/xlayer/eip7702/provider.d.ts +3 -0
- package/dist/chains/xlayer/eip7702/provider.js +17 -0
- package/dist/chains/xlayer/eip7702/time.d.ts +2 -0
- package/dist/chains/xlayer/eip7702/time.js +10 -0
- package/dist/chains/xlayer/eip7702/tx-build.d.ts +10 -0
- package/dist/chains/xlayer/eip7702/tx-build.js +128 -0
- package/dist/chains/xlayer/eip7702/utils.d.ts +19 -85
- package/dist/chains/xlayer/eip7702/utils.js +19 -484
- package/dist/chains/xlayer/eip7702/volume-bundle.d.ts +13 -0
- package/dist/chains/xlayer/eip7702/volume-bundle.js +250 -0
- package/dist/chains/xlayer/eip7702/volume-internal.d.ts +13 -0
- package/dist/chains/xlayer/eip7702/volume-internal.js +169 -0
- package/dist/chains/xlayer/eip7702/volume-make.d.ts +8 -0
- package/dist/chains/xlayer/eip7702/volume-make.js +38 -0
- package/dist/chains/xlayer/eip7702/volume-single-round.d.ts +17 -0
- package/dist/chains/xlayer/eip7702/volume-single-round.js +44 -0
- package/dist/chains/xlayer/eip7702/volume-swap.d.ts +18 -0
- package/dist/chains/xlayer/eip7702/volume-swap.js +30 -0
- package/dist/chains/xlayer/eip7702/volume-wash.d.ts +8 -0
- package/dist/chains/xlayer/eip7702/volume-wash.js +191 -0
- package/dist/chains/xlayer/eip7702/volume.d.ts +7 -35
- package/dist/chains/xlayer/eip7702/volume.js +5 -697
- package/dist/chains/xlayer/eip7702/wallet.d.ts +6 -0
- package/dist/chains/xlayer/eip7702/wallet.js +17 -0
- package/dist/chains/xlayer/eoa/aa-types.d.ts +176 -0
- package/dist/chains/xlayer/eoa/aa-types.js +6 -0
- package/dist/chains/xlayer/eoa/constants.d.ts +0 -2
- package/dist/chains/xlayer/eoa/constants.js +0 -2
- package/dist/chains/xlayer/eoa/context.d.ts +8 -0
- package/dist/chains/xlayer/eoa/context.js +23 -0
- package/dist/chains/xlayer/eoa/encoders.d.ts +147 -0
- package/dist/chains/xlayer/eoa/encoders.js +147 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-cross.d.ts +5 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-cross.js +113 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-helpers.d.ts +10 -123
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-helpers.js +10 -225
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-pure.d.ts +50 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-pure.js +170 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-quick.d.ts +5 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-quick.js +257 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-types.d.ts +99 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap-types.js +11 -0
- package/dist/chains/xlayer/eoa/eoa-bundle-swap.d.ts +5 -47
- package/dist/chains/xlayer/eoa/eoa-bundle-swap.js +3 -522
- package/dist/chains/xlayer/eoa/eoa-types.d.ts +776 -0
- package/dist/chains/xlayer/eoa/eoa-types.js +6 -0
- package/dist/chains/xlayer/eoa/eoa-wash-volume.d.ts +8 -0
- package/dist/chains/xlayer/eoa/eoa-wash-volume.js +8 -0
- package/dist/chains/xlayer/eoa/format.d.ts +34 -0
- package/dist/chains/xlayer/eoa/format.js +56 -0
- package/dist/chains/xlayer/eoa/hop-chain.d.ts +4 -0
- package/dist/chains/xlayer/eoa/hop-chain.js +87 -0
- package/dist/chains/xlayer/eoa/nonce-map.d.ts +20 -0
- package/dist/chains/xlayer/eoa/nonce-map.js +51 -0
- package/dist/chains/xlayer/eoa/portal-ops.d.ts +9 -292
- package/dist/chains/xlayer/eoa/portal-ops.js +9 -486
- package/dist/chains/xlayer/eoa/query.d.ts +117 -0
- package/dist/chains/xlayer/eoa/query.js +285 -0
- package/dist/chains/xlayer/eoa/quote.d.ts +6 -0
- package/dist/chains/xlayer/eoa/quote.js +90 -0
- package/dist/chains/xlayer/eoa/types.d.ts +9 -959
- package/dist/chains/xlayer/eoa/types.js +9 -49
- package/dist/core/clients/blockrazor.js +1 -1
- package/dist/core/clients/merkle.js +1 -1
- package/dist/core/erc20/allowances.d.ts +104 -0
- package/dist/core/erc20/allowances.js +205 -0
- package/dist/core/erc20/approve.d.ts +141 -0
- package/dist/core/erc20/approve.js +325 -0
- package/dist/core/erc20/helpers.d.ts +20 -0
- package/dist/core/erc20/helpers.js +109 -0
- package/dist/core/erc20/index.d.ts +13 -0
- package/dist/core/erc20/index.js +12 -0
- package/dist/core/gas/bundle-gas.d.ts +6 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/quote/index.d.ts +1 -0
- package/dist/core/quote/index.js +1 -0
- package/dist/core/quote/quote-helpers.d.ts +78 -0
- package/dist/core/quote/quote-helpers.js +289 -0
- package/dist/core/quote/types.d.ts +1 -0
- package/dist/core/quote/types.js +1 -0
- package/dist/core/sign-context-helpers.d.ts +29 -0
- package/dist/core/sign-context-helpers.js +63 -0
- package/dist/domains/dex/direct-router-helpers.d.ts +16 -268
- package/dist/domains/dex/direct-router-helpers.js +16 -535
- package/dist/domains/dex/direct-router-types.d.ts +104 -0
- package/dist/domains/dex/direct-router-types.js +81 -0
- package/dist/domains/dex/direct-router-v2-buy.d.ts +2 -0
- package/dist/domains/dex/direct-router-v2-buy.js +249 -0
- package/dist/domains/dex/direct-router-v2-sell.d.ts +5 -0
- package/dist/domains/dex/direct-router-v2-sell.js +270 -0
- package/dist/domains/dex/direct-router-v2.d.ts +9 -0
- package/dist/domains/dex/direct-router-v2.js +9 -0
- package/dist/domains/dex/direct-router-v3.d.ts +17 -0
- package/dist/domains/dex/direct-router-v3.js +432 -0
- package/dist/domains/dex/direct-router.d.ts +11 -26
- package/dist/domains/dex/direct-router.js +10 -977
- package/dist/domains/dex/dyo-encode.d.ts +62 -0
- package/dist/domains/dex/dyo-encode.js +124 -0
- package/dist/domains/dex/profit.d.ts +24 -0
- package/dist/domains/dex/profit.js +86 -0
- package/dist/domains/dex/provider.d.ts +10 -0
- package/dist/domains/dex/provider.js +27 -0
- package/dist/domains/dex/quote.d.ts +7 -0
- package/dist/domains/dex/quote.js +52 -0
- package/dist/domains/dex/router.d.ts +56 -0
- package/dist/domains/dex/router.js +193 -0
- package/dist/domains/flap/portal-bundle/batch.d.ts +9 -0
- package/dist/domains/flap/portal-bundle/batch.js +193 -0
- package/dist/domains/flap/portal-bundle/create.d.ts +5 -0
- package/dist/domains/flap/portal-bundle/create.js +153 -0
- package/dist/domains/flap/portal-bundle/helpers.d.ts +32 -0
- package/dist/domains/flap/portal-bundle/helpers.js +50 -0
- package/dist/domains/flap/portal-bundle/index.d.ts +16 -0
- package/dist/domains/flap/portal-bundle/index.js +15 -0
- package/dist/domains/flap/portal-bundle/private.d.ts +5 -0
- package/dist/domains/flap/portal-bundle/private.js +198 -0
- package/dist/domains/flap/portal-bundle/types.d.ts +102 -0
- package/dist/domains/flap/portal-bundle/types.js +1 -0
- package/dist/domains/flap/portal-bundle-merkle/core-batch.d.ts +13 -0
- package/dist/domains/flap/portal-bundle-merkle/core-batch.js +376 -0
- package/dist/domains/flap/portal-bundle-merkle/core-helpers.d.ts +75 -7
- package/dist/domains/flap/portal-bundle-merkle/core-helpers.js +259 -20
- package/dist/domains/flap/portal-bundle-merkle/core.d.ts +2 -13
- package/dist/domains/flap/portal-bundle-merkle/core.js +12 -629
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/constants.d.ts +70 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/constants.js +90 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/index.d.ts +12 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/index.js +11 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/main.d.ts +15 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/main.js +432 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/types.d.ts +113 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex/types.js +4 -0
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex.d.ts +4 -127
- package/dist/domains/flap/portal-bundle-merkle/create-to-dex.js +4 -527
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/constants.d.ts +42 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/constants.js +81 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/index.d.ts +12 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/index.js +11 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/main.d.ts +15 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/main.js +339 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/types.d.ts +72 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex/types.js +4 -0
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex.d.ts +4 -85
- package/dist/domains/flap/portal-bundle-merkle/curve-to-dex.js +4 -425
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/approve.d.ts +12 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/approve.js +102 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/buy.d.ts +5 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/buy.js +135 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/helpers.d.ts +52 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/helpers.js +267 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/index.d.ts +14 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/index.js +14 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/sell.d.ts +5 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/sell.js +195 -0
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy.d.ts +3 -24
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy.js +3 -700
- package/dist/domains/flap/portal-bundle-merkle/private/buy.d.ts +9 -0
- package/dist/domains/flap/portal-bundle-merkle/private/buy.js +188 -0
- package/dist/domains/flap/portal-bundle-merkle/private/helpers.d.ts +36 -0
- package/dist/domains/flap/portal-bundle-merkle/private/helpers.js +127 -0
- package/dist/domains/flap/portal-bundle-merkle/private/index.d.ts +12 -0
- package/dist/domains/flap/portal-bundle-merkle/private/index.js +12 -0
- package/dist/domains/flap/portal-bundle-merkle/private/sell.d.ts +9 -0
- package/dist/domains/flap/portal-bundle-merkle/private/sell.js +191 -0
- package/dist/domains/flap/portal-bundle-merkle/private.d.ts +5 -15
- package/dist/domains/flap/portal-bundle-merkle/private.js +5 -494
- package/dist/domains/flap/portal-bundle-merkle/swap-batch.js +3 -2
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-chain.d.ts +4 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-chain.js +43 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-constants.d.ts +13 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-constants.js +21 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-helpers.d.ts +11 -121
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-helpers.js +11 -109
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-multi-wallet.d.ts +20 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-multi-wallet.js +223 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-plan.d.ts +32 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-plan.js +66 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-profit.d.ts +22 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-profit.js +22 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-quote.d.ts +51 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-quote.js +149 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-types.d.ts +87 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-types.js +1 -0
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first.js +5 -404
- package/dist/domains/flap/portal-bundle-merkle/swap-helpers.d.ts +0 -1
- package/dist/domains/flap/portal-bundle-merkle/swap-helpers.js +0 -7
- package/dist/domains/flap/portal-bundle-merkle/swap-planning.js +1 -1
- package/dist/domains/flap/portal-bundle-merkle/swap-quick-batch.js +3 -2
- package/dist/domains/flap/portal-bundle-merkle/swap-single.js +3 -2
- package/dist/domains/flap/portal-bundle-merkle/utils/disperse.d.ts +2 -0
- package/dist/domains/flap/portal-bundle-merkle/utils/disperse.js +275 -0
- package/dist/domains/flap/portal-bundle-merkle/utils/index.d.ts +11 -0
- package/dist/domains/flap/portal-bundle-merkle/utils/index.js +11 -0
- package/dist/domains/flap/portal-bundle-merkle/utils/sweep.d.ts +9 -0
- package/dist/domains/flap/portal-bundle-merkle/utils/sweep.js +570 -0
- package/dist/domains/flap/portal-bundle-merkle/utils.d.ts +5 -8
- package/dist/domains/flap/portal-bundle-merkle/utils.js +5 -841
- package/dist/domains/flap/portal-bundle.d.ts +5 -117
- package/dist/domains/flap/portal-bundle.js +5 -587
- package/dist/domains/flap/portal.d.ts +13 -404
- package/dist/domains/flap/portal.js +12 -619
- package/dist/domains/flap/reader.d.ts +51 -0
- package/dist/domains/flap/reader.js +275 -0
- package/dist/domains/flap/types.d.ts +246 -0
- package/dist/domains/flap/types.js +104 -0
- package/dist/domains/flap/vault/constants.d.ts +220 -0
- package/dist/domains/flap/vault/constants.js +173 -0
- package/dist/domains/flap/vault/encode.d.ts +39 -0
- package/dist/domains/flap/vault/encode.js +135 -0
- package/dist/domains/flap/vault/index.d.ts +15 -0
- package/dist/domains/flap/vault/index.js +14 -0
- package/dist/domains/flap/vault/query.d.ts +40 -0
- package/dist/domains/flap/vault/query.js +104 -0
- package/dist/domains/flap/vault/types.d.ts +147 -0
- package/dist/domains/flap/vault/types.js +29 -0
- package/dist/domains/flap/vault.d.ts +3 -413
- package/dist/domains/flap/vault.js +3 -467
- package/dist/domains/flap/writer.d.ts +124 -0
- package/dist/domains/flap/writer.js +255 -0
- package/dist/domains/four/contracts/tm-bundle-batch.d.ts +35 -0
- package/dist/domains/four/contracts/tm-bundle-batch.js +286 -0
- package/dist/domains/four/contracts/tm-bundle-create.d.ts +2 -0
- package/dist/domains/four/contracts/tm-bundle-create.js +304 -0
- package/dist/domains/four/contracts/tm-bundle-helpers.d.ts +2 -1
- package/dist/domains/four/contracts/tm-bundle-helpers.js +3 -0
- package/dist/domains/four/contracts/tm-bundle-private.d.ts +36 -0
- package/dist/domains/four/contracts/tm-bundle-private.js +164 -0
- package/dist/domains/four/contracts/tm-bundle.d.ts +10 -71
- package/dist/domains/four/contracts/tm-bundle.js +9 -738
- package/dist/domains/lp-inspect/inspect-helpers.d.ts +25 -0
- package/dist/domains/lp-inspect/inspect-helpers.js +343 -0
- package/dist/domains/lp-inspect/inspect.d.ts +8 -0
- package/dist/domains/lp-inspect/inspect.js +332 -0
- package/dist/domains/lp-inspect/lp-inspect.d.ts +9 -37
- package/dist/domains/lp-inspect/lp-inspect.js +9 -775
- package/dist/domains/lp-inspect/registry.d.ts +43 -0
- package/dist/domains/lp-inspect/registry.js +127 -0
- package/dist/domains/merkle/index.d.ts +1 -1
- package/dist/exports/root-bundle-and-tooling.d.ts +9 -1
- package/dist/exports/root-bundle-and-tooling.js +8 -1
- package/dist/exports/root-foundations.d.ts +1 -1
- package/dist/exports/root-foundations.js +1 -1
- package/dist/exports/root-swap-dex-and-xlayer.d.ts +4 -4
- package/dist/exports/root-swap-dex-and-xlayer.js +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/utils/swap-helpers.js +1 -1
- package/package.json +1 -81
|
@@ -1,979 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* direct-router -
|
|
3
|
-
*/
|
|
4
|
-
import { ethers, Wallet, Contract } from 'ethers';
|
|
5
|
-
import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, buildGasFields } from '../../utils/bundle-helpers.js';
|
|
6
|
-
import { getProfitRecipient, CHAINS } from '../../core/constants/index.js';
|
|
7
|
-
import { GAS_LIMITS } from '../../core/constants/index.js';
|
|
8
|
-
import { getErrorMessageFromUnknown } from '../../core/index.js';
|
|
9
|
-
import { ERC20_ABI } from '../../abis/common.js';
|
|
10
|
-
import { getTokenToNativeQuote, quoteV2 } from '../quote/quote-helpers.js';
|
|
11
|
-
import { CHAIN_IDS, DIRECT_ROUTERS, SWAP_ROUTER02_V2_ABI, V2_ROUTER_ABI, V3_ROUTER02_ABI, V3_ROUTER_LEGACY_ABI, buildBribeTransaction, buildProfitTransactionWithHops, calculateProfitAmount, encodeDYORMulticall, encodeDYORRefundETH, encodeDYORSwapExactTokensForTokens, encodeDYORUnwrapWETH9, findMaxFlowIndex, filterEniNativeBuyIndices, getBribeAmount, getCachedProvider, getDeadline, getGasLimit, getGasPrice, getWrappedNative, isDYORSwap, isLegacySwapRouter, isNativeToken, isSwapRouter02, quoteXLayerV3TokenToNativeBySlot0, truncateDecimals, } from './direct-router-helpers.js';
|
|
12
|
-
export { DIRECT_ROUTERS } from './direct-router-helpers.js';
|
|
13
|
-
export async function directV2BatchBuy(params) {
|
|
14
|
-
const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, quoteToken, quoteTokenDecimals = 18, startNonces, config, } = params;
|
|
15
|
-
if (privateKeys.length !== buyAmounts.length) {
|
|
16
|
-
throw new Error('privateKeys 和 buyAmounts 长度必须相同');
|
|
17
|
-
}
|
|
18
|
-
const chainId = config.chainId || CHAIN_IDS[chain.toUpperCase()] || CHAINS.BSC.chainId;
|
|
19
|
-
// ✅ 方案 C:使用缓存的 Provider
|
|
20
|
-
const provider = getCachedProvider(config.rpcUrl, chainId, chain);
|
|
21
|
-
const useNative = isNativeToken(quoteToken);
|
|
22
|
-
const wrappedNative = getWrappedNative(chain);
|
|
23
|
-
// 创建钱包
|
|
24
|
-
const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
|
|
25
|
-
// ✅ 预先计算所有金额(同步操作,无 RPC)
|
|
26
|
-
const flowAmounts = buyAmounts.map((amount) => ethers.parseUnits(amount, quoteTokenDecimals));
|
|
27
|
-
const totalFlowWei = flowAmounts.reduce((sum, amt) => sum + amt, 0n);
|
|
28
|
-
const baseProfitWei = calculateProfitAmount(totalFlowWei);
|
|
29
|
-
// ✅ 方案 B:并行获取 nonces、gasPrice、ERC20 报价 以及(非原生代币时)授权额度
|
|
30
|
-
const quoteTokenContract = !useNative && quoteToken ? new Contract(quoteToken, ERC20_ABI, provider) : null;
|
|
31
|
-
const [nonces, gasPrice, nativeProfitWei, buyAllowances] = await Promise.all([
|
|
32
|
-
startNonces && startNonces.length === wallets.length
|
|
33
|
-
? Promise.resolve(startNonces)
|
|
34
|
-
: new NonceManager(provider).getNextNoncesForWallets(wallets),
|
|
35
|
-
getGasPrice(provider, config),
|
|
36
|
-
!useNative && baseProfitWei > 0n && quoteToken
|
|
37
|
-
? getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v2')
|
|
38
|
-
: Promise.resolve(baseProfitWei),
|
|
39
|
-
quoteTokenContract
|
|
40
|
-
? Promise.all(wallets.map((w) => quoteTokenContract.allowance(w.address, routerAddress).catch(() => 0n)))
|
|
41
|
-
: Promise.resolve(wallets.map(() => ethers.MaxUint256)),
|
|
42
|
-
]);
|
|
43
|
-
// 确定最终利润金额(ENI 链额外补偿利润转账的 gas 成本)
|
|
44
|
-
let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
|
|
45
|
-
if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
|
|
46
|
-
profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
|
|
47
|
-
}
|
|
48
|
-
const gasLimit = getGasLimit(config, 250000);
|
|
49
|
-
const txType = config.txType ?? 0;
|
|
50
|
-
const deadline = getDeadline();
|
|
51
|
-
// ENI 链原生代币买入:链上余额预检,跳过余额不足的钱包
|
|
52
|
-
let activeIndices = null;
|
|
53
|
-
if (useNative && chain.toUpperCase() === 'ENI') {
|
|
54
|
-
const eniBalances = await Promise.all(wallets.map((w) => provider.getBalance(w.address)));
|
|
55
|
-
activeIndices = filterEniNativeBuyIndices(eniBalances, flowAmounts, gasLimit, gasPrice, profitWei);
|
|
56
|
-
}
|
|
57
|
-
// 如果有钱包被跳过,重建数组(仅 ENI)
|
|
58
|
-
let activeWallets = wallets;
|
|
59
|
-
let activeFlowAmounts = flowAmounts;
|
|
60
|
-
let activeNonces = nonces;
|
|
61
|
-
let activeBuyAllowances = buyAllowances;
|
|
62
|
-
if (activeIndices) {
|
|
63
|
-
activeWallets = activeIndices.map((i) => wallets[i]);
|
|
64
|
-
activeFlowAmounts = activeIndices.map((i) => flowAmounts[i]);
|
|
65
|
-
activeNonces = activeIndices.map((i) => nonces[i]);
|
|
66
|
-
activeBuyAllowances = activeIndices.map((i) => buyAllowances[i]);
|
|
67
|
-
}
|
|
68
|
-
const activeTotalFlowWei = activeFlowAmounts.reduce((sum, amt) => sum + amt, 0n);
|
|
69
|
-
const activeBaseProfitWei = calculateProfitAmount(activeTotalFlowWei);
|
|
70
|
-
let activeProfitWei = activeBaseProfitWei > 0n ? activeBaseProfitWei : 0n;
|
|
71
|
-
if (activeProfitWei > 0n && chain.toUpperCase() === 'ENI') {
|
|
72
|
-
activeProfitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
|
|
73
|
-
}
|
|
74
|
-
if (!activeIndices) {
|
|
75
|
-
activeProfitWei = profitWei;
|
|
76
|
-
}
|
|
77
|
-
// ✅ 自动授权:ERC20 报价代币买入时,检查钱包对 Router 的授权额度,不足则插入 approve
|
|
78
|
-
const buyApproveTxs = [];
|
|
79
|
-
if (!useNative && quoteTokenContract) {
|
|
80
|
-
for (let i = 0; i < activeWallets.length; i++) {
|
|
81
|
-
if (activeFlowAmounts[i] <= 0n)
|
|
82
|
-
continue;
|
|
83
|
-
if (activeBuyAllowances[i] < activeFlowAmounts[i]) {
|
|
84
|
-
const approveData = quoteTokenContract.interface.encodeFunctionData('approve', [
|
|
85
|
-
routerAddress,
|
|
86
|
-
ethers.MaxUint256,
|
|
87
|
-
]);
|
|
88
|
-
const approveTx = await activeWallets[i].signTransaction({
|
|
89
|
-
to: quoteToken,
|
|
90
|
-
data: approveData,
|
|
91
|
-
value: 0n,
|
|
92
|
-
nonce: activeNonces[i],
|
|
93
|
-
gasLimit: 60000n,
|
|
94
|
-
...buildGasFields(txType, gasPrice),
|
|
95
|
-
chainId,
|
|
96
|
-
});
|
|
97
|
-
buyApproveTxs.push({ walletIndex: i, tx: approveTx });
|
|
98
|
-
activeNonces[i]++;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// 构建路径
|
|
103
|
-
const inputToken = useNative ? wrappedNative : quoteToken;
|
|
104
|
-
const path = [inputToken, tokenAddress];
|
|
105
|
-
// 判断 Router 类型
|
|
106
|
-
const useSwapRouter02 = isSwapRouter02(chain, routerAddress);
|
|
107
|
-
const useDYORSwap = isDYORSwap(chain, routerAddress);
|
|
108
|
-
const routerIface = useSwapRouter02
|
|
109
|
-
? new ethers.Interface(SWAP_ROUTER02_V2_ABI)
|
|
110
|
-
: new ethers.Interface(V2_ROUTER_ABI);
|
|
111
|
-
// 构建交易数据的辅助函数
|
|
112
|
-
const buildTxData = (wallet, amountWei) => {
|
|
113
|
-
if (useDYORSwap) {
|
|
114
|
-
const DYORSWAP_FACTORY = DIRECT_ROUTERS.XLAYER.DYORSWAP_FACTORY;
|
|
115
|
-
const multicallData = [];
|
|
116
|
-
multicallData.push(encodeDYORRefundETH(30));
|
|
117
|
-
multicallData.push(encodeDYORSwapExactTokensForTokens(useNative ? 0n : amountWei, 0n, path, [], wallet.address, 1n, DYORSWAP_FACTORY));
|
|
118
|
-
return { txData: encodeDYORMulticall(BigInt(deadline), multicallData), txValue: useNative ? amountWei : 0n };
|
|
119
|
-
}
|
|
120
|
-
else if (useSwapRouter02) {
|
|
121
|
-
const swapData = routerIface.encodeFunctionData('swapExactTokensForTokens', [
|
|
122
|
-
amountWei,
|
|
123
|
-
0n,
|
|
124
|
-
path,
|
|
125
|
-
wallet.address,
|
|
126
|
-
]);
|
|
127
|
-
return {
|
|
128
|
-
txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData]]),
|
|
129
|
-
txValue: useNative ? amountWei : 0n,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
else if (useNative) {
|
|
133
|
-
return {
|
|
134
|
-
txData: routerIface.encodeFunctionData('swapExactETHForTokensSupportingFeeOnTransferTokens', [
|
|
135
|
-
0n,
|
|
136
|
-
path,
|
|
137
|
-
wallet.address,
|
|
138
|
-
deadline,
|
|
139
|
-
]),
|
|
140
|
-
txValue: amountWei,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
return {
|
|
145
|
-
txData: routerIface.encodeFunctionData('swapExactTokensForTokensSupportingFeeOnTransferTokens', [
|
|
146
|
-
amountWei,
|
|
147
|
-
0n,
|
|
148
|
-
path,
|
|
149
|
-
wallet.address,
|
|
150
|
-
deadline,
|
|
151
|
-
]),
|
|
152
|
-
txValue: 0n,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
// 选择金额最大的钱包支付贿赂和利润
|
|
157
|
-
const maxFlowIndex = findMaxFlowIndex(activeFlowAmounts);
|
|
158
|
-
// 计算贿赂金额(仅 BSC 链)
|
|
159
|
-
const bribeWei = getBribeAmount(config, chain);
|
|
160
|
-
const hasBribe = bribeWei > 0n && activeWallets.length > 0;
|
|
161
|
-
const hasProfit = activeProfitWei > 0n;
|
|
162
|
-
// 计算 nonce 偏移
|
|
163
|
-
const nonceOffsets = activeWallets.map((_, i) => (i === maxFlowIndex && hasBribe ? 1 : 0));
|
|
164
|
-
// ✅ 方案 A:并行签名所有交易(贿赂、主交易、利润)
|
|
165
|
-
const signPromises = [];
|
|
166
|
-
// 贿赂交易
|
|
167
|
-
if (hasBribe) {
|
|
168
|
-
signPromises.push(buildBribeTransaction(activeWallets[maxFlowIndex], bribeWei, activeNonces[maxFlowIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
|
|
169
|
-
}
|
|
170
|
-
// 主交易(并行签名)
|
|
171
|
-
activeWallets.forEach((wallet, i) => {
|
|
172
|
-
const { txData, txValue } = buildTxData(wallet, activeFlowAmounts[i]);
|
|
173
|
-
signPromises.push(wallet
|
|
174
|
-
.signTransaction({
|
|
175
|
-
to: routerAddress,
|
|
176
|
-
data: txData,
|
|
177
|
-
value: txValue,
|
|
178
|
-
nonce: activeNonces[i] + nonceOffsets[i],
|
|
179
|
-
gasLimit,
|
|
180
|
-
...buildGasFields(txType, gasPrice),
|
|
181
|
-
chainId,
|
|
182
|
-
})
|
|
183
|
-
.then((tx) => ({ type: 'swap', index: i, tx })));
|
|
184
|
-
});
|
|
185
|
-
// ✅ 并行执行所有签名
|
|
186
|
-
const signedResults = await Promise.all(signPromises);
|
|
187
|
-
// 按类型分组并按顺序组装:approve → 贿赂 → 交易
|
|
188
|
-
const approveSignedTxs = buyApproveTxs.sort((a, b) => a.walletIndex - b.walletIndex).map((a) => a.tx);
|
|
189
|
-
const bribeTxs = signedResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
|
|
190
|
-
const swapTxs = signedResults
|
|
191
|
-
.filter((r) => r.type === 'swap')
|
|
192
|
-
.sort((a, b) => a.index - b.index)
|
|
193
|
-
.map((r) => r.tx);
|
|
194
|
-
const signedTxs = [...approveSignedTxs, ...bribeTxs, ...swapTxs];
|
|
195
|
-
// ✅ 检查是否使用分布式利润模式
|
|
196
|
-
const profitMode = config.profitMode || 'single';
|
|
197
|
-
const skipProfit = config.skipProfit === true;
|
|
198
|
-
const profitAddr = getProfitRecipient();
|
|
199
|
-
// 利润多跳转账
|
|
200
|
-
let profitHopWallets;
|
|
201
|
-
if (hasProfit && !skipProfit) {
|
|
202
|
-
if (profitMode === 'distributed') {
|
|
203
|
-
// ✅ 分布式模式:每个钱包独立扣除自己的利润
|
|
204
|
-
const MAX_DISTRIBUTED_WALLETS = 12;
|
|
205
|
-
if (activeWallets.length > MAX_DISTRIBUTED_WALLETS) {
|
|
206
|
-
throw new Error(`分布式利润模式最多支持 ${MAX_DISTRIBUTED_WALLETS} 个钱包,当前 ${activeWallets.length} 个`);
|
|
207
|
-
}
|
|
208
|
-
profitHopWallets = [];
|
|
209
|
-
// 计算每个钱包的利润(按比例分配)
|
|
210
|
-
for (let i = 0; i < activeWallets.length; i++) {
|
|
211
|
-
const walletProfit = activeTotalFlowWei > 0n ? (activeProfitWei * activeFlowAmounts[i]) / activeTotalFlowWei : 0n;
|
|
212
|
-
if (walletProfit > 0n) {
|
|
213
|
-
const walletProfitNonce = activeNonces[i] + nonceOffsets[i] + 1;
|
|
214
|
-
const profitResult = await buildProfitHopTransactions({
|
|
215
|
-
provider,
|
|
216
|
-
payerWallet: activeWallets[i],
|
|
217
|
-
profitAmount: walletProfit,
|
|
218
|
-
profitRecipient: profitAddr,
|
|
219
|
-
hopCount: PROFIT_HOP_COUNT,
|
|
220
|
-
gasPrice,
|
|
221
|
-
chainId,
|
|
222
|
-
txType,
|
|
223
|
-
startNonce: walletProfitNonce,
|
|
224
|
-
});
|
|
225
|
-
signedTxs.push(...profitResult.signedTransactions);
|
|
226
|
-
if (profitResult.hopWallets) {
|
|
227
|
-
profitHopWallets.push(...profitResult.hopWallets);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
// ✅ 单一模式(默认):从金额最大的钱包统一扣除
|
|
234
|
-
const profitNonce = activeNonces[maxFlowIndex] + nonceOffsets[maxFlowIndex] + 1;
|
|
235
|
-
const profitResult = await buildProfitTransactionWithHops(provider, activeWallets[maxFlowIndex], activeProfitWei, profitNonce, gasPrice, chainId, txType, profitAddr);
|
|
236
|
-
signedTxs.push(...profitResult.signedTransactions);
|
|
237
|
-
profitHopWallets = profitResult.hopWallets;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return {
|
|
241
|
-
signedTransactions: signedTxs,
|
|
242
|
-
profitHopWallets,
|
|
243
|
-
metadata: {
|
|
244
|
-
profitMode,
|
|
245
|
-
profitAmount: ethers.formatEther(activeProfitWei),
|
|
246
|
-
profitRecipient: profitAddr,
|
|
247
|
-
totalFlow: ethers.formatUnits(activeTotalFlowWei, quoteTokenDecimals),
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* V2 批量卖出(直接调用 Router)
|
|
253
|
-
*/
|
|
254
|
-
export async function directV2BatchSell(params) {
|
|
255
|
-
const { chain, privateKeys, sellPercentages, sellAmounts, tokenAddress, tokenDecimals: inputDecimals, routerAddress, quoteToken, startNonces, config, } = params;
|
|
256
|
-
const chainId = config.chainId || CHAIN_IDS[chain.toUpperCase()] || CHAINS.BSC.chainId;
|
|
257
|
-
// ✅ 方案 C:使用缓存的 Provider
|
|
258
|
-
const provider = getCachedProvider(config.rpcUrl, chainId, chain);
|
|
259
|
-
const useNativeOutput = isNativeToken(quoteToken);
|
|
260
|
-
const wrappedNative = getWrappedNative(chain);
|
|
261
|
-
// 创建钱包
|
|
262
|
-
const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
|
|
263
|
-
const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
|
|
264
|
-
// ✅ 性能优化:并行获取所有独立的 RPC 数据(包括授权额度)
|
|
265
|
-
const [fetchedDecimals, balances, allowances, nonces, gasPrice] = await Promise.all([
|
|
266
|
-
inputDecimals !== undefined
|
|
267
|
-
? Promise.resolve(inputDecimals)
|
|
268
|
-
: tokenContract
|
|
269
|
-
.decimals()
|
|
270
|
-
.then((d) => Number(d))
|
|
271
|
-
.catch(() => 18),
|
|
272
|
-
Promise.all(wallets.map((w) => tokenContract.balanceOf(w.address))),
|
|
273
|
-
Promise.all(wallets.map((w) => tokenContract.allowance(w.address, routerAddress).catch(() => 0n))),
|
|
274
|
-
startNonces && startNonces.length === wallets.length
|
|
275
|
-
? Promise.resolve(startNonces)
|
|
276
|
-
: new NonceManager(provider).getNextNoncesForWallets(wallets),
|
|
277
|
-
getGasPrice(provider, config),
|
|
278
|
-
]);
|
|
279
|
-
const tokenDecimals = fetchedDecimals;
|
|
280
|
-
const gasLimit = getGasLimit(config, 300000);
|
|
281
|
-
const txType = config.txType ?? 0;
|
|
282
|
-
const deadline = getDeadline();
|
|
283
|
-
// 计算卖出数量(同步操作,无 RPC),并安全兜底不超过链上实际余额
|
|
284
|
-
const sellAmountsWei = [];
|
|
285
|
-
for (let i = 0; i < wallets.length; i++) {
|
|
286
|
-
let amount;
|
|
287
|
-
if (sellAmounts && sellAmounts[i]) {
|
|
288
|
-
const truncatedAmount = truncateDecimals(sellAmounts[i], tokenDecimals);
|
|
289
|
-
amount = ethers.parseUnits(truncatedAmount, tokenDecimals);
|
|
290
|
-
}
|
|
291
|
-
else if (sellPercentages && sellPercentages[i]) {
|
|
292
|
-
const pct = Math.min(100, Math.max(0, sellPercentages[i]));
|
|
293
|
-
amount = (balances[i] * BigInt(pct)) / 100n;
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
amount = balances[i];
|
|
297
|
-
}
|
|
298
|
-
if (amount > balances[i]) {
|
|
299
|
-
amount = balances[i];
|
|
300
|
-
}
|
|
301
|
-
sellAmountsWei.push(amount);
|
|
302
|
-
}
|
|
303
|
-
const totalSellAmount = sellAmountsWei.reduce((sum, o) => sum + o, 0n);
|
|
304
|
-
// ✅ 自动授权:检查每个钱包对 Router 的授权额度,不足则插入 approve 交易
|
|
305
|
-
const approveTxs = [];
|
|
306
|
-
for (let i = 0; i < wallets.length; i++) {
|
|
307
|
-
if (sellAmountsWei[i] <= 0n)
|
|
308
|
-
continue;
|
|
309
|
-
if (allowances[i] < sellAmountsWei[i]) {
|
|
310
|
-
const approveData = tokenContract.interface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]);
|
|
311
|
-
const approveTx = await wallets[i].signTransaction({
|
|
312
|
-
to: tokenAddress,
|
|
313
|
-
data: approveData,
|
|
314
|
-
value: 0n,
|
|
315
|
-
nonce: nonces[i],
|
|
316
|
-
gasLimit: 60000n,
|
|
317
|
-
...buildGasFields(txType, gasPrice),
|
|
318
|
-
chainId,
|
|
319
|
-
});
|
|
320
|
-
approveTxs.push({ walletIndex: i, tx: approveTx });
|
|
321
|
-
nonces[i]++;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
// ✅ 修复:对于卖出操作,利润应基于【得到的 BNB/原生代币】而不是【卖出的代币数量】
|
|
325
|
-
// 使用 V2 Router 获取卖出报价,然后基于预估得到的原生代币数量计算利润
|
|
326
|
-
const nativeProfitPromise = (async () => {
|
|
327
|
-
try {
|
|
328
|
-
if (useNativeOutput) {
|
|
329
|
-
// 卖出代币 → 得到 BNB:先获取 V2 报价,再计算利润(✅ 使用当前 Router 报价,IROSwap 池需用 IROSwap Router)
|
|
330
|
-
const estimatedBNBOut = await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v2', undefined, routerAddress);
|
|
331
|
-
if (estimatedBNBOut <= 0n)
|
|
332
|
-
return 0n;
|
|
333
|
-
const profit = calculateProfitAmount(estimatedBNBOut);
|
|
334
|
-
return profit;
|
|
335
|
-
}
|
|
336
|
-
else if (quoteToken) {
|
|
337
|
-
// 卖出代币 → 得到 ERC20(如 USDT):两阶段报价
|
|
338
|
-
// IROSwap 等 DEX 可能只有 token/USDT 池,无 USDT/WBNB,直接 token→WBNB 会失败
|
|
339
|
-
// 1) 用当前 Router 报价 token→quoteToken(如 VOYA→USDT)
|
|
340
|
-
// 2) 用默认 PancakeSwap 报价 quoteToken→WBNB(USDT/WBNB 在 Pancake 上存在)
|
|
341
|
-
const step1 = await quoteV2(provider, tokenAddress, quoteToken, totalSellAmount, chain, routerAddress);
|
|
342
|
-
if (!step1.amountOut || step1.amountOut <= 0n)
|
|
343
|
-
return 0n;
|
|
344
|
-
const estimatedBNBOut = await getTokenToNativeQuote(provider, quoteToken, step1.amountOut, chain, 'v2');
|
|
345
|
-
if (estimatedBNBOut <= 0n)
|
|
346
|
-
return 0n;
|
|
347
|
-
const profit = calculateProfitAmount(estimatedBNBOut);
|
|
348
|
-
return profit;
|
|
349
|
-
}
|
|
350
|
-
return 0n;
|
|
351
|
-
}
|
|
352
|
-
catch (error) {
|
|
353
|
-
console.error(`[V2 Sell Profit] Error:`, getErrorMessageFromUnknown(error));
|
|
354
|
-
return 0n;
|
|
355
|
-
}
|
|
356
|
-
})();
|
|
357
|
-
// 构建路径和 Router
|
|
358
|
-
const outputToken = useNativeOutput ? wrappedNative : quoteToken;
|
|
359
|
-
const path = [tokenAddress, outputToken];
|
|
360
|
-
const useSwapRouter02 = isSwapRouter02(chain, routerAddress);
|
|
361
|
-
const useDYORSwap = isDYORSwap(chain, routerAddress);
|
|
362
|
-
const routerIface = useSwapRouter02
|
|
363
|
-
? new ethers.Interface(SWAP_ROUTER02_V2_ABI)
|
|
364
|
-
: new ethers.Interface(V2_ROUTER_ABI);
|
|
365
|
-
// 构建卖出交易数据的辅助函数
|
|
366
|
-
const buildSellTxData = (wallet, sellAmount) => {
|
|
367
|
-
if (useDYORSwap) {
|
|
368
|
-
const DYORSWAP_FACTORY = DIRECT_ROUTERS.XLAYER.DYORSWAP_FACTORY;
|
|
369
|
-
const ADDRESS_THIS = 2n;
|
|
370
|
-
const multicallData = [];
|
|
371
|
-
multicallData.push(encodeDYORSwapExactTokensForTokens(sellAmount, 0n, path, [DYORSWAP_FACTORY], ADDRESS_THIS, 1n, DYORSWAP_FACTORY));
|
|
372
|
-
if (useNativeOutput)
|
|
373
|
-
multicallData.push(encodeDYORUnwrapWETH9(0n, wallet.address, '0x'));
|
|
374
|
-
return encodeDYORMulticall(BigInt(deadline), multicallData);
|
|
375
|
-
}
|
|
376
|
-
else if (useSwapRouter02) {
|
|
377
|
-
const ADDRESS_THIS = '0x0000000000000000000000000000000000000002';
|
|
378
|
-
if (useNativeOutput) {
|
|
379
|
-
const multicallData = [
|
|
380
|
-
routerIface.encodeFunctionData('swapExactTokensForTokens', [sellAmount, 0n, path, ADDRESS_THIS]),
|
|
381
|
-
routerIface.encodeFunctionData('unwrapWETH9(uint256,address)', [0n, wallet.address]),
|
|
382
|
-
];
|
|
383
|
-
return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, multicallData]);
|
|
384
|
-
}
|
|
385
|
-
else {
|
|
386
|
-
return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [
|
|
387
|
-
deadline,
|
|
388
|
-
[routerIface.encodeFunctionData('swapExactTokensForTokens', [sellAmount, 0n, path, wallet.address])],
|
|
389
|
-
]);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
else if (useNativeOutput) {
|
|
393
|
-
return routerIface.encodeFunctionData('swapExactTokensForETHSupportingFeeOnTransferTokens', [
|
|
394
|
-
sellAmount,
|
|
395
|
-
0n,
|
|
396
|
-
path,
|
|
397
|
-
wallet.address,
|
|
398
|
-
deadline,
|
|
399
|
-
]);
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
return routerIface.encodeFunctionData('swapExactTokensForTokensSupportingFeeOnTransferTokens', [
|
|
403
|
-
sellAmount,
|
|
404
|
-
0n,
|
|
405
|
-
path,
|
|
406
|
-
wallet.address,
|
|
407
|
-
deadline,
|
|
408
|
-
]);
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
|
|
412
|
-
const bribeWei = getBribeAmount(config, chain);
|
|
413
|
-
const hasBribe = bribeWei > 0n && wallets.length > 0;
|
|
414
|
-
const nonceOffsets = wallets.map((_, i) => (i === maxOutputIndex && hasBribe ? 1 : 0));
|
|
415
|
-
// ✅ 方案 A:并行签名所有交易(贿赂、卖出、利润)+ 并行获取 ERC20 报价
|
|
416
|
-
const signPromises = [];
|
|
417
|
-
// 贿赂交易
|
|
418
|
-
if (hasBribe) {
|
|
419
|
-
signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
|
|
420
|
-
}
|
|
421
|
-
// 卖出交易(并行签名)
|
|
422
|
-
wallets.forEach((wallet, i) => {
|
|
423
|
-
if (sellAmountsWei[i] <= 0n)
|
|
424
|
-
return;
|
|
425
|
-
signPromises.push(wallet
|
|
426
|
-
.signTransaction({
|
|
427
|
-
to: routerAddress,
|
|
428
|
-
data: buildSellTxData(wallet, sellAmountsWei[i]),
|
|
429
|
-
value: 0n,
|
|
430
|
-
nonce: nonces[i] + nonceOffsets[i],
|
|
431
|
-
gasLimit,
|
|
432
|
-
...buildGasFields(txType, gasPrice),
|
|
433
|
-
chainId,
|
|
434
|
-
})
|
|
435
|
-
.then((tx) => ({ type: 'swap', index: i, tx })));
|
|
436
|
-
});
|
|
437
|
-
// ✅ 并行执行:签名 + ERC20 报价
|
|
438
|
-
const [signedResults, nativeProfitWei] = await Promise.all([Promise.all(signPromises), nativeProfitPromise]);
|
|
439
|
-
let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
|
|
440
|
-
if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
|
|
441
|
-
profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
|
|
442
|
-
}
|
|
443
|
-
// ✅ 检查是否使用分布式利润模式
|
|
444
|
-
const profitMode = config.profitMode || 'single';
|
|
445
|
-
const skipProfit = config.skipProfit === true;
|
|
446
|
-
const profitAddr = getProfitRecipient();
|
|
447
|
-
// 利润多跳转账
|
|
448
|
-
let profitTxs = [];
|
|
449
|
-
let profitHopWallets;
|
|
450
|
-
if (profitWei > 0n && wallets.length > 0 && !skipProfit) {
|
|
451
|
-
if (profitMode === 'distributed') {
|
|
452
|
-
// ✅ 分布式模式:每个钱包独立扣除自己的利润
|
|
453
|
-
const MAX_DISTRIBUTED_WALLETS = 12;
|
|
454
|
-
if (wallets.length > MAX_DISTRIBUTED_WALLETS) {
|
|
455
|
-
throw new Error(`分布式利润模式最多支持 ${MAX_DISTRIBUTED_WALLETS} 个钱包,当前 ${wallets.length} 个`);
|
|
456
|
-
}
|
|
457
|
-
profitHopWallets = [];
|
|
458
|
-
// 计算每个钱包的利润(按卖出金额比例分配)
|
|
459
|
-
for (let i = 0; i < wallets.length; i++) {
|
|
460
|
-
const walletProfit = totalSellAmount > 0n ? (profitWei * sellAmountsWei[i]) / totalSellAmount : 0n;
|
|
461
|
-
if (walletProfit > 0n) {
|
|
462
|
-
const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
|
|
463
|
-
const profitResult = await buildProfitHopTransactions({
|
|
464
|
-
provider,
|
|
465
|
-
payerWallet: wallets[i],
|
|
466
|
-
profitAmount: walletProfit,
|
|
467
|
-
profitRecipient: profitAddr,
|
|
468
|
-
hopCount: PROFIT_HOP_COUNT,
|
|
469
|
-
gasPrice,
|
|
470
|
-
chainId,
|
|
471
|
-
txType,
|
|
472
|
-
startNonce: walletProfitNonce,
|
|
473
|
-
});
|
|
474
|
-
profitTxs.push(...profitResult.signedTransactions);
|
|
475
|
-
if (profitResult.hopWallets) {
|
|
476
|
-
profitHopWallets.push(...profitResult.hopWallets);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
else {
|
|
482
|
-
// ✅ 单一模式(默认):从卖出金额最大的钱包统一扣除
|
|
483
|
-
const profitNonce = nonces[maxOutputIndex] + nonceOffsets[maxOutputIndex] + 1;
|
|
484
|
-
const profitResult = await buildProfitTransactionWithHops(provider, wallets[maxOutputIndex], profitWei, profitNonce, gasPrice, chainId, txType, profitAddr);
|
|
485
|
-
profitTxs = profitResult.signedTransactions;
|
|
486
|
-
profitHopWallets = profitResult.hopWallets;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
// 按类型分组并按顺序组装:approve → bribe → swap → profit
|
|
490
|
-
const validResults = signedResults.filter((r) => r !== null);
|
|
491
|
-
const bribeTxs = validResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
|
|
492
|
-
const swapTxs = validResults
|
|
493
|
-
.filter((r) => r.type === 'swap')
|
|
494
|
-
.sort((a, b) => a.index - b.index)
|
|
495
|
-
.map((r) => r.tx);
|
|
496
|
-
const approveSignedTxs = approveTxs.sort((a, b) => a.walletIndex - b.walletIndex).map((a) => a.tx);
|
|
497
|
-
const signedTxs = [...approveSignedTxs, ...bribeTxs, ...swapTxs, ...profitTxs];
|
|
498
|
-
return {
|
|
499
|
-
signedTransactions: signedTxs,
|
|
500
|
-
profitHopWallets,
|
|
501
|
-
metadata: {
|
|
502
|
-
profitMode, // ✅ 返回使用的利润模式
|
|
503
|
-
profitAmount: ethers.formatEther(profitWei),
|
|
504
|
-
profitRecipient: profitAddr,
|
|
505
|
-
totalFlow: ethers.formatEther(totalSellAmount),
|
|
506
|
-
},
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
// ============================================================================
|
|
510
|
-
// V3 直接交易
|
|
511
|
-
// ============================================================================
|
|
512
|
-
/**
|
|
513
|
-
* V3 批量买入(直接调用 Router)
|
|
514
|
-
*
|
|
515
|
-
* 自动识别 SwapRouter 版本:
|
|
516
|
-
* - SwapRouter02 (PancakeSwap V3): exactInputSingle 不含 deadline,multicall 含 deadline
|
|
517
|
-
* - SwapRouter (旧版 Uniswap V3): exactInputSingle 含 deadline,multicall 不含 deadline
|
|
518
|
-
*/
|
|
519
|
-
export async function directV3BatchBuy(params) {
|
|
520
|
-
const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, fee, quoteToken, quoteTokenDecimals = 18, startNonces, config, } = params;
|
|
521
|
-
if (privateKeys.length !== buyAmounts.length) {
|
|
522
|
-
throw new Error('privateKeys 和 buyAmounts 长度必须相同');
|
|
523
|
-
}
|
|
524
|
-
const chainId = config.chainId || CHAIN_IDS[chain.toUpperCase()] || CHAINS.BSC.chainId;
|
|
525
|
-
// ✅ 方案 C:使用缓存的 Provider
|
|
526
|
-
const provider = getCachedProvider(config.rpcUrl, chainId, chain);
|
|
527
|
-
const useNative = isNativeToken(quoteToken);
|
|
528
|
-
const wrappedNative = getWrappedNative(chain);
|
|
529
|
-
const useLegacyRouter = isLegacySwapRouter(chain, routerAddress);
|
|
530
|
-
const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
|
|
531
|
-
const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
|
|
532
|
-
// ✅ 预先计算所有金额(同步操作,无 RPC)
|
|
533
|
-
const flowAmounts = buyAmounts.map((amount) => ethers.parseUnits(amount, quoteTokenDecimals));
|
|
534
|
-
const totalFlowWei = flowAmounts.reduce((sum, amt) => sum + amt, 0n);
|
|
535
|
-
const baseProfitWei = calculateProfitAmount(totalFlowWei);
|
|
536
|
-
// ✅ 方案 B:并行获取 nonces、gasPrice 和 ERC20 报价
|
|
537
|
-
const [nonces, gasPrice, nativeProfitWei] = await Promise.all([
|
|
538
|
-
startNonces && startNonces.length === wallets.length
|
|
539
|
-
? Promise.resolve(startNonces)
|
|
540
|
-
: new NonceManager(provider).getNextNoncesForWallets(wallets),
|
|
541
|
-
getGasPrice(provider, config),
|
|
542
|
-
// ERC20 报价(V3 买入用 V3 报价)
|
|
543
|
-
!useNative && baseProfitWei > 0n && quoteToken
|
|
544
|
-
? chain.toUpperCase() === 'XLAYER'
|
|
545
|
-
? quoteXLayerV3TokenToNativeBySlot0({ provider, tokenIn: quoteToken, amountIn: baseProfitWei, fee })
|
|
546
|
-
: getTokenToNativeQuote(provider, quoteToken, baseProfitWei, chain, 'v3', fee)
|
|
547
|
-
: Promise.resolve(baseProfitWei),
|
|
548
|
-
]);
|
|
549
|
-
let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
|
|
550
|
-
if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
|
|
551
|
-
profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
|
|
552
|
-
}
|
|
553
|
-
const gasLimit = getGasLimit(config, 300000);
|
|
554
|
-
const txType = config.txType ?? 0;
|
|
555
|
-
const routerIface = new ethers.Interface(routerAbi);
|
|
556
|
-
const inputToken = useNative ? wrappedNative : quoteToken;
|
|
557
|
-
const deadline = getDeadline();
|
|
558
|
-
// 构建交易数据的辅助函数
|
|
559
|
-
const buildV3BuyTxData = (wallet, amountWei) => {
|
|
560
|
-
if (useLegacyRouter) {
|
|
561
|
-
const swapParams = {
|
|
562
|
-
tokenIn: inputToken,
|
|
563
|
-
tokenOut: tokenAddress,
|
|
564
|
-
fee,
|
|
565
|
-
recipient: wallet.address,
|
|
566
|
-
deadline,
|
|
567
|
-
amountIn: amountWei,
|
|
568
|
-
amountOutMinimum: 0n,
|
|
569
|
-
sqrtPriceLimitX96: 0n,
|
|
570
|
-
};
|
|
571
|
-
if (useNative) {
|
|
572
|
-
const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
|
|
573
|
-
const refundData = routerIface.encodeFunctionData('refundETH', []);
|
|
574
|
-
return {
|
|
575
|
-
txData: routerIface.encodeFunctionData('multicall(bytes[])', [[swapData, refundData]]),
|
|
576
|
-
txValue: amountWei,
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
return { txData: routerIface.encodeFunctionData('exactInputSingle', [swapParams]), txValue: 0n };
|
|
580
|
-
}
|
|
581
|
-
else {
|
|
582
|
-
const swapParams = {
|
|
583
|
-
tokenIn: inputToken,
|
|
584
|
-
tokenOut: tokenAddress,
|
|
585
|
-
fee,
|
|
586
|
-
recipient: wallet.address,
|
|
587
|
-
amountIn: amountWei,
|
|
588
|
-
amountOutMinimum: 0n,
|
|
589
|
-
sqrtPriceLimitX96: 0n,
|
|
590
|
-
};
|
|
591
|
-
if (useNative) {
|
|
592
|
-
const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
|
|
593
|
-
const refundData = routerIface.encodeFunctionData('refundETH', []);
|
|
594
|
-
return {
|
|
595
|
-
txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData, refundData]]),
|
|
596
|
-
txValue: amountWei,
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
// ✅ 修复:ERC20 买入也需要使用 multicall 包装以传递 deadline
|
|
600
|
-
// SwapRouter02 的 exactInputSingle 不包含 deadline 参数,必须通过 multicall 传递
|
|
601
|
-
const swapData = routerIface.encodeFunctionData('exactInputSingle', [swapParams]);
|
|
602
|
-
return {
|
|
603
|
-
txData: routerIface.encodeFunctionData('multicall(uint256,bytes[])', [deadline, [swapData]]),
|
|
604
|
-
txValue: 0n,
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
};
|
|
608
|
-
const maxFlowIndex = findMaxFlowIndex(flowAmounts);
|
|
609
|
-
const bribeWei = getBribeAmount(config, chain);
|
|
610
|
-
const hasBribe = bribeWei > 0n && wallets.length > 0;
|
|
611
|
-
const hasProfit = profitWei > 0n;
|
|
612
|
-
const nonceOffsets = wallets.map((_, i) => (i === maxFlowIndex && hasBribe ? 1 : 0));
|
|
613
|
-
// ✅ 方案 A:并行签名所有交易(贿赂、主交易、利润)
|
|
614
|
-
const signPromises = [];
|
|
615
|
-
if (hasBribe) {
|
|
616
|
-
signPromises.push(buildBribeTransaction(wallets[maxFlowIndex], bribeWei, nonces[maxFlowIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
|
|
617
|
-
}
|
|
618
|
-
wallets.forEach((wallet, i) => {
|
|
619
|
-
const { txData, txValue } = buildV3BuyTxData(wallet, flowAmounts[i]);
|
|
620
|
-
signPromises.push(wallet
|
|
621
|
-
.signTransaction({
|
|
622
|
-
to: routerAddress,
|
|
623
|
-
data: txData,
|
|
624
|
-
value: txValue,
|
|
625
|
-
nonce: nonces[i] + nonceOffsets[i],
|
|
626
|
-
gasLimit,
|
|
627
|
-
...buildGasFields(txType, gasPrice),
|
|
628
|
-
chainId,
|
|
629
|
-
})
|
|
630
|
-
.then((tx) => ({ type: 'swap', index: i, tx })));
|
|
631
|
-
});
|
|
632
|
-
const signedResults = await Promise.all(signPromises);
|
|
633
|
-
const bribeTxs = signedResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
|
|
634
|
-
const swapTxs = signedResults
|
|
635
|
-
.filter((r) => r.type === 'swap')
|
|
636
|
-
.sort((a, b) => a.index - b.index)
|
|
637
|
-
.map((r) => r.tx);
|
|
638
|
-
// ✅ 检查是否使用分布式利润模式
|
|
639
|
-
const profitMode = config.profitMode || 'single';
|
|
640
|
-
const skipProfit = config.skipProfit === true;
|
|
641
|
-
const profitAddr = getProfitRecipient();
|
|
642
|
-
// 利润多跳转账
|
|
643
|
-
let profitTxs = [];
|
|
644
|
-
let profitHopWallets;
|
|
645
|
-
if (hasProfit && !skipProfit) {
|
|
646
|
-
if (profitMode === 'distributed') {
|
|
647
|
-
// ✅ 分布式模式:每个钱包独立扣除自己的利润
|
|
648
|
-
const MAX_DISTRIBUTED_WALLETS = 12;
|
|
649
|
-
if (wallets.length > MAX_DISTRIBUTED_WALLETS) {
|
|
650
|
-
throw new Error(`分布式利润模式最多支持 ${MAX_DISTRIBUTED_WALLETS} 个钱包,当前 ${wallets.length} 个`);
|
|
651
|
-
}
|
|
652
|
-
profitHopWallets = [];
|
|
653
|
-
// 计算每个钱包的利润(按比例分配)
|
|
654
|
-
for (let i = 0; i < wallets.length; i++) {
|
|
655
|
-
const walletProfit = totalFlowWei > 0n ? (profitWei * flowAmounts[i]) / totalFlowWei : 0n;
|
|
656
|
-
if (walletProfit > 0n) {
|
|
657
|
-
const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
|
|
658
|
-
const profitResult = await buildProfitHopTransactions({
|
|
659
|
-
provider,
|
|
660
|
-
payerWallet: wallets[i],
|
|
661
|
-
profitAmount: walletProfit,
|
|
662
|
-
profitRecipient: profitAddr,
|
|
663
|
-
hopCount: PROFIT_HOP_COUNT,
|
|
664
|
-
gasPrice,
|
|
665
|
-
chainId,
|
|
666
|
-
txType,
|
|
667
|
-
startNonce: walletProfitNonce,
|
|
668
|
-
});
|
|
669
|
-
profitTxs.push(...profitResult.signedTransactions);
|
|
670
|
-
if (profitResult.hopWallets) {
|
|
671
|
-
profitHopWallets.push(...profitResult.hopWallets);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
else {
|
|
677
|
-
// ✅ 单一模式(默认):从金额最大的钱包统一扣除
|
|
678
|
-
const profitNonce = nonces[maxFlowIndex] + nonceOffsets[maxFlowIndex] + 1;
|
|
679
|
-
const profitResult = await buildProfitTransactionWithHops(provider, wallets[maxFlowIndex], profitWei, profitNonce, gasPrice, chainId, txType, profitAddr);
|
|
680
|
-
profitTxs = profitResult.signedTransactions;
|
|
681
|
-
profitHopWallets = profitResult.hopWallets;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
|
|
685
|
-
return {
|
|
686
|
-
signedTransactions: signedTxs,
|
|
687
|
-
profitHopWallets,
|
|
688
|
-
metadata: {
|
|
689
|
-
profitMode, // ✅ 返回使用的利润模式
|
|
690
|
-
profitAmount: ethers.formatEther(profitWei),
|
|
691
|
-
profitRecipient: profitAddr,
|
|
692
|
-
totalFlow: ethers.formatUnits(totalFlowWei, quoteTokenDecimals),
|
|
693
|
-
},
|
|
694
|
-
};
|
|
695
|
-
}
|
|
696
|
-
/**
|
|
697
|
-
* V3 批量卖出(直接调用 Router)
|
|
2
|
+
* direct-router - 主入口(barrel re-export)
|
|
698
3
|
*
|
|
699
|
-
*
|
|
700
|
-
* -
|
|
701
|
-
* -
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
const useNativeOutput = isNativeToken(quoteToken);
|
|
709
|
-
const wrappedNative = getWrappedNative(chain);
|
|
710
|
-
const useLegacyRouter = isLegacySwapRouter(chain, routerAddress);
|
|
711
|
-
const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
|
|
712
|
-
const wallets = privateKeys.map((pk) => new Wallet(pk, provider));
|
|
713
|
-
const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
|
|
714
|
-
// ✅ 并行获取所有 RPC 数据
|
|
715
|
-
const [balances, nonces, gasPrice] = await Promise.all([
|
|
716
|
-
Promise.all(wallets.map((w) => tokenContract.balanceOf(w.address))),
|
|
717
|
-
startNonces && startNonces.length === wallets.length
|
|
718
|
-
? Promise.resolve(startNonces)
|
|
719
|
-
: new NonceManager(provider).getNextNoncesForWallets(wallets),
|
|
720
|
-
getGasPrice(provider, config),
|
|
721
|
-
]);
|
|
722
|
-
const gasLimit = getGasLimit(config, 350000);
|
|
723
|
-
const txType = config.txType ?? 0;
|
|
724
|
-
// 计算卖出数量(同步操作,无 RPC)
|
|
725
|
-
const sellAmountsWei = [];
|
|
726
|
-
for (let i = 0; i < wallets.length; i++) {
|
|
727
|
-
if (sellAmounts && sellAmounts[i]) {
|
|
728
|
-
sellAmountsWei.push(ethers.parseUnits(sellAmounts[i], tokenDecimals));
|
|
729
|
-
}
|
|
730
|
-
else if (sellPercentages && sellPercentages[i]) {
|
|
731
|
-
const pct = Math.min(100, Math.max(0, sellPercentages[i]));
|
|
732
|
-
sellAmountsWei.push((balances[i] * BigInt(pct)) / 100n);
|
|
733
|
-
}
|
|
734
|
-
else {
|
|
735
|
-
sellAmountsWei.push(balances[i]);
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
const totalSellAmount = sellAmountsWei.reduce((sum, o) => sum + o, 0n);
|
|
739
|
-
// ✅ 修复:对于卖出操作,利润应基于【得到的 BNB/原生代币】而不是【卖出的代币数量】
|
|
740
|
-
// 使用 V2 Router 获取卖出报价,然后基于预估得到的原生代币数量计算利润
|
|
741
|
-
const nativeProfitPromise = (async () => {
|
|
742
|
-
try {
|
|
743
|
-
if (useNativeOutput) {
|
|
744
|
-
// 卖出代币 → 得到 BNB:先获取 V3 报价,再计算利润
|
|
745
|
-
const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
|
|
746
|
-
? await quoteXLayerV3TokenToNativeBySlot0({
|
|
747
|
-
provider,
|
|
748
|
-
tokenIn: tokenAddress,
|
|
749
|
-
amountIn: totalSellAmount,
|
|
750
|
-
fee,
|
|
751
|
-
})
|
|
752
|
-
: await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
|
|
753
|
-
if (estimatedBNBOut <= 0n)
|
|
754
|
-
return 0n;
|
|
755
|
-
const profit = calculateProfitAmount(estimatedBNBOut);
|
|
756
|
-
return profit;
|
|
757
|
-
}
|
|
758
|
-
else if (quoteToken) {
|
|
759
|
-
// 卖出代币 → 得到 ERC20:先获取 V3 报价,再计算利润
|
|
760
|
-
const estimatedBNBOut = chain.toUpperCase() === 'XLAYER'
|
|
761
|
-
? await quoteXLayerV3TokenToNativeBySlot0({
|
|
762
|
-
provider,
|
|
763
|
-
tokenIn: tokenAddress,
|
|
764
|
-
amountIn: totalSellAmount,
|
|
765
|
-
fee,
|
|
766
|
-
})
|
|
767
|
-
: await getTokenToNativeQuote(provider, tokenAddress, totalSellAmount, chain, 'v3', fee);
|
|
768
|
-
if (estimatedBNBOut <= 0n)
|
|
769
|
-
return 0n;
|
|
770
|
-
const profit = calculateProfitAmount(estimatedBNBOut);
|
|
771
|
-
return profit;
|
|
772
|
-
}
|
|
773
|
-
return 0n;
|
|
774
|
-
}
|
|
775
|
-
catch (error) {
|
|
776
|
-
console.error(`[V3 Sell Profit] Error:`, getErrorMessageFromUnknown(error));
|
|
777
|
-
return 0n;
|
|
778
|
-
}
|
|
779
|
-
})();
|
|
780
|
-
const routerIface = new ethers.Interface(routerAbi);
|
|
781
|
-
const outputToken = useNativeOutput ? wrappedNative : quoteToken;
|
|
782
|
-
const deadline = getDeadline();
|
|
783
|
-
// 构建卖出交易数据的辅助函数
|
|
784
|
-
const buildV3SellTxData = (wallet, sellAmount) => {
|
|
785
|
-
if (useLegacyRouter) {
|
|
786
|
-
const swapParams = {
|
|
787
|
-
tokenIn: tokenAddress,
|
|
788
|
-
tokenOut: outputToken,
|
|
789
|
-
fee,
|
|
790
|
-
recipient: useNativeOutput ? routerAddress : wallet.address,
|
|
791
|
-
deadline,
|
|
792
|
-
amountIn: sellAmount,
|
|
793
|
-
amountOutMinimum: 0n,
|
|
794
|
-
sqrtPriceLimitX96: 0n,
|
|
795
|
-
};
|
|
796
|
-
if (useNativeOutput) {
|
|
797
|
-
return routerIface.encodeFunctionData('multicall(bytes[])', [
|
|
798
|
-
[
|
|
799
|
-
routerIface.encodeFunctionData('exactInputSingle', [swapParams]),
|
|
800
|
-
routerIface.encodeFunctionData('unwrapWETH9', [0n, wallet.address]),
|
|
801
|
-
],
|
|
802
|
-
]);
|
|
803
|
-
}
|
|
804
|
-
// ✅ 修复:ERC20 输出也需要使用 multicall 包装以传递 deadline
|
|
805
|
-
return routerIface.encodeFunctionData('multicall(bytes[])', [
|
|
806
|
-
[routerIface.encodeFunctionData('exactInputSingle', [swapParams])],
|
|
807
|
-
]);
|
|
808
|
-
}
|
|
809
|
-
else {
|
|
810
|
-
const swapParams = {
|
|
811
|
-
tokenIn: tokenAddress,
|
|
812
|
-
tokenOut: outputToken,
|
|
813
|
-
fee,
|
|
814
|
-
recipient: useNativeOutput ? routerAddress : wallet.address,
|
|
815
|
-
amountIn: sellAmount,
|
|
816
|
-
amountOutMinimum: 0n,
|
|
817
|
-
sqrtPriceLimitX96: 0n,
|
|
818
|
-
};
|
|
819
|
-
if (useNativeOutput) {
|
|
820
|
-
return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [
|
|
821
|
-
deadline,
|
|
822
|
-
[
|
|
823
|
-
routerIface.encodeFunctionData('exactInputSingle', [swapParams]),
|
|
824
|
-
routerIface.encodeFunctionData('unwrapWETH9', [0n, wallet.address]),
|
|
825
|
-
],
|
|
826
|
-
]);
|
|
827
|
-
}
|
|
828
|
-
// ✅ 修复:ERC20 输出也需要使用 multicall 包装以传递 deadline
|
|
829
|
-
return routerIface.encodeFunctionData('multicall(uint256,bytes[])', [
|
|
830
|
-
deadline,
|
|
831
|
-
[routerIface.encodeFunctionData('exactInputSingle', [swapParams])],
|
|
832
|
-
]);
|
|
833
|
-
}
|
|
834
|
-
};
|
|
835
|
-
const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
|
|
836
|
-
const bribeWei = getBribeAmount(config, chain);
|
|
837
|
-
const hasBribe = bribeWei > 0n && wallets.length > 0;
|
|
838
|
-
const nonceOffsets = wallets.map((_, i) => (i === maxOutputIndex && hasBribe ? 1 : 0));
|
|
839
|
-
// ✅ 方案 A:并行签名所有交易(贿赂、卖出)+ 并行获取 ERC20 报价
|
|
840
|
-
const signPromises = [];
|
|
841
|
-
if (hasBribe) {
|
|
842
|
-
signPromises.push(buildBribeTransaction(wallets[maxOutputIndex], bribeWei, nonces[maxOutputIndex], gasPrice, chainId, txType).then((tx) => ({ type: 'bribe', index: 0, tx })));
|
|
843
|
-
}
|
|
844
|
-
wallets.forEach((wallet, i) => {
|
|
845
|
-
if (sellAmountsWei[i] <= 0n)
|
|
846
|
-
return;
|
|
847
|
-
signPromises.push(wallet
|
|
848
|
-
.signTransaction({
|
|
849
|
-
to: routerAddress,
|
|
850
|
-
data: buildV3SellTxData(wallet, sellAmountsWei[i]),
|
|
851
|
-
value: 0n,
|
|
852
|
-
nonce: nonces[i] + nonceOffsets[i],
|
|
853
|
-
gasLimit,
|
|
854
|
-
...buildGasFields(txType, gasPrice),
|
|
855
|
-
chainId,
|
|
856
|
-
})
|
|
857
|
-
.then((tx) => ({ type: 'swap', index: i, tx })));
|
|
858
|
-
});
|
|
859
|
-
// ✅ 并行执行:签名 + ERC20 报价
|
|
860
|
-
const [signedResults, nativeProfitWei] = await Promise.all([Promise.all(signPromises), nativeProfitPromise]);
|
|
861
|
-
let profitWei = nativeProfitWei > 0n ? nativeProfitWei : 0n;
|
|
862
|
-
if (profitWei > 0n && chain.toUpperCase() === 'ENI') {
|
|
863
|
-
profitWei += GAS_LIMITS.NATIVE_TRANSFER * gasPrice;
|
|
864
|
-
}
|
|
865
|
-
// ✅ 检查是否使用分布式利润模式
|
|
866
|
-
const profitMode = config.profitMode || 'single';
|
|
867
|
-
const skipProfit = config.skipProfit === true;
|
|
868
|
-
const profitAddr = getProfitRecipient();
|
|
869
|
-
// 利润多跳转账
|
|
870
|
-
let profitTxs = [];
|
|
871
|
-
let profitHopWallets;
|
|
872
|
-
if (profitWei > 0n && wallets.length > 0 && !skipProfit) {
|
|
873
|
-
if (profitMode === 'distributed') {
|
|
874
|
-
// ✅ 分布式模式:每个钱包独立扣除自己的利润
|
|
875
|
-
const MAX_DISTRIBUTED_WALLETS = 12;
|
|
876
|
-
if (wallets.length > MAX_DISTRIBUTED_WALLETS) {
|
|
877
|
-
throw new Error(`分布式利润模式最多支持 ${MAX_DISTRIBUTED_WALLETS} 个钱包,当前 ${wallets.length} 个`);
|
|
878
|
-
}
|
|
879
|
-
profitHopWallets = [];
|
|
880
|
-
// 计算每个钱包的利润(按卖出金额比例分配)
|
|
881
|
-
for (let i = 0; i < wallets.length; i++) {
|
|
882
|
-
const walletProfit = totalSellAmount > 0n ? (profitWei * sellAmountsWei[i]) / totalSellAmount : 0n;
|
|
883
|
-
if (walletProfit > 0n) {
|
|
884
|
-
const walletProfitNonce = nonces[i] + nonceOffsets[i] + 1;
|
|
885
|
-
const profitResult = await buildProfitHopTransactions({
|
|
886
|
-
provider,
|
|
887
|
-
payerWallet: wallets[i],
|
|
888
|
-
profitAmount: walletProfit,
|
|
889
|
-
profitRecipient: profitAddr,
|
|
890
|
-
hopCount: PROFIT_HOP_COUNT,
|
|
891
|
-
gasPrice,
|
|
892
|
-
chainId,
|
|
893
|
-
txType,
|
|
894
|
-
startNonce: walletProfitNonce,
|
|
895
|
-
});
|
|
896
|
-
profitTxs.push(...profitResult.signedTransactions);
|
|
897
|
-
if (profitResult.hopWallets) {
|
|
898
|
-
profitHopWallets.push(...profitResult.hopWallets);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
else {
|
|
904
|
-
// ✅ 单一模式(默认):从卖出金额最大的钱包统一扣除
|
|
905
|
-
const profitNonce = nonces[maxOutputIndex] + nonceOffsets[maxOutputIndex] + 1;
|
|
906
|
-
const profitResult = await buildProfitTransactionWithHops(provider, wallets[maxOutputIndex], profitWei, profitNonce, gasPrice, chainId, txType, profitAddr);
|
|
907
|
-
profitTxs = profitResult.signedTransactions;
|
|
908
|
-
profitHopWallets = profitResult.hopWallets;
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
// 按类型分组并按顺序组装
|
|
912
|
-
const validResults = signedResults.filter((r) => r !== null);
|
|
913
|
-
const bribeTxs = validResults.filter((r) => r.type === 'bribe').map((r) => r.tx);
|
|
914
|
-
const swapTxs = validResults
|
|
915
|
-
.filter((r) => r.type === 'swap')
|
|
916
|
-
.sort((a, b) => a.index - b.index)
|
|
917
|
-
.map((r) => r.tx);
|
|
918
|
-
const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
|
|
919
|
-
return {
|
|
920
|
-
signedTransactions: signedTxs,
|
|
921
|
-
profitHopWallets,
|
|
922
|
-
metadata: {
|
|
923
|
-
profitMode, // ✅ 返回使用的利润模式
|
|
924
|
-
profitAmount: ethers.formatEther(profitWei),
|
|
925
|
-
profitRecipient: profitAddr,
|
|
926
|
-
totalFlow: ethers.formatEther(totalSellAmount),
|
|
927
|
-
},
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
// ============================================================================
|
|
931
|
-
// 辅助函数:获取 Router 地址
|
|
932
|
-
// ============================================================================
|
|
933
|
-
/**
|
|
934
|
-
* 根据链和 DEX 获取 Router 地址
|
|
935
|
-
*/
|
|
936
|
-
export function getRouterAddress(chain, dexKey, version) {
|
|
937
|
-
const chainUpper = chain.toUpperCase();
|
|
938
|
-
if (chainUpper === 'BSC') {
|
|
939
|
-
if (dexKey === 'IROSWAP') {
|
|
940
|
-
return DIRECT_ROUTERS.BSC.IROSWAP_V2;
|
|
941
|
-
}
|
|
942
|
-
if (version === 'v2')
|
|
943
|
-
return DIRECT_ROUTERS.BSC.PANCAKESWAP_V2;
|
|
944
|
-
return DIRECT_ROUTERS.BSC.PANCAKESWAP_V3;
|
|
945
|
-
}
|
|
946
|
-
if (chainUpper === 'MONAD') {
|
|
947
|
-
if (dexKey === 'UNISWAP') {
|
|
948
|
-
if (version === 'v2')
|
|
949
|
-
return DIRECT_ROUTERS.MONAD.UNISWAP_V2;
|
|
950
|
-
return DIRECT_ROUTERS.MONAD.UNISWAP_V3;
|
|
951
|
-
}
|
|
952
|
-
// PancakeSwap on Monad - 支持 V2 和 V3
|
|
953
|
-
if (version === 'v2')
|
|
954
|
-
return DIRECT_ROUTERS.MONAD.PANCAKESWAP_V2;
|
|
955
|
-
return DIRECT_ROUTERS.MONAD.PANCAKESWAP_V3;
|
|
956
|
-
}
|
|
957
|
-
// ✅ XLayer: PotatoSwap 和 DYORSwap 支持
|
|
958
|
-
if (chainUpper === 'XLAYER') {
|
|
959
|
-
if (dexKey === 'DYORSWAP') {
|
|
960
|
-
// DYORSwap 使用 SwapRouter02 风格(multicall)
|
|
961
|
-
return DIRECT_ROUTERS.XLAYER.DYORSWAP_ROUTER;
|
|
962
|
-
}
|
|
963
|
-
// ✅ 修复:根据 version 返回正确的 PotatoSwap Router
|
|
964
|
-
if (version === 'v3') {
|
|
965
|
-
return DIRECT_ROUTERS.XLAYER.POTATOSWAP_V3;
|
|
966
|
-
}
|
|
967
|
-
return DIRECT_ROUTERS.XLAYER.POTATOSWAP_V2;
|
|
968
|
-
}
|
|
969
|
-
if (chainUpper === 'ENI') {
|
|
970
|
-
if (dexKey === 'IROSWAP') {
|
|
971
|
-
return DIRECT_ROUTERS.ENI.IROSWAP_V2;
|
|
972
|
-
}
|
|
973
|
-
if (version === 'v3') {
|
|
974
|
-
return DIRECT_ROUTERS.ENI.DSWAP_V3;
|
|
975
|
-
}
|
|
976
|
-
return DIRECT_ROUTERS.ENI.DSWAP_V2;
|
|
977
|
-
}
|
|
978
|
-
throw new Error(`Unsupported chain/dex combination: ${chain}/${dexKey}`);
|
|
979
|
-
}
|
|
4
|
+
* 实现已按版本拆分到子文件:
|
|
5
|
+
* - direct-router-v2.ts: V2 批量买卖 directV2BatchBuy / directV2BatchSell
|
|
6
|
+
* - direct-router-v3.ts: V3 批量买卖 directV3BatchBuy / directV3BatchSell
|
|
7
|
+
* - router.ts: getRouterAddress 等 Router 地址/识别工具
|
|
8
|
+
*/
|
|
9
|
+
export * from './direct-router-v2.js';
|
|
10
|
+
export * from './direct-router-v3.js';
|
|
11
|
+
export { getRouterAddress } from './router.js';
|
|
12
|
+
export { DIRECT_ROUTERS } from './direct-router-helpers.js';
|