Skip to content

Commit f5d86b7

Browse files
Merge branch 'develop' into fb/fix-nft-approve-text
2 parents 43fe5a3 + 6233ed4 commit f5d86b7

File tree

19 files changed

+9773
-85
lines changed

19 files changed

+9773
-85
lines changed

.circleci/config.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,19 @@ workflows:
136136
- benchmark:
137137
requires:
138138
- prep-build-test
139+
- stats-module-load-init:
140+
requires:
141+
- prep-build-test-mv3
139142
- job-publish-prerelease:
140143
requires:
141144
- prep-deps
142145
- prep-build
143146
- prep-build-beta
144147
- prep-build-flask
145148
- prep-build-storybook
149+
- prep-build-test-mv3
146150
- benchmark
151+
- stats-module-load-init
147152
- all-tests-pass
148153
- job-publish-release:
149154
filters:
@@ -596,6 +601,40 @@ jobs:
596601
paths:
597602
- test-artifacts
598603

604+
stats-module-load-init:
605+
executor: node-browsers-medium-plus
606+
steps:
607+
- checkout
608+
- run:
609+
name: Re-Install Chrome
610+
command: ./.circleci/scripts/chrome-install.sh
611+
- attach_workspace:
612+
at: .
613+
- run:
614+
name: Move test build to dist
615+
command: mv ./dist-test-mv3 ./dist
616+
- run:
617+
name: Move test zips to builds
618+
command: mv ./builds-test-mv3 ./builds
619+
- run:
620+
name: Run page load benchmark
621+
command: |
622+
mkdir -p test-artifacts/chrome/mv3
623+
cp -R development/charts/flamegraph test-artifacts/chrome/mv3/initialisation
624+
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/background
625+
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/ui
626+
cp -R development/charts/table test-artifacts/chrome/mv3/load_time
627+
- run:
628+
name: Run page load benchmark
629+
command: yarn mv3:stats:chrome --out test-artifacts/chrome/mv3
630+
- store_artifacts:
631+
path: test-artifacts
632+
destination: test-artifacts
633+
- persist_to_workspace:
634+
root: .
635+
paths:
636+
- test-artifacts
637+
599638
job-publish-prerelease:
600639
executor: node-browsers
601640
steps:

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = {
88
'app/vendor/**',
99
'builds/**/*',
1010
'development/chromereload.js',
11+
'development/charts/**',
1112
'dist/**/*',
1213
'node_modules/**/*',
1314
],

app/scripts/lib/createRPCMethodTrackingMiddleware.js

Lines changed: 174 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,205 @@
1+
import { MESSAGE_TYPE, ORIGIN_METAMASK } from '../../../shared/constants/app';
12
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
23
import { SECOND } from '../../../shared/constants/time';
34

4-
const USER_PROMPTED_EVENT_NAME_MAP = {
5-
eth_signTypedData_v4: EVENT_NAMES.SIGNATURE_REQUESTED,
6-
eth_signTypedData_v3: EVENT_NAMES.SIGNATURE_REQUESTED,
7-
eth_signTypedData: EVENT_NAMES.SIGNATURE_REQUESTED,
8-
eth_personal_sign: EVENT_NAMES.SIGNATURE_REQUESTED,
9-
eth_sign: EVENT_NAMES.SIGNATURE_REQUESTED,
10-
eth_getEncryptionPublicKey: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED,
11-
eth_decrypt: EVENT_NAMES.DECRYPTION_REQUESTED,
12-
wallet_requestPermissions: EVENT_NAMES.PERMISSIONS_REQUESTED,
13-
eth_requestAccounts: EVENT_NAMES.PERMISSIONS_REQUESTED,
5+
/**
6+
* These types determine how the method tracking middleware handles incoming
7+
* requests based on the method name. There are three options right now but
8+
* the types could be expanded to cover other options in the future.
9+
*/
10+
const RATE_LIMIT_TYPES = {
11+
RATE_LIMITED: 'rate_limited',
12+
BLOCKED: 'blocked',
13+
NON_RATE_LIMITED: 'non_rate_limited',
1414
};
1515

16-
const samplingTimeouts = {};
16+
/**
17+
* This object maps a method name to a RATE_LIMIT_TYPE. If not in this map the
18+
* default is 'RATE_LIMITED'
19+
*/
20+
const RATE_LIMIT_MAP = {
21+
[MESSAGE_TYPE.ETH_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
22+
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
23+
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
24+
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
25+
[MESSAGE_TYPE.PERSONAL_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
26+
[MESSAGE_TYPE.ETH_DECRYPT]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
27+
[MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]:
28+
RATE_LIMIT_TYPES.NON_RATE_LIMITED,
29+
[MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: RATE_LIMIT_TYPES.RATE_LIMITED,
30+
[MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: RATE_LIMIT_TYPES.RATE_LIMITED,
31+
[MESSAGE_TYPE.SEND_METADATA]: RATE_LIMIT_TYPES.BLOCKED,
32+
[MESSAGE_TYPE.GET_PROVIDER_STATE]: RATE_LIMIT_TYPES.BLOCKED,
33+
};
34+
35+
/**
36+
* For events with user interaction (approve / reject | cancel) this map will
37+
* return an object with APPROVED, REJECTED and REQUESTED keys that map to the
38+
* appropriate event names.
39+
*/
40+
const EVENT_NAME_MAP = {
41+
[MESSAGE_TYPE.ETH_SIGN]: {
42+
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
43+
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
44+
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
45+
},
46+
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: {
47+
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
48+
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
49+
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
50+
},
51+
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: {
52+
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
53+
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
54+
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
55+
},
56+
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: {
57+
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
58+
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
59+
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
60+
},
61+
[MESSAGE_TYPE.PERSONAL_SIGN]: {
62+
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
63+
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
64+
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
65+
},
66+
[MESSAGE_TYPE.ETH_DECRYPT]: {
67+
APPROVED: EVENT_NAMES.DECRYPTION_APPROVED,
68+
REJECTED: EVENT_NAMES.DECRYPTION_REJECTED,
69+
REQUESTED: EVENT_NAMES.DECRYPTION_REQUESTED,
70+
},
71+
[MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]: {
72+
APPROVED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_APPROVED,
73+
REJECTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REJECTED,
74+
REQUESTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED,
75+
},
76+
[MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: {
77+
APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED,
78+
REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED,
79+
REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED,
80+
},
81+
[MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: {
82+
APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED,
83+
REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED,
84+
REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED,
85+
},
86+
};
87+
88+
const rateLimitTimeouts = {};
1789

1890
/**
1991
* Returns a middleware that tracks inpage_provider usage using sampling for
2092
* each type of event except those that require user interaction, such as
2193
* signature requests
2294
*
2395
* @param {object} opts - options for the rpc method tracking middleware
24-
* @param {Function} opts.trackEvent - trackEvent method from MetaMetricsController
25-
* @param {Function} opts.getMetricsState - get the state of MetaMetricsController
96+
* @param {Function} opts.trackEvent - trackEvent method from
97+
* MetaMetricsController
98+
* @param {Function} opts.getMetricsState - get the state of
99+
* MetaMetricsController
100+
* @param {number} [opts.rateLimitSeconds] - number of seconds to wait before
101+
* allowing another set of events to be tracked.
26102
* @returns {Function}
27103
*/
28104
export default function createRPCMethodTrackingMiddleware({
29105
trackEvent,
30106
getMetricsState,
107+
rateLimitSeconds = 60,
31108
}) {
32109
return function rpcMethodTrackingMiddleware(
33110
/** @type {any} */ req,
34111
/** @type {any} */ res,
35112
/** @type {Function} */ next,
36113
) {
37-
const startTime = Date.now();
38-
const { origin } = req;
114+
const { origin, method } = req;
115+
116+
// Determine what type of rate limit to apply based on method
117+
const rateLimitType =
118+
RATE_LIMIT_MAP[method] ?? RATE_LIMIT_TYPES.RATE_LIMITED;
119+
120+
// If the rateLimitType is RATE_LIMITED check the rateLimitTimeouts
121+
const rateLimited =
122+
rateLimitType === RATE_LIMIT_TYPES.RATE_LIMITED &&
123+
typeof rateLimitTimeouts[method] !== 'undefined';
124+
125+
// Get the participateInMetaMetrics state to determine if we should track
126+
// anything. This is extra redundancy because this value is checked in
127+
// the metametrics controller's trackEvent method as well.
128+
const userParticipatingInMetaMetrics =
129+
getMetricsState().participateInMetaMetrics === true;
130+
131+
// Get the event type, each of which has APPROVED, REJECTED and REQUESTED
132+
// keys for the various events in the flow.
133+
const eventType = EVENT_NAME_MAP[method];
134+
135+
// Boolean variable that reduces code duplication and increases legibility
136+
const shouldTrackEvent =
137+
// Don't track if the request came from our own UI or background
138+
origin !== ORIGIN_METAMASK &&
139+
// Don't track if this is a blocked method
140+
rateLimitType !== RATE_LIMIT_TYPES.BLOCKED &&
141+
// Don't track if the rate limit has been hit
142+
rateLimited === false &&
143+
// Don't track if the user isn't participating in metametrics
144+
userParticipatingInMetaMetrics === true;
145+
146+
if (shouldTrackEvent) {
147+
// We track an initial "requested" event as soon as the dapp calls the
148+
// provider method. For the events not special cased this is the only
149+
// event that will be fired and the event name will be
150+
// 'Provider Method Called'.
151+
const event = eventType
152+
? eventType.REQUESTED
153+
: EVENT_NAMES.PROVIDER_METHOD_CALLED;
154+
155+
const properties = {};
156+
157+
if (event === EVENT_NAMES.SIGNATURE_REQUESTED) {
158+
properties.signature_type = method;
159+
} else {
160+
properties.method = method;
161+
}
162+
163+
trackEvent({
164+
event,
165+
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
166+
referrer: {
167+
url: origin,
168+
},
169+
properties,
170+
});
171+
172+
rateLimitTimeouts[method] = setTimeout(() => {
173+
delete rateLimitTimeouts[method];
174+
}, SECOND * rateLimitSeconds);
175+
}
39176

40177
next((callback) => {
41-
const endTime = Date.now();
42-
if (!getMetricsState().participateInMetaMetrics) {
178+
if (shouldTrackEvent === false || typeof eventType === 'undefined') {
43179
return callback();
44180
}
45-
if (USER_PROMPTED_EVENT_NAME_MAP[req.method]) {
46-
const userRejected = res.error?.code === 4001;
47-
trackEvent({
48-
event: USER_PROMPTED_EVENT_NAME_MAP[req.method],
49-
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
50-
referrer: {
51-
url: origin,
52-
},
53-
properties: {
54-
method: req.method,
55-
status: userRejected ? 'rejected' : 'approved',
56-
error_code: res.error?.code,
57-
error_message: res.error?.message,
58-
has_result: typeof res.result !== 'undefined',
59-
duration: endTime - startTime,
60-
},
61-
});
62-
} else if (typeof samplingTimeouts[req.method] === 'undefined') {
63-
trackEvent({
64-
event: 'Provider Method Called',
65-
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
66-
referrer: {
67-
url: origin,
68-
},
69-
properties: {
70-
method: req.method,
71-
error_code: res.error?.code,
72-
error_message: res.error?.message,
73-
has_result: typeof res.result !== 'undefined',
74-
duration: endTime - startTime,
75-
},
76-
});
77-
// Only record one call to this method every ten seconds to avoid
78-
// overloading network requests.
79-
samplingTimeouts[req.method] = setTimeout(() => {
80-
delete samplingTimeouts[req.method];
81-
}, SECOND * 10);
181+
182+
// An error code of 4001 means the user rejected the request, which we
183+
// can use here to determine which event to track.
184+
const event =
185+
res.error?.code === 4001 ? eventType.REJECTED : eventType.APPROVED;
186+
187+
const properties = {};
188+
189+
if (eventType.REQUESTED === EVENT_NAMES.SIGNATURE_REQUESTED) {
190+
properties.signature_type = method;
191+
} else {
192+
properties.method = method;
82193
}
194+
195+
trackEvent({
196+
event,
197+
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
198+
referrer: {
199+
url: origin,
200+
},
201+
properties,
202+
});
83203
return callback();
84204
});
85205
};

0 commit comments

Comments
 (0)