Skip to content

feat(transaction-pay): add Across strategy support#7886

Open
pedronfigueiredo wants to merge 1 commit intomainfrom
cor-6997-across-strategy
Open

feat(transaction-pay): add Across strategy support#7886
pedronfigueiredo wants to merge 1 commit intomainfrom
cor-6997-across-strategy

Conversation

@pedronfigueiredo
Copy link
Contributor

@pedronfigueiredo pedronfigueiredo commented Feb 10, 2026

Explanation

This PR extracts the Across strategy work on top of the provider-fallback baseline.

It adds:

  • Across strategy wiring (across strategy type + registration)
  • Across quote retrieval/parsing/normalization
  • Across submit flow for approval + swap/deposit execution paths
  • Across-specific types/constants required for compilation
  • Minimal selection/config hooks to make Across selectable
  • Changelog entries for transaction-controller and transaction-pay-controller

References

Addresses: https://github.com/MetaMask/MetaMask-planning/issues/6997

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Adds a new on-chain submission path that builds/sends approval and deposit transactions and introduces external API polling, so failures could impact transaction execution and fee/gas calculations. Feature-flag gating and extensive tests reduce but don’t eliminate integration risk.

Overview
Adds a new Across transaction-pay strategy and makes it part of the default strategy order/selection, with feature-flagged enablement and strategy-specific config (apiBase, integratorId, allowSameChain, postActionsEnabled).

Implements Across quote retrieval/normalization and submission: calls Across /swap/approval with optional MetaMask app-fee params and optional post-actions, estimates gas with buffering and fallbacks, submits approval+deposit as a batch (or a single deposit), marks intents complete, tracks required transaction IDs, and optionally polls Across /deposit/status to return the destination/fill hash.

Extends shared types/utilities to support this flow (new TransactionPayAction structure, getPayStrategiesConfig, shared sumAmounts/getFiatValueFromUsd, and a reusable estimateGasLimitWithBufferOrFallback), updates Relay’s supports gating, and introduces new TransactionTypes (perpsAcrossDeposit, predictAcrossDeposit) with changelog entries.

Written by Cursor Bugbot for commit 3c7fd02. This will update automatically on new commits. Configure here.

@pedronfigueiredo pedronfigueiredo force-pushed the cor-6997-across-strategy branch 2 times, most recently from 665488f to 8be8f8c Compare February 10, 2026 12:09
@pedronfigueiredo pedronfigueiredo force-pushed the cor-6992-extract-fallback-mechanism branch 4 times, most recently from 9cd0f37 to a6c9af9 Compare February 13, 2026 10:47
return getFeatureFlags(messenger).relayFallbackGas;
}

export async function estimateGasWithBufferOrFallback({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

estimateGasLimit?

};
}

export function getFallbackGas(messenger: TransactionPayControllerMessenger): {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be in feature-flags.ts?

error = caughtError;
}

const fallbackGas = getFallbackGas(messenger);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debatable whether we should have fallback gas or throw as it implies the transaction would revert?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fallback is now option but off by default

across?: PayStrategyConfigRaw;
relay?: {
enabled?: boolean;
relayQuoteUrl?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this redundant as we already have the top level value?

slippage: number;
};

export type PayStrategyConfigRaw = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be AcrossConfig?

messenger,
});

const max = calculateGasCost({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need gas station support here, but can do that in a future PR and re-use the Relay logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a ticket for this

request: QuoteRequest,
): Promise<TransactionPayQuote<AcrossQuote>['fees']['sourceNetwork']> {
const { from } = request;
const { swapTx } = quote;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also need to include gas cost of approvalTxns?

const chainId = toHex(params.chainId);
const value = toHex(params.value ?? '0x0');

const gas = await estimateGasWithBuffer(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to duplicate the gas logic again, but store the gas limits in the quote to use during submit, so we know the network fees will match.

data: params.data,
from,
gas: toHex(gas),
maxFeePerGas: normalizeOptionalHex(params.maxFeePerGas),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can they not return gas fee properties?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure I understand the question here, it's simply normalising to hex if needed.

}

await Promise.all(
transactionIds.map((txId) => waitForTransactionConfirmed(txId, messenger)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're waiting for the deposit transactions to succeed, but we also need to poll the Across API to verify the status of their transactions on the target chain.

Looks like /deposit/status?

@pedronfigueiredo pedronfigueiredo force-pushed the cor-6992-extract-fallback-mechanism branch 4 times, most recently from 08bac6a to 26c090a Compare February 16, 2026 10:51
@pedronfigueiredo pedronfigueiredo force-pushed the cor-6997-across-strategy branch 2 times, most recently from 303f7d7 to d1799f1 Compare February 25, 2026 12:12
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.


if (request.transaction?.type === TransactionType.perpsAcrossDeposit) {
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing predictAcrossDeposit guard causes potential recursion

High Severity

The supports() guard only rejects TransactionType.perpsAcrossDeposit but not TransactionType.predictAcrossDeposit. Since getAcrossDepositType maps predictDepositpredictAcrossDeposit, the Across strategy will incorrectly consider its own predict-type deposit transactions as eligible, potentially causing recursive re-processing.

Additional Locations (1)

Fix in Cursor Fix in Web

@pedronfigueiredo pedronfigueiredo force-pushed the cor-6997-across-strategy branch 2 times, most recently from 78893dc to 0680f84 Compare February 25, 2026 13:50
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants