four-flap-meme-sdk 1.7.16 → 1.7.18
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/eip7702/xlayer/bundle-approve.js +1 -1
- package/dist/eip7702/xlayer/bundle-buy.js +1 -1
- package/dist/eip7702/xlayer/bundle-create.js +3 -3
- package/dist/eip7702/xlayer/bundle-sell.js +1 -1
- package/dist/eip7702/xlayer/bundle-swap.js +2 -2
- package/dist/eip7702/xlayer/multi-hop-transfer.js +3 -3
- package/dist/eip7702/xlayer/utils.js +6 -4
- package/dist/eip7702/xlayer/volume.js +50 -11
- package/package.json +1 -1
|
@@ -48,7 +48,7 @@ export async function bundleApprove(params) {
|
|
|
48
48
|
throw new Error('privateKeys 不能为空');
|
|
49
49
|
}
|
|
50
50
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
51
|
-
const delegateAddress = config?.delegateAddress
|
|
51
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
52
52
|
const mainWallet = createWallet(mainPrivateKey, provider);
|
|
53
53
|
const wallets = privateKeys.map(pk => createWallet(pk, provider));
|
|
54
54
|
// 检查 mainWallet 是否在 wallets 中
|
|
@@ -182,7 +182,7 @@ export async function bundleBuy(params) {
|
|
|
182
182
|
throw new Error('privateKeys 和 buyAmounts 长度必须相同');
|
|
183
183
|
}
|
|
184
184
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
185
|
-
const delegateAddress = config?.delegateAddress
|
|
185
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
186
186
|
const actualRouter = routerAddress ?? getDefaultRouter(tradeType);
|
|
187
187
|
// ========================================
|
|
188
188
|
// 同步操作 - 批量创建钱包和解析金额
|
|
@@ -130,7 +130,7 @@ export async function bundleCreateBuy(params) {
|
|
|
130
130
|
throw new Error('buyerPrivateKeys 和 buyAmounts 长度必须相同');
|
|
131
131
|
}
|
|
132
132
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
133
|
-
const delegateAddress = config?.delegateAddress
|
|
133
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
134
134
|
const delegateInterface = new Interface(UNIFIED_DELEGATE_ABI);
|
|
135
135
|
// 创建钱包
|
|
136
136
|
const devWallet = createWallet(devPrivateKey, provider);
|
|
@@ -280,7 +280,7 @@ export async function bundleCreateToDex(params) {
|
|
|
280
280
|
throw new Error('dexBuyerPrivateKeys 和 dexBuyAmounts 长度必须相同');
|
|
281
281
|
}
|
|
282
282
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
283
|
-
const delegateAddress = config?.delegateAddress
|
|
283
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
284
284
|
const delegateInterface = new Interface(UNIFIED_DELEGATE_ABI);
|
|
285
285
|
// 创建钱包
|
|
286
286
|
const payerWallet = createWallet(payerPrivateKey, provider);
|
|
@@ -428,7 +428,7 @@ export async function bundleCreateToDex(params) {
|
|
|
428
428
|
export async function bundleGraduateBuy(params) {
|
|
429
429
|
const { tokenAddress, privateKeys, payerPrivateKey, amountMode, totalBuyAmount, minAmount, maxAmount, walletAmounts, enableDexBuy = false, extensionData = '0x', curveAddresses, dexAddresses, graduationAmount, config, } = params;
|
|
430
430
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
431
|
-
const delegateAddress = config?.delegateAddress
|
|
431
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
432
432
|
const delegateInterface = new Interface(UNIFIED_DELEGATE_ABI);
|
|
433
433
|
// 创建钱包
|
|
434
434
|
const payerWallet = createWallet(payerPrivateKey, provider);
|
|
@@ -193,7 +193,7 @@ function buildSellCalls(wallets, sellAmounts, tokenAddress, tradeType, routerAdd
|
|
|
193
193
|
export async function bundleSell(params) {
|
|
194
194
|
const { mainPrivateKey, privateKeys, sellAmounts, sellPercent, tokenAddress, tokenDecimals = 18, tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, config, } = params;
|
|
195
195
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
196
|
-
const delegateAddress = config?.delegateAddress
|
|
196
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
197
197
|
const actualRouter = routerAddress ?? getDefaultRouter(tradeType);
|
|
198
198
|
// ========================================
|
|
199
199
|
// 同步操作 - 批量创建钱包
|
|
@@ -189,7 +189,7 @@ export async function bundleSwap(params) {
|
|
|
189
189
|
const { sellerPrivateKey, buyerPrivateKey, tokenAddress, tokenDecimals = 18, sellAmount, hopCount = 2, // ✅ 设为 0 则不多跳,直接 seller → buyer
|
|
190
190
|
tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, config, } = params;
|
|
191
191
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
192
|
-
const delegateAddress = config?.delegateAddress
|
|
192
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
193
193
|
const actualRouter = routerAddress ?? getDefaultRouter(tradeType);
|
|
194
194
|
// ========================================
|
|
195
195
|
// 同步操作 - 创建钱包
|
|
@@ -266,7 +266,7 @@ export async function bundleBatchSwap(params) {
|
|
|
266
266
|
const { sellerPrivateKey, buyerPrivateKeys, tokenAddress, tokenDecimals = 18, sellAmount, hopCount = 2, // ✅ 设为 0 则不多跳
|
|
267
267
|
tradeType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, config, } = params;
|
|
268
268
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
269
|
-
const delegateAddress = config?.delegateAddress
|
|
269
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
270
270
|
const actualRouter = routerAddress ?? getDefaultRouter(tradeType);
|
|
271
271
|
// ========================================
|
|
272
272
|
// 同步操作 - 创建钱包
|
|
@@ -58,7 +58,7 @@ export async function disperse(params) {
|
|
|
58
58
|
throw new Error('recipients 和 amounts 长度必须相同');
|
|
59
59
|
}
|
|
60
60
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
61
|
-
const delegateAddress = config?.delegateAddress
|
|
61
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
62
62
|
const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
|
|
63
63
|
const mainWallet = createWallet(mainPrivateKey, provider);
|
|
64
64
|
const isNative = !tokenAddress;
|
|
@@ -259,7 +259,7 @@ export async function disperse(params) {
|
|
|
259
259
|
export async function sweep(params) {
|
|
260
260
|
const { targetAddress, sourcePrivateKeys, payerPrivateKey, tokenAddress, tokenDecimals = 18, hopCount = 0, reserveGas = true, percent = 100, config, } = params;
|
|
261
261
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
262
|
-
const delegateAddress = config?.delegateAddress
|
|
262
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
263
263
|
const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
|
|
264
264
|
const sourceWallets = sourcePrivateKeys.map(pk => createWallet(pk, provider));
|
|
265
265
|
const isNative = !tokenAddress;
|
|
@@ -520,7 +520,7 @@ export async function pairwiseTransfer(params) {
|
|
|
520
520
|
throw new Error('必须提供 amount 或 amounts');
|
|
521
521
|
})();
|
|
522
522
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
523
|
-
const delegateAddress = config?.delegateAddress
|
|
523
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
524
524
|
const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
|
|
525
525
|
const isNative = !tokenAddress;
|
|
526
526
|
// 创建钱包
|
|
@@ -196,11 +196,12 @@ export async function buildEIP7702Transaction(mainWallet, authorizations, calls,
|
|
|
196
196
|
const txHash = ethers.keccak256(toSign);
|
|
197
197
|
const signingKey = new ethers.SigningKey(mainWallet.privateKey);
|
|
198
198
|
const sig = signingKey.sign(txHash);
|
|
199
|
+
// ✅ 交易签名的 r/s 也需要去除前导零,符合 RLP 规范
|
|
199
200
|
const signedTxData = [
|
|
200
201
|
...txData,
|
|
201
202
|
bigintToBytes(BigInt(sig.yParity)),
|
|
202
|
-
ethers.getBytes(sig.r),
|
|
203
|
-
ethers.getBytes(sig.s),
|
|
203
|
+
trimLeadingZeros(ethers.getBytes(sig.r)),
|
|
204
|
+
trimLeadingZeros(ethers.getBytes(sig.s)),
|
|
204
205
|
];
|
|
205
206
|
const signedRlp = rlp.encode(signedTxData);
|
|
206
207
|
const signedTx = new Uint8Array(1 + signedRlp.length);
|
|
@@ -252,11 +253,12 @@ export function buildEIP7702TransactionSync(mainWallet, authorizations, calls, t
|
|
|
252
253
|
const txHash = ethers.keccak256(toSign);
|
|
253
254
|
const signingKey = new ethers.SigningKey(mainWallet.privateKey);
|
|
254
255
|
const sig = signingKey.sign(txHash);
|
|
256
|
+
// ✅ 交易签名的 r/s 也需要去除前导零,符合 RLP 规范
|
|
255
257
|
const signedTxData = [
|
|
256
258
|
...txData,
|
|
257
259
|
bigintToBytes(BigInt(sig.yParity)),
|
|
258
|
-
ethers.getBytes(sig.r),
|
|
259
|
-
ethers.getBytes(sig.s),
|
|
260
|
+
trimLeadingZeros(ethers.getBytes(sig.r)),
|
|
261
|
+
trimLeadingZeros(ethers.getBytes(sig.s)),
|
|
260
262
|
];
|
|
261
263
|
const signedRlp = rlp.encode(signedTxData);
|
|
262
264
|
const signedTx = new Uint8Array(1 + signedRlp.length);
|
|
@@ -42,14 +42,28 @@ export async function washVolume(params) {
|
|
|
42
42
|
if (privateKeys.length === 0) {
|
|
43
43
|
throw new Error('至少需要一个钱包');
|
|
44
44
|
}
|
|
45
|
+
// ✅ 验证私钥格式
|
|
46
|
+
const validPrivateKeys = privateKeys.filter(pk => {
|
|
47
|
+
const trimmed = (pk || '').trim();
|
|
48
|
+
return trimmed.length >= 64 && (trimmed.startsWith('0x') || /^[0-9a-fA-F]{64}$/.test(trimmed));
|
|
49
|
+
});
|
|
50
|
+
if (validPrivateKeys.length === 0) {
|
|
51
|
+
throw new Error('没有有效的私钥(私钥必须是 0x 开头的 66 位或 64 位十六进制字符串)');
|
|
52
|
+
}
|
|
53
|
+
if (validPrivateKeys.length !== privateKeys.length) {
|
|
54
|
+
console.warn(`[washVolume] 跳过 ${privateKeys.length - validPrivateKeys.length} 个无效私钥`);
|
|
55
|
+
}
|
|
56
|
+
// 使用验证后的私钥
|
|
57
|
+
const actualPrivateKeys = validPrivateKeys;
|
|
45
58
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
46
|
-
|
|
59
|
+
// ✅ 空字符串也使用默认值
|
|
60
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
47
61
|
const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
|
|
48
62
|
const portalInterface = new ethers.Interface(FLAP_PORTAL_ABI);
|
|
49
63
|
// 获取实际路由地址
|
|
50
64
|
const actualRouter = routerAddress ?? getDefaultRouter(poolType);
|
|
51
|
-
//
|
|
52
|
-
const wallets =
|
|
65
|
+
// 创建钱包(使用验证后的私钥)
|
|
66
|
+
const wallets = actualPrivateKeys.map(pk => createWallet(pk, provider));
|
|
53
67
|
const mainWallet = wallets[0];
|
|
54
68
|
// 计算金额
|
|
55
69
|
const buyAmountWei = ethers.parseEther(buyAmountPerWallet);
|
|
@@ -131,25 +145,50 @@ export async function washVolume(params) {
|
|
|
131
145
|
*/
|
|
132
146
|
export async function bundleVolume(params) {
|
|
133
147
|
const { buyerPrivateKeys, buyAmounts, sellerPrivateKeys, sellAmounts, sellPercent = 100, tokenAddress, tokenDecimals = 18, poolType = 'V3', routerAddress, fee = V3_FEE_TIERS.MEDIUM, config, } = params;
|
|
134
|
-
|
|
135
|
-
|
|
148
|
+
// ✅ 验证私钥格式的辅助函数
|
|
149
|
+
const isValidPrivateKey = (pk) => {
|
|
150
|
+
const trimmed = (pk || '').trim();
|
|
151
|
+
return trimmed.length >= 64 && (trimmed.startsWith('0x') || /^[0-9a-fA-F]{64}$/.test(trimmed));
|
|
152
|
+
};
|
|
153
|
+
// ✅ 验证买家私钥
|
|
154
|
+
const validBuyerIndices = [];
|
|
155
|
+
const validBuyerPrivateKeys = [];
|
|
156
|
+
const validBuyAmounts = [];
|
|
157
|
+
buyerPrivateKeys.forEach((pk, i) => {
|
|
158
|
+
if (isValidPrivateKey(pk)) {
|
|
159
|
+
validBuyerIndices.push(i);
|
|
160
|
+
validBuyerPrivateKeys.push(pk);
|
|
161
|
+
validBuyAmounts.push(buyAmounts[i] || '0');
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
if (validBuyerPrivateKeys.length === 0) {
|
|
165
|
+
throw new Error('没有有效的买家私钥');
|
|
166
|
+
}
|
|
167
|
+
// ✅ 验证卖家私钥
|
|
168
|
+
const validSellerPrivateKeys = sellerPrivateKeys.filter(pk => isValidPrivateKey(pk));
|
|
169
|
+
if (validSellerPrivateKeys.length === 0) {
|
|
170
|
+
throw new Error('没有有效的卖家私钥');
|
|
171
|
+
}
|
|
172
|
+
if (validBuyerPrivateKeys.length !== buyerPrivateKeys.length || validSellerPrivateKeys.length !== sellerPrivateKeys.length) {
|
|
173
|
+
console.warn(`[bundleVolume] 跳过无效私钥: 买家 ${buyerPrivateKeys.length - validBuyerPrivateKeys.length} 个, 卖家 ${sellerPrivateKeys.length - validSellerPrivateKeys.length} 个`);
|
|
136
174
|
}
|
|
137
175
|
const provider = getCachedProvider(config?.rpcUrl);
|
|
138
|
-
|
|
176
|
+
// ✅ 空字符串也使用默认值
|
|
177
|
+
const delegateAddress = (config?.delegateAddress && config.delegateAddress.trim()) || UNIFIED_DELEGATE_ADDRESS;
|
|
139
178
|
const delegateInterface = new ethers.Interface(UNIFIED_DELEGATE_ABI);
|
|
140
179
|
const portalInterface = new ethers.Interface(FLAP_PORTAL_ABI);
|
|
141
180
|
const actualRouter = routerAddress ?? getDefaultRouter(poolType);
|
|
142
|
-
//
|
|
143
|
-
const buyerWallets =
|
|
144
|
-
const sellerWallets =
|
|
181
|
+
// 创建钱包(使用验证后的私钥)
|
|
182
|
+
const buyerWallets = validBuyerPrivateKeys.map(pk => createWallet(pk, provider));
|
|
183
|
+
const sellerWallets = validSellerPrivateKeys.map(pk => createWallet(pk, provider));
|
|
145
184
|
// 合并所有钱包(去重)
|
|
146
185
|
const allWalletsMap = new Map();
|
|
147
186
|
buyerWallets.forEach(w => allWalletsMap.set(w.address.toLowerCase(), w));
|
|
148
187
|
sellerWallets.forEach(w => allWalletsMap.set(w.address.toLowerCase(), w));
|
|
149
188
|
const allWallets = Array.from(allWalletsMap.values());
|
|
150
189
|
const mainWallet = allWallets[0];
|
|
151
|
-
//
|
|
152
|
-
const buyAmountsWei =
|
|
190
|
+
// 计算买入金额(使用验证后的金额数组)
|
|
191
|
+
const buyAmountsWei = validBuyAmounts.map(amt => ethers.parseEther(amt));
|
|
153
192
|
const totalBuyAmount = buyAmountsWei.reduce((sum, amt) => sum + amt, 0n);
|
|
154
193
|
// 计算利润
|
|
155
194
|
const profitAmount = calculateProfitAmount(totalBuyAmount);
|