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
1 change: 1 addition & 0 deletions packages/transaction-pay-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Ignore synthetic gas legs when determining Across support for perps direct deposits ([#8527](https://github.com/MetaMask/core/pull/8527))
- Route Across status polling through the configured Across API base and support `depositTxnRef`/`fillTxnRef` for Across status responses ([#8512](https://github.com/MetaMask/core/pull/8512))

## [19.2.1]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,86 @@ describe('AcrossStrategy', () => {
).toBe(true);
});

it('ignores synthetic gas legs for supported perps direct deposits', () => {
const strategy = new AcrossStrategy();
expect(
strategy.supports({
...baseRequest,
transaction: {
...TRANSACTION_META_MOCK,
type: TransactionType.perpsDeposit,
} as TransactionMeta,
requests: [
{
from: '0xabc' as Hex,
sourceBalanceRaw: '100',
sourceChainId: CHAIN_ID_ARBITRUM,
sourceTokenAddress: ARBITRUM_USDC_ADDRESS,
sourceTokenAmount: '100',
targetAmountMinimum: '100',
targetChainId: CHAIN_ID_ARBITRUM,
targetTokenAddress: ARBITRUM_USDC_ADDRESS,
},
{
from: '0xabc' as Hex,
sourceBalanceRaw: '100',
sourceChainId: CHAIN_ID_ARBITRUM,
sourceTokenAddress: ARBITRUM_USDC_ADDRESS,
sourceTokenAmount: '100',
targetAmountMinimum: '0',
targetChainId: CHAIN_ID_ARBITRUM,
targetTokenAddress:
'0x0000000000000000000000000000000000000000' as Hex,
},
],
}),
).toBe(true);
});

it('returns false when all requests are synthetic zero-minimum legs', () => {
const strategy = new AcrossStrategy();
expect(
strategy.supports({
...baseRequest,
requests: [
{
from: '0xabc' as Hex,
sourceBalanceRaw: '100',
sourceChainId: CHAIN_ID_ARBITRUM,
sourceTokenAddress: ARBITRUM_USDC_ADDRESS,
sourceTokenAmount: '100',
targetAmountMinimum: '0',
targetChainId: CHAIN_ID_ARBITRUM,
targetTokenAddress:
'0x0000000000000000000000000000000000000000' as Hex,
},
],
}),
).toBe(false);
});

it('treats max-amount requests as actionable even with zero minimums', () => {
const strategy = new AcrossStrategy();
expect(
strategy.supports({
...baseRequest,
requests: [
{
from: '0xabc' as Hex,
isMaxAmount: true,
sourceBalanceRaw: '100',
sourceChainId: '0x1' as Hex,
sourceTokenAddress: '0xabc' as Hex,
sourceTokenAmount: '100',
targetAmountMinimum: '0',
targetChainId: '0x2' as Hex,
targetTokenAddress: '0xdef' as Hex,
},
],
}),
).toBe(true);
});

it('returns false for unsupported perps deposits', () => {
const strategy = new AcrossStrategy();
expect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getPayStrategiesConfig } from '../../utils/feature-flags';
import { getAcrossQuotes } from './across-quotes';
import { submitAcrossQuotes } from './across-submit';
import { isSupportedAcrossPerpsDepositRequest } from './perps';
import { isAcrossQuoteRequest } from './requests';
import type { AcrossQuote } from './types';

export class AcrossStrategy implements PayStrategy<AcrossQuote> {
Expand All @@ -20,8 +21,14 @@ export class AcrossStrategy implements PayStrategy<AcrossQuote> {
return false;
}

const actionableRequests = request.requests.filter(isAcrossQuoteRequest);

if (actionableRequests.length === 0) {
return false;
}

if (request.transaction?.type === TransactionType.perpsDeposit) {
return request.requests.every((singleRequest) =>
return actionableRequests.every((singleRequest) =>
isSupportedAcrossPerpsDepositRequest(
singleRequest,
request.transaction?.type,
Expand All @@ -30,7 +37,7 @@ export class AcrossStrategy implements PayStrategy<AcrossQuote> {
}

// Across doesn't support same-chain swaps (e.g. mUSD conversions).
return request.requests.every(
return actionableRequests.every(
(singleRequest) =>
singleRequest.sourceChainId !== singleRequest.targetChainId,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { estimateQuoteGasLimits } from '../../utils/quote-gas';
import { getTokenFiatRate } from '../../utils/token';
import { getAcrossDestination } from './across-actions';
import { normalizeAcrossRequest } from './perps';
import { isAcrossQuoteRequest } from './requests';
import { getAcrossOrderedTransactions } from './transactions';
import type {
AcrossAction,
Expand Down Expand Up @@ -50,12 +51,7 @@ export async function getAcrossQuotes(
log('Fetching quotes', requests);

try {
const normalizedRequests = requests.filter(
(singleRequest) =>
singleRequest.isMaxAmount === true ||
(singleRequest.targetAmountMinimum !== undefined &&
singleRequest.targetAmountMinimum !== '0'),
);
const normalizedRequests = requests.filter(isAcrossQuoteRequest);

if (normalizedRequests.length === 0) {
return [];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { QuoteRequest } from '../../types';

export function isAcrossQuoteRequest(request: QuoteRequest): boolean {
return (
request.isMaxAmount === true ||
(request.targetAmountMinimum !== undefined &&
request.targetAmountMinimum !== '0')
);
}
Loading