Skip to content

chore: move bridge tx status utils from extension to bridge-status-controller #5794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/bridge-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"@metamask/metamask-eth-abis": "^3.1.1",
"@metamask/multichain-network-controller": "^0.7.0",
"@metamask/polling-controller": "^13.0.0",
"@metamask/transaction-controller": "^54.3.0",
"@metamask/utils": "^11.2.0",
"bignumber.js": "^9.1.2",
"reselect": "^5.1.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
type BridgeStatusControllerMessenger,
BridgeClientId,
} from './types';
import * as bridgeStatusUtils from './utils/bridge-status';
import * as bridgeStatusUtils from './utils/fetch-tx-status';
import * as transactionUtils from './utils/transaction';
import { flushPromises } from '../../../tests/helpers';

Expand Down
105 changes: 68 additions & 37 deletions packages/bridge-status-controller/src/bridge-status-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import type {
import {
fetchBridgeTxStatus,
getStatusRequestWithSrcTxHash,
} from './utils/bridge-status';
} from './utils/fetch-tx-status';
import { getTxGasEstimates } from './utils/gas';
import {
getFinalizedTxProperties,
Expand All @@ -69,6 +69,10 @@ import {
handleSolanaTxResponse,
} from './utils/transaction';
import { generateActionId } from './utils/transaction';
import {
isBridgeTransaction,
isIncompleteTransactionCleanup,
} from './utils/tx-status';

const metadata: StateMetadata<BridgeStatusControllerState> = {
// We want to persist the bridge status state so that we can show the proper data for the Activity list
Expand Down Expand Up @@ -179,6 +183,24 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
// If you close the browser, the polling stops
// Check for historyItems that do not have a status of complete and restart polling
this.#restartPollingForIncompleteHistoryItems();

// TODO test this
this.messagingSystem.subscribe(
'TransactionController:transactionFailed',
({ transactionMeta }) => {
const { type, status } = transactionMeta;

if (
isBridgeTransaction(type) &&
!isIncompleteTransactionCleanup(status)
) {
this.#trackUnifiedSwapBridgeEvent(
UnifiedSwapBridgeEventName.Failed,
transactionMeta.id,
);
}
},
);
}

resetState = () => {
Expand Down Expand Up @@ -373,21 +395,12 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
this.stopPollingByPollingToken(pollingToken);

if (status.status === StatusTypes.COMPLETE) {
this.messagingSystem.publish(
`${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionComplete`,
{ bridgeHistoryItem: newBridgeHistoryItem },
);
this.#trackUnifiedSwapBridgeEvent(
UnifiedSwapBridgeEventName.Completed,
bridgeTxMetaId,
);
}
if (status.status === StatusTypes.FAILED) {
this.messagingSystem.publish(
`${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionFailed`,
{ bridgeHistoryItem: newBridgeHistoryItem },
);

this.#trackUnifiedSwapBridgeEvent(
UnifiedSwapBridgeEventName.Failed,
bridgeTxMetaId,
Expand Down Expand Up @@ -788,7 +801,9 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
);
this.#trackUnifiedSwapBridgeEvent(
UnifiedSwapBridgeEventName.SnapConfirmationViewed,
txMeta.id,
);
txMeta = await this.#handleSolanaTx(
quoteResponse as QuoteResponse<string> & QuoteMetadata,
);
}
// Submit EVM tx
Expand Down Expand Up @@ -888,24 +903,36 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
| typeof UnifiedSwapBridgeEventName.Completed,
>(
eventName: T,
txMetaId: string,
txMetaId?: string,
) => {
const historyItem: BridgeHistoryItem | undefined =
this.state.txHistory[txMetaId];
if (!historyItem) {
this.messagingSystem.call(
'BridgeController:trackUnifiedSwapBridgeEvent',
eventName,
{},
);
return;
}

let requiredEventProperties: Pick<RequiredEventContextFromClient, T>[T];
const selectedAccount = this.messagingSystem.call(
'AccountsController:getAccountByAddress',
historyItem.account,
);
const historyItem: BridgeHistoryItem | undefined = txMetaId
? this.state.txHistory[txMetaId]
: undefined;

// TODO remove this so Snap viewed and Failed before submission can still emit data from bridge controller
// if (!historyItem) {
// this.messagingSystem.call(
// 'BridgeController:trackUnifiedSwapBridgeEvent',
// eventName,
// {
// error_message: 'error_message',
// price_impact: Number(
// historyItem.quote.bridgePriceData?.priceImpact ?? '0',
// ),
// },
// );
// return;
// }

let requiredEventProperties:
| Pick<RequiredEventContextFromClient, T>[T]
| Record<string, unknown>;
const selectedAccount = historyItem
? this.messagingSystem.call(
'AccountsController:getAccountByAddress',
historyItem.account,
)
: undefined;

switch (eventName) {
case UnifiedSwapBridgeEventName.Submitted:
Expand All @@ -914,16 +941,20 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
default:
requiredEventProperties = {
action_type: getActionType(
historyItem.quote.srcChainId,
historyItem.quote.destChainId,
historyItem?.quote.srcChainId,
historyItem?.quote.destChainId,
),
...(historyItem ? getRequestParamFromHistory(historyItem) : {}),
...(historyItem
? getRequestMetadataFromHistory(historyItem, selectedAccount)
: {}),
...(historyItem ? getTradeDataFromHistory(historyItem) : {}),
...(historyItem ? getTxStatusesFromHistory(historyItem) : {}),
...(historyItem ? getFinalizedTxProperties(historyItem) : {}),
// error_message: 'error_message',
price_impact: Number(
historyItem?.quote.priceData?.priceImpact ?? '0',
),
...getRequestParamFromHistory(historyItem),
...getRequestMetadataFromHistory(historyItem, selectedAccount),
...getTradeDataFromHistory(historyItem),
...getTxStatusesFromHistory(historyItem),
...getFinalizedTxProperties(historyItem),
error_message: 'error_message',
price_impact: Number(historyItem.quote.priceData?.priceImpact ?? '0'),
};
}

Expand Down
10 changes: 10 additions & 0 deletions packages/bridge-status-controller/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,13 @@ export { BridgeId, FeeType, ActionTypes, BridgeStatusAction } from './types';
export { BridgeStatusController } from './bridge-status-controller';

export { getTxMetaFields } from './utils/transaction';

export {
isBridgeComplete,
isBridgeFailed,
getBridgeStatusKey,
getSrcTxStatus,
getDestTxStatus,
getStepStatus,
getIsDelayed,
} from './utils/tx-status';
3 changes: 2 additions & 1 deletion packages/bridge-status-controller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {
import type { HandleSnapRequest } from '@metamask/snaps-controllers';
import type {
TransactionControllerGetStateAction,
TransactionControllerTransactionFailedEvent,
TransactionMeta,
} from '@metamask/transaction-controller';

Expand Down Expand Up @@ -349,7 +350,7 @@ type AllowedActions =
/**
* The external events available to the BridgeStatusController.
*/
type AllowedEvents = never;
type AllowedEvents = TransactionControllerTransactionFailedEvent; // TODO also subscribe to other falsy events?

/**
* The messenger for the BridgeStatusController.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
fetchBridgeTxStatus,
getBridgeStatusUrl,
getStatusRequestDto,
} from './bridge-status';
} from './fetch-tx-status';
import { BRIDGE_PROD_API_BASE_URL } from '../constants';
import { BridgeClientId } from '../types';
import type { StatusRequestWithSrcTxHash, FetchFunction } from '../types';
Expand Down
68 changes: 68 additions & 0 deletions packages/bridge-status-controller/src/utils/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,71 @@ export const getRequestMetadataFromHistory = (
security_warnings: [],
};
};

// export const getCommonProperties = (
// bridgeHistoryItem: BridgeHistoryItem,
// state: { metamask: MetricsBackgroundState },
// ) => {
// const keyring = getCurrentKeyring(state);
// const is_hardware_wallet = isHardwareKeyring(keyring.type) ?? false;

// const chain_id_source = formatChainIdToCaip(
// bridgeHistoryItem.quote.srcChainId,
// );
// const chain_id_destination = formatChainIdToCaip(
// bridgeHistoryItem.quote.destChainId,
// );

// const usd_actual_gas = getHexGasTotalUsd({ bridgeHistoryItem, state }) ?? 0;
// const usd_quoted_return = Number(
// bridgeHistoryItem.pricingData?.quotedReturnInUsd,
// );
// const usd_quoted_gas = Number(bridgeHistoryItem.pricingData?.quotedGasInUsd);

// const isBridgeTx =
// bridgeHistoryItem.quote.srcChainId !== bridgeHistoryItem.quote.destChainId;

// return {
// action_type: 'crosschain_v1' as unknown,

// slippage_limit: bridgeHistoryItem.slippagePercentage,
// custom_slippage:
// bridgeHistoryItem.slippagePercentage !== BRIDGE_DEFAULT_SLIPPAGE,

// chain_id_source,
// chain_id_destination,

// token_address_source: bridgeHistoryItem.quote.srcAsset.assetId,
// token_address_destination: bridgeHistoryItem.quote.destAsset.assetId,

// token_symbol_source: bridgeHistoryItem.quote.srcAsset.symbol,
// token_symbol_destination: bridgeHistoryItem.quote.destAsset.symbol,

// stx_enabled: getIsSmartTransaction(state, chain_id_source),
// is_hardware_wallet,

// provider: formatProviderLabel(bridgeHistoryItem.quote),

// quoted_time_minutes: bridgeHistoryItem.estimatedProcessingTimeInSeconds
// ? bridgeHistoryItem.estimatedProcessingTimeInSeconds / 60
// : 0,
// actual_time_minutes:
// bridgeHistoryItem.completionTime && bridgeHistoryItem.startTime
// ? (bridgeHistoryItem.completionTime - bridgeHistoryItem.startTime) /
// 1000 /
// 60
// : 0,

// swap_type: (isBridgeTx
// ? 'crosschain_v1'
// : 'swapbridge_v1') as unknown as RequestMetadata['swap_type'],

// usd_amount_source: Number(bridgeHistoryItem.pricingData?.amountSentInUsd),

// usd_actual_gas,
// usd_quoted_return,
// usd_quoted_gas,

// gas_included: false, // TODO check if trade has gas included
// };
// };
Loading
Loading