four-flap-meme-sdk 1.5.82 → 1.5.84

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.
@@ -1551,24 +1551,33 @@ export class BundleExecutor {
1551
1551
  * 自动计算剩余毕业容量,将钱包分为内盘和外盘组,生成签名的交易列表
1552
1552
  */
1553
1553
  async bundleGraduateBuy(params) {
1554
- const { tokenAddress, privateKeys, payerPrivateKey, amountMode, totalBuyAmount, minAmount, maxAmount, walletAmounts, enableDexBuy = false, config = {} } = params;
1554
+ const { tokenAddress, privateKeys, payerPrivateKey, amountMode, totalBuyAmount, minAmount, maxAmount, walletAmounts, enableDexBuy = false, config = {}, graduationAmount, curveAddresses, dexAddresses } = params;
1555
1555
  const aaManager = this.getAAManager();
1556
1556
  const provider = aaManager.getProvider();
1557
1557
  // 1. 获取代币状态,动态计算毕业容量
1558
1558
  const tokenState = await this.portalQuery.getTokenV7(tokenAddress);
1559
- // ✅ 内联曲线公式计算毕业容量 (CDPV2)
1560
- // 储备量 R = k / (10亿 + h - 供应量 S) - r
1561
- const r = tokenState.r; // 衰减因子
1562
- const h = tokenState.h; // 初始高度
1563
- const k = tokenState.k; // 缩放系数
1564
- const dexSupplyThresh = tokenState.dexSupplyThresh;
1565
- const BILLION_WEI = 1000000000n * 10n ** 18n;
1566
- const denom = BILLION_WEI + h - dexSupplyThresh;
1567
- const graduationReserveWei = denom > 0n ? (k * 10n ** 18n) / denom - r : 0n;
1559
+ // ✅ 使用 progress (uint256, 1e18) 计算毕业储备量,这是最可靠的方式
1560
+ let graduationReserveWei = 0n;
1561
+ if (tokenState.status === 4) {
1562
+ graduationReserveWei = tokenState.reserve;
1563
+ }
1564
+ else if (tokenState.progress > 0n) {
1565
+ // graduationReserve = currentReserve / progress
1566
+ graduationReserveWei = (tokenState.reserve * 10n ** 18n) / tokenState.progress;
1567
+ }
1568
+ else {
1569
+ // 如果 progress 为 0 (刚开始),回退到曲线公式
1570
+ const BILLION_WEI = 1000000000n * 10n ** 18n;
1571
+ const denom = BILLION_WEI + tokenState.h - tokenState.dexSupplyThresh;
1572
+ graduationReserveWei = denom > 0n ? (tokenState.k * 10n ** 18n) / denom - tokenState.r : 0n;
1573
+ }
1568
1574
  // 剩余毕业金额 = 毕业阈值 - 当前储备(加 1.6% 手续费缓冲以覆盖 1.5% 平台费)
1569
- const remainingToGraduateWei = (tokenState.status === 4 || graduationReserveWei <= tokenState.reserve)
1570
- ? 0n
1571
- : ((graduationReserveWei - tokenState.reserve) * 1016n / 1000n);
1575
+ // 优先使用前端传入的 graduationAmount
1576
+ const remainingToGraduateWei = graduationAmount !== undefined
1577
+ ? ethers.parseEther(graduationAmount.toString())
1578
+ : ((tokenState.status === 4 || graduationReserveWei <= tokenState.reserve)
1579
+ ? 0n
1580
+ : ((graduationReserveWei - tokenState.reserve) * 1016n / 1000n));
1572
1581
  const graduationReserveStr = ethers.formatEther(graduationReserveWei);
1573
1582
  const poolReserveOkbStr = ethers.formatEther(tokenState.reserve);
1574
1583
  const remainingStr = ethers.formatEther(remainingToGraduateWei);
@@ -1605,71 +1614,111 @@ export class BundleExecutor {
1605
1614
  const amountWei = ethers.parseEther(finalAmounts[i].toFixed(18));
1606
1615
  const tasks = [];
1607
1616
  let isTrigger = false;
1608
- if (currentCurveTotal < remainingToGraduateWei) {
1609
- const needed = remainingToGraduateWei - currentCurveTotal;
1610
- if (amountWei <= needed) {
1611
- // 情况 A:全在内盘
1612
- tasks.push({
1613
- target: FLAP_PORTAL,
1614
- amount: amountWei,
1615
- data: encodeBuyCall(tokenAddress, amountWei, 0n)
1616
- });
1617
- currentCurveTotal += amountWei;
1618
- if (currentCurveTotal >= remainingToGraduateWei)
1619
- isTrigger = true;
1620
- }
1621
- else {
1622
- // 情况 B:跨内外盘(原子化拆分)
1623
- tasks.push({
1624
- target: FLAP_PORTAL,
1625
- amount: needed,
1626
- data: encodeBuyCall(tokenAddress, needed, 0n)
1627
- });
1628
- isTrigger = true; // 肯定是毕业触发者
1629
- currentCurveTotal = remainingToGraduateWei;
1630
- if (enableDexBuy) {
1631
- const excess = amountWei - needed;
1632
- const dexType = (tokenState.lpFeeProfile >= 0 && tokenState.tokenVersion >= 4) ? 'V3' : 'V2';
1633
- const deadline = Math.floor(Date.now() / 1000) + 1200;
1634
- let swapData;
1635
- let routerAddress;
1636
- if (dexType === 'V3') {
1637
- routerAddress = POTATOSWAP_V3_ROUTER;
1638
- swapData = encodeSwapExactETHForTokensV3({
1639
- tokenIn: WOKB, tokenOut: tokenAddress,
1640
- fee: lpFeeProfileToV3Fee(tokenState.lpFeeProfile),
1641
- recipient: ZERO_ADDRESS, // AA 内部 call,最终由 execute/executeBatch 决定 recipient
1642
- deadline, amountIn: excess, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n
1643
- });
1644
- }
1645
- else {
1646
- routerAddress = POTATOSWAP_V2_ROUTER;
1647
- swapData = encodeSwapExactETHForTokensSupportingFee(0n, [WOKB, tokenAddress], ZERO_ADDRESS, deadline);
1648
- }
1649
- tasks.push({ target: routerAddress, amount: excess, data: swapData });
1617
+ // 优先判断地址分组(由前端强制指定)
1618
+ const forceCurve = curveAddresses?.some(a => a.toLowerCase() === wallet.address.toLowerCase());
1619
+ const forceDex = dexAddresses?.some(a => a.toLowerCase() === wallet.address.toLowerCase());
1620
+ if (forceCurve) {
1621
+ // 强制内盘
1622
+ tasks.push({
1623
+ target: FLAP_PORTAL,
1624
+ amount: amountWei,
1625
+ data: encodeBuyCall(tokenAddress, amountWei, 0n)
1626
+ });
1627
+ currentCurveTotal += amountWei;
1628
+ if (currentCurveTotal >= remainingToGraduateWei)
1629
+ isTrigger = true;
1630
+ }
1631
+ else if (forceDex) {
1632
+ // 强制外盘
1633
+ if (enableDexBuy) {
1634
+ const dexType = (tokenState.lpFeeProfile >= 0 && tokenState.tokenVersion >= 4) ? 'V3' : 'V2';
1635
+ const deadline = Math.floor(Date.now() / 1000) + 1200;
1636
+ let swapData;
1637
+ let routerAddress;
1638
+ if (dexType === 'V3') {
1639
+ routerAddress = POTATOSWAP_V3_ROUTER;
1640
+ swapData = encodeSwapExactETHForTokensV3({
1641
+ tokenIn: WOKB, tokenOut: tokenAddress,
1642
+ fee: lpFeeProfileToV3Fee(tokenState.lpFeeProfile),
1643
+ recipient: ZERO_ADDRESS,
1644
+ deadline, amountIn: amountWei, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n
1645
+ });
1646
+ }
1647
+ else {
1648
+ routerAddress = POTATOSWAP_V2_ROUTER;
1649
+ swapData = encodeSwapExactETHForTokensSupportingFee(0n, [WOKB, tokenAddress], ZERO_ADDRESS, deadline);
1650
1650
  }
1651
+ tasks.push({ target: routerAddress, amount: amountWei, data: swapData });
1651
1652
  }
1652
1653
  }
1653
- else if (enableDexBuy) {
1654
- // 情况 C:全在外盘
1655
- const dexType = (tokenState.lpFeeProfile >= 0 && tokenState.tokenVersion >= 4) ? 'V3' : 'V2';
1656
- const deadline = Math.floor(Date.now() / 1000) + 1200;
1657
- let swapData;
1658
- let routerAddress;
1659
- if (dexType === 'V3') {
1660
- routerAddress = POTATOSWAP_V3_ROUTER;
1661
- swapData = encodeSwapExactETHForTokensV3({
1662
- tokenIn: WOKB, tokenOut: tokenAddress,
1663
- fee: lpFeeProfileToV3Fee(tokenState.lpFeeProfile),
1664
- recipient: ZERO_ADDRESS,
1665
- deadline, amountIn: amountWei, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n
1666
- });
1654
+ else {
1655
+ // 兜底逻辑:自动分配 (无强制分组)
1656
+ if (currentCurveTotal < remainingToGraduateWei) {
1657
+ const needed = remainingToGraduateWei - currentCurveTotal;
1658
+ if (amountWei <= needed) {
1659
+ // 情况 A:全在内盘
1660
+ tasks.push({
1661
+ target: FLAP_PORTAL,
1662
+ amount: amountWei,
1663
+ data: encodeBuyCall(tokenAddress, amountWei, 0n)
1664
+ });
1665
+ currentCurveTotal += amountWei;
1666
+ if (currentCurveTotal >= remainingToGraduateWei)
1667
+ isTrigger = true;
1668
+ }
1669
+ else {
1670
+ // 情况 B:跨内外盘(原子化拆分)
1671
+ tasks.push({
1672
+ target: FLAP_PORTAL,
1673
+ amount: needed,
1674
+ data: encodeBuyCall(tokenAddress, needed, 0n)
1675
+ });
1676
+ isTrigger = true;
1677
+ currentCurveTotal = remainingToGraduateWei;
1678
+ if (enableDexBuy) {
1679
+ const excess = amountWei - needed;
1680
+ const dexType = (tokenState.lpFeeProfile >= 0 && tokenState.tokenVersion >= 4) ? 'V3' : 'V2';
1681
+ const deadline = Math.floor(Date.now() / 1000) + 1200;
1682
+ let swapData;
1683
+ let routerAddress;
1684
+ if (dexType === 'V3') {
1685
+ routerAddress = POTATOSWAP_V3_ROUTER;
1686
+ swapData = encodeSwapExactETHForTokensV3({
1687
+ tokenIn: WOKB, tokenOut: tokenAddress,
1688
+ fee: lpFeeProfileToV3Fee(tokenState.lpFeeProfile),
1689
+ recipient: ZERO_ADDRESS,
1690
+ deadline, amountIn: excess, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n
1691
+ });
1692
+ }
1693
+ else {
1694
+ routerAddress = POTATOSWAP_V2_ROUTER;
1695
+ swapData = encodeSwapExactETHForTokensSupportingFee(0n, [WOKB, tokenAddress], ZERO_ADDRESS, deadline);
1696
+ }
1697
+ tasks.push({ target: routerAddress, amount: excess, data: swapData });
1698
+ }
1699
+ }
1667
1700
  }
1668
- else {
1669
- routerAddress = POTATOSWAP_V2_ROUTER;
1670
- swapData = encodeSwapExactETHForTokensSupportingFee(0n, [WOKB, tokenAddress], ZERO_ADDRESS, deadline);
1701
+ else if (enableDexBuy) {
1702
+ // 情况 C:全在外盘
1703
+ const dexType = (tokenState.lpFeeProfile >= 0 && tokenState.tokenVersion >= 4) ? 'V3' : 'V2';
1704
+ const deadline = Math.floor(Date.now() / 1000) + 1200;
1705
+ let swapData;
1706
+ let routerAddress;
1707
+ if (dexType === 'V3') {
1708
+ routerAddress = POTATOSWAP_V3_ROUTER;
1709
+ swapData = encodeSwapExactETHForTokensV3({
1710
+ tokenIn: WOKB, tokenOut: tokenAddress,
1711
+ fee: lpFeeProfileToV3Fee(tokenState.lpFeeProfile),
1712
+ recipient: ZERO_ADDRESS,
1713
+ deadline, amountIn: amountWei, amountOutMinimum: 0n, sqrtPriceLimitX96: 0n
1714
+ });
1715
+ }
1716
+ else {
1717
+ routerAddress = POTATOSWAP_V2_ROUTER;
1718
+ swapData = encodeSwapExactETHForTokensSupportingFee(0n, [WOKB, tokenAddress], ZERO_ADDRESS, deadline);
1719
+ }
1720
+ tasks.push({ target: routerAddress, amount: amountWei, data: swapData });
1671
1721
  }
1672
- tasks.push({ target: routerAddress, amount: amountWei, data: swapData });
1673
1722
  }
1674
1723
  if (tasks.length > 0) {
1675
1724
  buyerTasks.push({ wallet, calls: tasks, isGraduationTrigger: isTrigger });
@@ -69,7 +69,7 @@ export declare const ENTRYPOINT_ABI: readonly ["function getNonce(address sender
69
69
  /** SimpleAccount ABI */
70
70
  export declare const SIMPLE_ACCOUNT_ABI: readonly ["function execute(address dest, uint256 value, bytes func) external", "function executeBatch(address[] calldata dest, bytes[] calldata func) external", "function executeBatch(address[] calldata dest, uint256[] calldata values, bytes[] calldata func) external"];
71
71
  /** Flap Portal ABI */
72
- export declare const PORTAL_ABI: readonly ["function swapExactInput((address inputToken,address outputToken,uint256 inputAmount,uint256 minOutputAmount,bytes permitData) params) payable returns (uint256)", "function buy(address token, address to, uint256 minAmount) external payable returns (uint256)", "function sell(address token, uint256 amount, uint256 minEth) external returns (uint256)", "function quoteExactInput((address inputToken,address outputToken,uint256 inputAmount)) external returns (uint256)", "function previewBuy(address token, uint256 ethAmount) external view returns (uint256)", "function previewSell(address token, uint256 tokenAmount) external view returns (uint256)", "function getTokenV5(address token) external view returns ((uint8,uint256,uint256,uint256,uint8,uint256,uint256,uint256,uint256,address,bool,bytes32))", "function getTokenV7(address token) external view returns ((uint8,uint256,uint256,uint256,uint8,uint256,uint256,uint256,uint256,address,bool,bytes32,uint8,uint8))", "function newTokenV2((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData) params) external payable returns (address)", "function newTokenV3((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData) params) external payable returns (address)", "function newTokenV4((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData,uint8 dexId,uint8 lpFeeProfile) params) external payable returns (address)"];
72
+ export declare const PORTAL_ABI: readonly ["function swapExactInput((address inputToken,address outputToken,uint256 inputAmount,uint256 minOutputAmount,bytes permitData) params) payable returns (uint256)", "function buy(address token, address to, uint256 minAmount) external payable returns (uint256)", "function sell(address token, uint256 amount, uint256 minEth) external returns (uint256)", "function quoteExactInput((address inputToken,address outputToken,uint256 inputAmount)) external returns (uint256)", "function previewBuy(address token, uint256 ethAmount) external view returns (uint256)", "function previewSell(address token, uint256 tokenAmount) external view returns (uint256)", "function getTokenV5(address token) external view returns ((uint8,uint256,uint256,uint256,uint8,uint256,uint256,uint256,uint256,address,bool,bytes32))", "function getTokenV7(address token) external view returns ((uint8,uint256,uint256,uint256,uint8,uint256,uint256,uint256,uint256,address,bool,bytes32,uint256,address,uint256,uint8,uint8))", "function newTokenV2((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData) params) external payable returns (address)", "function newTokenV3((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData) params) external payable returns (address)", "function newTokenV4((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData,uint8 dexId,uint8 lpFeeProfile) params) external payable returns (address)"];
73
73
  /** ERC20 ABI */
74
74
  export declare const ERC20_ABI: readonly ["function balanceOf(address account) view returns (uint256)", "function allowance(address owner, address spender) view returns (uint256)", "function approve(address spender, uint256 amount) returns (bool)", "function transfer(address to, uint256 amount) returns (bool)", "function decimals() view returns (uint8)", "function symbol() view returns (string)", "function name() view returns (string)"];
75
75
  /** PotatoSwap V2 Router ABI */
@@ -113,7 +113,7 @@ export const PORTAL_ABI = [
113
113
  'function previewBuy(address token, uint256 ethAmount) external view returns (uint256)',
114
114
  'function previewSell(address token, uint256 tokenAmount) external view returns (uint256)',
115
115
  'function getTokenV5(address token) external view returns ((uint8,uint256,uint256,uint256,uint8,uint256,uint256,uint256,uint256,address,bool,bytes32))',
116
- 'function getTokenV7(address token) external view returns ((uint8,uint256,uint256,uint256,uint8,uint256,uint256,uint256,uint256,address,bool,bytes32,uint8,uint8))',
116
+ 'function getTokenV7(address token) external view returns ((uint8,uint256,uint256,uint256,uint8,uint256,uint256,uint256,uint256,address,bool,bytes32,uint256,address,uint256,uint8,uint8))',
117
117
  'function newTokenV2((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData) params) external payable returns (address)',
118
118
  'function newTokenV3((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData) params) external payable returns (address)',
119
119
  'function newTokenV4((string name,string symbol,string meta,uint8 dexThresh,bytes32 salt,uint16 taxRate,uint8 migratorType,address quoteToken,uint256 quoteAmt,address beneficiary,bytes permitData,bytes32 extensionID,bytes extensionData,uint8 dexId,uint8 lpFeeProfile) params) external payable returns (address)',
@@ -181,8 +181,11 @@ export declare class PortalQuery {
181
181
  quoteTokenAddress: string;
182
182
  nativeToQuoteSwapEnabled: boolean;
183
183
  extensionID: string;
184
- dexId: number;
184
+ taxRate: bigint;
185
+ pool: string;
186
+ progress: bigint;
185
187
  lpFeeProfile: number;
188
+ dexId: number;
186
189
  }>;
187
190
  /**
188
191
  * 批量获取多个账户的代币余额
@@ -216,8 +216,11 @@ export class PortalQuery {
216
216
  quoteTokenAddress: raw[9],
217
217
  nativeToQuoteSwapEnabled: raw[10],
218
218
  extensionID: raw[11],
219
- dexId: Number(raw[12]),
220
- lpFeeProfile: Number(raw[13]),
219
+ taxRate: raw[12],
220
+ pool: raw[13],
221
+ progress: raw[14],
222
+ lpFeeProfile: Number(raw[15]),
223
+ dexId: Number(raw[16]),
221
224
  };
222
225
  }
223
226
  /**
@@ -868,6 +868,12 @@ export interface BundleGraduateBuyParams {
868
868
  payerStartNonce?: number;
869
869
  /** beneficiary(默认 payer 地址) */
870
870
  beneficiary?: string;
871
+ /** 毕业剩余量覆盖 (OKB 数值,不传则自动探测) */
872
+ graduationAmount?: number;
873
+ /** 预设内盘钱包地址列表 (若提供则强制按此分组) */
874
+ curveAddresses?: string[];
875
+ /** 预设外盘钱包地址列表 (若提供则强制按此分组) */
876
+ dexAddresses?: string[];
871
877
  }
872
878
  /**
873
879
  * 捆绑买到毕业签名结果
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "four-flap-meme-sdk",
3
- "version": "1.5.82",
3
+ "version": "1.5.84",
4
4
  "description": "SDK for Flap bonding curve and four.meme TokenManager",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",