@hashspan/core 0.6.0 → 0.8.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 +35 -13
- package/dist/index.cjs +394 -47
- package/dist/index.d.cts +186 -25
- package/dist/index.d.mts +186 -25
- package/dist/index.mjs +382 -49
- package/package.json +1 -1
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.8.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.8.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";
|
|
@@ -46,12 +46,12 @@ const ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_NAME = "blockchain.contract.function.nam
|
|
|
46
46
|
const ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_SELECTOR = "blockchain.contract.function.selector";
|
|
47
47
|
/**
|
|
48
48
|
* Opt-in: decoded call arguments as a JSON array. See
|
|
49
|
-
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
49
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/adr/0004-privacy-defaults.md.
|
|
50
50
|
*/
|
|
51
51
|
const ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_ARGUMENTS = "blockchain.contract.function.arguments";
|
|
52
52
|
/**
|
|
53
53
|
* 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.
|
|
54
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/adr/0013-x402-payments.md.
|
|
55
55
|
*/
|
|
56
56
|
const ATTR_BLOCKCHAIN_PAYMENT_PROTOCOL = "blockchain.payment.protocol";
|
|
57
57
|
const ATTR_BLOCKCHAIN_PAYMENT_PAYER = "blockchain.payment.payer";
|
|
@@ -64,12 +64,33 @@ const ATTR_BLOCKCHAIN_PAYMENT_SETTLED_AMOUNT = "blockchain.payment.settled_amoun
|
|
|
64
64
|
/**
|
|
65
65
|
* Whether the settlement transaction's receipt carries the payment, as checked by the adapter; absent when no check
|
|
66
66
|
* was possible. See
|
|
67
|
-
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
67
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/adr/0017-x402-payment-verification.md.
|
|
68
68
|
*/
|
|
69
69
|
const ATTR_BLOCKCHAIN_PAYMENT_VERIFIED = "blockchain.payment.verified";
|
|
70
70
|
/** x402's own payment fields. */
|
|
71
71
|
const ATTR_X402_SCHEME = "x402.scheme";
|
|
72
72
|
const ATTR_X402_RESOURCE = "x402.resource";
|
|
73
|
+
/**
|
|
74
|
+
* User operations of ERC-4337 smart accounts. See
|
|
75
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/adr/0021-user-operations.md.
|
|
76
|
+
*/
|
|
77
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_HASH = "blockchain.user_operation.hash";
|
|
78
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_SENDER = "blockchain.user_operation.sender";
|
|
79
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT = "blockchain.user_operation.entry_point";
|
|
80
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT = "blockchain.user_operation.call_count";
|
|
81
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_NONCE = "blockchain.user_operation.nonce";
|
|
82
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS = "blockchain.user_operation.success";
|
|
83
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED = "blockchain.user_operation.gas.used";
|
|
84
|
+
/** What the operation itself paid, in wei; the bundle transaction's fee covers every operation in the bundle. */
|
|
85
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST = "blockchain.user_operation.gas.cost";
|
|
86
|
+
const ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER = "blockchain.user_operation.paymaster";
|
|
87
|
+
/**
|
|
88
|
+
* Metrics only: what a send, confirmation or fee sample is about. Recorded as `user_operation` on samples of user
|
|
89
|
+
* operations, and absent on those of transactions.
|
|
90
|
+
*/
|
|
91
|
+
const ATTR_BLOCKCHAIN_OPERATION_SUBJECT = "blockchain.operation.subject";
|
|
92
|
+
/** Values for {@link ATTR_BLOCKCHAIN_OPERATION_SUBJECT}. */
|
|
93
|
+
const BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION = "user_operation";
|
|
73
94
|
/** Values for {@link ATTR_BLOCKCHAIN_SYSTEM}. */
|
|
74
95
|
const BLOCKCHAIN_SYSTEM_VALUE_EVM = "evm";
|
|
75
96
|
/** Values for {@link ATTR_BLOCKCHAIN_OPERATION_NAME}. */
|
|
@@ -88,7 +109,7 @@ const BLOCKCHAIN_TX_STATUS_VALUE_REVERTED = "reverted";
|
|
|
88
109
|
/**
|
|
89
110
|
* @deprecated No longer recorded: a confirm span that gave up waiting records `error.type` `timeout` and no
|
|
90
111
|
* `blockchain.tx.status`. The constant is removed in 1.0. See
|
|
91
|
-
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
112
|
+
* https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/adr/0016-timeout-is-an-observer-outcome.md.
|
|
92
113
|
*/
|
|
93
114
|
const BLOCKCHAIN_TX_STATUS_VALUE_TIMEOUT = "timeout";
|
|
94
115
|
const BLOCKCHAIN_TX_STATUS_VALUE_REPLACED = "replaced";
|
|
@@ -101,6 +122,107 @@ const ATTR_ERROR_TYPE = "error.type";
|
|
|
101
122
|
/** Fallback {@link ATTR_ERROR_TYPE} value when the error has no name. */
|
|
102
123
|
const ERROR_TYPE_VALUE_OTHER = "_OTHER";
|
|
103
124
|
//#endregion
|
|
125
|
+
//#region src/metrics.ts
|
|
126
|
+
/**
|
|
127
|
+
* Duration of a send of a transaction or user operation: from the start of the sending call until the hash is known or
|
|
128
|
+
* the call failed.
|
|
129
|
+
*/
|
|
130
|
+
const METRIC_BLOCKCHAIN_CLIENT_SEND_DURATION = "blockchain.client.send.duration";
|
|
131
|
+
/**
|
|
132
|
+
* Duration of a confirmation of a transaction or user operation: from the start of the wait until the receipt, a
|
|
133
|
+
* timeout or a failure.
|
|
134
|
+
*/
|
|
135
|
+
const METRIC_BLOCKCHAIN_CLIENT_CONFIRMATION_DURATION = "blockchain.client.confirmation.duration";
|
|
136
|
+
/**
|
|
137
|
+
* Total fee of a mined transaction (execution fee plus L1 data fee), or the cost of a user operation, in the chain's
|
|
138
|
+
* smallest unit (wei).
|
|
139
|
+
*/
|
|
140
|
+
const METRIC_BLOCKCHAIN_CLIENT_FEE = "blockchain.client.fee";
|
|
141
|
+
const DURATION_BUCKETS = [
|
|
142
|
+
.05,
|
|
143
|
+
.1,
|
|
144
|
+
.25,
|
|
145
|
+
.5,
|
|
146
|
+
1,
|
|
147
|
+
2,
|
|
148
|
+
5,
|
|
149
|
+
10,
|
|
150
|
+
20,
|
|
151
|
+
30,
|
|
152
|
+
60,
|
|
153
|
+
120,
|
|
154
|
+
300
|
|
155
|
+
];
|
|
156
|
+
const FEE_BUCKETS = Array.from({ length: 11 }, (_, i) => 10 ** (i + 8));
|
|
157
|
+
const ERROR_CLASS = /^[A-Z][A-Za-z]{0,62}Error$|^Error$/;
|
|
158
|
+
const ERROR_CODE = /^[a-z]{1,32}(_[a-z]{1,32}){0,7}$/;
|
|
159
|
+
/**
|
|
160
|
+
* `attributes` with `error.type` kept only if it is an error class name or a lower-case code, else `_OTHER`. Error
|
|
161
|
+
* names are free text (any `Error.name`), and metrics do not pass through the `redact` hook; the span keeps its own
|
|
162
|
+
* `error.type`.
|
|
163
|
+
*/
|
|
164
|
+
function withMetricErrorType(attributes) {
|
|
165
|
+
const type = attributes[ATTR_ERROR_TYPE];
|
|
166
|
+
if (type === void 0) return attributes;
|
|
167
|
+
return typeof type === "string" && (type === "_OTHER" || ERROR_CLASS.test(type) || ERROR_CODE.test(type)) ? attributes : {
|
|
168
|
+
...attributes,
|
|
169
|
+
[ATTR_ERROR_TYPE]: ERROR_TYPE_VALUE_OTHER
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/** Milliseconds since the epoch of a span time, as the OpenTelemetry API accepts it. */
|
|
173
|
+
function toEpochMs(time) {
|
|
174
|
+
if (time === void 0) return Date.now();
|
|
175
|
+
if (time instanceof Date) return time.getTime();
|
|
176
|
+
if (Array.isArray(time)) return time[0] * 1e3 + time[1] / 1e6;
|
|
177
|
+
if (typeof time !== "number") return Date.now();
|
|
178
|
+
const origin = globalThis.performance?.timeOrigin;
|
|
179
|
+
return typeof origin === "number" && time < origin ? origin + time : time;
|
|
180
|
+
}
|
|
181
|
+
function createTxMetrics(meterProvider, name, version) {
|
|
182
|
+
let histograms;
|
|
183
|
+
const get = () => {
|
|
184
|
+
histograms ??= (() => {
|
|
185
|
+
const meter = (meterProvider ?? _opentelemetry_api.metrics.getMeterProvider()).getMeter(name, version);
|
|
186
|
+
return {
|
|
187
|
+
send: meter.createHistogram(METRIC_BLOCKCHAIN_CLIENT_SEND_DURATION, {
|
|
188
|
+
unit: "s",
|
|
189
|
+
description: "Duration of sending a transaction or user operation, until its hash is known",
|
|
190
|
+
advice: { explicitBucketBoundaries: DURATION_BUCKETS }
|
|
191
|
+
}),
|
|
192
|
+
confirmation: meter.createHistogram(METRIC_BLOCKCHAIN_CLIENT_CONFIRMATION_DURATION, {
|
|
193
|
+
unit: "s",
|
|
194
|
+
description: "Duration of waiting for a transaction or user operation receipt",
|
|
195
|
+
advice: { explicitBucketBoundaries: DURATION_BUCKETS }
|
|
196
|
+
}),
|
|
197
|
+
fee: meter.createHistogram(METRIC_BLOCKCHAIN_CLIENT_FEE, {
|
|
198
|
+
unit: "{wei}",
|
|
199
|
+
description: "Total fee of a mined transaction, or the cost of a user operation",
|
|
200
|
+
advice: { explicitBucketBoundaries: FEE_BUCKETS }
|
|
201
|
+
})
|
|
202
|
+
};
|
|
203
|
+
})();
|
|
204
|
+
return histograms;
|
|
205
|
+
};
|
|
206
|
+
const record = (what, run) => {
|
|
207
|
+
try {
|
|
208
|
+
run();
|
|
209
|
+
} catch (error) {
|
|
210
|
+
_opentelemetry_api.diag.error(`hashspan: failed to record the ${what} metric`, error);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
return {
|
|
214
|
+
sendDuration: (seconds, attributes) => record("send duration", () => {
|
|
215
|
+
if (seconds >= 0) get().send.record(seconds, withMetricErrorType(attributes));
|
|
216
|
+
}),
|
|
217
|
+
confirmationDuration: (seconds, attributes) => record("confirmation duration", () => {
|
|
218
|
+
if (seconds >= 0) get().confirmation.record(seconds, withMetricErrorType(attributes));
|
|
219
|
+
}),
|
|
220
|
+
fee: (wei, attributes) => record("fee", () => {
|
|
221
|
+
if (wei >= 0n) get().fee.record(Number(wei), attributes);
|
|
222
|
+
})
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
104
226
|
//#region src/confirm-registry.ts
|
|
105
227
|
/**
|
|
106
228
|
* Bounded registry from (chainId, tx hash) to its in-flight confirm span, or to "settled" for a while after a
|
|
@@ -386,7 +508,7 @@ function sanitizeResource(resource) {
|
|
|
386
508
|
}
|
|
387
509
|
//#endregion
|
|
388
510
|
//#region src/version.ts
|
|
389
|
-
const VERSION = "0.
|
|
511
|
+
const VERSION = "0.8.0";
|
|
390
512
|
//#endregion
|
|
391
513
|
//#region src/tracker.ts
|
|
392
514
|
const INSTRUMENTATION_NAME = "@hashspan/core";
|
|
@@ -409,13 +531,20 @@ const NON_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
|
409
531
|
ATTR_BLOCKCHAIN_PAYMENT_PROTOCOL,
|
|
410
532
|
ATTR_BLOCKCHAIN_PAYMENT_STATUS,
|
|
411
533
|
ATTR_BLOCKCHAIN_PAYMENT_VERIFIED,
|
|
534
|
+
ATTR_BLOCKCHAIN_USER_OPERATION_HASH,
|
|
535
|
+
ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS,
|
|
412
536
|
ATTR_ERROR_TYPE,
|
|
413
537
|
ATTR_EXCEPTION_TYPE
|
|
414
538
|
]);
|
|
415
539
|
const TX_HASH = /^0x[0-9a-fA-F]{64}$/;
|
|
416
540
|
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
541
|
+
const ZERO_ADDRESS = /^0x0{40}$/;
|
|
417
542
|
/** A non-negative integer that fits in 256 bits. */
|
|
418
543
|
const AMOUNT = /^(0|[1-9][0-9]{0,77})$/;
|
|
544
|
+
/** A `0x` hex quantity of at most 256 bits, as JSON-RPC encodes integers. */
|
|
545
|
+
const HEX_QUANTITY = /^0x[0-9a-fA-F]{1,64}$/;
|
|
546
|
+
const MAX_UINT256 = 2n ** 256n - 1n;
|
|
547
|
+
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
|
419
548
|
/** `error.type` of a wait that gave up: a confirmation or a payment whose outcome was never learned. */
|
|
420
549
|
const OBSERVER_TIMEOUT = "timeout";
|
|
421
550
|
const PAYMENT_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -434,6 +563,11 @@ const noopSend = (parent) => ({
|
|
|
434
563
|
end: () => {},
|
|
435
564
|
fail: () => {}
|
|
436
565
|
});
|
|
566
|
+
const noopUserOperationSend = (parent) => ({
|
|
567
|
+
context: parent,
|
|
568
|
+
end: () => {},
|
|
569
|
+
fail: () => {}
|
|
570
|
+
});
|
|
437
571
|
const NOOP_PAYMENT = {
|
|
438
572
|
end: () => {},
|
|
439
573
|
fail: () => {},
|
|
@@ -445,6 +579,11 @@ const NOOP_CONFIRM = {
|
|
|
445
579
|
timeout: () => {},
|
|
446
580
|
fail: () => {}
|
|
447
581
|
};
|
|
582
|
+
const NOOP_USER_OPERATION_CONFIRM = {
|
|
583
|
+
end: () => {},
|
|
584
|
+
timeout: () => {},
|
|
585
|
+
fail: () => {}
|
|
586
|
+
};
|
|
448
587
|
/** Runs `fn`, logging instead of throwing: instrumentation must never break the caller. */
|
|
449
588
|
function safely(what, fn, fallback) {
|
|
450
589
|
try {
|
|
@@ -467,6 +606,22 @@ const ERROR_TYPE_OVERRIDE = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
|
467
606
|
function identifier(value) {
|
|
468
607
|
return typeof value === "string" && ERROR_TYPE_OVERRIDE.test(value) ? value : void 0;
|
|
469
608
|
}
|
|
609
|
+
/**
|
|
610
|
+
* A non-negative integer of at most 256 bits, from a bigint, a safe integer, or a decimal or `0x` hex string, as
|
|
611
|
+
* bundlers return them; undefined for anything else.
|
|
612
|
+
*/
|
|
613
|
+
function quantity(value) {
|
|
614
|
+
let parsed;
|
|
615
|
+
if (typeof value === "bigint") parsed = value;
|
|
616
|
+
else if (typeof value === "number" && Number.isSafeInteger(value)) parsed = BigInt(value);
|
|
617
|
+
else if (typeof value === "string" && (AMOUNT.test(value) || HEX_QUANTITY.test(value))) parsed = BigInt(value);
|
|
618
|
+
return parsed !== void 0 && parsed >= 0n && parsed <= MAX_UINT256 ? parsed : void 0;
|
|
619
|
+
}
|
|
620
|
+
/** A quantity as a number, or undefined when it is none or too large to be one exactly. */
|
|
621
|
+
function smallQuantity(value) {
|
|
622
|
+
const parsed = quantity(value);
|
|
623
|
+
return parsed !== void 0 && parsed <= MAX_SAFE_INTEGER ? Number(parsed) : void 0;
|
|
624
|
+
}
|
|
470
625
|
/** A decimal amount, or undefined when `value` is not a non-negative integer. */
|
|
471
626
|
function amount(value) {
|
|
472
627
|
const text = typeof value === "bigint" ? value.toString() : value;
|
|
@@ -512,8 +667,44 @@ function reportedErrorType(error, options) {
|
|
|
512
667
|
return errorType(error);
|
|
513
668
|
}
|
|
514
669
|
/**
|
|
670
|
+
* Joins the confirm span for `hash` in `registry`, opening it with `open` for the first handle; undefined when the
|
|
671
|
+
* key recently got a receipt. A receipt from any handle ends the span; a timeout or failure only ends it when it is the
|
|
672
|
+
* last handle still waiting.
|
|
673
|
+
*/
|
|
674
|
+
function joinConfirm(registry, chainId, hash, open) {
|
|
675
|
+
const current = registry.get(chainId, hash);
|
|
676
|
+
if (current === "settled") return void 0;
|
|
677
|
+
let confirm = current;
|
|
678
|
+
if (!confirm) {
|
|
679
|
+
confirm = open();
|
|
680
|
+
registry.start(chainId, hash, confirm);
|
|
681
|
+
}
|
|
682
|
+
const shared = confirm;
|
|
683
|
+
shared.active += 1;
|
|
684
|
+
let done = false;
|
|
685
|
+
return {
|
|
686
|
+
shared,
|
|
687
|
+
receive: () => {
|
|
688
|
+
if (done || shared.ended) return false;
|
|
689
|
+
done = true;
|
|
690
|
+
shared.active -= 1;
|
|
691
|
+
shared.ended = true;
|
|
692
|
+
return true;
|
|
693
|
+
},
|
|
694
|
+
withdraw: (end) => {
|
|
695
|
+
if (done || shared.ended) return;
|
|
696
|
+
done = true;
|
|
697
|
+
shared.active -= 1;
|
|
698
|
+
if (shared.active > 0) return;
|
|
699
|
+
shared.ended = true;
|
|
700
|
+
registry.release(chainId, hash, shared);
|
|
701
|
+
end();
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
515
706
|
* Creates a tracker that records transactions as `send` and `confirm` spans, and payments as `payment` spans, with
|
|
516
|
-
* `@opentelemetry/api` (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
707
|
+
* `@opentelemetry/api` (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/semconv.md). It makes
|
|
517
708
|
* no network calls; the caller passes hashes and receipts. Its methods and handles never throw: failures are logged
|
|
518
709
|
* via `diag`, and a method that fails returns a handle that records nothing.
|
|
519
710
|
*/
|
|
@@ -529,6 +720,27 @@ function createTxTracker(options = {}) {
|
|
|
529
720
|
const formatAddress = safely("configure address mode", () => resolveAddressFormatter(options.address), OFF_ADDRESS_FORMATTER);
|
|
530
721
|
const errorMessages = safely("configure error message mode", () => resolveErrorMessageMode(options.errorMessages), "off");
|
|
531
722
|
const paymentResource = safely("configure payment resource mode", () => resolvePaymentResourceMode(options.paymentResource), "off");
|
|
723
|
+
const userOperationLinks = new LinkStore({
|
|
724
|
+
ttlMs: options.linkTtlMs ?? DEFAULT_LINK_TTL_MS,
|
|
725
|
+
maxEntries: options.maxTrackedTransactions ?? DEFAULT_MAX_TRACKED
|
|
726
|
+
});
|
|
727
|
+
const userOperationConfirmations = new ConfirmRegistry({
|
|
728
|
+
ttlMs: options.linkTtlMs ?? DEFAULT_LINK_TTL_MS,
|
|
729
|
+
maxEntries: options.maxTrackedTransactions ?? DEFAULT_MAX_TRACKED
|
|
730
|
+
});
|
|
731
|
+
const txMetrics = createTxMetrics(options.meterProvider, INSTRUMENTATION_NAME, VERSION);
|
|
732
|
+
/** Attributes of a metric: low-cardinality only, never an address, hash or agent identity. */
|
|
733
|
+
const metricAttributes = (chainId, extra = {}) => ({
|
|
734
|
+
[ATTR_BLOCKCHAIN_SYSTEM]: "evm",
|
|
735
|
+
[ATTR_BLOCKCHAIN_CHAIN_ID]: chainId,
|
|
736
|
+
...extra
|
|
737
|
+
});
|
|
738
|
+
/** Metric attributes of a user operation sample: as for transactions, plus what the sample is about. */
|
|
739
|
+
const userOperationMetricAttributes = (chainId, extra = {}) => metricAttributes(chainId, {
|
|
740
|
+
[ATTR_BLOCKCHAIN_OPERATION_SUBJECT]: BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION,
|
|
741
|
+
...extra
|
|
742
|
+
});
|
|
743
|
+
const secondsSince = (startMs, endTime) => (toEpochMs(endTime) - startMs) / 1e3;
|
|
532
744
|
let tracer;
|
|
533
745
|
const getTracer = () => {
|
|
534
746
|
tracer ??= (options.tracerProvider ?? _opentelemetry_api.trace.getTracerProvider()).getTracer(INSTRUMENTATION_NAME, VERSION);
|
|
@@ -553,7 +765,7 @@ function createTxTracker(options = {}) {
|
|
|
553
765
|
/**
|
|
554
766
|
* Exception event attributes for `error`, per the error message mode. The error object itself is never handed to
|
|
555
767
|
* the SDK: its message and stack can carry addresses and calldata
|
|
556
|
-
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
768
|
+
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/adr/0006-error-privacy.md).
|
|
557
769
|
*/
|
|
558
770
|
const exceptionAttributes = (type, error) => {
|
|
559
771
|
const attributes = { [ATTR_EXCEPTION_TYPE]: type };
|
|
@@ -586,6 +798,7 @@ function createTxTracker(options = {}) {
|
|
|
586
798
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
587
799
|
...message !== void 0 ? { message } : {}
|
|
588
800
|
});
|
|
801
|
+
return type;
|
|
589
802
|
};
|
|
590
803
|
/** Ends a span exactly once; the span is always ended even if recording attributes fails. */
|
|
591
804
|
const finisher = (span) => {
|
|
@@ -607,8 +820,8 @@ function createTxTracker(options = {}) {
|
|
|
607
820
|
const formatted = formatAddress(address);
|
|
608
821
|
if (formatted !== void 0) attributes[key] = formatted;
|
|
609
822
|
};
|
|
610
|
-
/** Records `address` only if it is one: payment addresses come from remote parties. */
|
|
611
|
-
const
|
|
823
|
+
/** Records `address` only if it is one: payment and user operation addresses come from remote parties. */
|
|
824
|
+
const setRemoteAddress = (attributes, key, address) => {
|
|
612
825
|
if (typeof address === "string" && ADDRESS.test(address)) setAddress(attributes, key, address);
|
|
613
826
|
};
|
|
614
827
|
const baseAttributes = (chainId, operation, ctx) => ({
|
|
@@ -637,6 +850,8 @@ function createTxTracker(options = {}) {
|
|
|
637
850
|
...input.startTime !== void 0 ? { startTime: input.startTime } : {}
|
|
638
851
|
}, parent);
|
|
639
852
|
const finish = finisher(span);
|
|
853
|
+
const startMs = toEpochMs(input.startTime);
|
|
854
|
+
const recordSend = (endTime, errorType) => txMetrics.sendDuration(secondsSince(startMs, endTime), metricAttributes(input.chainId, errorType === void 0 ? {} : { [ATTR_ERROR_TYPE]: errorType }));
|
|
640
855
|
return {
|
|
641
856
|
context: _opentelemetry_api.trace.setSpan(parent, span),
|
|
642
857
|
end: (result, second) => finish("record transaction hash", () => {
|
|
@@ -650,10 +865,11 @@ function createTxTracker(options = {}) {
|
|
|
650
865
|
parent
|
|
651
866
|
});
|
|
652
867
|
span.setAttributes(redact({ [ATTR_BLOCKCHAIN_TX_HASH]: hash }));
|
|
868
|
+
recordSend(handleOptions(second).endTime);
|
|
653
869
|
}, handleOptions(second).endTime),
|
|
654
870
|
fail: (error, second, third) => {
|
|
655
871
|
const options = handleOptions(second, third);
|
|
656
|
-
finish("record send failure", () => markError(span, reportedErrorType(error, options), error, errorType(error)), options.endTime);
|
|
872
|
+
finish("record send failure", () => recordSend(options.endTime, markError(span, reportedErrorType(error, options), error, errorType(error))), options.endTime);
|
|
657
873
|
}
|
|
658
874
|
};
|
|
659
875
|
};
|
|
@@ -689,6 +905,8 @@ function createTxTracker(options = {}) {
|
|
|
689
905
|
...explicitStart !== void 0 ? { startTime: explicitStart } : {}
|
|
690
906
|
}, parent);
|
|
691
907
|
const finish = finisher(span);
|
|
908
|
+
const startMs = toEpochMs(explicitStart);
|
|
909
|
+
const recordConfirmation = (endTime, outcome) => txMetrics.confirmationDuration(secondsSince(startMs, endTime), metricAttributes(input.chainId, outcome));
|
|
692
910
|
return {
|
|
693
911
|
active: 0,
|
|
694
912
|
ended: false,
|
|
@@ -698,11 +916,16 @@ function createTxTracker(options = {}) {
|
|
|
698
916
|
links: [{ context: span.spanContext() }, ...sent ? [{ context: sent.spanContext }] : []]
|
|
699
917
|
},
|
|
700
918
|
receipt: (receipt, endTime) => finish("record receipt", () => {
|
|
701
|
-
|
|
919
|
+
const attributes = receiptAttributes(receipt);
|
|
920
|
+
span.setAttributes(redact(attributes));
|
|
702
921
|
if (receipt.status === "reverted") markError(span, BLOCKCHAIN_TX_STATUS_VALUE_REVERTED);
|
|
922
|
+
const status = { [ATTR_BLOCKCHAIN_TX_STATUS]: attributes[ATTR_BLOCKCHAIN_TX_STATUS] };
|
|
923
|
+
recordConfirmation(endTime, status);
|
|
924
|
+
const fee = attributes[ATTR_BLOCKCHAIN_TX_FEE];
|
|
925
|
+
if (typeof fee === "string") txMetrics.fee(BigInt(fee), metricAttributes(input.chainId, status));
|
|
703
926
|
}, endTime),
|
|
704
|
-
timeout: (endTime) => finish("record confirmation timeout", () => markError(span, OBSERVER_TIMEOUT), endTime),
|
|
705
|
-
fail: (error, endTime) => finish("record confirmation failure", () => markError(span, errorType(error), error), endTime),
|
|
927
|
+
timeout: (endTime) => finish("record confirmation timeout", () => recordConfirmation(endTime, { [ATTR_ERROR_TYPE]: markError(span, OBSERVER_TIMEOUT) }), endTime),
|
|
928
|
+
fail: (error, endTime) => finish("record confirmation failure", () => recordConfirmation(endTime, { [ATTR_ERROR_TYPE]: markError(span, errorType(error), error) }), endTime),
|
|
706
929
|
replaced: (hash, reason, endTime) => finish("record replacement", () => {
|
|
707
930
|
const attributes = {
|
|
708
931
|
[ATTR_BLOCKCHAIN_TX_STATUS]: BLOCKCHAIN_TX_STATUS_VALUE_REPLACED,
|
|
@@ -710,8 +933,9 @@ function createTxTracker(options = {}) {
|
|
|
710
933
|
};
|
|
711
934
|
if (reason !== void 0 && REPLACEMENT_REASONS.has(reason)) attributes[ATTR_BLOCKCHAIN_TX_REPLACEMENT_REASON] = reason;
|
|
712
935
|
span.setAttributes(redact(attributes));
|
|
936
|
+
recordConfirmation(endTime, { [ATTR_BLOCKCHAIN_TX_STATUS]: BLOCKCHAIN_TX_STATUS_VALUE_REPLACED });
|
|
713
937
|
}, endTime),
|
|
714
|
-
unattributable: (endTime) => finish("record unattributable receipt", () => markError(span, ERROR_TYPE_VALUE_OTHER), endTime)
|
|
938
|
+
unattributable: (endTime) => finish("record unattributable receipt", () => recordConfirmation(endTime, { [ATTR_ERROR_TYPE]: markError(span, ERROR_TYPE_VALUE_OTHER) }), endTime)
|
|
715
939
|
};
|
|
716
940
|
};
|
|
717
941
|
/**
|
|
@@ -733,7 +957,7 @@ function createTxTracker(options = {}) {
|
|
|
733
957
|
};
|
|
734
958
|
/**
|
|
735
959
|
* Ends `shared` with `receipt`, attributing it to the transaction that was mined
|
|
736
|
-
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.
|
|
960
|
+
* (https://github.com/selimaytac/hashspan/blob/@hashspan/core@0.8.0/docs/adr/0008-replaced-transactions.md).
|
|
737
961
|
*/
|
|
738
962
|
const endWithReceipt = (chainId, hash, shared, receipt, endTime) => {
|
|
739
963
|
const mined = receipt.transactionHash;
|
|
@@ -763,41 +987,22 @@ function createTxTracker(options = {}) {
|
|
|
763
987
|
*/
|
|
764
988
|
const startConfirm = (input, parentCtx) => {
|
|
765
989
|
const { chainId, hash } = input;
|
|
766
|
-
const
|
|
767
|
-
if (
|
|
768
|
-
|
|
769
|
-
if (!confirm) {
|
|
770
|
-
confirm = openConfirm(input, parentCtx);
|
|
771
|
-
confirmations.start(chainId, hash, confirm);
|
|
772
|
-
}
|
|
773
|
-
const shared = confirm;
|
|
774
|
-
shared.active += 1;
|
|
775
|
-
let done = false;
|
|
776
|
-
const withdraw = (end) => {
|
|
777
|
-
if (done || shared.ended) return;
|
|
778
|
-
done = true;
|
|
779
|
-
shared.active -= 1;
|
|
780
|
-
if (shared.active > 0) return;
|
|
781
|
-
shared.ended = true;
|
|
782
|
-
confirmations.release(chainId, hash, shared);
|
|
783
|
-
end();
|
|
784
|
-
};
|
|
990
|
+
const claim = joinConfirm(confirmations, chainId, hash, () => openConfirm(input, parentCtx));
|
|
991
|
+
if (!claim) return NOOP_CONFIRM;
|
|
992
|
+
const { shared } = claim;
|
|
785
993
|
return {
|
|
786
994
|
end: (receipt, second) => {
|
|
787
995
|
const { endTime } = handleOptions(second);
|
|
788
|
-
if (
|
|
789
|
-
done = true;
|
|
790
|
-
shared.active -= 1;
|
|
791
|
-
shared.ended = true;
|
|
996
|
+
if (!claim.receive()) return;
|
|
792
997
|
safely("record receipt", () => endWithReceipt(chainId, hash, shared, receipt, endTime), void 0);
|
|
793
998
|
},
|
|
794
999
|
timeout: (second) => {
|
|
795
1000
|
const { endTime } = handleOptions(second);
|
|
796
|
-
withdraw(() => shared.timeout(endTime));
|
|
1001
|
+
claim.withdraw(() => shared.timeout(endTime));
|
|
797
1002
|
},
|
|
798
1003
|
fail: (error, second) => {
|
|
799
1004
|
const { endTime } = handleOptions(second);
|
|
800
|
-
withdraw(() => shared.fail(error, endTime));
|
|
1005
|
+
claim.withdraw(() => shared.fail(error, endTime));
|
|
801
1006
|
}
|
|
802
1007
|
};
|
|
803
1008
|
};
|
|
@@ -806,10 +1011,10 @@ function createTxTracker(options = {}) {
|
|
|
806
1011
|
const attributes = baseAttributes(input.chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_PAYMENT, parent);
|
|
807
1012
|
const protocol = identifier(input.protocol);
|
|
808
1013
|
if (protocol !== void 0) attributes[ATTR_BLOCKCHAIN_PAYMENT_PROTOCOL] = protocol;
|
|
809
|
-
|
|
1014
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_PAYMENT_PAYER, input.payer);
|
|
810
1015
|
const knownPayer = typeof input.payer === "string" && ADDRESS.test(input.payer);
|
|
811
|
-
|
|
812
|
-
|
|
1016
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_PAYMENT_RECIPIENT, input.recipient);
|
|
1017
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_PAYMENT_ASSET, input.asset);
|
|
813
1018
|
const paid = amount(input.amount);
|
|
814
1019
|
if (paid !== void 0) attributes[ATTR_BLOCKCHAIN_PAYMENT_AMOUNT] = paid;
|
|
815
1020
|
const scheme = identifier(input.x402?.scheme);
|
|
@@ -841,7 +1046,7 @@ function createTxTracker(options = {}) {
|
|
|
841
1046
|
const settled = { [ATTR_BLOCKCHAIN_PAYMENT_STATUS]: status };
|
|
842
1047
|
const hash = settlement.hash;
|
|
843
1048
|
if (linkHash(hash)) settled[ATTR_BLOCKCHAIN_TX_HASH] = hash;
|
|
844
|
-
if (!knownPayer)
|
|
1049
|
+
if (!knownPayer) setRemoteAddress(settled, ATTR_BLOCKCHAIN_PAYMENT_PAYER, settlement.payer);
|
|
845
1050
|
const settledAmount = amount(settlement.amount);
|
|
846
1051
|
if (settledAmount !== void 0) {
|
|
847
1052
|
settled[ATTR_BLOCKCHAIN_PAYMENT_SETTLED_AMOUNT] = settledAmount;
|
|
@@ -862,10 +1067,138 @@ function createTxTracker(options = {}) {
|
|
|
862
1067
|
link: (hash) => safely("link the payment span", () => void linkHash(hash), void 0)
|
|
863
1068
|
};
|
|
864
1069
|
};
|
|
1070
|
+
const startUserOperationSend = (input, parentCtx) => {
|
|
1071
|
+
const parent = parentCtx ?? _opentelemetry_api.context.active();
|
|
1072
|
+
const { chainId } = input;
|
|
1073
|
+
const attributes = baseAttributes(chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_SEND, parent);
|
|
1074
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_SENDER, input.sender);
|
|
1075
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT, input.entryPoint);
|
|
1076
|
+
const callCount = smallQuantity(input.callCount);
|
|
1077
|
+
if (callCount !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT] = callCount;
|
|
1078
|
+
const span = getTracer().startSpan(`send ${chainId}`, {
|
|
1079
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
1080
|
+
attributes: redact(attributes),
|
|
1081
|
+
...input.startTime !== void 0 ? { startTime: input.startTime } : {}
|
|
1082
|
+
}, parent);
|
|
1083
|
+
const finish = finisher(span);
|
|
1084
|
+
const startMs = toEpochMs(input.startTime);
|
|
1085
|
+
const recordSend = (endTime, errorType) => txMetrics.sendDuration(secondsSince(startMs, endTime), userOperationMetricAttributes(chainId, errorType === void 0 ? {} : { [ATTR_ERROR_TYPE]: errorType }));
|
|
1086
|
+
return {
|
|
1087
|
+
context: _opentelemetry_api.trace.setSpan(parent, span),
|
|
1088
|
+
end: (result, second) => {
|
|
1089
|
+
const { endTime } = handleOptions(second);
|
|
1090
|
+
finish("record user operation hash", () => {
|
|
1091
|
+
const hash = result?.userOpHash;
|
|
1092
|
+
if (typeof hash !== "string" || !TX_HASH.test(hash)) {
|
|
1093
|
+
_opentelemetry_api.diag.debug("hashspan: ending a send span without a valid user operation hash");
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
userOperationLinks.set(chainId, hash, {
|
|
1097
|
+
spanContext: span.spanContext(),
|
|
1098
|
+
parent
|
|
1099
|
+
});
|
|
1100
|
+
span.setAttributes(redact({ [ATTR_BLOCKCHAIN_USER_OPERATION_HASH]: hash }));
|
|
1101
|
+
recordSend(endTime);
|
|
1102
|
+
}, endTime);
|
|
1103
|
+
},
|
|
1104
|
+
fail: (error, second) => {
|
|
1105
|
+
const read = handleOptions(second);
|
|
1106
|
+
finish("record user operation send failure", () => recordSend(read.endTime, markError(span, reportedErrorType(error, read), error, errorType(error))), read.endTime);
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
};
|
|
1110
|
+
/**
|
|
1111
|
+
* Attributes of a user operation receipt. Its values come from a bundler: what is malformed is left out. The bundle
|
|
1112
|
+
* transaction's status, gas and fee are not recorded: they cover every operation in the bundle (ADR 0021).
|
|
1113
|
+
*/
|
|
1114
|
+
const userOperationReceiptAttributes = (receipt) => {
|
|
1115
|
+
const attributes = {};
|
|
1116
|
+
const success = receipt.success;
|
|
1117
|
+
if (typeof success === "boolean") attributes[ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS] = success;
|
|
1118
|
+
const gasUsed = smallQuantity(receipt.actualGasUsed);
|
|
1119
|
+
if (gasUsed !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED] = gasUsed;
|
|
1120
|
+
const gasCost = quantity(receipt.actualGasCost);
|
|
1121
|
+
if (gasCost !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST] = gasCost.toString();
|
|
1122
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_SENDER, receipt.sender);
|
|
1123
|
+
const nonce = quantity(receipt.nonce);
|
|
1124
|
+
if (nonce !== void 0) attributes[ATTR_BLOCKCHAIN_USER_OPERATION_NONCE] = nonce.toString();
|
|
1125
|
+
const paymaster = receipt.paymaster;
|
|
1126
|
+
if (typeof paymaster === "string" && !ZERO_ADDRESS.test(paymaster)) setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER, paymaster);
|
|
1127
|
+
setRemoteAddress(attributes, ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT, receipt.entryPoint);
|
|
1128
|
+
const reason = receipt.revertReason;
|
|
1129
|
+
if (typeof reason === "string") attributes[ATTR_BLOCKCHAIN_TX_REVERT_REASON] = formatAddressesIn(reason, formatAddress);
|
|
1130
|
+
const bundle = receipt.transactionHash;
|
|
1131
|
+
if (typeof bundle === "string" && TX_HASH.test(bundle)) attributes[ATTR_BLOCKCHAIN_TX_HASH] = bundle;
|
|
1132
|
+
const block = smallQuantity(receipt.blockNumber);
|
|
1133
|
+
if (block !== void 0) attributes[ATTR_BLOCKCHAIN_BLOCK_NUMBER] = block;
|
|
1134
|
+
return attributes;
|
|
1135
|
+
};
|
|
1136
|
+
/** Opens the confirm span of a user operation. */
|
|
1137
|
+
const openUserOperationConfirm = (input, parentCtx) => {
|
|
1138
|
+
const { chainId, userOpHash } = input;
|
|
1139
|
+
const sent = userOperationLinks.get(chainId, userOpHash);
|
|
1140
|
+
const active = _opentelemetry_api.context.active();
|
|
1141
|
+
const parent = parentCtx ?? (_opentelemetry_api.trace.getSpan(active) ? active : sent?.parent ?? active);
|
|
1142
|
+
const attributes = baseAttributes(chainId, BLOCKCHAIN_OPERATION_NAME_VALUE_CONFIRM, parent);
|
|
1143
|
+
attributes[ATTR_BLOCKCHAIN_USER_OPERATION_HASH] = userOpHash;
|
|
1144
|
+
const span = getTracer().startSpan(`confirm ${chainId}`, {
|
|
1145
|
+
kind: _opentelemetry_api.SpanKind.CLIENT,
|
|
1146
|
+
attributes: redact(attributes),
|
|
1147
|
+
links: sent ? [{ context: sent.spanContext }] : [],
|
|
1148
|
+
...input.startTime !== void 0 ? { startTime: input.startTime } : {}
|
|
1149
|
+
}, parent);
|
|
1150
|
+
const finish = finisher(span);
|
|
1151
|
+
const startMs = toEpochMs(input.startTime);
|
|
1152
|
+
const recordConfirmation = (endTime, outcome) => txMetrics.confirmationDuration(secondsSince(startMs, endTime), userOperationMetricAttributes(chainId, outcome));
|
|
1153
|
+
return {
|
|
1154
|
+
active: 0,
|
|
1155
|
+
ended: false,
|
|
1156
|
+
receipt: (receipt, endTime) => finish("record user operation receipt", () => {
|
|
1157
|
+
const attributes = userOperationReceiptAttributes(receipt ?? {});
|
|
1158
|
+
span.setAttributes(redact(attributes));
|
|
1159
|
+
const success = attributes[ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS];
|
|
1160
|
+
if (success === false) markError(span, BLOCKCHAIN_TX_STATUS_VALUE_REVERTED);
|
|
1161
|
+
const outcome = typeof success === "boolean" ? { [ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS]: success } : {};
|
|
1162
|
+
recordConfirmation(endTime, outcome);
|
|
1163
|
+
const cost = attributes[ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST];
|
|
1164
|
+
if (typeof cost === "string") txMetrics.fee(BigInt(cost), userOperationMetricAttributes(chainId, outcome));
|
|
1165
|
+
}, endTime),
|
|
1166
|
+
timeout: (endTime) => finish("record user operation confirmation timeout", () => recordConfirmation(endTime, { [ATTR_ERROR_TYPE]: markError(span, OBSERVER_TIMEOUT) }), endTime),
|
|
1167
|
+
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)
|
|
1168
|
+
};
|
|
1169
|
+
};
|
|
1170
|
+
const startUserOperationConfirm = (input, parentCtx) => {
|
|
1171
|
+
const { chainId, userOpHash } = input;
|
|
1172
|
+
if (typeof userOpHash !== "string" || !TX_HASH.test(userOpHash)) {
|
|
1173
|
+
_opentelemetry_api.diag.debug("hashspan: not confirming a user operation without a valid hash");
|
|
1174
|
+
return NOOP_USER_OPERATION_CONFIRM;
|
|
1175
|
+
}
|
|
1176
|
+
const claim = joinConfirm(userOperationConfirmations, chainId, userOpHash, () => openUserOperationConfirm(input, parentCtx));
|
|
1177
|
+
if (!claim) return NOOP_USER_OPERATION_CONFIRM;
|
|
1178
|
+
const { shared } = claim;
|
|
1179
|
+
return {
|
|
1180
|
+
end: (receipt, second) => {
|
|
1181
|
+
const { endTime } = handleOptions(second);
|
|
1182
|
+
if (!claim.receive()) return;
|
|
1183
|
+
userOperationConfirmations.settle(chainId, userOpHash, shared);
|
|
1184
|
+
shared.receipt(receipt, endTime);
|
|
1185
|
+
},
|
|
1186
|
+
timeout: (second) => {
|
|
1187
|
+
const { endTime } = handleOptions(second);
|
|
1188
|
+
claim.withdraw(() => shared.timeout(endTime));
|
|
1189
|
+
},
|
|
1190
|
+
fail: (error, second) => {
|
|
1191
|
+
const read = handleOptions(second);
|
|
1192
|
+
claim.withdraw(() => shared.fail(error, read));
|
|
1193
|
+
}
|
|
1194
|
+
};
|
|
1195
|
+
};
|
|
865
1196
|
return {
|
|
866
1197
|
startSend: (input, parent) => safely("start send span", () => startSend(input, parent), noopSend(parent ?? _opentelemetry_api.context.active())),
|
|
867
1198
|
startConfirm: (input, parent) => safely("start confirm span", () => startConfirm(input, parent), NOOP_CONFIRM),
|
|
868
|
-
startPayment: (input, parent) => safely("start payment span", () => startPayment(input, parent), NOOP_PAYMENT)
|
|
1199
|
+
startPayment: (input, parent) => safely("start payment span", () => startPayment(input, parent), NOOP_PAYMENT),
|
|
1200
|
+
startUserOperationSend: (input, parent) => safely("start user operation send span", () => startUserOperationSend(input, parent), noopUserOperationSend(parent ?? _opentelemetry_api.context.active())),
|
|
1201
|
+
startUserOperationConfirm: (input, parent) => safely("start user operation confirm span", () => startUserOperationConfirm(input, parent), NOOP_USER_OPERATION_CONFIRM)
|
|
869
1202
|
};
|
|
870
1203
|
}
|
|
871
1204
|
//#endregion
|
|
@@ -875,6 +1208,7 @@ exports.ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_ARGUMENTS = ATTR_BLOCKCHAIN_CONTRACT_F
|
|
|
875
1208
|
exports.ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_NAME = ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_NAME;
|
|
876
1209
|
exports.ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_SELECTOR = ATTR_BLOCKCHAIN_CONTRACT_FUNCTION_SELECTOR;
|
|
877
1210
|
exports.ATTR_BLOCKCHAIN_OPERATION_NAME = ATTR_BLOCKCHAIN_OPERATION_NAME;
|
|
1211
|
+
exports.ATTR_BLOCKCHAIN_OPERATION_SUBJECT = ATTR_BLOCKCHAIN_OPERATION_SUBJECT;
|
|
878
1212
|
exports.ATTR_BLOCKCHAIN_PAYMENT_AMOUNT = ATTR_BLOCKCHAIN_PAYMENT_AMOUNT;
|
|
879
1213
|
exports.ATTR_BLOCKCHAIN_PAYMENT_ASSET = ATTR_BLOCKCHAIN_PAYMENT_ASSET;
|
|
880
1214
|
exports.ATTR_BLOCKCHAIN_PAYMENT_PAYER = ATTR_BLOCKCHAIN_PAYMENT_PAYER;
|
|
@@ -897,6 +1231,15 @@ exports.ATTR_BLOCKCHAIN_TX_REVERT_REASON = ATTR_BLOCKCHAIN_TX_REVERT_REASON;
|
|
|
897
1231
|
exports.ATTR_BLOCKCHAIN_TX_STATUS = ATTR_BLOCKCHAIN_TX_STATUS;
|
|
898
1232
|
exports.ATTR_BLOCKCHAIN_TX_TO = ATTR_BLOCKCHAIN_TX_TO;
|
|
899
1233
|
exports.ATTR_BLOCKCHAIN_TX_VALUE = ATTR_BLOCKCHAIN_TX_VALUE;
|
|
1234
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT = ATTR_BLOCKCHAIN_USER_OPERATION_CALL_COUNT;
|
|
1235
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT = ATTR_BLOCKCHAIN_USER_OPERATION_ENTRY_POINT;
|
|
1236
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST = ATTR_BLOCKCHAIN_USER_OPERATION_GAS_COST;
|
|
1237
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED = ATTR_BLOCKCHAIN_USER_OPERATION_GAS_USED;
|
|
1238
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_HASH = ATTR_BLOCKCHAIN_USER_OPERATION_HASH;
|
|
1239
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_NONCE = ATTR_BLOCKCHAIN_USER_OPERATION_NONCE;
|
|
1240
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER = ATTR_BLOCKCHAIN_USER_OPERATION_PAYMASTER;
|
|
1241
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_SENDER = ATTR_BLOCKCHAIN_USER_OPERATION_SENDER;
|
|
1242
|
+
exports.ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS = ATTR_BLOCKCHAIN_USER_OPERATION_SUCCESS;
|
|
900
1243
|
exports.ATTR_ERROR_TYPE = ATTR_ERROR_TYPE;
|
|
901
1244
|
exports.ATTR_GEN_AI_AGENT_ID = ATTR_GEN_AI_AGENT_ID;
|
|
902
1245
|
exports.ATTR_GEN_AI_AGENT_NAME = ATTR_GEN_AI_AGENT_NAME;
|
|
@@ -905,6 +1248,7 @@ exports.ATTR_X402_SCHEME = ATTR_X402_SCHEME;
|
|
|
905
1248
|
exports.BLOCKCHAIN_OPERATION_NAME_VALUE_CONFIRM = BLOCKCHAIN_OPERATION_NAME_VALUE_CONFIRM;
|
|
906
1249
|
exports.BLOCKCHAIN_OPERATION_NAME_VALUE_PAYMENT = BLOCKCHAIN_OPERATION_NAME_VALUE_PAYMENT;
|
|
907
1250
|
exports.BLOCKCHAIN_OPERATION_NAME_VALUE_SEND = BLOCKCHAIN_OPERATION_NAME_VALUE_SEND;
|
|
1251
|
+
exports.BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION = BLOCKCHAIN_OPERATION_SUBJECT_VALUE_USER_OPERATION;
|
|
908
1252
|
exports.BLOCKCHAIN_PAYMENT_PROTOCOL_VALUE_X402 = BLOCKCHAIN_PAYMENT_PROTOCOL_VALUE_X402;
|
|
909
1253
|
exports.BLOCKCHAIN_PAYMENT_STATUS_VALUE_FAILED = BLOCKCHAIN_PAYMENT_STATUS_VALUE_FAILED;
|
|
910
1254
|
exports.BLOCKCHAIN_PAYMENT_STATUS_VALUE_PENDING = BLOCKCHAIN_PAYMENT_STATUS_VALUE_PENDING;
|
|
@@ -918,5 +1262,8 @@ exports.BLOCKCHAIN_TX_STATUS_VALUE_REVERTED = BLOCKCHAIN_TX_STATUS_VALUE_REVERTE
|
|
|
918
1262
|
exports.BLOCKCHAIN_TX_STATUS_VALUE_SUCCESS = BLOCKCHAIN_TX_STATUS_VALUE_SUCCESS;
|
|
919
1263
|
exports.BLOCKCHAIN_TX_STATUS_VALUE_TIMEOUT = BLOCKCHAIN_TX_STATUS_VALUE_TIMEOUT;
|
|
920
1264
|
exports.ERROR_TYPE_VALUE_OTHER = ERROR_TYPE_VALUE_OTHER;
|
|
1265
|
+
exports.METRIC_BLOCKCHAIN_CLIENT_CONFIRMATION_DURATION = METRIC_BLOCKCHAIN_CLIENT_CONFIRMATION_DURATION;
|
|
1266
|
+
exports.METRIC_BLOCKCHAIN_CLIENT_FEE = METRIC_BLOCKCHAIN_CLIENT_FEE;
|
|
1267
|
+
exports.METRIC_BLOCKCHAIN_CLIENT_SEND_DURATION = METRIC_BLOCKCHAIN_CLIENT_SEND_DURATION;
|
|
921
1268
|
exports.VERSION = VERSION;
|
|
922
1269
|
exports.createTxTracker = createTxTracker;
|