@formo/analytics 1.35.0 → 1.35.2
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 +134 -0
- package/dist/cjs/src/FormoAnalytics.js +647 -178
- 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/utils/mergeDeepRight.d.ts +22 -0
- package/dist/cjs/src/utils/mergeDeepRight.js +54 -0
- 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/esm/src/FormoAnalytics.d.ts +134 -0
- package/dist/esm/src/FormoAnalytics.js +647 -178
- 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/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/index.umd.min.js +1 -1
- package/package.json +2 -11
- 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
|
@@ -94,6 +94,39 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
94
94
|
evm: {},
|
|
95
95
|
solana: {},
|
|
96
96
|
};
|
|
97
|
+
/**
|
|
98
|
+
* Last known chain per tracked provider, fed by `chainChanged` / `connect`
|
|
99
|
+
* and by a one-off probe at tracking time. Read synchronously when labelling
|
|
100
|
+
* an autocaptured event, so the wallet's request transport is never used for
|
|
101
|
+
* analytics. Weak so an untracked provider can be collected.
|
|
102
|
+
*/
|
|
103
|
+
/**
|
|
104
|
+
* The connect this SDK has actually REPORTED for a provider.
|
|
105
|
+
*
|
|
106
|
+
* Deduplicating on "is an address known" was wrong in both directions.
|
|
107
|
+
* `onConnected` and `onAccountsChanged` both observe one connection, so
|
|
108
|
+
* something has to stop them double-reporting - but an address can be
|
|
109
|
+
* present without a connect ever having been sent: restored from the
|
|
110
|
+
* active-wallet cookie, or reported with an unresolved chain and then
|
|
111
|
+
* refused by `tracking.excludeChains`. Suppressing on address presence lost
|
|
112
|
+
* the connect entirely in those cases.
|
|
113
|
+
*
|
|
114
|
+
* Records what was reported, so a later event can be recognised as a
|
|
115
|
+
* genuine improvement on it rather than a duplicate.
|
|
116
|
+
*/
|
|
117
|
+
this._announcedConnect = new WeakMap();
|
|
118
|
+
this._providerChainIds = new WeakMap();
|
|
119
|
+
/**
|
|
120
|
+
* Bumped on every chain observation, PER PROVIDER. An `eth_chainId` answer
|
|
121
|
+
* that resolves after a newer observation for the same provider must not
|
|
122
|
+
* overwrite it.
|
|
123
|
+
*
|
|
124
|
+
* Deliberately per provider, not per SDK instance: a global counter meant
|
|
125
|
+
* any activity on wallet B discarded a perfectly valid in-flight answer for
|
|
126
|
+
* wallet A, leaving A at chain 0 - and, since an unresolved chain fails
|
|
127
|
+
* closed, dropping all of A's events whenever `excludeChains` is set.
|
|
128
|
+
*/
|
|
129
|
+
this._providerChainGenerations = new WeakMap();
|
|
97
130
|
this._providerListenersMap = new Map();
|
|
98
131
|
/**
|
|
99
132
|
* EIP-6963 provider details discovered through the browser
|
|
@@ -148,7 +181,18 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
148
181
|
this.transaction = this.transaction.bind(this);
|
|
149
182
|
this.detect = this.detect.bind(this);
|
|
150
183
|
this.track = this.track.bind(this);
|
|
184
|
+
this.page = this.page.bind(this);
|
|
185
|
+
this.reset = this.reset.bind(this);
|
|
186
|
+
this.cleanup = this.cleanup.bind(this);
|
|
187
|
+
this.optOutTracking = this.optOutTracking.bind(this);
|
|
188
|
+
this.optInTracking = this.optInTracking.bind(this);
|
|
189
|
+
this.hasOptedOutTracking = this.hasOptedOutTracking.bind(this);
|
|
151
190
|
this.isAutocaptureEnabled = this.isAutocaptureEnabled.bind(this);
|
|
191
|
+
this.syncPrivyActiveChain = this.syncPrivyActiveChain.bind(this);
|
|
192
|
+
this.isTrackingSuppressed = this.isTrackingSuppressed.bind(this);
|
|
193
|
+
this.getTrackedProvidersCount = this.getTrackedProvidersCount.bind(this);
|
|
194
|
+
this.getProviderState = this.getProviderState.bind(this);
|
|
195
|
+
this.syncWalletState = this.syncWalletState.bind(this);
|
|
152
196
|
// Initialize logger with configuration from options
|
|
153
197
|
Logger.init({
|
|
154
198
|
enabled: ((_b = options.logger) === null || _b === void 0 ? void 0 : _b.enabled) || false,
|
|
@@ -211,11 +255,37 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
211
255
|
return this._chainState.evm.provider;
|
|
212
256
|
},
|
|
213
257
|
set: function (value) {
|
|
258
|
+
var previous = this._chainState.evm.provider;
|
|
259
|
+
// A provider that stops being the active one has, from this SDK's point of
|
|
260
|
+
// view, ended its connection - so the connect it reported must stop
|
|
261
|
+
// counting. Otherwise toggling between two installed wallets silently
|
|
262
|
+
// loses every connect after the first: A's stale record suppresses the
|
|
263
|
+
// connect when the user comes back to it.
|
|
264
|
+
//
|
|
265
|
+
// Done in the setter rather than at each switch site because the active
|
|
266
|
+
// provider is reassigned from several paths - `accountsChanged`,
|
|
267
|
+
// `chainChanged`, `connect`, `handleProviderMismatch`, `untrackProvider` -
|
|
268
|
+
// and any one of them missed would reopen the same hole.
|
|
269
|
+
this.forgetConnectRecord(previous, value);
|
|
214
270
|
this._chainState.evm.provider = value;
|
|
215
271
|
},
|
|
216
272
|
enumerable: false,
|
|
217
273
|
configurable: true
|
|
218
274
|
});
|
|
275
|
+
/**
|
|
276
|
+
* Drop a provider's reported-connect record when it stops being active.
|
|
277
|
+
*
|
|
278
|
+
* The active provider is displaced from several places, and not all of them
|
|
279
|
+
* go through the `_provider` setter: `setChainState()` writes
|
|
280
|
+
* `_chainState.evm.provider` directly and `clearChainState()` replaces the
|
|
281
|
+
* whole namespace. Guarding only the setter left A's record alive across a
|
|
282
|
+
* real A-to-B switch, so returning to A was suppressed.
|
|
283
|
+
*/
|
|
284
|
+
FormoAnalytics.prototype.forgetConnectRecord = function (previous, next) {
|
|
285
|
+
if (previous && previous !== next) {
|
|
286
|
+
this._announcedConnect.delete(previous);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
219
289
|
Object.defineProperty(FormoAnalytics.prototype, "_evmAddress", {
|
|
220
290
|
get: function () {
|
|
221
291
|
return this._chainState.evm.address;
|
|
@@ -832,6 +902,18 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
832
902
|
* Opt out of tracking.
|
|
833
903
|
* @returns {void}
|
|
834
904
|
*/
|
|
905
|
+
/**
|
|
906
|
+
* Whether an event carrying this chain would currently be sent.
|
|
907
|
+
*
|
|
908
|
+
* Exposed for integrations that keep their own "already reported" state.
|
|
909
|
+
* `syncWalletState()` can accept a wallet that `trackEvent()` then drops -
|
|
910
|
+
* `tracking: false`, or a chain in `excludeChains` - and an integration that
|
|
911
|
+
* marked it as reported would stay silent about that wallet even after the
|
|
912
|
+
* configuration changed to allow it.
|
|
913
|
+
*/
|
|
914
|
+
FormoAnalytics.prototype.willTrackEvent = function (chainId) {
|
|
915
|
+
return this.shouldTrack(chainId);
|
|
916
|
+
};
|
|
835
917
|
FormoAnalytics.prototype.optOutTracking = function () {
|
|
836
918
|
logger.info("Opting out of tracking");
|
|
837
919
|
// Set opt-out flag in persistent storage using direct cookie access
|
|
@@ -849,9 +931,15 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
849
931
|
* @returns {void}
|
|
850
932
|
*/
|
|
851
933
|
FormoAnalytics.prototype.optInTracking = function () {
|
|
934
|
+
var _a;
|
|
852
935
|
logger.info("Opting back into tracking");
|
|
853
936
|
// Remove opt-out flag
|
|
854
937
|
removeConsentFlag(this.writeKey, CONSENT_OPT_OUT_KEY);
|
|
938
|
+
// A wallet connected while opted out was declined by syncWalletState, and
|
|
939
|
+
// an unchanged wagmi connection produces no status or chain update to
|
|
940
|
+
// retry on. Without this, opting back in leaves that wallet invisible for
|
|
941
|
+
// the rest of the page load.
|
|
942
|
+
(_a = this.wagmiHandler) === null || _a === void 0 ? void 0 : _a.retryAdoption();
|
|
855
943
|
logger.info("Successfully opted back into tracking");
|
|
856
944
|
};
|
|
857
945
|
/**
|
|
@@ -893,20 +981,43 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
893
981
|
// This ensures currentAddress, currentChainId, and _provider are always up-to-date
|
|
894
982
|
// Event emission is controlled conditionally inside the handlers
|
|
895
983
|
this.registerAccountsChangedListener(provider);
|
|
896
|
-
//
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
984
|
+
// `chainChanged` and `connect` are registered UNCONDITIONALLY: they are
|
|
985
|
+
// how this provider's chain is observed, and every signature and
|
|
986
|
+
// transaction has to be labelled with it. Gating registration on
|
|
987
|
+
// `autocapture.chain` conflated observing a chain with reporting one, so
|
|
988
|
+
// `{ chain: false, signature: true }` left the chain frozen at whatever
|
|
989
|
+
// was first seen - a switch to an excluded chain went unnoticed and its
|
|
990
|
+
// signatures were emitted under the old, allowed chain. Whether an
|
|
991
|
+
// event is emitted is decided inside each handler.
|
|
992
|
+
this.registerChainChangedListener(provider);
|
|
900
993
|
if (this.isAutocaptureEnabled("connect")) {
|
|
901
994
|
this.registerConnectListener(provider);
|
|
902
995
|
}
|
|
996
|
+
else {
|
|
997
|
+
// Observation only. The full connect handler calls `getAddress()`,
|
|
998
|
+
// which issues `eth_accounts`, and nothing analytics-only may go on
|
|
999
|
+
// the wallet's transport - a stalled request there sits in front of
|
|
1000
|
+
// the next signature the dapp makes. The chain rides along on the
|
|
1001
|
+
// event itself, so it costs nothing to record.
|
|
1002
|
+
this.registerConnectChainObserver(provider);
|
|
1003
|
+
}
|
|
1004
|
+
// Seed the chain from the provider's own synchronous state if it exposes
|
|
1005
|
+
// one. Deliberately a property read and never an RPC: see
|
|
1006
|
+
// resolveChainIdForProvider for why nothing analytics-only may go on the
|
|
1007
|
+
// wallet's transport.
|
|
1008
|
+
this.seedProviderChainFromState(provider);
|
|
903
1009
|
if (this.isAutocaptureEnabled("signature") || this.isAutocaptureEnabled("transaction")) {
|
|
904
1010
|
this.registerRequestListeners(provider);
|
|
905
1011
|
}
|
|
906
1012
|
else {
|
|
907
1013
|
logger.debug("TrackProvider: Skipping request wrapping (both signature and transaction autocapture disabled)");
|
|
908
1014
|
}
|
|
909
|
-
|
|
1015
|
+
// Registered UNCONDITIONALLY: this listener also ends the provider's
|
|
1016
|
+
// reported-connect record, and with `{ connect: true, disconnect: false }`
|
|
1017
|
+
// a wallet that disconnected and reconnected would otherwise find its
|
|
1018
|
+
// old record still standing and have the new connect suppressed. Whether
|
|
1019
|
+
// a disconnect EVENT is emitted is decided inside the handler.
|
|
1020
|
+
{
|
|
910
1021
|
this.registerDisconnectListener(provider);
|
|
911
1022
|
}
|
|
912
1023
|
// Only add to tracked providers after all listeners are successfully registered
|
|
@@ -1000,6 +1111,10 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1000
1111
|
evmChainId: this._evmChainId,
|
|
1001
1112
|
providerMatch: this._provider === provider,
|
|
1002
1113
|
});
|
|
1114
|
+
// The reported connect ends with the connection, so a genuine
|
|
1115
|
+
// reconnect later reports again rather than being taken for a
|
|
1116
|
+
// duplicate.
|
|
1117
|
+
this._announcedConnect.delete(provider);
|
|
1003
1118
|
if (!this.isAutocaptureEnabled("disconnect")) return [3 /*break*/, 5];
|
|
1004
1119
|
_a.label = 1;
|
|
1005
1120
|
case 1:
|
|
@@ -1148,9 +1263,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1148
1263
|
if (this._provider === provider && address === this._evmAddress) {
|
|
1149
1264
|
return [2 /*return*/];
|
|
1150
1265
|
}
|
|
1151
|
-
|
|
1152
|
-
case 26:
|
|
1153
|
-
nextChainId = _a.sent();
|
|
1266
|
+
nextChainId = this.resolveChainIdForProvider(provider);
|
|
1154
1267
|
wasDisconnected = !this._evmAddress;
|
|
1155
1268
|
// Update state regardless of whether connect *event* tracking is enabled,
|
|
1156
1269
|
// so disconnect events keep valid address/chainId values. (excludeChains is
|
|
@@ -1164,7 +1277,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1164
1277
|
}
|
|
1165
1278
|
providerInfo = this.getProviderInfo(provider);
|
|
1166
1279
|
effectiveChainId = nextChainId || 0;
|
|
1167
|
-
if (this.isAutocaptureEnabled("connect")
|
|
1280
|
+
if (this.isAutocaptureEnabled("connect") &&
|
|
1281
|
+
this.shouldReportConnect(provider, address)) {
|
|
1168
1282
|
logger.info("OnAccountsChanged: Detected wallet connection, emitting connect event", {
|
|
1169
1283
|
chainId: nextChainId,
|
|
1170
1284
|
address: address,
|
|
@@ -1176,6 +1290,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1176
1290
|
if (effectiveChainId === 0) {
|
|
1177
1291
|
logger.info("OnAccountsChanged: Using fallback chainId 0 for connect event");
|
|
1178
1292
|
}
|
|
1293
|
+
this.markConnectReported(provider, address, effectiveChainId);
|
|
1179
1294
|
this.connect({
|
|
1180
1295
|
chainId: effectiveChainId,
|
|
1181
1296
|
address: address,
|
|
@@ -1213,46 +1328,140 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1213
1328
|
};
|
|
1214
1329
|
FormoAnalytics.prototype.onChainChanged = function (provider, chainIdHex) {
|
|
1215
1330
|
return __awaiter(this, void 0, void 0, function () {
|
|
1216
|
-
var nextChainId;
|
|
1331
|
+
var nextChainId, error_3;
|
|
1217
1332
|
return __generator(this, function (_a) {
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1333
|
+
switch (_a.label) {
|
|
1334
|
+
case 0:
|
|
1335
|
+
logger.info("onChainChanged", chainIdHex);
|
|
1336
|
+
nextChainId = parseChainId(chainIdHex);
|
|
1337
|
+
// Record it for THIS provider regardless of which one is active. This is
|
|
1338
|
+
// the only way an autocaptured event from a non-active wallet can learn
|
|
1339
|
+
// its chain without putting an RPC on that wallet's transport.
|
|
1340
|
+
this.rememberProviderChain(provider, nextChainId);
|
|
1341
|
+
// Beyond that, a chain event from a NON-active provider is observation
|
|
1342
|
+
// only when chain autocapture is off.
|
|
1343
|
+
//
|
|
1344
|
+
// This listener is now registered unconditionally, so that a signature can
|
|
1345
|
+
// be labelled with its signer's chain. `handleProviderMismatch()` treats a
|
|
1346
|
+
// chain event from another wallet as a wallet switch and clears the active
|
|
1347
|
+
// wallet's address and chain. That is the established behaviour of the
|
|
1348
|
+
// chain feature and stays exactly as it was, but it must not start firing
|
|
1349
|
+
// for apps that never asked for chain tracking: a second wallet switching
|
|
1350
|
+
// network would silently erase the active wallet's attribution.
|
|
1351
|
+
// Observation only when chain autocapture is off, whether or not an
|
|
1352
|
+
// active provider has been established yet.
|
|
1353
|
+
//
|
|
1354
|
+
// `isProviderMismatch()` is false while `_provider` is undefined, which is
|
|
1355
|
+
// exactly the state left by restoring a wallet from the active-wallet
|
|
1356
|
+
// cookie. A background wallet's `chainChanged` could therefore claim the
|
|
1357
|
+
// active slot and overwrite the restored wallet's chain - suppressing
|
|
1358
|
+
// allowed events, or letting excluded ones through. The active provider is
|
|
1359
|
+
// established by an actual account/connect/request association, not by
|
|
1360
|
+
// another wallet changing network.
|
|
1361
|
+
if (!this.isAutocaptureEnabled("chain") && provider !== this._provider) {
|
|
1362
|
+
return [2 /*return*/];
|
|
1363
|
+
}
|
|
1364
|
+
// Only handle chain changes for the active provider (or if none is set yet)
|
|
1365
|
+
if (this.isProviderMismatch(provider)) {
|
|
1366
|
+
this.handleProviderMismatch(provider);
|
|
1367
|
+
}
|
|
1368
|
+
// Chain changes only matter for connected users
|
|
1369
|
+
if (!this._evmAddress) {
|
|
1370
|
+
logger.info("OnChainChanged: No current address, user appears disconnected");
|
|
1371
|
+
return [2 /*return*/, Promise.resolve()];
|
|
1372
|
+
}
|
|
1373
|
+
// Set provider if none exists
|
|
1374
|
+
if (!this._provider) {
|
|
1375
|
+
this._provider = provider;
|
|
1376
|
+
}
|
|
1377
|
+
this.setChainState('evm', { chainId: nextChainId });
|
|
1378
|
+
_a.label = 1;
|
|
1379
|
+
case 1:
|
|
1380
|
+
_a.trys.push([1, 5, , 6]);
|
|
1381
|
+
if (!this.isAutocaptureEnabled("chain")) return [3 /*break*/, 3];
|
|
1382
|
+
// Awaited, so a failing emission is caught below rather than escaping
|
|
1383
|
+
// as an unhandled rejection out of the provider's event listener.
|
|
1384
|
+
// `return`ing the promise left the catch here unreachable.
|
|
1385
|
+
return [4 /*yield*/, this.chain({
|
|
1238
1386
|
chainId: nextChainId,
|
|
1239
1387
|
address: this._evmAddress,
|
|
1240
1388
|
})];
|
|
1241
|
-
|
|
1242
|
-
|
|
1389
|
+
case 2:
|
|
1390
|
+
// Awaited, so a failing emission is caught below rather than escaping
|
|
1391
|
+
// as an unhandled rejection out of the provider's event listener.
|
|
1392
|
+
// `return`ing the promise left the catch here unreachable.
|
|
1393
|
+
_a.sent();
|
|
1394
|
+
return [3 /*break*/, 4];
|
|
1395
|
+
case 3:
|
|
1243
1396
|
logger.debug("OnChainChanged: Chain event skipped (autocapture.chain: false)", {
|
|
1244
1397
|
chainId: this._evmChainId,
|
|
1245
1398
|
address: this._evmAddress,
|
|
1246
1399
|
});
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1400
|
+
_a.label = 4;
|
|
1401
|
+
case 4: return [3 /*break*/, 6];
|
|
1402
|
+
case 5:
|
|
1403
|
+
error_3 = _a.sent();
|
|
1404
|
+
logger.error("OnChainChanged: Failed to emit chain event:", error_3);
|
|
1405
|
+
return [3 /*break*/, 6];
|
|
1406
|
+
case 6: return [2 /*return*/];
|
|
1251
1407
|
}
|
|
1252
|
-
return [2 /*return*/];
|
|
1253
1408
|
});
|
|
1254
1409
|
});
|
|
1255
1410
|
};
|
|
1411
|
+
/**
|
|
1412
|
+
* Record a provider's chain from its `connect` event, and nothing else.
|
|
1413
|
+
*
|
|
1414
|
+
* Used when connect autocapture is off. `connect` carries `chainId` in its
|
|
1415
|
+
* payload, so this needs no RPC - unlike the full handler, which resolves
|
|
1416
|
+
* the account.
|
|
1417
|
+
*/
|
|
1418
|
+
FormoAnalytics.prototype.registerConnectChainObserver = function (provider) {
|
|
1419
|
+
var _this = this;
|
|
1420
|
+
var listener = function () {
|
|
1421
|
+
var args = [];
|
|
1422
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
1423
|
+
args[_i] = arguments[_i];
|
|
1424
|
+
}
|
|
1425
|
+
var connection = args[0];
|
|
1426
|
+
if (typeof (connection === null || connection === void 0 ? void 0 : connection.chainId) !== "string")
|
|
1427
|
+
return;
|
|
1428
|
+
_this.rememberProviderChain(provider, parseChainId(connection.chainId));
|
|
1429
|
+
};
|
|
1430
|
+
provider.on("connect", listener);
|
|
1431
|
+
this.addProviderListener(provider, "connect", listener);
|
|
1432
|
+
};
|
|
1433
|
+
/**
|
|
1434
|
+
* Whether a connect for this wallet still needs reporting.
|
|
1435
|
+
*
|
|
1436
|
+
* True when nothing has been reported for this provider, or when the account
|
|
1437
|
+
* changed. A wallet already reported is not reported again.
|
|
1438
|
+
*
|
|
1439
|
+
* Deliberately does NOT re-report to correct a chain. When `accountsChanged`
|
|
1440
|
+
* wins the race on a provider that exposes no synchronous `chainId`, the
|
|
1441
|
+
* connect carries 0 - honestly, since the chain is unknown at that instant -
|
|
1442
|
+
* and the `connect` payload that follows knows the real one. Emitting again
|
|
1443
|
+
* to relabel would mean two connects for one connection, which is the bug
|
|
1444
|
+
* this whole path exists to prevent. That payload still corrects
|
|
1445
|
+
* `currentChainId`, so everything after it is attributed properly.
|
|
1446
|
+
*/
|
|
1447
|
+
FormoAnalytics.prototype.shouldReportConnect = function (provider, address) {
|
|
1448
|
+
var reported = this._announcedConnect.get(provider);
|
|
1449
|
+
if (!reported)
|
|
1450
|
+
return true;
|
|
1451
|
+
return reported.address.toLowerCase() !== address.toLowerCase();
|
|
1452
|
+
};
|
|
1453
|
+
/**
|
|
1454
|
+
* Record a connect as reported - but only if it will actually be sent.
|
|
1455
|
+
*
|
|
1456
|
+
* `connect()` passes through `shouldTrack()`, which refuses an unresolvable
|
|
1457
|
+
* chain when `tracking.excludeChains` is configured. Marking a refused event
|
|
1458
|
+
* as reported would suppress the authoritative one that follows.
|
|
1459
|
+
*/
|
|
1460
|
+
FormoAnalytics.prototype.markConnectReported = function (provider, address, chainId) {
|
|
1461
|
+
if (!this.willTrackEvent(chainId))
|
|
1462
|
+
return;
|
|
1463
|
+
this._announcedConnect.set(provider, { address: address, chainId: chainId });
|
|
1464
|
+
};
|
|
1256
1465
|
FormoAnalytics.prototype.registerConnectListener = function (provider) {
|
|
1257
1466
|
var _this = this;
|
|
1258
1467
|
logger.info("registerConnectListener");
|
|
@@ -1277,6 +1486,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1277
1486
|
case 0:
|
|
1278
1487
|
if (this._provider !== provider)
|
|
1279
1488
|
return [2 /*return*/];
|
|
1489
|
+
// As in the accountsChanged disconnect path: the reported connect ends
|
|
1490
|
+
// with the connection.
|
|
1491
|
+
this._announcedConnect.delete(provider);
|
|
1280
1492
|
logger.info("OnDisconnect: Wallet disconnect event received, current state:", {
|
|
1281
1493
|
currentAddress: this._evmAddress,
|
|
1282
1494
|
currentChainId: this._evmChainId,
|
|
@@ -1324,6 +1536,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1324
1536
|
if (!(connection === null || connection === void 0 ? void 0 : connection.chainId) || typeof connection.chainId !== "string")
|
|
1325
1537
|
return [2 /*return*/];
|
|
1326
1538
|
chainId = parseChainId(connection.chainId);
|
|
1539
|
+
// Record it for this provider before anything can bail out below.
|
|
1540
|
+
this.rememberProviderChain(provider, chainId);
|
|
1327
1541
|
return [4 /*yield*/, this.getAddress(provider)];
|
|
1328
1542
|
case 2:
|
|
1329
1543
|
address = _a.sent();
|
|
@@ -1348,8 +1562,18 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1348
1562
|
});
|
|
1349
1563
|
}
|
|
1350
1564
|
}
|
|
1351
|
-
// Conditionally emit connect event based on tracking configuration
|
|
1352
|
-
|
|
1565
|
+
// Conditionally emit connect event based on tracking configuration.
|
|
1566
|
+
//
|
|
1567
|
+
// Both handlers observe one connection, so `shouldReportConnect()`
|
|
1568
|
+
// decides which of them reports it. It keys on what was actually
|
|
1569
|
+
// REPORTED, not on whether an address is known: an address can be
|
|
1570
|
+
// present with no connect ever sent - restored from the active-wallet
|
|
1571
|
+
// cookie, or reported with an unresolved chain and then refused by
|
|
1572
|
+
// `excludeChains` - and this payload carries the authoritative chain,
|
|
1573
|
+
// so it must be able to supersede such a report.
|
|
1574
|
+
if (isActiveProvider &&
|
|
1575
|
+
this._evmAddress &&
|
|
1576
|
+
this.shouldReportConnect(provider, address)) {
|
|
1353
1577
|
providerInfo = this.getProviderInfo(provider);
|
|
1354
1578
|
effectiveChainId = chainId || 0;
|
|
1355
1579
|
if (this.isAutocaptureEnabled("connect")) {
|
|
@@ -1364,6 +1588,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1364
1588
|
if (effectiveChainId === 0) {
|
|
1365
1589
|
logger.info("OnConnected: Using fallback chainId 0 for connect event");
|
|
1366
1590
|
}
|
|
1591
|
+
this.markConnectReported(provider, address, effectiveChainId);
|
|
1367
1592
|
this.connect({
|
|
1368
1593
|
chainId: effectiveChainId,
|
|
1369
1594
|
address: address,
|
|
@@ -1420,162 +1645,209 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1420
1645
|
}
|
|
1421
1646
|
var request = provider.request.bind(provider);
|
|
1422
1647
|
var wrappedRequest = function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
|
|
1423
|
-
var
|
|
1648
|
+
var generation_1, responsePromise, capturedChainId_1, response_1, error_4, rpcError, txPromise, txChainId_1, transactionHash_1, error_5, rpcError;
|
|
1424
1649
|
var _this = this;
|
|
1650
|
+
var _c;
|
|
1425
1651
|
var method = _b.method, params = _b.params;
|
|
1426
1652
|
return __generator(this, function (_d) {
|
|
1427
1653
|
switch (_d.label) {
|
|
1428
1654
|
case 0:
|
|
1655
|
+
// Learn the chain from a call the APP was making anyway.
|
|
1656
|
+
//
|
|
1657
|
+
// A standards-compliant provider need not expose a synchronous `chainId`
|
|
1658
|
+
// property, and if it connected before the SDK initialised, its
|
|
1659
|
+
// `connect` event is never replayed. Such a provider stayed unknown -
|
|
1660
|
+
// reported as chain 0, and with `excludeChains` configured its events
|
|
1661
|
+
// were dropped even on an allowed chain. This adds no request of its
|
|
1662
|
+
// own; it only reads the answer to one the dapp already sent.
|
|
1663
|
+
if (method === "eth_chainId") {
|
|
1664
|
+
generation_1 = (_c = this._providerChainGenerations.get(provider)) !== null && _c !== void 0 ? _c : 0;
|
|
1665
|
+
return [2 /*return*/, request({ method: method, params: params }).then(function (result) {
|
|
1666
|
+
var _a;
|
|
1667
|
+
// A `chainChanged` for THIS provider may have landed while this was
|
|
1668
|
+
// in flight. It is newer by definition, so it must not be
|
|
1669
|
+
// overwritten by this answer.
|
|
1670
|
+
if (generation_1 === ((_a = _this._providerChainGenerations.get(provider)) !== null && _a !== void 0 ? _a : 0) &&
|
|
1671
|
+
typeof result === "string") {
|
|
1672
|
+
_this.rememberProviderChain(provider, parseChainId(result));
|
|
1673
|
+
}
|
|
1674
|
+
return result;
|
|
1675
|
+
})];
|
|
1676
|
+
}
|
|
1429
1677
|
if (!(Array.isArray(params) &&
|
|
1430
|
-
["eth_signTypedData_v4", "personal_sign"].includes(method))) return [3 /*break*/,
|
|
1678
|
+
["eth_signTypedData_v4", "personal_sign"].includes(method))) return [3 /*break*/, 4];
|
|
1431
1679
|
if (!this.isAutocaptureEnabled("signature")) {
|
|
1432
1680
|
logger.debug("Signature event skipped (autocapture.signature: false)", { method: method });
|
|
1433
1681
|
return [2 /*return*/, request({ method: method, params: params })];
|
|
1434
1682
|
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
_d.label = 2;
|
|
1441
|
-
case 2:
|
|
1442
|
-
capturedChainId_1 = _c;
|
|
1683
|
+
responsePromise = request({ method: method, params: params });
|
|
1684
|
+
// Attach a no-op handler now so a rejection arriving before the await
|
|
1685
|
+
// below is never reported as unhandled. The real handling is there.
|
|
1686
|
+
responsePromise.catch(function () { return undefined; });
|
|
1687
|
+
capturedChainId_1 = this.resolveChainIdForProvider(provider);
|
|
1443
1688
|
// Fire-and-forget tracking
|
|
1444
1689
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1690
|
+
var e_4;
|
|
1445
1691
|
return __generator(this, function (_a) {
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1692
|
+
switch (_a.label) {
|
|
1693
|
+
case 0:
|
|
1694
|
+
_a.trys.push([0, 2, , 3]);
|
|
1695
|
+
return [4 /*yield*/, this.signature(__assign({ status: SignatureStatus.REQUESTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)))];
|
|
1696
|
+
case 1:
|
|
1697
|
+
_a.sent();
|
|
1698
|
+
return [3 /*break*/, 3];
|
|
1699
|
+
case 2:
|
|
1700
|
+
e_4 = _a.sent();
|
|
1701
|
+
logger.error("Formo: Failed to track signature request", e_4);
|
|
1702
|
+
return [3 /*break*/, 3];
|
|
1703
|
+
case 3: return [2 /*return*/];
|
|
1451
1704
|
}
|
|
1452
|
-
return [2 /*return*/];
|
|
1453
1705
|
});
|
|
1454
1706
|
}); })();
|
|
1455
|
-
_d.label =
|
|
1456
|
-
case
|
|
1457
|
-
_d.trys.push([
|
|
1458
|
-
return [4 /*yield*/,
|
|
1459
|
-
case
|
|
1460
|
-
response_1 =
|
|
1707
|
+
_d.label = 1;
|
|
1708
|
+
case 1:
|
|
1709
|
+
_d.trys.push([1, 3, , 4]);
|
|
1710
|
+
return [4 /*yield*/, responsePromise];
|
|
1711
|
+
case 2:
|
|
1712
|
+
response_1 = _d.sent();
|
|
1461
1713
|
// Track signature confirmation only for truthy responses
|
|
1462
1714
|
if (response_1) {
|
|
1463
1715
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1716
|
+
var e_5;
|
|
1464
1717
|
return __generator(this, function (_a) {
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1718
|
+
switch (_a.label) {
|
|
1719
|
+
case 0:
|
|
1720
|
+
_a.trys.push([0, 2, , 3]);
|
|
1721
|
+
return [4 /*yield*/, this.signature(__assign({ status: SignatureStatus.CONFIRMED }, this.buildSignatureEventPayload(method, params, response_1, capturedChainId_1, provider)))];
|
|
1722
|
+
case 1:
|
|
1723
|
+
_a.sent();
|
|
1724
|
+
return [3 /*break*/, 3];
|
|
1725
|
+
case 2:
|
|
1726
|
+
e_5 = _a.sent();
|
|
1727
|
+
logger.error("Formo: Failed to track signature confirmation", e_5);
|
|
1728
|
+
return [3 /*break*/, 3];
|
|
1729
|
+
case 3: return [2 /*return*/];
|
|
1470
1730
|
}
|
|
1471
|
-
return [2 /*return*/];
|
|
1472
1731
|
});
|
|
1473
1732
|
}); })();
|
|
1474
1733
|
}
|
|
1475
1734
|
return [2 /*return*/, response_1];
|
|
1476
|
-
case
|
|
1477
|
-
|
|
1478
|
-
rpcError =
|
|
1735
|
+
case 3:
|
|
1736
|
+
error_4 = _d.sent();
|
|
1737
|
+
rpcError = error_4;
|
|
1479
1738
|
if ((rpcError === null || rpcError === void 0 ? void 0 : rpcError.code) === 4001) {
|
|
1480
1739
|
// Use the already cast rpcError to avoid duplication
|
|
1481
1740
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1741
|
+
var e_6;
|
|
1482
1742
|
return __generator(this, function (_a) {
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1743
|
+
switch (_a.label) {
|
|
1744
|
+
case 0:
|
|
1745
|
+
_a.trys.push([0, 2, , 3]);
|
|
1746
|
+
return [4 /*yield*/, this.signature(__assign({ status: SignatureStatus.REJECTED }, this.buildSignatureEventPayload(method, params, undefined, capturedChainId_1, provider)))];
|
|
1747
|
+
case 1:
|
|
1748
|
+
_a.sent();
|
|
1749
|
+
return [3 /*break*/, 3];
|
|
1750
|
+
case 2:
|
|
1751
|
+
e_6 = _a.sent();
|
|
1752
|
+
logger.error("Formo: Failed to track signature rejection", e_6);
|
|
1753
|
+
return [3 /*break*/, 3];
|
|
1754
|
+
case 3: return [2 /*return*/];
|
|
1488
1755
|
}
|
|
1489
|
-
return [2 /*return*/];
|
|
1490
1756
|
});
|
|
1491
1757
|
}); })();
|
|
1492
1758
|
}
|
|
1493
|
-
throw
|
|
1494
|
-
case
|
|
1759
|
+
throw error_4;
|
|
1760
|
+
case 4:
|
|
1495
1761
|
if (!(Array.isArray(params) &&
|
|
1496
1762
|
method === "eth_sendTransaction" &&
|
|
1497
|
-
params[0])) return [3 /*break*/,
|
|
1763
|
+
params[0])) return [3 /*break*/, 8];
|
|
1498
1764
|
if (!this.isAutocaptureEnabled("transaction")) {
|
|
1499
1765
|
logger.debug("Transaction event skipped (autocapture.transaction: false)", { method: method });
|
|
1500
1766
|
return [2 /*return*/, request({ method: method, params: params })];
|
|
1501
1767
|
}
|
|
1768
|
+
txPromise = request({ method: method, params: params });
|
|
1769
|
+
txPromise.catch(function () { return undefined; });
|
|
1770
|
+
txChainId_1 = this.resolveChainIdForProvider(provider);
|
|
1502
1771
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1503
|
-
var payload,
|
|
1772
|
+
var payload, e_7;
|
|
1504
1773
|
return __generator(this, function (_a) {
|
|
1505
1774
|
switch (_a.label) {
|
|
1506
1775
|
case 0:
|
|
1507
|
-
_a.trys.push([0,
|
|
1508
|
-
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider)];
|
|
1776
|
+
_a.trys.push([0, 3, , 4]);
|
|
1777
|
+
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
1509
1778
|
case 1:
|
|
1510
1779
|
payload = _a.sent();
|
|
1511
|
-
this.transaction(__assign({ status: TransactionStatus.STARTED }, payload));
|
|
1512
|
-
return [3 /*break*/, 3];
|
|
1780
|
+
return [4 /*yield*/, this.transaction(__assign({ status: TransactionStatus.STARTED }, payload))];
|
|
1513
1781
|
case 2:
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1782
|
+
_a.sent();
|
|
1783
|
+
return [3 /*break*/, 4];
|
|
1784
|
+
case 3:
|
|
1785
|
+
e_7 = _a.sent();
|
|
1786
|
+
logger.error("Formo: Failed to track transaction start", e_7);
|
|
1787
|
+
return [3 /*break*/, 4];
|
|
1788
|
+
case 4: return [2 /*return*/];
|
|
1518
1789
|
}
|
|
1519
1790
|
});
|
|
1520
1791
|
}); })();
|
|
1521
|
-
_d.label =
|
|
1522
|
-
case
|
|
1523
|
-
_d.trys.push([
|
|
1524
|
-
return [4 /*yield*/,
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
})];
|
|
1528
|
-
case 8:
|
|
1529
|
-
transactionHash_1 = (_d.sent());
|
|
1792
|
+
_d.label = 5;
|
|
1793
|
+
case 5:
|
|
1794
|
+
_d.trys.push([5, 7, , 8]);
|
|
1795
|
+
return [4 /*yield*/, txPromise];
|
|
1796
|
+
case 6:
|
|
1797
|
+
transactionHash_1 = _d.sent();
|
|
1530
1798
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1531
|
-
var payload,
|
|
1799
|
+
var payload, e_8;
|
|
1532
1800
|
return __generator(this, function (_a) {
|
|
1533
1801
|
switch (_a.label) {
|
|
1534
1802
|
case 0:
|
|
1535
|
-
_a.trys.push([0,
|
|
1536
|
-
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider)];
|
|
1803
|
+
_a.trys.push([0, 3, , 4]);
|
|
1804
|
+
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
1537
1805
|
case 1:
|
|
1538
1806
|
payload = _a.sent();
|
|
1539
|
-
this.transaction(__assign(__assign({ status: TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }));
|
|
1807
|
+
return [4 /*yield*/, this.transaction(__assign(__assign({ status: TransactionStatus.BROADCASTED }, payload), { transactionHash: transactionHash_1 }))];
|
|
1808
|
+
case 2:
|
|
1809
|
+
_a.sent();
|
|
1540
1810
|
// Start async polling for transaction receipt
|
|
1541
1811
|
this.pollTransactionReceipt(provider, transactionHash_1, payload);
|
|
1542
|
-
return [3 /*break*/,
|
|
1543
|
-
case
|
|
1544
|
-
|
|
1545
|
-
logger.error("Formo: Failed to track transaction broadcast",
|
|
1546
|
-
return [3 /*break*/,
|
|
1547
|
-
case
|
|
1812
|
+
return [3 /*break*/, 4];
|
|
1813
|
+
case 3:
|
|
1814
|
+
e_8 = _a.sent();
|
|
1815
|
+
logger.error("Formo: Failed to track transaction broadcast", e_8);
|
|
1816
|
+
return [3 /*break*/, 4];
|
|
1817
|
+
case 4: return [2 /*return*/];
|
|
1548
1818
|
}
|
|
1549
1819
|
});
|
|
1550
1820
|
}); })();
|
|
1551
1821
|
return [2 /*return*/, transactionHash_1];
|
|
1552
|
-
case
|
|
1553
|
-
|
|
1554
|
-
rpcError =
|
|
1822
|
+
case 7:
|
|
1823
|
+
error_5 = _d.sent();
|
|
1824
|
+
rpcError = error_5;
|
|
1555
1825
|
if ((rpcError === null || rpcError === void 0 ? void 0 : rpcError.code) === 4001) {
|
|
1556
1826
|
// Use the already cast rpcError to avoid duplication
|
|
1557
1827
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1558
|
-
var payload,
|
|
1828
|
+
var payload, e_9;
|
|
1559
1829
|
return __generator(this, function (_a) {
|
|
1560
1830
|
switch (_a.label) {
|
|
1561
1831
|
case 0:
|
|
1562
|
-
_a.trys.push([0,
|
|
1563
|
-
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider)];
|
|
1832
|
+
_a.trys.push([0, 3, , 4]);
|
|
1833
|
+
return [4 /*yield*/, this.buildTransactionEventPayload(params, provider, txChainId_1)];
|
|
1564
1834
|
case 1:
|
|
1565
1835
|
payload = _a.sent();
|
|
1566
|
-
this.transaction(__assign({ status: TransactionStatus.REJECTED }, payload));
|
|
1567
|
-
return [3 /*break*/, 3];
|
|
1836
|
+
return [4 /*yield*/, this.transaction(__assign({ status: TransactionStatus.REJECTED }, payload))];
|
|
1568
1837
|
case 2:
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1838
|
+
_a.sent();
|
|
1839
|
+
return [3 /*break*/, 4];
|
|
1840
|
+
case 3:
|
|
1841
|
+
e_9 = _a.sent();
|
|
1842
|
+
logger.error("Formo: Failed to track transaction rejection", e_9);
|
|
1843
|
+
return [3 /*break*/, 4];
|
|
1844
|
+
case 4: return [2 /*return*/];
|
|
1573
1845
|
}
|
|
1574
1846
|
});
|
|
1575
1847
|
}); })();
|
|
1576
1848
|
}
|
|
1577
|
-
throw
|
|
1578
|
-
case
|
|
1849
|
+
throw error_5;
|
|
1850
|
+
case 8: return [2 /*return*/, request({ method: method, params: params })];
|
|
1579
1851
|
}
|
|
1580
1852
|
});
|
|
1581
1853
|
}); };
|
|
@@ -1593,9 +1865,16 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1593
1865
|
};
|
|
1594
1866
|
FormoAnalytics.prototype.onLocationChange = function () {
|
|
1595
1867
|
return __awaiter(this, void 0, void 0, function () {
|
|
1596
|
-
|
|
1868
|
+
var _a;
|
|
1869
|
+
return __generator(this, function (_b) {
|
|
1597
1870
|
if (this._currentUrl !== window.location.href) {
|
|
1598
1871
|
this._currentUrl = window.location.href;
|
|
1872
|
+
// Host/path exclusions are evaluated per navigation, so a SPA can leave
|
|
1873
|
+
// an excluded route and become trackable without any wallet event
|
|
1874
|
+
// firing. The wagmi handler only observes *changes*, so an unchanged
|
|
1875
|
+
// connection it was forced to decline earlier would stay invisible for
|
|
1876
|
+
// the rest of the page load. Give it a chance to adopt it now.
|
|
1877
|
+
(_a = this.wagmiHandler) === null || _a === void 0 ? void 0 : _a.retryAdoption();
|
|
1599
1878
|
this.trackPageHit();
|
|
1600
1879
|
}
|
|
1601
1880
|
return [2 /*return*/];
|
|
@@ -1666,7 +1945,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1666
1945
|
if (_this._pageHooksDisposed)
|
|
1667
1946
|
return;
|
|
1668
1947
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1669
|
-
var
|
|
1948
|
+
var e_10;
|
|
1670
1949
|
return __generator(this, function (_a) {
|
|
1671
1950
|
switch (_a.label) {
|
|
1672
1951
|
case 0:
|
|
@@ -1679,8 +1958,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1679
1958
|
_a.sent();
|
|
1680
1959
|
return [3 /*break*/, 3];
|
|
1681
1960
|
case 2:
|
|
1682
|
-
|
|
1683
|
-
logger.error("Formo: Failed to track page hit",
|
|
1961
|
+
e_10 = _a.sent();
|
|
1962
|
+
logger.error("Formo: Failed to track page hit", e_10);
|
|
1684
1963
|
return [3 /*break*/, 3];
|
|
1685
1964
|
case 3: return [2 /*return*/];
|
|
1686
1965
|
}
|
|
@@ -1693,12 +1972,17 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1693
1972
|
};
|
|
1694
1973
|
FormoAnalytics.prototype.trackEvent = function (type, payload, properties, context, callback) {
|
|
1695
1974
|
return __awaiter(this, void 0, void 0, function () {
|
|
1696
|
-
var
|
|
1975
|
+
var error_6;
|
|
1697
1976
|
return __generator(this, function (_a) {
|
|
1698
1977
|
switch (_a.label) {
|
|
1699
1978
|
case 0:
|
|
1700
1979
|
_a.trys.push([0, 2, , 3]);
|
|
1701
|
-
|
|
1980
|
+
// Gate on the chain the event actually carries. `connect`, `disconnect`,
|
|
1981
|
+
// `chain`, `signature` and `transaction` all put one in the payload, and
|
|
1982
|
+
// it is authoritative: it can name a provider or a wagmi mutation chain
|
|
1983
|
+
// that is not the active one. Events without a chain (page, track,
|
|
1984
|
+
// identify) fall back to the central value.
|
|
1985
|
+
if (!this.shouldTrack(payload === null || payload === void 0 ? void 0 : payload.chainId)) {
|
|
1702
1986
|
logger.info("Skipping ".concat(type, " event due to tracking configuration"));
|
|
1703
1987
|
return [2 /*return*/];
|
|
1704
1988
|
}
|
|
@@ -1707,8 +1991,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1707
1991
|
_a.sent();
|
|
1708
1992
|
return [3 /*break*/, 3];
|
|
1709
1993
|
case 2:
|
|
1710
|
-
|
|
1711
|
-
logger.error("Error tracking event:",
|
|
1994
|
+
error_6 = _a.sent();
|
|
1995
|
+
logger.error("Error tracking event:", error_6);
|
|
1712
1996
|
return [3 /*break*/, 3];
|
|
1713
1997
|
case 3: return [2 /*return*/];
|
|
1714
1998
|
}
|
|
@@ -1745,16 +2029,24 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1745
2029
|
* an options object with `excludeChains` set, and only once a chain id is
|
|
1746
2030
|
* known.
|
|
1747
2031
|
*/
|
|
1748
|
-
FormoAnalytics.prototype.isCurrentChainExcluded = function () {
|
|
2032
|
+
FormoAnalytics.prototype.isCurrentChainExcluded = function (eventChainId) {
|
|
1749
2033
|
if (this.options.tracking === null ||
|
|
1750
2034
|
typeof this.options.tracking !== "object" ||
|
|
1751
2035
|
Array.isArray(this.options.tracking)) {
|
|
1752
2036
|
return false;
|
|
1753
2037
|
}
|
|
1754
2038
|
var _a = this.options.tracking.excludeChains, excludeChains = _a === void 0 ? [] : _a;
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
2039
|
+
if (excludeChains.length === 0)
|
|
2040
|
+
return false;
|
|
2041
|
+
// Mirrors `shouldTrack()`: the event's own chain wins when it has one,
|
|
2042
|
+
// and an unresolvable chain on a known wallet counts as excluded rather
|
|
2043
|
+
// than allowed.
|
|
2044
|
+
var chainToCheck = eventChainId !== null && eventChainId !== void 0 ? eventChainId : this.currentChainId;
|
|
2045
|
+
if (chainToCheck === 0)
|
|
2046
|
+
return true;
|
|
2047
|
+
if (chainToCheck === undefined)
|
|
2048
|
+
return false;
|
|
2049
|
+
return excludeChains.includes(chainToCheck);
|
|
1758
2050
|
};
|
|
1759
2051
|
/**
|
|
1760
2052
|
* Whether the current environment is excluded from tracking - the visitor's
|
|
@@ -1849,7 +2141,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1849
2141
|
* Determines if tracking should be enabled based on configuration and consent
|
|
1850
2142
|
* @returns {boolean} True if tracking should be enabled
|
|
1851
2143
|
*/
|
|
1852
|
-
FormoAnalytics.prototype.shouldTrack = function () {
|
|
2144
|
+
FormoAnalytics.prototype.shouldTrack = function (eventChainId) {
|
|
1853
2145
|
// First check if user has opted out of tracking
|
|
1854
2146
|
if (this.hasOptedOutTracking()) {
|
|
1855
2147
|
return false;
|
|
@@ -1868,11 +2160,42 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1868
2160
|
if (this.isCurrentEnvironmentExcluded()) {
|
|
1869
2161
|
return false;
|
|
1870
2162
|
}
|
|
1871
|
-
// Check chainId exclusions
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
2163
|
+
// Check chainId exclusions.
|
|
2164
|
+
//
|
|
2165
|
+
// The event's OWN chain wins over `currentChainId`. They differ whenever
|
|
2166
|
+
// the event did not come from the active provider: a second wallet
|
|
2167
|
+
// signing through its own provider, or a wagmi mutation that names an
|
|
2168
|
+
// explicit chain. Reading only the central field there would emit an
|
|
2169
|
+
// event that is labelled with an excluded chain, which is precisely what
|
|
2170
|
+
// the exclusion forbids - and would drop an allowed event whenever the
|
|
2171
|
+
// active provider happened to sit on an excluded chain.
|
|
2172
|
+
var chainToCheck = eventChainId !== null && eventChainId !== void 0 ? eventChainId : this.currentChainId;
|
|
2173
|
+
if (excludeChains.length > 0) {
|
|
2174
|
+
// Fail CLOSED on an unknown chain. `resolveChainIdForProvider` reports
|
|
2175
|
+
// 0 when it has never heard a chain from the signing wallet, and 0 is
|
|
2176
|
+
// in no exclusion list, so treating it as "not excluded" would let
|
|
2177
|
+
// exactly the events an operator excluded through - the wallet on the
|
|
2178
|
+
// excluded chain is often the one we know least about. An explicit
|
|
2179
|
+
// exclusion is a directive, so an unresolvable chain is refused.
|
|
2180
|
+
//
|
|
2181
|
+
// This covers the central value too, not just an explicit event
|
|
2182
|
+
// chain: `page`, `track` and `identify` carry no chain of their own
|
|
2183
|
+
// and fall back to `currentChainId`, so an unknown chain there would
|
|
2184
|
+
// otherwise send wallet-attributed events for a wallet that may well
|
|
2185
|
+
// be sitting on an excluded chain.
|
|
2186
|
+
// Deliberately keyed on 0 and NOT on `undefined`. 0 is the explicit
|
|
2187
|
+
// "we asked and could not tell" marker. `undefined` means no chain
|
|
2188
|
+
// state yet, which is a legitimate transient - the Privy path
|
|
2189
|
+
// reconciles a Solana wallet through exactly that state - and
|
|
2190
|
+
// refusing it would drop real events.
|
|
2191
|
+
//
|
|
2192
|
+
// `backfillActiveWallet()` never persists 0, so an unresolvable chain
|
|
2193
|
+
// cannot leak into `currentChainId` and reach the unscoped events
|
|
2194
|
+
// (page / track / identify) that fall back to it.
|
|
2195
|
+
if (chainToCheck === 0)
|
|
2196
|
+
return false;
|
|
2197
|
+
if (chainToCheck && excludeChains.includes(chainToCheck))
|
|
2198
|
+
return false;
|
|
1876
2199
|
}
|
|
1877
2200
|
// If nothing is excluded, tracking is enabled
|
|
1878
2201
|
return true;
|
|
@@ -1956,7 +2279,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1956
2279
|
_this.trackProviders(newDetails);
|
|
1957
2280
|
// Detect newly discovered wallets (session de-dupes) with error handling
|
|
1958
2281
|
(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1959
|
-
var
|
|
2282
|
+
var e_11;
|
|
1960
2283
|
return __generator(this, function (_a) {
|
|
1961
2284
|
switch (_a.label) {
|
|
1962
2285
|
case 0:
|
|
@@ -1966,8 +2289,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
1966
2289
|
_a.sent();
|
|
1967
2290
|
return [3 /*break*/, 3];
|
|
1968
2291
|
case 2:
|
|
1969
|
-
|
|
1970
|
-
logger.error("Formo: Failed to detect wallets",
|
|
2292
|
+
e_11 = _a.sent();
|
|
2293
|
+
logger.error("Formo: Failed to detect wallets", e_11);
|
|
1971
2294
|
return [3 /*break*/, 3];
|
|
1972
2295
|
case 3: return [2 /*return*/];
|
|
1973
2296
|
}
|
|
@@ -2160,6 +2483,105 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2160
2483
|
});
|
|
2161
2484
|
});
|
|
2162
2485
|
};
|
|
2486
|
+
/**
|
|
2487
|
+
* Resolve the chain an autocaptured request actually ran on.
|
|
2488
|
+
*
|
|
2489
|
+
* `_evmChainId` is maintained by `chainChanged` from whichever provider is
|
|
2490
|
+
* currently active. When a request arrives from a *different* tracked
|
|
2491
|
+
* provider - which happens whenever a visitor has two wallets installed -
|
|
2492
|
+
* that cached value describes the wrong wallet, and tagging the event with
|
|
2493
|
+
* it silently mis-attributes the chain.
|
|
2494
|
+
*
|
|
2495
|
+
* Answered entirely from a per-provider snapshot. This is deliberately
|
|
2496
|
+
* SYNCHRONOUS and never issues an RPC.
|
|
2497
|
+
*
|
|
2498
|
+
* An earlier version called `eth_chainId` on the signing provider and
|
|
2499
|
+
* time-boxed it with `Promise.race`. That is not safe: the race abandons the
|
|
2500
|
+
* SDK's promise but cannot cancel the provider's request. On a transport
|
|
2501
|
+
* that serializes - WalletConnect's relay socket, the very case this path
|
|
2502
|
+
* exists to serve - an abandoned lookup stays at the head of the wallet's
|
|
2503
|
+
* queue, and every later RPC the dapp makes queues behind it until reload.
|
|
2504
|
+
* Mislabelling a chain is a reporting defect; wedging the user's wallet is
|
|
2505
|
+
* not acceptable to avoid one.
|
|
2506
|
+
*
|
|
2507
|
+
* When nothing is known, this reports 0 ("unknown") rather than guessing
|
|
2508
|
+
* with the active provider's chain, which is known-wrong for another wallet.
|
|
2509
|
+
*/
|
|
2510
|
+
FormoAnalytics.prototype.resolveChainIdForProvider = function (provider) {
|
|
2511
|
+
if (provider) {
|
|
2512
|
+
var known = this._providerChainIds.get(provider);
|
|
2513
|
+
if (known)
|
|
2514
|
+
return known;
|
|
2515
|
+
// Only the active provider's chain is described by the central cache.
|
|
2516
|
+
if (provider === this._provider && this._evmChainId) {
|
|
2517
|
+
return this._evmChainId;
|
|
2518
|
+
}
|
|
2519
|
+
// A tracked provider we have never heard a chain from. Deliberately no
|
|
2520
|
+
// fall back to `_evmChainId`: it belongs to a different wallet.
|
|
2521
|
+
return 0;
|
|
2522
|
+
}
|
|
2523
|
+
return this._evmChainId || 0;
|
|
2524
|
+
};
|
|
2525
|
+
/**
|
|
2526
|
+
* Record a provider's chain. Fed by `chainChanged` and `connect`, and by the
|
|
2527
|
+
* one-off probe at tracking time - never from inside a user request.
|
|
2528
|
+
*/
|
|
2529
|
+
FormoAnalytics.prototype.rememberProviderChain = function (provider, chainId) {
|
|
2530
|
+
if (!provider || !chainId)
|
|
2531
|
+
return;
|
|
2532
|
+
// Any observation is newer than an `eth_chainId` still in flight for this
|
|
2533
|
+
// provider.
|
|
2534
|
+
this.bumpProviderChainGeneration(provider);
|
|
2535
|
+
this._providerChainIds.set(provider, chainId);
|
|
2536
|
+
// If this IS the active provider, central state has to follow. Recording
|
|
2537
|
+
// it only per provider left `currentChainId` on a chain restored from a
|
|
2538
|
+
// previous session, and the unscoped events that fall back to it were sent
|
|
2539
|
+
// despite an exclusion covering the chain the wallet was really on.
|
|
2540
|
+
//
|
|
2541
|
+
// Guarded on EVM already being the active namespace. `setChainState()`
|
|
2542
|
+
// makes whichever namespace it touches active, so syncing here
|
|
2543
|
+
// unconditionally let a background EVM wallet's chain report steal the
|
|
2544
|
+
// active slot from a live Solana wallet, and every later page or track
|
|
2545
|
+
// event was attributed to the wrong wallet entirely.
|
|
2546
|
+
if (provider === this._provider &&
|
|
2547
|
+
this._activeNamespace === "evm" &&
|
|
2548
|
+
this._evmChainId !== chainId) {
|
|
2549
|
+
this.setChainState('evm', { chainId: chainId });
|
|
2550
|
+
}
|
|
2551
|
+
};
|
|
2552
|
+
/** Advance and return this provider's chain-observation generation. */
|
|
2553
|
+
FormoAnalytics.prototype.bumpProviderChainGeneration = function (provider) {
|
|
2554
|
+
var _a;
|
|
2555
|
+
var next = ((_a = this._providerChainGenerations.get(provider)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
2556
|
+
this._providerChainGenerations.set(provider, next);
|
|
2557
|
+
return next;
|
|
2558
|
+
};
|
|
2559
|
+
/**
|
|
2560
|
+
* Seed a provider's chain from whatever it already exposes synchronously.
|
|
2561
|
+
*
|
|
2562
|
+
* Most EIP-1193 implementations carry a `chainId` property (MetaMask,
|
|
2563
|
+
* WalletConnect, Coinbase). Reading it costs nothing and cannot block.
|
|
2564
|
+
*
|
|
2565
|
+
* There is deliberately no RPC fallback. An earlier version probed with
|
|
2566
|
+
* `eth_chainId` when a provider was first tracked, on the theory that
|
|
2567
|
+
* tracking time is off the user's critical path. It is not: a serialized
|
|
2568
|
+
* transport has ONE queue, so a stalled probe sits in front of every later
|
|
2569
|
+
* signature and transaction the dapp makes. It could also land out of order
|
|
2570
|
+
* - a slow probe response overwriting a newer `chainChanged` - and relabel
|
|
2571
|
+
* events onto a chain the wallet had already left.
|
|
2572
|
+
*
|
|
2573
|
+
* A provider that exposes nothing stays unknown until it emits
|
|
2574
|
+
* `chainChanged` or `connect`, and unknown is reported honestly as 0.
|
|
2575
|
+
*/
|
|
2576
|
+
FormoAnalytics.prototype.seedProviderChainFromState = function (provider) {
|
|
2577
|
+
var raw = provider.chainId;
|
|
2578
|
+
var chainId = typeof raw === "string"
|
|
2579
|
+
? parseChainId(raw)
|
|
2580
|
+
: typeof raw === "number"
|
|
2581
|
+
? raw
|
|
2582
|
+
: undefined;
|
|
2583
|
+
this.rememberProviderChain(provider, chainId);
|
|
2584
|
+
};
|
|
2163
2585
|
FormoAnalytics.prototype.getCurrentChainId = function (provider) {
|
|
2164
2586
|
return __awaiter(this, void 0, void 0, function () {
|
|
2165
2587
|
var p, chainIdHex, err_5;
|
|
@@ -2195,7 +2617,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2195
2617
|
};
|
|
2196
2618
|
FormoAnalytics.prototype.buildSignatureEventPayload = function (method, params,
|
|
2197
2619
|
// Intentionally not read. Kept for positional call-site arity.
|
|
2198
|
-
_response, chainId) {
|
|
2620
|
+
_response, chainId, provider) {
|
|
2199
2621
|
var _a;
|
|
2200
2622
|
var rawAddress = method === "personal_sign"
|
|
2201
2623
|
? params[1]
|
|
@@ -2205,7 +2627,11 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2205
2627
|
throw new Error("Invalid address in signature payload: ".concat(rawAddress));
|
|
2206
2628
|
}
|
|
2207
2629
|
var effectiveChainId = (_a = chainId !== null && chainId !== void 0 ? chainId : this._evmChainId) !== null && _a !== void 0 ? _a : undefined;
|
|
2208
|
-
|
|
2630
|
+
// Only the active provider may write central wallet state - see the same
|
|
2631
|
+
// guard in buildTransactionEventPayload.
|
|
2632
|
+
if (!provider || provider === this._provider || !this._provider) {
|
|
2633
|
+
this.backfillActiveWallet(validAddress, effectiveChainId, provider);
|
|
2634
|
+
}
|
|
2209
2635
|
var basePayload = {
|
|
2210
2636
|
chainId: effectiveChainId,
|
|
2211
2637
|
address: validAddress,
|
|
@@ -2217,34 +2643,37 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2217
2643
|
// eth_signTypedData*: params[1] is the full EIP-712 struct.
|
|
2218
2644
|
return __assign(__assign({}, basePayload), { message: params[1] });
|
|
2219
2645
|
};
|
|
2220
|
-
FormoAnalytics.prototype.buildTransactionEventPayload = function (params, provider
|
|
2646
|
+
FormoAnalytics.prototype.buildTransactionEventPayload = function (params, provider,
|
|
2647
|
+
/**
|
|
2648
|
+
* Chain resolved once for this request's whole lifecycle. Passing it keeps
|
|
2649
|
+
* every status of one transaction on the same chain even if the user
|
|
2650
|
+
* switches network while the wallet prompt is open.
|
|
2651
|
+
*/
|
|
2652
|
+
capturedChainId) {
|
|
2221
2653
|
return __awaiter(this, void 0, void 0, function () {
|
|
2222
|
-
var _a, data, from, to, value, validAddress, chainId
|
|
2223
|
-
return __generator(this, function (
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
case 2:
|
|
2238
|
-
chainId = _b;
|
|
2239
|
-
this.backfillActiveWallet(validAddress, chainId);
|
|
2240
|
-
return [2 /*return*/, {
|
|
2241
|
-
chainId: chainId,
|
|
2242
|
-
data: data,
|
|
2243
|
-
address: validAddress,
|
|
2244
|
-
to: to,
|
|
2245
|
-
value: value,
|
|
2246
|
-
}];
|
|
2654
|
+
var _a, data, from, to, value, validAddress, chainId;
|
|
2655
|
+
return __generator(this, function (_b) {
|
|
2656
|
+
_a = params[0], data = _a.data, from = _a.from, to = _a.to, value = _a.value;
|
|
2657
|
+
validAddress = validateAndChecksumAddress(from);
|
|
2658
|
+
if (!validAddress) {
|
|
2659
|
+
throw new Error("Invalid address in transaction payload: ".concat(from));
|
|
2660
|
+
}
|
|
2661
|
+
chainId = capturedChainId !== null && capturedChainId !== void 0 ? capturedChainId : this.resolveChainIdForProvider(provider);
|
|
2662
|
+
// Only the ACTIVE provider may write central wallet state. A request from
|
|
2663
|
+
// a second, non-active wallet would otherwise overwrite the active
|
|
2664
|
+
// provider's address and chain, and every later request through the active
|
|
2665
|
+
// provider would then trust the other wallet's chain - persistent
|
|
2666
|
+
// mis-attribution, and a way around `excludeChains`.
|
|
2667
|
+
if (!provider || provider === this._provider || !this._provider) {
|
|
2668
|
+
this.backfillActiveWallet(validAddress, chainId, provider);
|
|
2247
2669
|
}
|
|
2670
|
+
return [2 /*return*/, {
|
|
2671
|
+
chainId: chainId,
|
|
2672
|
+
data: data,
|
|
2673
|
+
address: validAddress,
|
|
2674
|
+
to: to,
|
|
2675
|
+
value: value,
|
|
2676
|
+
}];
|
|
2248
2677
|
});
|
|
2249
2678
|
});
|
|
2250
2679
|
};
|
|
@@ -2256,16 +2685,51 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2256
2685
|
* social-login wrappers). If `accountsChanged` later fires it overwrites this
|
|
2257
2686
|
* value in the normal way; existing connections are never clobbered.
|
|
2258
2687
|
*/
|
|
2259
|
-
FormoAnalytics.prototype.backfillActiveWallet = function (address, chainId) {
|
|
2688
|
+
FormoAnalytics.prototype.backfillActiveWallet = function (address, chainId, provider) {
|
|
2689
|
+
// Refuse a chain the provider has since moved off.
|
|
2690
|
+
//
|
|
2691
|
+
// A request captures its chain once and reuses that snapshot for every
|
|
2692
|
+
// status it emits, which is right for the event payload - a confirmation
|
|
2693
|
+
// must not be relabelled mid-flight. But writing that captured value back
|
|
2694
|
+
// into central state on the LATER statuses restored a chain the wallet had
|
|
2695
|
+
// already left, and the unscoped events that fall back to it then bypassed
|
|
2696
|
+
// an exclusion that should have caught them.
|
|
2697
|
+
if (provider && chainId !== undefined && chainId !== 0) {
|
|
2698
|
+
var current = this._providerChainIds.get(provider);
|
|
2699
|
+
if (current !== undefined && current !== chainId) {
|
|
2700
|
+
chainId = current;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
// `0` is kept deliberately. It means "could not resolve", and persisting
|
|
2704
|
+
// it is what lets the exclusion gate refuse the unscoped events - `page`,
|
|
2705
|
+
// `track`, `identify` - that carry no chain of their own and fall back to
|
|
2706
|
+
// `currentChainId`. Erasing it to `undefined` looked tidier but removed
|
|
2707
|
+
// the only marker distinguishing "unknown" from "no wallet yet", and those
|
|
2708
|
+
// events then went out attributed to a wallet that might be sitting on an
|
|
2709
|
+
// excluded chain.
|
|
2260
2710
|
// Never learn identity while suppressed (opt-out / timezone / excluded host
|
|
2261
2711
|
// or path). A signature/transaction observed on an excluded route must not
|
|
2262
|
-
// populate currentAddress for later allowed-page events.
|
|
2263
|
-
// *adds* an address (it no-ops when one is already known), so there is no
|
|
2264
|
-
// stale state to clear here.
|
|
2712
|
+
// populate currentAddress for later allowed-page events.
|
|
2265
2713
|
if (this.isTrackingSuppressed())
|
|
2266
2714
|
return;
|
|
2267
|
-
|
|
2715
|
+
var known = this._evmAddress;
|
|
2716
|
+
if (known) {
|
|
2717
|
+
// Same wallet, newer chain: correct it rather than returning.
|
|
2718
|
+
//
|
|
2719
|
+
// A persisted wallet restores a chain from a previous session. If the
|
|
2720
|
+
// provider has since moved - to an excluded chain, or to one we cannot
|
|
2721
|
+
// resolve - the autocaptured event is gated correctly, but the stale
|
|
2722
|
+
// restored chain stayed in `currentChainId` and the unscoped events
|
|
2723
|
+
// that fall back to it went out under an exclusion that should have
|
|
2724
|
+
// caught them.
|
|
2725
|
+
if (chainId !== undefined &&
|
|
2726
|
+
known.toLowerCase() === address.toLowerCase() &&
|
|
2727
|
+
this._evmChainId !== chainId) {
|
|
2728
|
+
this.setChainState('evm', { address: known, chainId: chainId });
|
|
2729
|
+
}
|
|
2730
|
+
// A DIFFERENT address is another wallet's business; never overwrite.
|
|
2268
2731
|
return;
|
|
2732
|
+
}
|
|
2269
2733
|
this.setChainState('evm', { address: address, chainId: chainId });
|
|
2270
2734
|
};
|
|
2271
2735
|
/**
|
|
@@ -2296,7 +2760,7 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2296
2760
|
if (!provider)
|
|
2297
2761
|
return [2 /*return*/];
|
|
2298
2762
|
poll = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
2299
|
-
var receipt,
|
|
2763
|
+
var receipt, e_12;
|
|
2300
2764
|
return __generator(this, function (_a) {
|
|
2301
2765
|
switch (_a.label) {
|
|
2302
2766
|
case 0:
|
|
@@ -2320,8 +2784,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2320
2784
|
}
|
|
2321
2785
|
return [3 /*break*/, 3];
|
|
2322
2786
|
case 2:
|
|
2323
|
-
|
|
2324
|
-
logger.error("Error polling transaction receipt",
|
|
2787
|
+
e_12 = _a.sent();
|
|
2788
|
+
logger.error("Error polling transaction receipt", e_12);
|
|
2325
2789
|
return [3 /*break*/, 3];
|
|
2326
2790
|
case 3:
|
|
2327
2791
|
attempts++;
|
|
@@ -2451,6 +2915,9 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2451
2915
|
ns.chainId = namespaceOrChainId;
|
|
2452
2916
|
}
|
|
2453
2917
|
if (namespace === 'evm' && 'provider' in update) {
|
|
2918
|
+
// Displacing the active provider ends its connection as far as this SDK
|
|
2919
|
+
// is concerned, so the connect it reported stops counting.
|
|
2920
|
+
this.forgetConnectRecord(ns.provider, update.provider);
|
|
2454
2921
|
ns.provider = update.provider;
|
|
2455
2922
|
}
|
|
2456
2923
|
this._activeNamespace = namespace;
|
|
@@ -2464,6 +2931,8 @@ var FormoAnalytics = /** @class */ (function () {
|
|
|
2464
2931
|
? namespaceOrChainId
|
|
2465
2932
|
: this.getNamespace(namespaceOrChainId);
|
|
2466
2933
|
if (namespace === 'evm') {
|
|
2934
|
+
// Same rule: wiping the namespace drops the active provider.
|
|
2935
|
+
this.forgetConnectRecord(this._chainState.evm.provider, undefined);
|
|
2467
2936
|
this._chainState.evm = {};
|
|
2468
2937
|
}
|
|
2469
2938
|
else {
|