four-flap-meme-sdk 1.3.98 → 1.4.1

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.
@@ -55,6 +55,7 @@ export interface DirectV2BuyParams {
55
55
  routerAddress: string;
56
56
  quoteToken?: string;
57
57
  quoteTokenDecimals?: number;
58
+ startNonces?: number[];
58
59
  config: DirectRouterSignConfig;
59
60
  }
60
61
  export interface DirectV2SellParams {
@@ -62,6 +63,7 @@ export interface DirectV2SellParams {
62
63
  privateKeys: string[];
63
64
  sellPercentages?: number[];
64
65
  sellAmounts?: string[];
66
+ startNonces?: number[];
65
67
  tokenAddress: string;
66
68
  tokenDecimals?: number;
67
69
  routerAddress: string;
@@ -77,6 +79,7 @@ export interface DirectV3BuyParams {
77
79
  fee: number;
78
80
  quoteToken?: string;
79
81
  quoteTokenDecimals?: number;
82
+ startNonces?: number[];
80
83
  config: DirectRouterSignConfig;
81
84
  }
82
85
  export interface DirectV3SellParams {
@@ -89,6 +92,7 @@ export interface DirectV3SellParams {
89
92
  routerAddress: string;
90
93
  fee: number;
91
94
  quoteToken?: string;
95
+ startNonces?: number[];
92
96
  config: DirectRouterSignConfig;
93
97
  }
94
98
  export interface DirectRouterResult {
@@ -666,7 +666,7 @@ function isDYORSwap(chain, routerAddress) {
666
666
  * V2 批量买入(直接调用 Router)
667
667
  */
668
668
  export async function directV2BatchBuy(params) {
669
- const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, quoteToken, quoteTokenDecimals = 18, config, } = params;
669
+ const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, quoteToken, quoteTokenDecimals = 18, startNonces, config, } = params;
670
670
  if (privateKeys.length !== buyAmounts.length) {
671
671
  throw new Error('privateKeys 和 buyAmounts 长度必须相同');
672
672
  }
@@ -676,11 +676,13 @@ export async function directV2BatchBuy(params) {
676
676
  const wrappedNative = getWrappedNative(chain);
677
677
  // 创建钱包
678
678
  const wallets = privateKeys.map(pk => new Wallet(pk, provider));
679
- // 获取 nonce
680
- const nonceManager = new NonceManager(provider);
681
- const nonces = await nonceManager.getNextNoncesForWallets(wallets);
682
- // 获取 gas price
683
- const gasPrice = await getGasPrice(provider, config);
679
+ // ✅ 性能优化:如果前端已传入 nonces,则跳过 RPC 获取
680
+ const [nonces, gasPrice] = await Promise.all([
681
+ startNonces && startNonces.length === wallets.length
682
+ ? Promise.resolve(startNonces)
683
+ : new NonceManager(provider).getNextNoncesForWallets(wallets),
684
+ getGasPrice(provider, config)
685
+ ]);
684
686
  const gasLimit = getGasLimit(config, 250000);
685
687
  const txType = config.txType ?? 0;
686
688
  const deadline = getDeadline();
@@ -807,7 +809,7 @@ export async function directV2BatchBuy(params) {
807
809
  * V2 批量卖出(直接调用 Router)
808
810
  */
809
811
  export async function directV2BatchSell(params) {
810
- const { chain, privateKeys, sellPercentages, sellAmounts, tokenAddress, tokenDecimals: inputDecimals, routerAddress, quoteToken, config, } = params;
812
+ const { chain, privateKeys, sellPercentages, sellAmounts, tokenAddress, tokenDecimals: inputDecimals, routerAddress, quoteToken, startNonces, config, } = params;
811
813
  const chainId = config.chainId || CHAIN_IDS[chain.toUpperCase()] || 56;
812
814
  const provider = new JsonRpcProvider(config.rpcUrl, { chainId, name: chain });
813
815
  const useNativeOutput = isNativeToken(quoteToken);
@@ -816,19 +818,27 @@ export async function directV2BatchSell(params) {
816
818
  const wallets = privateKeys.map(pk => new Wallet(pk, provider));
817
819
  // 获取代币合约
818
820
  const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
819
- // ✅ 自动获取代币精度(如果未提供)
820
- let tokenDecimals = inputDecimals;
821
- if (tokenDecimals === undefined) {
822
- try {
823
- tokenDecimals = Number(await tokenContract.decimals());
824
- }
825
- catch {
826
- tokenDecimals = 18; // 默认 18
827
- }
828
- }
829
- // 获取代币余额
830
- const balances = await Promise.all(wallets.map(w => tokenContract.balanceOf(w.address)));
831
- // 计算卖出数量
821
+ // ✅ 性能优化:并行获取所有独立的 RPC 数据
822
+ // 如果前端已传入 nonces,则跳过 RPC 获取
823
+ const [fetchedDecimals, balances, nonces, gasPrice] = await Promise.all([
824
+ // 1. 获取代币精度(如果未提供)
825
+ inputDecimals !== undefined
826
+ ? Promise.resolve(inputDecimals)
827
+ : tokenContract.decimals().then((d) => Number(d)).catch(() => 18),
828
+ // 2. 批量获取余额
829
+ Promise.all(wallets.map(w => tokenContract.balanceOf(w.address))),
830
+ // 3. 批量获取 nonce(如果前端已传入则跳过)
831
+ startNonces && startNonces.length === wallets.length
832
+ ? Promise.resolve(startNonces)
833
+ : new NonceManager(provider).getNextNoncesForWallets(wallets),
834
+ // 4. 获取 gas price
835
+ getGasPrice(provider, config)
836
+ ]);
837
+ const tokenDecimals = fetchedDecimals;
838
+ const gasLimit = getGasLimit(config, 300000);
839
+ const txType = config.txType ?? 0;
840
+ const deadline = getDeadline();
841
+ // 计算卖出数量(同步操作,无 RPC)
832
842
  const sellAmountsWei = [];
833
843
  for (let i = 0; i < wallets.length; i++) {
834
844
  if (sellAmounts && sellAmounts[i]) {
@@ -844,13 +854,6 @@ export async function directV2BatchSell(params) {
844
854
  sellAmountsWei.push(balances[i]); // 默认全部卖出
845
855
  }
846
856
  }
847
- // 获取 nonce(每个钱包可能需要 2 个:授权 + 卖出)
848
- const nonceManager = new NonceManager(provider);
849
- const nonces = await nonceManager.getNextNoncesForWallets(wallets);
850
- const gasPrice = await getGasPrice(provider, config);
851
- const gasLimit = getGasLimit(config, 300000);
852
- const txType = config.txType ?? 0;
853
- const deadline = getDeadline();
854
857
  // 构建路径
855
858
  const outputToken = useNativeOutput ? wrappedNative : quoteToken;
856
859
  const path = [tokenAddress, outputToken];
@@ -861,7 +864,6 @@ export async function directV2BatchSell(params) {
861
864
  const routerIface = useSwapRouter02
862
865
  ? new ethers.Interface(SWAP_ROUTER02_V2_ABI)
863
866
  : new ethers.Interface(V2_ROUTER_ABI);
864
- const approveIface = new ethers.Interface(ERC20_ABI);
865
867
  // ✅ 优化:构建卖出交易数据的辅助函数(同步)
866
868
  const buildSellTxData = (wallet, sellAmount) => {
867
869
  if (useDYORSwap) {
@@ -895,40 +897,14 @@ export async function directV2BatchSell(params) {
895
897
  return routerIface.encodeFunctionData('swapExactTokensForTokensSupportingFeeOnTransferTokens', [sellAmount, 0n, path, wallet.address, deadline]);
896
898
  }
897
899
  };
898
- // ✅ 优化:并行检查所有授权
899
- let allowances = [];
900
- if (!config.skipApprovalCheck) {
901
- allowances = await Promise.all(wallets.map(w => tokenContract.allowance(w.address, routerAddress)));
902
- }
903
- // ✅ 先获取报价,确定哪个钱包输出最大(用于支付贿赂和利润)
904
- const router = new Contract(routerAddress, V2_ROUTER_ABI, provider);
905
- const quotePromises = wallets.map(async (_, i) => {
906
- if (sellAmountsWei[i] <= 0n)
907
- return sellAmountsWei[i];
908
- try {
909
- const amounts = await router.getAmountsOut(sellAmountsWei[i], path);
910
- return amounts[amounts.length - 1];
911
- }
912
- catch {
913
- return sellAmountsWei[i];
914
- }
915
- });
916
- const outputEstimates = await Promise.all(quotePromises);
917
- const maxOutputIndex = findMaxFlowIndex(outputEstimates);
900
+ // ✅ 性能优化:直接用 sellAmountsWei 找最大输出钱包(跳过 N 次 getAmountsOut RPC 调用)
901
+ // 因为卖出金额越大,输出也越大(假设线性关系),无需额外报价
902
+ const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
918
903
  // ✅ 计算贿赂金额(仅 BSC 链)
919
904
  const bribeWei = getBribeAmount(config, chain);
920
905
  const hasBribe = bribeWei > 0n && wallets.length > 0;
921
- // ✅ 优化:计算每个钱包的 nonce 偏移(授权 + 贿赂)
922
- const currentNonceOffset = wallets.map((_, i) => {
923
- let offset = 0;
924
- // 贿赂交易偏移(只有 maxOutputIndex 钱包需要)
925
- if (hasBribe && i === maxOutputIndex)
926
- offset++;
927
- // 授权交易偏移
928
- if (!config.skipApprovalCheck && allowances[i] < sellAmountsWei[i])
929
- offset++;
930
- return offset;
931
- });
906
+ // ✅ 计算 nonce 偏移(仅贿赂,已移除授权)
907
+ const nonceOffsets = wallets.map((_, i) => i === maxOutputIndex && hasBribe ? 1 : 0);
932
908
  // ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级)
933
909
  const bribeTxs = [];
934
910
  if (hasBribe) {
@@ -936,55 +912,23 @@ export async function directV2BatchSell(params) {
936
912
  gasPrice, chainId, txType);
937
913
  bribeTxs.push(bribeTx);
938
914
  }
939
- // ✅ 优化:并行签名所有授权交易
940
- const approvalTxPromises = wallets.map(async (wallet, i) => {
941
- if (config.skipApprovalCheck || sellAmountsWei[i] <= 0n)
942
- return null;
943
- if (allowances[i] >= sellAmountsWei[i])
944
- return null;
945
- // 授权交易的 nonce = 原始 nonce + 贿赂偏移
946
- const approvalNonce = nonces[i] + (hasBribe && i === maxOutputIndex ? 1 : 0);
947
- return wallet.signTransaction({
948
- to: tokenAddress,
949
- data: approveIface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]),
950
- value: 0n,
951
- nonce: approvalNonce,
952
- gasLimit: 60000n,
953
- gasPrice,
954
- chainId,
955
- type: txType,
956
- });
957
- });
958
- const approvalTxResults = await Promise.all(approvalTxPromises);
959
- // ✅ 优化:并行签名所有卖出交易
960
- const sellTxPromises = wallets.map(async (wallet, i) => {
915
+ // ✅ 优化:并行签名所有卖出交易(已移除授权交易)
916
+ const swapTxs = await Promise.all(wallets.map(async (wallet, i) => {
961
917
  if (sellAmountsWei[i] <= 0n)
962
918
  return null;
963
919
  return wallet.signTransaction({
964
920
  to: routerAddress,
965
921
  data: buildSellTxData(wallet, sellAmountsWei[i]),
966
922
  value: 0n,
967
- nonce: nonces[i] + currentNonceOffset[i],
923
+ nonce: nonces[i] + nonceOffsets[i],
968
924
  gasLimit,
969
925
  gasPrice,
970
926
  chainId,
971
927
  type: txType,
972
928
  });
973
- });
974
- const sellTxResults = await Promise.all(sellTxPromises);
975
- // 按顺序组装签名交易:先授权,后卖出
976
- const swapTxs = [];
977
- for (let i = 0; i < wallets.length; i++) {
978
- const approvalTx = approvalTxResults[i];
979
- const sellTx = sellTxResults[i];
980
- if (approvalTx)
981
- swapTxs.push(approvalTx);
982
- if (sellTx) {
983
- swapTxs.push(sellTx);
984
- currentNonceOffset[i]++; // 更新 offset 供利润交易使用
985
- }
986
- }
987
- const totalOutputEstimate = outputEstimates.reduce((sum, o) => sum + o, 0n);
929
+ })).then(results => results.filter((tx) => tx !== null));
930
+ // 使用 sellAmountsWei 作为输出估计(因为已跳过 getAmountsOut 调用)
931
+ const totalOutputEstimate = sellAmountsWei.reduce((sum, o) => sum + o, 0n);
988
932
  let profitWei = calculateProfitAmount(totalOutputEstimate);
989
933
  // ✅ 修复:ERC20 输出时,将利润转换为原生代币
990
934
  if (!useNativeOutput && profitWei > 0n && quoteToken) {
@@ -999,11 +943,13 @@ export async function directV2BatchSell(params) {
999
943
  // ✅ 利润交易
1000
944
  const profitTxs = [];
1001
945
  if (profitWei > 0n && wallets.length > 0) {
946
+ // 利润交易 nonce = 原始 nonce + 贿赂偏移 + 1(卖出交易)
947
+ const profitNonce = nonces[maxOutputIndex] + nonceOffsets[maxOutputIndex] + 1;
1002
948
  const profitTx = await buildProfitTransaction(wallets[maxOutputIndex], // ✅ 使用输出最大的钱包
1003
- profitWei, nonces[maxOutputIndex] + currentNonceOffset[maxOutputIndex], gasPrice, chainId, txType);
949
+ profitWei, profitNonce, gasPrice, chainId, txType);
1004
950
  profitTxs.push(profitTx);
1005
951
  }
1006
- // ✅ 组装最终交易列表:贿赂 → 授权+卖出 → 利润
952
+ // ✅ 组装最终交易列表:贿赂 → 卖出 → 利润
1007
953
  const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
1008
954
  return {
1009
955
  signedTransactions: signedTxs,
@@ -1025,7 +971,7 @@ export async function directV2BatchSell(params) {
1025
971
  * - SwapRouter (旧版 Uniswap V3): exactInputSingle 含 deadline,multicall 不含 deadline
1026
972
  */
1027
973
  export async function directV3BatchBuy(params) {
1028
- const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, fee, quoteToken, quoteTokenDecimals = 18, config, } = params;
974
+ const { chain, privateKeys, buyAmounts, tokenAddress, routerAddress, fee, quoteToken, quoteTokenDecimals = 18, startNonces, config, } = params;
1029
975
  if (privateKeys.length !== buyAmounts.length) {
1030
976
  throw new Error('privateKeys 和 buyAmounts 长度必须相同');
1031
977
  }
@@ -1037,9 +983,13 @@ export async function directV3BatchBuy(params) {
1037
983
  const useLegacyRouter = isLegacySwapRouter(chain, routerAddress);
1038
984
  const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
1039
985
  const wallets = privateKeys.map(pk => new Wallet(pk, provider));
1040
- const nonceManager = new NonceManager(provider);
1041
- const nonces = await nonceManager.getNextNoncesForWallets(wallets);
1042
- const gasPrice = await getGasPrice(provider, config);
986
+ // 性能优化:如果前端已传入 nonces,则跳过 RPC 获取
987
+ const [nonces, gasPrice] = await Promise.all([
988
+ startNonces && startNonces.length === wallets.length
989
+ ? Promise.resolve(startNonces)
990
+ : new NonceManager(provider).getNextNoncesForWallets(wallets),
991
+ getGasPrice(provider, config)
992
+ ]);
1043
993
  const gasLimit = getGasLimit(config, 300000);
1044
994
  const txType = config.txType ?? 0;
1045
995
  const routerIface = new ethers.Interface(routerAbi);
@@ -1159,7 +1109,7 @@ export async function directV3BatchBuy(params) {
1159
1109
  * - SwapRouter (旧版 Uniswap V3): exactInputSingle 含 deadline,multicall 不含 deadline
1160
1110
  */
1161
1111
  export async function directV3BatchSell(params) {
1162
- const { chain, privateKeys, sellPercentages, sellAmounts, tokenAddress, tokenDecimals = 18, routerAddress, fee, quoteToken, config, } = params;
1112
+ const { chain, privateKeys, sellPercentages, sellAmounts, tokenAddress, tokenDecimals = 18, routerAddress, fee, quoteToken, startNonces, config, } = params;
1163
1113
  const chainId = config.chainId || CHAIN_IDS[chain.toUpperCase()] || 56;
1164
1114
  const provider = new JsonRpcProvider(config.rpcUrl, { chainId, name: chain });
1165
1115
  const useNativeOutput = isNativeToken(quoteToken);
@@ -1169,9 +1119,21 @@ export async function directV3BatchSell(params) {
1169
1119
  const routerAbi = useLegacyRouter ? V3_ROUTER_LEGACY_ABI : V3_ROUTER02_ABI;
1170
1120
  const wallets = privateKeys.map(pk => new Wallet(pk, provider));
1171
1121
  const tokenContract = new Contract(tokenAddress, ERC20_ABI, provider);
1172
- // 获取余额
1173
- const balances = await Promise.all(wallets.map(w => tokenContract.balanceOf(w.address)));
1174
- // 计算卖出数量
1122
+ // ✅ 性能优化:并行获取所有独立的 RPC 数据
1123
+ // 如果前端已传入 nonces,则跳过 RPC 获取
1124
+ const [balances, nonces, gasPrice] = await Promise.all([
1125
+ // 1. 批量获取余额
1126
+ Promise.all(wallets.map(w => tokenContract.balanceOf(w.address))),
1127
+ // 2. 批量获取 nonce(如果前端已传入则跳过)
1128
+ startNonces && startNonces.length === wallets.length
1129
+ ? Promise.resolve(startNonces)
1130
+ : new NonceManager(provider).getNextNoncesForWallets(wallets),
1131
+ // 3. 获取 gas price
1132
+ getGasPrice(provider, config)
1133
+ ]);
1134
+ const gasLimit = getGasLimit(config, 350000);
1135
+ const txType = config.txType ?? 0;
1136
+ // 计算卖出数量(同步操作,无 RPC)
1175
1137
  const sellAmountsWei = [];
1176
1138
  for (let i = 0; i < wallets.length; i++) {
1177
1139
  if (sellAmounts && sellAmounts[i]) {
@@ -1185,13 +1147,7 @@ export async function directV3BatchSell(params) {
1185
1147
  sellAmountsWei.push(balances[i]);
1186
1148
  }
1187
1149
  }
1188
- const nonceManager = new NonceManager(provider);
1189
- const nonces = await nonceManager.getNextNoncesForWallets(wallets);
1190
- const gasPrice = await getGasPrice(provider, config);
1191
- const gasLimit = getGasLimit(config, 350000);
1192
- const txType = config.txType ?? 0;
1193
1150
  const routerIface = new ethers.Interface(routerAbi);
1194
- const approveIface = new ethers.Interface(ERC20_ABI);
1195
1151
  const outputToken = useNativeOutput ? wrappedNative : quoteToken;
1196
1152
  const deadline = getDeadline();
1197
1153
  // ✅ 优化:构建卖出交易数据的辅助函数
@@ -1236,28 +1192,14 @@ export async function directV3BatchSell(params) {
1236
1192
  }
1237
1193
  }
1238
1194
  };
1239
- // ✅ 优化:并行检查所有授权
1240
- let allowances = [];
1241
- if (!config.skipApprovalCheck) {
1242
- allowances = await Promise.all(wallets.map(w => tokenContract.allowance(w.address, routerAddress)));
1243
- }
1244
1195
  // ✅ 先找出输出最大的钱包索引(用于支付贿赂和利润)
1245
1196
  // 对于 V3 卖出,使用卖出金额作为输出估计
1246
1197
  const maxOutputIndex = findMaxFlowIndex(sellAmountsWei);
1247
1198
  // ✅ 计算贿赂金额(仅 BSC 链)
1248
1199
  const bribeWei = getBribeAmount(config, chain);
1249
1200
  const hasBribe = bribeWei > 0n && wallets.length > 0;
1250
- // ✅ 优化:计算每个钱包的 nonce 偏移(贿赂 + 授权)
1251
- const currentNonceOffset = wallets.map((_, i) => {
1252
- let offset = 0;
1253
- // 贿赂交易偏移(只有 maxOutputIndex 钱包需要)
1254
- if (hasBribe && i === maxOutputIndex)
1255
- offset++;
1256
- // 授权交易偏移
1257
- if (!config.skipApprovalCheck && sellAmountsWei[i] > 0n && allowances[i] < sellAmountsWei[i])
1258
- offset++;
1259
- return offset;
1260
- });
1201
+ // ✅ 计算 nonce 偏移(仅贿赂,已移除授权)
1202
+ const nonceOffsets = wallets.map((_, i) => i === maxOutputIndex && hasBribe ? 1 : 0);
1261
1203
  // ✅ 贿赂交易放在首位(提高 BlockRazor 打包优先级)
1262
1204
  const bribeTxs = [];
1263
1205
  if (hasBribe) {
@@ -1265,60 +1207,23 @@ export async function directV3BatchSell(params) {
1265
1207
  gasPrice, chainId, txType);
1266
1208
  bribeTxs.push(bribeTx);
1267
1209
  }
1268
- // ✅ 优化:并行签名所有授权交易
1269
- const approvalTxPromises = wallets.map(async (wallet, i) => {
1270
- if (config.skipApprovalCheck || sellAmountsWei[i] <= 0n)
1271
- return null;
1272
- if (allowances[i] >= sellAmountsWei[i])
1273
- return null;
1274
- // 授权交易的 nonce = 原始 nonce + 贿赂偏移
1275
- const approvalNonce = nonces[i] + (hasBribe && i === maxOutputIndex ? 1 : 0);
1276
- return wallet.signTransaction({
1277
- to: tokenAddress,
1278
- data: approveIface.encodeFunctionData('approve', [routerAddress, ethers.MaxUint256]),
1279
- value: 0n,
1280
- nonce: approvalNonce,
1281
- gasLimit: 60000n,
1282
- gasPrice,
1283
- chainId,
1284
- type: txType,
1285
- });
1286
- });
1287
- const approvalTxResults = await Promise.all(approvalTxPromises);
1288
- // ✅ 优化:并行签名所有卖出交易
1289
- const sellTxPromises = wallets.map(async (wallet, i) => {
1210
+ // ✅ 优化:并行签名所有卖出交易(已移除授权交易)
1211
+ const swapTxs = await Promise.all(wallets.map(async (wallet, i) => {
1290
1212
  if (sellAmountsWei[i] <= 0n)
1291
1213
  return null;
1292
1214
  return wallet.signTransaction({
1293
1215
  to: routerAddress,
1294
1216
  data: buildV3SellTxData(wallet, sellAmountsWei[i]),
1295
1217
  value: 0n,
1296
- nonce: nonces[i] + currentNonceOffset[i],
1218
+ nonce: nonces[i] + nonceOffsets[i],
1297
1219
  gasLimit,
1298
1220
  gasPrice,
1299
1221
  chainId,
1300
1222
  type: txType,
1301
1223
  });
1302
- });
1303
- const sellTxResults = await Promise.all(sellTxPromises);
1304
- // 按顺序组装签名交易:先授权,后卖出
1305
- const swapTxs = [];
1306
- const outputEstimates = [];
1307
- for (let i = 0; i < wallets.length; i++) {
1308
- const approvalTx = approvalTxResults[i];
1309
- const sellTx = sellTxResults[i];
1310
- if (approvalTx)
1311
- swapTxs.push(approvalTx);
1312
- if (sellTx) {
1313
- swapTxs.push(sellTx);
1314
- outputEstimates.push(sellAmountsWei[i]);
1315
- currentNonceOffset[i]++;
1316
- }
1317
- else {
1318
- outputEstimates.push(0n);
1319
- }
1320
- }
1321
- const totalOutputEstimate = outputEstimates.reduce((sum, o) => sum + o, 0n);
1224
+ })).then(results => results.filter((tx) => tx !== null));
1225
+ // 使用 sellAmountsWei 计算总输出
1226
+ const totalOutputEstimate = sellAmountsWei.reduce((sum, o) => sum + o, 0n);
1322
1227
  let profitWei = calculateProfitAmount(totalOutputEstimate);
1323
1228
  // ✅ 修复:ERC20 输出时,将利润转换为原生代币
1324
1229
  if (!useNativeOutput && profitWei > 0n && quoteToken) {
@@ -1333,11 +1238,13 @@ export async function directV3BatchSell(params) {
1333
1238
  // ✅ 利润交易
1334
1239
  const profitTxs = [];
1335
1240
  if (profitWei > 0n && wallets.length > 0) {
1241
+ // 利润交易 nonce = 原始 nonce + 贿赂偏移 + 1(卖出交易)
1242
+ const profitNonce = nonces[maxOutputIndex] + nonceOffsets[maxOutputIndex] + 1;
1336
1243
  const profitTx = await buildProfitTransaction(wallets[maxOutputIndex], // ✅ 使用输出最大的钱包
1337
- profitWei, nonces[maxOutputIndex] + currentNonceOffset[maxOutputIndex], gasPrice, chainId, txType);
1244
+ profitWei, profitNonce, gasPrice, chainId, txType);
1338
1245
  profitTxs.push(profitTx);
1339
1246
  }
1340
- // ✅ 组装最终交易列表:贿赂 → 授权+卖出 → 利润
1247
+ // ✅ 组装最终交易列表:贿赂 → 卖出 → 利润
1341
1248
  const signedTxs = [...bribeTxs, ...swapTxs, ...profitTxs];
1342
1249
  return {
1343
1250
  signedTransactions: signedTxs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.3.98",
3
+ "version": "1.4.1",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",