Skip to content

Commit

Permalink
swaps: anonymous tracking (#2325)
Browse files Browse the repository at this point in the history
* addtrack

* booleam

* fixanalytics

* trackanon

* devmoderevert

* track anonymously

* dont send data for non anonymized

* Revert "devmoderevert"

This reverts commit ff70e38.

Co-authored-by: Ethan Wessel <ejwessel@gmail.com>
  • Loading branch information
estebanmino and ejwessel authored Mar 4, 2021
1 parent 0ebbec1 commit 08fa75e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ public void trackEvent(ReadableMap e) {
this.mixpanel.track(eventCategory, props);
}

@ReactMethod
public void trackEventAnonymously(ReadableMap e) {
String eventCategory = e.getString("category");
String distinctId = this.mixpanel.getDistinctId();
this.mixpanel.identify("0x0000000000000000");
JSONObject props = toJSONObject(e);
this.mixpanel.track(eventCategory, props);
this.mixpanel.identify(distinctId);
}

@ReactMethod
public void getDistinctId(Promise promise) {
String distinctId = this.mixpanel.getDistinctId();
Expand Down
8 changes: 5 additions & 3 deletions app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,15 @@ const Main = props => {
delete newSwapsTransactions[transactionMeta.id].paramsForAnalytics;

InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(event, {
const parameters = {
...analyticsParams,
time_to_mine: timeToMine,
estimated_vs_used_gasRatio: estimatedVsUsedGasRatio,
quote_vs_executionRatio: quoteVsExecutionRatio,
token_to_amount_received: tokenToAmountReceived
});
token_to_amount_received: tokenToAmountReceived.toString()
};
Analytics.trackEventWithParameters(event, {});
Analytics.trackEventWithParameters(event, parameters, true);
});
} catch (e) {
Logger.error(e, ANALYTICS_EVENT_OPTS.SWAP_TRACKING_FAILED);
Expand Down
50 changes: 34 additions & 16 deletions app/components/UI/Swaps/QuotesView.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,12 @@ function SwapsQuotesView({
),
analytics: {
token_from: sourceToken.symbol,
token_from_amount: sourceAmount,
token_from_amount: fromTokenMinimalUnitString(sourceAmount, sourceToken.decimals),
token_to: destinationToken.symbol,
token_to_amount: selectedQuote.destinationAmount,
token_to_amount: fromTokenMinimalUnitString(
selectedQuote.destinationAmount,
destinationToken.decimals
),
request_type: hasEnoughTokenBalance ? 'Order' : 'Quote',
custom_slippage: slippage !== AppConstants.SWAPS.DEFAULT_SLIPPAGE,
best_quote_source: selectedQuote.aggregator,
Expand Down Expand Up @@ -518,7 +521,7 @@ function SwapsQuotesView({
}

InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.SWAP_STARTED, {
const parameters = {
token_from: sourceToken.symbol,
token_from_amount: fromTokenMinimalUnitString(sourceAmount, sourceToken.decimals),
token_to: destinationToken.symbol,
Expand All @@ -531,7 +534,9 @@ function SwapsQuotesView({
other_quote_selected: allQuotes[selectedQuoteId] === selectedQuote,
network_fees_USD: weiToFiat(toWei(selectedQuoteValue.ethFee), conversionRate, 'usd'),
network_fees_ETH: renderFromWei(toWei(selectedQuoteValue.ethFee))
});
};
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.SWAP_STARTED, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.SWAP_STARTED, parameters, true);
});

const { TransactionController } = Engine.context;
Expand Down Expand Up @@ -615,7 +620,7 @@ function SwapsQuotesView({
setEditQuoteTransactionsVisible(true);

InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.EDIT_SPEND_LIMIT_OPENED, {
const parameters = {
token_from: sourceToken.symbol,
token_from_amount: fromTokenMinimalUnitString(sourceAmount, sourceToken.decimals),
token_to: destinationToken.symbol,
Expand All @@ -629,7 +634,9 @@ function SwapsQuotesView({
gas_fees: weiToFiat(toWei(gasFee), conversionRate, currentCurrency),
custom_spend_limit_set: originalAmount !== currentAmount,
custom_spend_limit_amount: currentAmount
});
};
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.EDIT_SPEND_LIMIT_OPENED, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.EDIT_SPEND_LIMIT_OPENED, parameters, true);
});
}, [
allQuotes,
Expand All @@ -652,15 +659,17 @@ function SwapsQuotesView({
setCustomGasPrice(gasPrice);
setCustomGasLimit(gas);
InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.GAS_FEES_CHANGED, {
const parameters = {
speed_set: details.mode === 'advanced' ? undefined : details.mode,
gas_mode: details.mode === 'advanced' ? 'Advanced' : 'Basic',
gas_fees: weiToFiat(
toWei(util.calcTokenAmount(gasPrice * gas, 18)),
conversionRate,
currentCurrency
)
});
};
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.GAS_FEES_CHANGED, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.GAS_FEES_CHANGED, parameters, true);
});
},
[conversionRate, currentCurrency]
Expand All @@ -669,7 +678,7 @@ function SwapsQuotesView({
const handleQuotesReceivedMetric = useCallback(() => {
if (!selectedQuote || !selectedQuoteValue) return;
InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_RECEIVED, {
const parameters = {
token_from: sourceToken.symbol,
token_from_amount: fromTokenMinimalUnitString(sourceAmount, sourceToken.decimals),
token_to: destinationToken.symbol,
Expand All @@ -682,7 +691,9 @@ function SwapsQuotesView({
network_fees_USD: weiToFiat(toWei(selectedQuoteValue.ethFee), conversionRate, 'usd'),
network_fees_ETH: renderFromWei(toWei(selectedQuoteValue.ethFee)),
available_quotes: allQuotes.length
});
};
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_RECEIVED, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_RECEIVED, parameters, true);
});
}, [
sourceToken,
Expand All @@ -701,7 +712,7 @@ function SwapsQuotesView({
if (!selectedQuote || !selectedQuoteValue) return;
toggleQuotesModal();
InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.ALL_AVAILABLE_QUOTES_OPENED, {
const parameters = {
token_from: sourceToken.symbol,
token_from_amount: fromTokenMinimalUnitString(sourceAmount, sourceToken.decimals),
token_to: destinationToken.symbol,
Expand All @@ -714,7 +725,9 @@ function SwapsQuotesView({
network_fees_USD: weiToFiat(toWei(selectedQuoteValue.ethFee), conversionRate, 'usd'),
network_fees_ETH: renderFromWei(toWei(selectedQuoteValue.ethFee)),
available_quotes: allQuotes.length
});
};
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.ALL_AVAILABLE_QUOTES_OPENED, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.ALL_AVAILABLE_QUOTES_OPENED, parameters, true);
});
}, [
selectedQuote,
Expand Down Expand Up @@ -743,14 +756,18 @@ function SwapsQuotesView({
Logger.error(error?.description, `Swaps: ${error?.key}`);
if (error?.key === swapsUtils.SwapsError.QUOTES_EXPIRED_ERROR) {
InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_TIMED_OUT, {
const parameters = {
...data,
gas_fees: ''
});
};
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_TIMED_OUT, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_TIMED_OUT, parameters, true);
});
} else if (error?.key === swapsUtils.SwapsError.QUOTES_NOT_AVAILABLE_ERROR) {
InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.NO_QUOTES_AVAILABLE, { data });
const parameters = { data };
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.NO_QUOTES_AVAILABLE, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.NO_QUOTES_AVAILABLE, parameters, true);
});
}
},
Expand Down Expand Up @@ -902,7 +919,8 @@ function SwapsQuotesView({
navigation.setParams({ selectedQuote: undefined });
navigation.setParams({ quoteBegin: Date.now() });
InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_REQUESTED, data);
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_REQUESTED, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.QUOTES_REQUESTED, data, true);
});
}, [
destinationToken,
Expand Down
6 changes: 4 additions & 2 deletions app/components/UI/Swaps/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,14 @@ function SwapsAmountView({
if (liveness) {
// Triggered when a user enters the MetaMask Swap feature
InteractionManager.runAfterInteractions(() => {
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.SWAPS_OPENED, {
const parameters = {
source: initialSource === SWAPS_ETH_ADDRESS ? 'MainView' : 'TokenView',
activeCurrency: swapsTokens?.find(
token => token.address?.toLowerCase() === initialSource.toLowerCase()
)?.symbol
});
};
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.SWAPS_OPENED, {});
Analytics.trackEventWithParameters(ANALYTICS_EVENT_OPTS.SWAPS_OPENED, parameters, true);
});
} else {
navigation.pop();
Expand Down
64 changes: 40 additions & 24 deletions app/core/Analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,24 @@ class Analytics {
/**
* Track event if enabled and not DEV mode
*/
_trackEvent(name, { event, params = {}, value, info }) {
_trackEvent(name, { event, params = {}, value, info, anonymously = false }) {
if (!this.enabled) return;
if (!__DEV__) {
RCTAnalytics.trackEvent({
...event,
...params,
value,
info
});
if (!anonymously) {
RCTAnalytics.trackEvent({
...event,
...params,
value,
info
});
} else {
RCTAnalytics.trackEventAnonymously({
...event,
...params,
value,
info
});
}
} else {
Logger.log(`Analytics '${name}' -`, event, params, value, info);
}
Expand Down Expand Up @@ -119,8 +128,9 @@ class Analytics {
* Track event
*
* @param {object} event - Object containing event category, action and name
* @param {boolean} anonymously - Whether the tracking should be without the right distinctId
*/
trackEvent = event => {
trackEvent = (event, anonymously = false) => {
this._trackEvent('trackEvent', { event });
};

Expand All @@ -129,19 +139,21 @@ class Analytics {
*
* @param {object} event - Object containing event category, action and name
* @param {number} value - Value number to send with event
* @param {boolean} anonymously - Whether the tracking should be without the right distinctId
*/
trackEventWithValue = (event, value) => {
this._trackEvent('trackEventWithValue', { event, value });
trackEventWithValue = (event, value, anonymously = false) => {
this._trackEvent('trackEventWithValue', { event, value, anonymously });
};

/**
* Track event with information
*
* @param {object} event - Object containing event category, action and name
* @param {string} info - Information string to send with event
* @param {boolean} anonymously - Whether the tracking should be without the right distinctId
*/
trackEventWithInfo = (event, info) => {
this._trackEvent('trackEventWithInfo', { event, info });
trackEventWithInfo = (event, info, anonymously = false) => {
this._trackEvent('trackEventWithInfo', { event, info, anonymously });
};

/**
Expand All @@ -150,19 +162,21 @@ class Analytics {
* @param {object} event - Object containing event category, action and name
* @param {number} value - Value number to send with event
* @param {string} info - Information string to send with event
* @param {boolean} anonymously - Whether the tracking should be without the right distinctId
*/
trackEventWithValueAndInfo = (event, value, info) => {
this._trackEvent('trackEventWithValueAndInfo', { event, value, info });
trackEventWithValueAndInfo = (event, value, info, anonymously = false) => {
this._trackEvent('trackEventWithValueAndInfo', { event, value, info, anonymously });
};

/**
* Track event with parameters
*
* @param {object} event - Object containing event category, action and name
* @param {object} params - Object containing other params to send with event
* @param {boolean} anonymously - Whether the tracking should be without the right distinctId
*/
trackEventWithParameters = (event, params) => {
this._trackEvent('trackEventWithParameters', { event, params });
trackEventWithParameters = (event, params, anonymously = false) => {
this._trackEvent('trackEventWithParameters', { event, params, anonymously });
};

/**
Expand All @@ -171,9 +185,10 @@ class Analytics {
* @param {object} event - Object containing event category, action and name
* @param {number} value - Value number to send with event
* @param {object} params - Object containing other params to send with event
* @param {boolean} anonymously - Whether the tracking should be without the right distinctId
*/
trackEventWithValueAndParameters = (event, value, params) => {
this._trackEvent('trackEventWithValueAndParameters', { event, value, params });
trackEventWithValueAndParameters = (event, value, params, anonymously = false) => {
this._trackEvent('trackEventWithValueAndParameters', { event, value, params, anonymously });
};

/**
Expand All @@ -183,9 +198,10 @@ class Analytics {
* @param {number} value - Value number to send with event
* @param {string} info - Information string to send with event
* @param {object} params - Object containing other params to send with event
* @param {boolean} anonymously - Whether the tracking should be without the right distinctId
*/
trackEventWithValueAndInfoAndParameters = (event, value, info, params) => {
this._trackEvent('trackEventWithValueAndInfoAndParameters', { event, value, info, params });
trackEventWithValueAndInfoAndParameters = (event, value, info, params, anonymously = false) => {
this._trackEvent('trackEventWithValueAndInfoAndParameters', { event, value, info, params, anonymously });
};
}

Expand Down Expand Up @@ -220,11 +236,11 @@ export default {
getDistinctId() {
return instance && instance.getDistinctId();
},
trackEvent(event) {
return instance && instance.trackEvent(event);
trackEvent(event, anonymously) {
return instance && instance.trackEvent(event, anonymously);
},
trackEventWithParameters(event, parameters) {
return instance && instance.trackEventWithParameters(event, parameters);
trackEventWithParameters(event, parameters, anonymously) {
return instance && instance.trackEventWithParameters(event, parameters, anonymously);
},
getRemoteVariables() {
return instance.remoteVariables;
Expand Down
8 changes: 8 additions & 0 deletions ios/MetaMask/NativeModules/RCTAnalytics/RCTAnalytics.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ @implementation RCTAnalytics
[[Mixpanel sharedInstance] track: [self getCategory:event] properties:[self getInfo:event]];
}

RCT_EXPORT_METHOD(trackEventAnonymously:(NSDictionary *)event)
{
NSString *const distinctId = [[Mixpanel sharedInstance] distinctId];
[[Mixpanel sharedInstance] identify:@"0x0000000000000000"];
[[Mixpanel sharedInstance] track: [self getCategory:event] properties:[self getInfo:event]];
[[Mixpanel sharedInstance] identify:distinctId];
}


RCT_EXPORT_METHOD(peopleIdentify)
{
Expand Down

0 comments on commit 08fa75e

Please sign in to comment.