@formo/analytics 1.36.0 → 1.38.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/dist/cjs/src/FormoAnalytics.d.ts +64 -0
- package/dist/cjs/src/FormoAnalytics.js +155 -5
- package/dist/cjs/src/FormoAnalyticsProvider.js +1 -0
- package/dist/cjs/src/evm/EvmEventTracker.d.ts +38 -10
- package/dist/cjs/src/evm/EvmEventTracker.js +182 -0
- package/dist/cjs/src/evm/EvmProviderRegistry.js +26 -4
- package/dist/cjs/src/evm/EvmRequestTracker.d.ts +36 -40
- package/dist/cjs/src/evm/EvmRequestTracker.js +216 -115
- package/dist/cjs/src/evm/batch.d.ts +94 -0
- package/dist/cjs/src/evm/batch.js +130 -0
- package/dist/cjs/src/provider/detection.d.ts +30 -0
- package/dist/cjs/src/provider/detection.js +62 -0
- package/dist/cjs/src/provider/index.d.ts +1 -1
- package/dist/cjs/src/provider/index.js +3 -1
- package/dist/cjs/src/types/base.d.ts +23 -0
- package/dist/cjs/src/types/provider.d.ts +16 -0
- package/dist/cjs/src/types/provider.js +17 -1
- package/dist/cjs/src/version.d.ts +1 -1
- package/dist/cjs/src/version.js +1 -1
- package/dist/cjs/src/wagmi/WagmiEventHandler.d.ts +87 -0
- package/dist/cjs/src/wagmi/WagmiEventHandler.js +536 -13
- package/dist/esm/src/FormoAnalytics.d.ts +64 -0
- package/dist/esm/src/FormoAnalytics.js +155 -5
- package/dist/esm/src/FormoAnalyticsProvider.js +1 -0
- package/dist/esm/src/evm/EvmEventTracker.d.ts +38 -10
- package/dist/esm/src/evm/EvmEventTracker.js +183 -1
- package/dist/esm/src/evm/EvmProviderRegistry.js +27 -5
- package/dist/esm/src/evm/EvmRequestTracker.d.ts +36 -40
- package/dist/esm/src/evm/EvmRequestTracker.js +215 -114
- package/dist/esm/src/evm/batch.d.ts +94 -0
- package/dist/esm/src/evm/batch.js +123 -0
- package/dist/esm/src/provider/detection.d.ts +30 -0
- package/dist/esm/src/provider/detection.js +60 -0
- package/dist/esm/src/provider/index.d.ts +1 -1
- package/dist/esm/src/provider/index.js +1 -1
- package/dist/esm/src/types/base.d.ts +23 -0
- package/dist/esm/src/types/provider.d.ts +16 -0
- package/dist/esm/src/types/provider.js +16 -0
- package/dist/esm/src/version.d.ts +1 -1
- package/dist/esm/src/version.js +1 -1
- package/dist/esm/src/wagmi/WagmiEventHandler.d.ts +87 -0
- package/dist/esm/src/wagmi/WagmiEventHandler.js +536 -13
- package/dist/index.umd.min.js +1 -1
- package/package.json +4 -3
|
@@ -56,10 +56,21 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
56
56
|
}
|
|
57
57
|
return t;
|
|
58
58
|
};
|
|
59
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
60
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
61
|
+
if (ar || !(i in from)) {
|
|
62
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
63
|
+
ar[i] = from[i];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
67
|
+
};
|
|
59
68
|
import { logger } from "../logger";
|
|
69
|
+
import { isUserRejectionError } from "../provider";
|
|
60
70
|
import { parseChainId } from "../utils/chain";
|
|
61
71
|
import { validateAndChecksumAddress } from "../utils/address";
|
|
62
|
-
import { SignatureStatus, TransactionStatus, WRAPPED_REQUEST_SYMBOL, WRAPPED_REQUEST_REF_SYMBOL, } from "../types";
|
|
72
|
+
import { SignatureStatus, TransactionStatus, WRAPPED_REQUEST_SYMBOL, WRAPPED_REQUEST_REF_SYMBOL, WRAPPED_REQUEST_OWNER_SYMBOL, } from "../types";
|
|
73
|
+
import { readBatchId, readBatchStatusCode, batchCallOutcome, batchReceiptForCall, } from "./batch";
|
|
63
74
|
/**
|
|
64
75
|
* Decode a hex-encoded `personal_sign` message.
|
|
65
76
|
*
|
|
@@ -96,6 +107,19 @@ function hexToUtf8(hex) {
|
|
|
96
107
|
* probed - an SDK-issued lookup on a serialising transport can wedge the
|
|
97
108
|
* user's wallet, which is never an acceptable price for a label.
|
|
98
109
|
*/
|
|
110
|
+
/**
|
|
111
|
+
* Providers with a dispatch already on the synchronous call stack.
|
|
112
|
+
*
|
|
113
|
+
* A page can end up with LAYERED Formo wrappers: another library wraps our
|
|
114
|
+
* wrapper, the SDK rebuilds, and the new instance wraps the outer function
|
|
115
|
+
* because the marker is not on it. Both layers route to the same newest
|
|
116
|
+
* live tracker, which would instrument one user request twice. Every
|
|
117
|
+
* dispatch issues its underlying request synchronously (deliberately -
|
|
118
|
+
* the wallet call always goes out first), so an inner shim reached during
|
|
119
|
+
* that window belongs to the SAME user request and passes straight
|
|
120
|
+
* through.
|
|
121
|
+
*/
|
|
122
|
+
var dispatchInFlight = new WeakSet();
|
|
99
123
|
var EvmRequestTracker = /** @class */ (function () {
|
|
100
124
|
function EvmRequestTracker(wallet, registry, deps) {
|
|
101
125
|
this.wallet = wallet;
|
|
@@ -111,12 +135,28 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
111
135
|
*/
|
|
112
136
|
this.polls = new Set();
|
|
113
137
|
this.disposed = false;
|
|
138
|
+
/** Providers whose owner list includes this instance; pruned on cleanup. */
|
|
139
|
+
this.wrappedProviders = new Set();
|
|
114
140
|
}
|
|
115
141
|
/** Stop every poll in flight. Terminal, like the event queue's close(). */
|
|
116
142
|
EvmRequestTracker.prototype.cleanup = function () {
|
|
143
|
+
var _this = this;
|
|
117
144
|
this.disposed = true;
|
|
118
145
|
this.polls.forEach(function (timer) { return clearTimeout(timer); });
|
|
119
146
|
this.polls.clear();
|
|
147
|
+
// Remove this instance from every provider's owner list. The lists
|
|
148
|
+
// live on LONG-LIVED provider objects; leaving disposed trackers in
|
|
149
|
+
// them retains each old instance's whole object graph across rebuilds,
|
|
150
|
+
// growing without bound under HMR.
|
|
151
|
+
this.wrappedProviders.forEach(function (provider) {
|
|
152
|
+
var owners = provider[WRAPPED_REQUEST_OWNER_SYMBOL];
|
|
153
|
+
if (Array.isArray(owners)) {
|
|
154
|
+
var idx = owners.indexOf(_this);
|
|
155
|
+
if (idx !== -1)
|
|
156
|
+
owners.splice(idx, 1);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
this.wrappedProviders.clear();
|
|
120
160
|
};
|
|
121
161
|
/** Re-arm a poll, unless this tracker has been torn down. */
|
|
122
162
|
EvmRequestTracker.prototype.schedulePoll = function (fn, delayMs) {
|
|
@@ -142,19 +182,118 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
142
182
|
logger.error("Provider not found for request (signature, transaction) tracking");
|
|
143
183
|
return false;
|
|
144
184
|
}
|
|
145
|
-
//
|
|
185
|
+
// Already wrapped: take OWNERSHIP rather than skipping. The wrapper
|
|
186
|
+
// survives an SDK rebuild and closes over the instance that installed
|
|
187
|
+
// it, whose queue is closed after cleanup - "skip" made the rebuilt
|
|
188
|
+
// instance report success while every request-derived event died in
|
|
189
|
+
// the dead instance's queue. The wrapper reads the owner slot per call.
|
|
146
190
|
var currentRequest = provider.request;
|
|
147
191
|
if (this.registry.isWrapped(provider, currentRequest)) {
|
|
148
|
-
|
|
192
|
+
var owners = provider[WRAPPED_REQUEST_OWNER_SYMBOL];
|
|
193
|
+
if (!Array.isArray(owners)) {
|
|
194
|
+
// A wrapper without its owner list cannot be taken over, and
|
|
195
|
+
// claiming success would silence every request event.
|
|
196
|
+
logger.warn("wrapped without owner list; cannot rebind");
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
var idx = owners.indexOf(this);
|
|
200
|
+
if (idx !== -1)
|
|
201
|
+
owners.splice(idx, 1);
|
|
202
|
+
owners.push(this);
|
|
203
|
+
this.wrappedProviders.add(provider);
|
|
204
|
+
logger.info("Provider already wrapped; rebinding the wrapper to this instance.");
|
|
149
205
|
return true;
|
|
150
206
|
}
|
|
151
207
|
var request = provider.request.bind(provider);
|
|
152
208
|
var wrappedRequest = function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
|
|
209
|
+
var owners, liveOwner;
|
|
210
|
+
var method = _b.method, params = _b.params;
|
|
211
|
+
return __generator(this, function (_c) {
|
|
212
|
+
owners = provider[WRAPPED_REQUEST_OWNER_SYMBOL];
|
|
213
|
+
if (dispatchInFlight.has(provider)) {
|
|
214
|
+
// An outer Formo wrapper is already instrumenting this very
|
|
215
|
+
// request; this layer only forwards.
|
|
216
|
+
return [2 /*return*/, request({ method: method, params: params })];
|
|
217
|
+
}
|
|
218
|
+
liveOwner = Array.isArray(owners)
|
|
219
|
+
? __spreadArray([], owners, true).reverse().find(function (o) { return !o.disposed; })
|
|
220
|
+
: undefined;
|
|
221
|
+
dispatchInFlight.add(provider);
|
|
222
|
+
try {
|
|
223
|
+
return [2 /*return*/, (liveOwner !== null && liveOwner !== void 0 ? liveOwner : this).dispatchWrappedRequest({ method: method, params: params }, provider, request)];
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
// Cleared as soon as the dispatch call RETURNS its promise: the
|
|
227
|
+
// underlying request has been issued synchronously by then, so
|
|
228
|
+
// the window covers exactly the nested layers of this one call
|
|
229
|
+
// and never a concurrent request.
|
|
230
|
+
dispatchInFlight.delete(provider);
|
|
231
|
+
}
|
|
232
|
+
return [2 /*return*/];
|
|
233
|
+
});
|
|
234
|
+
}); };
|
|
235
|
+
try {
|
|
236
|
+
// MERGE with any existing list rather than overwriting: a wallet that
|
|
237
|
+
// replaced `request` forces a re-wrap, and discarding the prior list
|
|
238
|
+
// would drop other live instances from ownership - the newest-live
|
|
239
|
+
// fallback then has nobody to fall back to.
|
|
240
|
+
var slot = provider;
|
|
241
|
+
var prior = slot[WRAPPED_REQUEST_OWNER_SYMBOL];
|
|
242
|
+
var owners = Array.isArray(prior) ? prior : [];
|
|
243
|
+
var idx = owners.indexOf(this);
|
|
244
|
+
if (idx !== -1)
|
|
245
|
+
owners.splice(idx, 1);
|
|
246
|
+
owners.push(this);
|
|
247
|
+
if (!Array.isArray(prior)) {
|
|
248
|
+
slot[WRAPPED_REQUEST_OWNER_SYMBOL] = owners;
|
|
249
|
+
}
|
|
250
|
+
this.wrappedProviders.add(provider);
|
|
251
|
+
}
|
|
252
|
+
catch (_a) {
|
|
253
|
+
/* frozen provider: the request write below fails too and aborts */
|
|
254
|
+
}
|
|
255
|
+
return this.installWrappedRequest(provider, wrappedRequest);
|
|
256
|
+
};
|
|
257
|
+
/** Install the wrapper function onto the provider; separated so the
|
|
258
|
+
* routing shim above stays small. */
|
|
259
|
+
EvmRequestTracker.prototype.installWrappedRequest = function (provider, wrappedRequest) {
|
|
260
|
+
// Mark the wrapper so we can detect if request is replaced externally and keep a reference on provider
|
|
261
|
+
wrappedRequest[WRAPPED_REQUEST_SYMBOL] = true;
|
|
262
|
+
// Both writes go inside the try. A frozen or non-extensible provider
|
|
263
|
+
// throws on the symbol assignment just as readily as on `request`, and
|
|
264
|
+
// that one used to sit outside the guard, so an unwrappable provider
|
|
265
|
+
// aborted registration instead of being skipped.
|
|
266
|
+
try {
|
|
267
|
+
provider[WRAPPED_REQUEST_REF_SYMBOL] =
|
|
268
|
+
wrappedRequest;
|
|
269
|
+
provider.request = wrappedRequest;
|
|
270
|
+
// Read back: an accessor or Proxy can ACCEPT the assignment without
|
|
271
|
+
// installing it, and success here is a promise that capture works.
|
|
272
|
+
if (provider.request !== wrappedRequest) {
|
|
273
|
+
logger.warn("request assignment swallowed; not wrapped");
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
catch (e) {
|
|
279
|
+
logger.warn("Failed to wrap provider.request; skipping", e);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* The wrapper body proper: everything a request observation does, run
|
|
285
|
+
* against THIS instance's registry, wallet state, and event queue. Kept
|
|
286
|
+
* as a method so a surviving wrapper installed by a previous SDK
|
|
287
|
+
* instance can hand calls to the current one.
|
|
288
|
+
*/
|
|
289
|
+
EvmRequestTracker.prototype.dispatchWrappedRequest = function (_a, provider_1, request_1) {
|
|
290
|
+
return __awaiter(this, arguments, void 0, function (_b, provider, request) {
|
|
153
291
|
var generation_1, responsePromise, capturedChainId_1, response_1, error_1, rpcError, txPromise, txChainId_1, transactionHash_1, error_2, rpcError;
|
|
154
292
|
var _this = this;
|
|
293
|
+
var _c, _d, _e, _f;
|
|
155
294
|
var method = _b.method, params = _b.params;
|
|
156
|
-
return __generator(this, function (
|
|
157
|
-
switch (
|
|
295
|
+
return __generator(this, function (_g) {
|
|
296
|
+
switch (_g.label) {
|
|
158
297
|
case 0:
|
|
159
298
|
// Learn the chain from a call the APP was making anyway.
|
|
160
299
|
//
|
|
@@ -183,6 +322,10 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
183
322
|
logger.debug("Signature event skipped (autocapture.signature: false)", { method: method });
|
|
184
323
|
return [2 /*return*/, request({ method: method, params: params })];
|
|
185
324
|
}
|
|
325
|
+
if ((_d = (_c = this.deps).shouldSkipRequestCapture) === null || _d === void 0 ? void 0 : _d.call(_c, method, params)) {
|
|
326
|
+
// A pending wagmi mutation owns this capture.
|
|
327
|
+
return [2 /*return*/, request({ method: method, params: params })];
|
|
328
|
+
}
|
|
186
329
|
responsePromise = request({ method: method, params: params });
|
|
187
330
|
// Attach a no-op handler now so a rejection arriving before the await
|
|
188
331
|
// below is never reported as unhandled. The real handling is there.
|
|
@@ -195,7 +338,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
195
338
|
switch (_a.label) {
|
|
196
339
|
case 0:
|
|
197
340
|
_a.trys.push([0, 2, , 3]);
|
|
198
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)))];
|
|
341
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)), this.attributionFor(provider))];
|
|
199
342
|
case 1:
|
|
200
343
|
_a.sent();
|
|
201
344
|
return [3 /*break*/, 3];
|
|
@@ -207,12 +350,12 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
207
350
|
}
|
|
208
351
|
});
|
|
209
352
|
}); })();
|
|
210
|
-
|
|
353
|
+
_g.label = 1;
|
|
211
354
|
case 1:
|
|
212
|
-
|
|
355
|
+
_g.trys.push([1, 3, , 4]);
|
|
213
356
|
return [4 /*yield*/, responsePromise];
|
|
214
357
|
case 2:
|
|
215
|
-
response_1 =
|
|
358
|
+
response_1 = _g.sent();
|
|
216
359
|
// Track signature confirmation only for truthy responses
|
|
217
360
|
if (response_1) {
|
|
218
361
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
@@ -221,7 +364,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
221
364
|
switch (_a.label) {
|
|
222
365
|
case 0:
|
|
223
366
|
_a.trys.push([0, 2, , 3]);
|
|
224
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1, provider)))];
|
|
367
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1, provider)), this.attributionFor(provider))];
|
|
225
368
|
case 1:
|
|
226
369
|
_a.sent();
|
|
227
370
|
return [3 /*break*/, 3];
|
|
@@ -236,9 +379,9 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
236
379
|
}
|
|
237
380
|
return [2 /*return*/, response_1];
|
|
238
381
|
case 3:
|
|
239
|
-
error_1 =
|
|
382
|
+
error_1 = _g.sent();
|
|
240
383
|
rpcError = error_1;
|
|
241
|
-
if ((rpcError
|
|
384
|
+
if (isUserRejectionError(rpcError)) {
|
|
242
385
|
// Use the already cast rpcError to avoid duplication
|
|
243
386
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
244
387
|
var e_3;
|
|
@@ -246,7 +389,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
246
389
|
switch (_a.label) {
|
|
247
390
|
case 0:
|
|
248
391
|
_a.trys.push([0, 2, , 3]);
|
|
249
|
-
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)))];
|
|
392
|
+
return [4 /*yield*/, this.deps.signature(__assign({ status: SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)), this.attributionFor(provider))];
|
|
250
393
|
case 1:
|
|
251
394
|
_a.sent();
|
|
252
395
|
return [3 /*break*/, 3];
|
|
@@ -278,6 +421,10 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
278
421
|
logger.debug("Transaction event skipped (autocapture.transaction: false)", { method: method });
|
|
279
422
|
return [2 /*return*/, request({ method: method, params: params })];
|
|
280
423
|
}
|
|
424
|
+
if ((_f = (_e = this.deps).shouldSkipRequestCapture) === null || _f === void 0 ? void 0 : _f.call(_e, method, params)) {
|
|
425
|
+
// A pending wagmi mutation owns this capture.
|
|
426
|
+
return [2 /*return*/, request({ method: method, params: params })];
|
|
427
|
+
}
|
|
281
428
|
txPromise = request({ method: method, params: params });
|
|
282
429
|
txPromise.catch(function () { return undefined; });
|
|
283
430
|
txChainId_1 = this.registry.resolveChainId(provider);
|
|
@@ -290,7 +437,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
290
437
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
291
438
|
case 1:
|
|
292
439
|
payload = _a.sent();
|
|
293
|
-
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.STARTED }, payload))];
|
|
440
|
+
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.STARTED }, payload), this.attributionFor(provider))];
|
|
294
441
|
case 2:
|
|
295
442
|
_a.sent();
|
|
296
443
|
return [3 /*break*/, 4];
|
|
@@ -302,12 +449,12 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
302
449
|
}
|
|
303
450
|
});
|
|
304
451
|
}); })();
|
|
305
|
-
|
|
452
|
+
_g.label = 5;
|
|
306
453
|
case 5:
|
|
307
|
-
|
|
454
|
+
_g.trys.push([5, 7, , 8]);
|
|
308
455
|
return [4 /*yield*/, txPromise];
|
|
309
456
|
case 6:
|
|
310
|
-
transactionHash_1 =
|
|
457
|
+
transactionHash_1 = _g.sent();
|
|
311
458
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
312
459
|
var payload, e_5;
|
|
313
460
|
return __generator(this, function (_a) {
|
|
@@ -317,7 +464,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
317
464
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
318
465
|
case 1:
|
|
319
466
|
payload = _a.sent();
|
|
320
|
-
return [4 /*yield*/, this.deps.transaction(__assign(__assign({ status: TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }))];
|
|
467
|
+
return [4 /*yield*/, this.deps.transaction(__assign(__assign({ status: TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }), this.attributionFor(provider))];
|
|
321
468
|
case 2:
|
|
322
469
|
_a.sent();
|
|
323
470
|
// Start async polling for transaction receipt
|
|
@@ -333,9 +480,9 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
333
480
|
}); })();
|
|
334
481
|
return [2 /*return*/, transactionHash_1];
|
|
335
482
|
case 7:
|
|
336
|
-
error_2 =
|
|
483
|
+
error_2 = _g.sent();
|
|
337
484
|
rpcError = error_2;
|
|
338
|
-
if ((rpcError
|
|
485
|
+
if (isUserRejectionError(rpcError)) {
|
|
339
486
|
// Use the already cast rpcError to avoid duplication
|
|
340
487
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
341
488
|
var payload, e_6;
|
|
@@ -346,7 +493,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
346
493
|
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
347
494
|
case 1:
|
|
348
495
|
payload = _a.sent();
|
|
349
|
-
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.REJECTED }, payload))];
|
|
496
|
+
return [4 /*yield*/, this.deps.transaction(__assign({ status: TransactionStatus.REJECTED }, payload), this.attributionFor(provider))];
|
|
350
497
|
case 2:
|
|
351
498
|
_a.sent();
|
|
352
499
|
return [3 /*break*/, 4];
|
|
@@ -363,23 +510,19 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
363
510
|
case 8: return [2 /*return*/, request({ method: method, params: params })];
|
|
364
511
|
}
|
|
365
512
|
});
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
catch (e) {
|
|
380
|
-
logger.warn("Failed to wrap provider.request; skipping", e);
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
513
|
+
});
|
|
514
|
+
};
|
|
515
|
+
/**
|
|
516
|
+
* Wallet attribution for request-derived events.
|
|
517
|
+
*
|
|
518
|
+
* Live per read through the registry, so a WalletConnect session names
|
|
519
|
+
* its actual signer ("MetaMask Wallet", "Ledger Live") - the live-test
|
|
520
|
+
* rows had provider_name EMPTY on every signature and transaction, which
|
|
521
|
+
* made per-wallet activity unanswerable in the warehouse.
|
|
522
|
+
*/
|
|
523
|
+
EvmRequestTracker.prototype.attributionFor = function (provider) {
|
|
524
|
+
var info = this.registry.infoFor(provider);
|
|
525
|
+
return { providerName: info.name, rdns: info.rdns };
|
|
383
526
|
};
|
|
384
527
|
EvmRequestTracker.prototype.buildSignatureEventPayload = function (method, params,
|
|
385
528
|
// Intentionally not read. Kept for positional call-site arity.
|
|
@@ -475,7 +618,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
475
618
|
// status: 1 = success, 0 = reverted
|
|
476
619
|
if (receipt.status === "0x1" || receipt.status === 1) {
|
|
477
620
|
this.deps
|
|
478
|
-
.transaction(__assign(__assign({ status: TransactionStatus.CONFIRMED }, payload), { transactionHash: transactionHash }))
|
|
621
|
+
.transaction(__assign(__assign({ status: TransactionStatus.CONFIRMED }, payload), { transactionHash: transactionHash }), this.attributionFor(provider))
|
|
479
622
|
.catch(function (e) {
|
|
480
623
|
return logger.error("Formo: Failed to track transaction confirmation", e);
|
|
481
624
|
});
|
|
@@ -483,7 +626,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
483
626
|
}
|
|
484
627
|
else if (receipt.status === "0x0" || receipt.status === 0) {
|
|
485
628
|
this.deps
|
|
486
|
-
.transaction(__assign(__assign({ status: TransactionStatus.REVERTED }, payload), { transactionHash: transactionHash }))
|
|
629
|
+
.transaction(__assign(__assign({ status: TransactionStatus.REVERTED }, payload), { transactionHash: transactionHash }), this.attributionFor(provider))
|
|
487
630
|
.catch(function (e) {
|
|
488
631
|
return logger.error("Formo: Failed to track transaction revert", e);
|
|
489
632
|
});
|
|
@@ -511,11 +654,14 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
511
654
|
/**
|
|
512
655
|
* One `transaction` event per call in an EIP-5792 batch.
|
|
513
656
|
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
* per-contract
|
|
517
|
-
*
|
|
518
|
-
*
|
|
657
|
+
* The CALL is the unit of attribution: each has its own target, calldata,
|
|
658
|
+
* and value, and folding a batch into one event would misattribute revenue
|
|
659
|
+
* and per-contract activity for every app that adopts smart accounts. How
|
|
660
|
+
* many on-chain transactions a batch becomes depends on execution - an
|
|
661
|
+
* atomic batch lands as ONE transaction, a non-atomic fallback as several -
|
|
662
|
+
* so on-chain volume is `count(distinct transaction_hash)`, wallet actions
|
|
663
|
+
* `count(distinct batch_id)`, never the event count. Each call is reported
|
|
664
|
+
* on its own, carrying the batch id so the calls reassemble downstream.
|
|
519
665
|
*
|
|
520
666
|
* Status is per BATCH, because that is what `wallet_getCallsStatus` reports.
|
|
521
667
|
* When it resolves, every call in the batch moves together, except where
|
|
@@ -523,10 +669,10 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
523
669
|
*/
|
|
524
670
|
EvmRequestTracker.prototype.trackBatchedCalls = function (provider, request, params) {
|
|
525
671
|
return __awaiter(this, void 0, void 0, function () {
|
|
526
|
-
var sendPromise, batch, calls, declared, chainId, address, payloads, _i, payloads_1, p, properties, rest, result, batchId, _a, payloads_2, p, properties, rest, error_3, rpcError, _b, payloads_3, p, properties, rest;
|
|
527
|
-
var _c;
|
|
528
|
-
return __generator(this, function (
|
|
529
|
-
switch (
|
|
672
|
+
var sendPromise, batch, calls, declared, chainId, address, attribution, payloads, _i, payloads_1, p, properties, rest, result, batchId, _a, payloads_2, p, properties, rest, error_3, rpcError, _b, payloads_3, p, properties, rest;
|
|
673
|
+
var _c, _d, _e;
|
|
674
|
+
return __generator(this, function (_f) {
|
|
675
|
+
switch (_f.label) {
|
|
530
676
|
case 0:
|
|
531
677
|
if (!this.deps.isAutocaptureEnabled("transaction")) {
|
|
532
678
|
logger.debug("Transaction event skipped (autocapture.transaction: false)", {
|
|
@@ -534,13 +680,17 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
534
680
|
});
|
|
535
681
|
return [2 /*return*/, request({ method: "wallet_sendCalls", params: params })];
|
|
536
682
|
}
|
|
683
|
+
if ((_d = (_c = this.deps).shouldSkipRequestCapture) === null || _d === void 0 ? void 0 : _d.call(_c, "wallet_sendCalls", params)) {
|
|
684
|
+
// A pending wagmi sendCalls mutation owns this capture.
|
|
685
|
+
return [2 /*return*/, request({ method: "wallet_sendCalls", params: params })];
|
|
686
|
+
}
|
|
537
687
|
sendPromise = request({ method: "wallet_sendCalls", params: params });
|
|
538
688
|
sendPromise.catch(function () { return undefined; });
|
|
539
689
|
batch = params[0];
|
|
540
690
|
calls = Array.isArray(batch === null || batch === void 0 ? void 0 : batch.calls) ? batch.calls : [];
|
|
541
691
|
declared = typeof (batch === null || batch === void 0 ? void 0 : batch.chainId) === "string" ? parseChainId(batch.chainId) : undefined;
|
|
542
692
|
chainId = declared || this.registry.resolveChainId(provider);
|
|
543
|
-
address = validateAndChecksumAddress((
|
|
693
|
+
address = validateAndChecksumAddress((_e = batch === null || batch === void 0 ? void 0 : batch.from) !== null && _e !== void 0 ? _e : "");
|
|
544
694
|
if (!address) {
|
|
545
695
|
// Nothing can be attributed without a sender, and inventing one would
|
|
546
696
|
// be worse than reporting nothing. The user's call still goes through.
|
|
@@ -559,16 +709,14 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
559
709
|
if (!provider || provider === this.wallet.provider || !this.wallet.provider) {
|
|
560
710
|
this.wallet.backfill(address, chainId, provider);
|
|
561
711
|
}
|
|
712
|
+
attribution = this.attributionFor(provider);
|
|
562
713
|
payloads = calls.map(function (call, index) { return ({
|
|
563
714
|
chainId: chainId,
|
|
564
715
|
address: address,
|
|
565
716
|
to: call === null || call === void 0 ? void 0 : call.to,
|
|
566
717
|
value: call === null || call === void 0 ? void 0 : call.value,
|
|
567
718
|
data: call === null || call === void 0 ? void 0 : call.data,
|
|
568
|
-
properties: {
|
|
569
|
-
batch_size: calls.length,
|
|
570
|
-
batch_index: index,
|
|
571
|
-
},
|
|
719
|
+
properties: __assign({ batch_size: calls.length, batch_index: index }, attribution),
|
|
572
720
|
}); });
|
|
573
721
|
// STARTED carries no batch id: the wallet has not issued one yet, exactly
|
|
574
722
|
// as `eth_sendTransaction` has no hash at this point. Position within the
|
|
@@ -580,13 +728,13 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
580
728
|
.transaction(__assign({ status: TransactionStatus.STARTED }, rest), properties)
|
|
581
729
|
.catch(function (e) { return logger.error("Formo: Failed to track batch call start", e); });
|
|
582
730
|
}
|
|
583
|
-
|
|
731
|
+
_f.label = 1;
|
|
584
732
|
case 1:
|
|
585
|
-
|
|
733
|
+
_f.trys.push([1, 3, , 4]);
|
|
586
734
|
return [4 /*yield*/, sendPromise];
|
|
587
735
|
case 2:
|
|
588
|
-
result =
|
|
589
|
-
batchId =
|
|
736
|
+
result = _f.sent();
|
|
737
|
+
batchId = readBatchId(result);
|
|
590
738
|
for (_a = 0, payloads_2 = payloads; _a < payloads_2.length; _a++) {
|
|
591
739
|
p = payloads_2[_a];
|
|
592
740
|
properties = p.properties, rest = __rest(p, ["properties"]);
|
|
@@ -600,9 +748,9 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
600
748
|
this.pollBatchStatus(provider, batchId, payloads);
|
|
601
749
|
return [2 /*return*/, result];
|
|
602
750
|
case 3:
|
|
603
|
-
error_3 =
|
|
751
|
+
error_3 = _f.sent();
|
|
604
752
|
rpcError = error_3;
|
|
605
|
-
if ((rpcError
|
|
753
|
+
if (isUserRejectionError(rpcError)) {
|
|
606
754
|
// One rejection dismisses the whole prompt, so every call in it is
|
|
607
755
|
// rejected. Reporting only the first would undercount.
|
|
608
756
|
for (_b = 0, payloads_3 = payloads; _b < payloads_3.length; _b++) {
|
|
@@ -621,54 +769,6 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
621
769
|
});
|
|
622
770
|
});
|
|
623
771
|
};
|
|
624
|
-
/**
|
|
625
|
-
* How one call in a settled batch ended.
|
|
626
|
-
*
|
|
627
|
-
* A per-call receipt is authoritative where it exists: that is what makes a
|
|
628
|
-
* partially reverted non-atomic batch report honestly rather than tarring
|
|
629
|
-
* every call with the batch's worst outcome. A receipt whose own status is
|
|
630
|
-
* unreadable falls back to the batch verdict rather than being assumed good.
|
|
631
|
-
*
|
|
632
|
-
* The codes are EIP-5792's: 200 confirmed, 400 failed BEFORE landing on
|
|
633
|
-
* chain, 500 reverted, 600 partially reverted. 400 is a rejection, not a
|
|
634
|
-
* revert - nothing was mined, so calling it reverted would misreport gas
|
|
635
|
-
* spent and on-chain activity that never happened.
|
|
636
|
-
*
|
|
637
|
-
* Returns undefined when the call cannot be decided, which happens on 600
|
|
638
|
-
* for a call the wallet gave no receipt for.
|
|
639
|
-
*/
|
|
640
|
-
EvmRequestTracker.prototype.batchCallOutcome = function (code, receipt) {
|
|
641
|
-
var receiptStatus = receipt === null || receipt === void 0 ? void 0 : receipt.status;
|
|
642
|
-
if (receiptStatus !== undefined) {
|
|
643
|
-
return receiptStatus === "0x0" || receiptStatus === 0
|
|
644
|
-
? TransactionStatus.REVERTED
|
|
645
|
-
: TransactionStatus.CONFIRMED;
|
|
646
|
-
}
|
|
647
|
-
if (code >= 600)
|
|
648
|
-
return undefined;
|
|
649
|
-
if (code >= 500)
|
|
650
|
-
return TransactionStatus.REVERTED;
|
|
651
|
-
if (code >= 400)
|
|
652
|
-
return TransactionStatus.REJECTED;
|
|
653
|
-
return TransactionStatus.CONFIRMED;
|
|
654
|
-
};
|
|
655
|
-
/**
|
|
656
|
-
* The batch identifier from a `wallet_sendCalls` result.
|
|
657
|
-
*
|
|
658
|
-
* EIP-5792 settled on `{ id }`, but wallets shipped against the earlier
|
|
659
|
-
* draft return a bare string. Both are accepted so a wallet on either
|
|
660
|
-
* version is still grouped.
|
|
661
|
-
*/
|
|
662
|
-
EvmRequestTracker.prototype.readBatchId = function (result) {
|
|
663
|
-
if (typeof result === "string" && result.length > 0)
|
|
664
|
-
return result;
|
|
665
|
-
if (result && typeof result === "object") {
|
|
666
|
-
var id = result.id;
|
|
667
|
-
if (typeof id === "string" && id.length > 0)
|
|
668
|
-
return id;
|
|
669
|
-
}
|
|
670
|
-
return undefined;
|
|
671
|
-
};
|
|
672
772
|
/**
|
|
673
773
|
* Resolve a batch through `wallet_getCallsStatus`.
|
|
674
774
|
*
|
|
@@ -691,7 +791,7 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
691
791
|
return [2 /*return*/];
|
|
692
792
|
attempts = 0;
|
|
693
793
|
poll = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
694
|
-
var
|
|
794
|
+
var res_1, code_1, e_8;
|
|
695
795
|
var _this = this;
|
|
696
796
|
return __generator(this, function (_a) {
|
|
697
797
|
switch (_a.label) {
|
|
@@ -706,13 +806,14 @@ var EvmRequestTracker = /** @class */ (function () {
|
|
|
706
806
|
params: [batchId],
|
|
707
807
|
})];
|
|
708
808
|
case 2:
|
|
709
|
-
|
|
710
|
-
code_1 =
|
|
809
|
+
res_1 = (_a.sent());
|
|
810
|
+
code_1 = readBatchStatusCode(res_1);
|
|
711
811
|
if (code_1 !== undefined && code_1 >= 200) {
|
|
712
|
-
receipts_1 = Array.isArray(res === null || res === void 0 ? void 0 : res.receipts) ? res.receipts : [];
|
|
713
812
|
payloads.forEach(function (p, index) {
|
|
714
|
-
|
|
715
|
-
|
|
813
|
+
// Atomic-aware: one receipt covering the whole batch reaches
|
|
814
|
+
// every call, hash included, not just call 0.
|
|
815
|
+
var receipt = batchReceiptForCall(res_1, index, payloads.length);
|
|
816
|
+
var outcome = batchCallOutcome(code_1, receipt);
|
|
716
817
|
// 600 means SOME calls reverted, so a call with no receipt of its
|
|
717
818
|
// own has not been decided. Reporting it either way would invent
|
|
718
819
|
// a result; leaving it unsettled is the honest answer.
|