@hashspan/core 0.7.0 → 0.9.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/README.md +44 -18
- package/dist/index.cjs +589 -56
- package/dist/index.d.cts +324 -30
- package/dist/index.d.mts +324 -30
- package/dist/index.mjs +565 -57
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ const ATTR_GEN_AI_AGENT_NAME = "gen_ai.agent.name";
|
|
|
6
6
|
/**
|
|
7
7
|
* Agent identity as GenAI attributes. A field set in the static identity always wins; Baggage, which a remote caller
|
|
8
8
|
* can set, only fills fields it leaves unset, and is not read at all with `fromBaggage` false
|
|
9
|
-
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
9
|
+
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0011-agent-identity-precedence.md).
|
|
10
10
|
*/
|
|
11
11
|
function agentAttributes(ctx, identity, fromBaggage = true) {
|
|
12
12
|
const baggage = fromBaggage ? _opentelemetry_api.propagation.getBaggage(ctx) : void 0;
|
|
@@ -22,7 +22,7 @@ function agentAttributes(ctx, identity, fromBaggage = true) {
|
|
|
22
22
|
/**
|
|
23
23
|
* Attribute keys emitted by hashspan.
|
|
24
24
|
*
|
|
25
|
-
* Stability: development. See https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
25
|
+
* Stability: development. See https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/semconv.md for
|
|
26
26
|
* definitions and value types. These names are a public contract: changes follow the deprecation policy in AGENTS.md.
|
|
27
27
|
*/
|
|
28
28
|
const ATTR_BLOCKCHAIN_SYSTEM = "blockchain.system";
|
|
@@ -33,6 +33,12 @@ const ATTR_BLOCKCHAIN_TX_FROM = "blockchain.tx.from";
|
|
|
33
33
|
const ATTR_BLOCKCHAIN_TX_TO = "blockchain.tx.to";
|
|
34
34
|
const ATTR_BLOCKCHAIN_TX_VALUE = "blockchain.tx.value";
|
|
35
35
|
const ATTR_BLOCKCHAIN_TX_NONCE = "blockchain.tx.nonce";
|
|
36
|
+
/** Number of EIP-7702 authorizations a type 4 transaction carries. */
|
|
37
|
+
const ATTR_BLOCKCHAIN_TX_AUTHORIZATION_COUNT = "blockchain.tx.authorization.count";
|
|
38
|
+
/** Delegated contract address of each well-formed EIP-7702 authorization, per the address mode; at most 64. */
|
|
39
|
+
const ATTR_BLOCKCHAIN_TX_AUTHORIZATION_ADDRESSES = "blockchain.tx.authorization.addresses";
|
|
40
|
+
/** Chain id of each well-formed EIP-7702 authorization, aligned with the addresses; 0 means every chain. */
|
|
41
|
+
const ATTR_BLOCKCHAIN_TX_AUTHORIZATION_CHAIN_IDS = "blockchain.tx.authorization.chain_ids";
|
|
36
42
|
const ATTR_BLOCKCHAIN_TX_STATUS = "blockchain.tx.status";
|
|
37
43
|
const ATTR_BLOCKCHAIN_TX_GAS_USED = "blockchain.tx.gas.used";
|
|
38
44
|
const ATTR_BLOCKCHAIN_TX_EFFECTIVE_GAS_PRICE = "blockchain.tx.effective_gas_price";
|
|
@@ -46,12 +52,12 @@ const ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_NAME = "blockchain.contract.function.nam
|
|
|
46
52
|
const ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_SELECTOR = "blockchain.contract.function.selector";
|
|
47
53
|
/**
|
|
48
54
|
* Opt-in: decoded call arguments as a JSON array. See
|
|
49
|
-
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
55
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0004-privacy-defaults.md.
|
|
50
56
|
*/
|
|
51
57
|
const ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_ARGUMENTS = "blockchain.contract.function.arguments";
|
|
52
58
|
/**
|
|
53
59
|
* Payments settled on chain by a party other than the agent, e.g. an x402 facilitator. See
|
|
54
|
-
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
60
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0013-x402-payments.md.
|
|
55
61
|
*/
|
|
56
62
|
const ATTR_BLOCKCHAIN_PAYMENT_PROTOCOL = "blockchain.payment.protocol";
|
|
57
63
|
const ATTR_BLOCKCHAIN_PAYMENT_PAYER = "blockchain.payment.payer";
|
|
@@ -64,12 +70,52 @@ const ATTR_BLOCKCHAIN_PAYMENT_SETTLED_AMOUNT = "blockchain.payment.settled_amoun
|
|
|
64
70
|
/**
|
|
65
71
|
* Whether the settlement transaction's receipt carries the payment, as checked by the adapter; absent when no check
|
|
66
72
|
* was possible. See
|
|
67
|
-
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
73
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0017-x402-payment-verification.md.
|
|
68
74
|
*/
|
|
69
75
|
const ATTR_BLOCKCHAIN_PAYMENT_VERIFIED = "blockchain.payment.verified";
|
|
70
76
|
/** x402's own payment fields. */
|
|
71
77
|
const ATTR_X402_SCHEME = "x402.scheme";
|
|
72
78
|
const ATTR_X402_RESOURCE = "x402.resource";
|
|
79
|
+
/**
|
|
80
|
+
* User operations of ERC-4337 smart accounts. See
|
|
81
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0021-user-operations.md.
|
|
82
|
+
*/
|
|
83
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_HASH = "blockchain.user_operation.hash";
|
|
84
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_SENDER = "blockchain.user_operation.sender";
|
|
85
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT = "blockchain.user_operation.entry_point";
|
|
86
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT = "blockchain.user_operation.call_count";
|
|
87
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_NONCE = "blockchain.user_operation.nonce";
|
|
88
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS = "blockchain.user_operation.success";
|
|
89
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED = "blockchain.user_operation.gas.used";
|
|
90
|
+
/** What the operation itself paid, in wei; the bundle transaction's fee covers every operation in the bundle. */
|
|
91
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST = "blockchain.user_operation.gas.cost";
|
|
92
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER = "blockchain.user_operation.paymaster";
|
|
93
|
+
/**
|
|
94
|
+
* The batch id the wallet returned, truncated after 256 characters. See
|
|
95
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0022-call-batches.md.
|
|
96
|
+
*/
|
|
97
|
+
const ATTR_BLOCKCHAIN_CALL_BATCH_ID = "blockchain.call_batch.id";
|
|
98
|
+
const ATTR_BLOCKCHAIN_CALL_BATCH_SENDER = "blockchain.call_batch.sender";
|
|
99
|
+
const ATTR_BLOCKCHAIN_CALL_BATCH_CALL_COUNT = "blockchain.call_batch.call_count";
|
|
100
|
+
/** The outcome of a batch from chain data: `success`, `reverted` or `partially_reverted`. */
|
|
101
|
+
const ATTR_BLOCKCHAIN_CALL_BATCH_STATUS = "blockchain.call_batch.status";
|
|
102
|
+
/** The EIP-5792 status code of the batch as the wallet reported it, e.g. 200 confirmed or 500 reverted; spans only. */
|
|
103
|
+
const ATTR_BLOCKCHAIN_CALL_BATCH_STATUS_CODE = "blockchain.call_batch.status_code";
|
|
104
|
+
const ATTR_BLOCKCHAIN_CALL_BATCH_ATOMIC = "blockchain.call_batch.atomic";
|
|
105
|
+
/** Hashes of the transactions whose receipts the wallet reported for the batch. */
|
|
106
|
+
const ATTR_BLOCKCHAIN_CALL_BATCH_TRANSACTION_HASHES = "blockchain.call_batch.transaction_hashes";
|
|
107
|
+
/**
|
|
108
|
+
* Metrics only: what a send, confirmation or fee sample is about. Recorded as `user_operation` on samples of user
|
|
109
|
+
* operations and `call_batch` on those of call batches, and absent on those of transactions.
|
|
110
|
+
*/
|
|
111
|
+
const ATTR_BLOCKCHAIN_OPERATION_SUBJECT = "blockchain.operation.subject";
|
|
112
|
+
/** Values for {@link ATTR_BLOCKCHAIN_OPERATION_SUBJECT}. */
|
|
113
|
+
const BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION = "user_operation";
|
|
114
|
+
const BLOCKCHAIN_OPERATION_SUBJECT_VALUE_CALL_BATCH = "call_batch";
|
|
115
|
+
/** Values for {@link ATTR_BLOCKCHAIN_CALL_BATCH_STATUS}. */
|
|
116
|
+
const BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_SUCCESS = "success";
|
|
117
|
+
const BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_REVERTED = "reverted";
|
|
118
|
+
const BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_PARTIALLY_REVERTED = "partially_reverted";
|
|
73
119
|
/** Values for {@link ATTR_BLOCKCHAIN_SYSTEM}. */
|
|
74
120
|
const BLOCKCHAIN_SYSTEM_VALUE_EVM = "evm";
|
|
75
121
|
/** Values for {@link ATTR_BLOCKCHAIN_OPERATION_NAME}. */
|
|
@@ -88,7 +134,7 @@ const BLOCKCHAIN_TX_STATUS_VALUE_REVERTED = "reverted";
|
|
|
88
134
|
/**
|
|
89
135
|
* @deprecated No longer recorded: a confirm span that gave up waiting records `error.type` `timeout` and no
|
|
90
136
|
* `blockchain.tx.status`. The constant is removed in 1.0. See
|
|
91
|
-
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
137
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0016-timeout-is-an-observer-outcome.md.
|
|
92
138
|
*/
|
|
93
139
|
const BLOCKCHAIN_TX_STATUS_VALUE_TIMEOUT = "timeout";
|
|
94
140
|
const BLOCKCHAIN_TX_STATUS_VALUE_REPLACED = "replaced";
|
|
@@ -102,11 +148,20 @@ const ATTR_ERROR_TYPE = "error.type";
|
|
|
102
148
|
const ERROR_TYPE_VALUE_OTHER = "_OTHER";
|
|
103
149
|
//#endregion
|
|
104
150
|
//#region src/metrics.ts
|
|
105
|
-
/**
|
|
151
|
+
/**
|
|
152
|
+
* Duration of a send of a transaction or user operation: from the start of the sending call until the hash is known or
|
|
153
|
+
* the call failed.
|
|
154
|
+
*/
|
|
106
155
|
const METRIC_BLOCKCHAIN_CLIENT_SEND_DURATION = "blockchain.client.send.duration";
|
|
107
|
-
/**
|
|
156
|
+
/**
|
|
157
|
+
* Duration of a confirmation of a transaction or user operation: from the start of the wait until the receipt, a
|
|
158
|
+
* timeout or a failure.
|
|
159
|
+
*/
|
|
108
160
|
const METRIC_BLOCKCHAIN_CLIENT_CONFIRMATION_DURATION = "blockchain.client.confirmation.duration";
|
|
109
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Total fee of a mined transaction (execution fee plus L1 data fee), or the cost of a user operation, in the chain's
|
|
163
|
+
* smallest unit (wei).
|
|
164
|
+
*/
|
|
110
165
|
const METRIC_BLOCKCHAIN_CLIENT_FEE = "blockchain.client.fee";
|
|
111
166
|
const DURATION_BUCKETS = [
|
|
112
167
|
.05,
|
|
@@ -124,6 +179,21 @@ const DURATION_BUCKETS = [
|
|
|
124
179
|
300
|
|
125
180
|
];
|
|
126
181
|
const FEE_BUCKETS = Array.from({ length: 11 }, (_, i) => 10 ** (i + 8));
|
|
182
|
+
const ERROR_CLASS = /^[A-Z][A-Za-z]{0,62}Error$|^Error$/;
|
|
183
|
+
const ERROR_CODE = /^[a-z]{1,32}(_[a-z]{1,32}){0,7}$/;
|
|
184
|
+
/**
|
|
185
|
+
* `attributes` with `error.type` kept only if it is an error class name or a lower-case code, else `_OTHER`. Error
|
|
186
|
+
* names are free text (any `Error.name`), and metrics do not pass through the `redact` hook; the span keeps its own
|
|
187
|
+
* `error.type`.
|
|
188
|
+
*/
|
|
189
|
+
function withMetricErrorType(attributes) {
|
|
190
|
+
const type = attributes[ATTR_ERROR_TYPE];
|
|
191
|
+
if (type === void 0) return attributes;
|
|
192
|
+
return typeof type === "string" && (type === "_OTHER" || ERROR_CLASS.test(type) || ERROR_CODE.test(type)) ? attributes : {
|
|
193
|
+
...attributes,
|
|
194
|
+
[ATTR_ERROR_TYPE]: ERROR_TYPE_VALUE_OTHER
|
|
195
|
+
};
|
|
196
|
+
}
|
|
127
197
|
/** Milliseconds since the epoch of a span time, as the OpenTelemetry API accepts it. */
|
|
128
198
|
function toEpochMs(time) {
|
|
129
199
|
if (time === void 0) return Date.now();
|
|
@@ -141,17 +211,17 @@ function createTxMetrics(meterProvider, name, version) {
|
|
|
141
211
|
return {
|
|
142
212
|
send: meter.createHistogram(METRIC_BLOCKCHAIN_CLIENT_SEND_DURATION, {
|
|
143
213
|
unit: "s",
|
|
144
|
-
description: "Duration of sending a transaction, until its hash is known",
|
|
214
|
+
description: "Duration of sending a transaction or user operation, until its hash is known",
|
|
145
215
|
advice: { explicitBucketBoundaries: DURATION_BUCKETS }
|
|
146
216
|
}),
|
|
147
217
|
confirmation: meter.createHistogram(METRIC_BLOCKCHAIN_CLIENT_CONFIRMATION_DURATION, {
|
|
148
218
|
unit: "s",
|
|
149
|
-
description: "Duration of waiting for a transaction receipt",
|
|
219
|
+
description: "Duration of waiting for a transaction or user operation receipt",
|
|
150
220
|
advice: { explicitBucketBoundaries: DURATION_BUCKETS }
|
|
151
221
|
}),
|
|
152
222
|
fee: meter.createHistogram(METRIC_BLOCKCHAIN_CLIENT_FEE, {
|
|
153
223
|
unit: "{wei}",
|
|
154
|
-
description: "Total fee of a mined transaction",
|
|
224
|
+
description: "Total fee of a mined transaction, or the cost of a user operation",
|
|
155
225
|
advice: { explicitBucketBoundaries: FEE_BUCKETS }
|
|
156
226
|
})
|
|
157
227
|
};
|
|
@@ -167,10 +237,10 @@ function createTxMetrics(meterProvider, name, version) {
|
|
|
167
237
|
};
|
|
168
238
|
return {
|
|
169
239
|
sendDuration: (seconds, attributes) => record("send duration", () => {
|
|
170
|
-
if (seconds >= 0) get().send.record(seconds, attributes);
|
|
240
|
+
if (seconds >= 0) get().send.record(seconds, withMetricErrorType(attributes));
|
|
171
241
|
}),
|
|
172
242
|
confirmationDuration: (seconds, attributes) => record("confirmation duration", () => {
|
|
173
|
-
if (seconds >= 0) get().confirmation.record(seconds, attributes);
|
|
243
|
+
if (seconds >= 0) get().confirmation.record(seconds, withMetricErrorType(attributes));
|
|
174
244
|
}),
|
|
175
245
|
fee: (wei, attributes) => record("fee", () => {
|
|
176
246
|
if (wei >= 0n) get().fee.record(Number(wei), attributes);
|
|
@@ -287,7 +357,7 @@ function resolveAddressFormatter(option) {
|
|
|
287
357
|
hash: void 0
|
|
288
358
|
};
|
|
289
359
|
switch (mode) {
|
|
290
|
-
case "raw": return formatter((address) => address, false);
|
|
360
|
+
case "raw": return formatter((address) => address.toLowerCase(), false);
|
|
291
361
|
case "off": return OFF_ADDRESS_FORMATTER;
|
|
292
362
|
case "hashed": {
|
|
293
363
|
const hashFn = hash ?? defaultHash();
|
|
@@ -311,6 +381,8 @@ const ADDRESS_LENGTH = 42;
|
|
|
311
381
|
*/
|
|
312
382
|
const MAX_HEX_LENGTH = 66;
|
|
313
383
|
const MAX_MESSAGE_LENGTH = 256;
|
|
384
|
+
/** A URL in free text: `scheme://` up to the next whitespace, quote or bracket; the bounded scheme keeps it linear. */
|
|
385
|
+
const URL_IN_TEXT = /\b[A-Za-z][A-Za-z0-9+.-]{0,31}:\/\/[^\s"'<>()[\]{}]+/g;
|
|
314
386
|
/**
|
|
315
387
|
* Rewrites every address in `text` with the address mode (`<address>` when it records none). In `off` and `hashed`
|
|
316
388
|
* mode, hex values longer than an address become `<hex>`, because they can embed one.
|
|
@@ -322,11 +394,12 @@ function formatAddressesIn(text, formatAddress) {
|
|
|
322
394
|
});
|
|
323
395
|
}
|
|
324
396
|
/**
|
|
325
|
-
* First line of an error message with
|
|
326
|
-
*
|
|
397
|
+
* First line of an error message with URLs cut to their origin (an RPC URL can carry an API key in its path or
|
|
398
|
+
* query), addresses per address mode and longer hex data (such as calldata) replaced by `<hex>`. Best effort: other
|
|
399
|
+
* free text is kept, so the redaction hook still runs on the result.
|
|
327
400
|
*/
|
|
328
401
|
function sanitizeErrorMessage(message, formatAddress) {
|
|
329
|
-
const sanitized = formatAddressesIn(message.split("\n", 1)[0]?.trim() ?? "", formatAddress).replace(HEX, (hex) => hex.length > MAX_HEX_LENGTH ? "<hex>" : hex);
|
|
402
|
+
const sanitized = formatAddressesIn((message.split("\n", 1)[0]?.trim() ?? "").replace(URL_IN_TEXT, (url) => hidesUserInfo(url) ? "<url>" : originOf(url) ?? "<url>"), formatAddress).replace(HEX, (hex) => hex.length > MAX_HEX_LENGTH ? "<hex>" : hex);
|
|
330
403
|
return sanitized.length > MAX_MESSAGE_LENGTH ? `${sanitized.slice(0, MAX_MESSAGE_LENGTH)}...` : sanitized;
|
|
331
404
|
}
|
|
332
405
|
const MAX_ARGUMENTS_LENGTH = 4096;
|
|
@@ -429,7 +502,16 @@ function paymentResourceOf(resource, mode) {
|
|
|
429
502
|
if (mode === "off" || hidesUserInfo(resource)) return void 0;
|
|
430
503
|
const recorded = mode === "path" ? sanitizeResource(resource) : originOf(resource);
|
|
431
504
|
if (recorded === void 0) return void 0;
|
|
432
|
-
return recorded
|
|
505
|
+
return cutAt(recorded, MAX_RESOURCE_LENGTH);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* `text` cut to `max` characters, followed by `...`. A hex value that the cut splits is dropped whole: the part left
|
|
509
|
+
* is shorter than an address, so the address mode, applied later, would no longer recognise it as one.
|
|
510
|
+
*/
|
|
511
|
+
function cutAt(text, max) {
|
|
512
|
+
if (text.length <= max) return text;
|
|
513
|
+
const head = text.slice(0, max);
|
|
514
|
+
return `${/^[0-9a-fA-F]/.test(text.slice(max)) ? head.replace(/0[xX][0-9a-fA-F]*$/, "") : head}...`;
|
|
433
515
|
}
|
|
434
516
|
/** Longest `x402.resource` recorded; the value comes from the server that asks for the payment. */
|
|
435
517
|
const MAX_RESOURCE_LENGTH = 512;
|
|
@@ -463,7 +545,7 @@ function sanitizeResource(resource) {
|
|
|
463
545
|
}
|
|
464
546
|
//#endregion
|
|
465
547
|
//#region src/version.ts
|
|
466
|
-
const VERSION = "0.
|
|
548
|
+
const VERSION = "0.9.0";
|
|
467
549
|
//#endregion
|
|
468
550
|
//#region src/tracker.ts
|
|
469
551
|
const INSTRUMENTATION_NAME = "@hashspan/core";
|
|
@@ -486,15 +568,42 @@ const NON_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
|
486
568
|
ATTR_BLOCKCHAIN_PAYMENT_PROTOCOL,
|
|
487
569
|
ATTR_BLOCKCHAIN_PAYMENT_STATUS,
|
|
488
570
|
ATTR_BLOCKCHAIN_PAYMENT_VERIFIED,
|
|
571
|
+
ATTR_BLOCKCHAIN_USER_OPERATION_HASH,
|
|
572
|
+
ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS,
|
|
573
|
+
ATTR_BLOCKCHAIN_CALL_BATCH_ID,
|
|
574
|
+
ATTR_BLOCKCHAIN_CALL_BATCH_STATUS,
|
|
489
575
|
ATTR_ERROR_TYPE,
|
|
490
576
|
ATTR_EXCEPTION_TYPE
|
|
491
577
|
]);
|
|
492
578
|
const TX_HASH = /^0x[0-9a-fA-F]{64}$/;
|
|
493
579
|
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
580
|
+
const ZERO_ADDRESS = /^0x0{40}$/;
|
|
581
|
+
/** The value of an own data property of `target`; undefined for an accessor, so no getter of the caller runs. */
|
|
582
|
+
function ownValue(target, key) {
|
|
583
|
+
if (typeof target !== "object" || target === null) return void 0;
|
|
584
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
585
|
+
return descriptor !== void 0 && "value" in descriptor ? descriptor.value : void 0;
|
|
586
|
+
}
|
|
494
587
|
/** A non-negative integer that fits in 256 bits. */
|
|
495
588
|
const AMOUNT = /^(0|[1-9][0-9]{0,77})$/;
|
|
589
|
+
/** A `0x` hex quantity of at most 256 bits, as JSON-RPC encodes integers. */
|
|
590
|
+
const HEX_QUANTITY = /^0x[0-9a-fA-F]{1,64}$/;
|
|
591
|
+
const MAX_UINT256 = 2n ** 256n - 1n;
|
|
592
|
+
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
|
496
593
|
/** `error.type` of a wait that gave up: a confirmation or a payment whose outcome was never learned. */
|
|
497
594
|
const OBSERVER_TIMEOUT = "timeout";
|
|
595
|
+
/** `error.type` of a call batch that failed without being included (EIP-5792 status 400). */
|
|
596
|
+
const CALL_BATCH_FAILED = "failed";
|
|
597
|
+
/** A call batch id: `0x`-prefixed hex of at most 8194 characters, the bound EIP-5792 sets. */
|
|
598
|
+
const CALL_BATCH_ID = /^0x[0-9a-fA-F]{1,8192}$/;
|
|
599
|
+
/** Longest call batch id recorded as an attribute. */
|
|
600
|
+
const MAX_CALL_BATCH_ID_ATTRIBUTE_LENGTH = 256;
|
|
601
|
+
/** Most transaction hashes recorded for one call batch. */
|
|
602
|
+
const MAX_CALL_BATCH_TRANSACTION_HASHES = 64;
|
|
603
|
+
/** Most EIP-7702 authorizations listed on a send span; the count covers all of them. */
|
|
604
|
+
const MAX_AUTHORIZATIONS = 64;
|
|
605
|
+
/** EIP-5792 status code of a batch that is still pending. */
|
|
606
|
+
const CALL_BATCH_PENDING = 100;
|
|
498
607
|
const PAYMENT_STATUSES = /* @__PURE__ */ new Set([
|
|
499
608
|
BLOCKCHAIN_PAYMENT_STATUS_VALUE_SETTLED,
|
|
500
609
|
BLOCKCHAIN_PAYMENT_STATUS_VALUE_PENDING,
|
|
@@ -511,6 +620,11 @@ const noopSend = (parent) => ({
|
|
|
511
620
|
end: () => {},
|
|
512
621
|
fail: () => {}
|
|
513
622
|
});
|
|
623
|
+
const noopUserOperationSend = (parent) => ({
|
|
624
|
+
context: parent,
|
|
625
|
+
end: () => {},
|
|
626
|
+
fail: () => {}
|
|
627
|
+
});
|
|
514
628
|
const NOOP_PAYMENT = {
|
|
515
629
|
end: () => {},
|
|
516
630
|
fail: () => {},
|
|
@@ -522,6 +636,21 @@ const NOOP_CONFIRM = {
|
|
|
522
636
|
timeout: () => {},
|
|
523
637
|
fail: () => {}
|
|
524
638
|
};
|
|
639
|
+
const NOOP_USER_OPERATION_CONFIRM = {
|
|
640
|
+
end: () => {},
|
|
641
|
+
timeout: () => {},
|
|
642
|
+
fail: () => {}
|
|
643
|
+
};
|
|
644
|
+
const noopCallBatchSend = (parent) => ({
|
|
645
|
+
context: parent,
|
|
646
|
+
end: () => {},
|
|
647
|
+
fail: () => {}
|
|
648
|
+
});
|
|
649
|
+
const NOOP_CALL_BATCH_CONFIRM = {
|
|
650
|
+
end: () => {},
|
|
651
|
+
timeout: () => {},
|
|
652
|
+
fail: () => {}
|
|
653
|
+
};
|
|
525
654
|
/** Runs `fn`, logging instead of throwing: instrumentation must never break the caller. */
|
|
526
655
|
function safely(what, fn, fallback) {
|
|
527
656
|
try {
|
|
@@ -544,12 +673,27 @@ const ERROR_TYPE_OVERRIDE = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
|
544
673
|
function identifier(value) {
|
|
545
674
|
return typeof value === "string" && ERROR_TYPE_OVERRIDE.test(value) ? value : void 0;
|
|
546
675
|
}
|
|
676
|
+
/**
|
|
677
|
+
* A non-negative integer of at most 256 bits, from a bigint, a safe integer, or a decimal or `0x` hex string, as
|
|
678
|
+
* bundlers return them; undefined for anything else.
|
|
679
|
+
*/
|
|
680
|
+
function quantity(value) {
|
|
681
|
+
let parsed;
|
|
682
|
+
if (typeof value === "bigint") parsed = value;
|
|
683
|
+
else if (typeof value === "number" && Number.isSafeInteger(value)) parsed = BigInt(value);
|
|
684
|
+
else if (typeof value === "string" && (AMOUNT.test(value) || HEX_QUANTITY.test(value))) parsed = BigInt(value);
|
|
685
|
+
return parsed !== void 0 && parsed >= 0n && parsed <= MAX_UINT256 ? parsed : void 0;
|
|
686
|
+
}
|
|
687
|
+
/** A quantity as a number, or undefined when it is none or too large to be one exactly. */
|
|
688
|
+
function smallQuantity(value) {
|
|
689
|
+
const parsed = quantity(value);
|
|
690
|
+
return parsed !== void 0 && parsed <= MAX_SAFE_INTEGER ? Number(parsed) : void 0;
|
|
691
|
+
}
|
|
547
692
|
/** A decimal amount, or undefined when `value` is not a non-negative integer. */
|
|
548
693
|
function amount(value) {
|
|
549
694
|
const text = typeof value === "bigint" ? value.toString() : value;
|
|
550
695
|
return typeof text === "string" && AMOUNT.test(text) ? text : void 0;
|
|
551
696
|
}
|
|
552
|
-
/** The `error.type` for a failure: an adapter's override when it is a short identifier, else the class name. */
|
|
553
697
|
/** A finite number, an `HrTime` pair or a `Date`: what the deprecated positional `endTime` argument takes. */
|
|
554
698
|
function isTimeInput(value) {
|
|
555
699
|
if (typeof value === "number") return Number.isFinite(value);
|
|
@@ -581,6 +725,7 @@ function handleOptions(second, third) {
|
|
|
581
725
|
return {};
|
|
582
726
|
}
|
|
583
727
|
}
|
|
728
|
+
/** The `error.type` for a failure: an adapter's override when it is a short identifier, else the class name. */
|
|
584
729
|
function reportedErrorType(error, options) {
|
|
585
730
|
const override = options?.errorType;
|
|
586
731
|
if (override === void 0) return errorType(error);
|
|
@@ -588,9 +733,53 @@ function reportedErrorType(error, options) {
|
|
|
588
733
|
_opentelemetry_api.diag.debug("hashspan: ignoring an error type that is not a short identifier");
|
|
589
734
|
return errorType(error);
|
|
590
735
|
}
|
|
736
|
+
/** A call batch id the tracker keys and records. */
|
|
737
|
+
function isCallBatchId(id) {
|
|
738
|
+
return typeof id === "string" && CALL_BATCH_ID.test(id);
|
|
739
|
+
}
|
|
740
|
+
/** Whether `status` says the batch is still pending: its wait resolved before an outcome. */
|
|
741
|
+
function isPendingCallBatch(status) {
|
|
742
|
+
return status?.statusCode === CALL_BATCH_PENDING;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Joins the confirm span for `hash` in `registry`, opening it with `open` for the first handle; undefined when the
|
|
746
|
+
* key recently got a receipt. A receipt from any handle ends the span; a timeout or failure only ends it when it is the
|
|
747
|
+
* last handle still waiting.
|
|
748
|
+
*/
|
|
749
|
+
function joinConfirm(registry, chainId, hash, open) {
|
|
750
|
+
const current = registry.get(chainId, hash);
|
|
751
|
+
if (current === "settled") return void 0;
|
|
752
|
+
let confirm = current;
|
|
753
|
+
if (!confirm) {
|
|
754
|
+
confirm = open();
|
|
755
|
+
registry.start(chainId, hash, confirm);
|
|
756
|
+
}
|
|
757
|
+
const shared = confirm;
|
|
758
|
+
shared.active += 1;
|
|
759
|
+
let done = false;
|
|
760
|
+
return {
|
|
761
|
+
shared,
|
|
762
|
+
receive: () => {
|
|
763
|
+
if (done || shared.ended) return false;
|
|
764
|
+
done = true;
|
|
765
|
+
shared.active -= 1;
|
|
766
|
+
shared.ended = true;
|
|
767
|
+
return true;
|
|
768
|
+
},
|
|
769
|
+
withdraw: (end) => {
|
|
770
|
+
if (done || shared.ended) return;
|
|
771
|
+
done = true;
|
|
772
|
+
shared.active -= 1;
|
|
773
|
+
if (shared.active > 0) return;
|
|
774
|
+
shared.ended = true;
|
|
775
|
+
registry.release(chainId, hash, shared);
|
|
776
|
+
end();
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
}
|
|
591
780
|
/**
|
|
592
781
|
* Creates a tracker that records transactions as `send` and `confirm` spans, and payments as `payment` spans, with
|
|
593
|
-
* `@opentelemetry/api` (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
782
|
+
* `@opentelemetry/api` (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/semconv.md). It makes
|
|
594
783
|
* no network calls; the caller passes hashes and receipts. Its methods and handles never throw: failures are logged
|
|
595
784
|
* via `diag`, and a method that fails returns a handle that records nothing.
|
|
596
785
|
*/
|
|
@@ -606,6 +795,22 @@ function createTxTracker(options = {}) {
|
|
|
606
795
|
const formatAddress = safely("configure address mode", () => resolveAddressFormatter(options.address), OFF_ADDRESS_FORMATTER);
|
|
607
796
|
const errorMessages = safely("configure error message mode", () => resolveErrorMessageMode(options.errorMessages), "off");
|
|
608
797
|
const paymentResource = safely("configure payment resource mode", () => resolvePaymentResourceMode(options.paymentResource), "off");
|
|
798
|
+
const userOperationLinks = new LinkStore({
|
|
799
|
+
ttlMs: options.linkTtlMs ?? DEFAULT_LINK_TTL_MS,
|
|
800
|
+
maxEntries: options.maxTrackedTransactions ?? DEFAULT_MAX_TRACKED
|
|
801
|
+
});
|
|
802
|
+
const userOperationConfirmations = new ConfirmRegistry({
|
|
803
|
+
ttlMs: options.linkTtlMs ?? DEFAULT_LINK_TTL_MS,
|
|
804
|
+
maxEntries: options.maxTrackedTransactions ?? DEFAULT_MAX_TRACKED
|
|
805
|
+
});
|
|
806
|
+
const callBatchLinks = new LinkStore({
|
|
807
|
+
ttlMs: options.linkTtlMs ?? DEFAULT_LINK_TTL_MS,
|
|
808
|
+
maxEntries: options.maxTrackedTransactions ?? DEFAULT_MAX_TRACKED
|
|
809
|
+
});
|
|
810
|
+
const callBatchConfirmations = new ConfirmRegistry({
|
|
811
|
+
ttlMs: options.linkTtlMs ?? DEFAULT_LINK_TTL_MS,
|
|
812
|
+
maxEntries: options.maxTrackedTransactions ?? DEFAULT_MAX_TRACKED
|
|
813
|
+
});
|
|
609
814
|
const txMetrics = createTxMetrics(options.meterProvider, INSTRUMENTATION_NAME, VERSION);
|
|
610
815
|
/** Attributes of a metric: low-cardinality only, never an address, hash or agent identity. */
|
|
611
816
|
const metricAttributes = (chainId, extra = {}) => ({
|
|
@@ -613,6 +818,16 @@ function createTxTracker(options = {}) {
|
|
|
613
818
|
[ATTR_BLOCKCHAIN_CHAIN_ID]: chainId,
|
|
614
819
|
...extra
|
|
615
820
|
});
|
|
821
|
+
/** Metric attributes of a user operation sample: as for transactions, plus what the sample is about. */
|
|
822
|
+
const userOperationMetricAttributes = (chainId, extra = {}) => metricAttributes(chainId, {
|
|
823
|
+
[ATTR_BLOCKCHAIN_OPERATION_SUBJECT]: BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION,
|
|
824
|
+
...extra
|
|
825
|
+
});
|
|
826
|
+
/** Metric attributes of a call batch sample. */
|
|
827
|
+
const callBatchMetricAttributes = (chainId, extra = {}) => metricAttributes(chainId, {
|
|
828
|
+
[ATTR_BLOCKCHAIN_OPERATION_SUBJECT]: BLOCKCHAIN_OPERATION_SUBJECT_VALUE_CALL_BATCH,
|
|
829
|
+
...extra
|
|
830
|
+
});
|
|
616
831
|
const secondsSince = (startMs, endTime) => (toEpochMs(endTime) - startMs) / 1e3;
|
|
617
832
|
let tracer;
|
|
618
833
|
const getTracer = () => {
|
|
@@ -638,7 +853,7 @@ function createTxTracker(options = {}) {
|
|
|
638
853
|
/**
|
|
639
854
|
* Exception event attributes for `error`, per the error message mode. The error object itself is never handed to
|
|
640
855
|
* the SDK: its message and stack can carry addresses and calldata
|
|
641
|
-
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
856
|
+
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0006-error-privacy.md).
|
|
642
857
|
*/
|
|
643
858
|
const exceptionAttributes = (type, error) => {
|
|
644
859
|
const attributes = { [ATTR_EXCEPTION_TYPE]: type };
|
|
@@ -693,8 +908,30 @@ function createTxTracker(options = {}) {
|
|
|
693
908
|
const formatted = formatAddress(address);
|
|
694
909
|
if (formatted !== void 0) attributes[key] = formatted;
|
|
695
910
|
};
|
|
696
|
-
/**
|
|
697
|
-
|
|
911
|
+
/**
|
|
912
|
+
* Records an EIP-7702 authorization list: its length, and for each well-formed entry (an address and a non-negative
|
|
913
|
+
* integer chain id, read from own data properties only) its address per the address mode and its chain id, at most
|
|
914
|
+
* {@link MAX_AUTHORIZATIONS}. The two lists stay aligned: an entry is listed in both or in neither.
|
|
915
|
+
*/
|
|
916
|
+
const setAuthorizations = (attributes, list) => {
|
|
917
|
+
if (!Array.isArray(list) || list.length === 0) return;
|
|
918
|
+
attributes[ATTR_BLOCKCHAIN_TX_AUTHORIZATION_COUNT] = list.length;
|
|
919
|
+
const addresses = [];
|
|
920
|
+
const chainIds = [];
|
|
921
|
+
for (const entry of list.slice(0, MAX_AUTHORIZATIONS)) {
|
|
922
|
+
const address = ownValue(entry, "address");
|
|
923
|
+
const chainId = ownValue(entry, "chainId");
|
|
924
|
+
if (typeof address !== "string" || !ADDRESS.test(address)) continue;
|
|
925
|
+
if (typeof chainId !== "number" || !Number.isSafeInteger(chainId) || chainId < 0) continue;
|
|
926
|
+
const formatted = formatAddress(address);
|
|
927
|
+
if (formatted !== void 0) addresses.push(formatted);
|
|
928
|
+
chainIds.push(chainId);
|
|
929
|
+
}
|
|
930
|
+
if (addresses.length > 0) attributes[ATTR_BLOCKCHAIN_TX_AUTHORIZATION_ADDRESSES] = addresses;
|
|
931
|
+
if (chainIds.length > 0) attributes[ATTR_BLOCKCHAIN_TX_AUTHORIZATION_CHAIN_IDS] = chainIds;
|
|
932
|
+
};
|
|
933
|
+
/** Records `address` only if it is one: payment and user operation addresses come from remote parties. */
|
|
934
|
+
const setRemoteAddress = (attributes, key, address) => {
|
|
698
935
|
if (typeof address === "string" && ADDRESS.test(address)) setAddress(attributes, key, address);
|
|
699
936
|
};
|
|
700
937
|
const baseAttributes = (chainId, operation, ctx) => ({
|
|
@@ -710,6 +947,11 @@ function createTxTracker(options = {}) {
|
|
|
710
947
|
setAddress(attributes, ATTR_BLOCKCHAIN_TX_TO, input.to);
|
|
711
948
|
if (input.value !== void 0) attributes[ATTR_BLOCKCHAIN_TX_VALUE] = input.value.toString();
|
|
712
949
|
if (input.nonce !== void 0) attributes[ATTR_BLOCKCHAIN_TX_NONCE] = input.nonce;
|
|
950
|
+
try {
|
|
951
|
+
setAuthorizations(attributes, input.authorizations);
|
|
952
|
+
} catch (error) {
|
|
953
|
+
_opentelemetry_api.diag.debug(`hashspan: could not record authorizations (${errorType(error)})`);
|
|
954
|
+
}
|
|
713
955
|
if (input.functionName !== void 0) attributes[ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_NAME] = input.functionName;
|
|
714
956
|
if (input.functionSelector !== void 0) attributes[ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_SELECTOR] = input.functionSelector;
|
|
715
957
|
if (options.recordFunctionArguments === true && input.functionArguments !== void 0) try {
|
|
@@ -830,7 +1072,7 @@ function createTxTracker(options = {}) {
|
|
|
830
1072
|
};
|
|
831
1073
|
/**
|
|
832
1074
|
* Ends `shared` with `receipt`, attributing it to the transaction that was mined
|
|
833
|
-
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
1075
|
+
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.9.0/docs/adr/0008-replaced-transactions.md).
|
|
834
1076
|
*/
|
|
835
1077
|
const endWithReceipt = (chainId, hash, shared, receipt, endTime) => {
|
|
836
1078
|
const mined = receipt.transactionHash;
|
|
@@ -860,41 +1102,22 @@ function createTxTracker(options = {}) {
|
|
|
860
1102
|
*/
|
|
861
1103
|
const startConfirm = (input, parentCtx) => {
|
|
862
1104
|
const { chainId, hash } = input;
|
|
863
|
-
const
|
|
864
|
-
if (
|
|
865
|
-
|
|
866
|
-
if (!confirm) {
|
|
867
|
-
confirm = openConfirm(input, parentCtx);
|
|
868
|
-
confirmations.start(chainId, hash, confirm);
|
|
869
|
-
}
|
|
870
|
-
const shared = confirm;
|
|
871
|
-
shared.active += 1;
|
|
872
|
-
let done = false;
|
|
873
|
-
const withdraw = (end) => {
|
|
874
|
-
if (done || shared.ended) return;
|
|
875
|
-
done = true;
|
|
876
|
-
shared.active -= 1;
|
|
877
|
-
if (shared.active > 0) return;
|
|
878
|
-
shared.ended = true;
|
|
879
|
-
confirmations.release(chainId, hash, shared);
|
|
880
|
-
end();
|
|
881
|
-
};
|
|
1105
|
+
const claim = joinConfirm(confirmations, chainId, hash, () => openConfirm(input, parentCtx));
|
|
1106
|
+
if (!claim) return NOOP_CONFIRM;
|
|
1107
|
+
const { shared } = claim;
|
|
882
1108
|
return {
|
|
883
1109
|
end: (receipt, second) => {
|
|
884
1110
|
const { endTime } = handleOptions(second);
|
|
885
|
-
if (
|
|
886
|
-
done = true;
|
|
887
|
-
shared.active -= 1;
|
|
888
|
-
shared.ended = true;
|
|
1111
|
+
if (!claim.receive()) return;
|
|
889
1112
|
safely("record receipt", () => endWithReceipt(chainId, hash, shared, receipt, endTime), void 0);
|
|
890
1113
|
},
|
|
891
1114
|
timeout: (second) => {
|
|
892
1115
|
const { endTime } = handleOptions(second);
|
|
893
|
-
withdraw(() => shared.timeout(endTime));
|
|
1116
|
+
claim.withdraw(() => shared.timeout(endTime));
|
|
894
1117
|
},
|
|
895
1118
|
fail: (error, second) => {
|
|
896
1119
|
const { endTime } = handleOptions(second);
|
|
897
|
-
withdraw(() => shared.fail(error, endTime));
|
|
1120
|
+
claim.withdraw(() => shared.fail(error, endTime));
|
|
898
1121
|
}
|
|
899
1122
|
};
|
|
900
1123
|
};
|
|
@@ -903,10 +1126,10 @@ function createTxTracker(options = {}) {
|
|
|
903
1126
|
const attributes = baseAttributes(input.chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_PAYMENT, parent);
|
|
904
1127
|
const protocol = identifier(input.protocol);
|
|
905
1128
|
if (protocol !== void 0) attributes[ATTR_BLOCKCHAIN_PAYMENT_PROTOCOL] = protocol;
|
|
906
|
-
|
|
1129
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_PAYMENT_PAYER, input.payer);
|
|
907
1130
|
const knownPayer = typeof input.payer === "string" && ADDRESS.test(input.payer);
|
|
908
|
-
|
|
909
|
-
|
|
1131
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_PAYMENT_RECIPIENT, input.recipient);
|
|
1132
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_PAYMENT_ASSET, input.asset);
|
|
910
1133
|
const paid = amount(input.amount);
|
|
911
1134
|
if (paid !== void 0) attributes[ATTR_BLOCKCHAIN_PAYMENT_AMOUNT] = paid;
|
|
912
1135
|
const scheme = identifier(input.x402?.scheme);
|
|
@@ -938,7 +1161,7 @@ function createTxTracker(options = {}) {
|
|
|
938
1161
|
const settled = { [ATTR_BLOCKCHAIN_PAYMENT_STATUS]: status };
|
|
939
1162
|
const hash = settlement.hash;
|
|
940
1163
|
if (linkHash(hash)) settled[ATTR_BLOCKCHAIN_TX_HASH] = hash;
|
|
941
|
-
if (!knownPayer)
|
|
1164
|
+
if (!knownPayer) setRemoteAddress(settled, ATTR_BLOCKCHAIN_PAYMENT_PAYER, settlement.payer);
|
|
942
1165
|
const settledAmount = amount(settlement.amount);
|
|
943
1166
|
if (settledAmount !== void 0) {
|
|
944
1167
|
settled[ATTR_BLOCKCHAIN_PAYMENT_SETTLED_AMOUNT] = settledAmount;
|
|
@@ -959,19 +1182,312 @@ function createTxTracker(options = {}) {
|
|
|
959
1182
|
link: (hash) => safely("link the payment span", () => void linkHash(hash), void 0)
|
|
960
1183
|
};
|
|
961
1184
|
};
|
|
1185
|
+
const startUserOperationSend = (input, parentCtx) => {
|
|
1186
|
+
const parent = parentCtx ?? _opentelemetry_api.context.active();
|
|
1187
|
+
const { chainId } = input;
|
|
1188
|
+
const attributes = baseAttributes(chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_SEND, parent);
|
|
1189
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_SENDER, input.sender);
|
|
1190
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT, input.entryPoint);
|
|
1191
|
+
const callCount = smallQuantity(input.callCount);
|
|
1192
|
+
if (callCount !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT] = callCount;
|
|
1193
|
+
const span = getTracer().startSpan(`send ${chainId}`, {
|
|
1194
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
1195
|
+
attributes: redact(attributes),
|
|
1196
|
+
...input.startTime !== void 0 ? { startTime: input.startTime } : {}
|
|
1197
|
+
}, parent);
|
|
1198
|
+
const finish = finisher(span);
|
|
1199
|
+
const startMs = toEpochMs(input.startTime);
|
|
1200
|
+
const recordSend = (endTime, errorType) => txMetrics.sendDuration(secondsSince(startMs, endTime), userOperationMetricAttributes(chainId, errorType === void 0 ? {} : { [ATTR_ERROR_TYPE]: errorType }));
|
|
1201
|
+
return {
|
|
1202
|
+
context: _opentelemetry_api.trace.setSpan(parent, span),
|
|
1203
|
+
end: (result, second) => {
|
|
1204
|
+
const { endTime } = handleOptions(second);
|
|
1205
|
+
finish("record user operation hash", () => {
|
|
1206
|
+
const hash = result?.userOpHash;
|
|
1207
|
+
if (typeof hash !== "string" || !TX_HASH.test(hash)) {
|
|
1208
|
+
_opentelemetry_api.diag.debug("hashspan: ending a send span without a valid user operation hash");
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
userOperationLinks.set(chainId, hash, {
|
|
1212
|
+
spanContext: span.spanContext(),
|
|
1213
|
+
parent
|
|
1214
|
+
});
|
|
1215
|
+
span.setAttributes(redact({ [ATTR_BLOCKCHAIN_USER_OPERATION_HASH]: hash }));
|
|
1216
|
+
recordSend(endTime);
|
|
1217
|
+
}, endTime);
|
|
1218
|
+
},
|
|
1219
|
+
fail: (error, second) => {
|
|
1220
|
+
const read = handleOptions(second);
|
|
1221
|
+
finish("record user operation send failure", () => recordSend(read.endTime, markError(span, reportedErrorType(error, read), error, errorType(error))), read.endTime);
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
};
|
|
1225
|
+
/**
|
|
1226
|
+
* Attributes of a user operation receipt. Its values come from a bundler: what is malformed is left out. The bundle
|
|
1227
|
+
* transaction's status, gas and fee are not recorded: they cover every operation in the bundle (ADR 0021).
|
|
1228
|
+
*/
|
|
1229
|
+
const userOperationReceiptAttributes = (receipt) => {
|
|
1230
|
+
const attributes = {};
|
|
1231
|
+
const success = receipt.success;
|
|
1232
|
+
if (typeof success === "boolean") attributes[ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS] = success;
|
|
1233
|
+
const gasUsed = smallQuantity(receipt.actualGasUsed);
|
|
1234
|
+
if (gasUsed !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED] = gasUsed;
|
|
1235
|
+
const gasCost = quantity(receipt.actualGasCost);
|
|
1236
|
+
if (gasCost !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST] = gasCost.toString();
|
|
1237
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_SENDER, receipt.sender);
|
|
1238
|
+
const nonce = quantity(receipt.nonce);
|
|
1239
|
+
if (nonce !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_NONCE] = nonce.toString();
|
|
1240
|
+
const paymaster = receipt.paymaster;
|
|
1241
|
+
if (typeof paymaster === "string" && !ZERO_ADDRESS.test(paymaster)) setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER, paymaster);
|
|
1242
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT, receipt.entryPoint);
|
|
1243
|
+
const reason = receipt.revertReason;
|
|
1244
|
+
if (typeof reason === "string") attributes[ATTR_BLOCKCHAIN_TX_REVERT_REASON] = formatAddressesIn(reason, formatAddress);
|
|
1245
|
+
const bundle = receipt.transactionHash;
|
|
1246
|
+
if (typeof bundle === "string" && TX_HASH.test(bundle)) attributes[ATTR_BLOCKCHAIN_TX_HASH] = bundle;
|
|
1247
|
+
const block = smallQuantity(receipt.blockNumber);
|
|
1248
|
+
if (block !== void 0) attributes[ATTR_BLOCKCHAIN_BLOCK_NUMBER] = block;
|
|
1249
|
+
return attributes;
|
|
1250
|
+
};
|
|
1251
|
+
/** Opens the confirm span of a user operation. */
|
|
1252
|
+
const openUserOperationConfirm = (input, parentCtx) => {
|
|
1253
|
+
const { chainId, userOpHash } = input;
|
|
1254
|
+
const sent = userOperationLinks.get(chainId, userOpHash);
|
|
1255
|
+
const active = _opentelemetry_api.context.active();
|
|
1256
|
+
const parent = parentCtx ?? (_opentelemetry_api.trace.getSpan(active) ? active : sent?.parent ?? active);
|
|
1257
|
+
const attributes = baseAttributes(chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_CONFIRM, parent);
|
|
1258
|
+
attributes[ATTR_BLOCKCHAIN_USER_OPERATION_HASH] = userOpHash;
|
|
1259
|
+
const span = getTracer().startSpan(`confirm ${chainId}`, {
|
|
1260
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
1261
|
+
attributes: redact(attributes),
|
|
1262
|
+
links: sent ? [{ context: sent.spanContext }] : [],
|
|
1263
|
+
...input.startTime !== void 0 ? { startTime: input.startTime } : {}
|
|
1264
|
+
}, parent);
|
|
1265
|
+
const finish = finisher(span);
|
|
1266
|
+
const startMs = toEpochMs(input.startTime);
|
|
1267
|
+
const recordConfirmation = (endTime, outcome) => txMetrics.confirmationDuration(secondsSince(startMs, endTime), userOperationMetricAttributes(chainId, outcome));
|
|
1268
|
+
return {
|
|
1269
|
+
active: 0,
|
|
1270
|
+
ended: false,
|
|
1271
|
+
receipt: (receipt, endTime) => finish("record user operation receipt", () => {
|
|
1272
|
+
const attributes = userOperationReceiptAttributes(receipt ?? {});
|
|
1273
|
+
span.setAttributes(redact(attributes));
|
|
1274
|
+
const success = attributes[ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS];
|
|
1275
|
+
if (success === false) markError(span, BLOCKCHAIN_TX_STATUS_VALUE_REVERTED);
|
|
1276
|
+
const outcome = typeof success === "boolean" ? { [ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS]: success } : {};
|
|
1277
|
+
recordConfirmation(endTime, outcome);
|
|
1278
|
+
const cost = attributes[ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST];
|
|
1279
|
+
if (typeof cost === "string") txMetrics.fee(BigInt(cost), userOperationMetricAttributes(chainId, outcome));
|
|
1280
|
+
}, endTime),
|
|
1281
|
+
timeout: (endTime) => finish("record user operation confirmation timeout", () => recordConfirmation(endTime, { [ATTR_ERROR_TYPE]: markError(span, OBSERVER_TIMEOUT) }), endTime),
|
|
1282
|
+
fail: (error, read) => finish("record user operation confirmation failure", () => recordConfirmation(read.endTime, { [ATTR_ERROR_TYPE]: markError(span, reportedErrorType(error, read), error, errorType(error)) }), read.endTime)
|
|
1283
|
+
};
|
|
1284
|
+
};
|
|
1285
|
+
const startUserOperationConfirm = (input, parentCtx) => {
|
|
1286
|
+
const { chainId, userOpHash } = input;
|
|
1287
|
+
if (typeof userOpHash !== "string" || !TX_HASH.test(userOpHash)) {
|
|
1288
|
+
_opentelemetry_api.diag.debug("hashspan: not confirming a user operation without a valid hash");
|
|
1289
|
+
return NOOP_USER_OPERATION_CONFIRM;
|
|
1290
|
+
}
|
|
1291
|
+
const claim = joinConfirm(userOperationConfirmations, chainId, userOpHash, () => openUserOperationConfirm(input, parentCtx));
|
|
1292
|
+
if (!claim) return NOOP_USER_OPERATION_CONFIRM;
|
|
1293
|
+
const { shared } = claim;
|
|
1294
|
+
return {
|
|
1295
|
+
end: (receipt, second) => {
|
|
1296
|
+
const { endTime } = handleOptions(second);
|
|
1297
|
+
if (!claim.receive()) return;
|
|
1298
|
+
userOperationConfirmations.settle(chainId, userOpHash, shared);
|
|
1299
|
+
shared.receipt(receipt, endTime);
|
|
1300
|
+
},
|
|
1301
|
+
timeout: (second) => {
|
|
1302
|
+
const { endTime } = handleOptions(second);
|
|
1303
|
+
claim.withdraw(() => shared.timeout(endTime));
|
|
1304
|
+
},
|
|
1305
|
+
fail: (error, second) => {
|
|
1306
|
+
const read = handleOptions(second);
|
|
1307
|
+
claim.withdraw(() => shared.fail(error, read));
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
};
|
|
1311
|
+
const startCallBatchSend = (input, parentCtx) => {
|
|
1312
|
+
const parent = parentCtx ?? _opentelemetry_api.context.active();
|
|
1313
|
+
const { chainId } = input;
|
|
1314
|
+
const attributes = baseAttributes(chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_SEND, parent);
|
|
1315
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_CALL_BATCH_SENDER, input.sender);
|
|
1316
|
+
const callCount = smallQuantity(input.callCount);
|
|
1317
|
+
if (callCount !== void 0) attributes[ATTR_BLOCKCHAIN_CALL_BATCH_CALL_COUNT] = callCount;
|
|
1318
|
+
const span = getTracer().startSpan(`send ${chainId}`, {
|
|
1319
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
1320
|
+
attributes: redact(attributes),
|
|
1321
|
+
...input.startTime !== void 0 ? { startTime: input.startTime } : {}
|
|
1322
|
+
}, parent);
|
|
1323
|
+
const finish = finisher(span);
|
|
1324
|
+
const startMs = toEpochMs(input.startTime);
|
|
1325
|
+
const recordSend = (endTime, errorType) => txMetrics.sendDuration(secondsSince(startMs, endTime), callBatchMetricAttributes(chainId, errorType === void 0 ? {} : { [ATTR_ERROR_TYPE]: errorType }));
|
|
1326
|
+
return {
|
|
1327
|
+
context: _opentelemetry_api.trace.setSpan(parent, span),
|
|
1328
|
+
end: (result, second) => {
|
|
1329
|
+
const { endTime } = handleOptions(second);
|
|
1330
|
+
finish("record call batch id", () => {
|
|
1331
|
+
const id = result?.id;
|
|
1332
|
+
if (!isCallBatchId(id)) {
|
|
1333
|
+
_opentelemetry_api.diag.debug("hashspan: ending a send span without a valid call batch id");
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
const sent = {
|
|
1337
|
+
spanContext: span.spanContext(),
|
|
1338
|
+
parent
|
|
1339
|
+
};
|
|
1340
|
+
callBatchLinks.set(chainId, id, sent);
|
|
1341
|
+
const hashes = result.transactionHashes;
|
|
1342
|
+
if (Array.isArray(hashes)) {
|
|
1343
|
+
for (const hash of hashes) if (typeof hash === "string" && TX_HASH.test(hash) && !/^0x0+$/.test(hash)) links.set(chainId, hash, sent);
|
|
1344
|
+
}
|
|
1345
|
+
span.setAttributes(redact({ [ATTR_BLOCKCHAIN_CALL_BATCH_ID]: id.slice(0, MAX_CALL_BATCH_ID_ATTRIBUTE_LENGTH) }));
|
|
1346
|
+
recordSend(endTime);
|
|
1347
|
+
}, endTime);
|
|
1348
|
+
},
|
|
1349
|
+
fail: (error, second) => {
|
|
1350
|
+
const read = handleOptions(second);
|
|
1351
|
+
finish("record call batch send failure", () => recordSend(read.endTime, markError(span, reportedErrorType(error, read), error, errorType(error))), read.endTime);
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
};
|
|
1355
|
+
/** Attributes of a call batch status. Its values come from a wallet: what is malformed is left out. */
|
|
1356
|
+
const callBatchStatusAttributes = (status) => {
|
|
1357
|
+
const attributes = {};
|
|
1358
|
+
const code = smallQuantity(status.statusCode);
|
|
1359
|
+
if (code !== void 0) attributes[ATTR_BLOCKCHAIN_CALL_BATCH_STATUS_CODE] = code;
|
|
1360
|
+
const atomic = status.atomic;
|
|
1361
|
+
if (typeof atomic === "boolean") attributes[ATTR_BLOCKCHAIN_CALL_BATCH_ATOMIC] = atomic;
|
|
1362
|
+
const receipts = status.receipts;
|
|
1363
|
+
if (Array.isArray(receipts)) {
|
|
1364
|
+
const hashes = [];
|
|
1365
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1366
|
+
let block;
|
|
1367
|
+
for (const receipt of receipts) {
|
|
1368
|
+
const hash = receipt?.transactionHash;
|
|
1369
|
+
if (typeof hash === "string" && TX_HASH.test(hash) && !seen.has(hash.toLowerCase()) && hashes.length < MAX_CALL_BATCH_TRANSACTION_HASHES) {
|
|
1370
|
+
seen.add(hash.toLowerCase());
|
|
1371
|
+
hashes.push(hash);
|
|
1372
|
+
}
|
|
1373
|
+
const number = smallQuantity(receipt?.blockNumber);
|
|
1374
|
+
if (number !== void 0 && (block === void 0 || number > block)) block = number;
|
|
1375
|
+
}
|
|
1376
|
+
if (hashes.length > 0) attributes[ATTR_BLOCKCHAIN_CALL_BATCH_TRANSACTION_HASHES] = hashes;
|
|
1377
|
+
if (block !== void 0) attributes[ATTR_BLOCKCHAIN_BLOCK_NUMBER] = block;
|
|
1378
|
+
}
|
|
1379
|
+
return attributes;
|
|
1380
|
+
};
|
|
1381
|
+
/**
|
|
1382
|
+
* The outcome of an EIP-5792 status code (ADR 0022): `blockchain.call_batch.status` for outcomes from chain data,
|
|
1383
|
+
* `error.type` for the rest; a code the spec does not define, or none, is `_OTHER`.
|
|
1384
|
+
*/
|
|
1385
|
+
const callBatchOutcome = (code) => {
|
|
1386
|
+
switch (code) {
|
|
1387
|
+
case 200: return { status: BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_SUCCESS };
|
|
1388
|
+
case 400: return { errorType: CALL_BATCH_FAILED };
|
|
1389
|
+
case 500: return {
|
|
1390
|
+
status: BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_REVERTED,
|
|
1391
|
+
errorType: BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_REVERTED
|
|
1392
|
+
};
|
|
1393
|
+
case 600: return {
|
|
1394
|
+
status: BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_PARTIALLY_REVERTED,
|
|
1395
|
+
errorType: BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_PARTIALLY_REVERTED
|
|
1396
|
+
};
|
|
1397
|
+
default: return { errorType: ERROR_TYPE_VALUE_OTHER };
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
/** Opens the confirm span of a call batch. */
|
|
1401
|
+
const openCallBatchConfirm = (input, parentCtx) => {
|
|
1402
|
+
const { chainId, id } = input;
|
|
1403
|
+
const sent = callBatchLinks.get(chainId, id);
|
|
1404
|
+
const active = _opentelemetry_api.context.active();
|
|
1405
|
+
const parent = parentCtx ?? (_opentelemetry_api.trace.getSpan(active) ? active : sent?.parent ?? active);
|
|
1406
|
+
const attributes = baseAttributes(chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_CONFIRM, parent);
|
|
1407
|
+
attributes[ATTR_BLOCKCHAIN_CALL_BATCH_ID] = id.slice(0, MAX_CALL_BATCH_ID_ATTRIBUTE_LENGTH);
|
|
1408
|
+
const span = getTracer().startSpan(`confirm ${chainId}`, {
|
|
1409
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
1410
|
+
attributes: redact(attributes),
|
|
1411
|
+
links: sent ? [{ context: sent.spanContext }] : [],
|
|
1412
|
+
...input.startTime !== void 0 ? { startTime: input.startTime } : {}
|
|
1413
|
+
}, parent);
|
|
1414
|
+
const finish = finisher(span);
|
|
1415
|
+
const startMs = toEpochMs(input.startTime);
|
|
1416
|
+
const recordConfirmation = (endTime, outcome) => txMetrics.confirmationDuration(secondsSince(startMs, endTime), callBatchMetricAttributes(chainId, outcome));
|
|
1417
|
+
return {
|
|
1418
|
+
active: 0,
|
|
1419
|
+
ended: false,
|
|
1420
|
+
status: (status, endTime) => finish("record call batch status", () => {
|
|
1421
|
+
const attributes = callBatchStatusAttributes(status ?? {});
|
|
1422
|
+
if (isPendingCallBatch(status)) {
|
|
1423
|
+
span.setAttributes(redact(attributes));
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
const outcome = callBatchOutcome(status?.statusCode);
|
|
1427
|
+
if (outcome.status !== void 0) attributes[ATTR_BLOCKCHAIN_CALL_BATCH_STATUS] = outcome.status;
|
|
1428
|
+
span.setAttributes(redact(attributes));
|
|
1429
|
+
if (outcome.errorType !== void 0) markError(span, outcome.errorType);
|
|
1430
|
+
recordConfirmation(endTime, outcome.status !== void 0 ? { [ATTR_BLOCKCHAIN_CALL_BATCH_STATUS]: outcome.status } : { [ATTR_ERROR_TYPE]: outcome.errorType });
|
|
1431
|
+
}, endTime),
|
|
1432
|
+
timeout: (endTime) => finish("record call batch confirmation timeout", () => recordConfirmation(endTime, { [ATTR_ERROR_TYPE]: markError(span, OBSERVER_TIMEOUT) }), endTime),
|
|
1433
|
+
fail: (error, read) => finish("record call batch confirmation failure", () => recordConfirmation(read.endTime, { [ATTR_ERROR_TYPE]: markError(span, reportedErrorType(error, read), error, errorType(error)) }), read.endTime)
|
|
1434
|
+
};
|
|
1435
|
+
};
|
|
1436
|
+
const startCallBatchConfirm = (input, parentCtx) => {
|
|
1437
|
+
const { chainId, id } = input;
|
|
1438
|
+
if (!isCallBatchId(id)) {
|
|
1439
|
+
_opentelemetry_api.diag.debug("hashspan: not confirming a call batch without a valid id");
|
|
1440
|
+
return NOOP_CALL_BATCH_CONFIRM;
|
|
1441
|
+
}
|
|
1442
|
+
const claim = joinConfirm(callBatchConfirmations, chainId, id, () => openCallBatchConfirm(input, parentCtx));
|
|
1443
|
+
if (!claim) return NOOP_CALL_BATCH_CONFIRM;
|
|
1444
|
+
const { shared } = claim;
|
|
1445
|
+
return {
|
|
1446
|
+
end: (status, second) => {
|
|
1447
|
+
const { endTime } = handleOptions(second);
|
|
1448
|
+
if (isPendingCallBatch(status)) {
|
|
1449
|
+
claim.withdraw(() => shared.status(status, endTime));
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
if (!claim.receive()) return;
|
|
1453
|
+
callBatchConfirmations.settle(chainId, id, shared);
|
|
1454
|
+
shared.status(status, endTime);
|
|
1455
|
+
},
|
|
1456
|
+
timeout: (second) => {
|
|
1457
|
+
const { endTime } = handleOptions(second);
|
|
1458
|
+
claim.withdraw(() => shared.timeout(endTime));
|
|
1459
|
+
},
|
|
1460
|
+
fail: (error, second) => {
|
|
1461
|
+
const read = handleOptions(second);
|
|
1462
|
+
claim.withdraw(() => shared.fail(error, read));
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1465
|
+
};
|
|
962
1466
|
return {
|
|
963
1467
|
startSend: (input, parent) => safely("start send span", () => startSend(input, parent), noopSend(parent ?? _opentelemetry_api.context.active())),
|
|
964
1468
|
startConfirm: (input, parent) => safely("start confirm span", () => startConfirm(input, parent), NOOP_CONFIRM),
|
|
965
|
-
startPayment: (input, parent) => safely("start payment span", () => startPayment(input, parent), NOOP_PAYMENT)
|
|
1469
|
+
startPayment: (input, parent) => safely("start payment span", () => startPayment(input, parent), NOOP_PAYMENT),
|
|
1470
|
+
startUserOperationSend: (input, parent) => safely("start user operation send span", () => startUserOperationSend(input, parent), noopUserOperationSend(parent ?? _opentelemetry_api.context.active())),
|
|
1471
|
+
startUserOperationConfirm: (input, parent) => safely("start user operation confirm span", () => startUserOperationConfirm(input, parent), NOOP_USER_OPERATION_CONFIRM),
|
|
1472
|
+
startCallBatchSend: (input, parent) => safely("start call batch send span", () => startCallBatchSend(input, parent), noopCallBatchSend(parent ?? _opentelemetry_api.context.active())),
|
|
1473
|
+
startCallBatchConfirm: (input, parent) => safely("start call batch confirm span", () => startCallBatchConfirm(input, parent), NOOP_CALL_BATCH_CONFIRM)
|
|
966
1474
|
};
|
|
967
1475
|
}
|
|
968
1476
|
//#endregion
|
|
969
1477
|
exports.ATTR_BLOCKCHAIN_BLOCK_NUMBER = ATTR_BLOCKCHAIN_BLOCK_NUMBER;
|
|
1478
|
+
exports.ATTR_BLOCKCHAIN_CALL_BATCH_ATOMIC = ATTR_BLOCKCHAIN_CALL_BATCH_ATOMIC;
|
|
1479
|
+
exports.ATTR_BLOCKCHAIN_CALL_BATCH_CALL_COUNT = ATTR_BLOCKCHAIN_CALL_BATCH_CALL_COUNT;
|
|
1480
|
+
exports.ATTR_BLOCKCHAIN_CALL_BATCH_ID = ATTR_BLOCKCHAIN_CALL_BATCH_ID;
|
|
1481
|
+
exports.ATTR_BLOCKCHAIN_CALL_BATCH_SENDER = ATTR_BLOCKCHAIN_CALL_BATCH_SENDER;
|
|
1482
|
+
exports.ATTR_BLOCKCHAIN_CALL_BATCH_STATUS = ATTR_BLOCKCHAIN_CALL_BATCH_STATUS;
|
|
1483
|
+
exports.ATTR_BLOCKCHAIN_CALL_BATCH_STATUS_CODE = ATTR_BLOCKCHAIN_CALL_BATCH_STATUS_CODE;
|
|
1484
|
+
exports.ATTR_BLOCKCHAIN_CALL_BATCH_TRANSACTION_HASHES = ATTR_BLOCKCHAIN_CALL_BATCH_TRANSACTION_HASHES;
|
|
970
1485
|
exports.ATTR_BLOCKCHAIN_CHAIN_ID = ATTR_BLOCKCHAIN_CHAIN_ID;
|
|
971
1486
|
exports.ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_ARGUMENTS = ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_ARGUMENTS;
|
|
972
1487
|
exports.ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_NAME = ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_NAME;
|
|
973
1488
|
exports.ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_SELECTOR = ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_SELECTOR;
|
|
974
1489
|
exports.ATTR_BLOCKCHAIN_OPERATION_NAME = ATTR_BLOCKCHAIN_OPERATION_NAME;
|
|
1490
|
+
exports.ATTR_BLOCKCHAIN_OPERATION_SUBJECT = ATTR_BLOCKCHAIN_OPERATION_SUBJECT;
|
|
975
1491
|
exports.ATTR_BLOCKCHAIN_PAYMENT_AMOUNT = ATTR_BLOCKCHAIN_PAYMENT_AMOUNT;
|
|
976
1492
|
exports.ATTR_BLOCKCHAIN_PAYMENT_ASSET = ATTR_BLOCKCHAIN_PAYMENT_ASSET;
|
|
977
1493
|
exports.ATTR_BLOCKCHAIN_PAYMENT_PAYER = ATTR_BLOCKCHAIN_PAYMENT_PAYER;
|
|
@@ -981,6 +1497,9 @@ exports.ATTR_BLOCKCHAIN_PAYMENT_SETTLED_AMOUNT = ATTR_BLOCKCHAIN_PAYMENT_SETTLED
|
|
|
981
1497
|
exports.ATTR_BLOCKCHAIN_PAYMENT_STATUS = ATTR_BLOCKCHAIN_PAYMENT_STATUS;
|
|
982
1498
|
exports.ATTR_BLOCKCHAIN_PAYMENT_VERIFIED = ATTR_BLOCKCHAIN_PAYMENT_VERIFIED;
|
|
983
1499
|
exports.ATTR_BLOCKCHAIN_SYSTEM = ATTR_BLOCKCHAIN_SYSTEM;
|
|
1500
|
+
exports.ATTR_BLOCKCHAIN_TX_AUTHORIZATION_ADDRESSES = ATTR_BLOCKCHAIN_TX_AUTHORIZATION_ADDRESSES;
|
|
1501
|
+
exports.ATTR_BLOCKCHAIN_TX_AUTHORIZATION_CHAIN_IDS = ATTR_BLOCKCHAIN_TX_AUTHORIZATION_CHAIN_IDS;
|
|
1502
|
+
exports.ATTR_BLOCKCHAIN_TX_AUTHORIZATION_COUNT = ATTR_BLOCKCHAIN_TX_AUTHORIZATION_COUNT;
|
|
984
1503
|
exports.ATTR_BLOCKCHAIN_TX_EFFECTIVE_GAS_PRICE = ATTR_BLOCKCHAIN_TX_EFFECTIVE_GAS_PRICE;
|
|
985
1504
|
exports.ATTR_BLOCKCHAIN_TX_FEE = ATTR_BLOCKCHAIN_TX_FEE;
|
|
986
1505
|
exports.ATTR_BLOCKCHAIN_TX_FROM = ATTR_BLOCKCHAIN_TX_FROM;
|
|
@@ -994,14 +1513,28 @@ exports.ATTR_BLOCKCHAIN_TX_REVERT_REASON = ATTR_BLOCKCHAIN_TX_REVERT_REASON;
|
|
|
994
1513
|
exports.ATTR_BLOCKCHAIN_TX_STATUS = ATTR_BLOCKCHAIN_TX_STATUS;
|
|
995
1514
|
exports.ATTR_BLOCKCHAIN_TX_TO = ATTR_BLOCKCHAIN_TX_TO;
|
|
996
1515
|
exports.ATTR_BLOCKCHAIN_TX_VALUE = ATTR_BLOCKCHAIN_TX_VALUE;
|
|
1516
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT = ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT;
|
|
1517
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT = ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT;
|
|
1518
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST = ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST;
|
|
1519
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED = ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED;
|
|
1520
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_HASH = ATTR_BLOCKCHAIN_USER_OPERATION_HASH;
|
|
1521
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_NONCE = ATTR_BLOCKCHAIN_USER_OPERATION_NONCE;
|
|
1522
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER = ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER;
|
|
1523
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_SENDER = ATTR_BLOCKCHAIN_USER_OPERATION_SENDER;
|
|
1524
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS = ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS;
|
|
997
1525
|
exports.ATTR_ERROR_TYPE = ATTR_ERROR_TYPE;
|
|
998
1526
|
exports.ATTR_GEN_AI_AGENT_ID = ATTR_GEN_AI_AGENT_ID;
|
|
999
1527
|
exports.ATTR_GEN_AI_AGENT_NAME = ATTR_GEN_AI_AGENT_NAME;
|
|
1000
1528
|
exports.ATTR_X402_RESOURCE = ATTR_X402_RESOURCE;
|
|
1001
1529
|
exports.ATTR_X402_SCHEME = ATTR_X402_SCHEME;
|
|
1530
|
+
exports.BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_PARTIALLY_REVERTED = BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_PARTIALLY_REVERTED;
|
|
1531
|
+
exports.BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_REVERTED = BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_REVERTED;
|
|
1532
|
+
exports.BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_SUCCESS = BLOCKCHAIN_CALL_BATCH_STATUS_VALUE_SUCCESS;
|
|
1002
1533
|
exports.BLOCKCHAIN_OPERATION_NAME_VALUE_CONFIRM = BLOCKCHAIN_OPERATION_NAME_VALUE_CONFIRM;
|
|
1003
1534
|
exports.BLOCKCHAIN_OPERATION_NAME_VALUE_PAYMENT = BLOCKCHAIN_OPERATION_NAME_VALUE_PAYMENT;
|
|
1004
1535
|
exports.BLOCKCHAIN_OPERATION_NAME_VALUE_SEND = BLOCKCHAIN_OPERATION_NAME_VALUE_SEND;
|
|
1536
|
+
exports.BLOCKCHAIN_OPERATION_SUBJECT_VALUE_CALL_BATCH = BLOCKCHAIN_OPERATION_SUBJECT_VALUE_CALL_BATCH;
|
|
1537
|
+
exports.BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION = BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION;
|
|
1005
1538
|
exports.BLOCKCHAIN_PAYMENT_PROTOCOL_VALUE_X402 = BLOCKCHAIN_PAYMENT_PROTOCOL_VALUE_X402;
|
|
1006
1539
|
exports.BLOCKCHAIN_PAYMENT_STATUS_VALUE_FAILED = BLOCKCHAIN_PAYMENT_STATUS_VALUE_FAILED;
|
|
1007
1540
|
exports.BLOCKCHAIN_PAYMENT_STATUS_VALUE_PENDING = BLOCKCHAIN_PAYMENT_STATUS_VALUE_PENDING;
|