Skip to content
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
8 changes: 6 additions & 2 deletions packages/bridge-controller/src/bridge-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,17 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
*
* @param quoteRequest - The parameters for quote requests to fetch
* @param abortSignal - The abort signal to cancel all the requests
* @param featureId - The feature ID that maps to quoteParam overrides from LD
* @param featureIdOverride - Optional feature ID override (for backward compatibility). If not provided, uses featureId from quoteRequest.
* @returns A list of validated quotes
*/
fetchQuotes = async (
quoteRequest: GenericQuoteRequest,
abortSignal: AbortSignal | null = null,
featureId: FeatureId | null = null,
featureIdOverride: FeatureId | null = null,
): Promise<(QuoteResponse & L1GasFees & NonEvmFees)[]> => {
// Use override if provided (ex: perps case), otherwise use from request (ex: card case)
const featureId = featureIdOverride ?? quoteRequest.featureId ?? null;

const bridgeFeatureFlags = getBridgeFeatureFlags(this.messenger);
// If featureId is specified, retrieve the quoteRequestOverrides for that featureId
const quoteRequestOverrides = featureId
Expand Down Expand Up @@ -640,6 +643,7 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
const quotes = await this.fetchQuotes(
updatedQuoteRequest,
this.#abortController?.signal,
updatedQuoteRequest.featureId ?? null,
);
this.update((state) => {
// Set the initial load time if this is the first fetch
Expand Down
4 changes: 4 additions & 0 deletions packages/bridge-controller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ export type QuoteRequest<
* The fee that will be charged by MetaMask
*/
fee?: number;
/**
* Optional feature ID for feature-specific quote overrides and transaction types
*/
featureId?: FeatureId;
};

export enum StatusTypes {
Expand Down
2 changes: 2 additions & 0 deletions packages/bridge-controller/src/utils/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export enum FeeType {

export enum FeatureId {
PERPS = 'perps',
PREDICT = 'predict',
CARD = 'card',
}

export enum ActionTypes {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
isBitcoinTrade,
isTronTrade,
AbortReason,
FeatureId,
} from '@metamask/bridge-controller';
import type { TraceCallback } from '@metamask/controller-utils';
import { toHex } from '@metamask/controller-utils';
Expand Down Expand Up @@ -77,10 +78,12 @@ import {
import {
findAndUpdateTransactionsInBatch,
getAddTransactionBatchParams,
getApprovalTransactionType,
getClientRequest,
getHistoryKey,
getIntentFromQuote,
getStatusRequestParams,
getTransactionType,
handleApprovalDelay,
handleMobileHardwareWalletDelay,
handleNonEvmTxResponse,
Expand Down Expand Up @@ -220,6 +223,7 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
if (
type &&
[
// TODO: Handle all cases here.
TransactionType.bridge,
TransactionType.swap,
TransactionType.bridgeApproval,
Expand Down Expand Up @@ -1196,15 +1200,18 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
approval?: TxData,
resetApproval?: TxData,
requireApproval?: boolean,
featureId?: FeatureId,
): Promise<TransactionMeta | undefined> => {
if (approval) {
const approveTx = async (): Promise<TransactionMeta> => {
await this.#handleUSDTAllowanceReset(resetApproval);
await this.#handleUSDTAllowanceReset(
resetApproval,
isBridgeTx,
featureId,
);

const approvalTxMeta = await this.#handleEvmTransaction({
transactionType: isBridgeTx
? TransactionType.bridgeApproval
: TransactionType.swapApproval,
transactionType: getApprovalTransactionType(isBridgeTx, featureId),
trade: approval,
requireApproval,
});
Expand Down Expand Up @@ -1316,10 +1323,15 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid

readonly #handleUSDTAllowanceReset = async (
resetApproval?: TxData,
isBridgeTx?: boolean,
featureId?: FeatureId,
): Promise<void> => {
if (resetApproval) {
await this.#handleEvmTransaction({
transactionType: TransactionType.bridgeApproval,
transactionType: getApprovalTransactionType(
isBridgeTx ?? true,
featureId,
),
trade: resetApproval,
});
}
Expand Down Expand Up @@ -1615,6 +1627,7 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
: undefined,
quoteResponse.resetApproval,
requireApproval,
quoteResponse.featureId,
);

approvalTxId = approvalTxMeta?.id;
Expand Down Expand Up @@ -1645,9 +1658,10 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
// Pass txFee when gasIncluded is true to use the quote's gas fees
// instead of re-estimating (which would fail for max native token swaps)
const tradeTxMeta = await this.#handleEvmTransaction({
transactionType: isBridgeTx
? TransactionType.bridge
: TransactionType.swap,
transactionType: getTransactionType(
isBridgeTx,
quoteResponse.featureId,
),
trade: quoteResponse.trade,
requireApproval,
txFee: quoteResponse.quote.gasIncluded
Expand Down Expand Up @@ -1760,6 +1774,7 @@ export class BridgeStatusController extends StaticIntervalPollingController<Brid
: undefined,
quoteResponse.resetApproval,
/* requireApproval */ false,
quoteResponse.featureId,
);
approvalTxId = approvalTxMeta?.id;

Expand Down
61 changes: 53 additions & 8 deletions packages/bridge-status-controller/src/utils/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
formatChainIdToCaip,
formatChainIdToHex,
isCrossChain,
FeatureId,
} from '@metamask/bridge-controller';
import type {
Intent,
Expand Down Expand Up @@ -38,6 +39,53 @@ import type {

export const generateActionId = () => (Date.now() + Math.random()).toString();

/**
* Gets the appropriate transaction type based on whether it's a bridge transaction
* and the optional feature ID.
*
* @param isBridgeTx - Whether the transaction is a cross-chain bridge transaction
* @param featureId - Optional feature ID for feature-specific transaction types
* @returns The transaction type
*/
export const getBridgeTransactionType = (
isBridgeTx: boolean,
featureId?: FeatureId,
): TransactionType => {
switch (featureId) {
case FeatureId.CARD:
return isBridgeTx
? TransactionType.cardBridgeDeposit
: TransactionType.cardSwapDeposit;
// For now this handles the perps case for example but we could have more cases for it as well.
default:
return isBridgeTx ? TransactionType.bridge : TransactionType.swap;
}
};

/**
* Gets the appropriate approval transaction type based on whether it's a bridge transaction
* and the optional feature ID.
*
* @param isBridgeTx - Whether the transaction is a cross-chain bridge transaction
* @param featureId - Optional feature ID for feature-specific transaction types
* @returns The approval transaction type
*/
export const getBridgeApprovalTransactionType = (
isBridgeTx: boolean,
featureId?: FeatureId,
): TransactionType => {
switch (featureId) {
case FeatureId.CARD:
return isBridgeTx
? TransactionType.cardBridgeApproval
: TransactionType.cardSwapApproval;
default:
return isBridgeTx
? TransactionType.bridgeApproval
: TransactionType.swapApproval;
}
};

export const getStatusRequestParams = (quoteResponse: QuoteResponse) => {
return {
bridgeId: quoteResponse.quote.bridgeId,
Expand Down Expand Up @@ -159,7 +207,7 @@ export const handleNonEvmTxResponse = (
chainId: hexChainId,
networkClientId: snapId ?? hexChainId,
txParams: { from: selectedAccountAddress, data: tradeData },
type: isBridgeTx ? TransactionType.bridge : TransactionType.swap,
type: getBridgeTransactionType(isBridgeTx, quoteResponse.featureId),
status: TransactionStatus.submitted,
hash, // Add the transaction signature as hash
origin: snapId,
Expand Down Expand Up @@ -280,6 +328,7 @@ export const getAddTransactionBatchParams = async ({
},
sentAmount,
toTokenAmount,
featureId,
},
requireApproval = false,
estimateGasFeeFn,
Expand Down Expand Up @@ -325,9 +374,7 @@ export const getAddTransactionBatchParams = async ({
isGasless ? txFee : undefined,
);
transactions.push({
type: isBridgeTx
? TransactionType.bridgeApproval
: TransactionType.swapApproval,
type: getBridgeApprovalTransactionType(isBridgeTx, featureId),
params: toBatchTxParams(disable7702, resetApproval, gasFees),
});
}
Expand All @@ -342,9 +389,7 @@ export const getAddTransactionBatchParams = async ({
isGasless ? txFee : undefined,
);
transactions.push({
type: isBridgeTx
? TransactionType.bridgeApproval
: TransactionType.swapApproval,
type: getBridgeApprovalTransactionType(isBridgeTx, featureId),
params: toBatchTxParams(disable7702, approval, gasFees),
});
}
Expand All @@ -358,7 +403,7 @@ export const getAddTransactionBatchParams = async ({
isGasless ? txFee : undefined,
);
transactions.push({
type: isBridgeTx ? TransactionType.bridge : TransactionType.swap,
type: getBridgeTransactionType(isBridgeTx, featureId),
params: toBatchTxParams(disable7702, trade, gasFees),
assetsFiatValues: {
sending: sentAmount?.valueInCurrency?.toString(),
Expand Down
20 changes: 20 additions & 0 deletions packages/transaction-controller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,26 @@ export enum TransactionType {
*/
cancel = 'cancel',

/**
* A bridge deposit transaction initiated via Card.
*/
cardBridgeDeposit = 'cardBridgeDeposit',

/**
* An approval transaction for a bridge initiated via Card.
*/
cardBridgeApproval = 'cardBridgeApproval',

/**
* A swap deposit transaction initiated via Card.
*/
cardSwapDeposit = 'cardSwapDeposit',

/**
* An approval transaction for a swap initiated via Card.
*/
cardSwapApproval = 'cardSwapApproval',

/**
* A transaction that is interacting with a smart contract's methods that we
* have not treated as a special case, such as approve, transfer, and
Expand Down
Loading