four-flap-meme-sdk 1.3.7 → 1.3.8
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/clients/merkle.d.ts
CHANGED
|
@@ -70,9 +70,9 @@ export interface SendBundleOptions {
|
|
|
70
70
|
minTimestamp?: number;
|
|
71
71
|
/** 最大时间戳 */
|
|
72
72
|
maxTimestamp?: number;
|
|
73
|
-
/** 如果不指定 targetBlock,则使用当前区块 + offset(默认
|
|
73
|
+
/** 如果不指定 targetBlock,则使用当前区块 + offset(默认3) */
|
|
74
74
|
blockOffset?: number;
|
|
75
|
-
/** 最小区块偏移量,用于确保足够的提交时间窗口(默认
|
|
75
|
+
/** 最小区块偏移量,用于确保足够的提交时间窗口(默认3) */
|
|
76
76
|
minBlockOffset?: number;
|
|
77
77
|
/** 是否启用自动重试(默认false) */
|
|
78
78
|
autoRetry?: boolean;
|
package/dist/clients/merkle.js
CHANGED
|
@@ -133,22 +133,32 @@ export class MerkleClient {
|
|
|
133
133
|
if (!options.transactions || options.transactions.length === 0) {
|
|
134
134
|
throw new Error('Transactions array cannot be empty');
|
|
135
135
|
}
|
|
136
|
+
const minBlockOffset = options.minBlockOffset ?? 3; // 默认至少3个区块的窗口
|
|
136
137
|
const autoRetry = options.autoRetry ?? false;
|
|
137
138
|
const maxRetries = options.maxRetries ?? 2;
|
|
138
139
|
let attempt = 0;
|
|
139
140
|
let lastError = null;
|
|
140
141
|
while (attempt <= (autoRetry ? maxRetries : 0)) {
|
|
141
142
|
try {
|
|
143
|
+
// 实时获取当前区块(每次尝试都重新获取)
|
|
144
|
+
const currentBlock = await this.getBlockNumber();
|
|
145
|
+
// 确定目标区块
|
|
142
146
|
let targetBlock;
|
|
143
|
-
// ✅ 优化:如果已经传入 targetBlock,直接使用,不再查询区块号
|
|
144
147
|
if (options.targetBlock) {
|
|
145
148
|
targetBlock = options.targetBlock;
|
|
149
|
+
// 检查目标区块是否已经过期
|
|
150
|
+
if (targetBlock <= currentBlock) {
|
|
151
|
+
if (autoRetry && attempt < maxRetries) {
|
|
152
|
+
attempt++;
|
|
153
|
+
await new Promise(resolve => setTimeout(resolve, 300)); // 短暂延迟
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
throw new Error(`Target block ${targetBlock} has already passed (current block: ${currentBlock})`);
|
|
157
|
+
}
|
|
146
158
|
}
|
|
147
159
|
else {
|
|
148
|
-
//
|
|
149
|
-
const
|
|
150
|
-
const minBlockOffset = options.minBlockOffset ?? 1;
|
|
151
|
-
const requestedOffset = options.blockOffset ?? 1;
|
|
160
|
+
// 动态计算:确保至少有 minBlockOffset 个区块的窗口
|
|
161
|
+
const requestedOffset = options.blockOffset ?? 3;
|
|
152
162
|
const actualOffset = Math.max(requestedOffset, minBlockOffset);
|
|
153
163
|
targetBlock = currentBlock + actualOffset;
|
|
154
164
|
}
|
|
@@ -161,16 +171,22 @@ export class MerkleClient {
|
|
|
161
171
|
minTimestamp: options.minTimestamp,
|
|
162
172
|
maxTimestamp: options.maxTimestamp,
|
|
163
173
|
});
|
|
164
|
-
//
|
|
165
|
-
const txHashes =
|
|
174
|
+
// 提取交易哈希(添加异常处理)
|
|
175
|
+
const txHashes = [];
|
|
176
|
+
for (let i = 0; i < options.transactions.length; i++) {
|
|
166
177
|
try {
|
|
167
|
-
const tx = Transaction.from(
|
|
168
|
-
|
|
178
|
+
const tx = Transaction.from(options.transactions[i]);
|
|
179
|
+
if (tx.hash) {
|
|
180
|
+
txHashes.push(tx.hash);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
txHashes.push('');
|
|
184
|
+
}
|
|
169
185
|
}
|
|
170
|
-
catch {
|
|
171
|
-
|
|
186
|
+
catch (error) {
|
|
187
|
+
txHashes.push('');
|
|
172
188
|
}
|
|
173
|
-
}
|
|
189
|
+
}
|
|
174
190
|
return {
|
|
175
191
|
bundleHash,
|
|
176
192
|
txHashes,
|
|
@@ -14,9 +14,9 @@ export interface MerkleSubmitConfig {
|
|
|
14
14
|
customRpcUrl?: string;
|
|
15
15
|
/** 链ID(可选,默认56=BSC) */
|
|
16
16
|
chainId?: 56 | 1;
|
|
17
|
-
/** Bundle区块偏移量(可选,默认
|
|
17
|
+
/** Bundle区块偏移量(可选,默认3) */
|
|
18
18
|
bundleBlockOffset?: number;
|
|
19
|
-
/** 最小区块偏移量(可选,默认
|
|
19
|
+
/** 最小区块偏移量(可选,默认3) */
|
|
20
20
|
minBlockOffset?: number;
|
|
21
21
|
/** 是否自动重试(可选,默认false) */
|
|
22
22
|
autoRetryBundle?: boolean;
|
|
@@ -6,21 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { MerkleClient } from '../../clients/merkle.js';
|
|
8
8
|
import { ethers } from 'ethers';
|
|
9
|
-
// ✅ MerkleClient 缓存,避免重复创建 Provider
|
|
10
|
-
const merkleClientCache = new Map();
|
|
11
|
-
function getMerkleClient(config) {
|
|
12
|
-
const cacheKey = `${config.apiKey}-${config.chainId ?? 56}-${config.customRpcUrl ?? ''}`;
|
|
13
|
-
let client = merkleClientCache.get(cacheKey);
|
|
14
|
-
if (!client) {
|
|
15
|
-
client = new MerkleClient({
|
|
16
|
-
apiKey: config.apiKey,
|
|
17
|
-
chainId: config.chainId ?? 56,
|
|
18
|
-
customRpcUrl: config.customRpcUrl
|
|
19
|
-
});
|
|
20
|
-
merkleClientCache.set(cacheKey, client);
|
|
21
|
-
}
|
|
22
|
-
return client;
|
|
23
|
-
}
|
|
24
9
|
/**
|
|
25
10
|
* 提交已签名的交易到Merkle(服务器端使用)
|
|
26
11
|
*
|
|
@@ -67,14 +52,17 @@ export async function submitBundleToMerkle(signedTransactions, config) {
|
|
|
67
52
|
error: 'apiKey is required in config'
|
|
68
53
|
};
|
|
69
54
|
}
|
|
70
|
-
//
|
|
71
|
-
const merkle =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
// 初始化Merkle客户端
|
|
56
|
+
const merkle = new MerkleClient({
|
|
57
|
+
apiKey: config.apiKey,
|
|
58
|
+
chainId: config.chainId ?? 56,
|
|
59
|
+
customRpcUrl: config.customRpcUrl
|
|
60
|
+
});
|
|
61
|
+
// 提交Bundle
|
|
75
62
|
const bundleResult = await merkle.sendBundle({
|
|
76
63
|
transactions: signedTransactions,
|
|
77
|
-
|
|
64
|
+
blockOffset: config.bundleBlockOffset ?? 3,
|
|
65
|
+
minBlockOffset: config.minBlockOffset ?? 3,
|
|
78
66
|
autoRetry: config.autoRetryBundle ?? false,
|
|
79
67
|
maxRetries: config.maxBundleRetries ?? 2
|
|
80
68
|
});
|