four-flap-meme-sdk 1.6.8 → 1.6.10

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.
@@ -36,15 +36,9 @@ export declare class AAAccountManager {
36
36
  private deployedSenderSet;
37
37
  private feeDataCache?;
38
38
  private readonly feeDataCacheTtlMs;
39
- private entryPointSynced;
40
39
  private defaultGasPolicy?;
41
40
  private defaultFixedGas?;
42
41
  constructor(config?: XLayerConfig);
43
- /**
44
- * ✅ 同步 EntryPoint(带缓存,避免重复 RPC 调用)
45
- *
46
- * 优化:EntryPoint 地址在运行期间几乎不会变化,只需同步一次
47
- */
48
42
  private syncEntryPointIfNeeded;
49
43
  /**
50
44
  * 获取 Provider
@@ -29,8 +29,6 @@ export class AAAccountManager {
29
29
  // PERF: 本文件的改造会尽量减少逐地址 RPC 调用
30
30
  this.deployedSenderSet = new Set(); // key: senderLower(只缓存 deployed=true)
31
31
  this.feeDataCacheTtlMs = 1200;
32
- // ✅ 优化:缓存 EntryPoint 同步状态,避免重复 RPC 调用
33
- this.entryPointSynced = false;
34
32
  this.chainId = config.chainId ?? XLAYER_CHAIN_ID;
35
33
  const rpcUrl = config.rpcUrl ?? DEFAULT_RPC_URL;
36
34
  this.rpcUrl = rpcUrl;
@@ -57,15 +55,7 @@ export class AAAccountManager {
57
55
  timeoutMs: config.timeoutMs,
58
56
  });
59
57
  }
60
- /**
61
- * ✅ 同步 EntryPoint(带缓存,避免重复 RPC 调用)
62
- *
63
- * 优化:EntryPoint 地址在运行期间几乎不会变化,只需同步一次
64
- */
65
58
  async syncEntryPointIfNeeded() {
66
- // ✅ 如果已同步过,直接返回(避免重复 RPC 调用)
67
- if (this.entryPointSynced)
68
- return;
69
59
  try {
70
60
  const eps = await this.bundler.getSupportedEntryPoints();
71
61
  if (Array.isArray(eps) && eps.length > 0) {
@@ -76,8 +66,6 @@ export class AAAccountManager {
76
66
  this.bundler.setEntryPoint(this.entryPointAddress);
77
67
  }
78
68
  }
79
- // ✅ 标记为已同步
80
- this.entryPointSynced = true;
81
69
  }
82
70
  catch { }
83
71
  }
@@ -0,0 +1,48 @@
1
+ import type { XLayerConfig, UserOperation } from './types.js';
2
+ /**
3
+ * ✅ XLayer AA:单一 owner 的 AA(Sender) 批量分发(SDK 安全版,内置利润)
4
+ * - native: execute(MULTICALL3, totalValue, aggregate3Value([...to + profitRecipient]))
5
+ * - erc20: execute(MULTICALL3, 0, aggregate3([...transfer(to) + transfer(profitRecipient)]))
6
+ *
7
+ * 安全:利润比例与接收者硬编码在 SDK 内部(PROFIT_CONFIG)。
8
+ * 规则:利润从“总分发金额”中扣除,不额外增加资金需求。
9
+ */
10
+ export declare function buildDisperseFromSingleOwnerOpsWithProfit(params: {
11
+ kind: 'native' | 'erc20';
12
+ tokenAddress?: string;
13
+ tokenDecimals?: number;
14
+ ownerPrivateKey: string;
15
+ toAddresses: string[];
16
+ amounts: string[];
17
+ config?: Partial<XLayerConfig>;
18
+ senderAddress?: string;
19
+ startNonce?: bigint;
20
+ assumeDeployed?: boolean;
21
+ maxTransfersPerUserOp?: number;
22
+ }): Promise<{
23
+ ops: UserOperation[];
24
+ sender: string;
25
+ profitWei: bigint;
26
+ }>;
27
+ /**
28
+ * ✅ XLayer AA:多 owner 归集/转账(SDK 安全版,内置利润)
29
+ *
30
+ * 每个 owner 的 AA(Sender) 内部用 executeBatch 同时转账:
31
+ * - native:profitRecipient + toAddress(value 拆分)
32
+ * - erc20:token.transfer(profitRecipient) + token.transfer(toAddress)
33
+ *
34
+ * 安全:利润配置硬编码在 SDK 内部(PROFIT_CONFIG)。
35
+ */
36
+ export declare function buildTransfersWithProfit(params: {
37
+ kind: 'native' | 'erc20';
38
+ tokenAddress?: string;
39
+ tokenDecimals?: number;
40
+ ownerPrivateKeys: string[];
41
+ toAddresses: string[];
42
+ amounts: string[];
43
+ config?: Partial<XLayerConfig>;
44
+ }): Promise<{
45
+ ops: UserOperation[];
46
+ senders: string[];
47
+ profitWei: bigint;
48
+ }>;
@@ -0,0 +1,304 @@
1
+ import { ethers } from 'ethers';
2
+ import { PROFIT_CONFIG } from '../utils/constants.js';
3
+ import { createAAAccountManager, createWallet, encodeExecute, encodeExecuteBatch } from './aa-account.js';
4
+ const MULTICALL3 = '0xca11bde05977b3631167028862be2a173976ca11';
5
+ function clampBps(bps) {
6
+ if (!Number.isFinite(bps))
7
+ return 0;
8
+ return Math.max(0, Math.min(10000, Math.floor(bps)));
9
+ }
10
+ function calcProfitWei(amountWei, bps) {
11
+ if (amountWei <= 0n)
12
+ return 0n;
13
+ const x = clampBps(bps);
14
+ if (x <= 0)
15
+ return 0n;
16
+ return (amountWei * BigInt(x)) / 10000n;
17
+ }
18
+ /**
19
+ * ✅ XLayer AA:单一 owner 的 AA(Sender) 批量分发(SDK 安全版,内置利润)
20
+ * - native: execute(MULTICALL3, totalValue, aggregate3Value([...to + profitRecipient]))
21
+ * - erc20: execute(MULTICALL3, 0, aggregate3([...transfer(to) + transfer(profitRecipient)]))
22
+ *
23
+ * 安全:利润比例与接收者硬编码在 SDK 内部(PROFIT_CONFIG)。
24
+ * 规则:利润从“总分发金额”中扣除,不额外增加资金需求。
25
+ */
26
+ export async function buildDisperseFromSingleOwnerOpsWithProfit(params) {
27
+ const effConfig = { ...(params.config ?? {}) };
28
+ const aaManager = createAAAccountManager(effConfig);
29
+ const provider = aaManager.getProvider();
30
+ const ownerWallet = createWallet(String(params.ownerPrivateKey), effConfig);
31
+ const toList = (params.toAddresses || []).map((a) => String(a || '').trim()).filter(Boolean);
32
+ const amtList = (params.amounts || []).map((a) => String(a || '').trim());
33
+ if (toList.length === 0)
34
+ return { ops: [], sender: '', profitWei: 0n };
35
+ if (toList.length !== amtList.length)
36
+ throw new Error('AA disperse:toAddresses 与 amounts 数量不一致');
37
+ for (const to of toList) {
38
+ if (!/^0x[a-fA-F0-9]{40}$/.test(to))
39
+ throw new Error(`AA disperse:to 地址不合法: ${to}`);
40
+ }
41
+ const hinted = String(params.senderAddress || '').trim();
42
+ const sender = hinted && /^0x[a-fA-F0-9]{40}$/.test(hinted)
43
+ ? hinted
44
+ : await aaManager.predictSenderAddress(ownerWallet.address);
45
+ const entryPoint = aaManager.getEntryPoint?.() || aaManager.entryPoint;
46
+ if (!entryPoint)
47
+ throw new Error('AA disperse:无法获取 EntryPoint 合约实例');
48
+ const hasStartNonce = typeof params.startNonce === 'bigint';
49
+ const [nonce0Raw, code] = await Promise.all([
50
+ hasStartNonce ? Promise.resolve(params.startNonce) : entryPoint.getNonce(sender, 0),
51
+ provider.getCode(sender),
52
+ ]);
53
+ const onchainDeployed = code != null && String(code) !== '0x';
54
+ const deployed0 = hasStartNonce ? (params.assumeDeployed ?? true) : onchainDeployed;
55
+ const initCode0 = deployed0 ? '0x' : aaManager.generateInitCode(ownerWallet.address);
56
+ const nonce0 = BigInt(nonce0Raw);
57
+ const multicallIface = new ethers.Interface([
58
+ 'function aggregate3((address target,bool allowFailure,bytes callData)[] calls) payable returns ((bool success,bytes returnData)[] returnData)',
59
+ 'function aggregate3Value((address target,bool allowFailure,uint256 value,bytes callData)[] calls) payable returns ((bool success,bytes returnData)[] returnData)',
60
+ ]);
61
+ const erc20Iface = new ethers.Interface([
62
+ 'function transfer(address to, uint256 amount) returns (bool)',
63
+ ]);
64
+ // 计算总金额与利润(从总额中扣除)
65
+ let totalWei = 0n;
66
+ if (params.kind === 'native') {
67
+ const values = amtList.map((x) => {
68
+ const v = ethers.parseEther(String(x || '0'));
69
+ return v > 0n ? v : 0n;
70
+ });
71
+ totalWei = values.reduce((a, b) => a + b, 0n);
72
+ }
73
+ else {
74
+ const token = String(params.tokenAddress || '').trim();
75
+ const dec = Number(params.tokenDecimals);
76
+ if (!token || !/^0x[a-fA-F0-9]{40}$/.test(token))
77
+ throw new Error('AA disperse:tokenAddress 不合法');
78
+ if (!Number.isFinite(dec) || dec < 0)
79
+ throw new Error('AA disperse:tokenDecimals 不合法');
80
+ const values = amtList.map((x) => {
81
+ const v = ethers.parseUnits(String(x || '0'), dec);
82
+ return v > 0n ? v : 0n;
83
+ });
84
+ totalWei = values.reduce((a, b) => a + b, 0n);
85
+ }
86
+ const profitWei = calcProfitWei(totalWei, PROFIT_CONFIG.RATE_BPS);
87
+ const distributableWei = totalWei > profitWei ? (totalWei - profitWei) : 0n;
88
+ // 按比例缩放每个收款金额,使“总分发=总额-利润”;利润单独转给 recipient
89
+ const scaled = [];
90
+ if (totalWei > 0n && distributableWei > 0n) {
91
+ if (params.kind === 'native') {
92
+ const raw = amtList.map((x) => {
93
+ const v = ethers.parseEther(String(x || '0'));
94
+ return v > 0n ? v : 0n;
95
+ });
96
+ let acc = 0n;
97
+ for (let i = 0; i < raw.length; i++) {
98
+ const v = raw[i];
99
+ const out = (v * distributableWei) / totalWei;
100
+ scaled.push(out);
101
+ acc += out;
102
+ }
103
+ // 把余数补到最后一个非 0 位置
104
+ const rem = distributableWei - acc;
105
+ if (rem > 0n) {
106
+ for (let i = scaled.length - 1; i >= 0; i--) {
107
+ if (scaled[i] > 0n || raw[i] > 0n) {
108
+ scaled[i] = scaled[i] + rem;
109
+ break;
110
+ }
111
+ }
112
+ }
113
+ }
114
+ else {
115
+ const dec = Number(params.tokenDecimals);
116
+ const raw = amtList.map((x) => {
117
+ const v = ethers.parseUnits(String(x || '0'), dec);
118
+ return v > 0n ? v : 0n;
119
+ });
120
+ let acc = 0n;
121
+ for (let i = 0; i < raw.length; i++) {
122
+ const v = raw[i];
123
+ const out = (v * distributableWei) / totalWei;
124
+ scaled.push(out);
125
+ acc += out;
126
+ }
127
+ const rem = distributableWei - acc;
128
+ if (rem > 0n) {
129
+ for (let i = scaled.length - 1; i >= 0; i--) {
130
+ if (scaled[i] > 0n || raw[i] > 0n) {
131
+ scaled[i] = scaled[i] + rem;
132
+ break;
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ else {
139
+ // 无法分发(全为 0 或利润>=总额)
140
+ for (let i = 0; i < amtList.length; i++)
141
+ scaled.push(0n);
142
+ }
143
+ const maxPerOp = Math.max(1, Math.floor(Number(params.maxTransfersPerUserOp ?? (params.kind === 'native' ? 30 : 20))));
144
+ const items = toList.map((to, i) => ({ to, amountWei: scaled[i] ?? 0n }))
145
+ .filter((x) => x.amountWei > 0n);
146
+ if (profitWei > 0n) {
147
+ items.push({ to: PROFIT_CONFIG.RECIPIENT, amountWei: profitWei });
148
+ }
149
+ const chunks = [];
150
+ for (let i = 0; i < items.length; i += maxPerOp)
151
+ chunks.push(items.slice(i, i + maxPerOp));
152
+ const fnFixed = aaManager.buildUserOpWithFixedGas;
153
+ if (typeof fnFixed !== 'function')
154
+ throw new Error('AA disperse:SDK 不支持 buildUserOpWithFixedGas');
155
+ const ops = [];
156
+ for (let i = 0; i < chunks.length; i++) {
157
+ const list = chunks[i];
158
+ if (params.kind === 'native') {
159
+ const calls = list.map((it) => ({
160
+ target: it.to,
161
+ allowFailure: false,
162
+ value: it.amountWei,
163
+ callData: '0x',
164
+ }));
165
+ const totalValue = list.reduce((a, b) => a + b.amountWei, 0n);
166
+ const mcData = multicallIface.encodeFunctionData('aggregate3Value', [calls]);
167
+ const callData = encodeExecute(MULTICALL3, totalValue, mcData);
168
+ const nonce = nonce0 + BigInt(i);
169
+ const initCode = i === 0 ? String(initCode0) : '0x';
170
+ const deployed = i === 0 ? deployed0 : true;
171
+ const base = 180000n;
172
+ const per = 65000n;
173
+ const g = base + per * BigInt(calls.length);
174
+ const callGasLimit = g > 4500000n ? 4500000n : g;
175
+ const built = await fnFixed.call(aaManager, {
176
+ ownerWallet,
177
+ sender,
178
+ callData,
179
+ nonce,
180
+ initCode,
181
+ deployed,
182
+ fixedGas: { callGasLimit },
183
+ });
184
+ const signed = await aaManager.signUserOp(built.userOp, ownerWallet);
185
+ ops.push(signed.userOp);
186
+ }
187
+ else {
188
+ const token = String(params.tokenAddress || '').trim();
189
+ const calls = list.map((it) => ({
190
+ target: token,
191
+ allowFailure: false,
192
+ callData: erc20Iface.encodeFunctionData('transfer', [it.to, it.amountWei]),
193
+ }));
194
+ const mcData = multicallIface.encodeFunctionData('aggregate3', [calls]);
195
+ const callData = encodeExecute(MULTICALL3, 0n, mcData);
196
+ const nonce = nonce0 + BigInt(i);
197
+ const initCode = i === 0 ? String(initCode0) : '0x';
198
+ const deployed = i === 0 ? deployed0 : true;
199
+ const base = 220000n;
200
+ const per = 85000n;
201
+ const g = base + per * BigInt(calls.length);
202
+ const callGasLimit = g > 4500000n ? 4500000n : g;
203
+ const built = await fnFixed.call(aaManager, {
204
+ ownerWallet,
205
+ sender,
206
+ callData,
207
+ nonce,
208
+ initCode,
209
+ deployed,
210
+ fixedGas: { callGasLimit },
211
+ });
212
+ const signed = await aaManager.signUserOp(built.userOp, ownerWallet);
213
+ ops.push(signed.userOp);
214
+ }
215
+ }
216
+ return { ops, sender, profitWei };
217
+ }
218
+ /**
219
+ * ✅ XLayer AA:多 owner 归集/转账(SDK 安全版,内置利润)
220
+ *
221
+ * 每个 owner 的 AA(Sender) 内部用 executeBatch 同时转账:
222
+ * - native:profitRecipient + toAddress(value 拆分)
223
+ * - erc20:token.transfer(profitRecipient) + token.transfer(toAddress)
224
+ *
225
+ * 安全:利润配置硬编码在 SDK 内部(PROFIT_CONFIG)。
226
+ */
227
+ export async function buildTransfersWithProfit(params) {
228
+ const effConfig = { ...(params.config ?? {}) };
229
+ const aaManager = createAAAccountManager(effConfig);
230
+ if (params.ownerPrivateKeys.length !== params.toAddresses.length || params.ownerPrivateKeys.length !== params.amounts.length) {
231
+ throw new Error('AA transfer:私钥数量与目标地址/数量不一致');
232
+ }
233
+ const ownerWallets = params.ownerPrivateKeys.map((pk) => createWallet(String(pk), effConfig));
234
+ const owners = ownerWallets.map((w) => w.address);
235
+ const infos = await aaManager.getMultipleAccountInfo(owners);
236
+ const senders = infos.map((x) => String(x?.sender || ''));
237
+ const erc20Iface = new ethers.Interface(['function transfer(address to, uint256 amount) returns (bool)']);
238
+ let totalProfitWei = 0n;
239
+ const unsigned = [];
240
+ const opOwnerIndex = [];
241
+ for (let i = 0; i < ownerWallets.length; i++) {
242
+ const w = ownerWallets[i];
243
+ const ai = infos[i];
244
+ const sender = senders[i];
245
+ const to = String(params.toAddresses[i] || '').trim();
246
+ if (!/^0x[a-fA-F0-9]{40}$/.test(to))
247
+ throw new Error(`AA transfer:to 地址不合法: ${to}`);
248
+ let amountWei = 0n;
249
+ if (params.kind === 'native') {
250
+ amountWei = ethers.parseEther(String(params.amounts[i] || '0'));
251
+ }
252
+ else {
253
+ const token = String(params.tokenAddress || '').trim();
254
+ const dec = Number(params.tokenDecimals);
255
+ if (!token || !/^0x[a-fA-F0-9]{40}$/.test(token))
256
+ throw new Error('AA transfer:tokenAddress 不合法');
257
+ if (!Number.isFinite(dec) || dec < 0)
258
+ throw new Error('AA transfer:tokenDecimals 不合法');
259
+ amountWei = ethers.parseUnits(String(params.amounts[i] || '0'), dec);
260
+ }
261
+ if (amountWei <= 0n)
262
+ continue;
263
+ const profitWei = calcProfitWei(amountWei, PROFIT_CONFIG.RATE_BPS);
264
+ const toWei = amountWei - profitWei;
265
+ totalProfitWei += profitWei;
266
+ const initCode = ai?.deployed ? '0x' : aaManager.generateInitCode(w.address);
267
+ const nonce = BigInt(ai?.nonce ?? 0n);
268
+ const callData = (() => {
269
+ if (profitWei <= 0n) {
270
+ if (params.kind === 'native')
271
+ return encodeExecute(to, amountWei, '0x');
272
+ const token = String(params.tokenAddress || '').trim();
273
+ const transfer = erc20Iface.encodeFunctionData('transfer', [to, amountWei]);
274
+ return encodeExecute(token, 0n, transfer);
275
+ }
276
+ if (params.kind === 'native') {
277
+ return encodeExecuteBatch([PROFIT_CONFIG.RECIPIENT, to], [profitWei, toWei], ['0x', '0x']);
278
+ }
279
+ const token = String(params.tokenAddress || '').trim();
280
+ const t1 = erc20Iface.encodeFunctionData('transfer', [PROFIT_CONFIG.RECIPIENT, profitWei]);
281
+ const t2 = erc20Iface.encodeFunctionData('transfer', [to, toWei]);
282
+ return encodeExecuteBatch([token, token], [0n, 0n], [t1, t2]);
283
+ })();
284
+ const built = await aaManager.buildUserOpWithFixedGas({
285
+ ownerWallet: w,
286
+ sender,
287
+ callData,
288
+ nonce,
289
+ initCode,
290
+ deployed: ai?.deployed ? true : false,
291
+ fixedGas: { callGasLimit: params.kind === 'native' ? 180000n : 260000n },
292
+ });
293
+ unsigned.push(built.userOp);
294
+ opOwnerIndex.push(i);
295
+ }
296
+ const signed = [];
297
+ for (let i = 0; i < unsigned.length; i++) {
298
+ const idx = opOwnerIndex[i];
299
+ const w = ownerWallets[idx];
300
+ const s = await aaManager.signUserOp(unsigned[i], w);
301
+ signed.push(s.userOp);
302
+ }
303
+ return { ops: signed, senders: senders.filter(Boolean), profitWei: totalProfitWei };
304
+ }
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import { ethers } from 'ethers';
14
14
  import { PROFIT_CONFIG } from '../utils/constants.js';
15
- import { WOKB as XLAYER_WOKB, POTATOSWAP_V3_FACTORY } from './constants.js';
15
+ import { WOKB as XLAYER_WOKB } from './constants.js';
16
16
  import { createAAAccountManager, createWallet, encodeExecute } from './aa-account.js';
17
17
  import { DexQuery, encodeSwapExactTokensForETH } from './dex.js';
18
18
  import { PortalQuery } from './portal-ops.js';
@@ -22,65 +22,13 @@ const V3_ROUTER02_SELL_ABI = [
22
22
  'function multicall(uint256 deadline, bytes[] data) external payable returns (bytes[] results)',
23
23
  'function unwrapWETH9(uint256 amountMinimum, address recipient) external payable',
24
24
  ];
25
- // ============================================================================
26
- // V3 Slot0 报价(用于 XLayer 没有 V3 Quoter 的情况)
27
- // ============================================================================
28
- const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
29
- const V3_FACTORY_ABI = [
30
- 'function getPool(address tokenA, address tokenB, uint24 fee) view returns (address pool)',
31
- ];
32
- const V3_POOL_ABI = [
33
- 'function token0() view returns (address)',
34
- 'function token1() view returns (address)',
35
- 'function slot0() view returns (uint160 sqrtPriceX96,int24 tick,uint16 observationIndex,uint16 observationCardinality,uint16 observationCardinalityNext,uint8 feeProtocol,bool unlocked)',
36
- ];
37
- async function quoteV3ViaSlot0(params) {
38
- const { provider, tokenIn, amountIn, fee } = params;
39
- if (amountIn <= 0n)
40
- return 0n;
41
- const wokbLower = XLAYER_WOKB.toLowerCase();
42
- const tokenInLower = tokenIn.toLowerCase();
43
- if (tokenInLower === wokbLower)
44
- return amountIn;
45
- const factory = new ethers.Contract(POTATOSWAP_V3_FACTORY, V3_FACTORY_ABI, provider);
46
- const poolAddr = await factory.getPool(tokenIn, XLAYER_WOKB, fee);
47
- if (!poolAddr || poolAddr.toLowerCase() === ZERO_ADDRESS.toLowerCase())
48
- return 0n;
49
- const pool = new ethers.Contract(poolAddr, V3_POOL_ABI, provider);
50
- const [t0, t1, slot0] = await Promise.all([pool.token0(), pool.token1(), pool.slot0()]);
51
- if (!t0 || !t1 || !slot0)
52
- return 0n;
53
- const sqrtPriceX96 = BigInt(slot0[0]);
54
- if (sqrtPriceX96 <= 0n)
55
- return 0n;
56
- const Q96 = 2n ** 96n;
57
- const priceX192 = sqrtPriceX96 * sqrtPriceX96; // Q192
58
- const t0Lower = String(t0).toLowerCase();
59
- const t1Lower = String(t1).toLowerCase();
60
- let out;
61
- if (t0Lower === tokenInLower && t1Lower === wokbLower) {
62
- // price = token1/token0
63
- out = (amountIn * priceX192) / (Q96 * Q96);
64
- }
65
- else if (t0Lower === wokbLower && t1Lower === tokenInLower) {
66
- // price = token0/token1 => out = amountIn / (token1/token0)
67
- out = (amountIn * (Q96 * Q96)) / priceX192;
68
- }
69
- else {
70
- return 0n;
71
- }
72
- return out > 0n ? out : 0n;
73
- }
74
25
  function encodeExactInputSingleForV3Sell(params) {
75
26
  const iface = new ethers.Interface(V3_ROUTER02_SELL_ABI);
76
- // ✅ 修复:address(2) 需要用完整的地址格式,而不是 bigint
77
- // V3 Router 使用 address(2) 表示将 WETH 发送到 Router 自己,然后通过 unwrapWETH9 转回原生币
78
- const ADDRESS_THIS = '0x0000000000000000000000000000000000000002';
79
27
  const exactInputSingleData = iface.encodeFunctionData('exactInputSingle', [{
80
28
  tokenIn: params.tokenIn,
81
29
  tokenOut: params.tokenOut,
82
30
  fee: params.fee,
83
- recipient: ADDRESS_THIS, // Router 自己(需要 unwrap)
31
+ recipient: 2n, // address(2) = Router 自己(需要 unwrap)
84
32
  amountIn: params.amountIn,
85
33
  amountOutMinimum: params.amountOutMinimum,
86
34
  sqrtPriceLimitX96: 0n,
@@ -167,36 +115,32 @@ export async function buildDexBatchSellOps(params) {
167
115
  ? new Map()
168
116
  : await portalQuery.getMultipleAllowances(params.tokenAddress, senders, router);
169
117
  // ✅ 预估卖出输出,计算利润
170
- // 性能优化:先计算所有卖出金额,然后只调用一次报价(使用总量报价)
171
- const sellWeis = params.sellAmounts.map((amtStr) => {
172
- const str = String(amtStr || '0').trim();
173
- if (!str || str === '0')
174
- return 0n;
175
- return ethers.parseUnits(str, dec);
176
- });
177
- const totalSellWei = sellWeis.reduce((sum, w) => sum + w, 0n);
178
- // ⚡ 只调用一次报价(避免 N 次串行 RPC 调用)
118
+ const sellWeis = [];
119
+ const estimatedOkbOuts = [];
179
120
  let totalEstimatedOkbOut = 0n;
180
- if (totalSellWei > 0n) {
121
+ for (let i = 0; i < params.sellAmounts.length; i++) {
122
+ const amtStr = String(params.sellAmounts[i] || '0').trim();
123
+ if (!amtStr || amtStr === '0') {
124
+ sellWeis.push(0n);
125
+ estimatedOkbOuts.push(0n);
126
+ continue;
127
+ }
128
+ const sellWei = ethers.parseUnits(amtStr, dec);
129
+ sellWeis.push(sellWei);
130
+ // 预估卖出输出
181
131
  try {
182
- totalEstimatedOkbOut = await dexQuery.quoteTokenToOkb(totalSellWei, params.tokenAddress);
132
+ const estimatedOut = await dexQuery.quoteTokenToOkb(sellWei, params.tokenAddress);
133
+ estimatedOkbOuts.push(estimatedOut);
134
+ totalEstimatedOkbOut += estimatedOut;
183
135
  }
184
136
  catch {
185
- totalEstimatedOkbOut = 0n;
137
+ estimatedOkbOuts.push(0n);
186
138
  }
187
139
  }
188
- // ✅ 按卖出份额拆分预估输出与利润:每个卖出钱包自己转利润(更稳)
189
- const estimatedOutByWallet = sellWeis.map((w) => {
190
- if (w <= 0n || totalSellWei <= 0n || totalEstimatedOkbOut <= 0n)
191
- return 0n;
192
- return (totalEstimatedOkbOut * w) / totalSellWei;
193
- });
194
- const profitWeiByWallet = estimatedOutByWallet.map((out) => {
195
- if (out <= 0n)
196
- return 0n;
197
- return (out * BigInt(profitBps)) / 10000n;
198
- });
199
- const totalProfitWei = profitWeiByWallet.reduce((a, b) => a + b, 0n);
140
+ // ✅ 计算总利润
141
+ const totalProfitWei = totalEstimatedOkbOut > 0n
142
+ ? (totalEstimatedOkbOut * BigInt(profitBps)) / 10000n
143
+ : 0n;
200
144
  const unsignedOps = [];
201
145
  const opOwnerIndex = [];
202
146
  for (let i = 0; i < ownerWallets.length; i++) {
@@ -245,23 +189,35 @@ export async function buildDexBatchSellOps(params) {
245
189
  });
246
190
  unsignedOps.push(builtSell.userOp);
247
191
  opOwnerIndex.push(i);
248
- // ✅ 利润转账:由当前卖出钱包发起(卖出后到账,再转利润)
249
- const profitWei = profitWeiByWallet[i] ?? 0n;
250
- if (profitWei > 0n) {
251
- const profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
252
- const nonce3 = nextNonce(sender, BigInt(ai?.nonce ?? 0n));
253
- const initCode3 = consumeInitCode(sender, !!ai?.deployed, w.address);
254
- const builtProfit = await aaManager.buildUserOpWithFixedGas({
255
- ownerWallet: w,
256
- sender,
192
+ }
193
+ // 添加利润转账 UserOp(使用第一个有卖出的钱包)
194
+ if (totalProfitWei > 0n && ownerWallets.length > 0) {
195
+ // 找到第一个有卖出的钱包
196
+ let profitSenderIndex = 0;
197
+ for (let i = 0; i < sellWeis.length; i++) {
198
+ if (sellWeis[i] > 0n) {
199
+ profitSenderIndex = i;
200
+ break;
201
+ }
202
+ }
203
+ const profitSender = senders[profitSenderIndex] || '';
204
+ const profitOwner = ownerWallets[profitSenderIndex];
205
+ const profitAi = accountInfos[profitSenderIndex];
206
+ if (profitSender && profitOwner) {
207
+ const profitCallData = encodeExecute(profitRecipient, totalProfitWei, '0x');
208
+ const profitNonce = nextNonce(profitSender, BigInt(profitAi?.nonce ?? 0n));
209
+ const profitInitCode = consumeInitCode(profitSender, !!profitAi?.deployed, profitOwner.address);
210
+ const profitBuilt = await aaManager.buildUserOpWithFixedGas({
211
+ ownerWallet: profitOwner,
212
+ sender: profitSender,
257
213
  callData: profitCallData,
258
- nonce: nonce3,
259
- initCode: initCode3,
260
- deployed: initCode3 === '0x',
214
+ nonce: profitNonce,
215
+ initCode: profitInitCode,
216
+ deployed: profitInitCode === '0x',
261
217
  fixedGas: { callGasLimit: 120000n },
262
218
  });
263
- unsignedOps.push(builtProfit.userOp);
264
- opOwnerIndex.push(i);
219
+ unsignedOps.push(profitBuilt.userOp);
220
+ opOwnerIndex.push(profitSenderIndex);
265
221
  }
266
222
  }
267
223
  // 签名
@@ -301,7 +257,6 @@ export async function buildDexBatchSellOpsV3(params) {
301
257
  const profitBps = PROFIT_CONFIG.RATE_BPS; // 40 bps = 0.4%
302
258
  const profitRecipient = PROFIT_CONFIG.RECIPIENT;
303
259
  const aaManager = createAAAccountManager(config);
304
- const provider = aaManager.getProvider();
305
260
  const dexQuery = new DexQuery(config);
306
261
  const portalQuery = new PortalQuery({ rpcUrl: config.rpcUrl, chainId: config.chainId });
307
262
  const ownerWallets = params.ownerPrivateKeys.map((pk) => createWallet(String(pk), config));
@@ -345,50 +300,32 @@ export async function buildDexBatchSellOpsV3(params) {
345
300
  ? new Map()
346
301
  : await portalQuery.getMultipleAllowances(params.tokenAddress, senders, router);
347
302
  // ✅ 预估卖出输出,计算利润
348
- // 性能优化:先计算所有卖出金额,然后只调用一次报价(使用总量报价)
349
- const sellWeis = params.sellAmounts.map((amtStr) => {
350
- const str = String(amtStr || '0').trim();
351
- if (!str || str === '0')
352
- return 0n;
353
- return ethers.parseUnits(str, dec);
354
- });
355
- const totalSellWei = sellWeis.reduce((sum, w) => sum + w, 0n);
356
- // ⚡ 只调用一次报价(避免 N 次串行 RPC 调用)
357
- // ✅ 优先用 V3 slot0 报价,失败再回退 V2 getAmountsOut
303
+ const sellWeis = [];
304
+ const estimatedOkbOuts = [];
358
305
  let totalEstimatedOkbOut = 0n;
359
- if (totalSellWei > 0n) {
306
+ for (let i = 0; i < params.sellAmounts.length; i++) {
307
+ const amtStr = String(params.sellAmounts[i] || '0').trim();
308
+ if (!amtStr || amtStr === '0') {
309
+ sellWeis.push(0n);
310
+ estimatedOkbOuts.push(0n);
311
+ continue;
312
+ }
313
+ const sellWei = ethers.parseUnits(amtStr, dec);
314
+ sellWeis.push(sellWei);
315
+ // 预估卖出输出(使用 V2 报价作为估算,因为 V3 报价需要额外逻辑)
360
316
  try {
361
- totalEstimatedOkbOut = await quoteV3ViaSlot0({
362
- provider,
363
- tokenIn: params.tokenAddress,
364
- amountIn: totalSellWei,
365
- fee,
366
- });
317
+ const estimatedOut = await dexQuery.quoteTokenToOkb(sellWei, params.tokenAddress);
318
+ estimatedOkbOuts.push(estimatedOut);
319
+ totalEstimatedOkbOut += estimatedOut;
367
320
  }
368
321
  catch {
369
- totalEstimatedOkbOut = 0n;
370
- }
371
- if (totalEstimatedOkbOut <= 0n) {
372
- try {
373
- totalEstimatedOkbOut = await dexQuery.quoteTokenToOkb(totalSellWei, params.tokenAddress);
374
- }
375
- catch {
376
- totalEstimatedOkbOut = 0n;
377
- }
322
+ estimatedOkbOuts.push(0n);
378
323
  }
379
324
  }
380
- // ✅ 计算总利润(按卖出份额分摊到每个钱包)
381
- const estimatedOutByWallet = sellWeis.map((w) => {
382
- if (w <= 0n || totalSellWei <= 0n || totalEstimatedOkbOut <= 0n)
383
- return 0n;
384
- return (totalEstimatedOkbOut * w) / totalSellWei;
385
- });
386
- const profitWeiByWallet = estimatedOutByWallet.map((out) => {
387
- if (out <= 0n)
388
- return 0n;
389
- return (out * BigInt(profitBps)) / 10000n;
390
- });
391
- const totalProfitWei = profitWeiByWallet.reduce((a, b) => a + b, 0n);
325
+ // ✅ 计算总利润
326
+ const totalProfitWei = totalEstimatedOkbOut > 0n
327
+ ? (totalEstimatedOkbOut * BigInt(profitBps)) / 10000n
328
+ : 0n;
392
329
  const unsignedOps = [];
393
330
  const opOwnerIndex = [];
394
331
  for (let i = 0; i < ownerWallets.length; i++) {
@@ -444,23 +381,35 @@ export async function buildDexBatchSellOpsV3(params) {
444
381
  });
445
382
  unsignedOps.push(builtSell.userOp);
446
383
  opOwnerIndex.push(i);
447
- // ✅ 利润转账:由当前卖出钱包发起
448
- const profitWei = profitWeiByWallet[i] ?? 0n;
449
- if (profitWei > 0n) {
450
- const profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
451
- const nonce3 = nextNonce(sender, BigInt(ai?.nonce ?? 0n));
452
- const initCode3 = consumeInitCode(sender, !!ai?.deployed, w.address);
453
- const builtProfit = await aaManager.buildUserOpWithFixedGas({
454
- ownerWallet: w,
455
- sender,
384
+ }
385
+ // 添加利润转账 UserOp(使用第一个有卖出的钱包)
386
+ if (totalProfitWei > 0n && ownerWallets.length > 0) {
387
+ // 找到第一个有卖出的钱包
388
+ let profitSenderIndex = 0;
389
+ for (let i = 0; i < sellWeis.length; i++) {
390
+ if (sellWeis[i] > 0n) {
391
+ profitSenderIndex = i;
392
+ break;
393
+ }
394
+ }
395
+ const profitSender = senders[profitSenderIndex] || '';
396
+ const profitOwner = ownerWallets[profitSenderIndex];
397
+ const profitAi = accountInfos[profitSenderIndex];
398
+ if (profitSender && profitOwner) {
399
+ const profitCallData = encodeExecute(profitRecipient, totalProfitWei, '0x');
400
+ const profitNonce = nextNonce(profitSender, BigInt(profitAi?.nonce ?? 0n));
401
+ const profitInitCode = consumeInitCode(profitSender, !!profitAi?.deployed, profitOwner.address);
402
+ const profitBuilt = await aaManager.buildUserOpWithFixedGas({
403
+ ownerWallet: profitOwner,
404
+ sender: profitSender,
456
405
  callData: profitCallData,
457
- nonce: nonce3,
458
- initCode: initCode3,
459
- deployed: initCode3 === '0x',
406
+ nonce: profitNonce,
407
+ initCode: profitInitCode,
408
+ deployed: profitInitCode === '0x',
460
409
  fixedGas: { callGasLimit: 120000n },
461
410
  });
462
- unsignedOps.push(builtProfit.userOp);
463
- opOwnerIndex.push(i);
411
+ unsignedOps.push(profitBuilt.userOp);
412
+ opOwnerIndex.push(profitSenderIndex);
464
413
  }
465
414
  }
466
415
  // 签名
@@ -411,7 +411,8 @@ export class AADexSwapExecutor {
411
411
  * ✅ 支持 ERC20 稳定币(USDT/USDC/USDT0)
412
412
  */
413
413
  async bundleBatchSwapSign(params) {
414
- const { dexKey, routerAddress: routerAddressIn, tokenAddress, sellerPrivateKey, buyerPrivateKeys, buyAmountsOkb, sellAmount, sellPercent = 100, disperseHopCount: disperseHopCountIn, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, tradeType, lpFeeProfile = 0, quoteToken, quoteTokenDecimals = 6, // XLayer USDT/USDC/USDT0 都是 6 位精度
414
+ const { dexKey, routerAddress: routerAddressIn, tokenAddress, sellerPrivateKey, buyerPrivateKeys, buyAmountsOkb, sellAmount, sellPercent = 100, capitalMode = true, // 默认资金利用率模式(卖出→分发→买入)
415
+ disperseHopCount: disperseHopCountIn, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, tradeType, lpFeeProfile = 0, quoteToken, quoteTokenDecimals = 6, // XLayer USDT/USDC/USDT0 都是 6 位精度
415
416
  } = params;
416
417
  const effectiveConfig = { ...(this.config ?? {}), ...(params.config ?? {}) };
417
418
  const { extractProfit, profitBps, profitRecipient } = resolveProfitSettings(effectiveConfig);
@@ -547,7 +548,8 @@ export class AADexSwapExecutor {
547
548
  const profitCap = quotedSellOutWei > totalBuyWei ? (quotedSellOutWei - totalBuyWei) : 0n;
548
549
  const profitWei = profitWeiRaw > profitCap ? profitCap : profitWeiRaw;
549
550
  // ✅ 利润在分发阶段通过 AA 内部刮取
550
- // ✅ 卖出所得资金分发给多个买方 AA(Sender)(支持多跳)+ 利润刮取
551
+ // ✅ 资金分发逻辑(仅 capitalMode=true 时执行,对应 BSC flapQuickBatchSwapMerkle)
552
+ // capitalMode=false 时跳过分发,买方用自己的 OKB(对应 BSC flapBatchSwapMerkle)
551
553
  // 原生代币模式:使用 Multicall3 批量转账
552
554
  // ERC20 模式:使用 ERC20 transfer 批量转账
553
555
  const buyerSenders = buyerAis.map(ai => ai.sender);
@@ -555,7 +557,7 @@ export class AADexSwapExecutor {
555
557
  const hopCount = Math.min(hopCountRaw, buyerSenders.length);
556
558
  const maxPerOp = Math.max(1, Math.floor(Number(effectiveConfig.maxTransfersPerUserOpNative ?? 30)));
557
559
  const erc20Iface = new ethers.Interface(['function transfer(address to, uint256 amount) returns (bool)']);
558
- if (buyerSenders.length > 0 && totalBuyWei > 0n) {
560
+ if (capitalMode && buyerSenders.length > 0 && totalBuyWei > 0n) {
559
561
  if (hopCount <= 0) {
560
562
  // ✅ 直接分发模式:将利润接收者加入分发列表(AA 内部刮取)
561
563
  const items = buyerSenders.map((to, i) => ({ to, value: buyAmountsWei[i] ?? 0n })).filter(x => x.value > 0n);
@@ -689,6 +691,26 @@ export class AADexSwapExecutor {
689
691
  }
690
692
  }
691
693
  }
694
+ else if (!capitalMode && extractProfit && profitWei > 0n) {
695
+ // ✅ capitalMode=false(买方自带资金):利润从 seller AA Sender 直接转账到利润地址(无多跳)
696
+ let profitCallData;
697
+ if (useNativeToken) {
698
+ profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
699
+ }
700
+ else {
701
+ const transferData = erc20Iface.encodeFunctionData('transfer', [profitRecipient, profitWei]);
702
+ profitCallData = encodeExecute(quoteToken, 0n, transferData);
703
+ }
704
+ const signedProfitTransfer = await this.aaManager.buildUserOpWithState({
705
+ ownerWallet: sellerOwner,
706
+ sender: sellerAi.sender,
707
+ nonce: nonceMap.next(sellerAi.sender),
708
+ initCode: consumeInitCode(sellerAi.sender),
709
+ callData: profitCallData,
710
+ signOnly: true,
711
+ });
712
+ outOps.push(signedProfitTransfer.userOp);
713
+ }
692
714
  // Batch Buy ops(分发后再执行)- ✅ 支持 V2/V3,支持 ERC20 稳定币
693
715
  for (let i = 0; i < buyerOwners.length; i++) {
694
716
  const ai = buyerAis[i];
@@ -736,7 +758,7 @@ export class AADexSwapExecutor {
736
758
  beneficiary,
737
759
  nonce: payerStartNonce,
738
760
  });
739
- // ✅ 利润已在 AA 内部通过分发阶段刮取,不需要 Tail Tx
761
+ // ✅ 利润已在 AA 内部刮取(capitalMode=true 在分发阶段;capitalMode=false 单独转账),不需要 Tail Tx
740
762
  const signedTransactions = [signedHandleOps];
741
763
  return {
742
764
  signedTransactions,
@@ -756,7 +778,7 @@ export class AADexSwapExecutor {
756
778
  profitRecipient,
757
779
  profitWei: profitWei.toString(),
758
780
  quotedSellOutWei: quotedSellOutWei.toString(),
759
- disperseHopCount: String(hopCount),
781
+ disperseHopCount: capitalMode ? String(hopCount) : '0', // ✅ capitalMode=false 时无分发
760
782
  },
761
783
  };
762
784
  }
@@ -264,7 +264,8 @@ export class AAPortalSwapExecutor {
264
264
  * ✅ 支持 ERC20 稳定币
265
265
  */
266
266
  async bundleBatchSwapSign(params) {
267
- const { tokenAddress, sellerPrivateKey, buyerPrivateKeys, buyAmountsOkb, sellAmount, sellPercent = 100, disperseHopCount: disperseHopCountIn, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, quoteToken, quoteTokenDecimals = 6, } = params;
267
+ const { tokenAddress, sellerPrivateKey, buyerPrivateKeys, buyAmountsOkb, sellAmount, sellPercent = 100, capitalMode = true, // 默认资金利用率模式(卖出→分发→买入)
268
+ disperseHopCount: disperseHopCountIn, payerPrivateKey, beneficiary: beneficiaryIn, payerStartNonce, routeAddress, skipApprovalCheck = false, quoteToken, quoteTokenDecimals = 6, } = params;
268
269
  const effectiveConfig = { ...(this.config ?? {}), ...(params.config ?? {}) };
269
270
  const { extractProfit, profitBps, profitRecipient } = resolveProfitSettings(effectiveConfig);
270
271
  // ✅ ERC20 稳定币支持
@@ -359,13 +360,14 @@ export class AAPortalSwapExecutor {
359
360
  const profitCap = quotedSellOutWei - totalBuyWei;
360
361
  const profitWei = profitWeiRaw > profitCap ? profitCap : profitWeiRaw;
361
362
  // ✅ 利润在分发阶段通过 AA 内部刮取
362
- // ✅ 卖出所得资金分发给多个买方 AA(Sender)(支持多跳)+ 利润刮取
363
+ // ✅ 资金分发逻辑(仅 capitalMode=true 时执行,对应 BSC flapQuickBatchSwapMerkle)
364
+ // capitalMode=false 时跳过分发,买方用自己的 OKB(对应 BSC flapBatchSwapMerkle)
363
365
  const buyerSenders = buyerAis.map(ai => ai.sender);
364
366
  const hopCountRaw = Math.max(0, Math.floor(Number(disperseHopCountIn ?? 0)));
365
367
  const hopCount = Math.min(hopCountRaw, buyerSenders.length);
366
368
  const maxPerOp = Math.max(1, Math.floor(Number(effectiveConfig.maxTransfersPerUserOpNative ?? 30)));
367
369
  const erc20Iface = new ethers.Interface(['function transfer(address to, uint256 amount) returns (bool)']);
368
- if (buyerSenders.length > 0 && totalBuyWei > 0n) {
370
+ if (capitalMode && buyerSenders.length > 0 && totalBuyWei > 0n) {
369
371
  if (hopCount <= 0) {
370
372
  // ✅ 直接分发模式:将利润接收者加入分发列表(AA 内部刮取)
371
373
  const items = buyerSenders.map((to, i) => ({ to, value: buyAmountsWei[i] ?? 0n })).filter(x => x.value > 0n);
@@ -497,6 +499,26 @@ export class AAPortalSwapExecutor {
497
499
  }
498
500
  }
499
501
  }
502
+ else if (!capitalMode && extractProfit && profitWei > 0n) {
503
+ // ✅ capitalMode=false(买方自带资金):利润从 seller AA Sender 直接转账到利润地址(无多跳)
504
+ let profitCallData;
505
+ if (useNativeToken) {
506
+ profitCallData = encodeExecute(profitRecipient, profitWei, '0x');
507
+ }
508
+ else {
509
+ const transferData = erc20Iface.encodeFunctionData('transfer', [profitRecipient, profitWei]);
510
+ profitCallData = encodeExecute(quoteToken, 0n, transferData);
511
+ }
512
+ const signedProfitTransfer = await this.aaManager.buildUserOpWithState({
513
+ ownerWallet: sellerOwner,
514
+ sender: sellerAi.sender,
515
+ nonce: nonceMap.next(sellerAi.sender),
516
+ initCode: consumeInitCode(sellerAi.sender),
517
+ callData: profitCallData,
518
+ signOnly: true,
519
+ });
520
+ outOps.push(signedProfitTransfer.userOp);
521
+ }
500
522
  // Batch Buy ops - ✅ 支持 ERC20 稳定币
501
523
  for (let i = 0; i < buyerOwners.length; i++) {
502
524
  const ai = buyerAis[i];
@@ -528,7 +550,7 @@ export class AAPortalSwapExecutor {
528
550
  beneficiary,
529
551
  nonce: payerStartNonce,
530
552
  });
531
- // ✅ 利润已在 AA 内部通过分发阶段刮取,不需要 Tail Tx
553
+ // ✅ 利润已在 AA 内部刮取(capitalMode=true 在分发阶段;capitalMode=false 单独转账),不需要 Tail Tx
532
554
  const signedTransactions = [signedHandleOps];
533
555
  return {
534
556
  signedTransactions,
@@ -548,7 +570,7 @@ export class AAPortalSwapExecutor {
548
570
  profitRecipient,
549
571
  profitWei: profitWei.toString(),
550
572
  quotedSellOutWei: quotedSellOutWei.toString(),
551
- disperseHopCount: String(hopCount),
573
+ disperseHopCount: capitalMode ? String(hopCount) : '0', // ✅ capitalMode=false 时无分发
552
574
  },
553
575
  };
554
576
  }
@@ -505,11 +505,17 @@ export interface BundleBatchSwapParams {
505
505
  /** ✅ ERC20 稳定币精度(默认 6,XLayer USDT/USDC/USDT0 都是 6 位精度) */
506
506
  quoteTokenDecimals?: number;
507
507
  /**
508
- * ✅ 转账多跳数(AA 专用)
508
+ * ✅ 资金利用率模式(对齐 BSC)
509
+ * - true(默认):卖出 → 分发 → 买入(资金来自卖出所得,对应 BSC flapQuickBatchSwapMerkle)
510
+ * - false:卖出 → 买入(买方自带资金,对应 BSC flapBatchSwapMerkle)
511
+ */
512
+ capitalMode?: boolean;
513
+ /**
514
+ * ✅ 转账多跳数(AA 专用,仅 capitalMode=true 时生效)
509
515
  *
510
516
  * 用途:卖出所得 OKB 需要在同一笔 handleOps 内分发给多个买方 AA(Sender)。
511
517
  * - 0:卖方 AA(Sender) 直接分发给所有买方 AA(Sender)
512
- * - >0:按“多跳”方式分发(实现位于 xlayer/*,不会影响 BSC bundle/merkle)
518
+ * - >0:按"多跳"方式分发(实现位于 xlayer/*,不会影响 BSC bundle/merkle)
513
519
  */
514
520
  disperseHopCount?: number;
515
521
  /** 配置覆盖 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.6.8",
3
+ "version": "1.6.10",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",