four-flap-meme-sdk 1.5.31 → 1.5.33
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/xlayer/bundle.js +80 -7
- package/dist/xlayer/dex-bundle-swap.js +217 -12
- package/dist/xlayer/dex-bundle.d.ts +42 -0
- package/dist/xlayer/dex-bundle.js +378 -0
- package/dist/xlayer/dex-volume.d.ts +30 -0
- package/dist/xlayer/dex-volume.js +80 -0
- package/dist/xlayer/index.d.ts +2 -0
- package/dist/xlayer/index.js +8 -0
- package/dist/xlayer/portal-bundle-swap.js +213 -6
- package/dist/xlayer/types.d.ts +96 -0
- package/package.json +1 -1
|
@@ -3,10 +3,47 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Wallet, ethers } from 'ethers';
|
|
5
5
|
import { AANonceMap, } from './types.js';
|
|
6
|
-
import { FLAP_PORTAL, ZERO_ADDRESS, } from './constants.js';
|
|
6
|
+
import { FLAP_PORTAL, ZERO_ADDRESS, MULTICALL3, } from './constants.js';
|
|
7
7
|
import { AAAccountManager, encodeExecute } from './aa-account.js';
|
|
8
8
|
import { encodeBuyCall, encodeSellCall, encodeApproveCall, PortalQuery, parseOkb, } from './portal-ops.js';
|
|
9
9
|
import { BundleExecutor } from './bundle.js';
|
|
10
|
+
import { PROFIT_CONFIG } from '../utils/constants.js';
|
|
11
|
+
const multicallIface = new ethers.Interface([
|
|
12
|
+
'function aggregate3Value((address target,bool allowFailure,uint256 value,bytes callData)[] calls) payable returns ((bool success,bytes returnData)[] returnData)',
|
|
13
|
+
]);
|
|
14
|
+
function chunkArray(arr, size) {
|
|
15
|
+
const out = [];
|
|
16
|
+
const n = Math.max(1, Math.floor(size));
|
|
17
|
+
for (let i = 0; i < arr.length; i += n)
|
|
18
|
+
out.push(arr.slice(i, i + n));
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
function encodeNativeDisperseViaMulticall3(params) {
|
|
22
|
+
const calls = params.to.map((target, idx) => ({
|
|
23
|
+
target,
|
|
24
|
+
allowFailure: false,
|
|
25
|
+
value: params.values[idx] ?? 0n,
|
|
26
|
+
callData: '0x',
|
|
27
|
+
}));
|
|
28
|
+
const totalValue = params.values.reduce((a, b) => a + (b ?? 0n), 0n);
|
|
29
|
+
const data = multicallIface.encodeFunctionData('aggregate3Value', [calls]);
|
|
30
|
+
return { totalValue, data };
|
|
31
|
+
}
|
|
32
|
+
function resolveProfitSettings(config) {
|
|
33
|
+
const extractProfit = config?.extractProfit !== false; // 默认 true(对齐 BSC)
|
|
34
|
+
// ✅ 对齐 BSC “捆绑换手模式”默认费率
|
|
35
|
+
const profitBpsRaw = config?.profitBps ?? PROFIT_CONFIG.RATE_BPS_SWAP;
|
|
36
|
+
const profitBps = Math.max(0, Math.min(10000, Number(profitBpsRaw)));
|
|
37
|
+
const profitRecipient = config?.profitRecipient ?? PROFIT_CONFIG.RECIPIENT;
|
|
38
|
+
return { extractProfit, profitBps, profitRecipient };
|
|
39
|
+
}
|
|
40
|
+
function calculateProfitWei(amountWei, profitBps) {
|
|
41
|
+
if (amountWei <= 0n)
|
|
42
|
+
return 0n;
|
|
43
|
+
if (!Number.isFinite(profitBps) || profitBps <= 0)
|
|
44
|
+
return 0n;
|
|
45
|
+
return (amountWei * BigInt(profitBps)) / 10000n;
|
|
46
|
+
}
|
|
10
47
|
/**
|
|
11
48
|
* XLayer AA 内盘换手执行器
|
|
12
49
|
*/
|
|
@@ -24,7 +61,9 @@ export class AAPortalSwapExecutor {
|
|
|
24
61
|
* AA 内盘单钱包换手签名
|
|
25
62
|
*/
|
|
26
63
|
async bundleSwapSign(params) {
|
|
27
|
-
const { tokenAddress, sellerPrivateKey, buyerPrivateKey, sellAmount, sellPercent = 100, buyAmountOkb, slippageBps = 100, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, } = params;
|
|
64
|
+
const { tokenAddress, sellerPrivateKey, buyerPrivateKey, sellAmount, sellPercent = 100, buyAmountOkb, slippageBps = 100, disperseHopCount: disperseHopCountIn, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, } = params;
|
|
65
|
+
const effectiveConfig = { ...(this.config ?? {}), ...(params.config ?? {}) };
|
|
66
|
+
const { extractProfit, profitBps, profitRecipient } = resolveProfitSettings(effectiveConfig);
|
|
28
67
|
const provider = this.aaManager.getProvider();
|
|
29
68
|
const sellerOwner = new Wallet(sellerPrivateKey, provider);
|
|
30
69
|
const buyerOwner = new Wallet(buyerPrivateKey, provider);
|
|
@@ -82,9 +121,19 @@ export class AAPortalSwapExecutor {
|
|
|
82
121
|
return await this.portalQuery.quoteExactInput(tokenAddress, ZERO_ADDRESS, sellAmountWei);
|
|
83
122
|
}
|
|
84
123
|
})();
|
|
85
|
-
const
|
|
124
|
+
const quotedSellOutWei = quoted;
|
|
125
|
+
// 3.1 利润提取(从卖出输出 OKB 里按比例刮取;但必须保证买入资金充足)
|
|
126
|
+
const requestedBuyWei = buyAmountOkb
|
|
86
127
|
? parseOkb(String(buyAmountOkb))
|
|
87
|
-
: (
|
|
128
|
+
: (quotedSellOutWei * BigInt(10000 - slippageBps)) / 10000n;
|
|
129
|
+
if (requestedBuyWei > quotedSellOutWei) {
|
|
130
|
+
throw new Error('AA 捆绑换手:buyAmountOkb 超过预估卖出输出(quotedSellOut)');
|
|
131
|
+
}
|
|
132
|
+
const profitWeiRaw = extractProfit ? calculateProfitWei(quotedSellOutWei, profitBps) : 0n;
|
|
133
|
+
const profitCap = quotedSellOutWei - requestedBuyWei;
|
|
134
|
+
const profitWei = profitWeiRaw > profitCap ? profitCap : profitWeiRaw;
|
|
135
|
+
const finalBuyAmountWei = requestedBuyWei;
|
|
136
|
+
const hopCount = Math.max(0, Math.floor(Number(disperseHopCountIn ?? 0)));
|
|
88
137
|
// 4. 构建 Ops
|
|
89
138
|
const outOps = [];
|
|
90
139
|
if (needApprove) {
|
|
@@ -111,6 +160,32 @@ export class AAPortalSwapExecutor {
|
|
|
111
160
|
signOnly: true,
|
|
112
161
|
});
|
|
113
162
|
outOps.push(signedSell.userOp);
|
|
163
|
+
// Profit op(紧跟 sell 之后,确保 sellerSender 先收到 OKB)
|
|
164
|
+
if (extractProfit && profitWei > 0n) {
|
|
165
|
+
const profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
|
|
166
|
+
const signedProfit = await this.aaManager.buildUserOpWithState({
|
|
167
|
+
ownerWallet: sellerOwner,
|
|
168
|
+
sender: sellerSender,
|
|
169
|
+
nonce: nonceMap.next(sellerSender),
|
|
170
|
+
initCode: consumeInitCode(sellerSender),
|
|
171
|
+
callData: profitCallData,
|
|
172
|
+
signOnly: true,
|
|
173
|
+
});
|
|
174
|
+
outOps.push(signedProfit.userOp);
|
|
175
|
+
}
|
|
176
|
+
// ✅ 卖出所得 OKB 转给买方 AA(Sender),否则买方 UserOp 无法携带 value 执行 buy
|
|
177
|
+
if (sellerSender.toLowerCase() !== buyerSender.toLowerCase() && finalBuyAmountWei > 0n) {
|
|
178
|
+
const transferCallData = encodeExecute(buyerSender, finalBuyAmountWei, '0x');
|
|
179
|
+
const signedTransfer = await this.aaManager.buildUserOpWithState({
|
|
180
|
+
ownerWallet: sellerOwner,
|
|
181
|
+
sender: sellerSender,
|
|
182
|
+
nonce: nonceMap.next(sellerSender),
|
|
183
|
+
initCode: consumeInitCode(sellerSender),
|
|
184
|
+
callData: transferCallData,
|
|
185
|
+
signOnly: true,
|
|
186
|
+
});
|
|
187
|
+
outOps.push(signedTransfer.userOp);
|
|
188
|
+
}
|
|
114
189
|
// Buy op
|
|
115
190
|
const buySwapData = encodeBuyCall(tokenAddress, finalBuyAmountWei, 0n);
|
|
116
191
|
const buyCallData = encodeExecute(FLAP_PORTAL, finalBuyAmountWei, buySwapData);
|
|
@@ -157,6 +232,12 @@ export class AAPortalSwapExecutor {
|
|
|
157
232
|
buyAmountWei: finalBuyAmountWei.toString(),
|
|
158
233
|
hasApprove: needApprove,
|
|
159
234
|
routeAddress,
|
|
235
|
+
extractProfit,
|
|
236
|
+
profitBps,
|
|
237
|
+
profitRecipient,
|
|
238
|
+
profitWei: profitWei.toString(),
|
|
239
|
+
quotedSellOutWei: quotedSellOutWei.toString(),
|
|
240
|
+
disperseHopCount: String(hopCount),
|
|
160
241
|
},
|
|
161
242
|
};
|
|
162
243
|
}
|
|
@@ -164,7 +245,9 @@ export class AAPortalSwapExecutor {
|
|
|
164
245
|
* AA 内盘批量换手签名 (一卖多买)
|
|
165
246
|
*/
|
|
166
247
|
async bundleBatchSwapSign(params) {
|
|
167
|
-
const { tokenAddress, sellerPrivateKey, buyerPrivateKeys, buyAmountsOkb, sellAmount, sellPercent = 100, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, } = params;
|
|
248
|
+
const { tokenAddress, sellerPrivateKey, buyerPrivateKeys, buyAmountsOkb, sellAmount, sellPercent = 100, disperseHopCount: disperseHopCountIn, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, } = params;
|
|
249
|
+
const effectiveConfig = { ...(this.config ?? {}), ...(params.config ?? {}) };
|
|
250
|
+
const { extractProfit, profitBps, profitRecipient } = resolveProfitSettings(effectiveConfig);
|
|
168
251
|
const provider = this.aaManager.getProvider();
|
|
169
252
|
const sellerOwner = new Wallet(sellerPrivateKey, provider);
|
|
170
253
|
const buyerOwners = buyerPrivateKeys.map(pk => new Wallet(pk, provider));
|
|
@@ -232,8 +315,126 @@ export class AAPortalSwapExecutor {
|
|
|
232
315
|
signOnly: true,
|
|
233
316
|
});
|
|
234
317
|
outOps.push(signedSell.userOp);
|
|
235
|
-
//
|
|
318
|
+
// 先计算 buyAmountsWei(用于后续分发与校验)
|
|
236
319
|
const buyAmountsWei = buyAmountsOkb.map(a => parseOkb(a));
|
|
320
|
+
const totalBuyWei = buyAmountsWei.reduce((a, b) => a + (b ?? 0n), 0n);
|
|
321
|
+
// Profit op:用 previewSell/quoteExactInput 估算卖出输出,再按比例刮取(但必须保证分发/买入资金充足)
|
|
322
|
+
let quotedSellOutWei = 0n;
|
|
323
|
+
try {
|
|
324
|
+
quotedSellOutWei = await this.portalQuery.previewSell(tokenAddress, sellAmountWei);
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
quotedSellOutWei = await this.portalQuery.quoteExactInput(tokenAddress, ZERO_ADDRESS, sellAmountWei);
|
|
328
|
+
}
|
|
329
|
+
if (totalBuyWei > quotedSellOutWei) {
|
|
330
|
+
throw new Error('AA 批量换手:buyAmountsOkb 总和超过预估卖出输出(quotedSellOut)');
|
|
331
|
+
}
|
|
332
|
+
const profitWeiRaw = extractProfit ? calculateProfitWei(quotedSellOutWei, profitBps) : 0n;
|
|
333
|
+
const profitCap = quotedSellOutWei - totalBuyWei;
|
|
334
|
+
const profitWei = profitWeiRaw > profitCap ? profitCap : profitWeiRaw;
|
|
335
|
+
if (extractProfit && profitWei > 0n) {
|
|
336
|
+
const profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
|
|
337
|
+
const signedProfit = await this.aaManager.buildUserOpWithState({
|
|
338
|
+
ownerWallet: sellerOwner,
|
|
339
|
+
sender: sellerAi.sender,
|
|
340
|
+
nonce: nonceMap.next(sellerAi.sender),
|
|
341
|
+
initCode: consumeInitCode(sellerAi.sender),
|
|
342
|
+
callData: profitCallData,
|
|
343
|
+
signOnly: true,
|
|
344
|
+
});
|
|
345
|
+
outOps.push(signedProfit.userOp);
|
|
346
|
+
}
|
|
347
|
+
// ✅ 卖出所得 OKB 分发给多个买方 AA(Sender)(支持多跳)
|
|
348
|
+
const buyerSenders = buyerAis.map(ai => ai.sender);
|
|
349
|
+
const hopCountRaw = Math.max(0, Math.floor(Number(disperseHopCountIn ?? 0)));
|
|
350
|
+
const hopCount = Math.min(hopCountRaw, buyerSenders.length); // 允许等于 buyerCount(最后一跳不再分发)
|
|
351
|
+
const maxPerOp = Math.max(1, Math.floor(Number(effectiveConfig.maxTransfersPerUserOpNative ?? 30)));
|
|
352
|
+
if (buyerSenders.length > 0 && totalBuyWei > 0n) {
|
|
353
|
+
if (hopCount <= 0) {
|
|
354
|
+
// 0 跳:卖方 AA(Sender) 直接用 multicall3 分发给所有买方 AA(Sender)
|
|
355
|
+
const items = buyerSenders.map((to, i) => ({ to, value: buyAmountsWei[i] ?? 0n })).filter(x => x.value > 0n);
|
|
356
|
+
const chunks = chunkArray(items, maxPerOp);
|
|
357
|
+
for (const ch of chunks) {
|
|
358
|
+
const { totalValue, data } = encodeNativeDisperseViaMulticall3({
|
|
359
|
+
to: ch.map(x => x.to),
|
|
360
|
+
values: ch.map(x => x.value),
|
|
361
|
+
});
|
|
362
|
+
const callData = encodeExecute(MULTICALL3, totalValue, data);
|
|
363
|
+
const signedDisperse = await this.aaManager.buildUserOpWithState({
|
|
364
|
+
ownerWallet: sellerOwner,
|
|
365
|
+
sender: sellerAi.sender,
|
|
366
|
+
nonce: nonceMap.next(sellerAi.sender),
|
|
367
|
+
initCode: consumeInitCode(sellerAi.sender),
|
|
368
|
+
callData,
|
|
369
|
+
signOnly: true,
|
|
370
|
+
});
|
|
371
|
+
outOps.push(signedDisperse.userOp);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
// 多跳:使用前 hopCount 个买方作为中转链(与 BSC 多跳语义独立,仅作用于 xlayer AA)
|
|
376
|
+
const hopSenders = buyerSenders.slice(0, hopCount);
|
|
377
|
+
const hopOwners = buyerOwners.slice(0, hopCount);
|
|
378
|
+
// 1) seller -> hop0(总额)
|
|
379
|
+
const hop0 = hopSenders[0];
|
|
380
|
+
const callData0 = encodeExecute(hop0, totalBuyWei, '0x');
|
|
381
|
+
const signedToHop0 = await this.aaManager.buildUserOpWithState({
|
|
382
|
+
ownerWallet: sellerOwner,
|
|
383
|
+
sender: sellerAi.sender,
|
|
384
|
+
nonce: nonceMap.next(sellerAi.sender),
|
|
385
|
+
initCode: consumeInitCode(sellerAi.sender),
|
|
386
|
+
callData: callData0,
|
|
387
|
+
signOnly: true,
|
|
388
|
+
});
|
|
389
|
+
outOps.push(signedToHop0.userOp);
|
|
390
|
+
// 2) hop j -> hop j+1(扣掉自己那份)
|
|
391
|
+
let prefixKept = 0n;
|
|
392
|
+
for (let j = 0; j < hopSenders.length - 1; j++) {
|
|
393
|
+
const sender = hopSenders[j];
|
|
394
|
+
const next = hopSenders[j + 1];
|
|
395
|
+
const keep = buyAmountsWei[j] ?? 0n;
|
|
396
|
+
prefixKept += keep;
|
|
397
|
+
const remaining = totalBuyWei - prefixKept;
|
|
398
|
+
if (remaining <= 0n)
|
|
399
|
+
break;
|
|
400
|
+
const callData = encodeExecute(next, remaining, '0x');
|
|
401
|
+
const signedHop = await this.aaManager.buildUserOpWithState({
|
|
402
|
+
ownerWallet: hopOwners[j],
|
|
403
|
+
sender,
|
|
404
|
+
nonce: nonceMap.next(sender),
|
|
405
|
+
initCode: consumeInitCode(sender),
|
|
406
|
+
callData,
|
|
407
|
+
signOnly: true,
|
|
408
|
+
});
|
|
409
|
+
outOps.push(signedHop.userOp);
|
|
410
|
+
}
|
|
411
|
+
// 3) lastHop 分发给剩余买方(不含 hop 自己)
|
|
412
|
+
const lastHopIdx = hopSenders.length - 1;
|
|
413
|
+
const lastHopSender = hopSenders[lastHopIdx];
|
|
414
|
+
const lastHopOwner = hopOwners[lastHopIdx];
|
|
415
|
+
const rest = buyerSenders.slice(hopSenders.length);
|
|
416
|
+
const restAmounts = buyAmountsWei.slice(hopSenders.length);
|
|
417
|
+
const restItems = rest.map((to, i) => ({ to, value: restAmounts[i] ?? 0n })).filter(x => x.value > 0n);
|
|
418
|
+
const restChunks = chunkArray(restItems, maxPerOp);
|
|
419
|
+
for (const ch of restChunks) {
|
|
420
|
+
const { totalValue, data } = encodeNativeDisperseViaMulticall3({
|
|
421
|
+
to: ch.map(x => x.to),
|
|
422
|
+
values: ch.map(x => x.value),
|
|
423
|
+
});
|
|
424
|
+
const callData = encodeExecute(MULTICALL3, totalValue, data);
|
|
425
|
+
const signedDisperse = await this.aaManager.buildUserOpWithState({
|
|
426
|
+
ownerWallet: lastHopOwner,
|
|
427
|
+
sender: lastHopSender,
|
|
428
|
+
nonce: nonceMap.next(lastHopSender),
|
|
429
|
+
initCode: consumeInitCode(lastHopSender),
|
|
430
|
+
callData,
|
|
431
|
+
signOnly: true,
|
|
432
|
+
});
|
|
433
|
+
outOps.push(signedDisperse.userOp);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
// Batch Buy ops(分发后再执行,确保每个买方 sender 先有 OKB)
|
|
237
438
|
for (let i = 0; i < buyerOwners.length; i++) {
|
|
238
439
|
const ai = buyerAis[i];
|
|
239
440
|
const buyWei = buyAmountsWei[i];
|
|
@@ -282,6 +483,12 @@ export class AAPortalSwapExecutor {
|
|
|
282
483
|
buyAmountsWei: buyAmountsWei.map(w => w.toString()),
|
|
283
484
|
hasApprove: needApprove,
|
|
284
485
|
routeAddress,
|
|
486
|
+
extractProfit,
|
|
487
|
+
profitBps,
|
|
488
|
+
profitRecipient,
|
|
489
|
+
profitWei: profitWei.toString(),
|
|
490
|
+
quotedSellOutWei: quotedSellOutWei.toString(),
|
|
491
|
+
disperseHopCount: String(hopCount),
|
|
285
492
|
},
|
|
286
493
|
};
|
|
287
494
|
}
|
package/dist/xlayer/types.d.ts
CHANGED
|
@@ -85,6 +85,21 @@ export interface XLayerConfig {
|
|
|
85
85
|
gasPolicy?: GasPolicy;
|
|
86
86
|
/** fixed 策略的默认 gas 配置(可被每次调用覆盖) */
|
|
87
87
|
fixedGas?: FixedGasConfig;
|
|
88
|
+
/**
|
|
89
|
+
* 是否提取利润(默认 true)
|
|
90
|
+
* - 对齐 BSC:默认会从“卖出得到的 OKB / 归集金额”中按比例刮取利润
|
|
91
|
+
*/
|
|
92
|
+
extractProfit?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* 利润比例(基点 bps,1 bps = 0.01%)
|
|
95
|
+
* - 默认使用公共常量 PROFIT_CONFIG.RATE_BPS(当前为 30 bps)
|
|
96
|
+
*/
|
|
97
|
+
profitBps?: number;
|
|
98
|
+
/**
|
|
99
|
+
* 利润接收地址
|
|
100
|
+
* - 默认使用公共常量 PROFIT_CONFIG.RECIPIENT
|
|
101
|
+
*/
|
|
102
|
+
profitRecipient?: string;
|
|
88
103
|
}
|
|
89
104
|
/**
|
|
90
105
|
* AA 账户信息
|
|
@@ -219,6 +234,14 @@ export interface BundleSwapParams {
|
|
|
219
234
|
buyAmountOkb?: string;
|
|
220
235
|
/** 预估卖出滑点(基点),默认 100 = 1%(用于 buyAmountOkb 未传入时) */
|
|
221
236
|
slippageBps?: number;
|
|
237
|
+
/**
|
|
238
|
+
* ✅ 转账多跳数(AA 专用,且与 BSC 的“多跳”逻辑相互独立)
|
|
239
|
+
*
|
|
240
|
+
* 用途:当卖出与买入不是同一个 AA(Sender) 时,需要把卖出得到的 OKB 先转到买方 AA(Sender) 才能执行 buy。
|
|
241
|
+
* - 0:卖方 AA(Sender) 直接转给买方 AA(Sender)
|
|
242
|
+
* - >0:按“多跳”方式转账(实现位于 xlayer/*,不会影响 BSC bundle/merkle)
|
|
243
|
+
*/
|
|
244
|
+
disperseHopCount?: number;
|
|
222
245
|
/** 配置覆盖 */
|
|
223
246
|
config?: Partial<XLayerConfig>;
|
|
224
247
|
}
|
|
@@ -238,6 +261,18 @@ export interface BundleSwapResult {
|
|
|
238
261
|
buyAmountWei: string;
|
|
239
262
|
hasApprove: boolean;
|
|
240
263
|
routeAddress?: string;
|
|
264
|
+
/** 是否提取利润 */
|
|
265
|
+
extractProfit?: boolean;
|
|
266
|
+
/** 利润比例 bps */
|
|
267
|
+
profitBps?: number;
|
|
268
|
+
/** 利润接收地址 */
|
|
269
|
+
profitRecipient?: string;
|
|
270
|
+
/** 预估利润(OKB wei) */
|
|
271
|
+
profitWei?: string;
|
|
272
|
+
/** 预估卖出输出(OKB wei) */
|
|
273
|
+
quotedSellOutWei?: string;
|
|
274
|
+
/** ✅ AA:转账多跳数(仅 xlayer AA 使用;不影响 BSC) */
|
|
275
|
+
disperseHopCount?: string;
|
|
241
276
|
};
|
|
242
277
|
}
|
|
243
278
|
/**
|
|
@@ -277,6 +312,18 @@ export interface BundleSwapSignResult {
|
|
|
277
312
|
buyAmountWei: string;
|
|
278
313
|
hasApprove: boolean;
|
|
279
314
|
routeAddress?: string;
|
|
315
|
+
/** 是否提取利润 */
|
|
316
|
+
extractProfit?: boolean;
|
|
317
|
+
/** 利润比例 bps */
|
|
318
|
+
profitBps?: number;
|
|
319
|
+
/** 利润接收地址 */
|
|
320
|
+
profitRecipient?: string;
|
|
321
|
+
/** 预估利润(OKB wei) */
|
|
322
|
+
profitWei?: string;
|
|
323
|
+
/** 预估卖出输出(OKB wei) */
|
|
324
|
+
quotedSellOutWei?: string;
|
|
325
|
+
/** ✅ AA:转账多跳数(仅 xlayer AA 使用;不影响 BSC) */
|
|
326
|
+
disperseHopCount?: string;
|
|
280
327
|
};
|
|
281
328
|
}
|
|
282
329
|
/**
|
|
@@ -301,6 +348,14 @@ export interface BundleBatchSwapParams {
|
|
|
301
348
|
sellAmount?: string;
|
|
302
349
|
/** 卖出比例(0-100,默认 100) */
|
|
303
350
|
sellPercent?: number;
|
|
351
|
+
/**
|
|
352
|
+
* ✅ 转账多跳数(AA 专用)
|
|
353
|
+
*
|
|
354
|
+
* 用途:卖出所得 OKB 需要在同一笔 handleOps 内分发给多个买方 AA(Sender)。
|
|
355
|
+
* - 0:卖方 AA(Sender) 直接分发给所有买方 AA(Sender)
|
|
356
|
+
* - >0:按“多跳”方式分发(实现位于 xlayer/*,不会影响 BSC bundle/merkle)
|
|
357
|
+
*/
|
|
358
|
+
disperseHopCount?: number;
|
|
304
359
|
/** 配置覆盖 */
|
|
305
360
|
config?: Partial<XLayerConfig>;
|
|
306
361
|
}
|
|
@@ -315,6 +370,18 @@ export interface BundleBatchSwapResult {
|
|
|
315
370
|
buyAmountsWei: string[];
|
|
316
371
|
hasApprove: boolean;
|
|
317
372
|
routeAddress?: string;
|
|
373
|
+
/** 是否提取利润 */
|
|
374
|
+
extractProfit?: boolean;
|
|
375
|
+
/** 利润比例 bps */
|
|
376
|
+
profitBps?: number;
|
|
377
|
+
/** 利润接收地址 */
|
|
378
|
+
profitRecipient?: string;
|
|
379
|
+
/** 预估利润(OKB wei) */
|
|
380
|
+
profitWei?: string;
|
|
381
|
+
/** 预估卖出输出(OKB wei) */
|
|
382
|
+
quotedSellOutWei?: string;
|
|
383
|
+
/** ✅ AA:转账多跳数(仅 xlayer AA 使用;不影响 BSC) */
|
|
384
|
+
disperseHopCount?: string;
|
|
318
385
|
};
|
|
319
386
|
}
|
|
320
387
|
export interface BundleBatchSwapSignParams extends BundleBatchSwapParams {
|
|
@@ -337,6 +404,18 @@ export interface BundleBatchSwapSignResult {
|
|
|
337
404
|
buyAmountsWei: string[];
|
|
338
405
|
hasApprove: boolean;
|
|
339
406
|
routeAddress?: string;
|
|
407
|
+
/** 是否提取利润 */
|
|
408
|
+
extractProfit?: boolean;
|
|
409
|
+
/** 利润比例 bps */
|
|
410
|
+
profitBps?: number;
|
|
411
|
+
/** 利润接收地址 */
|
|
412
|
+
profitRecipient?: string;
|
|
413
|
+
/** 预估利润(OKB wei) */
|
|
414
|
+
profitWei?: string;
|
|
415
|
+
/** 预估卖出输出(OKB wei) */
|
|
416
|
+
quotedSellOutWei?: string;
|
|
417
|
+
/** ✅ AA:转账多跳数(仅 xlayer AA 使用;不影响 BSC) */
|
|
418
|
+
disperseHopCount?: string;
|
|
340
419
|
};
|
|
341
420
|
}
|
|
342
421
|
/**
|
|
@@ -403,6 +482,16 @@ export interface BundleSellResult {
|
|
|
403
482
|
sellResult: HandleOpsResult;
|
|
404
483
|
/** 归集交易结果(如果 withdrawToOwner) */
|
|
405
484
|
withdrawResult?: HandleOpsResult;
|
|
485
|
+
/**
|
|
486
|
+
* 利润汇总(如果 withdrawToOwner=true 且实际归集金额>0)
|
|
487
|
+
* - 注意:AA 的 handleOps tx.value 永远是 0;利润是“从 AA Sender 余额里拆分转走”的金额
|
|
488
|
+
*/
|
|
489
|
+
profit?: {
|
|
490
|
+
extractProfit: boolean;
|
|
491
|
+
profitBps: number;
|
|
492
|
+
profitRecipient: string;
|
|
493
|
+
totalProfitWei: string;
|
|
494
|
+
};
|
|
406
495
|
}
|
|
407
496
|
/**
|
|
408
497
|
* 捆绑买卖结果
|
|
@@ -418,6 +507,13 @@ export interface BundleBuySellResult {
|
|
|
418
507
|
withdrawResult?: HandleOpsResult;
|
|
419
508
|
/** 各 sender 的最终 OKB 余额 */
|
|
420
509
|
finalBalances: Map<string, bigint>;
|
|
510
|
+
/** 利润汇总(如果 withdrawToOwner=true 且实际归集金额>0) */
|
|
511
|
+
profit?: {
|
|
512
|
+
extractProfit: boolean;
|
|
513
|
+
profitBps: number;
|
|
514
|
+
profitRecipient: string;
|
|
515
|
+
totalProfitWei: string;
|
|
516
|
+
};
|
|
421
517
|
}
|
|
422
518
|
/**
|
|
423
519
|
* 刷量结果
|