four-flap-meme-sdk 1.2.92 → 1.2.95
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.
|
@@ -18,10 +18,12 @@ export async function disperseWithBundleMerkle(params) {
|
|
|
18
18
|
}
|
|
19
19
|
// 初始化
|
|
20
20
|
const chainIdNum = config.chainId ?? 56;
|
|
21
|
+
// ✅ 根据 chainId 动态设置链名
|
|
22
|
+
const chainName = chainIdNum === 143 ? 'Monad' : chainIdNum === 56 ? 'BSC' : `Chain-${chainIdNum}`;
|
|
21
23
|
// ✅ 直接使用传入的 RPC URL 创建 provider(不依赖 Merkle)
|
|
22
24
|
const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
|
|
23
25
|
chainId: chainIdNum,
|
|
24
|
-
name:
|
|
26
|
+
name: chainName
|
|
25
27
|
});
|
|
26
28
|
const [gasPrice, mainWallet] = await Promise.all([
|
|
27
29
|
getOptimizedGasPrice(provider, getGasPriceConfig(config)),
|
|
@@ -325,10 +327,12 @@ export async function sweepWithBundleMerkle(params) {
|
|
|
325
327
|
}
|
|
326
328
|
// 初始化
|
|
327
329
|
const chainIdNum = config.chainId ?? 56;
|
|
330
|
+
// ✅ 根据 chainId 动态设置链名
|
|
331
|
+
const chainName = chainIdNum === 143 ? 'Monad' : chainIdNum === 56 ? 'BSC' : `Chain-${chainIdNum}`;
|
|
328
332
|
// ✅ 直接使用传入的 RPC URL 创建 provider(不依赖 Merkle)
|
|
329
333
|
const provider = new ethers.JsonRpcProvider(config.rpcUrl, {
|
|
330
334
|
chainId: chainIdNum,
|
|
331
|
-
name:
|
|
335
|
+
name: chainName
|
|
332
336
|
});
|
|
333
337
|
const gasPrice = await getOptimizedGasPrice(provider, getGasPriceConfig(config));
|
|
334
338
|
const isNative = _isNativeTokenAddress(tokenAddress);
|
|
@@ -7,10 +7,12 @@ export declare function createTokenWithBundleBuyMerkle(params: FlapCreateWithBun
|
|
|
7
7
|
/**
|
|
8
8
|
* Flap Protocol: 批量购买(仅签名版本 - 不依赖 Merkle)
|
|
9
9
|
* ✅ 精简版:只负责签名交易,不提交到 Merkle
|
|
10
|
+
* ✅ 支持 quoteToken:传入 USDC 等地址时使用该代币购买,否则使用原生代币
|
|
10
11
|
*/
|
|
11
12
|
export declare function batchBuyWithBundleMerkle(params: FlapBatchBuySignParams): Promise<FlapBatchBuyMerkleResult>;
|
|
12
13
|
/**
|
|
13
14
|
* Flap Protocol: 批量卖出(仅签名版本 - 不依赖 Merkle)
|
|
14
15
|
* ✅ 精简版:只负责签名交易,不提交到 Merkle
|
|
16
|
+
* ✅ 支持 quoteToken:传入 USDC 等地址时卖出为该代币,否则卖出为原生代币
|
|
15
17
|
*/
|
|
16
18
|
export declare function batchSellWithBundleMerkle(params: FlapBatchSellSignParams): Promise<FlapBatchSellMerkleResult>;
|
|
@@ -121,9 +121,12 @@ export async function createTokenWithBundleBuyMerkle(params) {
|
|
|
121
121
|
/**
|
|
122
122
|
* Flap Protocol: 批量购买(仅签名版本 - 不依赖 Merkle)
|
|
123
123
|
* ✅ 精简版:只负责签名交易,不提交到 Merkle
|
|
124
|
+
* ✅ 支持 quoteToken:传入 USDC 等地址时使用该代币购买,否则使用原生代币
|
|
124
125
|
*/
|
|
125
126
|
export async function batchBuyWithBundleMerkle(params) {
|
|
126
|
-
const { chain, privateKeys, buyAmounts, tokenAddress, config } = params;
|
|
127
|
+
const { chain, privateKeys, buyAmounts, tokenAddress, quoteToken, config } = params;
|
|
128
|
+
console.log('🔍 SDK batchBuyWithBundleMerkle - quoteToken:', quoteToken);
|
|
129
|
+
console.log('🔍 SDK batchBuyWithBundleMerkle - params.quoteToken:', params.quoteToken);
|
|
127
130
|
if (privateKeys.length === 0 || buyAmounts.length !== privateKeys.length) {
|
|
128
131
|
throw new Error(getErrorMessage('KEY_AMOUNT_MISMATCH'));
|
|
129
132
|
}
|
|
@@ -135,10 +138,16 @@ export async function batchBuyWithBundleMerkle(params) {
|
|
|
135
138
|
const { fundsList, originalAmounts, totalBuyAmount, totalProfit } = analyzeBuyFunds(buyAmounts, config, extractProfit);
|
|
136
139
|
const maxFundsIndex = findMaxIndex(originalAmounts);
|
|
137
140
|
const gasLimits = buildGasLimitList(buyers.length, config);
|
|
141
|
+
// ✅ 确定 inputToken:如果传入了 quoteToken 且非零地址,则使用它;否则使用零地址(原生代币)
|
|
142
|
+
const inputToken = quoteToken && quoteToken !== ZERO_ADDRESS ? quoteToken : ZERO_ADDRESS;
|
|
143
|
+
// ✅ 如果使用非原生代币,则 value 应为 0(不发送原生代币)
|
|
144
|
+
const useNativeToken = inputToken === ZERO_ADDRESS;
|
|
145
|
+
console.log('🔍 SDK inputToken 计算结果:', inputToken);
|
|
146
|
+
console.log('🔍 SDK useNativeToken:', useNativeToken);
|
|
138
147
|
// ✅ 优化:并行执行 gasPrice 和 populateBuyTransactions(最耗时的两个操作)
|
|
139
148
|
const [gasPrice, unsignedBuys] = await Promise.all([
|
|
140
149
|
resolveGasPrice(provider, config),
|
|
141
|
-
|
|
150
|
+
populateBuyTransactionsWithQuote(buyers, FLAP_PORTAL_ADDRESSES[chain], tokenAddress, fundsList, inputToken, useNativeToken)
|
|
142
151
|
]);
|
|
143
152
|
const buyerNonces = await allocateBuyerNonces(buyers, extractProfit, maxFundsIndex, totalProfit, nonceManager);
|
|
144
153
|
const signedBuys = await signBuyTransactions({
|
|
@@ -172,9 +181,10 @@ export async function batchBuyWithBundleMerkle(params) {
|
|
|
172
181
|
/**
|
|
173
182
|
* Flap Protocol: 批量卖出(仅签名版本 - 不依赖 Merkle)
|
|
174
183
|
* ✅ 精简版:只负责签名交易,不提交到 Merkle
|
|
184
|
+
* ✅ 支持 quoteToken:传入 USDC 等地址时卖出为该代币,否则卖出为原生代币
|
|
175
185
|
*/
|
|
176
186
|
export async function batchSellWithBundleMerkle(params) {
|
|
177
|
-
const { chain, privateKeys, sellAmounts, tokenAddress, minOutputAmounts, config } = params;
|
|
187
|
+
const { chain, privateKeys, sellAmounts, tokenAddress, quoteToken, minOutputAmounts, config } = params;
|
|
178
188
|
if (privateKeys.length === 0 || sellAmounts.length !== privateKeys.length) {
|
|
179
189
|
throw new Error(getErrorMessage('SELL_KEY_AMOUNT_MISMATCH'));
|
|
180
190
|
}
|
|
@@ -186,16 +196,18 @@ export async function batchSellWithBundleMerkle(params) {
|
|
|
186
196
|
const portalAddr = FLAP_PORTAL_ADDRESSES[chain];
|
|
187
197
|
const readOnlyPortal = new ethers.Contract(portalAddr, PORTAL_ABI, provider);
|
|
188
198
|
const gasLimits = buildGasLimitList(wallets.length, config);
|
|
199
|
+
// ✅ 确定 outputToken:如果传入了 quoteToken 且非零地址,则使用它;否则使用零地址(原生代币)
|
|
200
|
+
const outputToken = quoteToken && quoteToken !== ZERO_ADDRESS ? quoteToken : ZERO_ADDRESS;
|
|
189
201
|
// ✅ 优化:并行执行 gasPrice 和 quoteSellOutputs(最耗时的两个操作)
|
|
190
202
|
const [gasPrice, quotedOutputs] = await Promise.all([
|
|
191
203
|
resolveGasPrice(provider, config),
|
|
192
|
-
|
|
204
|
+
quoteSellOutputsWithQuote(readOnlyPortal, tokenAddress, amountsWei, outputToken)
|
|
193
205
|
]);
|
|
194
206
|
const minOuts = resolveMinOutputs(minOutputAmounts, wallets.length, quotedOutputs);
|
|
195
207
|
const portals = wallets.map(w => new ethers.Contract(portalAddr, PORTAL_ABI, w));
|
|
196
208
|
const unsignedList = await Promise.all(portals.map((portal, i) => portal.swapExactInput.populateTransaction({
|
|
197
209
|
inputToken: tokenAddress,
|
|
198
|
-
outputToken
|
|
210
|
+
outputToken, // ✅ 使用动态 outputToken
|
|
199
211
|
inputAmount: amountsWei[i],
|
|
200
212
|
minOutputAmount: minOuts[i],
|
|
201
213
|
permitData: '0x'
|
|
@@ -285,6 +297,22 @@ async function populateBuyTransactions(buyers, portalAddr, tokenAddress, fundsLi
|
|
|
285
297
|
permitData: '0x'
|
|
286
298
|
}, { value: fundsList[i] })));
|
|
287
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* ✅ 支持 quoteToken 的买入交易构建
|
|
302
|
+
* 当 inputToken 为非零地址(如 USDC)时,value 为 0
|
|
303
|
+
*/
|
|
304
|
+
async function populateBuyTransactionsWithQuote(buyers, portalAddr, tokenAddress, fundsList, inputToken, useNativeToken) {
|
|
305
|
+
const portals = buyers.map(wallet => new ethers.Contract(portalAddr, PORTAL_ABI, wallet));
|
|
306
|
+
return await Promise.all(portals.map((portal, i) => portal.swapExactInput.populateTransaction({
|
|
307
|
+
inputToken,
|
|
308
|
+
outputToken: tokenAddress,
|
|
309
|
+
inputAmount: fundsList[i],
|
|
310
|
+
minOutputAmount: 0n,
|
|
311
|
+
permitData: '0x'
|
|
312
|
+
},
|
|
313
|
+
// ✅ 如果使用原生代币,value 为购买金额;否则为 0
|
|
314
|
+
useNativeToken ? { value: fundsList[i] } : {})));
|
|
315
|
+
}
|
|
288
316
|
function buildGasLimitList(length, config) {
|
|
289
317
|
const gasLimit = getGasLimit(config);
|
|
290
318
|
return new Array(length).fill(gasLimit);
|
|
@@ -356,6 +384,23 @@ async function quoteSellOutputs(portal, tokenAddress, amountsWei) {
|
|
|
356
384
|
}
|
|
357
385
|
}));
|
|
358
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* ✅ 支持 quoteToken 的卖出报价
|
|
389
|
+
*/
|
|
390
|
+
async function quoteSellOutputsWithQuote(portal, tokenAddress, amountsWei, outputToken) {
|
|
391
|
+
return await Promise.all(amountsWei.map(async (amount) => {
|
|
392
|
+
try {
|
|
393
|
+
return await portal.quoteExactInput.staticCall({
|
|
394
|
+
inputToken: tokenAddress,
|
|
395
|
+
outputToken, // ✅ 使用动态 outputToken
|
|
396
|
+
inputAmount: amount
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
return 0n;
|
|
401
|
+
}
|
|
402
|
+
}));
|
|
403
|
+
}
|
|
359
404
|
function resolveMinOutputs(provided, walletCount, quotedOutputs) {
|
|
360
405
|
if (provided && provided.length === walletCount) {
|
|
361
406
|
return provided.map(m => typeof m === 'string' ? ethers.parseEther(m) : BigInt(m));
|
|
@@ -119,6 +119,8 @@ export type FlapBatchBuySignParams = {
|
|
|
119
119
|
privateKeys: string[];
|
|
120
120
|
buyAmounts: string[];
|
|
121
121
|
tokenAddress: string;
|
|
122
|
+
/** 报价代币地址(如 USDC),零地址或不传表示使用原生代币(MON/BNB) */
|
|
123
|
+
quoteToken?: string;
|
|
122
124
|
minOutputAmounts?: (string | bigint)[];
|
|
123
125
|
config: FlapSignConfig;
|
|
124
126
|
};
|
|
@@ -139,6 +141,8 @@ export type FlapBatchSellSignParams = {
|
|
|
139
141
|
privateKeys: string[];
|
|
140
142
|
sellAmounts: string[];
|
|
141
143
|
tokenAddress: string;
|
|
144
|
+
/** 报价代币地址(如 USDC),零地址或不传表示输出原生代币(MON/BNB) */
|
|
145
|
+
quoteToken?: string;
|
|
142
146
|
minOutputAmounts?: (string | bigint)[];
|
|
143
147
|
config: FlapSignConfig;
|
|
144
148
|
};
|