Skip to content

Commit aef7c41

Browse files
committed
Merge remote-tracking branch 'origin/main' into refactor/unlock-deep-defi-v5-compat
2 parents 6503e55 + 4e1f85a commit aef7c41

File tree

26 files changed

+648
-201
lines changed

26 files changed

+648
-201
lines changed

CHANGELOG.md

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

88
## [Unreleased]
99

10+
## [13.8.0]
11+
12+
### Added
13+
14+
- Bump bitcoin snap version to v1.4.3 (#37023)
15+
- Subscription & shield controller updates (#37371)
16+
- Added account type labels to asset details (#37332)
17+
- Show Need help link together with error on Claims form Transaction hash field (#37297)
18+
- Update payment-method component in shield-subscription page (#37340)
19+
- Added optional prop, `fallbackName` to `name-details` component. (#37299)
20+
Provide token symbol from shield pricing as a
21+
`fallbackName` prop in Shield-subscription-approval page.
22+
- Claims form back button redirect to Transaction shield page (#37333)
23+
- Set autofocus false on confirmation alert modals (#37294)
24+
- Added account type tags for bitcoin (#36927)
25+
- Use ArrowDown instead of ArrowRight on shield list buttons (#37292)
26+
- Updated two-tab components to use full-width layout for better visual balance (#37142)
27+
- Sidebar experimental PR (#36564)
28+
- Hide search field on asset picker inside Shield plan (#37193)
29+
- Updated add custom RPC flow (#36640)
30+
- Added support for buying Bitcoin and other non-EVM cryptocurrencies through the MetaMask buy crypto flow (#37146)
31+
- Added chain ID and display backend errors properly (#37174)
32+
- Added copy icon to network addresses in the account header (#37112)
33+
- Updated UI and copywriting on Shield Plan Confirm page (#37159)
34+
- Updated pay with crypto copywriting (#37110)
35+
36+
### Fixed
37+
38+
- Updates add account button text to `Add account` (#37288)
39+
- Fixes `Background connection unresponsive` issues caused by the UI attempting to load before the background process has (#36729)
40+
begun initializing.
41+
- Updated smart account terminology in the UI from "Enable smart contract account" to "Use smart account" (#37235)
42+
- Transaction shield covered button show modal (#37225)
43+
- Update broken onekey tutorial link. (#37217)
44+
- Added popular networks (Arbitrum, BSC, Optimism, Polygon, Sei, and Base) by default for all users, filtered to only (#37172)
45+
include networks supported by accounts API v4
46+
- Fixed a bug causing the setting showNativeTokenAsMainBalance to not display native user balance when ON. (#37233)
47+
- Enables storing EIP-7715 permissions granted by the user (#37158)
48+
- Reduce excess re-renders (#37293)
49+
- Aligned the Import Wallet UI in the 'Add Wallet' flow with the existing 'Import SRP' onboarding design for consistency (#37207)
50+
- Fixed shield subscription trial days value inconsistency (#37295)
51+
- Removed scroll state for MetaMetric UI when opening it on small-screen devices. (#37220)
52+
- Fixed address security alerts to be properly cached per network, preventing incorrect security warnings when switching between (#36708)
53+
chains
54+
- Fix wrong link on BTC asset details (#37180)
55+
- Added modal overlay for onboarding modal (#37206)
56+
- Fixed delay checking if token is already imported inside import tokens modal. (#37116)
57+
- Fix BTC activity is not shown on asset details (#37170)
58+
- Fixed Solana and Bitcoin icons not showing in the details page (#37065)
59+
- Fixed pre-emptive phishing page redirect on Google search results. (#37029)
60+
- Normalize basePath trailing slash in getRelativeLocationForNestedRoutes (#37161)
61+
- Fixed an issue where some avatars would be out of sync (#37173)
62+
- Fix the manual refresh and token detection (#37130)
63+
- Fixes subscription-polling when shield feature is disabled (#37476)
64+
- Fixes network nicknames for popular networks (#37477)
65+
- Fixes historical prices chart ranges for non-evm assets (#37505)
66+
- Fixes issue where we're failing to log swap comparisons in some scenarios (#37496)
67+
- Fixes token image and symbol in confirmation for EVM transactions when nonEVM network is selected at wallet view (#37491)
68+
- Fixes a bug where tokenId for NFT was not being sent correctly in send flow (#37555)
69+
1070
## [13.7.0]
1171

1272
### Added
@@ -1009,7 +1069,8 @@ authorized by the user.` error until the user fully revoked dapp
10091069
- This changelog was split off with 12.22.0
10101070
- All older changes can be found in [docs/CHANGELOG_older.md](https://github.com/MetaMask/metamask-extension/blob/main/docs/CHANGELOG_older.md)
10111071

1012-
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v13.7.0...HEAD
1072+
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v13.8.0...HEAD
1073+
[13.8.0]: https://github.com/MetaMask/metamask-extension/compare/v13.7.0...v13.8.0
10131074
[13.7.0]: https://github.com/MetaMask/metamask-extension/compare/v13.6.0...v13.7.0
10141075
[13.6.0]: https://github.com/MetaMask/metamask-extension/compare/v13.5.0...v13.6.0
10151076
[13.5.0]: https://github.com/MetaMask/metamask-extension/compare/v13.4.3...v13.5.0

builds.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ buildTypes:
2121
- multi-srp
2222
- multichain
2323
- bitcoin
24+
- bitcoin-swaps
2425
# Additional env variables that are specific to this build
2526
env:
2627
- INFURA_PROD_PROJECT_ID
@@ -450,6 +451,3 @@ env:
450451
# This should only be used for local testing, and should not be enabled in any
451452
# production builds (including beta and Flask).
452453
- FORCE_PREINSTALLED_SNAPS: 'false'
453-
454-
# Enable dapp swap shield implementation
455-
- DAPP_SWAP_SHIELD_ENABLED: false

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "metamask-crx",
3-
"version": "13.9.0",
3+
"version": "13.10.0",
44
"private": true,
55
"repository": {
66
"type": "git",
@@ -321,7 +321,7 @@
321321
"@metamask/logging-controller": "^7.0.0",
322322
"@metamask/logo": "^4.0.0",
323323
"@metamask/message-manager": "^14.0.0",
324-
"@metamask/message-signing-snap": "1.1.3",
324+
"@metamask/message-signing-snap": "1.1.4",
325325
"@metamask/messenger": "^0.3.0",
326326
"@metamask/metamask-eth-abis": "^3.1.1",
327327
"@metamask/multichain-account-service": "^2.1.0",

test/e2e/tests/confirmations/transactions/metrics.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ import { assertAdvancedGasDetails } from './shared';
1818
const { withFixtures, getEventPayloads } = require('../../../helpers');
1919
const FixtureBuilder = require('../../../fixture-builder');
2020

21+
// Type definition for event structure
22+
type MetricsEvent = {
23+
event: string;
24+
[key: string]: unknown;
25+
};
26+
2127
describe('Metrics', function () {
2228
it('Sends a contract interaction type 2 transaction (EIP1559) with the right properties in the metric events', async function () {
2329
await withFixtures(
@@ -75,6 +81,18 @@ describe('Metrics', function () {
7581
await transactionConfirmation.checkGasFeeSymbol('ETH');
7682
await transactionConfirmation.checkGasFee('0.0009');
7783

84+
// Wait for Transaction Added events before enabling advanced view
85+
// This ensures contract interaction "Added" events have transaction_advanced_view: undefined
86+
await driver.wait(async () => {
87+
const currentEvents = await getEventPayloads(driver, mockedEndpoints);
88+
const addedEvents = currentEvents.filter(
89+
(event: MetricsEvent) =>
90+
event.event === 'Transaction Added' ||
91+
event.event === 'Transaction Added Anon',
92+
);
93+
return addedEvents.length >= 4; // Wait for 4 "Added" events (2 deployment + 2 contract interaction)
94+
}, 10000);
95+
7896
// enable the advanced view
7997
await transactionConfirmation.clickAdvancedDetailsButton();
8098
await transactionConfirmation.verifyAdvancedDetailsHexDataIsDisplayed(

test/env.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,3 @@ process.env.METAMASK_VERSION = 'MOCK_VERSION';
1818
process.env.TZ = 'UTC';
1919
process.env.SEEDLESS_ONBOARDING_ENABLED = 'true';
2020
process.env.METAMASK_SHIELD_ENABLED = 'false';
21-
process.env.DAPP_SWAP_SHIELD_ENABLED = 'true';

ui/components/app/import-token/token-list/token-list.component.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export default class TokenList extends Component {
7171
.fill(undefined)
7272
.map((_, i) => {
7373
const { symbol, name, address, chainId } = results[i] || {};
74+
const uniqueKey = `${address || 'unknown'}-${chainId || 'nochain'}-${i}-${symbol || 'nosymbol'}-${name || 'noname'}`;
7475
let tokenAlreadyAdded = false;
7576

7677
tokenAlreadyAdded = checkExistingAllTokens(
@@ -85,7 +86,7 @@ export default class TokenList extends Component {
8586
return (
8687
Boolean(results[i]?.iconUrl || symbol || name) && (
8788
<Box
88-
key={address}
89+
key={uniqueKey}
8990
display={Display.Flex}
9091
alignItems={AlignItems.center}
9192
flexDirection={FlexDirection.Row}

ui/components/app/multichain-bridge-transaction-details-modal/multichain-bridge-transaction-details-modal.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,16 @@ const MultichainBridgeTransactionDetailsModal = ({
450450
: assetData.amount;
451451
return `${displayAmount} ${assetData.unit}`;
452452
}
453+
454+
// Fallback to quote data when transaction.from is empty (e.g., BTC transactions)
455+
if (quote?.srcTokenAmount && quote?.srcAsset?.symbol) {
456+
const formattedAmount = formatDestTokenAmount(
457+
quote.srcTokenAmount,
458+
quote.srcAsset.decimals,
459+
);
460+
return `${formattedAmount} ${quote.srcAsset.symbol}`;
461+
}
462+
453463
return '';
454464
})()}
455465
</Text>

ui/contexts/rive-wasm/index.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,21 @@ const RiveWasmContext = createContext<{
5454
error: Error | undefined;
5555
urlBufferMap: Record<string, ArrayBuffer>;
5656
setUrlBufferCache: (url: string, buffer: ArrayBuffer) => void;
57+
animationCompleted: Record<string, boolean>;
58+
setIsAnimationCompleted: (
59+
animationName: string,
60+
isAnimationCompleted: boolean,
61+
) => void;
5762
}>({
5863
isWasmReady: false,
5964
loading: false,
6065
error: undefined,
6166
urlBufferMap: {},
6267
// eslint-disable-next-line no-empty-function
6368
setUrlBufferCache: () => {},
69+
animationCompleted: {},
70+
// eslint-disable-next-line no-empty-function
71+
setIsAnimationCompleted: () => {},
6472
});
6573

6674
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31860
@@ -73,18 +81,40 @@ export default function RiveWasmProvider({
7381
const [urlBufferMap, setUrlBufferMap] = useState<Record<string, ArrayBuffer>>(
7482
{},
7583
);
84+
const [animationCompleted, setAnimationCompleted] = useState<
85+
Record<string, boolean>
86+
>({});
87+
7688
const setUrlBufferCache = useCallback(
7789
(url: string, buffer: ArrayBuffer) => {
7890
setUrlBufferMap((prev) => ({ ...prev, [url]: buffer }));
7991
},
8092
[setUrlBufferMap],
8193
);
8294

95+
const setIsAnimationCompleted = useCallback(
96+
(animationName: string, isAnimationCompleted: boolean) => {
97+
setAnimationCompleted((prev) => ({
98+
...prev,
99+
[animationName]: isAnimationCompleted,
100+
}));
101+
},
102+
[setAnimationCompleted],
103+
);
104+
83105
const { isWasmReady, loading, error } = useRiveWasmReady();
84106

85107
return (
86108
<RiveWasmContext.Provider
87-
value={{ isWasmReady, loading, error, urlBufferMap, setUrlBufferCache }}
109+
value={{
110+
isWasmReady,
111+
loading,
112+
error,
113+
urlBufferMap,
114+
setUrlBufferCache,
115+
animationCompleted,
116+
setIsAnimationCompleted,
117+
}}
88118
>
89119
{children}
90120
</RiveWasmContext.Provider>

ui/pages/bridge/quotes/multichain-bridge-quote-card.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ import {
2727
getIsStxEnabled,
2828
} from '../../../ducks/bridge/selectors';
2929
import { useI18nContext } from '../../../hooks/useI18nContext';
30-
import { formatCurrencyAmount, formatTokenAmount } from '../utils/quote';
30+
import {
31+
formatCurrencyAmount,
32+
formatNetworkFee,
33+
formatTokenAmount,
34+
} from '../utils/quote';
3135
import { getCurrentCurrency } from '../../../ducks/metamask/metamask';
3236
import {
3337
IconColor,
@@ -264,15 +268,13 @@ export const MultichainBridgeQuoteCard = ({
264268
style={{ textDecoration: 'line-through' }}
265269
>
266270
{activeQuote.includedTxFees?.valueInCurrency
267-
? formatCurrencyAmount(
271+
? formatNetworkFee(
268272
activeQuote.includedTxFees.valueInCurrency,
269273
currency,
270-
2,
271274
)
272-
: formatCurrencyAmount(
275+
: formatNetworkFee(
273276
activeQuote.totalNetworkFee?.valueInCurrency,
274277
currency,
275-
2,
276278
)}
277279
</Text>
278280
<Text
@@ -289,10 +291,9 @@ export const MultichainBridgeQuoteCard = ({
289291
color={TextColor.textAlternative}
290292
data-testid="network-fees"
291293
>
292-
{formatCurrencyAmount(
294+
{formatNetworkFee(
293295
activeQuote.totalNetworkFee?.valueInCurrency,
294296
currency,
295-
2,
296297
)}
297298
</Text>
298299
)}

ui/pages/bridge/utils/quote.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const formatTokenAmount = (
2525
};
2626

2727
export const formatCurrencyAmount = (
28-
stringifiedDecAmount: string | null,
28+
stringifiedDecAmount: string | null | undefined,
2929
currency: string,
3030
precision: number = DEFAULT_PRECISION,
3131
) => {
@@ -45,6 +45,62 @@ export const formatCurrencyAmount = (
4545
return formatCurrency(amount.toString(), currency, precision);
4646
};
4747

48+
/**
49+
* Formats network fees with dynamic precision to avoid showing $0.00 for non-zero fees.
50+
* If fees are less than $0.01, increases decimal places up to 4 until the first non-zero digit is shown.
51+
* If fees are non-zero but smaller than $0.0001, rounds up to $0.0001.
52+
*
53+
* @param stringifiedDecAmount - The fee amount as a string
54+
* @param currency - The currency code (e.g., 'USD')
55+
* @returns Formatted currency string with appropriate precision
56+
*/
57+
export function formatNetworkFee(
58+
stringifiedDecAmount: string | null | undefined,
59+
currency: string,
60+
): string | undefined {
61+
if (!stringifiedDecAmount) {
62+
return undefined;
63+
}
64+
65+
const amount = new BigNumber(stringifiedDecAmount);
66+
67+
// If amount is zero, return formatted zero
68+
if (amount.isZero()) {
69+
return formatCurrency(amount.toString(), currency, 2);
70+
}
71+
72+
// If amount is >= $0.01, use standard 2 decimal places
73+
if (amount.gte(0.01)) {
74+
return formatCurrency(amount.toString(), currency, 2);
75+
}
76+
77+
// For amounts < $0.01, find the precision that shows the first non-zero digit
78+
// Try precision from 2 to 4 (max allowed)
79+
for (let precision = 2; precision <= 4; precision++) {
80+
// Scale the amount by 10^precision to move the target digit to the ones place
81+
// Example: 0.0005 with precision 3 → 0.5 (moves 3rd decimal to ones place)
82+
const scaleFactor = new BigNumber(10).pow(precision);
83+
const scaledAmount = amount.times(scaleFactor);
84+
85+
// Round using ROUND_HALF_UP to match currency formatter's rounding behavior
86+
// If the rounded value is non-zero, this precision will show a non-zero digit
87+
const roundedValue = scaledAmount.round(0, BigNumber.ROUND_HALF_UP);
88+
89+
if (roundedValue.gt(0)) {
90+
return formatCurrency(amount.toString(), currency, precision);
91+
}
92+
}
93+
94+
// If after 4 decimal places it's still showing as zero but original amount > 0,
95+
// round up to $0.0001
96+
if (amount.gt(0)) {
97+
return formatCurrency('0.0001', currency, 4);
98+
}
99+
100+
// Fallback to 2 decimal places
101+
return formatCurrency(amount.toString(), currency, 2);
102+
}
103+
48104
export const formatProviderLabel = (args?: {
49105
bridgeId: QuoteResponse['quote']['bridgeId'];
50106
bridges: QuoteResponse['quote']['bridges'];

0 commit comments

Comments
 (0)