four-flap-meme-sdk 2.0.0 → 2.2.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/__tests__/subpath-exports.test.js +64 -0
- package/dist/chains/bsc/iro.d.ts +5 -0
- package/dist/chains/bsc/iro.js +4 -0
- package/dist/chains/eni/flat-aliases.d.ts +10 -0
- package/dist/chains/eni/flat-aliases.js +8 -0
- package/dist/chains/eni/index.d.ts +1 -0
- package/dist/chains/eni/index.js +1 -0
- package/dist/chains/index.d.ts +13 -0
- package/dist/chains/index.js +13 -0
- package/dist/chains/xlayer/eip7702/flat-aliases.d.ts +13 -0
- package/dist/chains/xlayer/eip7702/flat-aliases.js +10 -0
- package/dist/chains/xlayer/eip7702/index.d.ts +1 -0
- package/dist/chains/xlayer/eip7702/index.js +1 -0
- package/dist/chains/xlayer/index.d.ts +3 -2
- package/dist/chains/xlayer/index.js +4 -7
- package/dist/flap/index.d.ts +10 -0
- package/dist/flap/index.js +8 -0
- package/dist/merkle/index.d.ts +12 -0
- package/dist/merkle/index.js +11 -0
- package/dist/shared/constants/index.d.ts +2 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/vanity/index.d.ts +5 -0
- package/dist/vanity/index.js +5 -0
- package/package.json +93 -2
- package/dist/chains/bsc/four/disperse.d.ts +0 -12
- package/dist/chains/bsc/four/disperse.js +0 -470
- package/dist/chains/bsc/four/pairwise.d.ts +0 -7
- package/dist/chains/bsc/four/pairwise.js +0 -308
- package/dist/chains/bsc/four/submit/blockrazor.d.ts +0 -18
- package/dist/chains/bsc/four/submit/blockrazor.js +0 -86
- package/dist/chains/bsc/four/submit/direct.d.ts +0 -66
- package/dist/chains/bsc/four/submit/direct.js +0 -452
- package/dist/chains/bsc/four/submit/helpers.d.ts +0 -18
- package/dist/chains/bsc/four/submit/helpers.js +0 -57
- package/dist/chains/bsc/four/submit/index.d.ts +0 -12
- package/dist/chains/bsc/four/submit/index.js +0 -11
- package/dist/chains/bsc/four/submit/merkle.d.ts +0 -18
- package/dist/chains/bsc/four/submit/merkle.js +0 -74
- package/dist/chains/bsc/four/submit/types.d.ts +0 -143
- package/dist/chains/bsc/four/swap/index.d.ts +0 -32
- package/dist/chains/bsc/four/swap/index.js +0 -829
- package/dist/chains/bsc/four/swap/types.d.ts +0 -70
- package/dist/chains/bsc/four/swap/types.js +0 -1
- package/dist/chains/bsc/four/sweep.d.ts +0 -13
- package/dist/chains/bsc/four/sweep.js +0 -788
- package/dist/chains/bsc/four/utils/index.d.ts +0 -20
- package/dist/chains/bsc/four/utils/index.js +0 -1558
- package/dist/chains/bsc/four/utils/types.d.ts +0 -1
- package/dist/chains/bsc/four/utils/types.js +0 -1
- package/dist/chains/bsc/pancake/bundle-buy-first/index.d.ts +0 -8
- package/dist/chains/bsc/pancake/bundle-buy-first/index.js +0 -907
- package/dist/chains/bsc/pancake/bundle-buy-first/types.d.ts +0 -73
- package/dist/chains/bsc/pancake/bundle-buy-first/types.js +0 -1
- package/dist/chains/bsc/pancake/bundle-swap/helpers.d.ts +0 -102
- package/dist/chains/bsc/pancake/bundle-swap/helpers.js +0 -572
- package/dist/chains/bsc/pancake/bundle-swap/index.d.ts +0 -50
- package/dist/chains/bsc/pancake/bundle-swap/index.js +0 -1066
- package/dist/chains/bsc/pancake/bundle-swap/types.d.ts +0 -202
- package/dist/chains/bsc/pancake/bundle-swap/types.js +0 -3
- package/dist/chains/xlayer/eip7702/bundle-swap/index.d.ts +0 -72
- package/dist/chains/xlayer/eip7702/bundle-swap/index.js +0 -921
- package/dist/chains/xlayer/eip7702/bundle-swap/types.d.ts +0 -65
- package/dist/chains/xlayer/eip7702/bundle-swap/types.js +0 -1
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.d.ts +0 -128
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/index.js +0 -857
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.d.ts +0 -85
- package/dist/chains/xlayer/eip7702/multi-hop-transfer/types.js +0 -1
- package/dist/chains/xlayer/eip7702/volume/index.d.ts +0 -96
- package/dist/chains/xlayer/eip7702/volume/index.js +0 -793
- package/dist/chains/xlayer/eip7702/volume/types.d.ts +0 -124
- package/dist/chains/xlayer/eip7702/volume/types.js +0 -1
- package/dist/chains/xlayer/eoa/types-core.d.ts +0 -363
- package/dist/chains/xlayer/eoa/types-core.js +0 -53
- package/dist/chains/xlayer/eoa/types-create.d.ts +0 -413
- package/dist/chains/xlayer/eoa/types-create.js +0 -9
- package/dist/chains/xlayer/eoa/types-volume.d.ts +0 -209
- package/dist/chains/xlayer/eoa/types-volume.js +0 -13
- package/dist/dex/direct-router/index.d.ts +0 -70
- package/dist/dex/direct-router/index.js +0 -1410
- package/dist/dex/direct-router/types.d.ts +0 -81
- package/dist/dex/direct-router/types.js +0 -1
- package/dist/shared/abis/TaxToken.json +0 -969
- package/dist/shared/abis/TokenManager.json +0 -836
- package/dist/shared/abis/TokenManager2.json +0 -136
- package/dist/shared/abis/TokenManagerHelper3.json +0 -993
- package/dist/shared/abis 2/TaxToken.json +0 -105
- package/dist/shared/abis 2/TokenManager.json +0 -836
- package/dist/shared/abis 2/TokenManager2.json +0 -60
- package/dist/shared/abis 2/TokenManagerHelper3.json +0 -993
- package/dist/shared/abis 2/common.d.ts +0 -85
- package/dist/shared/abis 2/common.js +0 -254
- package/dist/shared/abis 2/index.d.ts +0 -8
- package/dist/shared/abis 2/index.js +0 -8
- package/dist/shared/clients 2/blockrazor.d.ts +0 -314
- package/dist/shared/clients 2/blockrazor.js +0 -596
- package/dist/shared/clients 2/club48.d.ts +0 -154
- package/dist/shared/clients 2/club48.js +0 -331
- package/dist/shared/clients 2/emitservice.d.ts +0 -47
- package/dist/shared/clients 2/emitservice.js +0 -44
- package/dist/shared/clients 2/four.d.ts +0 -132
- package/dist/shared/clients 2/four.js +0 -281
- package/dist/shared/clients 2/merkle.d.ts +0 -210
- package/dist/shared/clients 2/merkle.js +0 -400
- package/dist/shared/flap/__tests__/curve.test.d.ts +0 -1
- package/dist/shared/flap/__tests__/curve.test.js +0 -85
- package/dist/shared/flap/portal/index.d.ts +0 -12
- package/dist/shared/flap/portal/index.js +0 -11
- package/dist/shared/flap/portal/portal.d.ts +0 -47
- package/dist/shared/flap/portal/portal.js +0 -218
- package/dist/shared/flap/portal/types.d.ts +0 -227
- package/dist/shared/flap/portal/types.js +0 -80
- package/dist/shared/flap/portal/writer.d.ts +0 -121
- package/dist/shared/flap/portal/writer.js +0 -265
- package/dist/shared/flap/portal-bundle-merkle/core/index.d.ts +0 -18
- package/dist/shared/flap/portal-bundle-merkle/core/index.js +0 -938
- package/dist/shared/flap/portal-bundle-merkle/core/types.d.ts +0 -1
- package/dist/shared/flap/portal-bundle-merkle/core/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/swap/index.d.ts +0 -42
- package/dist/shared/flap/portal-bundle-merkle/swap/index.js +0 -1448
- package/dist/shared/flap/portal-bundle-merkle/swap/types.d.ts +0 -84
- package/dist/shared/flap/portal-bundle-merkle/swap/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/utils/index.d.ts +0 -17
- package/dist/shared/flap/portal-bundle-merkle/utils/index.js +0 -1024
- package/dist/shared/flap/portal-bundle-merkle/utils/types.d.ts +0 -16
- package/dist/shared/flap/portal-bundle-merkle/utils/types.js +0 -1
- package/dist/shared/flap/portal-bundle-merkle/utils-helpers.d.ts +0 -100
- package/dist/shared/flap/portal-bundle-merkle/utils-helpers.js +0 -133
- package/dist/shared/flap 2/__tests__/curve.test.d.ts +0 -1
- package/dist/shared/flap 2/__tests__/curve.test.js +0 -85
- package/dist/shared/flap 2/abi.d.ts +0 -4
- package/dist/shared/flap 2/abi.js +0 -4
- package/dist/shared/flap 2/constants.d.ts +0 -128
- package/dist/shared/flap 2/constants.js +0 -143
- package/dist/shared/flap 2/curve.d.ts +0 -33
- package/dist/shared/flap 2/curve.js +0 -84
- package/dist/shared/flap 2/errors.d.ts +0 -37
- package/dist/shared/flap 2/errors.js +0 -114
- package/dist/shared/flap 2/index.d.ts +0 -22
- package/dist/shared/flap 2/index.js +0 -33
- package/dist/shared/flap 2/ipfs.d.ts +0 -21
- package/dist/shared/flap 2/ipfs.js +0 -38
- package/dist/shared/flap 2/meta.d.ts +0 -30
- package/dist/shared/flap 2/meta.js +0 -195
- package/dist/shared/flap 2/permit.d.ts +0 -16
- package/dist/shared/flap 2/permit.js +0 -67
- package/dist/shared/flap 2/pinata.d.ts +0 -40
- package/dist/shared/flap 2/pinata.js +0 -106
- package/dist/shared/flap 2/portal-bundle-merkle/config.d.ts +0 -79
- package/dist/shared/flap 2/portal-bundle-merkle/config.js +0 -133
- package/dist/shared/flap 2/portal-bundle-merkle/core.d.ts +0 -18
- package/dist/shared/flap 2/portal-bundle-merkle/core.js +0 -938
- package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.d.ts +0 -125
- package/dist/shared/flap 2/portal-bundle-merkle/create-to-dex.js +0 -665
- package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.d.ts +0 -88
- package/dist/shared/flap 2/portal-bundle-merkle/curve-to-dex.js +0 -446
- package/dist/shared/flap 2/portal-bundle-merkle/index.d.ts +0 -14
- package/dist/shared/flap 2/portal-bundle-merkle/index.js +0 -26
- package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.d.ts +0 -28
- package/dist/shared/flap 2/portal-bundle-merkle/pancake-proxy.js +0 -701
- package/dist/shared/flap 2/portal-bundle-merkle/private.d.ts +0 -17
- package/dist/shared/flap 2/portal-bundle-merkle/private.js +0 -549
- package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.d.ts +0 -65
- package/dist/shared/flap 2/portal-bundle-merkle/swap-buy-first.js +0 -831
- package/dist/shared/flap 2/portal-bundle-merkle/swap.d.ts +0 -201
- package/dist/shared/flap 2/portal-bundle-merkle/swap.js +0 -1359
- package/dist/shared/flap 2/portal-bundle-merkle/types.d.ts +0 -358
- package/dist/shared/flap 2/portal-bundle-merkle/types.js +0 -1
- package/dist/shared/flap 2/portal-bundle-merkle/utils.d.ts +0 -89
- package/dist/shared/flap 2/portal-bundle-merkle/utils.js +0 -963
- package/dist/shared/flap 2/portal-bundle.d.ts +0 -119
- package/dist/shared/flap 2/portal-bundle.js +0 -584
- package/dist/shared/flap 2/portal.d.ts +0 -392
- package/dist/shared/flap 2/portal.js +0 -559
- package/dist/shared/flap 2/vanity.d.ts +0 -48
- package/dist/shared/flap 2/vanity.js +0 -110
- package/dist/shared/flap 2/vault.d.ts +0 -240
- package/dist/shared/flap 2/vault.js +0 -366
- package/dist/shared/four 2/index.d.ts +0 -7
- package/dist/shared/four 2/index.js +0 -22
- package/dist/shared/four 2/tax-token.d.ts +0 -176
- package/dist/shared/four 2/tax-token.js +0 -302
- package/dist/shared/index 2.js +0 -10
- package/dist/shared/index.d 2.ts +0 -10
- package/dist/types/distribute.d.ts +0 -72
- package/dist/types/distribute.js +0 -1
- package/dist/types 2/errors.d.ts +0 -27
- package/dist/types 2/errors.js +0 -34
- package/dist/utils/__tests__/errors.test.d.ts +0 -1
- package/dist/utils/__tests__/errors.test.js +0 -76
- package/dist/utils/airdrop-sweep-types.d.ts +0 -1
- package/dist/utils/airdrop-sweep-types.js +0 -1
- package/dist/utils/erc20/index.d.ts +0 -242
- package/dist/utils/erc20/index.js +0 -645
- package/dist/utils/erc20/types.d.ts +0 -77
- package/dist/utils/erc20/types.js +0 -1
- package/dist/utils/erc20-types.d.ts +0 -1
- package/dist/utils/erc20-types.js +0 -1
- package/dist/utils/holders-maker/helpers.d.ts +0 -43
- package/dist/utils/holders-maker/helpers.js +0 -371
- package/dist/utils/holders-maker/index.d.ts +0 -26
- package/dist/utils/holders-maker/index.js +0 -218
- package/dist/utils/holders-maker/types.d.ts +0 -72
- package/dist/utils/holders-maker/types.js +0 -4
- package/dist/utils/holders-maker-types.d.ts +0 -1
- package/dist/utils/holders-maker-types.js +0 -1
- package/dist/utils/lp-inspect/index.d.ts +0 -44
- package/dist/utils/lp-inspect/index.js +0 -937
- package/dist/utils/lp-inspect/types.d.ts +0 -100
- package/dist/utils/lp-inspect/types.js +0 -1
- package/dist/utils/lp-inspect-types.d.ts +0 -1
- package/dist/utils/lp-inspect-types.js +0 -1
- package/dist/utils/private-sale-types.d.ts +0 -1
- package/dist/utils/private-sale-types.js +0 -1
- package/dist/utils/quote-helpers/index.d.ts +0 -107
- package/dist/utils/quote-helpers/index.js +0 -346
- package/dist/utils/quote-helpers/types.d.ts +0 -16
- package/dist/utils/quote-helpers/types.js +0 -1
- package/dist/utils/quote-helpers-types.d.ts +0 -1
- package/dist/utils/quote-helpers-types.js +0 -1
- /package/dist/{chains/bsc/four/submit/types.js → __tests__/subpath-exports.test.d.ts} +0 -0
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import { ethers, Wallet } from 'ethers';
|
|
2
|
-
import { getOptimizedGasPrice, NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, buildGasFields } from '../../../utils/bundle-helpers.js';
|
|
3
|
-
import { BLOCKRAZOR_BUILDER_EOA, calculateTransferFee } from '../../../utils/constants.js';
|
|
4
|
-
import { GAS_LIMITS, CHAINS } from '../../../shared/constants/index.js';
|
|
5
|
-
import { getTxType, getGasPriceConfig, shouldExtractProfit, getProfitRecipient, getBribeAmount } from './config.js';
|
|
6
|
-
// ==================== Gas 常量(使用统一常量) ====================
|
|
7
|
-
const NATIVE_TRANSFER_GAS_LIMIT = GAS_LIMITS.NATIVE_TRANSFER;
|
|
8
|
-
const BRIBE_GAS_LIMIT = GAS_LIMITS.BRIBE;
|
|
9
|
-
import { getErc20DecimalsMerkle as _getErc20DecimalsMerkle, generateHopWallets as _generateHopWallets, calculateGasLimit as _calculateGasLimit, isNativeTokenAddress as _isNativeTokenAddress } from './internal.js';
|
|
10
|
-
// ==================== 钱包转账按地址收费 ====================
|
|
11
|
-
/**
|
|
12
|
-
* 分发(仅签名版本 - 不依赖 Merkle)
|
|
13
|
-
* ✅ 精简版:只负责签名交易,不提交到 Merkle
|
|
14
|
-
* ✅ 优化版:支持 startNonce 参数避免并行调用时的 nonce 冲突
|
|
15
|
-
*/
|
|
16
|
-
export async function pairwiseTransferWithBundleMerkle(params) {
|
|
17
|
-
const { senderPrivateKeys, receiverAddresses, amount, amounts, tokenAddress, tokenDecimals, hopCount = 0, hopPrivateKeys, config, startNonce, } = params;
|
|
18
|
-
if (!senderPrivateKeys || senderPrivateKeys.length === 0) {
|
|
19
|
-
return { signedTransactions: [], hopWallets: undefined };
|
|
20
|
-
}
|
|
21
|
-
if (!receiverAddresses || receiverAddresses.length === 0) {
|
|
22
|
-
return { signedTransactions: [], hopWallets: undefined };
|
|
23
|
-
}
|
|
24
|
-
if (senderPrivateKeys.length !== receiverAddresses.length) {
|
|
25
|
-
throw new Error(`senderPrivateKeys length (${senderPrivateKeys.length}) must match receiverAddresses length (${receiverAddresses.length})`);
|
|
26
|
-
}
|
|
27
|
-
const pairCount = senderPrivateKeys.length;
|
|
28
|
-
const normalizedAmounts = (() => {
|
|
29
|
-
if (amounts && amounts.length > 0) {
|
|
30
|
-
if (amounts.length !== pairCount) {
|
|
31
|
-
throw new Error(`amounts length (${amounts.length}) must match pair count (${pairCount})`);
|
|
32
|
-
}
|
|
33
|
-
return amounts.map(a => (typeof a === 'bigint' ? a.toString() : String(a)));
|
|
34
|
-
}
|
|
35
|
-
if (amount !== undefined && String(amount).trim().length > 0) {
|
|
36
|
-
const v = typeof amount === 'bigint' ? amount.toString() : String(amount);
|
|
37
|
-
return new Array(pairCount).fill(v);
|
|
38
|
-
}
|
|
39
|
-
throw new Error('Either amount or amounts must be provided');
|
|
40
|
-
})();
|
|
41
|
-
const chainIdNum = config.chainId ?? CHAINS.BSC.chainId;
|
|
42
|
-
const chainName = chainIdNum === CHAINS.MONAD.chainId ? 'Monad' : chainIdNum === CHAINS.BSC.chainId ? 'BSC' : `Chain-${chainIdNum}`;
|
|
43
|
-
const provider = new ethers.JsonRpcProvider(config.rpcUrl, { chainId: chainIdNum, name: chainName });
|
|
44
|
-
const txType = getTxType(config);
|
|
45
|
-
const isNative = _isNativeTokenAddress(tokenAddress);
|
|
46
|
-
const nonceManager = new NonceManager(provider);
|
|
47
|
-
// hop 私钥链优先使用传入
|
|
48
|
-
const providedHops = (() => {
|
|
49
|
-
if (hopPrivateKeys && hopPrivateKeys.length > 0) {
|
|
50
|
-
if (hopPrivateKeys.length !== pairCount) {
|
|
51
|
-
throw new Error(`hopPrivateKeys length (${hopPrivateKeys.length}) must match pair count (${pairCount})`);
|
|
52
|
-
}
|
|
53
|
-
return hopPrivateKeys.every(h => h.length === 0) ? null : hopPrivateKeys;
|
|
54
|
-
}
|
|
55
|
-
return null;
|
|
56
|
-
})();
|
|
57
|
-
const preparedHops = providedHops ?? _generateHopWallets(pairCount, hopCount);
|
|
58
|
-
const hasHops = preparedHops !== null;
|
|
59
|
-
const maxHopCount = hasHops ? Math.max(...preparedHops.map(h => h.length)) : 0;
|
|
60
|
-
const finalGasLimit = _calculateGasLimit(config, isNative, hasHops, maxHopCount);
|
|
61
|
-
const nativeGasLimit = (config.prefer21000ForNative ?? false) ? BRIBE_GAS_LIMIT : finalGasLimit;
|
|
62
|
-
// 与 disperse/swap.ts 保持一致:多跳场景固定 gas limit
|
|
63
|
-
const nativeTransferGasLimit = NATIVE_TRANSFER_GAS_LIMIT;
|
|
64
|
-
const erc20TransferGasLimit = GAS_LIMITS.ERC20_TRANSFER;
|
|
65
|
-
const [gasPrice, decimals] = await Promise.all([
|
|
66
|
-
getOptimizedGasPrice(provider, getGasPriceConfig(config)),
|
|
67
|
-
isNative ? Promise.resolve(18) : Promise.resolve(tokenDecimals ?? await _getErc20DecimalsMerkle(provider, tokenAddress, chainIdNum))
|
|
68
|
-
]);
|
|
69
|
-
const gasFields = buildGasFields(txType, gasPrice);
|
|
70
|
-
const iface = isNative ? null : new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
|
|
71
|
-
// ✅ 费用:按地址数量收取固定费用(原生代币),由第一个 sender 支付
|
|
72
|
-
const extractProfit = shouldExtractProfit(config);
|
|
73
|
-
const profitAddr = getProfitRecipient();
|
|
74
|
-
let totalAmountBeforeProfit = 0n;
|
|
75
|
-
let totalProfitNative = 0n;
|
|
76
|
-
const parsedAmountsWei = normalizedAmounts.map(v => {
|
|
77
|
-
const amt = isNative ? ethers.parseEther(v) : ethers.parseUnits(v, decimals);
|
|
78
|
-
totalAmountBeforeProfit += amt;
|
|
79
|
-
return amt;
|
|
80
|
-
});
|
|
81
|
-
// ✅ 按地址数量收取固定费用
|
|
82
|
-
if (extractProfit && pairCount > 0) {
|
|
83
|
-
totalProfitNative = calculateTransferFee(chainIdNum, pairCount);
|
|
84
|
-
}
|
|
85
|
-
// ✅ BSC 链贿赂支持(由第一个 sender 支付)
|
|
86
|
-
const bribeAmount = chainIdNum === CHAINS.BSC.chainId ? getBribeAmount(config) : 0n;
|
|
87
|
-
const needBribeTx = bribeAmount > 0n;
|
|
88
|
-
const bribeSignedTx = [];
|
|
89
|
-
// 计算每个 sender 需要的 nonce 数量(聚合到地址)
|
|
90
|
-
const senderWallets = senderPrivateKeys.map(pk => new Wallet(pk, provider));
|
|
91
|
-
const senderAddrLowerList = senderWallets.map(w => w.address.toLowerCase());
|
|
92
|
-
const firstSenderAddrLower = senderAddrLowerList[0];
|
|
93
|
-
const nonceNeedBySender = new Map();
|
|
94
|
-
for (let i = 0; i < pairCount; i++) {
|
|
95
|
-
const addrLower = senderAddrLowerList[i];
|
|
96
|
-
const hopLen = preparedHops ? preparedHops[i].length : 0;
|
|
97
|
-
const perPairTxCount = (() => {
|
|
98
|
-
if (isNative)
|
|
99
|
-
return 1;
|
|
100
|
-
return hopLen > 0 ? 2 : 1;
|
|
101
|
-
})();
|
|
102
|
-
const cur = nonceNeedBySender.get(addrLower);
|
|
103
|
-
if (cur)
|
|
104
|
-
cur.count += perPairTxCount;
|
|
105
|
-
else
|
|
106
|
-
nonceNeedBySender.set(addrLower, { wallet: senderWallets[i], count: perPairTxCount });
|
|
107
|
-
}
|
|
108
|
-
// ✅ 贿赂交易需要 1 个额外的 nonce
|
|
109
|
-
if (needBribeTx) {
|
|
110
|
-
const cur = nonceNeedBySender.get(firstSenderAddrLower);
|
|
111
|
-
if (cur)
|
|
112
|
-
cur.count += 1;
|
|
113
|
-
}
|
|
114
|
-
if (extractProfit && totalProfitNative > 0n) {
|
|
115
|
-
const cur = nonceNeedBySender.get(firstSenderAddrLower);
|
|
116
|
-
if (cur)
|
|
117
|
-
cur.count += 1;
|
|
118
|
-
}
|
|
119
|
-
const nonceQueueBySender = new Map();
|
|
120
|
-
for (const [addrLower, entry] of nonceNeedBySender.entries()) {
|
|
121
|
-
const count = entry.count;
|
|
122
|
-
const nonces = (addrLower === firstSenderAddrLower && startNonce !== undefined)
|
|
123
|
-
? Array.from({ length: count }, (_, i) => startNonce + i)
|
|
124
|
-
: await nonceManager.getNextNonceBatch(entry.wallet, count);
|
|
125
|
-
nonceQueueBySender.set(addrLower, nonces);
|
|
126
|
-
}
|
|
127
|
-
const popNonce = (addrLower) => {
|
|
128
|
-
const q = nonceQueueBySender.get(addrLower);
|
|
129
|
-
if (!q || q.length === 0)
|
|
130
|
-
throw new Error(`nonce queue empty for sender ${addrLower}`);
|
|
131
|
-
return q.shift();
|
|
132
|
-
};
|
|
133
|
-
const txsToSign = [];
|
|
134
|
-
const nativeHopGasFee = nativeTransferGasLimit * gasPrice;
|
|
135
|
-
const erc20HopGasFee = erc20TransferGasLimit * gasPrice;
|
|
136
|
-
const nativeHopGasFeeForErc20 = nativeTransferGasLimit * gasPrice;
|
|
137
|
-
for (let i = 0; i < pairCount; i++) {
|
|
138
|
-
const senderWallet = senderWallets[i];
|
|
139
|
-
const senderLower = senderAddrLowerList[i];
|
|
140
|
-
const to = receiverAddresses[i];
|
|
141
|
-
const amtWei = parsedAmountsWei[i];
|
|
142
|
-
const hopChain = preparedHops ? preparedHops[i] : [];
|
|
143
|
-
if (!hopChain || hopChain.length === 0) {
|
|
144
|
-
const nonce = popNonce(senderLower);
|
|
145
|
-
if (isNative) {
|
|
146
|
-
txsToSign.push({
|
|
147
|
-
wallet: senderWallet,
|
|
148
|
-
tx: { to, value: amtWei, nonce, gasLimit: nativeGasLimit, chainId: chainIdNum, ...gasFields }
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
const data = iface.encodeFunctionData('transfer', [to, amtWei]);
|
|
153
|
-
txsToSign.push({
|
|
154
|
-
wallet: senderWallet,
|
|
155
|
-
tx: { to: tokenAddress, data, value: 0n, nonce, gasLimit: finalGasLimit, chainId: chainIdNum, ...gasFields }
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
const fullChain = [senderWallet, ...hopChain.map(w => new Wallet(typeof w === 'string' ? w : w.privateKey, provider))];
|
|
161
|
-
const addresses = [...fullChain.map(w => w.address), to];
|
|
162
|
-
if (isNative) {
|
|
163
|
-
for (let j = 0; j < addresses.length - 1; j++) {
|
|
164
|
-
const fromWallet = fullChain[j];
|
|
165
|
-
const toAddress = addresses[j + 1];
|
|
166
|
-
const nonce = j === 0 ? popNonce(senderLower) : 0;
|
|
167
|
-
const remainingHops = addresses.length - 2 - j;
|
|
168
|
-
const additionalGas = nativeHopGasFee * BigInt(remainingHops);
|
|
169
|
-
const transferValue = amtWei + additionalGas;
|
|
170
|
-
txsToSign.push({
|
|
171
|
-
wallet: fromWallet,
|
|
172
|
-
tx: { to: toAddress, value: transferValue, nonce, gasLimit: nativeTransferGasLimit, chainId: chainIdNum, ...gasFields }
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
const hopGasNeeds = [];
|
|
178
|
-
for (let j = hopChain.length - 1; j >= 0; j--) {
|
|
179
|
-
if (j === hopChain.length - 1)
|
|
180
|
-
hopGasNeeds.unshift(erc20HopGasFee);
|
|
181
|
-
else {
|
|
182
|
-
const nextHopGas = hopGasNeeds[0];
|
|
183
|
-
hopGasNeeds.unshift(nativeHopGasFeeForErc20 + erc20HopGasFee + nextHopGas);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
txsToSign.push({
|
|
187
|
-
wallet: senderWallet,
|
|
188
|
-
tx: {
|
|
189
|
-
to: fullChain[1].address,
|
|
190
|
-
value: hopGasNeeds[0],
|
|
191
|
-
nonce: popNonce(senderLower),
|
|
192
|
-
gasLimit: nativeTransferGasLimit,
|
|
193
|
-
chainId: chainIdNum,
|
|
194
|
-
...gasFields
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
const mainToFirstHopData = iface.encodeFunctionData('transfer', [fullChain[1].address, amtWei]);
|
|
198
|
-
txsToSign.push({
|
|
199
|
-
wallet: senderWallet,
|
|
200
|
-
tx: {
|
|
201
|
-
to: tokenAddress,
|
|
202
|
-
data: mainToFirstHopData,
|
|
203
|
-
value: 0n,
|
|
204
|
-
nonce: popNonce(senderLower),
|
|
205
|
-
gasLimit: erc20TransferGasLimit,
|
|
206
|
-
chainId: chainIdNum,
|
|
207
|
-
...gasFields
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
// hop wallets:逐层传递
|
|
211
|
-
for (let j = 1; j < fullChain.length; j++) {
|
|
212
|
-
const fromWallet = fullChain[j];
|
|
213
|
-
const toAddress = addresses[j + 1];
|
|
214
|
-
const isLastHop = j === fullChain.length - 1;
|
|
215
|
-
if (!isLastHop) {
|
|
216
|
-
const gasToTransfer = hopGasNeeds[j];
|
|
217
|
-
txsToSign.push({
|
|
218
|
-
wallet: fromWallet,
|
|
219
|
-
tx: {
|
|
220
|
-
to: toAddress,
|
|
221
|
-
value: gasToTransfer,
|
|
222
|
-
nonce: 0,
|
|
223
|
-
gasLimit: nativeTransferGasLimit,
|
|
224
|
-
chainId: chainIdNum,
|
|
225
|
-
...gasFields
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
const erc20Data = iface.encodeFunctionData('transfer', [toAddress, amtWei]);
|
|
229
|
-
txsToSign.push({
|
|
230
|
-
wallet: fromWallet,
|
|
231
|
-
tx: {
|
|
232
|
-
to: tokenAddress,
|
|
233
|
-
data: erc20Data,
|
|
234
|
-
value: 0n,
|
|
235
|
-
nonce: 1,
|
|
236
|
-
gasLimit: erc20TransferGasLimit,
|
|
237
|
-
chainId: chainIdNum,
|
|
238
|
-
...gasFields
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
const erc20Data = iface.encodeFunctionData('transfer', [toAddress, amtWei]);
|
|
244
|
-
txsToSign.push({
|
|
245
|
-
wallet: fromWallet,
|
|
246
|
-
tx: {
|
|
247
|
-
to: tokenAddress,
|
|
248
|
-
data: erc20Data,
|
|
249
|
-
value: 0n,
|
|
250
|
-
nonce: 0,
|
|
251
|
-
gasLimit: erc20TransferGasLimit,
|
|
252
|
-
chainId: chainIdNum,
|
|
253
|
-
...gasFields
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
if (needBribeTx) {
|
|
261
|
-
const firstSenderWallet = senderWallets[0];
|
|
262
|
-
const bribeNonce = popNonce(firstSenderAddrLower);
|
|
263
|
-
const bribeTx = await firstSenderWallet.signTransaction({
|
|
264
|
-
to: BLOCKRAZOR_BUILDER_EOA,
|
|
265
|
-
value: bribeAmount,
|
|
266
|
-
nonce: bribeNonce,
|
|
267
|
-
gasLimit: BRIBE_GAS_LIMIT,
|
|
268
|
-
chainId: chainIdNum,
|
|
269
|
-
...gasFields
|
|
270
|
-
});
|
|
271
|
-
bribeSignedTx.push(bribeTx);
|
|
272
|
-
}
|
|
273
|
-
const signedTxs = await Promise.all(txsToSign.map(({ wallet, tx }) => wallet.signTransaction(tx)));
|
|
274
|
-
// 利润多跳(固定 2 hop)
|
|
275
|
-
let profitHopWallets;
|
|
276
|
-
if (extractProfit && totalProfitNative > 0n) {
|
|
277
|
-
const firstSenderWallet = senderWallets[0];
|
|
278
|
-
const profitNonce = popNonce(firstSenderAddrLower);
|
|
279
|
-
const profitHopResult = await buildProfitHopTransactions({
|
|
280
|
-
provider,
|
|
281
|
-
payerWallet: firstSenderWallet,
|
|
282
|
-
profitAmount: totalProfitNative,
|
|
283
|
-
profitRecipient: profitAddr,
|
|
284
|
-
hopCount: PROFIT_HOP_COUNT,
|
|
285
|
-
gasPrice,
|
|
286
|
-
chainId: chainIdNum,
|
|
287
|
-
txType,
|
|
288
|
-
startNonce: profitNonce
|
|
289
|
-
});
|
|
290
|
-
signedTxs.push(...profitHopResult.signedTransactions);
|
|
291
|
-
profitHopWallets = profitHopResult.hopWallets;
|
|
292
|
-
}
|
|
293
|
-
return {
|
|
294
|
-
signedTransactions: [...bribeSignedTx, ...signedTxs], // ✅ 贿赂交易放在最前面
|
|
295
|
-
hopWallets: preparedHops || undefined,
|
|
296
|
-
profitHopWallets,
|
|
297
|
-
metadata: extractProfit ? {
|
|
298
|
-
pairCount,
|
|
299
|
-
isNative,
|
|
300
|
-
tokenAddress: isNative ? undefined : tokenAddress,
|
|
301
|
-
totalAmount: isNative ? ethers.formatEther(totalAmountBeforeProfit) : ethers.formatUnits(totalAmountBeforeProfit, decimals),
|
|
302
|
-
profitAmount: ethers.formatEther(totalProfitNative),
|
|
303
|
-
profitRecipient: profitAddr,
|
|
304
|
-
hasBribeTx: bribeSignedTx.length > 0, // ✅ 标记是否有贿赂交易
|
|
305
|
-
bribeAmount: bribeSignedTx.length > 0 ? ethers.formatEther(bribeAmount) : undefined
|
|
306
|
-
} : undefined
|
|
307
|
-
};
|
|
308
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { BlockRazorSubmitConfig, BlockRazorSubmitResult } from './types.js';
|
|
2
|
-
export declare function submitBundleToBlockRazor(signedTransactions: string[], config: BlockRazorSubmitConfig): Promise<BlockRazorSubmitResult>;
|
|
3
|
-
/**
|
|
4
|
-
* 批量提交多个 Bundle 到 BlockRazor(顺序执行)
|
|
5
|
-
*
|
|
6
|
-
* @param bundles 多个 Bundle 的签名交易数组
|
|
7
|
-
* @param config BlockRazor 提交配置
|
|
8
|
-
* @returns Bundle 提交结果数组
|
|
9
|
-
*/
|
|
10
|
-
export declare function submitMultipleBundlesToBlockRazor(bundles: string[][], config: BlockRazorSubmitConfig): Promise<BlockRazorSubmitResult[]>;
|
|
11
|
-
/**
|
|
12
|
-
* 并行提交多个 Bundle 到 BlockRazor(适用于独立的 Bundle)
|
|
13
|
-
*
|
|
14
|
-
* @param bundles 多个 Bundle 的签名交易数组
|
|
15
|
-
* @param config BlockRazor 提交配置
|
|
16
|
-
* @returns Bundle 提交结果数组
|
|
17
|
-
*/
|
|
18
|
-
export declare function submitMultipleBundlesToBlockRazorParallel(bundles: string[][], config: BlockRazorSubmitConfig): Promise<BlockRazorSubmitResult[]>;
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { BlockRazorClient } from '../../../../shared/clients/blockrazor.js';
|
|
2
|
-
const blockRazorClientCache = new Map();
|
|
3
|
-
const CLIENT_CACHE_TTL_MS = 60 * 1000;
|
|
4
|
-
function getBlockRazorClient(config) {
|
|
5
|
-
const cacheKey = `${config.apiKey || ''}-${config.builderRpcUrl || ''}`;
|
|
6
|
-
const now = Date.now();
|
|
7
|
-
const cached = blockRazorClientCache.get(cacheKey);
|
|
8
|
-
if (cached && cached.expireAt > now)
|
|
9
|
-
return cached.client;
|
|
10
|
-
const client = new BlockRazorClient({
|
|
11
|
-
apiKey: config.apiKey,
|
|
12
|
-
customRpcUrl: config.customRpcUrl,
|
|
13
|
-
builderRpcUrl: config.builderRpcUrl,
|
|
14
|
-
chainId: 56,
|
|
15
|
-
});
|
|
16
|
-
blockRazorClientCache.set(cacheKey, { client, expireAt: now + CLIENT_CACHE_TTL_MS });
|
|
17
|
-
return client;
|
|
18
|
-
}
|
|
19
|
-
export async function submitBundleToBlockRazor(signedTransactions, config) {
|
|
20
|
-
try {
|
|
21
|
-
const totalTransactions = signedTransactions?.length ?? 0;
|
|
22
|
-
// 验证输入
|
|
23
|
-
if (!signedTransactions || signedTransactions.length === 0) {
|
|
24
|
-
return {
|
|
25
|
-
code: false,
|
|
26
|
-
totalTransactions,
|
|
27
|
-
error: 'signedTransactions cannot be empty'
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
// ✅ 使用缓存的 BlockRazorClient
|
|
31
|
-
const client = getBlockRazorClient(config);
|
|
32
|
-
// 提交 Bundle
|
|
33
|
-
const bundleResult = await client.sendBundle({
|
|
34
|
-
transactions: signedTransactions,
|
|
35
|
-
blockOffset: config.blockOffset ?? 100,
|
|
36
|
-
maxBlockOffset: config.maxBlockOffset ?? 100,
|
|
37
|
-
noMerge: config.noMerge ?? false,
|
|
38
|
-
revertingTxHashes: config.revertingTxHashes,
|
|
39
|
-
autoRetry: config.autoRetry ?? false,
|
|
40
|
-
maxRetries: config.maxRetries ?? 3
|
|
41
|
-
});
|
|
42
|
-
// ✅ 提交成功
|
|
43
|
-
return {
|
|
44
|
-
code: true,
|
|
45
|
-
totalTransactions,
|
|
46
|
-
bundleHash: bundleResult.bundleHash,
|
|
47
|
-
txHashes: bundleResult.txHashes,
|
|
48
|
-
maxBlockNumber: bundleResult.maxBlockNumber,
|
|
49
|
-
txCount: bundleResult.txCount
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
// ❌ 提交失败
|
|
54
|
-
return {
|
|
55
|
-
code: false,
|
|
56
|
-
totalTransactions: signedTransactions?.length ?? 0,
|
|
57
|
-
error: error?.message || String(error)
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* 批量提交多个 Bundle 到 BlockRazor(顺序执行)
|
|
63
|
-
*
|
|
64
|
-
* @param bundles 多个 Bundle 的签名交易数组
|
|
65
|
-
* @param config BlockRazor 提交配置
|
|
66
|
-
* @returns Bundle 提交结果数组
|
|
67
|
-
*/
|
|
68
|
-
export async function submitMultipleBundlesToBlockRazor(bundles, config) {
|
|
69
|
-
const results = [];
|
|
70
|
-
for (const signedTransactions of bundles) {
|
|
71
|
-
const result = await submitBundleToBlockRazor(signedTransactions, config);
|
|
72
|
-
results.push(result);
|
|
73
|
-
}
|
|
74
|
-
return results;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* 并行提交多个 Bundle 到 BlockRazor(适用于独立的 Bundle)
|
|
78
|
-
*
|
|
79
|
-
* @param bundles 多个 Bundle 的签名交易数组
|
|
80
|
-
* @param config BlockRazor 提交配置
|
|
81
|
-
* @returns Bundle 提交结果数组
|
|
82
|
-
*/
|
|
83
|
-
export async function submitMultipleBundlesToBlockRazorParallel(bundles, config) {
|
|
84
|
-
const promises = bundles.map(signedTransactions => submitBundleToBlockRazor(signedTransactions, config));
|
|
85
|
-
return await Promise.all(promises);
|
|
86
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { DirectSubmitConfig, DirectSubmitResult } from './types.js';
|
|
2
|
-
export declare function submitDirectToRpc(signedTransactions: string[], config: DirectSubmitConfig): Promise<DirectSubmitResult>;
|
|
3
|
-
/**
|
|
4
|
-
* ✅ 顺序广播并等待确认(用于多跳交易等需要顺序执行的场景)
|
|
5
|
-
*
|
|
6
|
-
* 每笔交易广播后会等待上链确认,确保后续交易能正确执行
|
|
7
|
-
*
|
|
8
|
-
* ⚠️ 多跳场景:如果某笔交易失败,会立即停止(因为后续交易肯定也会失败)
|
|
9
|
-
*
|
|
10
|
-
* @param signedTransactions 签名后的交易数组
|
|
11
|
-
* @param config 直接广播配置
|
|
12
|
-
* @returns 广播结果
|
|
13
|
-
*/
|
|
14
|
-
export declare function submitDirectToRpcSequential(signedTransactions: string[], config: DirectSubmitConfig): Promise<DirectSubmitResult>;
|
|
15
|
-
/**
|
|
16
|
-
* ✅ 顺序广播但不等待确认(用于 AA handleOps + tail 等 nonce 连续的场景)
|
|
17
|
-
*
|
|
18
|
-
* 按顺序逐笔发送交易,每笔只等待广播成功(RPC 返回 txHash),不等待链上确认。
|
|
19
|
-
* 这样可以保证交易按顺序进入 mempool,同时避免等待确认超时。
|
|
20
|
-
*
|
|
21
|
-
* @param signedTransactions 签名后的交易数组
|
|
22
|
-
* @param config 直接广播配置
|
|
23
|
-
* @returns 广播结果
|
|
24
|
-
*/
|
|
25
|
-
export declare function submitDirectToRpcSequentialNoWait(signedTransactions: string[], config: DirectSubmitConfig): Promise<DirectSubmitResult>;
|
|
26
|
-
/**
|
|
27
|
-
* 并行逐笔广播到 RPC(速度更快,但可能有 nonce 冲突)
|
|
28
|
-
*
|
|
29
|
-
* ⚠️ 注意:仅适用于不同钱包的交易,同一钱包的多笔交易应使用顺序广播
|
|
30
|
-
*
|
|
31
|
-
* @param signedTransactions 签名后的交易数组
|
|
32
|
-
* @param config 直接广播配置
|
|
33
|
-
* @returns 广播结果
|
|
34
|
-
*/
|
|
35
|
-
export declare function submitDirectToRpcParallel(signedTransactions: string[], config: DirectSubmitConfig): Promise<DirectSubmitResult>;
|
|
36
|
-
/**
|
|
37
|
-
* ✅ 智能广播到 RPC(自动选择并行或顺序)
|
|
38
|
-
*
|
|
39
|
-
* 根据交易的发送者地址自动决定广播策略:
|
|
40
|
-
* - 如果所有交易来自不同钱包:使用并行广播(速度快)
|
|
41
|
-
* - 如果存在同一钱包的多笔交易:使用顺序广播(确保 nonce 顺序)
|
|
42
|
-
*
|
|
43
|
-
* @param signedTransactions 签名后的交易数组
|
|
44
|
-
* @param config 直接广播配置
|
|
45
|
-
* @param options 额外选项
|
|
46
|
-
* @returns 广播结果(包含使用的模式)
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```typescript
|
|
50
|
-
* import { submitDirectToRpcSmart } from 'four-flap-meme-sdk';
|
|
51
|
-
*
|
|
52
|
-
* const result = await submitDirectToRpcSmart(signedTransactions, {
|
|
53
|
-
* rpcUrl: 'https://xlayerrpc.okx.com',
|
|
54
|
-
* chainId: 196,
|
|
55
|
-
* chainName: 'XLAYER'
|
|
56
|
-
* });
|
|
57
|
-
*
|
|
58
|
-
* console.log('使用模式:', result.mode); // 'parallel' 或 'sequential'
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
export declare function submitDirectToRpcSmart(signedTransactions: string[], config: DirectSubmitConfig, options?: {
|
|
62
|
-
/** 顺序模式时是否等待确认(默认 false) */
|
|
63
|
-
waitConfirmation?: boolean;
|
|
64
|
-
}): Promise<DirectSubmitResult & {
|
|
65
|
-
mode: 'parallel' | 'sequential';
|
|
66
|
-
}>;
|