four-flap-meme-sdk 1.5.38 → 1.5.40

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.
@@ -7,7 +7,7 @@
7
7
  * - 买卖一体化:买入 -> 授权 -> 卖出 -> 归集
8
8
  * - OKB 归集:将 sender 的 OKB 转回 owner
9
9
  */
10
- import type { XLayerConfig, BundleBuyParams, BundleBuyResult, BundleSellParams, BundleSellResult, BundleBuySellParams, BundleBuySellResult, BundleCreateBuyParams, BundleCreateBuyResult, BundleCreateBuySignParams, BundleCreateBuySignResult } from './types.js';
10
+ import type { XLayerConfig, BundleBuyParams, BundleBuyResult, BundleSellParams, BundleSellResult, BundleBuySellParams, BundleBuySellResult, BundleCreateBuyParams, BundleCreateBuyResult, BundleCreateBuySignParams, BundleCreateBuySignResult, BundlePreApproveParams, BundlePreApproveResult, ApprovalStatusResult } from './types.js';
11
11
  import { AAAccountManager } from './aa-account.js';
12
12
  import { PortalQuery } from './portal-ops.js';
13
13
  /**
@@ -95,6 +95,39 @@ export declare class BundleExecutor {
95
95
  * 捆绑发射代币 + 购买(执行版本)
96
96
  */
97
97
  bundleCreateBuy(params: BundleCreateBuyParams): Promise<BundleCreateBuyResult>;
98
+ /**
99
+ * 检查多个 AA 账户的授权状态
100
+ *
101
+ * 用于判断是否需要执行预授权,或查看当前授权进度
102
+ *
103
+ * @param tokenAddress - 代币地址
104
+ * @param privateKeys - Owner 私钥列表
105
+ * @param spender - 授权目标(默认 FLAP_PORTAL)
106
+ * @returns 每个地址的授权状态
107
+ */
108
+ checkApprovalStatus(tokenAddress: string, privateKeys: string[], spender?: string): Promise<ApprovalStatusResult[]>;
109
+ /**
110
+ * 批量预授权
111
+ *
112
+ * 提前授权代币给 Portal/Router,避免交易时等待授权确认
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * // 预授权给 Portal(用于内盘交易)
117
+ * const result = await executor.bundlePreApprove({
118
+ * tokenAddress: '0x...',
119
+ * privateKeys: ['0x...', '0x...'],
120
+ * });
121
+ *
122
+ * // 预授权给外盘 Router
123
+ * const result = await executor.bundlePreApprove({
124
+ * tokenAddress: '0x...',
125
+ * privateKeys: ['0x...'],
126
+ * spender: POTATOSWAP_V2_ROUTER,
127
+ * });
128
+ * ```
129
+ */
130
+ bundlePreApprove(params: BundlePreApproveParams): Promise<BundlePreApproveResult>;
98
131
  }
99
132
  /**
100
133
  * 创建捆绑交易执行器
@@ -120,3 +153,15 @@ export declare function bundleCreateBuy(params: BundleCreateBuyParams): Promise<
120
153
  * 快速捆绑发射 + 购买(仅签名)
121
154
  */
122
155
  export declare function bundleCreateBuySign(params: BundleCreateBuySignParams): Promise<BundleCreateBuySignResult>;
156
+ /**
157
+ * 快速预授权
158
+ *
159
+ * 一键授权多个 AA 账户的代币,避免交易时等待授权确认
160
+ */
161
+ export declare function bundlePreApprove(params: BundlePreApproveParams): Promise<BundlePreApproveResult>;
162
+ /**
163
+ * 检查授权状态
164
+ *
165
+ * 批量查询多个 AA 账户的代币授权状态
166
+ */
167
+ export declare function checkApprovalStatus(tokenAddress: string, privateKeys: string[], spender?: string, config?: XLayerConfig): Promise<ApprovalStatusResult[]>;
@@ -765,40 +765,9 @@ export class BundleExecutor {
765
765
  for (const ai of accountInfos)
766
766
  nonceMap.init(ai.sender, ai.nonce);
767
767
  const tokenBalances = await this.portalQuery.getMultipleTokenBalances(tokenAddress, senders);
768
- const allowances = await this.portalQuery.getMultipleAllowances(tokenAddress, senders);
769
- // 1. 检查授权,必要时先 approve
770
- const approveItems = [];
771
- const didApprove = new Array(wallets.length).fill(false);
772
- const touched = new Array(wallets.length).fill(false); // 任意阶段使用过 UserOp(用于决定 initCode=0x)
773
- for (let i = 0; i < wallets.length; i++) {
774
- const sender = senders[i];
775
- const balance = tokenBalances.get(sender) ?? 0n;
776
- const allowance = allowances.get(sender) ?? 0n;
777
- if (balance === 0n)
778
- continue;
779
- if (allowance >= balance)
780
- continue;
781
- const ai = accountInfos[i];
782
- const initCode = ai.deployed ? '0x' : this.aaManager.generateInitCode(wallets[i].address);
783
- approveItems.push({ i, sender, nonce: nonceMap.next(sender), initCode });
784
- didApprove[i] = true;
785
- touched[i] = true;
786
- }
787
- const approveOps = [];
788
- if (approveItems.length > 0) {
789
- const signedApproves = await mapWithConcurrency(approveItems, 4, async (it) => {
790
- const i = it.i;
791
- const signed = await this.buildApproveUserOp(wallets[i], tokenAddress, this.portalAddress, it.sender, it.nonce, it.initCode, `owner${i + 1}`);
792
- return { i, userOp: signed.userOp };
793
- });
794
- for (const r of signedApproves)
795
- approveOps.push(r.userOp);
796
- }
797
- let approveResult;
798
- if (approveOps.length > 0) {
799
- approveResult = await this.runHandleOps('approveBundle', approveOps, bundlerSigner, beneficiary) ?? undefined;
800
- }
801
- // 2. 卖出
768
+ // 不再内联授权,假设已通过 bundlePreApprove 预先授权
769
+ const touched = new Array(wallets.length).fill(false);
770
+ // 直接卖出
802
771
  const sellOps = [];
803
772
  const sellItems = [];
804
773
  for (let i = 0; i < wallets.length; i++) {
@@ -811,16 +780,15 @@ export class BundleExecutor {
811
780
  continue;
812
781
  const ai = accountInfos[i];
813
782
  const initCode = ai.deployed ? '0x' : this.aaManager.generateInitCode(wallets[i].address);
814
- // approve 已单独打包并等待确认,因此这里不需要用“needApprove=真”去走保守 callGasLimit
815
- const needApprove = false;
816
783
  const nonce = nonceMap.next(sender);
817
- sellItems.push({ i, sender, nonce, initCode: didApprove[i] ? '0x' : initCode, needApprove, sellAmount });
784
+ sellItems.push({ i, sender, nonce, initCode, sellAmount });
818
785
  touched[i] = true;
819
786
  }
820
787
  if (sellItems.length > 0) {
821
788
  const signedSells = await mapWithConcurrency(sellItems, 4, async (it) => {
822
789
  const i = it.i;
823
- const signed = await this.buildSellUserOp(wallets[i], tokenAddress, it.sellAmount, it.sender, it.nonce, it.initCode, it.needApprove, `owner${i + 1}`);
790
+ const signed = await this.buildSellUserOp(wallets[i], tokenAddress, it.sellAmount, it.sender, it.nonce, it.initCode, false, // needApprove=false,假设已预先授权
791
+ `owner${i + 1}`);
824
792
  return signed.userOp;
825
793
  });
826
794
  sellOps.push(...signedSells);
@@ -878,7 +846,6 @@ export class BundleExecutor {
878
846
  }
879
847
  }
880
848
  return {
881
- approveResult,
882
849
  sellResult,
883
850
  withdrawResult,
884
851
  profit: withdrawToOwner
@@ -1058,8 +1025,7 @@ export class BundleExecutor {
1058
1025
  }
1059
1026
  // 获取买入后的代币余额
1060
1027
  const tokenBalances = await this.portalQuery.getMultipleTokenBalances(tokenAddress, senders);
1061
- const allowances = await this.portalQuery.getMultipleAllowances(tokenAddress, senders);
1062
- // 2. 授权 + 卖出(可以合并到同一笔 handleOps)
1028
+ // 2. 直接卖出(✅ 不再内联授权,假设已通过 bundlePreApprove 预先授权)
1063
1029
  const sellOps = [];
1064
1030
  const sellPerWallet = await mapWithConcurrency(wallets, 4, async (w, i) => {
1065
1031
  const sender = senders[i];
@@ -1068,20 +1034,14 @@ export class BundleExecutor {
1068
1034
  console.log(`[owner${i + 1}] 没买到代币,跳过卖出`);
1069
1035
  return [];
1070
1036
  }
1071
- const allowance = allowances.get(sender) ?? 0n;
1072
- const needApprove = allowance < balance;
1073
1037
  const initCode = '0x';
1074
1038
  const out = [];
1075
- if (needApprove) {
1076
- const nonce = nonceMap.next(sender);
1077
- const approveOp = await this.buildApproveUserOp(w, tokenAddress, this.portalAddress, sender, nonce, initCode, `owner${i + 1}`);
1078
- out.push(approveOp.userOp);
1079
- }
1080
1039
  const sellAmount = (balance * BigInt(sellPercent)) / 100n;
1081
1040
  if (sellAmount === 0n)
1082
1041
  return out;
1083
1042
  const sellNonce = nonceMap.next(sender);
1084
- const sellOp = await this.buildSellUserOp(w, tokenAddress, sellAmount, sender, sellNonce, initCode, needApprove, `owner${i + 1}`);
1043
+ const sellOp = await this.buildSellUserOp(w, tokenAddress, sellAmount, sender, sellNonce, initCode, false, // needApprove=false,假设已预先授权
1044
+ `owner${i + 1}`);
1085
1045
  out.push(sellOp.userOp);
1086
1046
  return out;
1087
1047
  });
@@ -1398,6 +1358,167 @@ export class BundleExecutor {
1398
1358
  tokenAddress: signResult.tokenAddress
1399
1359
  };
1400
1360
  }
1361
+ // ============================================================================
1362
+ // 预授权 API(一键授权,提升交易速度)
1363
+ // ============================================================================
1364
+ /**
1365
+ * 检查多个 AA 账户的授权状态
1366
+ *
1367
+ * 用于判断是否需要执行预授权,或查看当前授权进度
1368
+ *
1369
+ * @param tokenAddress - 代币地址
1370
+ * @param privateKeys - Owner 私钥列表
1371
+ * @param spender - 授权目标(默认 FLAP_PORTAL)
1372
+ * @returns 每个地址的授权状态
1373
+ */
1374
+ async checkApprovalStatus(tokenAddress, privateKeys, spender = FLAP_PORTAL) {
1375
+ const sharedProvider = this.aaManager.getProvider();
1376
+ const wallets = privateKeys.map((pk) => new Wallet(pk, sharedProvider));
1377
+ // 批量获取账户信息
1378
+ const accountInfos = await this.aaManager.getMultipleAccountInfo(wallets.map((w) => w.address));
1379
+ const senders = accountInfos.map((ai) => ai.sender);
1380
+ // 批量获取代币余额和授权额度
1381
+ const [tokenBalances, allowances] = await Promise.all([
1382
+ this.portalQuery.getMultipleTokenBalances(tokenAddress, senders),
1383
+ this.portalQuery.getMultipleAllowances(tokenAddress, senders, spender),
1384
+ ]);
1385
+ // 组装结果
1386
+ return wallets.map((wallet, i) => {
1387
+ const sender = senders[i];
1388
+ const tokenBalance = tokenBalances.get(sender) ?? 0n;
1389
+ const currentAllowance = allowances.get(sender) ?? 0n;
1390
+ // 如果授权额度 >= 代币余额,视为已授权(足够完成卖出)
1391
+ const isApproved = currentAllowance >= tokenBalance;
1392
+ return {
1393
+ owner: wallet.address,
1394
+ sender,
1395
+ isApproved,
1396
+ currentAllowance,
1397
+ tokenBalance,
1398
+ };
1399
+ });
1400
+ }
1401
+ /**
1402
+ * 批量预授权
1403
+ *
1404
+ * 提前授权代币给 Portal/Router,避免交易时等待授权确认
1405
+ *
1406
+ * @example
1407
+ * ```typescript
1408
+ * // 预授权给 Portal(用于内盘交易)
1409
+ * const result = await executor.bundlePreApprove({
1410
+ * tokenAddress: '0x...',
1411
+ * privateKeys: ['0x...', '0x...'],
1412
+ * });
1413
+ *
1414
+ * // 预授权给外盘 Router
1415
+ * const result = await executor.bundlePreApprove({
1416
+ * tokenAddress: '0x...',
1417
+ * privateKeys: ['0x...'],
1418
+ * spender: POTATOSWAP_V2_ROUTER,
1419
+ * });
1420
+ * ```
1421
+ */
1422
+ async bundlePreApprove(params) {
1423
+ const { tokenAddress, privateKeys, spender = FLAP_PORTAL, signOnly = false, config, payerPrivateKey } = params;
1424
+ const sharedProvider = this.aaManager.getProvider();
1425
+ const wallets = privateKeys.map((pk) => new Wallet(pk, sharedProvider));
1426
+ // 如果提供了 payerPrivateKey,使用它作为 bundlerSigner(特别是 signOnly 模式下,payer 可能是单独的账号)
1427
+ // 否则默认使用第一个 owner
1428
+ const bundlerSigner = payerPrivateKey
1429
+ ? new Wallet(payerPrivateKey, sharedProvider)
1430
+ : wallets[0];
1431
+ const beneficiary = bundlerSigner.address;
1432
+ // 1. 批量获取账户信息
1433
+ const accountInfos = await this.aaManager.getMultipleAccountInfo(wallets.map((w) => w.address));
1434
+ const senders = accountInfos.map((ai) => ai.sender);
1435
+ const nonceMap = new AANonceMap();
1436
+ for (const ai of accountInfos)
1437
+ nonceMap.init(ai.sender, ai.nonce);
1438
+ // 2. 批量获取代币余额和授权额度
1439
+ const [tokenBalances, allowances] = await Promise.all([
1440
+ this.portalQuery.getMultipleTokenBalances(tokenAddress, senders),
1441
+ this.portalQuery.getMultipleAllowances(tokenAddress, senders, spender),
1442
+ ]);
1443
+ // 3. 过滤需要授权的账户
1444
+ const approveItems = [];
1445
+ const details = [];
1446
+ for (let i = 0; i < wallets.length; i++) {
1447
+ const sender = senders[i];
1448
+ const tokenBalance = tokenBalances.get(sender) ?? 0n;
1449
+ const allowance = allowances.get(sender) ?? 0n;
1450
+ const isApproved = allowance >= tokenBalance || tokenBalance === 0n;
1451
+ details.push({
1452
+ owner: wallets[i].address,
1453
+ sender,
1454
+ isApproved,
1455
+ currentAllowance: allowance,
1456
+ tokenBalance,
1457
+ });
1458
+ // 如果有余额且授权不足,需要授权
1459
+ if (tokenBalance > 0n && allowance < tokenBalance) {
1460
+ const ai = accountInfos[i];
1461
+ const initCode = ai.deployed ? '0x' : this.aaManager.generateInitCode(wallets[i].address);
1462
+ approveItems.push({ i, sender, nonce: nonceMap.next(sender), initCode });
1463
+ }
1464
+ }
1465
+ const alreadyApprovedCount = details.filter((d) => d.isApproved).length;
1466
+ // 如果全部已授权,直接返回
1467
+ if (approveItems.length === 0) {
1468
+ console.log('所有地址已授权,无需操作');
1469
+ return {
1470
+ approvedCount: 0,
1471
+ alreadyApprovedCount,
1472
+ details,
1473
+ signedTransactions: signOnly ? [] : undefined,
1474
+ };
1475
+ }
1476
+ console.log(`需要授权: ${approveItems.length}/${wallets.length}`);
1477
+ // 4. 构建授权 UserOps(signOnly 模式跳过 prefund)
1478
+ const approveOps = [];
1479
+ const signedApproves = await mapWithConcurrency(approveItems, 4, async (it) => {
1480
+ const i = it.i;
1481
+ const signed = await this.buildApproveUserOp(wallets[i], tokenAddress, spender, it.sender, it.nonce, it.initCode, `owner${i + 1}`, signOnly // signOnly=true 时跳过 ensureSenderBalance
1482
+ );
1483
+ return signed.userOp;
1484
+ });
1485
+ approveOps.push(...signedApproves);
1486
+ // ============ signOnly 模式:签名 handleOps 交易,返回 raw tx ============
1487
+ if (signOnly) {
1488
+ console.log('signOnly 模式:签名 handleOps 交易...');
1489
+ const signedTx = await this.signHandleOpsTx({
1490
+ ops: approveOps,
1491
+ payerWallet: bundlerSigner,
1492
+ beneficiary,
1493
+ });
1494
+ console.log('签名完成,返回 raw tx');
1495
+ return {
1496
+ approvedCount: approveItems.length,
1497
+ alreadyApprovedCount,
1498
+ details,
1499
+ signedTransactions: [signedTx],
1500
+ };
1501
+ }
1502
+ // ============ 非 signOnly 模式:执行 handleOps ============
1503
+ const approveResult = await this.runHandleOps('preApproveBundle', approveOps, bundlerSigner, beneficiary);
1504
+ if (!approveResult) {
1505
+ throw new Error('预授权交易失败');
1506
+ }
1507
+ // 更新 details 中授权成功的状态
1508
+ for (const it of approveItems) {
1509
+ const detail = details.find((d) => d.sender === it.sender);
1510
+ if (detail) {
1511
+ detail.isApproved = true;
1512
+ detail.currentAllowance = ethers.MaxUint256;
1513
+ }
1514
+ }
1515
+ return {
1516
+ approvedCount: approveItems.length,
1517
+ alreadyApprovedCount,
1518
+ approveResult,
1519
+ details,
1520
+ };
1521
+ }
1401
1522
  }
1402
1523
  // ============================================================================
1403
1524
  // 便捷函数
@@ -1443,3 +1564,21 @@ export async function bundleCreateBuySign(params) {
1443
1564
  const executor = createBundleExecutor(params.config);
1444
1565
  return executor.bundleCreateBuySign(params);
1445
1566
  }
1567
+ /**
1568
+ * 快速预授权
1569
+ *
1570
+ * 一键授权多个 AA 账户的代币,避免交易时等待授权确认
1571
+ */
1572
+ export async function bundlePreApprove(params) {
1573
+ const executor = createBundleExecutor(params.config);
1574
+ return executor.bundlePreApprove(params);
1575
+ }
1576
+ /**
1577
+ * 检查授权状态
1578
+ *
1579
+ * 批量查询多个 AA 账户的代币授权状态
1580
+ */
1581
+ export async function checkApprovalStatus(tokenAddress, privateKeys, spender, config) {
1582
+ const executor = createBundleExecutor(config);
1583
+ return executor.checkApprovalStatus(tokenAddress, privateKeys, spender);
1584
+ }
@@ -80,9 +80,6 @@ async function example3_bundleSell() {
80
80
  withdrawReserve: '0.00005', // 保留少量在 sender
81
81
  config,
82
82
  });
83
- if (result.approveResult) {
84
- console.log('授权交易哈希:', result.approveResult.txHash);
85
- }
86
83
  console.log('卖出交易哈希:', result.sellResult.txHash);
87
84
  if (result.withdrawResult) {
88
85
  console.log('归集交易哈希:', result.withdrawResult.txHash);
@@ -62,7 +62,7 @@ import type { BundleSwapSignParams, BundleSwapSignResult, BundleBatchSwapSignPar
62
62
  export { BundlerClient, createBundlerClient, type BundlerConfig, type BundlerReceipt, } from './bundler.js';
63
63
  export { AAAccountManager, createAAAccountManager, predictSender, createWallet, encodeExecute, encodeExecuteBatch, generateAAWallets, generateAAWalletsFromMnemonic, predictSendersFromPrivateKeys, type GeneratedAAWallet, type GenerateAAWalletsParams, type GenerateAAWalletsResult, } from './aa-account.js';
64
64
  export { encodeBuyCall, encodeSellCall, encodeApproveCall, encodeTransferCall, PortalQuery, createPortalQuery, applySlippage, formatOkb, parseOkb, formatTokenAmount, parseTokenAmount, type PortalQueryConfig, } from './portal-ops.js';
65
- export { BundleExecutor, createBundleExecutor, bundleBuy, bundleSell, bundleBuySell, bundleCreateBuy, bundleCreateBuySign, } from './bundle.js';
65
+ export { BundleExecutor, createBundleExecutor, bundleBuy, bundleSell, bundleBuySell, bundleCreateBuy, bundleCreateBuySign, bundlePreApprove, checkApprovalStatus, } from './bundle.js';
66
66
  export { DexBundleExecutor, createDexBundleExecutor, dexBundleBuySell, type DexBundleConfig, type DexBundleBuySellParams, } from './dex-bundle.js';
67
67
  export { AAPortalSwapExecutor, } from './portal-bundle-swap.js';
68
68
  export { AADexSwapExecutor, } from './dex-bundle-swap.js';
@@ -96,6 +96,8 @@ export declare const xlayer: {
96
96
  bundleBatchSwapSign: (params: BundleBatchSwapSignParams & {
97
97
  skipApprovalCheck?: boolean;
98
98
  }) => Promise<BundleBatchSwapSignResult>;
99
+ bundlePreApprove: (params: import("./types.js").BundlePreApproveParams) => Promise<import("./types.js").BundlePreApproveResult>;
100
+ checkApprovalStatus: (tokenAddress: string, privateKeys: string[], spender?: string | undefined, config?: import("./types.js").XLayerConfig | undefined) => Promise<import("./types.js").ApprovalStatusResult[]>;
99
101
  makeVolume: (params: import("./types.js").VolumeParams) => Promise<import("./types.js").VolumeResult>;
100
102
  quoteOkbToToken: (okbAmount: bigint, tokenAddress: string, config?: import("./dex.js").DexConfig | undefined) => Promise<bigint>;
101
103
  quoteTokenToOkb: (tokenAmount: bigint, tokenAddress: string, config?: import("./dex.js").DexConfig | undefined) => Promise<bigint>;
@@ -81,7 +81,9 @@ export { encodeBuyCall, encodeSellCall, encodeApproveCall, encodeTransferCall, P
81
81
  // ============================================================================
82
82
  // 捆绑交易
83
83
  // ============================================================================
84
- export { BundleExecutor, createBundleExecutor, bundleBuy, bundleSell, bundleBuySell, bundleCreateBuy, bundleCreateBuySign, } from './bundle.js';
84
+ export { BundleExecutor, createBundleExecutor, bundleBuy, bundleSell, bundleBuySell, bundleCreateBuy, bundleCreateBuySign,
85
+ // 预授权(一键授权)
86
+ bundlePreApprove, checkApprovalStatus, } from './bundle.js';
85
87
  // ============================================================================
86
88
  // 外盘捆绑交易(DEX Bundle)
87
89
  // ============================================================================
@@ -166,6 +168,15 @@ export const xlayer = {
166
168
  // 捆绑换手(AA):仅签名(raw signed tx)
167
169
  bundleSwapSign: async (...args) => bundleSwapSign(...args),
168
170
  bundleBatchSwapSign: async (...args) => bundleBatchSwapSign(...args),
171
+ // 预授权(一键授权)
172
+ bundlePreApprove: async (...args) => {
173
+ const { bundlePreApprove } = await import('./bundle.js');
174
+ return bundlePreApprove(...args);
175
+ },
176
+ checkApprovalStatus: async (...args) => {
177
+ const { checkApprovalStatus } = await import('./bundle.js');
178
+ return checkApprovalStatus(...args);
179
+ },
169
180
  // 刷量
170
181
  makeVolume: async (...args) => {
171
182
  const { makeVolume } = await import('./volume.js');
@@ -565,8 +565,6 @@ export interface BundleBuyResult {
565
565
  * 捆绑卖出结果
566
566
  */
567
567
  export interface BundleSellResult {
568
- /** 授权交易结果(如果需要) */
569
- approveResult?: HandleOpsResult;
570
568
  /** 卖出交易结果 */
571
569
  sellResult: HandleOpsResult;
572
570
  /** 归集交易结果(如果 withdrawToOwner) */
@@ -588,8 +586,6 @@ export interface BundleSellResult {
588
586
  export interface BundleBuySellResult {
589
587
  /** 买入阶段结果 */
590
588
  buyResult: HandleOpsResult;
591
- /** 授权阶段结果(如果需要) */
592
- approveResult?: HandleOpsResult;
593
589
  /** 卖出阶段结果 */
594
590
  sellResult: HandleOpsResult;
595
591
  /** 归集阶段结果(如果 withdrawToOwner) */
@@ -699,6 +695,58 @@ export interface DexSwapResult {
699
695
  outputAmount: bigint;
700
696
  gasUsed: bigint;
701
697
  }
698
+ /**
699
+ * 预授权参数
700
+ * 用于提前授权代币,避免在交易时等待授权确认
701
+ */
702
+ export interface BundlePreApproveParams {
703
+ /** 代币地址 */
704
+ tokenAddress: string;
705
+ /** Owner 私钥列表 */
706
+ privateKeys: string[];
707
+ /** 授权目标(默认 FLAP_PORTAL,可传 Router 地址用于外盘交易) */
708
+ spender?: string;
709
+ /**
710
+ * 是否仅签名(不执行)
711
+ * - true: 返回签名后的 handleOps 交易,由前端发送到服务端广播
712
+ * - false(默认): 直接执行 handleOps
713
+ */
714
+ signOnly?: boolean;
715
+ /** 配置覆盖 */
716
+ config?: Partial<XLayerConfig>;
717
+ /** Payer 私钥(signOnly=true 时必传,用于支付 gas) */
718
+ payerPrivateKey?: string;
719
+ }
720
+ /**
721
+ * 预授权结果
722
+ */
723
+ export interface BundlePreApproveResult {
724
+ /** 发送授权交易的数量 */
725
+ approvedCount: number;
726
+ /** 已经授权无需操作的数量 */
727
+ alreadyApprovedCount: number;
728
+ /** 授权交易结果(signOnly=false 时有值) */
729
+ approveResult?: HandleOpsResult;
730
+ /** 每个地址的授权状态详情 */
731
+ details: ApprovalStatusResult[];
732
+ /** signOnly=true 时:签名后的 handleOps 交易(raw signed tx) */
733
+ signedTransactions?: string[];
734
+ }
735
+ /**
736
+ * 授权状态检查结果
737
+ */
738
+ export interface ApprovalStatusResult {
739
+ /** Owner EOA 地址 */
740
+ owner: string;
741
+ /** AA Sender 地址 */
742
+ sender: string;
743
+ /** 是否已授权(授权额度 >= 代币余额) */
744
+ isApproved: boolean;
745
+ /** 当前授权额度 */
746
+ currentAllowance: bigint;
747
+ /** 当前代币余额 */
748
+ tokenBalance: bigint;
749
+ }
702
750
  /**
703
751
  * 深度 Partial 类型
704
752
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.38",
3
+ "version": "1.5.40",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",