four-flap-meme-sdk 1.7.21 → 1.7.23
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/eip7702/xlayer/bundle-buy.d.ts +6 -1
- package/dist/eip7702/xlayer/bundle-buy.js +5 -3
- package/dist/eip7702/xlayer/bundle-create.js +13 -10
- package/dist/eip7702/xlayer/bundle-sell.d.ts +6 -1
- package/dist/eip7702/xlayer/bundle-sell.js +146 -7
- package/dist/eip7702/xlayer/bundle-swap.d.ts +76 -1
- package/dist/eip7702/xlayer/bundle-swap.js +346 -11
- package/dist/eip7702/xlayer/constants.d.ts +11 -3
- package/dist/eip7702/xlayer/constants.js +11 -2
- package/dist/eip7702/xlayer/index.d.ts +7 -6
- package/dist/eip7702/xlayer/index.js +6 -2
- package/dist/eip7702/xlayer/types.d.ts +22 -0
- package/dist/eip7702/xlayer/utils.d.ts +32 -0
- package/dist/eip7702/xlayer/utils.js +54 -3
- package/dist/eip7702/xlayer/volume.d.ts +5 -0
- package/dist/eip7702/xlayer/volume.js +11 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/package.json +1 -1
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
*
|
|
7
7
|
* 只生成签名,由调用方决定如何提交
|
|
8
8
|
*/
|
|
9
|
-
import type { BundleBuyParams, BundleBuyResult } from './types.js';
|
|
9
|
+
import type { BundleBuyParams as BaseBundleBuyParams, BundleBuyResult } from './types.js';
|
|
10
|
+
import { type UserType } from './utils.js';
|
|
11
|
+
export interface BundleBuyParams extends BaseBundleBuyParams {
|
|
12
|
+
/** 用户类型(影响利润率) */
|
|
13
|
+
userType?: UserType;
|
|
14
|
+
}
|
|
10
15
|
/**
|
|
11
16
|
* 批量买入 - 生成签名后的交易
|
|
12
17
|
*
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 只生成签名,由调用方决定如何提交
|
|
8
8
|
*/
|
|
9
9
|
import { ethers } from 'ethers';
|
|
10
|
-
import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync,
|
|
10
|
+
import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync, calculateProfitAmountByTxCount, getProfitRecipient, } from './utils.js';
|
|
11
11
|
import { UNIFIED_DELEGATE_ADDRESS, POTATOSWAP_V2_ROUTER, POTATOSWAP_V3_ROUTER, FLAP_PORTAL_ADDRESS, WOKB_ADDRESS, V3_FEE_TIERS, UNIFIED_DELEGATE_ABI, FLAP_PORTAL_ABI, } from './constants.js';
|
|
12
12
|
// ========================================
|
|
13
13
|
// 路由地址获取
|
|
@@ -177,7 +177,8 @@ function buildProfitCall(mainWallet, profitAmount, profitRecipient) {
|
|
|
177
177
|
* });
|
|
178
178
|
*/
|
|
179
179
|
export async function bundleBuy(params) {
|
|
180
|
-
const { mainPrivateKey, privateKeys, buyAmounts, tokenAddress, tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM,
|
|
180
|
+
const { mainPrivateKey, privateKeys, buyAmounts, tokenAddress, tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', // ✅ 用户类型(影响利润率)
|
|
181
|
+
config, } = params;
|
|
181
182
|
if (privateKeys.length !== buyAmounts.length) {
|
|
182
183
|
throw new Error('privateKeys 和 buyAmounts 长度必须相同');
|
|
183
184
|
}
|
|
@@ -192,7 +193,8 @@ export async function bundleBuy(params) {
|
|
|
192
193
|
// 批量解析金额(同步)
|
|
193
194
|
const buyAmountsWei = buyAmounts.map(amt => ethers.parseEther(amt));
|
|
194
195
|
const totalBuyAmount = buyAmountsWei.reduce((sum, amt) => sum + amt, 0n);
|
|
195
|
-
|
|
196
|
+
// ✅ 使用 userType 计算利润
|
|
197
|
+
const profitAmount = calculateProfitAmountByTxCount(totalBuyAmount, wallets.length, userType);
|
|
196
198
|
const profitRecipient = getProfitRecipient(config);
|
|
197
199
|
// 确定需要授权的钱包
|
|
198
200
|
const mainWalletIndex = wallets.findIndex(w => w.address.toLowerCase() === mainWallet.address.toLowerCase());
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { ethers, Interface, Contract } from 'ethers';
|
|
12
12
|
import { FLAP_PORTAL_ADDRESS, UNIFIED_DELEGATE_ADDRESS, UNIFIED_DELEGATE_ABI, FLAP_PORTAL_ABI, WOKB_ADDRESS, POTATOSWAP_V2_ROUTER, POTATOSWAP_V3_ROUTER, V3_FEE_TIERS, } from './constants.js';
|
|
13
|
-
import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync,
|
|
13
|
+
import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync, calculateProfitAmountByUserType, getProfitRecipient, } from './utils.js';
|
|
14
14
|
// ========================================
|
|
15
15
|
// 常量
|
|
16
16
|
// ========================================
|
|
@@ -125,7 +125,8 @@ function buildProfitCall(walletAddress, profitAmount, profitRecipient, delegateI
|
|
|
125
125
|
* @returns 只返回签名后的交易,不发送
|
|
126
126
|
*/
|
|
127
127
|
export async function bundleCreateBuy(params) {
|
|
128
|
-
const { tokenInfo, tokenAddress = ZERO_ADDRESS, devPrivateKey, buyerPrivateKeys, buyAmounts,
|
|
128
|
+
const { tokenInfo, tokenAddress = ZERO_ADDRESS, devPrivateKey, buyerPrivateKeys, buyAmounts, userType = 'v0', // ✅ 用户类型(影响利润率)
|
|
129
|
+
config, } = params;
|
|
129
130
|
if (buyerPrivateKeys.length !== buyAmounts.length) {
|
|
130
131
|
throw new Error('buyerPrivateKeys 和 buyAmounts 长度必须相同');
|
|
131
132
|
}
|
|
@@ -137,10 +138,10 @@ export async function bundleCreateBuy(params) {
|
|
|
137
138
|
const buyerWallets = buyerPrivateKeys.map(pk => createWallet(pk, provider));
|
|
138
139
|
const allWallets = [devWallet, ...buyerWallets];
|
|
139
140
|
const mainWallet = devWallet;
|
|
140
|
-
//
|
|
141
|
+
// 计算买入金额和利润(单边模式:只有买入)
|
|
141
142
|
const buyAmountsWei = buyAmounts.map(amt => ethers.parseEther(amt));
|
|
142
143
|
const totalBuyAmount = buyAmountsWei.reduce((sum, amt) => sum + amt, 0n);
|
|
143
|
-
const profitAmount =
|
|
144
|
+
const profitAmount = calculateProfitAmountByUserType(totalBuyAmount, userType, false); // ✅ 支持 userType
|
|
144
145
|
const profitRecipient = getProfitRecipient(config);
|
|
145
146
|
// 并行获取 nonce 和 fee data
|
|
146
147
|
const [nonces, feeData] = await Promise.all([
|
|
@@ -272,7 +273,8 @@ export async function bundleCreateBuy(params) {
|
|
|
272
273
|
* @returns 只返回签名后的交易,不发送
|
|
273
274
|
*/
|
|
274
275
|
export async function bundleCreateToDex(params) {
|
|
275
|
-
const { tokenInfo, tokenAddress = ZERO_ADDRESS, payerPrivateKey, curveBuyerPrivateKeys, curveBuyAmounts, enableDexBuy = false, dexBuyerPrivateKeys = [], dexBuyAmounts = [],
|
|
276
|
+
const { tokenInfo, tokenAddress = ZERO_ADDRESS, payerPrivateKey, curveBuyerPrivateKeys, curveBuyAmounts, enableDexBuy = false, dexBuyerPrivateKeys = [], dexBuyAmounts = [], userType = 'v0', // ✅ 用户类型(影响利润率)
|
|
277
|
+
config, } = params;
|
|
276
278
|
if (curveBuyerPrivateKeys.length !== curveBuyAmounts.length) {
|
|
277
279
|
throw new Error('curveBuyerPrivateKeys 和 curveBuyAmounts 长度必须相同');
|
|
278
280
|
}
|
|
@@ -294,13 +296,13 @@ export async function bundleCreateToDex(params) {
|
|
|
294
296
|
const allWallets = Array.from(allWalletsMap.values());
|
|
295
297
|
const mainWallet = payerWallet;
|
|
296
298
|
const mainWalletIndex = allWallets.findIndex(w => w.address.toLowerCase() === mainWallet.address.toLowerCase());
|
|
297
|
-
//
|
|
299
|
+
// 计算金额和利润(单边模式:只有买入)
|
|
298
300
|
const curveBuyAmountsWei = curveBuyAmounts.map(amt => ethers.parseEther(amt));
|
|
299
301
|
const dexBuyAmountsWei = dexBuyAmounts.map(amt => ethers.parseEther(amt));
|
|
300
302
|
const totalCurveBuyAmount = curveBuyAmountsWei.reduce((sum, amt) => sum + amt, 0n);
|
|
301
303
|
const totalDexBuyAmount = dexBuyAmountsWei.reduce((sum, amt) => sum + amt, 0n);
|
|
302
304
|
const totalBuyAmount = totalCurveBuyAmount + totalDexBuyAmount;
|
|
303
|
-
const profitAmount =
|
|
305
|
+
const profitAmount = calculateProfitAmountByUserType(totalBuyAmount, userType, false); // ✅ 支持 userType
|
|
304
306
|
const profitRecipient = getProfitRecipient(config);
|
|
305
307
|
// 并行获取 nonce 和 fee data
|
|
306
308
|
const [nonces, feeData] = await Promise.all([
|
|
@@ -426,7 +428,8 @@ export async function bundleCreateToDex(params) {
|
|
|
426
428
|
* @returns 只返回签名后的交易,不发送
|
|
427
429
|
*/
|
|
428
430
|
export async function bundleGraduateBuy(params) {
|
|
429
|
-
const { tokenAddress, privateKeys, payerPrivateKey, amountMode, totalBuyAmount, minAmount, maxAmount, walletAmounts, enableDexBuy = false, extensionData = '0x', curveAddresses, dexAddresses, graduationAmount,
|
|
431
|
+
const { tokenAddress, privateKeys, payerPrivateKey, amountMode, totalBuyAmount, minAmount, maxAmount, walletAmounts, enableDexBuy = false, extensionData = '0x', curveAddresses, dexAddresses, graduationAmount, userType = 'v0', // ✅ 用户类型(影响利润率)
|
|
432
|
+
config, } = params;
|
|
430
433
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
431
434
|
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
432
435
|
const delegateInterface = new Interface(UNIFIED_DELEGATE_ABI);
|
|
@@ -519,11 +522,11 @@ export async function bundleGraduateBuy(params) {
|
|
|
519
522
|
const allWallets = Array.from(allWalletsMap.values());
|
|
520
523
|
const mainWallet = payerWallet;
|
|
521
524
|
const mainWalletIndex = allWallets.findIndex(w => w.address.toLowerCase() === mainWallet.address.toLowerCase());
|
|
522
|
-
//
|
|
525
|
+
// 计算金额和利润(单边模式:只有买入)
|
|
523
526
|
const curveTotalWei = curveBuyers.reduce((sum, b) => sum + b.amount, 0n);
|
|
524
527
|
const dexTotalWei = dexBuyers.reduce((sum, b) => sum + b.amount, 0n);
|
|
525
528
|
const totalAmount = curveTotalWei + dexTotalWei;
|
|
526
|
-
const profitAmount =
|
|
529
|
+
const profitAmount = calculateProfitAmountByUserType(totalAmount, userType, false); // ✅ 支持 userType
|
|
527
530
|
const profitRecipient = getProfitRecipient(config);
|
|
528
531
|
// 并行获取 nonce 和 fee data
|
|
529
532
|
const [nonces, feeData] = await Promise.all([
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
*
|
|
7
7
|
* 只生成签名,由调用方决定如何提交
|
|
8
8
|
*/
|
|
9
|
-
import type { BundleSellParams, BundleSellResult } from './types.js';
|
|
9
|
+
import type { BundleSellParams as BaseBundleSellParams, BundleSellResult } from './types.js';
|
|
10
|
+
import { type UserType } from './utils.js';
|
|
11
|
+
export interface BundleSellParams extends BaseBundleSellParams {
|
|
12
|
+
/** 用户类型(影响利润率) */
|
|
13
|
+
userType?: UserType;
|
|
14
|
+
}
|
|
10
15
|
/**
|
|
11
16
|
* 批量卖出 - 生成签名后的交易
|
|
12
17
|
*
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* 只生成签名,由调用方决定如何提交
|
|
8
8
|
*/
|
|
9
|
-
import { ethers, Contract } from 'ethers';
|
|
10
|
-
import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync, getProfitRecipient, } from './utils.js';
|
|
11
|
-
import { UNIFIED_DELEGATE_ADDRESS, POTATOSWAP_V2_ROUTER, POTATOSWAP_V3_ROUTER, FLAP_PORTAL_ADDRESS, WOKB_ADDRESS, V3_FEE_TIERS, UNIFIED_DELEGATE_ABI, FLAP_PORTAL_ABI, ERC20_ABI, } from './constants.js';
|
|
9
|
+
import { ethers, Contract, JsonRpcProvider } from 'ethers';
|
|
10
|
+
import { getCachedProvider, createWallet, signAuthorizationsWithNonces, batchGetNonces, buildEIP7702TransactionSync, calculateProfitAmountByUserType, getProfitRecipient, } from './utils.js';
|
|
11
|
+
import { UNIFIED_DELEGATE_ADDRESS, POTATOSWAP_V2_ROUTER, POTATOSWAP_V3_ROUTER, FLAP_PORTAL_ADDRESS, WOKB_ADDRESS, V3_FEE_TIERS, UNIFIED_DELEGATE_ABI, FLAP_PORTAL_ABI, ERC20_ABI, XLAYER_RPC_URL, XLAYER_CHAIN_ID, } from './constants.js';
|
|
12
|
+
import { quoteV2, quoteV3 } from '../../utils/quote-helpers.js';
|
|
12
13
|
// ========================================
|
|
13
14
|
// 路由地址获取
|
|
14
15
|
// ========================================
|
|
@@ -23,6 +24,88 @@ function getDefaultRouter(tradeType) {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
// ========================================
|
|
27
|
+
// 卖出报价(Token → OKB)
|
|
28
|
+
// ========================================
|
|
29
|
+
/**
|
|
30
|
+
* 获取卖出报价:预估卖出代币能得到多少 OKB
|
|
31
|
+
*
|
|
32
|
+
* @param totalSellAmount - 总卖出代币数量(wei)
|
|
33
|
+
* @param tokenAddress - 代币地址
|
|
34
|
+
* @param tradeType - 交易类型(FLAP/V2/V3)
|
|
35
|
+
* @param fee - V3 费率
|
|
36
|
+
* @param rpcUrl - RPC URL
|
|
37
|
+
* @returns 预估得到的 OKB 数量(wei)
|
|
38
|
+
*/
|
|
39
|
+
async function quoteSellOutput(totalSellAmount, tokenAddress, tradeType, fee, rpcUrl) {
|
|
40
|
+
if (totalSellAmount <= 0n)
|
|
41
|
+
return 0n;
|
|
42
|
+
const provider = new JsonRpcProvider(rpcUrl || XLAYER_RPC_URL, { chainId: XLAYER_CHAIN_ID, name: 'xlayer', ensAddress: undefined });
|
|
43
|
+
try {
|
|
44
|
+
switch (tradeType) {
|
|
45
|
+
case 'FLAP': {
|
|
46
|
+
// FLAP Portal 报价
|
|
47
|
+
const portalContract = new Contract(FLAP_PORTAL_ADDRESS, FLAP_PORTAL_ABI, provider);
|
|
48
|
+
// 先尝试 quoteSell(Token → OKB)
|
|
49
|
+
try {
|
|
50
|
+
const okbOut = await portalContract.quoteSell(tokenAddress, totalSellAmount);
|
|
51
|
+
console.log(`[Bundle Sell] FLAP quoteSell 成功: ${ethers.formatEther(okbOut)} OKB`);
|
|
52
|
+
return BigInt(okbOut.toString());
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
console.warn(`[Bundle Sell] FLAP quoteSell 失败,尝试 quoteExactInput...`);
|
|
56
|
+
}
|
|
57
|
+
// 再尝试 quoteExactInput
|
|
58
|
+
try {
|
|
59
|
+
const okbOut = await portalContract.quoteExactInput({
|
|
60
|
+
inputToken: tokenAddress,
|
|
61
|
+
outputToken: ethers.ZeroAddress, // OKB
|
|
62
|
+
inputAmount: totalSellAmount,
|
|
63
|
+
});
|
|
64
|
+
console.log(`[Bundle Sell] FLAP quoteExactInput 成功: ${ethers.formatEther(okbOut)} OKB`);
|
|
65
|
+
return BigInt(okbOut.toString());
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
console.warn(`[Bundle Sell] FLAP quoteExactInput 失败,尝试 V2...`);
|
|
69
|
+
}
|
|
70
|
+
// 回退到 V2
|
|
71
|
+
const v2Result = await quoteV2(provider, tokenAddress, WOKB_ADDRESS, totalSellAmount, 'XLAYER');
|
|
72
|
+
if (v2Result.amountOut > 0n) {
|
|
73
|
+
console.log(`[Bundle Sell] FLAP 回退 V2 报价成功: ${ethers.formatEther(v2Result.amountOut)} OKB`);
|
|
74
|
+
return v2Result.amountOut;
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case 'V2': {
|
|
79
|
+
const result = await quoteV2(provider, tokenAddress, WOKB_ADDRESS, totalSellAmount, 'XLAYER');
|
|
80
|
+
if (result.amountOut > 0n) {
|
|
81
|
+
console.log(`[Bundle Sell] V2 报价成功: ${ethers.formatEther(result.amountOut)} OKB`);
|
|
82
|
+
return result.amountOut;
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'V3': {
|
|
87
|
+
const result = await quoteV3(provider, tokenAddress, WOKB_ADDRESS, totalSellAmount, 'XLAYER', fee);
|
|
88
|
+
if (result.amountOut > 0n) {
|
|
89
|
+
console.log(`[Bundle Sell] V3 报价成功 (fee=${result.fee}): ${ethers.formatEther(result.amountOut)} OKB`);
|
|
90
|
+
return result.amountOut;
|
|
91
|
+
}
|
|
92
|
+
// 回退到 V2
|
|
93
|
+
const v2Result = await quoteV2(provider, tokenAddress, WOKB_ADDRESS, totalSellAmount, 'XLAYER');
|
|
94
|
+
if (v2Result.amountOut > 0n) {
|
|
95
|
+
console.log(`[Bundle Sell] V3 回退 V2 报价成功: ${ethers.formatEther(v2Result.amountOut)} OKB`);
|
|
96
|
+
return v2Result.amountOut;
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error(`[Bundle Sell] 报价失败:`, error);
|
|
104
|
+
}
|
|
105
|
+
console.warn(`[Bundle Sell] 无法获取报价,利润计算可能不准确`);
|
|
106
|
+
return 0n;
|
|
107
|
+
}
|
|
108
|
+
// ========================================
|
|
26
109
|
// 代币余额查询
|
|
27
110
|
// ========================================
|
|
28
111
|
async function getTokenBalances(wallets, tokenAddress) {
|
|
@@ -191,9 +274,11 @@ function buildSellCalls(wallets, sellAmounts, tokenAddress, tradeType, routerAdd
|
|
|
191
274
|
* });
|
|
192
275
|
*/
|
|
193
276
|
export async function bundleSell(params) {
|
|
194
|
-
const { mainPrivateKey, privateKeys, sellAmounts, sellPercent, tokenAddress, tokenDecimals = 18, tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM,
|
|
277
|
+
const { mainPrivateKey, privateKeys, sellAmounts, sellPercent, tokenAddress, tokenDecimals = 18, tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, userType = 'v0', // ✅ 用户类型(影响利润率)
|
|
278
|
+
config, } = params;
|
|
195
279
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
196
280
|
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
281
|
+
const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
|
|
197
282
|
const actualRouter = routerAddress ?? getDefaultRouter(tradeType);
|
|
198
283
|
// ========================================
|
|
199
284
|
// 同步操作 - 批量创建钱包
|
|
@@ -252,11 +337,62 @@ export async function bundleSell(params) {
|
|
|
252
337
|
throw new Error('无法确定卖出数量');
|
|
253
338
|
}
|
|
254
339
|
const totalSellAmount = sellAmountsWei.reduce((sum, amt) => sum + amt, 0n);
|
|
340
|
+
const validSellCount = wallets.filter((_, i) => sellAmountsWei[i] > 0n).length;
|
|
341
|
+
// ✅ 修复:获取卖出报价,基于预估的 OKB 输出计算利润
|
|
342
|
+
// 1. 先获取报价:卖出 totalSellAmount 代币能得到多少 OKB
|
|
343
|
+
const estimatedOkbOut = await quoteSellOutput(totalSellAmount, tokenAddress, tradeType, fee, config?.rpcUrl);
|
|
344
|
+
// 2. 基于预估的 OKB 输出计算利润(单边模式,isDoubleMode = false)
|
|
345
|
+
const profitAmount = estimatedOkbOut > 0n
|
|
346
|
+
? calculateProfitAmountByUserType(estimatedOkbOut, userType, false)
|
|
347
|
+
: 0n;
|
|
348
|
+
console.log(`[Bundle Sell] 卖出数量: ${ethers.formatUnits(totalSellAmount, tokenDecimals)} Token`);
|
|
349
|
+
console.log(`[Bundle Sell] 预估获得: ${ethers.formatEther(estimatedOkbOut)} OKB`);
|
|
350
|
+
console.log(`[Bundle Sell] 利润: ${ethers.formatEther(profitAmount)} OKB (userType=${userType})`);
|
|
255
351
|
// ========================================
|
|
256
352
|
// 同步构建授权和调用
|
|
257
353
|
// ========================================
|
|
258
354
|
const authorizations = signAuthorizationsWithNonces(allWallets, walletNonces, delegateAddress, mainWalletIndex === -1 ? 0 : mainWalletIndex);
|
|
259
|
-
|
|
355
|
+
// ✅ 计算每个钱包的利润(按卖出数量比例分配)
|
|
356
|
+
const profitPerWallet = [];
|
|
357
|
+
if (profitAmount > 0n && totalSellAmount > 0n) {
|
|
358
|
+
for (let i = 0; i < wallets.length; i++) {
|
|
359
|
+
const sellAmount = sellAmountsWei[i];
|
|
360
|
+
if (sellAmount > 0n) {
|
|
361
|
+
// 按比例分配利润
|
|
362
|
+
const walletProfit = (profitAmount * sellAmount) / totalSellAmount;
|
|
363
|
+
profitPerWallet.push(walletProfit);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
profitPerWallet.push(0n);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
for (let i = 0; i < wallets.length; i++) {
|
|
372
|
+
profitPerWallet.push(0n);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// ✅ 构建调用列表(卖出调用 + 每个钱包的利润刮取)
|
|
376
|
+
const calls = [];
|
|
377
|
+
// 1. 先执行卖出,每个钱包卖出代币获得 OKB
|
|
378
|
+
const sellCalls = buildSellCalls(wallets, sellAmountsWei, tokenAddress, tradeType, actualRouter, fee);
|
|
379
|
+
calls.push(...sellCalls);
|
|
380
|
+
// 2. ✅ 每个卖出钱包从自己的卖出所得中扣除利润
|
|
381
|
+
// 使用 transferAmount 传递精确金额
|
|
382
|
+
for (let i = 0; i < wallets.length; i++) {
|
|
383
|
+
const walletProfit = profitPerWallet[i];
|
|
384
|
+
if (walletProfit > 0n) {
|
|
385
|
+
calls.push({
|
|
386
|
+
target: wallets[i].address,
|
|
387
|
+
allowFailure: false,
|
|
388
|
+
value: 0n,
|
|
389
|
+
callData: delegateInterface.encodeFunctionData('transferAmount', [
|
|
390
|
+
profitRecipient,
|
|
391
|
+
walletProfit,
|
|
392
|
+
]),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
260
396
|
// ========================================
|
|
261
397
|
// 同步构建并签名交易
|
|
262
398
|
// ========================================
|
|
@@ -265,8 +401,11 @@ export async function bundleSell(params) {
|
|
|
265
401
|
signedTransaction,
|
|
266
402
|
metadata: {
|
|
267
403
|
totalSellAmount: ethers.formatUnits(totalSellAmount, tokenDecimals),
|
|
268
|
-
walletCount:
|
|
269
|
-
|
|
404
|
+
walletCount: validSellCount,
|
|
405
|
+
estimatedOkbOut: ethers.formatEther(estimatedOkbOut), // ✅ 预估卖出所得 OKB
|
|
406
|
+
profitAmount: ethers.formatEther(profitAmount), // ✅ 利润是 OKB,用 18 位精度
|
|
407
|
+
profitRecipient,
|
|
408
|
+
userType,
|
|
270
409
|
},
|
|
271
410
|
};
|
|
272
411
|
}
|
|
@@ -9,7 +9,16 @@
|
|
|
9
9
|
* 支持 FLAP 内盘、V2 和 V3 三种交易类型
|
|
10
10
|
* 只生成签名,由调用方决定如何提交
|
|
11
11
|
*/
|
|
12
|
-
import type { BundleSwapParams, BundleBatchSwapParams, BundleSwapResult } from './types.js';
|
|
12
|
+
import type { BundleSwapParams as BaseBundleSwapParams, BundleBatchSwapParams as BaseBundleBatchSwapParams, BundleSwapResult, TradeType, EIP7702Config } from './types.js';
|
|
13
|
+
export interface BundleSwapParams extends BaseBundleSwapParams {
|
|
14
|
+
/** 用户类型(影响利润率) */
|
|
15
|
+
userType?: UserType;
|
|
16
|
+
}
|
|
17
|
+
export interface BundleBatchSwapParams extends BaseBundleBatchSwapParams {
|
|
18
|
+
/** 用户类型(影响利润率) */
|
|
19
|
+
userType?: UserType;
|
|
20
|
+
}
|
|
21
|
+
import { type UserType } from './utils.js';
|
|
13
22
|
/**
|
|
14
23
|
* 捆绑换手 - 生成签名后的交易
|
|
15
24
|
*
|
|
@@ -45,3 +54,69 @@ export declare function bundleSwap(params: BundleSwapParams): Promise<BundleSwap
|
|
|
45
54
|
* });
|
|
46
55
|
*/
|
|
47
56
|
export declare function bundleBatchSwap(params: BundleBatchSwapParams): Promise<BundleSwapResult>;
|
|
57
|
+
export interface BundleMultiSwapParams {
|
|
58
|
+
/** Payer 钱包私钥(支付 Gas 费) */
|
|
59
|
+
mainPrivateKey: string;
|
|
60
|
+
/** 卖出钱包私钥列表 */
|
|
61
|
+
sellerPrivateKeys: string[];
|
|
62
|
+
/** 买入钱包私钥列表 */
|
|
63
|
+
buyerPrivateKeys: string[];
|
|
64
|
+
/** 买入总金额 (OKB) */
|
|
65
|
+
totalBuyAmount: string;
|
|
66
|
+
/** 代币地址 */
|
|
67
|
+
tokenAddress: string;
|
|
68
|
+
/** 代币精度 */
|
|
69
|
+
tokenDecimals?: number;
|
|
70
|
+
/** 卖出百分比(1-100,默认 100) */
|
|
71
|
+
sellPercent?: number;
|
|
72
|
+
/** 交易类型:FLAP 内盘 / V2 / V3(默认 V3) */
|
|
73
|
+
tradeType?: TradeType;
|
|
74
|
+
/** 路由地址(可选,根据 tradeType 自动选择) */
|
|
75
|
+
routerAddress?: string;
|
|
76
|
+
/** V3 费率(可选,默认 2500,仅 V3 使用) */
|
|
77
|
+
fee?: number;
|
|
78
|
+
/** 用户类型(影响利润率) */
|
|
79
|
+
userType?: UserType;
|
|
80
|
+
/** 配置 */
|
|
81
|
+
config?: EIP7702Config;
|
|
82
|
+
}
|
|
83
|
+
export interface BundleMultiSwapResult {
|
|
84
|
+
/** 签名后的交易 */
|
|
85
|
+
signedTransaction: string;
|
|
86
|
+
/** 元数据 */
|
|
87
|
+
metadata: {
|
|
88
|
+
payerAddress: string;
|
|
89
|
+
sellerAddresses: string[];
|
|
90
|
+
buyerAddresses: string[];
|
|
91
|
+
sellerCount: number;
|
|
92
|
+
buyerCount: number;
|
|
93
|
+
totalBuyAmount: string;
|
|
94
|
+
totalSellAmount: string;
|
|
95
|
+
profitAmount: string;
|
|
96
|
+
profitRecipient: string;
|
|
97
|
+
userType: string;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 多对多换手 - 多个卖家 + 多个买家
|
|
102
|
+
*
|
|
103
|
+
* 核心逻辑:[利润刮取] + [卖出Ops...] + [买入Ops...]
|
|
104
|
+
*
|
|
105
|
+
* 特点:
|
|
106
|
+
* - 多个卖家同时卖出
|
|
107
|
+
* - 多个买家同时买入
|
|
108
|
+
* - 所有操作在一笔交易中原子执行
|
|
109
|
+
* - 利润根据 userType 动态计算
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* const result = await bundleMultiSwap({
|
|
113
|
+
* mainPrivateKey: '0x...', // Payer 支付 Gas
|
|
114
|
+
* sellerPrivateKeys: ['0x...', '0x...'],
|
|
115
|
+
* buyerPrivateKeys: ['0x...', '0x...'],
|
|
116
|
+
* totalBuyAmount: '0.1', // 总买入 0.1 OKB
|
|
117
|
+
* tokenAddress: '0x...',
|
|
118
|
+
* tradeType: 'V3',
|
|
119
|
+
* userType: 'v0',
|
|
120
|
+
* });
|
|
121
|
+
*/
|
|
122
|
+
export declare function bundleMultiSwap(params: BundleMultiSwapParams): Promise<BundleMultiSwapResult>;
|