four-flap-meme-sdk 4.3.22 → 4.4.0
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/bundle/four-meme/approve-tokenmanager.js +46 -16
- package/dist/bundle/four-meme/core/create-token-quote.d.ts +5 -1
- package/dist/bundle/four-meme/core/create-token-quote.js +29 -4
- package/dist/bundle/four-meme/core/sell-flow.js +3 -3
- package/dist/bundle/four-meme/pancake-proxy/approve.js +47 -10
- package/dist/bundle/four-meme/private/sell.js +2 -10
- package/dist/bundle/four-meme/swap/bundle.js +4 -4
- package/dist/bundle/four-meme/swap-buy-first/multi-wallet.js +25 -8
- package/dist/bundle/four-meme/swap-buy-first/single.js +30 -9
- package/dist/bundle/four-meme/swap-sign-helpers.js +56 -3
- package/dist/bundle/four-meme/utils-sweep/erc20-no-hop.js +18 -7
- package/dist/bundle/four-meme/utils-sweep/with-hops.js +10 -4
- package/dist/bundle/internal.d.ts +5 -0
- package/dist/bundle/internal.js +36 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-quote.js +24 -8
- package/dist/chains/bsc/pancake/bundle-buy-first-types.d.ts +2 -0
- package/dist/chains/bsc/pancake/bundle-buy-first-validate.d.ts +1 -1
- package/dist/chains/bsc/pancake/bundle-buy-first-validate.js +2 -2
- package/dist/chains/bsc/pancake/bundle-buy-first.js +1 -0
- package/dist/chains/bsc/pancake/bundle-swap-types.d.ts +2 -0
- package/dist/chains/bsc/pancake/quote.d.ts +7 -0
- package/dist/chains/bsc/pancake/quote.js +9 -1
- package/dist/chains/bsc/pancake/swap-batch.js +15 -16
- package/dist/chains/bsc/pancake/swap-build.d.ts +1 -1
- package/dist/chains/bsc/pancake/swap-build.js +15 -9
- package/dist/chains/bsc/pancake/swap-quick.js +4 -4
- package/dist/chains/bsc/pancake/swap-single.js +1 -0
- package/dist/chains/bsc/platforms/iro/token.d.ts +1 -0
- package/dist/chains/bsc/platforms/iro/token.js +36 -1
- package/dist/chains/eni/batch-router/transfer-sweep.js +10 -14
- package/dist/chains/eni/platforms/daoaas/graduation.js +60 -14
- package/dist/chains/eni/platforms/daoaas/meta.d.ts +0 -4
- package/dist/chains/eni/platforms/daoaas/meta.js +112 -27
- package/dist/chains/eni/platforms/daoaas/portal-direct-submit.js +11 -6
- package/dist/chains/eni/platforms/daoaas/portal-direct-tx.js +4 -2
- package/dist/chains/eni/platforms/daoaas/portal.d.ts +5 -0
- package/dist/chains/eni/platforms/daoaas/portal.js +63 -9
- package/dist/chains/eni/platforms/dswap/liquidity.js +144 -49
- package/dist/chains/eni/platforms/fair-launch/launcher.js +2 -10
- package/dist/chains/eni/platforms/fair-launch/pool.d.ts +1 -0
- package/dist/chains/eni/platforms/fair-launch/pool.js +16 -2
- package/dist/chains/eni/platforms/iro/token.d.ts +1 -0
- package/dist/chains/eni/platforms/iro/token.js +36 -1
- package/dist/chains/robinhood/pons-v2/launch.js +49 -18
- package/dist/chains/xlayer/eip7702/bundle-approve.js +8 -8
- package/dist/chains/xlayer/eip7702/bundle-sell.js +3 -4
- package/dist/chains/xlayer/eip7702/bundle-swap-batch.js +4 -2
- package/dist/chains/xlayer/eip7702/bundle-swap-multi.js +3 -3
- package/dist/chains/xlayer/eip7702/multi-hop-transfer-sweep.js +4 -10
- package/dist/chains/xlayer/eip7702/volume-bundle.js +45 -24
- package/dist/chains/xlayer/eoa/eoa-wash-volume.js +4 -14
- package/dist/core/quote/quote-helpers.d.ts +11 -0
- package/dist/core/quote/quote-helpers.js +121 -20
- package/dist/core/quote/quote-helpers.test.js +11 -1
- package/dist/domains/dex/direct-router-v2-buy.js +4 -2
- package/dist/domains/dex/direct-router-v2-sell.js +63 -12
- package/dist/domains/dex/direct-router-v3.js +3 -4
- package/dist/domains/dex/quote.js +15 -5
- package/dist/domains/flap/portal-bundle-merkle/pancake-proxy/approve.js +48 -8
- package/dist/domains/flap/portal-bundle-merkle/swap-batch.js +8 -10
- package/dist/domains/flap/portal-bundle-merkle/swap-buy-first-quote.js +24 -9
- package/dist/domains/flap/portal-bundle-merkle/swap-planning.js +6 -2
- package/dist/domains/flap/portal-bundle-merkle/utils/sweep.js +14 -7
- package/dist/domains/flap/reader.d.ts +6 -0
- package/dist/domains/flap/reader.js +77 -1
- package/dist/domains/four/contracts/tm-bundle-batch.js +2 -10
- package/dist/domains/four/contracts/tm-bundle-create.js +5 -2
- package/dist/domains/four/contracts/tm.d.ts +2 -0
- package/dist/domains/four/contracts/tm.js +59 -2
- package/dist/domains/four/tax-token.js +60 -28
- package/dist/domains/lp-inspect/inspect-tax.js +98 -12
- package/dist/domains/lp-inspect/inspect.js +57 -44
- package/dist/domains/lp-inspect/registry.js +33 -7
- package/dist/domains/openfour/registry.js +15 -5
- package/dist/utils/airdrop-sweep.js +37 -17
- package/dist/utils/swap-helpers.js +35 -7
- package/package.json +1 -1
package/dist/bundle/internal.js
CHANGED
|
@@ -93,6 +93,42 @@ export async function batchGetBalances(provider, addresses, tokenAddress, chainI
|
|
|
93
93
|
return Promise.all(fallbackCalls);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
+
/** 同一批地址的 ERC20 余额和原生币余额,一次 aggregate3。 */
|
|
97
|
+
export async function batchGetTokenAndNativeBalances(provider, addresses, tokenAddress, chainId) {
|
|
98
|
+
if (addresses.length === 0)
|
|
99
|
+
return { token: [], native: [] };
|
|
100
|
+
const resolvedChainId = chainId ?? Number((await provider.getNetwork()).chainId);
|
|
101
|
+
const multicall3Address = getMulticall3Address(resolvedChainId);
|
|
102
|
+
const erc20 = new ethers.Interface(['function balanceOf(address) view returns (uint256)']);
|
|
103
|
+
const nativeIface = new ethers.Interface(MULTICALL3_ABI);
|
|
104
|
+
const calls = [
|
|
105
|
+
...addresses.map((addr) => ({
|
|
106
|
+
target: tokenAddress,
|
|
107
|
+
allowFailure: true,
|
|
108
|
+
callData: erc20.encodeFunctionData('balanceOf', [addr]),
|
|
109
|
+
})),
|
|
110
|
+
...addresses.map((addr) => ({
|
|
111
|
+
target: multicall3Address,
|
|
112
|
+
allowFailure: true,
|
|
113
|
+
callData: nativeIface.encodeFunctionData('getEthBalance', [addr]),
|
|
114
|
+
})),
|
|
115
|
+
];
|
|
116
|
+
try {
|
|
117
|
+
const multicall = new ethers.Contract(multicall3Address, MULTICALL3_ABI, provider);
|
|
118
|
+
const results = (await multicall.aggregate3(calls));
|
|
119
|
+
return {
|
|
120
|
+
token: mapAggregate3Results(results.slice(0, addresses.length), (returnData) => erc20.decodeFunctionResult('balanceOf', returnData)[0], 0n),
|
|
121
|
+
native: mapAggregate3Results(results.slice(addresses.length), (returnData) => nativeIface.decodeFunctionResult('getEthBalance', returnData)[0], 0n),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
const [token, native] = await Promise.all([
|
|
126
|
+
batchGetBalances(provider, addresses, tokenAddress, resolvedChainId),
|
|
127
|
+
batchGetBalances(provider, addresses, undefined, resolvedChainId),
|
|
128
|
+
]);
|
|
129
|
+
return { token, native };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
96
132
|
export async function estimateErc20TransferGas(provider, tokenAddress, from, to, amount, bufferPercent = 5) {
|
|
97
133
|
try {
|
|
98
134
|
const iface = new ethers.Interface(['function transfer(address,uint256) returns (bool)']);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PancakeSwap Buy-First 报价/资金/上下文 helper(从 bundle-buy-first-helpers.ts 抽取)
|
|
3
3
|
*/
|
|
4
|
-
import { ethers
|
|
4
|
+
import { ethers } from 'ethers';
|
|
5
5
|
import { createSignProvider } from '../../../core/sign-context-helpers.js';
|
|
6
6
|
import { CHAINS } from '../../../core/constants/index.js';
|
|
7
|
+
import { batchGetTokenAndNativeBalances } from '../../../bundle/internal.js';
|
|
7
8
|
import { splitAmountByWeight as splitAmount } from '../../../core/amount/split-by-weight.js';
|
|
8
|
-
import { quoteV2, quoteV3 } from '../../../core/quote/quote-helpers.js';
|
|
9
|
+
import { quoteV2, quoteV2ManyAmounts, quoteV3 } from '../../../core/quote/quote-helpers.js';
|
|
9
10
|
import { applyPancakeSlippage, applyTaxBps, pairSameWalletSellAmounts, prefixSumAmounts, sequentialBuyAmountOutMins, sequentialPrefixOutputs, } from './quote.js';
|
|
10
|
-
import { ERC20_BALANCE_OF_ABI } from './bundle-buy-first-constants.js';
|
|
11
11
|
/**
|
|
12
12
|
* 获取 Gas Limit
|
|
13
13
|
*/
|
|
@@ -35,13 +35,14 @@ export async function calculateBuyerFunds({ buyer, buyerFunds, buyerFundsPercent
|
|
|
35
35
|
const reserveGasWei = ethers.parseEther((reserveGas ?? 0.0005).toString());
|
|
36
36
|
// ✅ 根据是否使用原生代币获取不同的余额
|
|
37
37
|
let buyerBalance;
|
|
38
|
+
let buyerNativeBalance = 0n;
|
|
38
39
|
if (useNativeToken) {
|
|
39
40
|
buyerBalance = await buyer.provider.getBalance(buyer.address);
|
|
40
41
|
}
|
|
41
42
|
else {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const paired = await batchGetTokenAndNativeBalances((provider || buyer.provider), [buyer.address], quoteToken, CHAINS.BSC.chainId);
|
|
44
|
+
buyerBalance = paired.token[0] ?? 0n;
|
|
45
|
+
buyerNativeBalance = paired.native[0] ?? 0n;
|
|
45
46
|
}
|
|
46
47
|
let buyerFundsWei;
|
|
47
48
|
if (buyerFunds !== undefined) {
|
|
@@ -78,12 +79,17 @@ export async function calculateBuyerFunds({ buyer, buyerFunds, buyerFundsPercent
|
|
|
78
79
|
throw new Error(`买方代币余额不足: 需要 ${ethers.formatUnits(buyerFundsWei, quoteTokenDecimals)},实际 ${ethers.formatUnits(buyerBalance, quoteTokenDecimals)}`);
|
|
79
80
|
}
|
|
80
81
|
// ✅ ERC20 购买时,还需要检查买方是否有足够 BNB 支付 Gas
|
|
81
|
-
const buyerBnbBalance =
|
|
82
|
+
const buyerBnbBalance = buyerNativeBalance;
|
|
82
83
|
if (buyerBnbBalance < reserveGasWei) {
|
|
83
84
|
throw new Error(`买方 BNB 余额不足 (用于支付 Gas): 需要 ${ethers.formatEther(reserveGasWei)} BNB,实际 ${ethers.formatEther(buyerBnbBalance)} BNB`);
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
buyerFundsWei,
|
|
89
|
+
buyerBalance,
|
|
90
|
+
reserveGas: reserveGasWei,
|
|
91
|
+
nativeBalance: useNativeToken ? undefined : buyerNativeBalance,
|
|
92
|
+
};
|
|
87
93
|
}
|
|
88
94
|
/**
|
|
89
95
|
* ✅ 使用 quote-helpers 统一报价
|
|
@@ -144,6 +150,16 @@ export function reverseBuyRouteParams(routeParams) {
|
|
|
144
150
|
}
|
|
145
151
|
export async function quotePrefixSequentialOuts(params) {
|
|
146
152
|
const prefixes = prefixSumAmounts(params.amountsWei);
|
|
153
|
+
if (params.routeParams.routeType === 'v2') {
|
|
154
|
+
const path = params.routeParams.v2Path;
|
|
155
|
+
const batched = await quoteV2ManyAmounts(params.provider, path[0], path[path.length - 1], prefixes, 'BSC', params.v2RouterOverride);
|
|
156
|
+
if (batched) {
|
|
157
|
+
if (prefixes.some((sum, index) => sum > 0n && (batched[index] ?? 0n) <= 0n)) {
|
|
158
|
+
throw new Error('V2 报价失败');
|
|
159
|
+
}
|
|
160
|
+
return sequentialPrefixOutputs(batched);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
147
163
|
const prefixQuoted = await Promise.all(prefixes.map(async (sum) => {
|
|
148
164
|
if (sum <= 0n)
|
|
149
165
|
return 0n;
|
|
@@ -105,6 +105,7 @@ export type BuyerFundsResult = {
|
|
|
105
105
|
buyerFundsWei: bigint;
|
|
106
106
|
buyerBalance: bigint;
|
|
107
107
|
reserveGas: bigint;
|
|
108
|
+
nativeBalance?: bigint;
|
|
108
109
|
};
|
|
109
110
|
export type QuoteTokenResult = {
|
|
110
111
|
quotedTokenOut: bigint;
|
|
@@ -170,6 +171,7 @@ export type BalanceValidationParams = {
|
|
|
170
171
|
quoteTokenDecimals?: number;
|
|
171
172
|
provider?: ethers.JsonRpcProvider;
|
|
172
173
|
buyerAddress?: string;
|
|
174
|
+
nativeBalance?: bigint;
|
|
173
175
|
};
|
|
174
176
|
export interface MultiWalletParams {
|
|
175
177
|
buyerPrivateKeys: string[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { BalanceValidationParams } from './bundle-buy-first-types.js';
|
|
2
|
-
export declare function validateFinalBalances({ sameAddress, buyerFundsWei, buyerBalance, reserveGas, gasLimit, gasPrice, useNativeToken, quoteTokenDecimals, provider, buyerAddress, }: BalanceValidationParams): Promise<void>;
|
|
2
|
+
export declare function validateFinalBalances({ sameAddress, buyerFundsWei, buyerBalance, reserveGas, gasLimit, gasPrice, useNativeToken, quoteTokenDecimals, provider, buyerAddress, nativeBalance, }: BalanceValidationParams): Promise<void>;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { ethers } from 'ethers';
|
|
5
5
|
import { FLAT_FEE } from './bundle-buy-first-constants.js';
|
|
6
|
-
export async function validateFinalBalances({ sameAddress, buyerFundsWei, buyerBalance, reserveGas, gasLimit, gasPrice, useNativeToken = true, quoteTokenDecimals = 18, provider, buyerAddress, }) {
|
|
6
|
+
export async function validateFinalBalances({ sameAddress, buyerFundsWei, buyerBalance, reserveGas, gasLimit, gasPrice, useNativeToken = true, quoteTokenDecimals = 18, provider, buyerAddress, nativeBalance, }) {
|
|
7
7
|
const gasCost = gasLimit * gasPrice;
|
|
8
8
|
if (sameAddress) {
|
|
9
9
|
// 同一地址:需要足够的余额支付两笔交易
|
|
@@ -21,7 +21,7 @@ export async function validateFinalBalances({ sameAddress, buyerFundsWei, buyerB
|
|
|
21
21
|
}
|
|
22
22
|
// 检查 BNB Gas
|
|
23
23
|
if (provider && buyerAddress) {
|
|
24
|
-
const bnbBalance = await provider.getBalance(buyerAddress);
|
|
24
|
+
const bnbBalance = nativeBalance ?? (await provider.getBalance(buyerAddress));
|
|
25
25
|
const requiredGas = gasCost * 2n;
|
|
26
26
|
if (bnbBalance < requiredGas) {
|
|
27
27
|
throw new Error(`账户 BNB 余额不足 (用于支付 Gas):\n - 需要: ${ethers.formatEther(requiredGas)} BNB\n - 实际: ${ethers.formatEther(bnbBalance)} BNB`);
|
|
@@ -148,6 +148,7 @@ export async function pancakeBundleBuyFirstMerkle(params) {
|
|
|
148
148
|
quoteTokenDecimals,
|
|
149
149
|
provider: context.provider,
|
|
150
150
|
buyerAddress: buyer.address,
|
|
151
|
+
nativeBalance: buyerFundsInfo.nativeBalance,
|
|
151
152
|
});
|
|
152
153
|
// ✅ 组装顺序:贿赂 → 买入(多笔) → 卖出(多笔)(与 Flap 一致)
|
|
153
154
|
const allTransactions = [];
|
|
@@ -85,6 +85,7 @@ export type BalanceValidationParams = {
|
|
|
85
85
|
quoteTokenDecimals?: number;
|
|
86
86
|
provider?: ethers.JsonRpcProvider;
|
|
87
87
|
buyerAddress?: string;
|
|
88
|
+
nativeBalance?: bigint;
|
|
88
89
|
};
|
|
89
90
|
export interface PancakeSwapSignConfig {
|
|
90
91
|
rpcUrl: string;
|
|
@@ -179,6 +180,7 @@ export type BuyerBudget = {
|
|
|
179
180
|
requiredBalance: bigint;
|
|
180
181
|
buyAmountBNB: bigint;
|
|
181
182
|
useNativeToken: boolean;
|
|
183
|
+
nativeBalance?: bigint;
|
|
182
184
|
};
|
|
183
185
|
export type NoncePlan = {
|
|
184
186
|
sellerNonce: number;
|
|
@@ -41,6 +41,13 @@ export declare function isSameWalletBuySell(buyers: Array<{
|
|
|
41
41
|
* quotedTotal 必须是卖出应得的计价币数量,不能传买入花费。
|
|
42
42
|
*/
|
|
43
43
|
export declare function resolveBuyFirstSellMins(sameWallet: boolean, quotedTotal: bigint, sellAmounts: bigint[], slippageBps?: number): bigint[];
|
|
44
|
+
/** 多笔买入报价。V2 已选定路径时一次 multicall;V3 仍逐笔 eth_call。 */
|
|
45
|
+
export declare function quoteBuyOutputs(params: {
|
|
46
|
+
routeParams: RouteParams;
|
|
47
|
+
buyAmountsWei: readonly bigint[];
|
|
48
|
+
provider: ethers.JsonRpcProvider;
|
|
49
|
+
v2RouterAddress?: string;
|
|
50
|
+
}): Promise<bigint[]>;
|
|
44
51
|
export declare function quoteBuyOutput(params: {
|
|
45
52
|
routeParams: RouteParams;
|
|
46
53
|
buyAmountWei: bigint;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ADDRESSES, applySlippageBps, getProfitRateBps as getSharedProfitRateBps, calculateBundleSwapRoundTripProfit } from '../../../core/constants/index.js';
|
|
2
|
-
import { quoteV2, quoteV3 } from '../../../core/quote/quote-helpers.js';
|
|
2
|
+
import { QUOTE_CONFIG, quoteV2, quoteV2SamePathAmounts, quoteV3 } from '../../../core/quote/quote-helpers.js';
|
|
3
3
|
import { WBNB_ADDRESS, ZERO_ADDRESS, } from './bundle-swap-types.js';
|
|
4
4
|
function normalizeAddr(addr) {
|
|
5
5
|
return String(addr || '').trim().toLowerCase();
|
|
@@ -102,6 +102,14 @@ export function resolveBuyFirstSellMins(sameWallet, quotedTotal, sellAmounts, sl
|
|
|
102
102
|
return sellAmounts.map(() => 0n);
|
|
103
103
|
return splitQuotedMins(quotedTotal, sellAmounts, slippageBps);
|
|
104
104
|
}
|
|
105
|
+
/** 多笔买入报价。V2 已选定路径时一次 multicall;V3 仍逐笔 eth_call。 */
|
|
106
|
+
export async function quoteBuyOutputs(params) {
|
|
107
|
+
const { routeParams, buyAmountsWei, provider, v2RouterAddress } = params;
|
|
108
|
+
if (routeParams.routeType === 'v2' && routeParams.v2Path.length >= 2) {
|
|
109
|
+
return quoteV2SamePathAmounts(provider, 'BSC', v2RouterAddress || QUOTE_CONFIG.BSC.v2Router, [...routeParams.v2Path].reverse(), buyAmountsWei);
|
|
110
|
+
}
|
|
111
|
+
return Promise.all(buyAmountsWei.map((buyAmountWei) => quoteBuyOutput({ routeParams, buyAmountWei, provider, v2RouterAddress })));
|
|
112
|
+
}
|
|
105
113
|
export async function quoteBuyOutput(params) {
|
|
106
114
|
const { routeParams, buyAmountWei, provider, v2RouterAddress } = params;
|
|
107
115
|
if (buyAmountWei <= 0n)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* swap-batch - 批量换手(一卖多买)
|
|
3
3
|
*/
|
|
4
|
-
import { getProfitRecipient, BLOCKRAZOR_BUILDER_EOA } from '../../../core/constants/index.js';
|
|
4
|
+
import { getProfitRecipient, BLOCKRAZOR_BUILDER_EOA, CHAINS } from '../../../core/constants/index.js';
|
|
5
|
+
import { batchGetBalances } from '../../../bundle/internal.js';
|
|
5
6
|
import { getGasLimit } from '../../../core/gas/bundle-gas.js';
|
|
6
7
|
import { ethers, Contract, Wallet } from 'ethers';
|
|
7
8
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
8
9
|
import { NonceManager, getDeadline, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
9
|
-
import { BRIBE_GAS_LIMIT,
|
|
10
|
+
import { BRIBE_GAS_LIMIT, FLAT_FEE, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, WBNB_ADDRESS, calculateProfitAmount, createPancakeContext, getERC20ToNativeQuote, getGasPrice, grossUpPancakeSellProceedsToBuySide, quoteSellOutput, quoteBuyOutputs, applyPancakeSlippage, resolvePancakeQuoteMode, taxedSellQuoteInput, sequentialBuyAmountOutMins, } from './bundle-swap-helpers.js';
|
|
10
11
|
/**
|
|
11
12
|
* PancakeSwap 批量换手(一卖多买)
|
|
12
13
|
*
|
|
@@ -76,32 +77,30 @@ export async function pancakeBatchSwapMerkle(params) {
|
|
|
76
77
|
}
|
|
77
78
|
// ✅ 并行验证所有买方余额
|
|
78
79
|
const reserveGas = ethers.parseEther((config.reserveGasBNB ?? 0.0005).toString());
|
|
79
|
-
const
|
|
80
|
-
await
|
|
80
|
+
const buyerAddresses = buyers.map((buyer) => buyer.address);
|
|
81
|
+
const buyerBalances = await batchGetBalances(context.provider, buyerAddresses, useNativeToken ? undefined : effectiveQuoteToken, CHAINS.BSC.chainId);
|
|
82
|
+
buyerBalances.forEach((buyerBalance, i) => {
|
|
81
83
|
const buyAmount = buyAmountsWei[i];
|
|
82
84
|
if (useNativeToken) {
|
|
83
|
-
const buyerBalance = await buyer.provider.getBalance(buyer.address);
|
|
84
85
|
const required = buyAmount + FLAT_FEE + reserveGas;
|
|
85
86
|
if (buyerBalance < required) {
|
|
86
87
|
throw new Error(`买方 ${i + 1} 余额不足: 需要 ${ethers.formatEther(required)}, 实际 ${ethers.formatEther(buyerBalance)}`);
|
|
87
88
|
}
|
|
89
|
+
return;
|
|
88
90
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (buyerBalance < required) {
|
|
93
|
-
throw new Error(`买方 ${i + 1} 代币余额不足: 需要 ${ethers.formatUnits(required, quoteTokenDecimals)}, 实际 ${ethers.formatUnits(buyerBalance, quoteTokenDecimals)}`);
|
|
94
|
-
}
|
|
91
|
+
const required = buyAmount + FLAT_FEE;
|
|
92
|
+
if (buyerBalance < required) {
|
|
93
|
+
throw new Error(`买方 ${i + 1} 代币余额不足: 需要 ${ethers.formatUnits(required, quoteTokenDecimals)}, 实际 ${ethers.formatUnits(buyerBalance, quoteTokenDecimals)}`);
|
|
95
94
|
}
|
|
96
|
-
})
|
|
95
|
+
});
|
|
97
96
|
const slippageBps = config.slippageBps ?? 100;
|
|
98
97
|
const sellMinOut = applyPancakeSlippage(estimatedBNBOut, slippageBps);
|
|
99
|
-
const buyQuotedOuts = await
|
|
98
|
+
const buyQuotedOuts = await quoteBuyOutputs({
|
|
100
99
|
routeParams,
|
|
101
|
-
|
|
100
|
+
buyAmountsWei,
|
|
102
101
|
provider: context.provider,
|
|
103
|
-
v2RouterAddress: config.v2RouterAddress,
|
|
104
|
-
})
|
|
102
|
+
v2RouterAddress: config.v2RouterAddress || PANCAKE_V2_ROUTER_ADDRESS,
|
|
103
|
+
});
|
|
105
104
|
const buyMinOuts = sequentialBuyAmountOutMins(buyQuotedOuts, taxRateBps, slippageBps);
|
|
106
105
|
const deadline = getDeadline();
|
|
107
106
|
const v3RouterIface = new ethers.Interface(PANCAKE_V3_ROUTER_ABI);
|
|
@@ -15,5 +15,5 @@ export declare function buildNoncePlanFromNonces(startNonces: number[], sameAddr
|
|
|
15
15
|
* 贿赂和利润由卖方发送
|
|
16
16
|
*/
|
|
17
17
|
export declare function planNonces({ seller, buyer, sameAddress, approvalExists, profitNeeded, needBribeTx, nonceManager, }: PlanNonceParams): Promise<NoncePlan>;
|
|
18
|
-
export declare function validateFinalBalances({ sameAddress, buyerBalance, buyAmountBNB, reserveGas, gasLimit, gasPrice, useNativeToken, quoteTokenDecimals, provider, buyerAddress, }: BalanceValidationParams): Promise<void>;
|
|
18
|
+
export declare function validateFinalBalances({ sameAddress, buyerBalance, buyAmountBNB, reserveGas, gasLimit, gasPrice, useNativeToken, quoteTokenDecimals, provider, buyerAddress, nativeBalance, }: BalanceValidationParams): Promise<void>;
|
|
19
19
|
export declare function countTruthy(values: Array<string | number | bigint | boolean | null | undefined>): number;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ethers, Contract } from 'ethers';
|
|
2
2
|
import { createSignProvider } from '../../../core/sign-context-helpers.js';
|
|
3
3
|
import { CHAINS } from '../../../core/constants/index.js';
|
|
4
|
+
import { batchGetTokenAndNativeBalances } from '../../../bundle/internal.js';
|
|
4
5
|
import { getDeadline } from '../../../utils/bundle-helpers.js';
|
|
5
|
-
import {
|
|
6
|
+
import { FLAT_FEE, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, } from './bundle-swap-types.js';
|
|
6
7
|
export function createPancakeContext(config) {
|
|
7
8
|
const chainId = config.chainId ?? CHAINS.BSC.chainId;
|
|
8
9
|
const provider = createSignProvider(config.rpcUrl, chainId);
|
|
@@ -95,19 +96,24 @@ export async function calculateBuyerBudget({ buyer, quotedBNBOut, reserveGasBNB,
|
|
|
95
96
|
return { buyerBalance, reserveGas, requiredBalance, buyAmountBNB, useNativeToken };
|
|
96
97
|
}
|
|
97
98
|
else {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
const paired = await batchGetTokenAndNativeBalances((provider || buyer.provider), [buyer.address], quoteToken, CHAINS.BSC.chainId);
|
|
100
|
+
buyerBalance = paired.token[0] ?? 0n;
|
|
101
|
+
const buyerBnbBalance = paired.native[0] ?? 0n;
|
|
101
102
|
const requiredBalance = buyAmountBNB + FLAT_FEE; // ERC20 不需要预留 Gas 在代币余额中
|
|
102
103
|
if (buyerBalance < requiredBalance) {
|
|
103
104
|
throw new Error(`买方代币余额不足: 需要 ${ethers.formatUnits(requiredBalance, quoteTokenDecimals)}, 实际 ${ethers.formatUnits(buyerBalance, quoteTokenDecimals)}`);
|
|
104
105
|
}
|
|
105
|
-
// ✅ ERC20 购买时,还需要检查买方是否有足够 BNB 支付 Gas
|
|
106
|
-
const buyerBnbBalance = await buyer.provider.getBalance(buyer.address);
|
|
107
106
|
if (buyerBnbBalance < reserveGas) {
|
|
108
107
|
throw new Error(`买方 BNB 余额不足 (用于支付 Gas): 需要 ${ethers.formatEther(reserveGas)} BNB, 实际 ${ethers.formatEther(buyerBnbBalance)} BNB`);
|
|
109
108
|
}
|
|
110
|
-
return {
|
|
109
|
+
return {
|
|
110
|
+
buyerBalance,
|
|
111
|
+
reserveGas,
|
|
112
|
+
requiredBalance,
|
|
113
|
+
buyAmountBNB,
|
|
114
|
+
useNativeToken,
|
|
115
|
+
nativeBalance: buyerBnbBalance,
|
|
116
|
+
};
|
|
111
117
|
}
|
|
112
118
|
}
|
|
113
119
|
/**
|
|
@@ -176,7 +182,7 @@ export async function planNonces({ seller, buyer, sameAddress, approvalExists, p
|
|
|
176
182
|
]);
|
|
177
183
|
return { sellerNonce, buyerNonce };
|
|
178
184
|
}
|
|
179
|
-
export async function validateFinalBalances({ sameAddress, buyerBalance, buyAmountBNB, reserveGas, gasLimit, gasPrice, useNativeToken = true, quoteTokenDecimals = 18, provider, buyerAddress, }) {
|
|
185
|
+
export async function validateFinalBalances({ sameAddress, buyerBalance, buyAmountBNB, reserveGas, gasLimit, gasPrice, useNativeToken = true, quoteTokenDecimals = 18, provider, buyerAddress, nativeBalance, }) {
|
|
180
186
|
const gasCost = gasLimit * gasPrice;
|
|
181
187
|
if (sameAddress) {
|
|
182
188
|
// 同一地址:需要足够的余额支付两笔交易
|
|
@@ -194,7 +200,7 @@ export async function validateFinalBalances({ sameAddress, buyerBalance, buyAmou
|
|
|
194
200
|
}
|
|
195
201
|
// 检查 BNB Gas
|
|
196
202
|
if (provider && buyerAddress) {
|
|
197
|
-
const bnbBalance = await provider.getBalance(buyerAddress);
|
|
203
|
+
const bnbBalance = nativeBalance ?? (await provider.getBalance(buyerAddress));
|
|
198
204
|
const requiredGas = gasCost * 2n;
|
|
199
205
|
if (bnbBalance < requiredGas) {
|
|
200
206
|
throw new Error(`账户 BNB 余额不足 (用于支付 Gas):\n - 需要: ${ethers.formatEther(requiredGas)} BNB\n - 实际: ${ethers.formatEther(bnbBalance)} BNB`);
|
|
@@ -7,7 +7,7 @@ import { ethers, Contract, Wallet } from 'ethers';
|
|
|
7
7
|
import { calculateSellAmount } from '../../../utils/swap-helpers.js';
|
|
8
8
|
import { NonceManager, buildProfitHopTransactions, PROFIT_HOP_COUNT, } from '../../../utils/bundle-helpers.js';
|
|
9
9
|
import { ERC20_ABI } from '../../../abis/common.js';
|
|
10
|
-
import { BRIBE_GAS_LIMIT, FLAT_FEE, NATIVE_TRANSFER_GAS_LIMIT, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, WBNB_ADDRESS, buildBNBHopChainForERC20, buildERC20HopChain, buildNativeHopChain, calculateProfitAmount, createPancakeContext, generateDisperseHopPaths, getERC20ToNativeQuote, getGasPrice, grossUpPancakeSellProceedsToBuySide, quoteSellOutput,
|
|
10
|
+
import { BRIBE_GAS_LIMIT, FLAT_FEE, NATIVE_TRANSFER_GAS_LIMIT, PANCAKE_V2_ROUTER_ABI, PANCAKE_V2_ROUTER_ADDRESS, PANCAKE_V3_ROUTER_ABI, PANCAKE_V3_ROUTER_ADDRESS, WBNB_ADDRESS, buildBNBHopChainForERC20, buildERC20HopChain, buildNativeHopChain, calculateProfitAmount, createPancakeContext, generateDisperseHopPaths, getERC20ToNativeQuote, getGasPrice, grossUpPancakeSellProceedsToBuySide, quoteSellOutput, quoteBuyOutputs, applyPancakeSlippage, sequentialBuyAmountOutMins, taxedSellQuoteInput, resolvePancakeQuoteMode, } from './bundle-swap-helpers.js';
|
|
11
11
|
/**
|
|
12
12
|
* PancakeSwap 快捷批量换手(资金自动流转)
|
|
13
13
|
*
|
|
@@ -189,12 +189,12 @@ export async function pancakeQuickBatchSwapMerkle(params) {
|
|
|
189
189
|
}
|
|
190
190
|
const slippageBps = config.slippageBps ?? 100;
|
|
191
191
|
const sellMinOut = applyPancakeSlippage(estimatedOutput, slippageBps);
|
|
192
|
-
const buyQuotedOuts = await
|
|
192
|
+
const buyQuotedOuts = await quoteBuyOutputs({
|
|
193
193
|
routeParams,
|
|
194
|
-
|
|
194
|
+
buyAmountsWei: transferAmountsWei,
|
|
195
195
|
provider: context.provider,
|
|
196
196
|
v2RouterAddress: config.v2RouterAddress,
|
|
197
|
-
})
|
|
197
|
+
});
|
|
198
198
|
const buyMinOuts = sequentialBuyAmountOutMins(buyQuotedOuts, taxRateBps, slippageBps);
|
|
199
199
|
// ==================== 规划 Nonce ====================
|
|
200
200
|
// ✅ 如果前端传入了 startNonces,直接使用(性能优化)
|
|
@@ -160,6 +160,7 @@ export async function pancakeBundleSwapMerkle(params) {
|
|
|
160
160
|
quoteTokenDecimals,
|
|
161
161
|
provider: context.provider,
|
|
162
162
|
buyerAddress: buyer.address,
|
|
163
|
+
nativeBalance: buyerBudget.nativeBalance,
|
|
163
164
|
});
|
|
164
165
|
// ✅ 组装顺序:贿赂 → 卖出 → 买入
|
|
165
166
|
const signedTransactions = [];
|
|
@@ -11,6 +11,7 @@ import type { IroSubscribeParams, IroPledgeParams, IroTxResult, IroTokenInfo, Ir
|
|
|
11
11
|
export declare class IroTokenQuery {
|
|
12
12
|
private provider;
|
|
13
13
|
private token;
|
|
14
|
+
private chainId;
|
|
14
15
|
readonly tokenAddress: string;
|
|
15
16
|
constructor(tokenAddress: string, rpcUrl?: string, chainId?: number);
|
|
16
17
|
name(): Promise<string>;
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* - 查询: price, creator, isOpen, getTokenPrice 等
|
|
8
8
|
*/
|
|
9
9
|
import { Contract, Interface, Wallet, JsonRpcProvider } from 'ethers';
|
|
10
|
+
import { MULTICALL3_ABI } from '../../../../abis/common.js';
|
|
11
|
+
import { getMulticall3Address } from '../../../../core/constants/index.js';
|
|
10
12
|
import { BSC_CHAIN_ID, BSC_RPC_URL } from '../../constants.js';
|
|
11
13
|
import { IRO_TOKEN_ABI, SUBSCRIBE_GAS_LIMIT } from './constants.js';
|
|
12
14
|
import { buildProfitHopTransactions, PROFIT_HOP_COUNT } from '../../../../utils/bundle-helpers.js';
|
|
@@ -15,13 +17,28 @@ const tokenIface = new Interface(IRO_TOKEN_ABI);
|
|
|
15
17
|
// ============================================================================
|
|
16
18
|
// 查询
|
|
17
19
|
// ============================================================================
|
|
20
|
+
const IRO_INFO_VIEWS = ['name', 'symbol', 'decimals', 'totalSupply', 'POOL', 'isOpen', 'price', 'creator', 'TKA'];
|
|
21
|
+
async function readIroInfoViews(provider, tokenAddress, chainId) {
|
|
22
|
+
const multicall = new Contract(getMulticall3Address(chainId), MULTICALL3_ABI, provider);
|
|
23
|
+
const aggregate3 = multicall.aggregate3;
|
|
24
|
+
if (!aggregate3)
|
|
25
|
+
throw new Error('aggregate3 missing');
|
|
26
|
+
const rows = (await aggregate3.staticCall(IRO_INFO_VIEWS.map((name) => ({
|
|
27
|
+
target: tokenAddress,
|
|
28
|
+
allowFailure: false,
|
|
29
|
+
callData: tokenIface.encodeFunctionData(name, []),
|
|
30
|
+
}))));
|
|
31
|
+
return IRO_INFO_VIEWS.map((name, index) => tokenIface.decodeFunctionResult(name, rows[index].returnData)[0]);
|
|
32
|
+
}
|
|
18
33
|
export class IroTokenQuery {
|
|
19
34
|
provider;
|
|
20
35
|
token;
|
|
36
|
+
chainId;
|
|
21
37
|
tokenAddress;
|
|
22
38
|
constructor(tokenAddress, rpcUrl, chainId) {
|
|
23
39
|
this.tokenAddress = tokenAddress;
|
|
24
|
-
this.
|
|
40
|
+
this.chainId = chainId ?? BSC_CHAIN_ID;
|
|
41
|
+
this.provider = new JsonRpcProvider(rpcUrl ?? BSC_RPC_URL, this.chainId, { staticNetwork: true });
|
|
25
42
|
this.token = new Contract(tokenAddress, IRO_TOKEN_ABI, this.provider);
|
|
26
43
|
}
|
|
27
44
|
async name() {
|
|
@@ -93,6 +110,24 @@ export class IroTokenQuery {
|
|
|
93
110
|
}
|
|
94
111
|
/** 获取完整代币信息 */
|
|
95
112
|
async getTokenInfo() {
|
|
113
|
+
try {
|
|
114
|
+
const row = await readIroInfoViews(this.provider, this.tokenAddress, this.chainId);
|
|
115
|
+
return {
|
|
116
|
+
name: String(row[0]),
|
|
117
|
+
symbol: String(row[1]),
|
|
118
|
+
decimals: Number(row[2]),
|
|
119
|
+
totalSupply: row[3],
|
|
120
|
+
tokenAddress: this.tokenAddress,
|
|
121
|
+
poolAddress: String(row[4]),
|
|
122
|
+
isOpen: Boolean(row[5]),
|
|
123
|
+
price: row[6],
|
|
124
|
+
creator: String(row[7]),
|
|
125
|
+
tka: String(row[8]),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
/* 回退逐个 view */
|
|
130
|
+
}
|
|
96
131
|
const [name, symbol, decimals, totalSupply, poolAddress, isOpen, priceVal, creatorAddr, tkaAddr] = await Promise.all([
|
|
97
132
|
this.name(),
|
|
98
133
|
this.symbol(),
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* - batchSweepEgas: 批量归集 EGAS (各钱包独立签名)
|
|
6
6
|
* - eniSweepForSubmit: 前端统一入口 (EGAS / ERC20 归集)
|
|
7
7
|
*/
|
|
8
|
-
import { Wallet,
|
|
8
|
+
import { Wallet, ethers } from 'ethers';
|
|
9
9
|
import { ENI_CHAIN_ID, ENI_RPC_URL } from '../constants.js';
|
|
10
10
|
import { createEniProvider } from '../../../utils/provider-factory.js';
|
|
11
|
-
import { ERC20_ABI } from '../../../abis/common.js';
|
|
12
11
|
import { getProfitRecipient, calculateTransferFee } from '../../../core/constants/profit.js';
|
|
12
|
+
import { batchGetBalances, batchGetTokenAndNativeBalances } from '../../../bundle/internal.js';
|
|
13
13
|
import { GAS_LIMITS } from '../../../core/constants/gas.js';
|
|
14
14
|
import { erc20Iface, DEFAULT_GAS_PER_SWEEP, GAS_NATIVE_TRANSFER } from './transfer-shared.js';
|
|
15
15
|
export async function batchSweepToken(params) {
|
|
@@ -76,10 +76,7 @@ export async function eniSweepForSubmit(params) {
|
|
|
76
76
|
const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? 0n;
|
|
77
77
|
const gasForTransfer = GAS_NATIVE_TRANSFER * maxFeePerGas;
|
|
78
78
|
if (isNative) {
|
|
79
|
-
const balances = await
|
|
80
|
-
const wallet = new Wallet(key, provider);
|
|
81
|
-
return provider.getBalance(wallet.address);
|
|
82
|
-
}));
|
|
79
|
+
const balances = await batchGetBalances(provider, sourcePrivateKeys.map((key) => new Wallet(key).address), undefined, ENI_CHAIN_ID);
|
|
83
80
|
const totalHopGasReserve = hopCount > 0 ? gasForTransfer * BigInt(hopCount) : 0n;
|
|
84
81
|
const validKeys = [];
|
|
85
82
|
const validAmounts = [];
|
|
@@ -131,17 +128,16 @@ export async function eniSweepForSubmit(params) {
|
|
|
131
128
|
return { signedTransactions: signedTxs };
|
|
132
129
|
}
|
|
133
130
|
// ===== ERC20 归集 =====
|
|
134
|
-
const erc20 = new Contract(tokenAddress, ERC20_ABI, provider);
|
|
135
131
|
const erc20TransferGasCost = erc20GasLimit * maxFeePerGas;
|
|
136
132
|
const hopGasCostPerWallet = hopCount > 0 ? gasForTransfer * BigInt(hopCount) + erc20GasLimit * maxFeePerGas * BigInt(hopCount) : 0n;
|
|
137
133
|
const minNativeRequired = erc20TransferGasCost + hopGasCostPerWallet;
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
]
|
|
144
|
-
|
|
134
|
+
const sourceAddresses = sourcePrivateKeys.map((key) => new Wallet(key).address);
|
|
135
|
+
const paired = await batchGetTokenAndNativeBalances(provider, sourceAddresses, tokenAddress, ENI_CHAIN_ID);
|
|
136
|
+
const tokenBals = paired.token;
|
|
137
|
+
const nativeBals = paired.native;
|
|
138
|
+
const walletsData = sourceAddresses.map((_, i) => ({
|
|
139
|
+
tokenBal: tokenBals[i] ?? 0n,
|
|
140
|
+
nativeBal: nativeBals[i] ?? 0n,
|
|
145
141
|
}));
|
|
146
142
|
const validKeys = [];
|
|
147
143
|
const validAmounts = [];
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* LPFairLauncher 创建的代币不经过 bonding curve,没有毕业阶段
|
|
10
10
|
*/
|
|
11
|
+
import { Contract, Interface, JsonRpcProvider } from 'ethers';
|
|
12
|
+
import { DAOAAS_PORTAL, DAOAAS_PORTAL_ABI, ENI_CHAIN_ID, ENI_MULTICALL3, ENI_RPC_URL } from '../../constants.js';
|
|
13
|
+
import { MULTICALL3_ABI } from '../../../../abis/common.js';
|
|
11
14
|
import { DaoaasPortalQuery } from './portal.js';
|
|
12
15
|
import { DaoaasTokenStatus } from './types.js';
|
|
13
16
|
/**
|
|
@@ -28,20 +31,63 @@ export async function getGraduationInfo(token, config) {
|
|
|
28
31
|
* 批量查询毕业状态
|
|
29
32
|
*/
|
|
30
33
|
export async function batchGetGraduationInfo(tokens, config) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
if (tokens.length === 0)
|
|
35
|
+
return [];
|
|
36
|
+
const rpcUrl = config?.rpcUrl ?? ENI_RPC_URL;
|
|
37
|
+
const portal = config?.portal ?? DAOAAS_PORTAL;
|
|
38
|
+
const multicall3 = config?.multicall3 ?? ENI_MULTICALL3;
|
|
39
|
+
const provider = new JsonRpcProvider(rpcUrl, ENI_CHAIN_ID, { staticNetwork: true });
|
|
40
|
+
const portalIface = new Interface(DAOAAS_PORTAL_ABI);
|
|
41
|
+
const empty = (token) => ({
|
|
42
|
+
token,
|
|
43
|
+
status: DaoaasTokenStatus.NotCreated,
|
|
44
|
+
isGraduated: false,
|
|
45
|
+
isTrading: false,
|
|
46
|
+
price: 0n,
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
const multicall = new Contract(multicall3, MULTICALL3_ABI, provider);
|
|
50
|
+
const aggregate3 = multicall.aggregate3;
|
|
51
|
+
if (!aggregate3)
|
|
52
|
+
throw new Error('aggregate3 missing');
|
|
53
|
+
const calls = tokens.flatMap((token) => [
|
|
54
|
+
{ target: portal, allowFailure: true, callData: portalIface.encodeFunctionData('getTokenState', [token]) },
|
|
55
|
+
{ target: portal, allowFailure: true, callData: portalIface.encodeFunctionData('getPrice', [token]) },
|
|
56
|
+
]);
|
|
57
|
+
const rows = (await aggregate3.staticCall(calls));
|
|
58
|
+
return tokens.map((token, index) => {
|
|
59
|
+
const stateRow = rows[index * 2];
|
|
60
|
+
const priceRow = rows[index * 2 + 1];
|
|
61
|
+
if (!stateRow?.success || stateRow.returnData === '0x')
|
|
62
|
+
return empty(token);
|
|
63
|
+
try {
|
|
64
|
+
const status = Number(portalIface.decodeFunctionResult('getTokenState', stateRow.returnData)[0]);
|
|
65
|
+
const price = priceRow?.success && priceRow.returnData !== '0x'
|
|
66
|
+
? portalIface.decodeFunctionResult('getPrice', priceRow.returnData)[0]
|
|
67
|
+
: 0n;
|
|
68
|
+
return {
|
|
69
|
+
token,
|
|
70
|
+
status,
|
|
71
|
+
isGraduated: status === DaoaasTokenStatus.Graduated,
|
|
72
|
+
isTrading: status === DaoaasTokenStatus.Trading,
|
|
73
|
+
price,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return empty(token);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
const results = [];
|
|
83
|
+
for (const token of tokens) {
|
|
84
|
+
try {
|
|
85
|
+
results.push(await getGraduationInfo(token, config));
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
results.push(empty(token));
|
|
89
|
+
}
|
|
44
90
|
}
|
|
91
|
+
return results;
|
|
45
92
|
}
|
|
46
|
-
return results;
|
|
47
93
|
}
|
|
@@ -25,8 +25,4 @@ export declare function getTokenMeta(token: string, rpcUrl?: string): Promise<Da
|
|
|
25
25
|
* FairLaunch 代币的 logo 和 metadata 存储在 LaunchParams 中
|
|
26
26
|
*/
|
|
27
27
|
export declare function getFairLaunchTokenMeta(token: string, rpcUrl?: string): Promise<DaoaasTokenMeta>;
|
|
28
|
-
/**
|
|
29
|
-
* 批量获取代币元数据(自动识别 Portal 或 FairLaunch 来源)
|
|
30
|
-
* 对标 BSC: getFlapMetasByAddresses
|
|
31
|
-
*/
|
|
32
28
|
export declare function getTokenMetasBatch(tokens: string[], rpcUrl?: string): Promise<DaoaasTokenMeta[]>;
|