@formo/analytics 1.35.1 → 1.36.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 +90 -240
- package/dist/cjs/src/FormoAnalytics.js +432 -1840
- package/dist/cjs/src/constants/base.d.ts +0 -1
- package/dist/cjs/src/constants/base.js +1 -3
- package/dist/cjs/src/event/EventFactory.js +1 -1
- package/dist/cjs/src/event/EventManager.d.ts +3 -1
- package/dist/cjs/src/event/EventManager.js +5 -1
- package/dist/cjs/src/event/type.d.ts +1 -0
- package/dist/cjs/src/evm/EvmEventTracker.d.ts +175 -0
- package/dist/cjs/src/evm/EvmEventTracker.js +1030 -0
- package/dist/cjs/src/evm/EvmProviderRegistry.d.ts +132 -0
- package/dist/cjs/src/evm/EvmProviderRegistry.js +348 -0
- package/dist/cjs/src/evm/EvmRequestTracker.d.ts +120 -0
- package/dist/cjs/src/evm/EvmRequestTracker.js +756 -0
- package/dist/cjs/src/queue/EventQueue.d.ts +28 -0
- package/dist/cjs/src/queue/EventQueue.js +97 -19
- package/dist/cjs/src/queue/type.d.ts +1 -0
- package/dist/cjs/src/tracking/TrackingPolicy.d.ts +146 -0
- package/dist/cjs/src/tracking/TrackingPolicy.js +200 -0
- package/dist/cjs/src/utils/mergeDeepRight.d.ts +22 -0
- package/dist/cjs/src/utils/mergeDeepRight.js +54 -0
- package/dist/cjs/src/validators/address.d.ts +1 -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 +193 -1
- package/dist/cjs/src/wagmi/WagmiEventHandler.js +1317 -77
- package/dist/cjs/src/wagmi/types.d.ts +6 -0
- package/dist/cjs/src/wallet/WalletStateStore.d.ts +223 -0
- package/dist/cjs/src/wallet/WalletStateStore.js +515 -0
- package/dist/esm/src/FormoAnalytics.d.ts +90 -240
- package/dist/esm/src/FormoAnalytics.js +433 -1841
- package/dist/esm/src/constants/base.d.ts +0 -1
- package/dist/esm/src/constants/base.js +0 -2
- package/dist/esm/src/event/EventFactory.js +1 -1
- package/dist/esm/src/event/EventManager.d.ts +3 -1
- package/dist/esm/src/event/EventManager.js +5 -1
- package/dist/esm/src/event/type.d.ts +1 -0
- package/dist/esm/src/evm/EvmEventTracker.d.ts +175 -0
- package/dist/esm/src/evm/EvmEventTracker.js +1027 -0
- package/dist/esm/src/evm/EvmProviderRegistry.d.ts +132 -0
- package/dist/esm/src/evm/EvmProviderRegistry.js +345 -0
- package/dist/esm/src/evm/EvmRequestTracker.d.ts +120 -0
- package/dist/esm/src/evm/EvmRequestTracker.js +753 -0
- package/dist/esm/src/queue/EventQueue.d.ts +28 -0
- package/dist/esm/src/queue/EventQueue.js +97 -19
- package/dist/esm/src/queue/type.d.ts +1 -0
- package/dist/esm/src/tracking/TrackingPolicy.d.ts +146 -0
- package/dist/esm/src/tracking/TrackingPolicy.js +197 -0
- package/dist/esm/src/utils/mergeDeepRight.d.ts +22 -0
- package/dist/esm/src/utils/mergeDeepRight.js +51 -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 +193 -1
- package/dist/esm/src/wagmi/WagmiEventHandler.js +1315 -76
- package/dist/esm/src/wagmi/types.d.ts +6 -0
- package/dist/esm/src/wallet/WalletStateStore.d.ts +223 -0
- package/dist/esm/src/wallet/WalletStateStore.js +512 -0
- package/dist/index.umd.min.js +1 -1
- package/package.json +5 -13
- package/dist/cjs/src/ramda/internal/_curry1.d.ts +0 -10
- package/dist/cjs/src/ramda/internal/_curry1.js +0 -26
- package/dist/cjs/src/ramda/internal/_curry2.d.ts +0 -10
- package/dist/cjs/src/ramda/internal/_curry2.js +0 -43
- package/dist/cjs/src/ramda/internal/_curry3.d.ts +0 -10
- package/dist/cjs/src/ramda/internal/_curry3.js +0 -74
- package/dist/cjs/src/ramda/internal/_has.d.ts +0 -2
- package/dist/cjs/src/ramda/internal/_has.js +0 -7
- package/dist/cjs/src/ramda/internal/_isObject.d.ts +0 -2
- package/dist/cjs/src/ramda/internal/_isObject.js +0 -7
- package/dist/cjs/src/ramda/internal/_isPlaceholder.d.ts +0 -2
- package/dist/cjs/src/ramda/internal/_isPlaceholder.js +0 -7
- package/dist/cjs/src/ramda/mergeDeepRight.d.ts +0 -3
- package/dist/cjs/src/ramda/mergeDeepRight.js +0 -14
- package/dist/cjs/src/ramda/mergeDeepWithKey.d.ts +0 -3
- package/dist/cjs/src/ramda/mergeDeepWithKey.js +0 -20
- package/dist/cjs/src/ramda/mergeWithKey.d.ts +0 -3
- package/dist/cjs/src/ramda/mergeWithKey.js +0 -26
- package/dist/esm/src/ramda/internal/_curry1.d.ts +0 -10
- package/dist/esm/src/ramda/internal/_curry1.js +0 -20
- package/dist/esm/src/ramda/internal/_curry2.d.ts +0 -10
- package/dist/esm/src/ramda/internal/_curry2.js +0 -37
- package/dist/esm/src/ramda/internal/_curry3.d.ts +0 -10
- package/dist/esm/src/ramda/internal/_curry3.js +0 -68
- package/dist/esm/src/ramda/internal/_has.d.ts +0 -2
- package/dist/esm/src/ramda/internal/_has.js +0 -4
- package/dist/esm/src/ramda/internal/_isObject.d.ts +0 -2
- package/dist/esm/src/ramda/internal/_isObject.js +0 -4
- package/dist/esm/src/ramda/internal/_isPlaceholder.d.ts +0 -2
- package/dist/esm/src/ramda/internal/_isPlaceholder.js +0 -4
- package/dist/esm/src/ramda/mergeDeepRight.d.ts +0 -3
- package/dist/esm/src/ramda/mergeDeepRight.js +0 -9
- package/dist/esm/src/ramda/mergeDeepWithKey.d.ts +0 -3
- package/dist/esm/src/ramda/mergeDeepWithKey.js +0 -15
- package/dist/esm/src/ramda/mergeWithKey.d.ts +0 -3
- package/dist/esm/src/ramda/mergeWithKey.js +0 -21
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { EIP6963ProviderDetail } from "mipd";
|
|
2
|
+
import { Address, ChainID, EIP1193Provider, WrappedRequestFunction } from "../types";
|
|
3
|
+
/** What the registry needs from the SDK that owns it. */
|
|
4
|
+
export interface EvmProviderRegistryDeps {
|
|
5
|
+
/** The provider the SDK currently attributes activity to. */
|
|
6
|
+
activeProvider(): EIP1193Provider | undefined;
|
|
7
|
+
/** The active provider's chain, per central state. */
|
|
8
|
+
activeChainId(): ChainID | undefined;
|
|
9
|
+
/** The wallet already known for EVM, if any. */
|
|
10
|
+
knownEvmAddress(): Address | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* A provider reported a chain.
|
|
13
|
+
*
|
|
14
|
+
* The registry records it per provider; whether central state should follow
|
|
15
|
+
* is the SDK's decision, not the registry's, because it depends on which
|
|
16
|
+
* namespace is active.
|
|
17
|
+
*/
|
|
18
|
+
onChainObserved(provider: EIP1193Provider, chainId: number): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Which EVM wallets exist, and what is known about each.
|
|
22
|
+
*
|
|
23
|
+
* Split out of `FormoAnalytics` so "the provider registry" is one thing with
|
|
24
|
+
* one owner. It deliberately holds no event logic: registering listeners and
|
|
25
|
+
* reacting to them stays with the SDK for now, and moves next.
|
|
26
|
+
*
|
|
27
|
+
* Three provider sets, which are not the same thing:
|
|
28
|
+
* - `details` is every EIP-6963 provider discovered, with its metadata.
|
|
29
|
+
* - `tracked` is the subset that has listeners wired up.
|
|
30
|
+
* - `seen` guards `details` against duplicates.
|
|
31
|
+
*/
|
|
32
|
+
export declare class EvmProviderRegistry {
|
|
33
|
+
private readonly deps;
|
|
34
|
+
private details;
|
|
35
|
+
private tracked;
|
|
36
|
+
private seen;
|
|
37
|
+
/** Last chain heard from each provider, whoever is active. */
|
|
38
|
+
private chainIds;
|
|
39
|
+
/**
|
|
40
|
+
* Bumped on every chain observation, PER PROVIDER, so a stale answer that
|
|
41
|
+
* arrives late cannot overwrite a newer one.
|
|
42
|
+
*/
|
|
43
|
+
private chainGenerations;
|
|
44
|
+
/** Listeners this SDK attached, so teardown can remove exactly those. */
|
|
45
|
+
private listeners;
|
|
46
|
+
/** The window-injected provider, once detected, so it is not re-wrapped. */
|
|
47
|
+
private injectedDetail?;
|
|
48
|
+
constructor(deps: EvmProviderRegistryDeps);
|
|
49
|
+
get all(): readonly EIP6963ProviderDetail[];
|
|
50
|
+
isTracked(provider: EIP1193Provider): boolean;
|
|
51
|
+
markTracked(provider: EIP1193Provider): void;
|
|
52
|
+
forgetTracked(provider: EIP1193Provider): void;
|
|
53
|
+
trackedProviders(): EIP1193Provider[];
|
|
54
|
+
isSeen(provider: EIP1193Provider): boolean;
|
|
55
|
+
get injected(): EIP6963ProviderDetail | undefined;
|
|
56
|
+
set injected(detail: EIP6963ProviderDetail | undefined);
|
|
57
|
+
/** Counts for the public debug helpers. */
|
|
58
|
+
get counts(): {
|
|
59
|
+
totalProviders: number;
|
|
60
|
+
trackedProviders: number;
|
|
61
|
+
seenProviders: number;
|
|
62
|
+
};
|
|
63
|
+
/** Add a discovered provider once. Returns false if already present. */
|
|
64
|
+
add(detail: EIP6963ProviderDetail): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* A provider's display name and rdns.
|
|
67
|
+
*
|
|
68
|
+
* EIP-6963 metadata is authoritative when we have it; otherwise fall back to
|
|
69
|
+
* sniffing the injected provider, which is all a pre-6963 wallet offers.
|
|
70
|
+
*/
|
|
71
|
+
infoFor(provider: EIP1193Provider): {
|
|
72
|
+
name: string;
|
|
73
|
+
rdns: string;
|
|
74
|
+
};
|
|
75
|
+
addListener(provider: EIP1193Provider, event: string, listener: (...args: unknown[]) => void): void;
|
|
76
|
+
/** Remove only the listeners this SDK attached, never the host app's. */
|
|
77
|
+
removeListeners(provider: EIP1193Provider): void;
|
|
78
|
+
/** Events still attached to a provider after a failed teardown. */
|
|
79
|
+
attachedEvents(provider: EIP1193Provider): string[];
|
|
80
|
+
/**
|
|
81
|
+
* Whether this provider's `request` is already our wrapper.
|
|
82
|
+
*
|
|
83
|
+
* Checks the wrapper's own marker AND that the provider still points at
|
|
84
|
+
* that exact function, so a wallet that replaced `request` after we wrapped
|
|
85
|
+
* it is re-wrapped rather than left uninstrumented.
|
|
86
|
+
*/
|
|
87
|
+
isWrapped(provider: EIP1193Provider, currentRequest: WrappedRequestFunction | undefined): boolean;
|
|
88
|
+
chainIdOf(provider: EIP1193Provider): number | undefined;
|
|
89
|
+
/** Advance and return this provider's chain-observation generation. */
|
|
90
|
+
bumpChainGeneration(provider: EIP1193Provider): number;
|
|
91
|
+
chainGeneration(provider: EIP1193Provider): number;
|
|
92
|
+
/**
|
|
93
|
+
* Record a provider's chain. Fed by `chainChanged` and `connect`, and by
|
|
94
|
+
* the one-off probe at tracking time, never from inside a user request.
|
|
95
|
+
*/
|
|
96
|
+
rememberChain(provider: EIP1193Provider | undefined, chainId: number | undefined): void;
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the chain an autocaptured request actually ran on.
|
|
99
|
+
*
|
|
100
|
+
* Central chain state is maintained by `chainChanged` from whichever
|
|
101
|
+
* provider is currently active. When a request arrives from a DIFFERENT
|
|
102
|
+
* tracked provider, which happens whenever a visitor has two wallets
|
|
103
|
+
* installed, that cached value describes the wrong wallet, and tagging the
|
|
104
|
+
* event with it silently mis-attributes the chain.
|
|
105
|
+
*
|
|
106
|
+
* Answered entirely from a per-provider snapshot. Deliberately SYNCHRONOUS
|
|
107
|
+
* and never issues an RPC.
|
|
108
|
+
*
|
|
109
|
+
* An earlier version called `eth_chainId` on the signing provider and
|
|
110
|
+
* time-boxed it with `Promise.race`. That is not safe: the race abandons
|
|
111
|
+
* the SDK's promise but cannot cancel the provider's request. On a
|
|
112
|
+
* transport that serialises (WalletConnect's relay socket, the very case
|
|
113
|
+
* this path exists to serve) an abandoned lookup stays at the head of the
|
|
114
|
+
* wallet's queue, and every later RPC the dapp makes queues behind it until
|
|
115
|
+
* reload. Mislabelling a chain is a reporting defect; wedging the user's
|
|
116
|
+
* wallet is not an acceptable way to avoid one.
|
|
117
|
+
*
|
|
118
|
+
* When nothing is known this reports 0 ("unknown") rather than guessing
|
|
119
|
+
* with the active provider's chain, which is known-wrong for another wallet.
|
|
120
|
+
*/
|
|
121
|
+
resolveChainId(provider?: EIP1193Provider): number;
|
|
122
|
+
/**
|
|
123
|
+
* The wallet's first account, or null.
|
|
124
|
+
*
|
|
125
|
+
* Prefers what the SDK already knows, so an EVM context never returns a
|
|
126
|
+
* Solana address and no RPC is issued when the answer is already in hand.
|
|
127
|
+
*/
|
|
128
|
+
addressOf(provider?: EIP1193Provider): Promise<Address | null>;
|
|
129
|
+
/** Every checksummed account a provider reports, or null. */
|
|
130
|
+
accountsOf(provider?: EIP1193Provider): Promise<Address[] | null>;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=EvmProviderRegistry.d.ts.map
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
39
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
40
|
+
if (ar || !(i in from)) {
|
|
41
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
42
|
+
ar[i] = from[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.EvmProviderRegistry = void 0;
|
|
49
|
+
var logger_1 = require("../logger");
|
|
50
|
+
var address_1 = require("../utils/address");
|
|
51
|
+
var provider_1 = require("../provider");
|
|
52
|
+
var types_1 = require("../types");
|
|
53
|
+
/**
|
|
54
|
+
* Which EVM wallets exist, and what is known about each.
|
|
55
|
+
*
|
|
56
|
+
* Split out of `FormoAnalytics` so "the provider registry" is one thing with
|
|
57
|
+
* one owner. It deliberately holds no event logic: registering listeners and
|
|
58
|
+
* reacting to them stays with the SDK for now, and moves next.
|
|
59
|
+
*
|
|
60
|
+
* Three provider sets, which are not the same thing:
|
|
61
|
+
* - `details` is every EIP-6963 provider discovered, with its metadata.
|
|
62
|
+
* - `tracked` is the subset that has listeners wired up.
|
|
63
|
+
* - `seen` guards `details` against duplicates.
|
|
64
|
+
*/
|
|
65
|
+
var EvmProviderRegistry = /** @class */ (function () {
|
|
66
|
+
function EvmProviderRegistry(deps) {
|
|
67
|
+
this.deps = deps;
|
|
68
|
+
this.details = [];
|
|
69
|
+
this.tracked = new Set();
|
|
70
|
+
this.seen = new Set();
|
|
71
|
+
/** Last chain heard from each provider, whoever is active. */
|
|
72
|
+
this.chainIds = new WeakMap();
|
|
73
|
+
/**
|
|
74
|
+
* Bumped on every chain observation, PER PROVIDER, so a stale answer that
|
|
75
|
+
* arrives late cannot overwrite a newer one.
|
|
76
|
+
*/
|
|
77
|
+
this.chainGenerations = new WeakMap();
|
|
78
|
+
/** Listeners this SDK attached, so teardown can remove exactly those. */
|
|
79
|
+
this.listeners = new Map();
|
|
80
|
+
}
|
|
81
|
+
Object.defineProperty(EvmProviderRegistry.prototype, "all", {
|
|
82
|
+
// ── the provider set ─────────────────────────────────────────────────────
|
|
83
|
+
get: function () {
|
|
84
|
+
return this.details;
|
|
85
|
+
},
|
|
86
|
+
enumerable: false,
|
|
87
|
+
configurable: true
|
|
88
|
+
});
|
|
89
|
+
EvmProviderRegistry.prototype.isTracked = function (provider) {
|
|
90
|
+
return this.tracked.has(provider);
|
|
91
|
+
};
|
|
92
|
+
EvmProviderRegistry.prototype.markTracked = function (provider) {
|
|
93
|
+
this.tracked.add(provider);
|
|
94
|
+
};
|
|
95
|
+
EvmProviderRegistry.prototype.forgetTracked = function (provider) {
|
|
96
|
+
this.tracked.delete(provider);
|
|
97
|
+
};
|
|
98
|
+
EvmProviderRegistry.prototype.trackedProviders = function () {
|
|
99
|
+
return Array.from(this.tracked);
|
|
100
|
+
};
|
|
101
|
+
EvmProviderRegistry.prototype.isSeen = function (provider) {
|
|
102
|
+
return this.seen.has(provider);
|
|
103
|
+
};
|
|
104
|
+
Object.defineProperty(EvmProviderRegistry.prototype, "injected", {
|
|
105
|
+
get: function () {
|
|
106
|
+
return this.injectedDetail;
|
|
107
|
+
},
|
|
108
|
+
set: function (detail) {
|
|
109
|
+
this.injectedDetail = detail;
|
|
110
|
+
},
|
|
111
|
+
enumerable: false,
|
|
112
|
+
configurable: true
|
|
113
|
+
});
|
|
114
|
+
Object.defineProperty(EvmProviderRegistry.prototype, "counts", {
|
|
115
|
+
/** Counts for the public debug helpers. */
|
|
116
|
+
get: function () {
|
|
117
|
+
return {
|
|
118
|
+
totalProviders: this.details.length,
|
|
119
|
+
trackedProviders: this.tracked.size,
|
|
120
|
+
seenProviders: this.seen.size,
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
enumerable: false,
|
|
124
|
+
configurable: true
|
|
125
|
+
});
|
|
126
|
+
/** Add a discovered provider once. Returns false if already present. */
|
|
127
|
+
EvmProviderRegistry.prototype.add = function (detail) {
|
|
128
|
+
var provider = detail === null || detail === void 0 ? void 0 : detail.provider;
|
|
129
|
+
if (!provider)
|
|
130
|
+
return false;
|
|
131
|
+
if (this.details.some(function (existing) { return existing.provider === provider; })) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
this.details = __spreadArray(__spreadArray([], this.details, true), [detail], false);
|
|
135
|
+
this.seen.add(provider);
|
|
136
|
+
return true;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* A provider's display name and rdns.
|
|
140
|
+
*
|
|
141
|
+
* EIP-6963 metadata is authoritative when we have it; otherwise fall back to
|
|
142
|
+
* sniffing the injected provider, which is all a pre-6963 wallet offers.
|
|
143
|
+
*/
|
|
144
|
+
EvmProviderRegistry.prototype.infoFor = function (provider) {
|
|
145
|
+
var announced = this.details.find(function (p) { return p.provider === provider; });
|
|
146
|
+
if (announced) {
|
|
147
|
+
return { name: announced.info.name, rdns: announced.info.rdns };
|
|
148
|
+
}
|
|
149
|
+
var injected = (0, provider_1.detectInjectedProviderInfo)(provider);
|
|
150
|
+
return { name: injected.name, rdns: injected.rdns };
|
|
151
|
+
};
|
|
152
|
+
// ── listener bookkeeping ─────────────────────────────────────────────────
|
|
153
|
+
EvmProviderRegistry.prototype.addListener = function (provider, event, listener) {
|
|
154
|
+
var map = this.listeners.get(provider) || {};
|
|
155
|
+
map[event] = listener;
|
|
156
|
+
this.listeners.set(provider, map);
|
|
157
|
+
};
|
|
158
|
+
/** Remove only the listeners this SDK attached, never the host app's. */
|
|
159
|
+
EvmProviderRegistry.prototype.removeListeners = function (provider) {
|
|
160
|
+
var attached = this.listeners.get(provider);
|
|
161
|
+
if (!attached)
|
|
162
|
+
return;
|
|
163
|
+
// Keep whatever could not be removed. Forgetting a listener that is still
|
|
164
|
+
// attached loses the only reference to it, so nothing can ever try again:
|
|
165
|
+
// the callback stays live for the life of the page and holds the instance
|
|
166
|
+
// it closes over. A provider that throws transiently during teardown gets
|
|
167
|
+
// another chance on the next attempt.
|
|
168
|
+
var stillAttached = {};
|
|
169
|
+
for (var _i = 0, _a = Object.entries(attached); _i < _a.length; _i++) {
|
|
170
|
+
var _b = _a[_i], event_1 = _b[0], fn = _b[1];
|
|
171
|
+
try {
|
|
172
|
+
provider.removeListener(event_1, fn);
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
logger_1.logger.warn("Failed to remove listener for ".concat(String(event_1)), e);
|
|
176
|
+
stillAttached[event_1] = fn;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (Object.keys(stillAttached).length > 0) {
|
|
180
|
+
this.listeners.set(provider, stillAttached);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.listeners.delete(provider);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
/** Events still attached to a provider after a failed teardown. */
|
|
187
|
+
EvmProviderRegistry.prototype.attachedEvents = function (provider) {
|
|
188
|
+
var _a;
|
|
189
|
+
return Object.keys((_a = this.listeners.get(provider)) !== null && _a !== void 0 ? _a : {});
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Whether this provider's `request` is already our wrapper.
|
|
193
|
+
*
|
|
194
|
+
* Checks the wrapper's own marker AND that the provider still points at
|
|
195
|
+
* that exact function, so a wallet that replaced `request` after we wrapped
|
|
196
|
+
* it is re-wrapped rather than left uninstrumented.
|
|
197
|
+
*/
|
|
198
|
+
EvmProviderRegistry.prototype.isWrapped = function (provider, currentRequest) {
|
|
199
|
+
return !!(currentRequest &&
|
|
200
|
+
typeof currentRequest === "function" &&
|
|
201
|
+
currentRequest[types_1.WRAPPED_REQUEST_SYMBOL] &&
|
|
202
|
+
provider[types_1.WRAPPED_REQUEST_REF_SYMBOL] ===
|
|
203
|
+
currentRequest);
|
|
204
|
+
};
|
|
205
|
+
// ── per-provider chain knowledge ─────────────────────────────────────────
|
|
206
|
+
EvmProviderRegistry.prototype.chainIdOf = function (provider) {
|
|
207
|
+
return this.chainIds.get(provider);
|
|
208
|
+
};
|
|
209
|
+
/** Advance and return this provider's chain-observation generation. */
|
|
210
|
+
EvmProviderRegistry.prototype.bumpChainGeneration = function (provider) {
|
|
211
|
+
var _a;
|
|
212
|
+
var next = ((_a = this.chainGenerations.get(provider)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
213
|
+
this.chainGenerations.set(provider, next);
|
|
214
|
+
return next;
|
|
215
|
+
};
|
|
216
|
+
EvmProviderRegistry.prototype.chainGeneration = function (provider) {
|
|
217
|
+
var _a;
|
|
218
|
+
return (_a = this.chainGenerations.get(provider)) !== null && _a !== void 0 ? _a : 0;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Record a provider's chain. Fed by `chainChanged` and `connect`, and by
|
|
222
|
+
* the one-off probe at tracking time, never from inside a user request.
|
|
223
|
+
*/
|
|
224
|
+
EvmProviderRegistry.prototype.rememberChain = function (provider, chainId) {
|
|
225
|
+
if (!provider || !chainId)
|
|
226
|
+
return;
|
|
227
|
+
// Any observation is newer than an `eth_chainId` still in flight for this
|
|
228
|
+
// provider.
|
|
229
|
+
this.bumpChainGeneration(provider);
|
|
230
|
+
this.chainIds.set(provider, chainId);
|
|
231
|
+
this.deps.onChainObserved(provider, chainId);
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Resolve the chain an autocaptured request actually ran on.
|
|
235
|
+
*
|
|
236
|
+
* Central chain state is maintained by `chainChanged` from whichever
|
|
237
|
+
* provider is currently active. When a request arrives from a DIFFERENT
|
|
238
|
+
* tracked provider, which happens whenever a visitor has two wallets
|
|
239
|
+
* installed, that cached value describes the wrong wallet, and tagging the
|
|
240
|
+
* event with it silently mis-attributes the chain.
|
|
241
|
+
*
|
|
242
|
+
* Answered entirely from a per-provider snapshot. Deliberately SYNCHRONOUS
|
|
243
|
+
* and never issues an RPC.
|
|
244
|
+
*
|
|
245
|
+
* An earlier version called `eth_chainId` on the signing provider and
|
|
246
|
+
* time-boxed it with `Promise.race`. That is not safe: the race abandons
|
|
247
|
+
* the SDK's promise but cannot cancel the provider's request. On a
|
|
248
|
+
* transport that serialises (WalletConnect's relay socket, the very case
|
|
249
|
+
* this path exists to serve) an abandoned lookup stays at the head of the
|
|
250
|
+
* wallet's queue, and every later RPC the dapp makes queues behind it until
|
|
251
|
+
* reload. Mislabelling a chain is a reporting defect; wedging the user's
|
|
252
|
+
* wallet is not an acceptable way to avoid one.
|
|
253
|
+
*
|
|
254
|
+
* When nothing is known this reports 0 ("unknown") rather than guessing
|
|
255
|
+
* with the active provider's chain, which is known-wrong for another wallet.
|
|
256
|
+
*/
|
|
257
|
+
EvmProviderRegistry.prototype.resolveChainId = function (provider) {
|
|
258
|
+
if (provider) {
|
|
259
|
+
var known = this.chainIds.get(provider);
|
|
260
|
+
if (known)
|
|
261
|
+
return known;
|
|
262
|
+
// Only the active provider's chain is described by central state.
|
|
263
|
+
var activeChain = this.deps.activeChainId();
|
|
264
|
+
if (provider === this.deps.activeProvider() && activeChain) {
|
|
265
|
+
return activeChain;
|
|
266
|
+
}
|
|
267
|
+
// A tracked provider we have never heard a chain from. Deliberately no
|
|
268
|
+
// fall back to central state: it belongs to a different wallet.
|
|
269
|
+
return 0;
|
|
270
|
+
}
|
|
271
|
+
return this.deps.activeChainId() || 0;
|
|
272
|
+
};
|
|
273
|
+
// ── reading accounts off a provider ──────────────────────────────────────
|
|
274
|
+
/**
|
|
275
|
+
* The wallet's first account, or null.
|
|
276
|
+
*
|
|
277
|
+
* Prefers what the SDK already knows, so an EVM context never returns a
|
|
278
|
+
* Solana address and no RPC is issued when the answer is already in hand.
|
|
279
|
+
*/
|
|
280
|
+
EvmProviderRegistry.prototype.addressOf = function (provider) {
|
|
281
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
282
|
+
var active, p, known, accounts;
|
|
283
|
+
return __generator(this, function (_a) {
|
|
284
|
+
switch (_a.label) {
|
|
285
|
+
case 0:
|
|
286
|
+
active = this.deps.activeProvider();
|
|
287
|
+
p = provider || active;
|
|
288
|
+
// The cached wallet describes the ACTIVE provider, so it may only answer
|
|
289
|
+
// for that one. Returning it for any provider reported the active wallet's
|
|
290
|
+
// address under every other wallet's name and rdns, which is exactly what
|
|
291
|
+
// `identify()` does when it scans the providers it has discovered.
|
|
292
|
+
if (!provider || provider === active) {
|
|
293
|
+
known = this.deps.knownEvmAddress();
|
|
294
|
+
if (known)
|
|
295
|
+
return [2 /*return*/, known];
|
|
296
|
+
}
|
|
297
|
+
if (!p) {
|
|
298
|
+
logger_1.logger.info("The provider is not set");
|
|
299
|
+
return [2 /*return*/, null];
|
|
300
|
+
}
|
|
301
|
+
return [4 /*yield*/, this.accountsOf(p)];
|
|
302
|
+
case 1:
|
|
303
|
+
accounts = _a.sent();
|
|
304
|
+
if (accounts && accounts.length > 0) {
|
|
305
|
+
return [2 /*return*/, (0, address_1.validateAndChecksumAddress)(accounts[0]) || null];
|
|
306
|
+
}
|
|
307
|
+
return [2 /*return*/, null];
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
};
|
|
312
|
+
/** Every checksummed account a provider reports, or null. */
|
|
313
|
+
EvmProviderRegistry.prototype.accountsOf = function (provider) {
|
|
314
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
315
|
+
var p, res, err_1, code;
|
|
316
|
+
return __generator(this, function (_a) {
|
|
317
|
+
switch (_a.label) {
|
|
318
|
+
case 0:
|
|
319
|
+
p = provider || this.deps.activeProvider();
|
|
320
|
+
_a.label = 1;
|
|
321
|
+
case 1:
|
|
322
|
+
_a.trys.push([1, 3, , 4]);
|
|
323
|
+
return [4 /*yield*/, (p === null || p === void 0 ? void 0 : p.request({
|
|
324
|
+
method: "eth_accounts",
|
|
325
|
+
}))];
|
|
326
|
+
case 2:
|
|
327
|
+
res = _a.sent();
|
|
328
|
+
if (!res || res.length === 0)
|
|
329
|
+
return [2 /*return*/, null];
|
|
330
|
+
return [2 /*return*/, res
|
|
331
|
+
.map(function (e) { return (0, address_1.validateAndChecksumAddress)(e); })
|
|
332
|
+
.filter(function (e) { return e !== undefined; })];
|
|
333
|
+
case 3:
|
|
334
|
+
err_1 = _a.sent();
|
|
335
|
+
code = err_1 === null || err_1 === void 0 ? void 0 : err_1.code;
|
|
336
|
+
if (code !== 4001) {
|
|
337
|
+
logger_1.logger.error("EvmProviderRegistry::accountsOf: eth_accounts threw an error", err_1);
|
|
338
|
+
}
|
|
339
|
+
return [2 /*return*/, null];
|
|
340
|
+
case 4: return [2 /*return*/];
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
};
|
|
345
|
+
return EvmProviderRegistry;
|
|
346
|
+
}());
|
|
347
|
+
exports.EvmProviderRegistry = EvmProviderRegistry;
|
|
348
|
+
//# sourceMappingURL=EvmProviderRegistry.js.map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Address, ChainID, EIP1193Provider, IFormoEventProperties, SignatureStatus, TransactionStatus } from "../types";
|
|
2
|
+
import { WalletStateStore } from "../wallet/WalletStateStore";
|
|
3
|
+
import { EvmProviderRegistry } from "./EvmProviderRegistry";
|
|
4
|
+
import { AutocaptureEventType } from "../tracking/TrackingPolicy";
|
|
5
|
+
/** What the request tracker needs from the SDK that owns it. */
|
|
6
|
+
export interface EvmRequestTrackerDeps {
|
|
7
|
+
isAutocaptureEnabled(eventType: AutocaptureEventType): boolean;
|
|
8
|
+
signature(params: {
|
|
9
|
+
status: SignatureStatus;
|
|
10
|
+
chainId?: ChainID;
|
|
11
|
+
address: Address;
|
|
12
|
+
message: string;
|
|
13
|
+
}, properties?: IFormoEventProperties): Promise<void>;
|
|
14
|
+
transaction(params: {
|
|
15
|
+
status: TransactionStatus;
|
|
16
|
+
chainId: ChainID;
|
|
17
|
+
address: Address;
|
|
18
|
+
data?: string;
|
|
19
|
+
to?: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
transactionHash?: string;
|
|
22
|
+
function_name?: string;
|
|
23
|
+
function_args?: Record<string, unknown>;
|
|
24
|
+
}, properties?: IFormoEventProperties): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Autocapture for signatures and transactions, by wrapping a provider's
|
|
28
|
+
* `request`.
|
|
29
|
+
*
|
|
30
|
+
* The wrapper is deliberately thin: it observes the call the dapp was already
|
|
31
|
+
* making and never issues one of its own. That rule is why the chain a
|
|
32
|
+
* request ran on is read from `eth_chainId` calls the app makes, rather than
|
|
33
|
+
* probed - an SDK-issued lookup on a serialising transport can wedge the
|
|
34
|
+
* user's wallet, which is never an acceptable price for a label.
|
|
35
|
+
*/
|
|
36
|
+
export declare class EvmRequestTracker {
|
|
37
|
+
private readonly wallet;
|
|
38
|
+
private readonly registry;
|
|
39
|
+
private readonly deps;
|
|
40
|
+
/**
|
|
41
|
+
* Timers for receipt and batch-status polling.
|
|
42
|
+
*
|
|
43
|
+
* A poll re-arms for up to thirty seconds, so a torn-down instance would
|
|
44
|
+
* otherwise keep asking a wallet about transactions nobody is listening
|
|
45
|
+
* for, and hold the process open for the whole window. That is the same
|
|
46
|
+
* shape as the batch timer that hung the test suite in #338.
|
|
47
|
+
*/
|
|
48
|
+
private polls;
|
|
49
|
+
private disposed;
|
|
50
|
+
constructor(wallet: WalletStateStore, registry: EvmProviderRegistry, deps: EvmRequestTrackerDeps);
|
|
51
|
+
/** Stop every poll in flight. Terminal, like the event queue's close(). */
|
|
52
|
+
cleanup(): void;
|
|
53
|
+
/** Re-arm a poll, unless this tracker has been torn down. */
|
|
54
|
+
private schedulePoll;
|
|
55
|
+
/**
|
|
56
|
+
* Wrap a provider's `request`. Returns whether the wrapper is installed:
|
|
57
|
+
* a caller that marks the provider as tracked on a false return would
|
|
58
|
+
* never retry it, and every signature and transaction from that wallet
|
|
59
|
+
* would be missed for the rest of the session.
|
|
60
|
+
*/
|
|
61
|
+
registerRequestListeners(provider: EIP1193Provider): boolean;
|
|
62
|
+
private buildSignatureEventPayload;
|
|
63
|
+
private buildTransactionEventPayload;
|
|
64
|
+
/**
|
|
65
|
+
* Polls for transaction receipt and emits tx.status = CONFIRMED or REVERTED.
|
|
66
|
+
*/
|
|
67
|
+
private pollTransactionReceipt;
|
|
68
|
+
/**
|
|
69
|
+
* One `transaction` event per call in an EIP-5792 batch.
|
|
70
|
+
*
|
|
71
|
+
* A batch is not a transaction. It maps to several on-chain transactions,
|
|
72
|
+
* so reporting it as one event would understate volume and make revenue and
|
|
73
|
+
* per-contract attribution wrong for every app that adopts smart accounts.
|
|
74
|
+
* Each call is reported on its own, carrying the batch id so the calls can
|
|
75
|
+
* be reassembled downstream.
|
|
76
|
+
*
|
|
77
|
+
* Status is per BATCH, because that is what `wallet_getCallsStatus` reports.
|
|
78
|
+
* When it resolves, every call in the batch moves together, except where
|
|
79
|
+
* per-call receipts say otherwise on a non-atomic batch.
|
|
80
|
+
*/
|
|
81
|
+
private trackBatchedCalls;
|
|
82
|
+
/**
|
|
83
|
+
* How one call in a settled batch ended.
|
|
84
|
+
*
|
|
85
|
+
* A per-call receipt is authoritative where it exists: that is what makes a
|
|
86
|
+
* partially reverted non-atomic batch report honestly rather than tarring
|
|
87
|
+
* every call with the batch's worst outcome. A receipt whose own status is
|
|
88
|
+
* unreadable falls back to the batch verdict rather than being assumed good.
|
|
89
|
+
*
|
|
90
|
+
* The codes are EIP-5792's: 200 confirmed, 400 failed BEFORE landing on
|
|
91
|
+
* chain, 500 reverted, 600 partially reverted. 400 is a rejection, not a
|
|
92
|
+
* revert - nothing was mined, so calling it reverted would misreport gas
|
|
93
|
+
* spent and on-chain activity that never happened.
|
|
94
|
+
*
|
|
95
|
+
* Returns undefined when the call cannot be decided, which happens on 600
|
|
96
|
+
* for a call the wallet gave no receipt for.
|
|
97
|
+
*/
|
|
98
|
+
private batchCallOutcome;
|
|
99
|
+
/**
|
|
100
|
+
* The batch identifier from a `wallet_sendCalls` result.
|
|
101
|
+
*
|
|
102
|
+
* EIP-5792 settled on `{ id }`, but wallets shipped against the earlier
|
|
103
|
+
* draft return a bare string. Both are accepted so a wallet on either
|
|
104
|
+
* version is still grouped.
|
|
105
|
+
*/
|
|
106
|
+
private readBatchId;
|
|
107
|
+
/**
|
|
108
|
+
* Resolve a batch through `wallet_getCallsStatus`.
|
|
109
|
+
*
|
|
110
|
+
* The status codes are EIP-5792's: 100 pending, 200 confirmed, 400 failed
|
|
111
|
+
* before landing, 500 reverted, 600 partially reverted. Anything below 200
|
|
112
|
+
* means keep waiting.
|
|
113
|
+
*
|
|
114
|
+
* A per-call receipt wins over the batch verdict where one exists, which is
|
|
115
|
+
* what makes a partially reverted non-atomic batch report honestly instead
|
|
116
|
+
* of marking every call with the batch's worst outcome.
|
|
117
|
+
*/
|
|
118
|
+
private pollBatchStatus;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=EvmRequestTracker.d.ts.map
|