Skip to content

Commit 5bc4880

Browse files
authored
feat: enhance Snaps metrics tracking (#218)
* feat: enhance Snaps metrics tracking with additional permission data and justification support * refactor: remove unused PermissionValue type from snapsMetricsService
1 parent e4a1c70 commit 5bc4880

File tree

4 files changed

+158
-106
lines changed

4 files changed

+158
-106
lines changed

docs/snaps-metrics.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,26 @@ The `SnapsMetricsService` class provides methods to track various events using M
3636
- `Permission Rejected`: When the user rejects a permission
3737
- `Permission Granted`: When a permission is successfully granted
3838

39-
**Tracked Data:**
39+
**Common Tracked Data:**
4040
- `permission_type`: One of `native-token-stream`, `native-token-periodic`, `erc20-token-stream`, `erc20-token-periodic`
41-
- `chain_id`: The blockchain network ID
42-
- `period_seconds`: The time period for periodic permissions
43-
- `amount`: The token amount
44-
- `token`: The token address (0x0 for native tokens)
45-
- `duration_seconds`: Permission duration
46-
- `is_adjustment_allowed`: Boolean indicating if permission adjustment was allowed
41+
- `chain_id`: The blockchain network ID (hex string)
42+
- `justification`: Optional user-provided justification text
43+
- `is_adjustment_allowed`: Boolean indicating if permission adjustment was allowed (only for `Permission Granted`)
44+
45+
**Permission-Specific Data:**
46+
47+
For **Periodic Permissions** (`native-token-periodic`, `erc20-token-periodic`):
48+
- `period_amount`: The token amount per period (hex string)
49+
- `period_duration`: The time period duration in seconds (number)
50+
- `start_time`: Permission start timestamp in seconds (number)
51+
- `token_address`: Token contract address (hex string, only for ERC20)
52+
53+
For **Streaming Permissions** (`native-token-stream`, `erc20-token-stream`):
54+
- `amount_per_second`: Token amount streamed per second (hex string)
55+
- `initial_amount`: Initial upfront amount (hex string, optional)
56+
- `max_amount`: Maximum total amount (hex string, optional)
57+
- `start_time`: Permission start timestamp in seconds (number)
58+
- `token_address`: Token contract address (hex string, only for ERC20)
4759

4860
### 2. Smart Account Upgrades
4961

@@ -79,7 +91,6 @@ All events include:
7991
- `origin`: The dapp origin requesting the permission
8092
- Additional event-specific properties
8193

82-
8394
## Data Flow
8495

8596
1. User initiates permission request → `trackPermissionRequestStarted`
@@ -89,4 +100,3 @@ All events include:
89100
5. Delegation signing → `trackDelegationSigning`
90101
6. Permission granted → `trackPermissionGranted`
91102
7. Profile sync (if enabled) → `trackProfileSync`
92-

packages/gator-permissions-snap/src/core/permissionRequestLifecycleOrchestrator.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,8 @@ export class PermissionRequestLifecycleOrchestrator {
127127
await this.#snapsMetricsService.trackPermissionRequestStarted({
128128
origin,
129129
permissionType,
130-
permissionValue: {
131-
chainId: permissionRequest.chainId,
132-
},
130+
chainId: permissionRequest.chainId,
131+
permissionData: permissionRequest.permission.data,
133132
});
134133

135134
// only necessary when not pre-installed, to ensure that the account
@@ -216,9 +215,9 @@ export class PermissionRequestLifecycleOrchestrator {
216215
await this.#snapsMetricsService.trackPermissionDialogShown({
217216
origin,
218217
permissionType,
219-
permissionValue: {
220-
chainId: permissionRequest.chainId,
221-
},
218+
chainId: permissionRequest.chainId,
219+
permissionData: permissionRequest.permission.data,
220+
justification: context.justification,
222221
});
223222
} catch (error) {
224223
await confirmationDialog.closeWithError(error as Error);
@@ -310,9 +309,9 @@ export class PermissionRequestLifecycleOrchestrator {
310309
await this.#snapsMetricsService.trackPermissionRejected({
311310
origin,
312311
permissionType,
313-
permissionValue: {
314-
chainId: permissionRequest.chainId,
315-
},
312+
chainId: permissionRequest.chainId,
313+
permissionData: permissionRequest.permission.data,
314+
justification: context.justification,
316315
});
317316

318317
return {
@@ -502,9 +501,9 @@ export class PermissionRequestLifecycleOrchestrator {
502501
await this.#snapsMetricsService.trackPermissionGranted({
503502
origin,
504503
permissionType,
505-
permissionValue: {
506-
chainId: numberToHex(chainId),
507-
},
504+
chainId: numberToHex(chainId),
505+
permissionData: populatedPermission.data,
506+
justification: modifiedContext.justification,
508507
isAdjustmentAllowed,
509508
});
510509

packages/gator-permissions-snap/src/services/snapsMetricsService.ts

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,6 @@ import { logger } from '@metamask/7715-permissions-shared/utils';
33
import type { Json, SnapsProvider } from '@metamask/snaps-sdk';
44
import type { Hex } from '@metamask/utils';
55

6-
/**
7-
* Permission value details for analytics.
8-
*/
9-
export type PermissionValue = {
10-
/** The period in seconds (for periodic permissions) */
11-
period?: number;
12-
/** The amount in the token's base unit */
13-
amount?: string;
14-
/** The token address (0x0 for native tokens) */
15-
token?: Hex;
16-
/** The chain ID */
17-
chainId?: Hex;
18-
/** Duration/expiry in seconds */
19-
duration?: number;
20-
};
21-
226
/**
237
* Base parameters shared by all permission tracking methods.
248
*/
@@ -34,34 +18,48 @@ export type BasePermissionTrackingParams = {
3418
*/
3519
export type TrackPermissionRequestStartedParams =
3620
BasePermissionTrackingParams & {
37-
/** Optional permission value details */
38-
permissionValue?: PermissionValue;
21+
/** Chain ID */
22+
chainId: Hex;
23+
/** Permission data */
24+
permissionData: Record<string, unknown>;
3925
};
4026

4127
/**
4228
* Parameters for tracking permission dialog shown.
4329
*/
4430
export type TrackPermissionDialogShownParams = BasePermissionTrackingParams & {
45-
/** Optional permission value details */
46-
permissionValue?: PermissionValue;
31+
/** Chain ID */
32+
chainId: Hex;
33+
/** Permission data */
34+
permissionData: Record<string, unknown>;
35+
/** Optional justification text */
36+
justification?: string;
4737
};
4838

4939
/**
5040
* Parameters for tracking permission rejected.
5141
*/
5242
export type TrackPermissionRejectedParams = BasePermissionTrackingParams & {
53-
/** Optional permission value details */
54-
permissionValue?: PermissionValue;
43+
/** Chain ID */
44+
chainId: Hex;
45+
/** Permission data */
46+
permissionData: Record<string, unknown>;
47+
/** Optional justification text */
48+
justification?: string;
5549
};
5650

5751
/**
5852
* Parameters for tracking permission granted.
5953
*/
6054
export type TrackPermissionGrantedParams = BasePermissionTrackingParams & {
61-
/** Permission value details */
62-
permissionValue: PermissionValue;
6355
/** Whether the permission adjustment was allowed */
6456
isAdjustmentAllowed: boolean;
57+
/** Chain ID */
58+
chainId: string;
59+
/** Permission data */
60+
permissionData: Record<string, unknown>;
61+
/** Optional justification text */
62+
justification?: string;
6563
};
6664

6765
/**
@@ -151,7 +149,10 @@ export class SnapsMetricsService {
151149
message: 'User initiated permission request',
152150
origin: params.origin,
153151
permission_type: params.permissionType,
154-
...this.#formatPermissionValue(params.permissionValue),
152+
...this.#formatPermissionData({
153+
chainId: params.chainId,
154+
permissionData: params.permissionData,
155+
}),
155156
});
156157
}
157158

@@ -166,7 +167,11 @@ export class SnapsMetricsService {
166167
message: 'Permission confirmation dialog displayed',
167168
origin: params.origin,
168169
permission_type: params.permissionType,
169-
...this.#formatPermissionValue(params.permissionValue),
170+
...this.#formatPermissionData({
171+
chainId: params.chainId,
172+
permissionData: params.permissionData,
173+
...(params.justification && { justification: params.justification }),
174+
}),
170175
});
171176
}
172177

@@ -181,7 +186,11 @@ export class SnapsMetricsService {
181186
message: 'User rejected permission request',
182187
origin: params.origin,
183188
permission_type: params.permissionType,
184-
...this.#formatPermissionValue(params.permissionValue),
189+
...this.#formatPermissionData({
190+
chainId: params.chainId,
191+
permissionData: params.permissionData,
192+
...(params.justification && { justification: params.justification }),
193+
}),
185194
});
186195
}
187196

@@ -197,7 +206,11 @@ export class SnapsMetricsService {
197206
origin: params.origin,
198207
permission_type: params.permissionType,
199208
is_adjustment_allowed: params.isAdjustmentAllowed,
200-
...this.#formatPermissionValue(params.permissionValue),
209+
...this.#formatPermissionData({
210+
chainId: params.chainId,
211+
permissionData: params.permissionData,
212+
...(params.justification && { justification: params.justification }),
213+
}),
201214
});
202215
}
203216

@@ -253,37 +266,49 @@ export class SnapsMetricsService {
253266
}
254267

255268
/**
256-
* Format permission value for analytics.
257-
* @param permissionValue - The permission value to format.
269+
* Formats permission data for analytics.
270+
* @param params - The formatting parameters.
271+
* @param params.chainId - The chain ID for the permission.
272+
* @param params.permissionData - The permission data to format.
273+
* @param params.justification - Optional justification text provided by the user.
258274
* @returns Formatted properties for tracking.
259275
*/
260-
#formatPermissionValue(
261-
permissionValue?: PermissionValue,
262-
): Record<string, Json> {
263-
if (!permissionValue) {
264-
return {};
265-
}
276+
#formatPermissionData(params: {
277+
chainId: string;
278+
permissionData: Record<string, unknown>;
279+
justification?: string;
280+
}): Record<string, Json> {
281+
const formatted: Record<string, Json> = {
282+
chain_id: params.chainId,
283+
};
266284

267-
const formatted: Record<string, Json> = {};
285+
const { permissionData } = params;
268286

269-
if (permissionValue.period !== undefined) {
270-
formatted.period_seconds = permissionValue.period;
287+
if (permissionData.periodAmount !== undefined) {
288+
formatted.period_amount = permissionData.periodAmount as string;
271289
}
272-
273-
if (permissionValue.amount !== undefined) {
274-
formatted.amount = permissionValue.amount;
290+
if (permissionData.periodDuration !== undefined) {
291+
formatted.period_duration = permissionData.periodDuration as number;
275292
}
276-
277-
if (permissionValue.token !== undefined) {
278-
formatted.token = permissionValue.token;
293+
if (permissionData.startTime !== undefined) {
294+
formatted.start_time = permissionData.startTime as number;
279295
}
280-
281-
if (permissionValue.chainId !== undefined) {
282-
formatted.chain_id = permissionValue.chainId;
296+
if (permissionData.tokenAddress !== undefined) {
297+
formatted.token_address = permissionData.tokenAddress as string;
298+
}
299+
if (permissionData.amountPerSecond !== undefined) {
300+
formatted.amount_per_second = permissionData.amountPerSecond as string;
301+
}
302+
if (permissionData.initialAmount !== undefined) {
303+
formatted.initial_amount = permissionData.initialAmount as string;
304+
}
305+
if (permissionData.maxAmount !== undefined) {
306+
formatted.max_amount = permissionData.maxAmount as string;
283307
}
284308

285-
if (permissionValue.duration !== undefined) {
286-
formatted.duration_seconds = permissionValue.duration;
309+
// Add justification if provided
310+
if (params.justification) {
311+
formatted.justification = params.justification;
287312
}
288313

289314
return formatted;

0 commit comments

Comments
 (0)