dequanto 0.2.8 → 0.2.13
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/lib/cjs/clients/debug/ClientDebugMethods.js +3 -13
- package/lib/cjs/clients/debug/ClientDebugMethods.js.map +1 -1
- package/lib/cjs/contracts/ContractReader.js +16 -2
- package/lib/cjs/contracts/ContractReader.js.map +1 -1
- package/lib/cjs/hardhat/HardhatProvider.js +7 -2
- package/lib/cjs/hardhat/HardhatProvider.js.map +1 -1
- package/lib/cjs/hardhat/HardhatWeb3Client.js +4 -0
- package/lib/cjs/hardhat/HardhatWeb3Client.js.map +1 -1
- package/lib/cjs/txs/TxDataBuilder.js +20 -0
- package/lib/cjs/txs/TxDataBuilder.js.map +1 -1
- package/lib/cjs/utils/$color.js +2 -2
- package/lib/cjs/utils/$color.js.map +1 -1
- package/lib/cjs/utils/$contract.js +10 -0
- package/lib/cjs/utils/$contract.js.map +1 -1
- package/lib/cjs/utils/$require.js +7 -0
- package/lib/cjs/utils/$require.js.map +1 -1
- package/lib/cjs/utils/$traces.js +492 -0
- package/lib/cjs/utils/$traces.js.map +1 -0
- package/lib/esm/clients/debug/ClientDebugMethods.js.map +1 -1
- package/lib/esm/clients/debug/ClientDebugMethods.mjs +3 -13
- package/lib/esm/contracts/ContractReader.js.map +1 -1
- package/lib/esm/contracts/ContractReader.mjs +16 -2
- package/lib/esm/hardhat/HardhatProvider.js.map +1 -1
- package/lib/esm/hardhat/HardhatProvider.mjs +7 -2
- package/lib/esm/hardhat/HardhatWeb3Client.js.map +1 -1
- package/lib/esm/hardhat/HardhatWeb3Client.mjs +4 -0
- package/lib/esm/txs/TxDataBuilder.js.map +1 -1
- package/lib/esm/txs/TxDataBuilder.mjs +20 -0
- package/lib/esm/utils/$color.js.map +1 -1
- package/lib/esm/utils/$color.mjs +1 -1
- package/lib/esm/utils/$contract.js.map +1 -1
- package/lib/esm/utils/$contract.mjs +10 -0
- package/lib/esm/utils/$require.js.map +1 -1
- package/lib/esm/utils/$require.mjs +7 -0
- package/lib/esm/utils/$traces.js.map +1 -0
- package/lib/esm/utils/$traces.mjs +486 -0
- package/lib/types/clients/debug/ClientDebugMethods.d.ts +18 -0
- package/lib/types/clients/interfaces/IWeb3Client.d.ts +4 -0
- package/lib/types/contracts/ContractReader.d.ts +1 -1
- package/lib/types/models/TEth.d.ts +2 -2
- package/lib/types/utils/$color.d.ts +62 -0
- package/lib/types/utils/$contract.d.ts +8 -0
- package/lib/types/utils/$require.d.ts +2 -0
- package/lib/types/utils/$traces.d.ts +18 -0
- package/package.json +1 -1
- package/src/clients/debug/ClientDebugMethods.ts +23 -14
- package/src/clients/interfaces/IWeb3Client.ts +4 -0
- package/src/contracts/ContractReader.ts +18 -3
- package/src/hardhat/HardhatProvider.ts +8 -3
- package/src/hardhat/HardhatWeb3Client.ts +4 -0
- package/src/models/TEth.ts +2 -2
- package/src/txs/TxDataBuilder.ts +20 -0
- package/src/types/TAbi.ts +1 -1
- package/src/utils/$color.ts +1 -1
- package/src/utils/$contract.ts +17 -1
- package/src/utils/$require.ts +9 -0
- package/src/utils/$traces.ts +600 -0
- package/lib/cjs/utils/$sign.js +0 -118
- package/lib/cjs/utils/$sign.js.map +0 -1
- package/lib/esm/utils/$sign.js.map +0 -1
- package/lib/esm/utils/$sign.mjs +0 -117
- package/lib/types/utils/$sign.d.ts +0 -1
- package/src/utils/$sign.ts +0 -136
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { $abiCoder } from '../abi/$abiCoder.mjs';
|
|
2
|
+
import { $abiUtils } from './$abiUtils.mjs';
|
|
3
|
+
import { $bigint } from './$bigint.mjs';
|
|
4
|
+
import { $hex } from './$hex.mjs';
|
|
5
|
+
import { $color } from './$color.mjs';
|
|
6
|
+
import alot from 'alot';
|
|
7
|
+
export var $traces;
|
|
8
|
+
(function ($traces) {
|
|
9
|
+
const CALL_OPS = new Set(['CALL', 'STATICCALL', 'DELEGATECALL', 'CALLCODE']);
|
|
10
|
+
const FAILURE_OPS = new Set(['REVERT', 'INVALID']);
|
|
11
|
+
async function format(params) {
|
|
12
|
+
const logs = params.traces.structLogs ?? [];
|
|
13
|
+
const frames = logs.length > 0
|
|
14
|
+
? buildFrames(logs)
|
|
15
|
+
: [];
|
|
16
|
+
const abiCache = new Map();
|
|
17
|
+
const entryAbiMeta = params.tx.to != null
|
|
18
|
+
? await getAbiMeta(params.tx.to)
|
|
19
|
+
: null;
|
|
20
|
+
const entryAbiItem = getFunctionAbiItem(entryAbiMeta, getSelector(params.tx));
|
|
21
|
+
if (frames[0] != null) {
|
|
22
|
+
frames[0].to = params.tx.to ?? null;
|
|
23
|
+
frames[0].value = params.tx.value ?? null;
|
|
24
|
+
frames[0].input = getInput(params.tx);
|
|
25
|
+
frames[0].selector = getSelector(params.tx);
|
|
26
|
+
frames[0].output = params.traces.returnValue ?? frames[0].output;
|
|
27
|
+
}
|
|
28
|
+
await Promise.all(frames.map(async (frame) => {
|
|
29
|
+
let abiMeta = frame.to != null
|
|
30
|
+
? await getAbiMeta(frame.to)
|
|
31
|
+
: null;
|
|
32
|
+
let abiItem = getFunctionAbiItem(abiMeta, frame.selector);
|
|
33
|
+
if (frame.id !== 0) {
|
|
34
|
+
frame.label = formatFrameLabel(frame, abiMeta?.contractName ?? abiMeta?.name, abiItem, params);
|
|
35
|
+
}
|
|
36
|
+
for (let event of frame.events) {
|
|
37
|
+
event.label = formatEventLabel(event, abiMeta, params);
|
|
38
|
+
}
|
|
39
|
+
}));
|
|
40
|
+
for (let frame of frames) {
|
|
41
|
+
if (frame.id !== 0) {
|
|
42
|
+
frame.label ??= formatFrameLabel(frame, null, null, params);
|
|
43
|
+
}
|
|
44
|
+
for (let event of frame.events) {
|
|
45
|
+
event.label ??= formatEventLabel(event, null, params);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
let lines = [];
|
|
49
|
+
let entryLine = formatEntrypointLabel(params.tx, params.traces, entryAbiMeta?.contractName ?? entryAbiMeta?.name, entryAbiItem, params);
|
|
50
|
+
lines.push(`${entryLine}${params.traces.failed ? ' [FAILED]' : ''}`);
|
|
51
|
+
let root = frames[0];
|
|
52
|
+
if (root != null) {
|
|
53
|
+
appendEntries(root, 1, lines);
|
|
54
|
+
}
|
|
55
|
+
let addresses = alot.fromObject(params.addresses ?? {}).map(x => {
|
|
56
|
+
return `${x.key} <=> ${x.value}`;
|
|
57
|
+
}).toArray();
|
|
58
|
+
lines.push('\n', ...addresses);
|
|
59
|
+
return lines.join('\n');
|
|
60
|
+
async function getAbiMeta(contract) {
|
|
61
|
+
let key = contract.toLowerCase();
|
|
62
|
+
if (abiCache.has(key) === false) {
|
|
63
|
+
abiCache.set(key, params.getABI(contract).catch(() => null));
|
|
64
|
+
}
|
|
65
|
+
return await abiCache.get(key);
|
|
66
|
+
}
|
|
67
|
+
function appendEntries(frame, level, out) {
|
|
68
|
+
let indent = ' '.repeat(level);
|
|
69
|
+
let entries = [
|
|
70
|
+
...frame.children.map(child => ({ kind: 'frame', index: child.start, frame: child })),
|
|
71
|
+
...frame.events.map(event => ({ kind: 'event', index: event.index, event })),
|
|
72
|
+
].sort((a, b) => a.index - b.index);
|
|
73
|
+
for (let entry of entries) {
|
|
74
|
+
if (entry.kind === 'frame') {
|
|
75
|
+
out.push(`${indent}${entry.frame.label}${entry.frame.failed ? ' [FAILED]' : ''}`);
|
|
76
|
+
appendEntries(entry.frame, level + 1, out);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
out.push(`${indent}${entry.event.label}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
$traces.format = format;
|
|
84
|
+
function buildFrames(logs) {
|
|
85
|
+
let root = {
|
|
86
|
+
id: 0,
|
|
87
|
+
parentId: null,
|
|
88
|
+
depth: logs[0].depth,
|
|
89
|
+
start: 0,
|
|
90
|
+
end: logs.length - 1,
|
|
91
|
+
callSite: null,
|
|
92
|
+
callOp: 'ROOT',
|
|
93
|
+
to: null,
|
|
94
|
+
value: null,
|
|
95
|
+
input: null,
|
|
96
|
+
selector: null,
|
|
97
|
+
output: null,
|
|
98
|
+
children: [],
|
|
99
|
+
events: []
|
|
100
|
+
};
|
|
101
|
+
let frames = [root];
|
|
102
|
+
let open = [root];
|
|
103
|
+
for (let i = 1; i < logs.length; i++) {
|
|
104
|
+
let prev = logs[i - 1];
|
|
105
|
+
let current = logs[i];
|
|
106
|
+
while (open.length > 0 && open[open.length - 1].depth > current.depth) {
|
|
107
|
+
let closing = open.pop();
|
|
108
|
+
closing.end = i - 1;
|
|
109
|
+
}
|
|
110
|
+
let active = open[open.length - 1];
|
|
111
|
+
if (current.depth > active.depth) {
|
|
112
|
+
let meta = CALL_OPS.has(prev.op)
|
|
113
|
+
? getCallMeta(prev)
|
|
114
|
+
: { op: prev.op, to: null, value: null, input: null, selector: null };
|
|
115
|
+
let frame = {
|
|
116
|
+
id: frames.length,
|
|
117
|
+
parentId: active.id,
|
|
118
|
+
depth: current.depth,
|
|
119
|
+
start: i,
|
|
120
|
+
end: i,
|
|
121
|
+
callSite: i - 1,
|
|
122
|
+
callOp: meta.op,
|
|
123
|
+
to: meta.to,
|
|
124
|
+
value: meta.value,
|
|
125
|
+
input: meta.input,
|
|
126
|
+
selector: meta.selector,
|
|
127
|
+
output: null,
|
|
128
|
+
children: [],
|
|
129
|
+
events: []
|
|
130
|
+
};
|
|
131
|
+
active.children.push(frame);
|
|
132
|
+
frames.push(frame);
|
|
133
|
+
open.push(frame);
|
|
134
|
+
active = frame;
|
|
135
|
+
}
|
|
136
|
+
let event = getEventMeta(current, i);
|
|
137
|
+
if (event != null) {
|
|
138
|
+
active.events.push(event);
|
|
139
|
+
}
|
|
140
|
+
active.end = i;
|
|
141
|
+
}
|
|
142
|
+
while (open.length > 0) {
|
|
143
|
+
let frame = open.pop();
|
|
144
|
+
frame.end = logs.length - 1;
|
|
145
|
+
}
|
|
146
|
+
for (let frame of frames) {
|
|
147
|
+
let endLog = logs[frame.end];
|
|
148
|
+
frame.exitOp = endLog?.op;
|
|
149
|
+
frame.failed = FAILURE_OPS.has(frame.exitOp);
|
|
150
|
+
frame.output = getOutputMeta(endLog);
|
|
151
|
+
}
|
|
152
|
+
return frames;
|
|
153
|
+
}
|
|
154
|
+
function getCallMeta(log) {
|
|
155
|
+
let stack = log.stack ?? [];
|
|
156
|
+
let to = null;
|
|
157
|
+
let value = null;
|
|
158
|
+
let inputOffset = 0;
|
|
159
|
+
let inputSize = 0;
|
|
160
|
+
if (log.op === 'CALL' || log.op === 'CALLCODE') {
|
|
161
|
+
if (stack.length < 7) {
|
|
162
|
+
return { op: log.op, to: null, value: null, input: null, selector: null };
|
|
163
|
+
}
|
|
164
|
+
to = toAddress(stack[stack.length - 2]);
|
|
165
|
+
value = toBigInt(stack[stack.length - 3]);
|
|
166
|
+
inputOffset = toNumber(stack[stack.length - 4]);
|
|
167
|
+
inputSize = toNumber(stack[stack.length - 5]);
|
|
168
|
+
}
|
|
169
|
+
else if (log.op === 'STATICCALL' || log.op === 'DELEGATECALL') {
|
|
170
|
+
if (stack.length < 6) {
|
|
171
|
+
return { op: log.op, to: null, value: null, input: null, selector: null };
|
|
172
|
+
}
|
|
173
|
+
to = toAddress(stack[stack.length - 2]);
|
|
174
|
+
inputOffset = toNumber(stack[stack.length - 3]);
|
|
175
|
+
inputSize = toNumber(stack[stack.length - 4]);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
return { op: log.op, to: null, value: null, input: null, selector: null };
|
|
179
|
+
}
|
|
180
|
+
let input = readMemory(log.memory ?? [], inputOffset, inputSize);
|
|
181
|
+
let selector = input != null && input.length >= 10
|
|
182
|
+
? input.slice(0, 10)
|
|
183
|
+
: null;
|
|
184
|
+
return {
|
|
185
|
+
op: log.op,
|
|
186
|
+
to,
|
|
187
|
+
value,
|
|
188
|
+
input,
|
|
189
|
+
selector,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function getEventMeta(log, index) {
|
|
193
|
+
let match = /^LOG([0-4])$/.exec(log.op);
|
|
194
|
+
if (match == null) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
let topicCount = Number(match[1]);
|
|
198
|
+
let stack = log.stack ?? [];
|
|
199
|
+
if (stack.length < topicCount + 2) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
let offset = toNumber(stack[stack.length - 1]);
|
|
203
|
+
let size = toNumber(stack[stack.length - 2]);
|
|
204
|
+
let topics = Array.from({ length: topicCount }, (_, i) => {
|
|
205
|
+
return $hex.ensure(stack[stack.length - 3 - i]);
|
|
206
|
+
});
|
|
207
|
+
let data = readMemory(log.memory ?? [], offset, size) ?? '0x';
|
|
208
|
+
return {
|
|
209
|
+
index,
|
|
210
|
+
op: log.op,
|
|
211
|
+
topics,
|
|
212
|
+
data,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function readMemory(memory, offset, size) {
|
|
216
|
+
if (size <= 0 || memory.length === 0) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
let hex = memory.join('');
|
|
220
|
+
let start = offset * 2;
|
|
221
|
+
let end = start + size * 2;
|
|
222
|
+
return `0x${hex.slice(start, end)}`;
|
|
223
|
+
}
|
|
224
|
+
function formatEntrypointLabel(tx, traces, contractName, abi, params) {
|
|
225
|
+
let frame = {
|
|
226
|
+
id: -1,
|
|
227
|
+
parentId: null,
|
|
228
|
+
depth: 0,
|
|
229
|
+
start: 0,
|
|
230
|
+
end: 0,
|
|
231
|
+
callSite: null,
|
|
232
|
+
callOp: '',
|
|
233
|
+
to: tx.to ?? null,
|
|
234
|
+
value: tx.value ?? null,
|
|
235
|
+
input: getInput(tx),
|
|
236
|
+
selector: getSelector(tx),
|
|
237
|
+
output: traces.returnValue ?? null,
|
|
238
|
+
children: [],
|
|
239
|
+
events: [],
|
|
240
|
+
failed: traces.failed,
|
|
241
|
+
exitOp: null,
|
|
242
|
+
};
|
|
243
|
+
return formatFrameLabel(frame, contractName, abi, params);
|
|
244
|
+
}
|
|
245
|
+
function formatFrameLabel(frame, contractName, abi, params) {
|
|
246
|
+
let head = color('gray', frame.callOp.toLowerCase(), params);
|
|
247
|
+
let suffix = '';
|
|
248
|
+
if (frame.to != null) {
|
|
249
|
+
let address = shortAddress(frame.to, params);
|
|
250
|
+
if (contractName != null && abi != null && 'name' in abi && abi.name != null) {
|
|
251
|
+
let args = frame.input != null
|
|
252
|
+
? decodeArgs(abi, frame.input, params)
|
|
253
|
+
: '';
|
|
254
|
+
if (params != null) {
|
|
255
|
+
params.addresses ??= {};
|
|
256
|
+
params.addresses[address] = contractName;
|
|
257
|
+
}
|
|
258
|
+
suffix = `${color('bold', contractName, params)}.${color('magenta', abi.name, params)}(${args})`;
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
suffix = `${address}${frame.selector ? ` ${frame.selector}` : ''}`;
|
|
262
|
+
if (frame.input != null) {
|
|
263
|
+
suffix += ` calldata=${shortHex(frame.input, 18, 10)}`;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (frame.value != null && frame.value !== 0n) {
|
|
268
|
+
suffix += `${suffix ? ' ' : ''}`;
|
|
269
|
+
if (frame.value && BigInt(frame.value) > 0n) {
|
|
270
|
+
suffix += `value=${frame.value.toString()}`;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (frame.exitOp != null && frame.exitOp !== 'STOP' && frame.exitOp !== 'RETURN') {
|
|
274
|
+
suffix += `${suffix ? ' ' : ''}exit=${frame.exitOp}`;
|
|
275
|
+
}
|
|
276
|
+
if (frame.output != null) {
|
|
277
|
+
let returnValue = formatReturnValue(frame, abi, params);
|
|
278
|
+
suffix += `: ${returnValue}`;
|
|
279
|
+
}
|
|
280
|
+
return suffix ? `${head} ${suffix}` : head;
|
|
281
|
+
}
|
|
282
|
+
function formatEventLabel(event, abiMeta, params) {
|
|
283
|
+
let abi = getEventAbiItem(abiMeta, event.topics);
|
|
284
|
+
if (abi == null) {
|
|
285
|
+
let head = color('cyan', 'event', params);
|
|
286
|
+
let name = event.topics[0] != null
|
|
287
|
+
? shortHex(event.topics[0], 18, 10)
|
|
288
|
+
: event.op;
|
|
289
|
+
return `${head} ${name}`;
|
|
290
|
+
}
|
|
291
|
+
let args = decodeEventArgs(abi, event, params);
|
|
292
|
+
return `${color('cyan', 'event', params)} ${color('magenta', abi.name, params)}(${args})`;
|
|
293
|
+
}
|
|
294
|
+
function getFunctionAbiItem(abiMeta, selector) {
|
|
295
|
+
if (abiMeta == null || selector == null) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
return abiMeta.abi.find(item => {
|
|
299
|
+
if (item.type !== 'function' || !('name' in item)) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
return $abiUtils.getMethodSignature(item) === selector;
|
|
303
|
+
}) ?? null;
|
|
304
|
+
}
|
|
305
|
+
function getEventAbiItem(abiMeta, topics) {
|
|
306
|
+
if (abiMeta == null) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
return abiMeta.abi.find(item => {
|
|
310
|
+
if (item.type !== 'event' || !('name' in item) || item.name == null) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
if ('anonymous' in item && item.anonymous === true) {
|
|
314
|
+
return topics.length === (item.inputs?.filter(x => x.indexed).length ?? 0);
|
|
315
|
+
}
|
|
316
|
+
return topics[0] === $abiUtils.getTopicSignature(item);
|
|
317
|
+
}) ?? null;
|
|
318
|
+
}
|
|
319
|
+
function decodeArgs(abi, input, params) {
|
|
320
|
+
try {
|
|
321
|
+
let inputs = 'inputs' in abi && Array.isArray(abi.inputs)
|
|
322
|
+
? abi.inputs
|
|
323
|
+
: [];
|
|
324
|
+
if (inputs.length === 0) {
|
|
325
|
+
return '';
|
|
326
|
+
}
|
|
327
|
+
let data = `0x${input.slice(10)}`;
|
|
328
|
+
let values = $abiCoder.decode(inputs, data);
|
|
329
|
+
return inputs.map((param, index) => {
|
|
330
|
+
let name = param.name?.trim() || `arg${index}`;
|
|
331
|
+
return `${name}: ${formatValue(values[index], params)}`;
|
|
332
|
+
}).join(', ');
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
return shortHex(input, 18, 10);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function decodeEventArgs(abi, event, params) {
|
|
339
|
+
try {
|
|
340
|
+
let inputs = 'inputs' in abi && Array.isArray(abi.inputs)
|
|
341
|
+
? abi.inputs
|
|
342
|
+
: [];
|
|
343
|
+
if (inputs.length === 0) {
|
|
344
|
+
return '';
|
|
345
|
+
}
|
|
346
|
+
let dataInputs = inputs.filter(x => x.indexed !== true);
|
|
347
|
+
let dataValues = dataInputs.length > 0
|
|
348
|
+
? $abiCoder.decode(dataInputs, event.data)
|
|
349
|
+
: [];
|
|
350
|
+
let topicIndex = 'anonymous' in abi && abi.anonymous === true ? 0 : 1;
|
|
351
|
+
let dataIndex = 0;
|
|
352
|
+
return inputs.map((param, index) => {
|
|
353
|
+
let name = param.name?.trim() || `arg${index}`;
|
|
354
|
+
let value;
|
|
355
|
+
if (param.indexed === true) {
|
|
356
|
+
let topic = event.topics[topicIndex++];
|
|
357
|
+
if (topic == null) {
|
|
358
|
+
value = 'undefined';
|
|
359
|
+
}
|
|
360
|
+
else if ($abiUtils.isDynamicType(param.type)) {
|
|
361
|
+
value = topic;
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
value = $abiCoder.decode([param], topic)[0];
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
value = dataValues[dataIndex++];
|
|
369
|
+
}
|
|
370
|
+
return `${name}: ${formatValue(value, params)}`;
|
|
371
|
+
}).join(', ');
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
let rendered = [
|
|
375
|
+
...event.topics.map(topic => shortHex(topic, 18, 10)),
|
|
376
|
+
event.data !== '0x' ? shortHex(event.data, 18, 10) : null,
|
|
377
|
+
].filter(Boolean);
|
|
378
|
+
return rendered.join(', ');
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
function formatReturnValue(frame, abi, params) {
|
|
382
|
+
if (frame.output == null) {
|
|
383
|
+
return '0x';
|
|
384
|
+
}
|
|
385
|
+
if (frame.failed !== true && abi != null) {
|
|
386
|
+
try {
|
|
387
|
+
let outputs = 'outputs' in abi && Array.isArray(abi.outputs)
|
|
388
|
+
? abi.outputs
|
|
389
|
+
: [];
|
|
390
|
+
if (outputs.length > 0) {
|
|
391
|
+
let values = $abiCoder.decode(outputs, frame.output);
|
|
392
|
+
return outputs.map((param, index) => {
|
|
393
|
+
let name = param.name?.trim();
|
|
394
|
+
if (!name && outputs.length > 1) {
|
|
395
|
+
name = `out${index}`;
|
|
396
|
+
}
|
|
397
|
+
if (name) {
|
|
398
|
+
name += ': ';
|
|
399
|
+
}
|
|
400
|
+
return `${name ?? ''}${formatValue(values[index], params)}`;
|
|
401
|
+
}).join(', ');
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
// Fall back to raw bytes if decoding fails.
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return shortHex(frame.output, 18, 10);
|
|
409
|
+
}
|
|
410
|
+
function getOutputMeta(log) {
|
|
411
|
+
if (log == null || (log.op !== 'RETURN' && log.op !== 'REVERT')) {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
let stack = log.stack ?? [];
|
|
415
|
+
if (stack.length < 2) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
let offset = toNumber(stack[stack.length - 1]);
|
|
419
|
+
let size = toNumber(stack[stack.length - 2]);
|
|
420
|
+
return readMemory(log.memory ?? [], offset, size);
|
|
421
|
+
}
|
|
422
|
+
function getInput(tx) {
|
|
423
|
+
return tx.data ?? tx.input ?? null;
|
|
424
|
+
}
|
|
425
|
+
function getSelector(tx) {
|
|
426
|
+
let input = getInput(tx);
|
|
427
|
+
return input != null && input.length >= 10
|
|
428
|
+
? input.slice(0, 10)
|
|
429
|
+
: null;
|
|
430
|
+
}
|
|
431
|
+
function formatValue(value, params) {
|
|
432
|
+
if (typeof value === 'bigint') {
|
|
433
|
+
return color('cyan', value.toString(), params);
|
|
434
|
+
}
|
|
435
|
+
if (Array.isArray(value)) {
|
|
436
|
+
return `[${value.map(x => formatValue(x, params)).join(', ')}]`;
|
|
437
|
+
}
|
|
438
|
+
if (value != null && typeof value === 'object') {
|
|
439
|
+
let entries = Object.entries(value);
|
|
440
|
+
return `{ ${entries.map(([key, val]) => `${key}: ${formatValue(val, params)}`).join(', ')} }`;
|
|
441
|
+
}
|
|
442
|
+
if (typeof value === 'string') {
|
|
443
|
+
if (/^0x[a-fA-F0-9]{40}$/.test(value)) {
|
|
444
|
+
return value;
|
|
445
|
+
}
|
|
446
|
+
if (/^0x[a-fA-F0-9]{18,}$/.test(value)) {
|
|
447
|
+
return shortHex(value, 18, 10);
|
|
448
|
+
}
|
|
449
|
+
return color('yellow', value, params);
|
|
450
|
+
}
|
|
451
|
+
return String(value);
|
|
452
|
+
}
|
|
453
|
+
function shortAddress(address, params) {
|
|
454
|
+
if (params.shortAddress === false) {
|
|
455
|
+
return address;
|
|
456
|
+
}
|
|
457
|
+
return `${address.slice(0, 8)}...${address.slice(-4)}`;
|
|
458
|
+
}
|
|
459
|
+
function shortHex(hex, start, end) {
|
|
460
|
+
if (hex.length <= start + end) {
|
|
461
|
+
return hex;
|
|
462
|
+
}
|
|
463
|
+
return `${hex.slice(0, start)}...${hex.slice(-end)}`;
|
|
464
|
+
}
|
|
465
|
+
function toAddress(word) {
|
|
466
|
+
let hex = word.replace(/^0x/, '').slice(-40).toLowerCase();
|
|
467
|
+
return `0x${hex}`;
|
|
468
|
+
}
|
|
469
|
+
function toBigInt(word) {
|
|
470
|
+
return $bigint.from($hex.ensure(word));
|
|
471
|
+
}
|
|
472
|
+
function toNumber(word) {
|
|
473
|
+
let value = toBigInt(word);
|
|
474
|
+
return value > BigInt(Number.MAX_SAFE_INTEGER)
|
|
475
|
+
? Number.MAX_SAFE_INTEGER
|
|
476
|
+
: Number(value);
|
|
477
|
+
}
|
|
478
|
+
function color(name, str, params) {
|
|
479
|
+
if (!params.color) {
|
|
480
|
+
return str;
|
|
481
|
+
}
|
|
482
|
+
return $color(`${name}<${str}>`);
|
|
483
|
+
}
|
|
484
|
+
})($traces || ($traces = {}));
|
|
485
|
+
//# sourceMappingURL=$traces.js.map
|
|
486
|
+
//# sourceMappingURL=$traces.ts.map
|
|
@@ -27,5 +27,23 @@ export declare class ClientDebugMethods {
|
|
|
27
27
|
snapshot(): Promise<number>;
|
|
28
28
|
revert(snapId: number): Promise<any>;
|
|
29
29
|
setAutomine(enabled: boolean): Promise<any>;
|
|
30
|
+
traceCall(data: TEth.TxLike, block?: number | string | 'latest', params?: {
|
|
31
|
+
disableMemory?: boolean;
|
|
32
|
+
disableStack?: boolean;
|
|
33
|
+
disableStorage?: boolean;
|
|
34
|
+
}): Promise<TClientDebugTraces>;
|
|
30
35
|
private call;
|
|
31
36
|
}
|
|
37
|
+
export type TClientDebugTraces = {
|
|
38
|
+
failed?: boolean;
|
|
39
|
+
returnValue?: TEth.Hex;
|
|
40
|
+
structLogs?: {
|
|
41
|
+
depth: number;
|
|
42
|
+
gas: number;
|
|
43
|
+
gasCost: number;
|
|
44
|
+
op: string;
|
|
45
|
+
pc: number;
|
|
46
|
+
memory?: string[];
|
|
47
|
+
stack?: string[];
|
|
48
|
+
}[];
|
|
49
|
+
};
|
|
@@ -86,5 +86,5 @@ export declare namespace ContractReaderUtils {
|
|
|
86
86
|
type TIContractReadParamsInferredMany<T extends IContractReadParams[]> = {
|
|
87
87
|
[P in keyof T]: T[P] extends IContractReadParams<infer P> ? P : never;
|
|
88
88
|
};
|
|
89
|
-
function readAsyncBatch(client: Web3Client, requests: IContractReadParams[]): Promise<any[]>;
|
|
89
|
+
function readAsyncBatch(client: Web3Client, requests: (IContractReadParams | null)[]): Promise<any[]>;
|
|
90
90
|
}
|
|
@@ -143,8 +143,8 @@ export declare namespace TEth {
|
|
|
143
143
|
[P in keyof T]?: T[P] extends bigint ? bigint | number | string | TEth.Hex : (T[P] extends number ? number | TEth.Hex | bigint : (T[P] extends [] ? DataLike<T[P][0]>[] : DataLike<T[P]>));
|
|
144
144
|
};
|
|
145
145
|
namespace Abi {
|
|
146
|
-
type Type = 'function' | 'constructor' | 'event' | 'fallback';
|
|
147
|
-
type StateMutabilityType = 'pure' | 'view' | 'nonpayable' | 'payable';
|
|
146
|
+
type Type = 'function' | 'constructor' | 'event' | 'error' | 'fallback' | 'receive';
|
|
147
|
+
type StateMutabilityType = 'constant' | 'pure' | 'view' | 'nonpayable' | 'payable';
|
|
148
148
|
interface Item {
|
|
149
149
|
anonymous?: boolean;
|
|
150
150
|
constant?: boolean;
|
|
@@ -2,3 +2,65 @@ export declare function $color(str: string): string;
|
|
|
2
2
|
export declare function $color_options(opts: {
|
|
3
3
|
type: 'none' | 'ascii';
|
|
4
4
|
}): void;
|
|
5
|
+
export declare namespace ColorData {
|
|
6
|
+
const ColorAscii: {
|
|
7
|
+
type: string;
|
|
8
|
+
START: string;
|
|
9
|
+
END: string;
|
|
10
|
+
value: {
|
|
11
|
+
red: string;
|
|
12
|
+
green: string;
|
|
13
|
+
yellow: string;
|
|
14
|
+
blue: string;
|
|
15
|
+
magenta: string;
|
|
16
|
+
cyan: string;
|
|
17
|
+
white: string;
|
|
18
|
+
black: string;
|
|
19
|
+
gray: string;
|
|
20
|
+
bg_black: string;
|
|
21
|
+
bg_red: string;
|
|
22
|
+
bg_green: string;
|
|
23
|
+
bg_yellow: string;
|
|
24
|
+
bg_blue: string;
|
|
25
|
+
bg_magenta: string;
|
|
26
|
+
bg_cyan: string;
|
|
27
|
+
bg_white: string;
|
|
28
|
+
bold: string;
|
|
29
|
+
italic: string;
|
|
30
|
+
underline: string;
|
|
31
|
+
inverse: string;
|
|
32
|
+
};
|
|
33
|
+
start(key: any): any;
|
|
34
|
+
rgx_search: RegExp;
|
|
35
|
+
};
|
|
36
|
+
const ColorNone: {
|
|
37
|
+
type: string;
|
|
38
|
+
END: string;
|
|
39
|
+
START: string;
|
|
40
|
+
value: {
|
|
41
|
+
red: string;
|
|
42
|
+
green: string;
|
|
43
|
+
yellow: string;
|
|
44
|
+
blue: string;
|
|
45
|
+
magenta: string;
|
|
46
|
+
cyan: string;
|
|
47
|
+
white: string;
|
|
48
|
+
black: string;
|
|
49
|
+
gray: string;
|
|
50
|
+
bg_black: string;
|
|
51
|
+
bg_red: string;
|
|
52
|
+
bg_green: string;
|
|
53
|
+
bg_yellow: string;
|
|
54
|
+
bg_blue: string;
|
|
55
|
+
bg_magenta: string;
|
|
56
|
+
bg_cyan: string;
|
|
57
|
+
bg_white: string;
|
|
58
|
+
bold: string;
|
|
59
|
+
italic: string;
|
|
60
|
+
underline: string;
|
|
61
|
+
inverse: string;
|
|
62
|
+
};
|
|
63
|
+
start: (key: any) => string;
|
|
64
|
+
rgx_search: RegExp;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -36,7 +36,15 @@ export declare namespace $contract {
|
|
|
36
36
|
namespace store {
|
|
37
37
|
function getFlattened(): TAbiItem[];
|
|
38
38
|
function register(contract: {
|
|
39
|
+
address?: TEth.Address;
|
|
40
|
+
name?: string;
|
|
39
41
|
abi: TAbiItem[];
|
|
40
42
|
}): void;
|
|
43
|
+
function getContract(address: TEth.Address): {
|
|
44
|
+
name?: string;
|
|
45
|
+
address?: TEth.Address;
|
|
46
|
+
abi: TAbiItem[];
|
|
47
|
+
};
|
|
48
|
+
function getAbiItem(selector: TEth.Hex): TAbiItem;
|
|
41
49
|
}
|
|
42
50
|
}
|
|
@@ -25,6 +25,8 @@ export declare namespace $require {
|
|
|
25
25
|
function eq<T = any>(a: T, b: T, message?: string): void;
|
|
26
26
|
function match(rgx: RegExp, str: string, message?: string): void;
|
|
27
27
|
function oneOf<T = any>(a: T, arr: T[], message?: string): void;
|
|
28
|
+
function has<T = any>(a: T, arr: T[], message?: string): any;
|
|
29
|
+
function has<T = any>(a: string, str: string, message?: string): any;
|
|
28
30
|
function Address(val: TAddress | string, message?: string): TAddress;
|
|
29
31
|
function AddressNotEmpty(val: TAddress | string, message?: string): TAddress;
|
|
30
32
|
function AddressChecked(val: TAddress, message?: string): TAddress;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TClientDebugTraces } from '../clients/debug/ClientDebugMethods';
|
|
2
|
+
import { TEth } from '../models/TEth';
|
|
3
|
+
export declare namespace $traces {
|
|
4
|
+
type TAbiMeta = {
|
|
5
|
+
name?: string;
|
|
6
|
+
contractName?: string;
|
|
7
|
+
abi: TEth.Abi.Item[];
|
|
8
|
+
};
|
|
9
|
+
export function format(params: {
|
|
10
|
+
tx: TEth.TxLike;
|
|
11
|
+
traces: TClientDebugTraces;
|
|
12
|
+
getABI(contract: TEth.Address): Promise<TAbiMeta>;
|
|
13
|
+
color?: boolean;
|
|
14
|
+
shortAddress?: boolean;
|
|
15
|
+
addresses?: Record<TEth.Address, string>;
|
|
16
|
+
}): Promise<string>;
|
|
17
|
+
export {};
|
|
18
|
+
}
|