four-flap-meme-sdk 1.5.36 → 1.5.38

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.
@@ -8,7 +8,7 @@
8
8
  * - OKB 归集:将 sender 的 OKB 转回 owner
9
9
  */
10
10
  import { Wallet, Interface, Contract, ethers } from 'ethers';
11
- import { FLAP_PORTAL, ENTRYPOINT_ABI, DEFAULT_CALL_GAS_LIMIT_SELL, DEFAULT_WITHDRAW_RESERVE, } from './constants.js';
11
+ import { FLAP_PORTAL, ENTRYPOINT_ABI, PORTAL_ABI, DEFAULT_CALL_GAS_LIMIT_SELL, DEFAULT_WITHDRAW_RESERVE, } from './constants.js';
12
12
  import { AAAccountManager, encodeExecute, encodeExecuteBatch } from './aa-account.js';
13
13
  import { encodeBuyCall, encodeSellCall, encodeApproveCall, encodeTransferCall, encodeCreateCallV2, encodeCreateCallV3, encodeCreateCallV4, PortalQuery, parseOkb, formatOkb, } from './portal-ops.js';
14
14
  import { mapWithConcurrency } from '../utils/concurrency.js';
@@ -1247,21 +1247,47 @@ export class BundleExecutor {
1247
1247
  const signedDevOp = await this.aaManager.signUserOp(devCreateOp.userOp, devWallet);
1248
1248
  ops.push(signedDevOp.userOp);
1249
1249
  // 2b. Buyers 买入
1250
+ const profitSettings = resolveProfitSettings(effConfig);
1251
+ const inputToken = params.quoteToken && params.quoteToken !== ZERO_ADDRESS ? params.quoteToken : ZERO_ADDRESS;
1252
+ const useNativeToken = inputToken === ZERO_ADDRESS;
1253
+ // BundleCreateBuyParams 目前没有 quoteTokenDecimals,默认用 18
1254
+ const quoteDecimals = 18;
1250
1255
  let totalBuyWei = 0n;
1256
+ let totalBuyProfitWei = 0n; // inputToken 本位利润
1251
1257
  const buyerSenders = [];
1258
+ const profitWeis = [];
1259
+ const portalIface = new Interface(PORTAL_ABI);
1252
1260
  for (let i = 0; i < buyerWallets.length; i++) {
1253
1261
  const buyer = buyerWallets[i];
1254
- const amount = buyAmounts[i] || '0';
1255
- const amountWei = parseOkb(amount);
1256
- totalBuyWei += amountWei;
1262
+ const amountStr = buyAmounts[i] || '0';
1263
+ const originalWei = useNativeToken ? parseOkb(amountStr) : ethers.parseUnits(amountStr, quoteDecimals);
1264
+ let buyWei = originalWei;
1265
+ let profitWei = 0n;
1266
+ if (profitSettings.extractProfit) {
1267
+ const res = calculateProfit(originalWei, profitSettings.profitBps);
1268
+ buyWei = res.remaining;
1269
+ profitWei = res.profit;
1270
+ }
1271
+ totalBuyWei += buyWei;
1272
+ totalBuyProfitWei += profitWei;
1273
+ profitWeis.push(profitWei);
1257
1274
  const buyerAccount = await this.aaManager.getAccountInfo(buyer.address);
1258
1275
  buyerSenders.push(buyerAccount.sender);
1259
1276
  nonceMap.init(buyerAccount.sender, buyerAccount.nonce);
1260
- const buyData = encodeBuyCall(tokenAddress, amountWei, 0n);
1277
+ // 买入:使用扣除利润后的金额
1278
+ const swapData = portalIface.encodeFunctionData('swapExactInput', [
1279
+ {
1280
+ inputToken,
1281
+ outputToken: tokenAddress,
1282
+ inputAmount: buyWei,
1283
+ minOutputAmount: 0n,
1284
+ permitData: '0x',
1285
+ },
1286
+ ]);
1261
1287
  const buyOp = await this.aaManager.buildUserOpWithFixedGas({
1262
1288
  ownerWallet: buyer,
1263
1289
  sender: buyerAccount.sender,
1264
- callData: encodeExecute(this.portalAddress, amountWei, buyData),
1290
+ callData: encodeExecute(this.portalAddress, useNativeToken ? buyWei : 0n, swapData),
1265
1291
  nonce: nonceMap.next(buyerAccount.sender),
1266
1292
  initCode: buyerAccount.deployed ? '0x' : this.aaManager.generateInitCode(buyer.address),
1267
1293
  deployed: buyerAccount.deployed
@@ -1269,6 +1295,49 @@ export class BundleExecutor {
1269
1295
  const signedBuyOp = await this.aaManager.signUserOp(buyOp.userOp, buyer);
1270
1296
  ops.push(signedBuyOp.userOp);
1271
1297
  }
1298
+ // ✅ 刮取利润:折算并转账(SignOnly 模式也需要包含此 UserOp)
1299
+ if (profitSettings.extractProfit && totalBuyProfitWei > 0n) {
1300
+ // 1. 获取 OKB 报价(SignOnly 模式也需要这个报价来决定最终转账金额)
1301
+ let nativeProfitAmount = totalBuyProfitWei;
1302
+ if (!useNativeToken) {
1303
+ try {
1304
+ const dq = new DexQuery(effConfig);
1305
+ nativeProfitAmount = await dq.quoteTokenToOkb(totalBuyProfitWei, inputToken);
1306
+ }
1307
+ catch {
1308
+ try {
1309
+ const pq = this.portalQuery;
1310
+ nativeProfitAmount = await pq.quoteExactInput(inputToken, ZERO_ADDRESS, totalBuyProfitWei);
1311
+ }
1312
+ catch {
1313
+ nativeProfitAmount = 0n;
1314
+ }
1315
+ }
1316
+ }
1317
+ if (nativeProfitAmount > 0n) {
1318
+ console.log(`[利润提取-签名] 总利润: ${useNativeToken ? formatOkb(nativeProfitAmount) : `${formatOkb(totalBuyProfitWei)} (ERC20) -> ${formatOkb(nativeProfitAmount)} (OKB)`} -> ${profitSettings.profitRecipient}`);
1319
+ // 找到利润贡献最大的买家作为利润转账的 sender
1320
+ const maxProfitIndex = profitWeis.reduce((maxIdx, p, idx) => p > (profitWeis[maxIdx] ?? 0n) ? idx : maxIdx, 0);
1321
+ const pOwner = buyerWallets[maxProfitIndex];
1322
+ const pSender = buyerSenders[maxProfitIndex];
1323
+ // 利润转账:直接转 OKB(对齐 bundleBuy 语义)
1324
+ const profitCallData = encodeExecute(profitSettings.profitRecipient, nativeProfitAmount, '0x');
1325
+ const profitOp = await this.aaManager.buildUserOpWithFixedGas({
1326
+ ownerWallet: pOwner,
1327
+ sender: pSender,
1328
+ callData: profitCallData,
1329
+ nonce: nonceMap.next(pSender),
1330
+ initCode: '0x', // 之前买入阶段已处理 initCode
1331
+ deployed: true,
1332
+ fixedGas: {
1333
+ ...(effConfig.fixedGas ?? {}),
1334
+ callGasLimit: effConfig.fixedGas?.callGasLimit ?? DEFAULT_CALL_GAS_LIMIT_WITHDRAW,
1335
+ }
1336
+ });
1337
+ const signedProfitOp = await this.aaManager.signUserOp(profitOp.userOp, pOwner);
1338
+ ops.push(signedProfitOp.userOp);
1339
+ }
1340
+ }
1272
1341
  // 3. 签名 handleOps 交易
1273
1342
  const signedTx = await this.signHandleOpsTx({
1274
1343
  ops,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.36",
3
+ "version": "1.5.38",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",