Skip to content

Commit 8e85d4e

Browse files
authored
Merge branch 'main' into ogp/enable-max-withdraw-to-ma
2 parents 3c620b9 + a9b5174 commit 8e85d4e

7 files changed

Lines changed: 145 additions & 11 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@metamask/core-monorepo",
3-
"version": "1119.0.0",
3+
"version": "1120.0.0",
44
"private": true,
55
"description": "Monorepo for packages shared between MetaMask clients",
66
"repository": {

packages/transaction-pay-controller/CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [24.1.0]
11+
1012
### Added
1113

1214
- Enable max-amount Relay bridge flows to deposit settled mUSD into the Money Account vault via a post-Relay sponsored deposit ([#9497](https://github.com/MetaMask/core/pull/9497))
15+
- Add `getStablecoins` feature flag reader that resolves the stablecoin list from the `stable-tokens` LaunchDarkly flag, falling back to the hardcoded constant when absent ([#9495](https://github.com/MetaMask/core/pull/9495))
1316
- Add generic signature steps to the server pay strategy, supporting EIP-712 sign-then-POST flows ([#9051](https://github.com/MetaMask/core/pull/9051))
1417
- Trigger quote refresh when `txParams.to` or `requiredAssets` changes on a transaction, in addition to the existing `txParams.data` trigger
1518

1619
### Changed
1720

21+
- Replace hardcoded `STABLECOINS` usage in `token.ts` and `relay-quotes.ts` with the remotely configurable `getStablecoins(messenger)` lookup ([#9495](https://github.com/MetaMask/core/pull/9495))
1822
- Bump `@metamask/assets-controller` from `^10.2.1` to `^11.0.0` ([#9485](https://github.com/MetaMask/core/pull/9485))
1923
- Bump `@metamask/ramps-controller` from `^16.0.0` to `^17.0.0` ([#9491](https://github.com/MetaMask/core/pull/9491))
2024

@@ -1286,7 +1290,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12861290

12871291
- Initial release ([#6820](https://github.com/MetaMask/core/pull/6820))
12881292

1289-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@24.0.3...HEAD
1293+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@24.1.0...HEAD
1294+
[24.1.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@24.0.3...@metamask/transaction-pay-controller@24.1.0
12901295
[24.0.3]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@24.0.2...@metamask/transaction-pay-controller@24.0.3
12911296
[24.0.2]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@24.0.1...@metamask/transaction-pay-controller@24.0.2
12921297
[24.0.1]: https://github.com/MetaMask/core/compare/@metamask/transaction-pay-controller@24.0.0...@metamask/transaction-pay-controller@24.0.1

packages/transaction-pay-controller/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@metamask/transaction-pay-controller",
3-
"version": "24.0.3",
3+
"version": "24.1.0",
44
"description": "Manages alternate payment strategies to provide required funds for transactions in MetaMask",
55
"keywords": [
66
"Ethereum",

packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
NATIVE_TOKEN_ADDRESS,
2222
PERPS_DEPOSIT_TYPES,
2323
USDC_DECIMALS,
24-
STABLECOINS,
2524
PaymentOverride,
2625
} from '../../constants';
2726
import { projectLogger } from '../../logger';
@@ -38,6 +37,7 @@ import {
3837
getFeatureFlags,
3938
getRelayOriginGasOverhead,
4039
getSlippage,
40+
getStablecoins,
4141
isEIP7702Chain,
4242
isRelayExecuteEnabled,
4343
} from '../../utils/feature-flags';
@@ -626,7 +626,7 @@ async function normalizeQuote(
626626
usdToFiatRate,
627627
);
628628

629-
const subsidizedFeeUsd = getSubsidizedFeeAmountUsd(quote);
629+
const subsidizedFeeUsd = getSubsidizedFeeAmountUsd(messenger, quote);
630630

631631
const appFeeUsd = new BigNumber(quote.fees?.app?.amountUsd ?? '0');
632632
const metaMaskFee = getFiatValueFromUsd(appFeeUsd, usdToFiatRate);
@@ -667,6 +667,7 @@ async function normalizeQuote(
667667
};
668668

669669
const isTargetStablecoin = isStablecoin(
670+
messenger,
670671
request.targetChainId,
671672
request.targetTokenAddress,
672673
);
@@ -1243,7 +1244,10 @@ function getTransferRecipient(data: Hex): Hex {
12431244
.decodeFunctionData('transfer', data)
12441245
.to.toLowerCase();
12451246
}
1246-
function getSubsidizedFeeAmountUsd(quote: RelayQuote): BigNumber {
1247+
function getSubsidizedFeeAmountUsd(
1248+
messenger: TransactionPayControllerMessenger,
1249+
quote: RelayQuote,
1250+
): BigNumber {
12471251
const subsidizedFee = quote.fees?.subsidized;
12481252
const amountUsd = new BigNumber(subsidizedFee?.amountUsd ?? '0');
12491253
const amountFormatted = new BigNumber(subsidizedFee?.amountFormatted ?? '0');
@@ -1253,15 +1257,22 @@ function getSubsidizedFeeAmountUsd(quote: RelayQuote): BigNumber {
12531257
}
12541258

12551259
const isSubsidizedStablecoin = isStablecoin(
1260+
messenger,
12561261
toHex(subsidizedFee.currency.chainId),
12571262
subsidizedFee.currency.address,
12581263
);
12591264

12601265
return isSubsidizedStablecoin ? amountFormatted : amountUsd;
12611266
}
12621267

1263-
function isStablecoin(chainId: string, tokenAddress: string): boolean {
1268+
function isStablecoin(
1269+
messenger: TransactionPayControllerMessenger,
1270+
chainId: string,
1271+
tokenAddress: string,
1272+
): boolean {
12641273
return Boolean(
1265-
STABLECOINS[chainId as Hex]?.includes(tokenAddress.toLowerCase() as Hex),
1274+
getStablecoins(messenger)[chainId as Hex]?.includes(
1275+
tokenAddress.toLowerCase() as Hex,
1276+
),
12661277
);
12671278
}

packages/transaction-pay-controller/src/utils/feature-flags.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
getRelayOriginGasOverhead,
3232
getRelayPollingInterval,
3333
getRelayPollingTimeout,
34+
getStablecoins,
3435
isChainExcludedFromInfura,
3536
isEIP7702Chain,
3637
isRelayExecuteEnabled,
@@ -1943,4 +1944,85 @@ describe('Feature Flags Utils', () => {
19431944
).toBe(DEFAULT_HYPERLIQUID_ACTIVATION_FEE_USD);
19441945
});
19451946
});
1947+
1948+
describe('getStablecoins', () => {
1949+
it('returns hardcoded fallback when flag is absent', () => {
1950+
const result = getStablecoins(messenger);
1951+
expect(result).toHaveProperty('0x1');
1952+
expect(result['0x1' as Hex]).toContain(
1953+
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
1954+
);
1955+
});
1956+
1957+
it('returns flag value when stable-tokens is a valid object', () => {
1958+
const flagValue = {
1959+
'0x1': ['0xaaa', '0xbbb'],
1960+
'0xa4b1': ['0xccc'],
1961+
};
1962+
1963+
getRemoteFeatureFlagControllerStateMock.mockReturnValue({
1964+
...getDefaultRemoteFeatureFlagControllerState(),
1965+
remoteFeatureFlags: {
1966+
'stable-tokens': flagValue,
1967+
},
1968+
});
1969+
1970+
expect(getStablecoins(messenger)).toStrictEqual(flagValue);
1971+
});
1972+
1973+
it('normalizes addresses and chain IDs to lowercase', () => {
1974+
getRemoteFeatureFlagControllerStateMock.mockReturnValue({
1975+
...getDefaultRemoteFeatureFlagControllerState(),
1976+
remoteFeatureFlags: {
1977+
'stable-tokens': {
1978+
'0xA4B1': ['0xAf88d065e77c8cC2239327C5EDb3A432268e5831'],
1979+
},
1980+
},
1981+
});
1982+
1983+
const result = getStablecoins(messenger);
1984+
expect(result).toStrictEqual({
1985+
'0xa4b1': ['0xaf88d065e77c8cc2239327c5edb3a432268e5831'],
1986+
});
1987+
});
1988+
1989+
it('skips non-array entries in flag value', () => {
1990+
getRemoteFeatureFlagControllerStateMock.mockReturnValue({
1991+
...getDefaultRemoteFeatureFlagControllerState(),
1992+
remoteFeatureFlags: {
1993+
'stable-tokens': {
1994+
'0x1': ['0xaaa'],
1995+
'0xa4b1': 'not-an-array',
1996+
},
1997+
},
1998+
});
1999+
2000+
const result = getStablecoins(messenger);
2001+
expect(result).toStrictEqual({ '0x1': ['0xaaa'] });
2002+
});
2003+
2004+
it('returns fallback when flag is an array', () => {
2005+
getRemoteFeatureFlagControllerStateMock.mockReturnValue({
2006+
...getDefaultRemoteFeatureFlagControllerState(),
2007+
remoteFeatureFlags: {
2008+
'stable-tokens': ['not', 'an', 'object'],
2009+
},
2010+
});
2011+
2012+
const result = getStablecoins(messenger);
2013+
expect(result).toHaveProperty('0x1');
2014+
});
2015+
2016+
it('returns fallback when flag is a primitive', () => {
2017+
getRemoteFeatureFlagControllerStateMock.mockReturnValue({
2018+
...getDefaultRemoteFeatureFlagControllerState(),
2019+
remoteFeatureFlags: {
2020+
'stable-tokens': true,
2021+
},
2022+
});
2023+
2024+
const result = getStablecoins(messenger);
2025+
expect(result).toHaveProperty('0x1');
2026+
});
2027+
});
19462028
});

packages/transaction-pay-controller/src/utils/feature-flags.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { createModuleLogger } from '@metamask/utils';
44
import { BigNumber } from 'bignumber.js';
55
import { uniq } from 'lodash';
66

7-
import { isTransactionPayStrategy, TransactionPayStrategy } from '../constants';
7+
import {
8+
isTransactionPayStrategy,
9+
STABLECOINS,
10+
TransactionPayStrategy,
11+
} from '../constants';
812
import { projectLogger } from '../logger';
913
import type { TransactionPayFiatAsset } from '../strategy/fiat/constants';
1014
import {
@@ -524,6 +528,38 @@ export function getFeatureFlags(
524528
return result;
525529
}
526530

531+
/**
532+
* Get the stablecoins map from the `stable-tokens` feature flag.
533+
* Falls back to the hardcoded {@link STABLECOINS} constant when the flag is
534+
* absent or not a valid object.
535+
*
536+
* @param messenger - Controller messenger.
537+
* @returns Stablecoins keyed by chain ID.
538+
*/
539+
export function getStablecoins(
540+
messenger: TransactionPayControllerMessenger,
541+
): Record<Hex, Hex[]> {
542+
const state = messenger.call('RemoteFeatureFlagController:getState');
543+
const flag = state.remoteFeatureFlags?.['stable-tokens'];
544+
545+
if (flag && typeof flag === 'object' && !Array.isArray(flag)) {
546+
const raw = flag as Record<string, string[]>;
547+
return Object.entries(raw).reduce<Record<Hex, Hex[]>>(
548+
(acc, [chainId, addresses]) => {
549+
if (Array.isArray(addresses)) {
550+
acc[chainId.toLowerCase() as Hex] = addresses.map(
551+
(a) => a.toLowerCase() as Hex,
552+
);
553+
}
554+
return acc;
555+
},
556+
{},
557+
);
558+
}
559+
560+
return STABLECOINS;
561+
}
562+
527563
/**
528564
* Get Pay Strategies configuration.
529565
*

packages/transaction-pay-controller/src/utils/token.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import {
1010
CHAIN_ID_POLYGON,
1111
NATIVE_TOKEN_ADDRESS,
1212
SLIP44_COIN_TYPE_BY_CHAIN,
13-
STABLECOINS,
1413
} from '../constants';
1514
import type { FiatRates, TransactionPayControllerMessenger } from '../types';
1615
import {
1716
getAssetsUnifyStateFeature,
17+
getStablecoins,
1818
isChainExcludedFromInfura,
1919
} from './feature-flags';
2020
import { getNetworkClientId, rpcRequest } from './provider';
@@ -209,7 +209,7 @@ export function getTokenFiatRate(
209209
if (nativeToFiatRate === null || nativeToUsdRate === null) {
210210
return undefined;
211211
}
212-
const isStablecoin = STABLECOINS[chainId]?.includes(
212+
const isStablecoin = getStablecoins(messenger)[chainId]?.includes(
213213
tokenAddress.toLowerCase() as Hex,
214214
);
215215

0 commit comments

Comments
 (0)