@w3lib/evm-batch-call 0.4.1 → 0.5.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/CHANGELOG.md +21 -0
- package/README.md +166 -3
- package/dist/aggregate.d.ts.map +1 -1
- package/dist/aggregate.js +153 -40
- package/dist/aggregate.js.map +1 -1
- package/dist/fallback.d.ts +20 -0
- package/dist/fallback.d.ts.map +1 -1
- package/dist/fallback.js +36 -5
- package/dist/fallback.js.map +1 -1
- package/dist/lp.d.ts +149 -0
- package/dist/lp.d.ts.map +1 -0
- package/dist/lp.js +499 -0
- package/dist/lp.js.map +1 -0
- package/dist/lpMath.d.ts +25 -0
- package/dist/lpMath.d.ts.map +1 -0
- package/dist/lpMath.js +103 -0
- package/dist/lpMath.js.map +1 -0
- package/dist/lpV4.d.ts +108 -0
- package/dist/lpV4.d.ts.map +1 -0
- package/dist/lpV4.js +283 -0
- package/dist/lpV4.js.map +1 -0
- package/dist/owner.d.ts +1 -1
- package/dist/owner.d.ts.map +1 -1
- package/dist/owner.js +18 -5
- package/dist/owner.js.map +1 -1
- package/dist/scan.d.ts +54 -0
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +124 -92
- package/dist/scan.js.map +1 -1
- package/dist/source.d.ts +2 -0
- package/dist/source.d.ts.map +1 -1
- package/dist/source.js +4 -0
- package/dist/source.js.map +1 -1
- package/dist/subpaths/lp.d.ts +33 -0
- package/dist/subpaths/lp.d.ts.map +1 -0
- package/dist/subpaths/lp.js +47 -0
- package/dist/subpaths/lp.js.map +1 -0
- package/dist/subpaths/write.d.ts +20 -0
- package/dist/subpaths/write.d.ts.map +1 -0
- package/dist/subpaths/write.js +18 -0
- package/dist/subpaths/write.js.map +1 -0
- package/dist/tron.d.ts +2 -0
- package/dist/tron.d.ts.map +1 -1
- package/dist/tron.js +4 -0
- package/dist/tron.js.map +1 -1
- package/dist/write/batch.d.ts +88 -0
- package/dist/write/batch.d.ts.map +1 -0
- package/dist/write/batch.js +231 -0
- package/dist/write/batch.js.map +1 -0
- package/dist/write/collect.d.ts +53 -0
- package/dist/write/collect.d.ts.map +1 -0
- package/dist/write/collect.js +255 -0
- package/dist/write/collect.js.map +1 -0
- package/dist/write/rpc.d.ts +68 -0
- package/dist/write/rpc.d.ts.map +1 -0
- package/dist/write/rpc.js +236 -0
- package/dist/write/rpc.js.map +1 -0
- package/dist/write/send.d.ts +124 -0
- package/dist/write/send.d.ts.map +1 -0
- package/dist/write/send.js +373 -0
- package/dist/write/send.js.map +1 -0
- package/dist/write/signer.d.ts +58 -0
- package/dist/write/signer.d.ts.map +1 -0
- package/dist/write/signer.js +41 -0
- package/dist/write/signer.js.map +1 -0
- package/dist/write/transfer.d.ts +83 -0
- package/dist/write/transfer.d.ts.map +1 -0
- package/dist/write/transfer.js +259 -0
- package/dist/write/transfer.js.map +1 -0
- package/dist/write/tron.d.ts +58 -0
- package/dist/write/tron.d.ts.map +1 -0
- package/dist/write/tron.js +956 -0
- package/dist/write/tron.js.map +1 -0
- package/package.json +27 -14
- package/src/aggregate.ts +168 -36
- package/src/fallback.ts +55 -11
- package/src/lp.ts +721 -0
- package/src/lpMath.ts +113 -0
- package/src/lpV4.ts +406 -0
- package/src/owner.ts +19 -6
- package/src/scan.ts +155 -86
- package/src/source.ts +5 -0
- package/src/subpaths/lp.ts +71 -0
- package/src/subpaths/write.ts +26 -0
- package/src/tron.ts +5 -0
- package/src/write/batch.ts +302 -0
- package/src/write/collect.ts +312 -0
- package/src/write/rpc.ts +277 -0
- package/src/write/send.ts +490 -0
- package/src/write/signer.ts +90 -0
- package/src/write/transfer.ts +344 -0
- package/src/write/tron.ts +1100 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { Interface, getAddress, getBigInt } from 'ethers';
|
|
2
|
+
import { ERC20_ABI, NATIVE_TOKEN, formatUnits } from '../erc20.js';
|
|
3
|
+
import { isExecutionError } from '../errors.js';
|
|
4
|
+
import { WriteRpc, failureText, l1Fee } from './rpc.js';
|
|
5
|
+
import { FeeSource, applyGasMultiplier, emptyOutcome, mapPool, sendJobs, toWriteResult } from './send.js';
|
|
6
|
+
import { resolveSigner } from './signer.js';
|
|
7
|
+
import { tronModule } from './batch.js';
|
|
8
|
+
import { batchTransfer } from './transfer.js';
|
|
9
|
+
const erc20Interface = new Interface(ERC20_ABI);
|
|
10
|
+
/** 预估代币转账 gas 失败(有的节点对没有主币的地址预估时报余额不足)时用的 gasLimit */
|
|
11
|
+
const FALLBACK_TOKEN_GAS = 120000n;
|
|
12
|
+
/**
|
|
13
|
+
* 归集:多个钱包的代币 / 主币转到同一个地址。每个钱包内按代币顺序逐笔发送,钱包之间并发。
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const { results, topUps } = await batchCollect(multi, [key1, key2, key3], hotWallet, {
|
|
17
|
+
* tokens: [USDT, NATIVE_TOKEN], // 主币放在里面表示代币归集完后扫空剩余主币
|
|
18
|
+
* gasWallet: gasKey, // 子钱包主币不够付手续费时先从这里补
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* 流程:一次 multicall 读出所有钱包的余额 → 预估每笔归集的手续费 → 给不够的钱包补 gas(等确认)
|
|
23
|
+
* → 发代币归集 → (包含主币时)等代币归集确认、按最新余额扫空主币。
|
|
24
|
+
* dryRun 时只做到预估,返回计划(补多少 gas、每笔 gasLimit),不发任何交易
|
|
25
|
+
*/
|
|
26
|
+
export async function batchCollect(provider, wallets, to, options) {
|
|
27
|
+
const tron = await tronModule(provider);
|
|
28
|
+
if (tron) {
|
|
29
|
+
return tron.tronBatchCollect(provider, wallets, to, options);
|
|
30
|
+
}
|
|
31
|
+
const rpc = await WriteRpc.from(provider);
|
|
32
|
+
const target = getAddress(to);
|
|
33
|
+
const cache = new Map();
|
|
34
|
+
const signers = await Promise.all(wallets.map((w) => resolveSigner(w, cache)));
|
|
35
|
+
const tokens = options.tokens;
|
|
36
|
+
const nativeIndex = tokens.findIndex((t) => provider.isNativeToken(t));
|
|
37
|
+
const sweep = nativeIndex >= 0;
|
|
38
|
+
const multiplier = options.gasMultiplier;
|
|
39
|
+
// 一次 multicall 读出所有钱包的代币余额 + 主币余额(算手续费要用)
|
|
40
|
+
const queryTokens = sweep ? [...tokens] : [...tokens, NATIVE_TOKEN];
|
|
41
|
+
const nativeAt = sweep ? nativeIndex : tokens.length;
|
|
42
|
+
const balances = await provider.multiBalances(signers.map((s) => ({ owner: s.address, tokens: queryTokens })));
|
|
43
|
+
const minAmount = new Map(Object.entries(options.minAmount ?? {}).map(([k, v]) => [k.toLowerCase(), getBigInt(v)]));
|
|
44
|
+
const items = [];
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
signers.forEach((signer, w) => {
|
|
47
|
+
const duplicate = seen.has(signer.address.toLowerCase());
|
|
48
|
+
seen.add(signer.address.toLowerCase());
|
|
49
|
+
tokens.forEach((token, t) => {
|
|
50
|
+
const balance = balances[w]?.[t];
|
|
51
|
+
const native = t === nativeIndex;
|
|
52
|
+
const decimals = balance.success ? balance.decimals : null;
|
|
53
|
+
const item = {
|
|
54
|
+
index: w * tokens.length + t,
|
|
55
|
+
signer,
|
|
56
|
+
token: native ? token : getAddress(token),
|
|
57
|
+
native,
|
|
58
|
+
amount: native ? 0n : balance.success ? BigInt(balance.balance) : 0n,
|
|
59
|
+
decimals,
|
|
60
|
+
gasLimit: null,
|
|
61
|
+
result: null,
|
|
62
|
+
};
|
|
63
|
+
const skip = !balance.success
|
|
64
|
+
? `cannot read balance: ${balance.error ?? 'unknown error'}`
|
|
65
|
+
: signer.address === target
|
|
66
|
+
? 'skipped: wallet is the collect address'
|
|
67
|
+
: duplicate
|
|
68
|
+
? 'skipped: duplicate wallet'
|
|
69
|
+
: !native && item.amount === 0n
|
|
70
|
+
? 'skipped: zero balance'
|
|
71
|
+
: !native && item.amount < (minAmount.get(token.toLowerCase()) ?? 0n)
|
|
72
|
+
? 'skipped: below minAmount'
|
|
73
|
+
: null;
|
|
74
|
+
item.result = toCollectResult(item, target, emptyOutcome(skip ? (balance.success ? 'skipped' : 'failed') : 'skipped', skip));
|
|
75
|
+
items.push(item);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
const results = items.map((i) => i.result);
|
|
79
|
+
const report = (item, outcome) => {
|
|
80
|
+
item.result = toCollectResult(item, target, outcome);
|
|
81
|
+
results[item.index] = item.result;
|
|
82
|
+
options.onUpdate?.(item.result);
|
|
83
|
+
};
|
|
84
|
+
const active = (item) => item.result.error === null;
|
|
85
|
+
// 预估每个钱包的代币归集 gas,算出需要补多少主币。
|
|
86
|
+
// 手续费价格只取这一次,代币归集也按它发:补 gas 等确认期间节点报价上涨,也不会超出补的数量、因余额不足被拒
|
|
87
|
+
const fee = await new FeeSource(rpc, options).get();
|
|
88
|
+
const fees = FeeSource.fixed(rpc, fee);
|
|
89
|
+
const byWallet = new Map();
|
|
90
|
+
items.forEach((item) => {
|
|
91
|
+
if (active(item)) {
|
|
92
|
+
byWallet.set(item.signer.address, [...(byWallet.get(item.signer.address) ?? []), item]);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const plans = await mapPool([...byWallet.entries()], options.concurrency ?? 8, async ([address, list]) => {
|
|
96
|
+
const native = balances[signers.findIndex((s) => s.address === address)]?.[nativeAt];
|
|
97
|
+
if (!native.success) {
|
|
98
|
+
// 主币余额读不到:不知道要补多少,不补(按 0 算会多补,而这个钱包也不会扫主币,多补的收不回来)
|
|
99
|
+
list.filter((i) => !i.native).forEach((i) => report(i, emptyOutcome('failed', `cannot read the native balance: ${native.error ?? 'unknown error'}`)));
|
|
100
|
+
return { address, list, shortfall: 0n };
|
|
101
|
+
}
|
|
102
|
+
let need = 0n;
|
|
103
|
+
for (const item of list) {
|
|
104
|
+
if (item.native) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const tx = { from: address, to: item.token, data: erc20Interface.encodeFunctionData('transfer', [target, item.amount]) };
|
|
108
|
+
try {
|
|
109
|
+
item.gasLimit = applyGasMultiplier(await rpc.estimateGas(tx), multiplier);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
if (!/insufficient funds/i.test(failureText(err))) {
|
|
113
|
+
report(item, { ...emptyOutcome('failed', failureText(err)) });
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
item.gasLimit = FALLBACK_TOKEN_GAS;
|
|
117
|
+
}
|
|
118
|
+
need += item.gasLimit * fee.perGas + (await l1Fee(rpc, { ...tx, from: undefined, gasLimit: item.gasLimit, ...feeFields(fee) }));
|
|
119
|
+
}
|
|
120
|
+
const wallet = signers.findIndex((s) => s.address === address);
|
|
121
|
+
const nativeBalance = BigInt((balances[wallet]?.[nativeAt]).balance);
|
|
122
|
+
const buffered = (need * BigInt(Math.round((options.gasBuffer ?? 1) * 1000))) / 1000n;
|
|
123
|
+
return { address, list, shortfall: buffered > nativeBalance ? buffered - nativeBalance : 0n };
|
|
124
|
+
});
|
|
125
|
+
// 补 gas
|
|
126
|
+
let topUps = [];
|
|
127
|
+
const short = plans.filter((p) => p.shortfall > 0n && p.list.some((i) => !i.native && active(i)));
|
|
128
|
+
if (short.length) {
|
|
129
|
+
if (!options.gasWallet) {
|
|
130
|
+
short.forEach((p) => p.list.filter((i) => !i.native && active(i)).forEach((i) => report(i, emptyOutcome('failed', `insufficient native balance for gas: need ${p.shortfall} more wei (pass gasWallet to top up automatically)`))));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
topUps = await batchTransfer(provider, options.gasWallet, short.map((p) => ({ to: p.address, amount: p.shortfall, token: NATIVE_TOKEN })), { ...sendOptions(options), mode: options.gasMode ?? 'disperse', wait: true });
|
|
134
|
+
topUps.forEach((t, k) => {
|
|
135
|
+
const ok = t.status === 'confirmed' || (options.dryRun && t.status === 'simulated');
|
|
136
|
+
if (!ok) {
|
|
137
|
+
;
|
|
138
|
+
short[k].list.filter((i) => !i.native && active(i)).forEach((i) => report(i, emptyOutcome('failed', `gas top-up ${t.status}: ${t.error ?? ''}`.trim())));
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// 代币归集
|
|
144
|
+
const tokenItems = items.filter((i) => !i.native && active(i));
|
|
145
|
+
if (options.dryRun) {
|
|
146
|
+
tokenItems.forEach((i) => report(i, { ...emptyOutcome('simulated'), gasLimit: i.gasLimit }));
|
|
147
|
+
if (sweep) {
|
|
148
|
+
items.filter((i) => i.native && active(i)).forEach((i) => report(i, { ...emptyOutcome('simulated'), gasLimit: 21000n }));
|
|
149
|
+
}
|
|
150
|
+
return { results, topUps };
|
|
151
|
+
}
|
|
152
|
+
const minBlock = new Map();
|
|
153
|
+
topUps.forEach((t) => t.blockNumber !== null && minBlock.set(getAddress(t.to), t.blockNumber));
|
|
154
|
+
const track = (item, outcome) => {
|
|
155
|
+
if (outcome.blockNumber !== null) {
|
|
156
|
+
minBlock.set(item.signer.address, Math.max(minBlock.get(item.signer.address) ?? 0, outcome.blockNumber));
|
|
157
|
+
}
|
|
158
|
+
report(item, outcome);
|
|
159
|
+
};
|
|
160
|
+
// 发送前重新预估(不用补 gas 前的 gasLimit):预估时余额不足、用了兜底值的项按实际需要发;余额变了的项预估失败,不会上链 revert 白付手续费
|
|
161
|
+
const jobs = tokenItems.map((item) => ({
|
|
162
|
+
signer: item.signer,
|
|
163
|
+
continueOnError: true,
|
|
164
|
+
build: async () => ({ to: item.token, data: erc20Interface.encodeFunctionData('transfer', [target, item.amount]), value: 0n }),
|
|
165
|
+
onUpdate: (outcome) => track(item, outcome),
|
|
166
|
+
}));
|
|
167
|
+
// 要扫主币时必须等代币归集确认(扫的是扣完手续费后的余额)
|
|
168
|
+
await sendJobs(rpc, jobs, sweep ? { ...options, wait: true } : options, fees);
|
|
169
|
+
// 代币没有全部归集成功的钱包不扫主币:留着付之后重新归集的手续费;还没确认的交易也要用这部分主币付手续费
|
|
170
|
+
items
|
|
171
|
+
.filter((i) => i.native && active(i))
|
|
172
|
+
.forEach((native) => {
|
|
173
|
+
const unfinished = items.find((i) => !i.native && i.signer.address === native.signer.address && i.result.status !== 'confirmed' && i.result.status !== 'skipped');
|
|
174
|
+
if (unfinished) {
|
|
175
|
+
report(native, emptyOutcome('skipped', `skipped: collecting ${unfinished.token} did not succeed (${unfinished.result.status})`));
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
// 扫空主币:按最新余额(不早于该钱包最后一笔确认交易的区块)减去这笔的手续费
|
|
179
|
+
const sweepItems = items.filter((i) => i.native && active(i));
|
|
180
|
+
if (sweep && sweepItems.length && !options.signal?.aborted) {
|
|
181
|
+
// 代币归集已经发出:这一阶段出错不能整体抛错(调用方会拿不到这些结果),扫主币的项标记失败
|
|
182
|
+
const failSweep = (error) => {
|
|
183
|
+
sweepItems.forEach((i) => report(i, emptyOutcome('failed', error)));
|
|
184
|
+
return { results, topUps };
|
|
185
|
+
};
|
|
186
|
+
let sweepFee;
|
|
187
|
+
try {
|
|
188
|
+
sweepFee = await new FeeSource(rpc, options).get();
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
return failSweep(`cannot get the fee data: ${failureText(err)}`);
|
|
192
|
+
}
|
|
193
|
+
let gasLimit = 21000n;
|
|
194
|
+
try {
|
|
195
|
+
gasLimit = applyGasMultiplier(await rpc.estimateGas({ from: sweepItems[0].signer.address, to: target, value: 1n }), multiplier);
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
// 归集地址拒收主币(如没有 receive 的合约):发了也必然 revert,白付手续费
|
|
199
|
+
if (isExecutionError(err))
|
|
200
|
+
return failSweep(`the collect address cannot receive the native coin: ${failureText(err)}`);
|
|
201
|
+
// 节点暂时出错:按普通转账
|
|
202
|
+
}
|
|
203
|
+
const sweepJobs = await mapPool(sweepItems, options.concurrency ?? 8, async (item) => {
|
|
204
|
+
const block = minBlock.get(item.signer.address);
|
|
205
|
+
let balance;
|
|
206
|
+
try {
|
|
207
|
+
;
|
|
208
|
+
[balance] = await provider.balances(item.signer.address, [NATIVE_TOKEN], block === undefined ? {} : { minBlock: block });
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
// 代币归集已经发出:不能整体抛错(调用方会拿不到这些结果),这一项标记失败
|
|
212
|
+
report(item, emptyOutcome('failed', `cannot read balance: ${failureText(err)}`));
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
if (!balance?.success) {
|
|
216
|
+
report(item, emptyOutcome('failed', `cannot read balance: ${balance?.error ?? 'unknown error'}`));
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const reserve = gasLimit * sweepFee.perGas + (await l1Fee(rpc, { to: target, value: BigInt(balance.balance), gasLimit, ...feeFields(sweepFee) }));
|
|
220
|
+
const amount = BigInt(balance.balance) - reserve;
|
|
221
|
+
if (amount <= 0n) {
|
|
222
|
+
report(item, emptyOutcome('skipped', 'skipped: native balance does not cover the gas fee'));
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
item.amount = amount;
|
|
226
|
+
return {
|
|
227
|
+
signer: item.signer,
|
|
228
|
+
gasLimit,
|
|
229
|
+
continueOnError: true,
|
|
230
|
+
build: async () => ({ to: target, data: '0x', value: amount }),
|
|
231
|
+
onUpdate: (outcome) => report(item, outcome),
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
await sendJobs(rpc, sweepJobs.filter((j) => j !== null), options, FeeSource.fixed(rpc, sweepFee));
|
|
235
|
+
}
|
|
236
|
+
return { results, topUps };
|
|
237
|
+
}
|
|
238
|
+
/** 只保留发送参数(补 gas 时不带 tokens / onUpdate 等归集参数) */
|
|
239
|
+
function sendOptions(options) {
|
|
240
|
+
const { tokens: _tokens, gasWallet: _gasWallet, gasMode: _gasMode, gasBuffer: _gasBuffer, minAmount: _minAmount, onUpdate: _onUpdate, ...rest } = options;
|
|
241
|
+
return rest;
|
|
242
|
+
}
|
|
243
|
+
function feeFields(fee) {
|
|
244
|
+
return fee.type === 2 ? { type: 2, maxFeePerGas: fee.maxFeePerGas, maxPriorityFeePerGas: fee.maxPriorityFeePerGas } : { type: 0, gasPrice: fee.gasPrice };
|
|
245
|
+
}
|
|
246
|
+
function toCollectResult(item, to, outcome) {
|
|
247
|
+
return {
|
|
248
|
+
...toWriteResult(item.index, item.signer.address, to, outcome),
|
|
249
|
+
token: item.token,
|
|
250
|
+
native: item.native,
|
|
251
|
+
amount: item.amount.toString(),
|
|
252
|
+
formatted: item.decimals === null ? null : formatUnits(item.amount, item.decimals),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=collect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.js","sourceRoot":"","sources":["../../src/write/collect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAqB,MAAM,QAAQ,CAAA;AAE5E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAqB,MAAM,aAAa,CAAA;AAErF,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACvD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAqG,MAAM,WAAW,CAAA;AAC5M,OAAO,EAAE,aAAa,EAAyC,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,aAAa,EAAuB,MAAM,eAAe,CAAA;AAElE,MAAM,cAAc,GAAG,IAAI,SAAS,CAAC,SAAgC,CAAC,CAAA;AAEtE,sDAAsD;AACtD,MAAM,kBAAkB,GAAG,OAAQ,CAAA;AAgDnC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAkB,EAAE,OAA+B,EAAE,EAAU,EAAE,OAA4B;IAC9H,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAA;IACvC,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACzC,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC,CAAA;IAC7B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAE,CAAA;IACvB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;IAC9E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAC7B,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACtE,MAAM,KAAK,GAAG,WAAW,IAAI,CAAC,CAAA;IAC9B,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAA;IAExC,0CAA0C;IAC1C,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,YAAY,CAAC,CAAA;IACnE,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAA;IACpD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9G,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAEnH,MAAM,KAAK,GAAW,EAAE,CAAA;IACxB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;QACxD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;QACtC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YAC1B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAiB,CAAA;YAChD,MAAM,MAAM,GAAG,CAAC,KAAK,WAAW,CAAA;YAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAA;YAC1D,MAAM,IAAI,GAAS;gBACjB,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC;gBAC5B,MAAM;gBACN,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC;gBACzC,MAAM;gBACN,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;gBACpE,QAAQ;gBACR,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,IAAoC;aAC7C,CAAA;YACD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO;gBAC3B,CAAC,CAAC,wBAAwB,OAAO,CAAC,KAAK,IAAI,eAAe,EAAE;gBAC5D,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,MAAM;oBACzB,CAAC,CAAC,wCAAwC;oBAC1C,CAAC,CAAC,SAAS;wBACT,CAAC,CAAC,2BAA2B;wBAC7B,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE;4BAC7B,CAAC,CAAC,uBAAuB;4BACzB,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;gCACnE,CAAC,CAAC,0BAA0B;gCAC5B,CAAC,CAAC,IAAI,CAAA;YAChB,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAA;YAC5H,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,CAAC,IAAU,EAAE,OAAkB,EAAE,EAAE;QAChD,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QACpD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,CAAA;QACjC,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACjC,CAAC,CAAA;IACD,MAAM,MAAM,GAAG,CAAC,IAAU,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAA;IAEzD,6BAA6B;IAC7B,0DAA0D;IAC1D,MAAM,GAAG,GAAG,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,EAAE,CAAA;IACnD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC1C,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACrB,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACjB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAA;QACzF,CAAC;IACH,CAAC,CAAC,CAAA;IACF,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,WAAW,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;QACvG,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAiB,CAAA;QACpG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,mDAAmD;YACnD,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,QAAQ,EAAE,mCAAmC,MAAM,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,CAAA;YACrJ,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;QACzC,CAAC;QACD,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,SAAQ;YACV,CAAC;YACD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAA;YACxH,IAAI,CAAC;gBACH,IAAI,CAAC,QAAQ,GAAG,kBAAkB,CAAC,MAAM,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,CAAA;YAC3E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBAClD,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAA;oBAC7D,SAAQ;gBACV,CAAC;gBACD,IAAI,CAAC,QAAQ,GAAG,kBAAkB,CAAA;YACpC,CAAC;YACD,IAAI,IAAI,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QACjI,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAA;QAC9D,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAkB,CAAA,CAAC,OAAO,CAAC,CAAA;QACpF,MAAM,QAAQ,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;QACrF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;IAC/F,CAAC,CAAC,CAAA;IAEF,QAAQ;IACR,IAAI,MAAM,GAAqB,EAAE,CAAA;IACjC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACjG,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YACvB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,QAAQ,EAAE,6CAA6C,CAAC,CAAC,SAAS,oDAAoD,CAAC,CAAC,CAAC,CAAC,CAAA;QACpO,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,MAAM,aAAa,CAC1B,QAAQ,EACR,OAAO,CAAC,SAAS,EACjB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,EAC/E,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,IAAI,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,CAC7E,CAAA;YACD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACtB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAA;gBACnF,IAAI,CAAC,EAAE,EAAE,CAAC;oBACR,CAAC;oBAAC,KAAK,CAAC,CAAC,CAA4B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;gBACvL,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,OAAO;IACP,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAC9D,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QAC5F,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAO,EAAE,CAAC,CAAC,CAAA;QAC3H,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;IAC5B,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAA;IAC9F,MAAM,KAAK,GAAG,CAAC,IAAU,EAAE,OAAkB,EAAE,EAAE;QAC/C,IAAI,OAAO,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YACjC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAA;QAC1G,CAAC;QACD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACvB,CAAC,CAAA;IACD,kFAAkF;IAClF,MAAM,IAAI,GAAY,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,eAAe,EAAE,IAAI;QACrB,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC9H,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;KAC5C,CAAC,CAAC,CAAA;IACH,+BAA+B;IAC/B,MAAM,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAE7E,sDAAsD;IACtD,KAAK;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;SACpC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QAClB,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAA;QACjK,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,SAAS,EAAE,uBAAuB,UAAU,CAAC,KAAK,qBAAqB,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAClI,CAAC;IACH,CAAC,CAAC,CAAA;IAEJ,wCAAwC;IACxC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7D,IAAI,KAAK,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QAC3D,+CAA+C;QAC/C,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE;YAClC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;YACnE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;QAC5B,CAAC,CAAA;QACD,IAAI,QAAgB,CAAA;QACpB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,EAAE,CAAA;QACpD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,SAAS,CAAC,4BAA4B,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAClE,CAAC;QACD,IAAI,QAAQ,GAAG,MAAO,CAAA;QACtB,IAAI,CAAC;YACH,QAAQ,GAAG,kBAAkB,CAAC,MAAM,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAG,UAAU,CAAC,CAAC,CAAU,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,EAAE,UAAU,CAAC,CAAA;QAC3I,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,+CAA+C;YAC/C,IAAI,gBAAgB,CAAC,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAC,uDAAuD,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACtH,eAAe;QACjB,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,WAAW,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAyB,EAAE;YAC1G,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC/C,IAAI,OAAiC,CAAA;YACrC,IAAI,CAAC;gBACH,CAAC;gBAAA,CAAC,OAAO,CAAC,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;YAC3H,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,uCAAuC;gBACvC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,wBAAwB,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;gBAChF,OAAO,IAAI,CAAA;YACb,CAAC;YACD,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,wBAAwB,OAAO,EAAE,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC,CAAA;gBACjG,OAAO,IAAI,CAAA;YACb,CAAC;YACD,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;YACjJ,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;YAChD,IAAI,MAAM,IAAI,EAAE,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,SAAS,EAAE,oDAAoD,CAAC,CAAC,CAAA;gBAC3F,OAAO,IAAI,CAAA;YACb,CAAC;YACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;YACpB,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ;gBACR,eAAe,EAAE,IAAI;gBACrB,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;gBAC9D,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC;aAC7C,CAAA;QACH,CAAC,CAAC,CAAA;QACF,MAAM,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAc,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;IAC/G,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;AAC5B,CAAC;AAED,iDAAiD;AACjD,SAAS,WAAW,CAAC,OAA4B;IAC/C,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IACzJ,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAA;AAC3J,CAAC;AAED,SAAS,eAAe,CAAC,IAAU,EAAE,EAAU,EAAE,OAAkB;IACjE,OAAO;QACL,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC;QAC9D,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;QAC9B,SAAS,EAAE,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;KACnF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type TransactionReceipt, type TransactionRequest } from 'ethers';
|
|
2
|
+
import type { EthersLikeProvider } from '../aggregate.js';
|
|
3
|
+
import type { Provider } from '../provider.js';
|
|
4
|
+
export interface FeeData {
|
|
5
|
+
gasPrice: bigint | null;
|
|
6
|
+
maxFeePerGas: bigint | null;
|
|
7
|
+
maxPriorityFeePerGas: bigint | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 广播结果:已进交易池(含节点说已经有这笔);nonce 已被用掉(可能就是这笔已上链,也可能被别的交易占用);
|
|
11
|
+
* 或不确定(超时、连接失败,或前一个节点超时后另一个节点拒绝:前一个节点也许已经收下了),交易可能已经发出
|
|
12
|
+
*/
|
|
13
|
+
export type BroadcastOutcome = 'accepted' | 'nonce-used' | {
|
|
14
|
+
uncertain: string;
|
|
15
|
+
};
|
|
16
|
+
/** 广播被节点明确拒绝、换节点也一样(交易没进交易池) */
|
|
17
|
+
export declare function isFinalBroadcastError(err: unknown): boolean;
|
|
18
|
+
/** 预估 / 执行失败的可读原因:优先解析 revert 数据(Error(string) / Panic),否则取节点的原始信息 */
|
|
19
|
+
export declare function failureText(err: unknown): string;
|
|
20
|
+
/** 预估 gas 时 revert 带回的数据(解析 7702 批量执行里是第几个调用失败用) */
|
|
21
|
+
export declare function revertData(err: unknown): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* 在 Provider 的节点上执行请求:多节点时与 call / getBalance 相同的故障切换(ChainCheckedProvider 先校验链);
|
|
24
|
+
* isFinal 判定为确定性的错误(revert、余额不足等)直接抛出,不拿去别的节点重试
|
|
25
|
+
*/
|
|
26
|
+
export declare function runOnNodes<T>(rpc: EthersLikeProvider, method: string, fn: (node: EthersLikeProvider) => Promise<T>, isFinal?: (err: unknown) => boolean): Promise<T>;
|
|
27
|
+
/**
|
|
28
|
+
* 写操作的节点访问:nonce、fee、预估 gas、广播、查回执,都经过 Provider 的多节点故障切换。
|
|
29
|
+
* 确定性错误(revert、余额不足等)直接抛出,不拿去别的节点重试
|
|
30
|
+
*/
|
|
31
|
+
export declare class WriteRpc {
|
|
32
|
+
#private;
|
|
33
|
+
readonly rpc: EthersLikeProvider;
|
|
34
|
+
readonly chainId: number;
|
|
35
|
+
constructor(rpc: EthersLikeProvider, chainId: number);
|
|
36
|
+
static from(provider: Provider): Promise<WriteRpc>;
|
|
37
|
+
/**
|
|
38
|
+
* 下一个可用的 nonce:节点的 pending 计数(含交易池里待确认的交易)与本次已用过的取大者。
|
|
39
|
+
* 多节点时先返回的节点可能还没看到刚发出的交易,只信节点会拿到已用过的 nonce
|
|
40
|
+
*/
|
|
41
|
+
nonce(address: string): Promise<number>;
|
|
42
|
+
/** 已上链的交易数(latest nonce) */
|
|
43
|
+
latestNonce(address: string): Promise<number>;
|
|
44
|
+
/** 记录 nonce 已被占用(交易已广播,或节点说已被用掉) */
|
|
45
|
+
useNonce(address: string, nonce: number): void;
|
|
46
|
+
code(address: string): Promise<string>;
|
|
47
|
+
feeData(): Promise<FeeData>;
|
|
48
|
+
/** 预估 gas;revert / 余额不足等直接抛出(error.data 是 revert 数据) */
|
|
49
|
+
estimateGas(tx: TransactionRequest): Promise<bigint>;
|
|
50
|
+
/** eth_call;revert 直接抛出 */
|
|
51
|
+
call(tx: TransactionRequest): Promise<string>;
|
|
52
|
+
/**
|
|
53
|
+
* 广播已签名的交易。同一笔签名交易重复广播是安全的:节点说已经有了视为成功;
|
|
54
|
+
* nonce 已被用掉时返回 'nonce-used'(调用方查回执确认是不是这笔已上链)。其他交易本身的问题直接抛出
|
|
55
|
+
*/
|
|
56
|
+
broadcast(signed: string): Promise<BroadcastOutcome>;
|
|
57
|
+
receipt(hash: string): Promise<TransactionReceipt | null>;
|
|
58
|
+
}
|
|
59
|
+
/** 已签名交易的哈希 */
|
|
60
|
+
export declare function signedHash(signed: string): string;
|
|
61
|
+
/** 测试用 */
|
|
62
|
+
export declare function resetL1OracleCache(): void;
|
|
63
|
+
/**
|
|
64
|
+
* 交易的 L1 数据费(OP Stack / Scroll),其他链为 0。结果加 25% 余量(L1 gas 价格在交易上链前可能上涨)。
|
|
65
|
+
* 查询失败时返回 0(不阻塞发送,只影响扫空主币时的预留)
|
|
66
|
+
*/
|
|
67
|
+
export declare function l1Fee(rpc: WriteRpc, tx: TransactionRequest): Promise<bigint>;
|
|
68
|
+
//# sourceMappingURL=rpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../src/write/rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoE,KAAK,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AAE3I,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAGzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAO9C,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,YAAY,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAA;AAchF,gCAAgC;AAChC,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE3D;AAcD,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAOhD;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAGtD;AASD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAqB,GAAG,OAAO,CAAC,CAAC,CAAC,CAiBvL;AAED;;;GAGG;AACH,qBAAa,QAAQ;;IAEjB,QAAQ,CAAC,GAAG,EAAE,kBAAkB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM;gBADf,GAAG,EAAE,kBAAkB,EACvB,OAAO,EAAE,MAAM;WAGb,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAyBxD;;;OAGG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK7C,4BAA4B;IAC5B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7C,oCAAoC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK9C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIhC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAKjC,wDAAwD;IACxD,WAAW,CAAC,EAAE,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAIpD,2BAA2B;IAC3B,IAAI,CAAC,EAAE,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7C;;;OAGG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuC1D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;CAG1D;AAED,eAAe;AACf,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AASD,UAAU;AACV,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAuBD;;;GAGG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAalF"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { Interface, Transaction, isError } from 'ethers';
|
|
2
|
+
import { decodeRevertReason, isExecutionError } from '../errors.js';
|
|
3
|
+
import { FallbackRpc, errorText } from '../fallback.js';
|
|
4
|
+
import { ChainCheckedProvider } from '../source.js';
|
|
5
|
+
import { TronProvider, isTronChain } from '../tron.js';
|
|
6
|
+
/** 换节点也不会变的失败(余额不足、revert、gas 参数不合法等),不再请求其他节点 */
|
|
7
|
+
class Final {
|
|
8
|
+
error;
|
|
9
|
+
constructor(error) {
|
|
10
|
+
this.error = error;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
// 节点对“交易池里已经有这笔交易”的各种说法:同一笔签名交易发到多个节点 / 重发时会遇到,视为成功
|
|
14
|
+
const ALREADY_KNOWN_RE = /already known|known transaction|already imported|already exists|alreadyknown|already in (the )?(tx|transaction)?\s*pool/i;
|
|
15
|
+
const NONCE_USED_RE = /nonce too low|nonce has already been used|nonce is too low|invalid nonce|old nonce/i;
|
|
16
|
+
// 交易本身的问题:换节点结果一样
|
|
17
|
+
const TX_INVALID_RE = /insufficient funds|intrinsic gas too low|exceeds block gas limit|gas limit reached|max fee per gas less than block base fee|fee cap less than block base fee|underpriced|tip higher than|max priority fee per gas higher than|invalid sender|invalid chain id|only replay-protected|transaction type not supported|tx type not supported|oversized data/i;
|
|
18
|
+
/** 广播被节点明确拒绝、换节点也一样(交易没进交易池) */
|
|
19
|
+
export function isFinalBroadcastError(err) {
|
|
20
|
+
return isError(err, 'INSUFFICIENT_FUNDS') || isError(err, 'REPLACEMENT_UNDERPRICED') || isError(err, 'INVALID_ARGUMENT') || TX_INVALID_RE.test(errorText(err));
|
|
21
|
+
}
|
|
22
|
+
/** 节点明确拒绝了这笔交易(给出了 JSON-RPC 错误,或限频):交易肯定没进这个节点的交易池 */
|
|
23
|
+
function isRejection(err) {
|
|
24
|
+
const e = err;
|
|
25
|
+
const message = e?.error?.message ?? e?.info?.error?.message;
|
|
26
|
+
if (isFinalBroadcastError(err) || /too many requests|rate.?limit|\b429\b/i.test(errorText(err)))
|
|
27
|
+
return true;
|
|
28
|
+
return typeof message === 'string' && !/timeout|timed out|busy|unavailable|overload|try again/i.test(message);
|
|
29
|
+
}
|
|
30
|
+
function isFinalEstimateError(err) {
|
|
31
|
+
return isExecutionError(err) || isError(err, 'INSUFFICIENT_FUNDS') || isError(err, 'INVALID_ARGUMENT') || /insufficient funds|gas required exceeds allowance|transaction type not supported/i.test(errorText(err));
|
|
32
|
+
}
|
|
33
|
+
/** 预估 / 执行失败的可读原因:优先解析 revert 数据(Error(string) / Panic),否则取节点的原始信息 */
|
|
34
|
+
export function failureText(err) {
|
|
35
|
+
const data = err?.data;
|
|
36
|
+
const reason = typeof data === 'string' ? decodeRevertReason(data) : null;
|
|
37
|
+
if (reason) {
|
|
38
|
+
return `execution reverted: ${reason}`;
|
|
39
|
+
}
|
|
40
|
+
return errorText(err);
|
|
41
|
+
}
|
|
42
|
+
/** 预估 gas 时 revert 带回的数据(解析 7702 批量执行里是第几个调用失败用) */
|
|
43
|
+
export function revertData(err) {
|
|
44
|
+
const data = err?.data;
|
|
45
|
+
return typeof data === 'string' && data !== '0x' ? data : null;
|
|
46
|
+
}
|
|
47
|
+
function asWriteNode(node, method) {
|
|
48
|
+
if (typeof node[method] !== 'function') {
|
|
49
|
+
throw new Error(`${method} is not supported by this node; pass an RPC URL or an ethers Provider`);
|
|
50
|
+
}
|
|
51
|
+
return node;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 在 Provider 的节点上执行请求:多节点时与 call / getBalance 相同的故障切换(ChainCheckedProvider 先校验链);
|
|
55
|
+
* isFinal 判定为确定性的错误(revert、余额不足等)直接抛出,不拿去别的节点重试
|
|
56
|
+
*/
|
|
57
|
+
export async function runOnNodes(rpc, method, fn, isFinal = () => false) {
|
|
58
|
+
const guarded = (node) => {
|
|
59
|
+
if (node instanceof ChainCheckedProvider) {
|
|
60
|
+
return node.request((inner) => guarded(inner));
|
|
61
|
+
}
|
|
62
|
+
return fn(node).catch((err) => {
|
|
63
|
+
if (isFinal(err)) {
|
|
64
|
+
return new Final(err);
|
|
65
|
+
}
|
|
66
|
+
throw err;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const result = rpc instanceof FallbackRpc ? await rpc.request(method, guarded) : await guarded(rpc);
|
|
70
|
+
if (result instanceof Final) {
|
|
71
|
+
throw result.error;
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 写操作的节点访问:nonce、fee、预估 gas、广播、查回执,都经过 Provider 的多节点故障切换。
|
|
77
|
+
* 确定性错误(revert、余额不足等)直接抛出,不拿去别的节点重试
|
|
78
|
+
*/
|
|
79
|
+
export class WriteRpc {
|
|
80
|
+
rpc;
|
|
81
|
+
chainId;
|
|
82
|
+
constructor(rpc, chainId) {
|
|
83
|
+
this.rpc = rpc;
|
|
84
|
+
this.chainId = chainId;
|
|
85
|
+
}
|
|
86
|
+
static async from(provider) {
|
|
87
|
+
const chainId = await provider.getChainId();
|
|
88
|
+
if (isTronChain(chainId)) {
|
|
89
|
+
throw new Error('This operation is not supported on Tron');
|
|
90
|
+
}
|
|
91
|
+
return new WriteRpc(provider.rpc, chainId);
|
|
92
|
+
}
|
|
93
|
+
#run(method, fn, isFinal) {
|
|
94
|
+
return runOnNodes(this.rpc, method, (node) => {
|
|
95
|
+
if (node instanceof TronProvider) {
|
|
96
|
+
return Promise.reject(new Error('This operation is not supported on Tron'));
|
|
97
|
+
}
|
|
98
|
+
return fn(asWriteNode(node, method));
|
|
99
|
+
}, isFinal);
|
|
100
|
+
}
|
|
101
|
+
/** 本次批量操作里各钱包已用到的 nonce + 1(同一个 WriteRpc 分几轮发送时接上) */
|
|
102
|
+
#nextNonce = new Map();
|
|
103
|
+
/**
|
|
104
|
+
* 下一个可用的 nonce:节点的 pending 计数(含交易池里待确认的交易)与本次已用过的取大者。
|
|
105
|
+
* 多节点时先返回的节点可能还没看到刚发出的交易,只信节点会拿到已用过的 nonce
|
|
106
|
+
*/
|
|
107
|
+
async nonce(address) {
|
|
108
|
+
const pending = await this.#run('getTransactionCount', (node) => node.getTransactionCount(address, 'pending'));
|
|
109
|
+
return Math.max(pending, this.#nextNonce.get(address.toLowerCase()) ?? 0);
|
|
110
|
+
}
|
|
111
|
+
/** 已上链的交易数(latest nonce) */
|
|
112
|
+
latestNonce(address) {
|
|
113
|
+
return this.#run('getTransactionCount', (node) => node.getTransactionCount(address, 'latest'));
|
|
114
|
+
}
|
|
115
|
+
/** 记录 nonce 已被占用(交易已广播,或节点说已被用掉) */
|
|
116
|
+
useNonce(address, nonce) {
|
|
117
|
+
const key = address.toLowerCase();
|
|
118
|
+
this.#nextNonce.set(key, Math.max(this.#nextNonce.get(key) ?? 0, nonce + 1));
|
|
119
|
+
}
|
|
120
|
+
code(address) {
|
|
121
|
+
return this.#run('getCode', (node) => node.getCode(address));
|
|
122
|
+
}
|
|
123
|
+
async feeData() {
|
|
124
|
+
const fee = await this.#run('getFeeData', (node) => node.getFeeData());
|
|
125
|
+
return { gasPrice: fee.gasPrice, maxFeePerGas: fee.maxFeePerGas, maxPriorityFeePerGas: fee.maxPriorityFeePerGas };
|
|
126
|
+
}
|
|
127
|
+
/** 预估 gas;revert / 余额不足等直接抛出(error.data 是 revert 数据) */
|
|
128
|
+
estimateGas(tx) {
|
|
129
|
+
return this.#run('estimateGas', (node) => node.estimateGas(tx), isFinalEstimateError);
|
|
130
|
+
}
|
|
131
|
+
/** eth_call;revert 直接抛出 */
|
|
132
|
+
call(tx) {
|
|
133
|
+
return this.#run('call', (node) => node.call(tx), isExecutionError);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 广播已签名的交易。同一笔签名交易重复广播是安全的:节点说已经有了视为成功;
|
|
137
|
+
* nonce 已被用掉时返回 'nonce-used'(调用方查回执确认是不是这笔已上链)。其他交易本身的问题直接抛出
|
|
138
|
+
*/
|
|
139
|
+
async broadcast(signed) {
|
|
140
|
+
// 记录各节点的结果:只有所有尝试都是“明确拒绝”、并且没有还在进行中的尝试时,才能确定交易没发出去
|
|
141
|
+
let attempts = 0;
|
|
142
|
+
let rejections = 0;
|
|
143
|
+
let pending = 0;
|
|
144
|
+
try {
|
|
145
|
+
return await this.#run('broadcastTransaction', async (node) => {
|
|
146
|
+
attempts++;
|
|
147
|
+
pending++;
|
|
148
|
+
try {
|
|
149
|
+
await node.broadcastTransaction(signed);
|
|
150
|
+
return 'accepted';
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
const text = errorText(err);
|
|
154
|
+
if (ALREADY_KNOWN_RE.test(text)) {
|
|
155
|
+
return 'accepted';
|
|
156
|
+
}
|
|
157
|
+
if (isError(err, 'NONCE_EXPIRED') || NONCE_USED_RE.test(text)) {
|
|
158
|
+
return 'nonce-used';
|
|
159
|
+
}
|
|
160
|
+
if (isRejection(err))
|
|
161
|
+
rejections++;
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
pending--;
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
// 明确拒绝、而且之前没有不确定的尝试:不再问别的节点
|
|
169
|
+
(err) => isFinalBroadcastError(err) && rejections === attempts && pending === 0);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
if (attempts === 0 || rejections === attempts) {
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
return { uncertain: `broadcast not acknowledged: ${failureText(err)}` };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
receipt(hash) {
|
|
179
|
+
return this.#run('getTransactionReceipt', (node) => node.getTransactionReceipt(hash));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** 已签名交易的哈希 */
|
|
183
|
+
export function signedHash(signed) {
|
|
184
|
+
return Transaction.from(signed).hash;
|
|
185
|
+
}
|
|
186
|
+
// OP Stack(GasPriceOracle)与 Scroll(L1GasPriceOracle)的 L1 数据费:不包含在 gasLimit × gasPrice 里,单独从余额里扣。
|
|
187
|
+
// 扫空主币余额时要预留,否则交易因余额不足失败
|
|
188
|
+
const L1_ORACLES = ['0x420000000000000000000000000000000000000F', '0x5300000000000000000000000000000000000002'];
|
|
189
|
+
const l1OracleInterface = new Interface(['function getL1Fee(bytes data) view returns (uint256)']);
|
|
190
|
+
/** chainId → 这条链的 L1 费用预言机地址(null 表示不是这类链) */
|
|
191
|
+
const l1OracleByChain = new Map();
|
|
192
|
+
/** 测试用 */
|
|
193
|
+
export function resetL1OracleCache() {
|
|
194
|
+
l1OracleByChain.clear();
|
|
195
|
+
}
|
|
196
|
+
async function l1Oracle(rpc) {
|
|
197
|
+
const cached = l1OracleByChain.get(rpc.chainId);
|
|
198
|
+
if (cached !== undefined) {
|
|
199
|
+
return cached;
|
|
200
|
+
}
|
|
201
|
+
let found = null;
|
|
202
|
+
for (const address of L1_ORACLES) {
|
|
203
|
+
try {
|
|
204
|
+
const code = await rpc.code(address);
|
|
205
|
+
if (code && code !== '0x') {
|
|
206
|
+
found = address;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return null; // 节点出错:这次按没有处理,下次再查
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
l1OracleByChain.set(rpc.chainId, found);
|
|
215
|
+
return found;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* 交易的 L1 数据费(OP Stack / Scroll),其他链为 0。结果加 25% 余量(L1 gas 价格在交易上链前可能上涨)。
|
|
219
|
+
* 查询失败时返回 0(不阻塞发送,只影响扫空主币时的预留)
|
|
220
|
+
*/
|
|
221
|
+
export async function l1Fee(rpc, tx) {
|
|
222
|
+
const oracle = await l1Oracle(rpc);
|
|
223
|
+
if (!oracle) {
|
|
224
|
+
return 0n;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const unsigned = Transaction.from({ ...tx, from: undefined, chainId: rpc.chainId }).unsignedSerialized;
|
|
228
|
+
const data = await rpc.call({ to: oracle, data: l1OracleInterface.encodeFunctionData('getL1Fee', [unsigned]) });
|
|
229
|
+
const [fee] = l1OracleInterface.decodeFunctionResult('getL1Fee', data);
|
|
230
|
+
return (fee * 125n) / 100n;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return 0n;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=rpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/write/rpc.ts"],"names":[],"mappings":"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"}
|