Skip to content
This repository was archived by the owner on Jul 31, 2026. It is now read-only.
Open
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
4 changes: 4 additions & 0 deletions packages/snap/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Display known non-URL origins in confirmations without throwing on invalid origin values ([#340](https://github.com/MetaMask/snap-tron-wallet/pull/340))

## [1.28.0]

### Added
Expand Down
24 changes: 10 additions & 14 deletions packages/snap/src/utils/formatOrigin.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { formatOrigin } from './formatOrigin';

describe('formatOrigin', () => {
it('formats "metamask" as "MetaMask"', () => {
it('maps "metamask" to "MetaMask" (case-insensitive)', () => {
expect(formatOrigin('metamask')).toBe('MetaMask');
});

it('formats "METAMASK" as "MetaMask"', () => {
expect(formatOrigin('METAMASK')).toBe('MetaMask');
});

it('formats "MetaMask" as "MetaMask"', () => {
expect(formatOrigin('MetaMask')).toBe('MetaMask');
expect(formatOrigin('MeTaMaSk')).toBe('MetaMask');
});

it('formats "MeTaMaSk" (mixed case) as "MetaMask"', () => {
expect(formatOrigin('MeTaMaSk')).toBe('MetaMask');
it('maps "wallet-connect" to "WalletConnect" (case-insensitive)', () => {
expect(formatOrigin('wallet-connect')).toBe('WalletConnect');
expect(formatOrigin('WALLET-CONNECT')).toBe('WalletConnect');
expect(formatOrigin('Wallet-Connect')).toBe('WalletConnect');
});

it('extracts hostname from valid URLs', () => {
Expand All @@ -29,11 +26,10 @@ describe('formatOrigin', () => {
);
});

it('returns original value for invalid URLs', () => {
// Note: These should be rejected by validation, but formatOrigin is lenient
expect(formatOrigin('example.com')).toBe('example.com');
expect(formatOrigin('not-a-url')).toBe('not-a-url');
expect(formatOrigin('just some text')).toBe('just some text');
it('returns an empty string for non-URL / invalid origins', () => {
expect(formatOrigin('example.com')).toBe('');
expect(formatOrigin('not-a-url')).toBe('');
expect(formatOrigin('just some text')).toBe('');
});

it('returns "Unknown" for undefined', () => {
Expand Down
40 changes: 32 additions & 8 deletions packages/snap/src/utils/formatOrigin.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
/**
* Maps known non-URL origins to their display labels (case-insensitive lookup).
* In-app requests use 'MetaMask' (capitalized), so the lookup is case-insensitive.
*/
const KNOWN_ORIGIN_LABELS: Record<string, string> = {
metamask: 'MetaMask',
'wallet-connect': 'WalletConnect',
};

/**
* Formats an origin for display purposes.
*
* Returns 'Unknown' for undefined/empty origins. Returns a friendly label for
* known origins ('metamask' to 'MetaMask', 'wallet-connect' to 'WalletConnect'),
* matched case-insensitively. Returns the hostname for http(s) URLs. Returns an
* empty string for everything else (channelIds, non-http URLs, invalid strings)
* so display guards `{origin ? (...) : null}` hide the row.
*
* @param origin - The origin string to format (e.g., 'metamask', 'https://example.com').
* @returns The formatted origin string (e.g., 'MetaMask', 'example.com').
* @returns The formatted origin string (e.g., 'MetaMask', 'example.com', '').
*/
export function formatOrigin(origin: string | undefined): string {
if (!origin) {
return 'Unknown';
}

// Special case: format 'metamask' as 'MetaMask' (case-insensitive)
if (origin.toLowerCase() === 'metamask') {
return 'MetaMask';
const knownLabel = KNOWN_ORIGIN_LABELS[origin.toLowerCase()];
if (knownLabel) {
return knownLabel;
}

// Try to extract hostname from URL
try {
return new URL(origin).hostname;
const url = new URL(origin);
return isHttpOrHttpsUrl(url) ? url.hostname : '';
} catch {
// If not a valid URL, return the original value
// This shouldn't happen if validation is working correctly
return origin;
return '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unknown origin shows blank label

Medium Severity

Sign-transaction confirmation sets missing origins to the literal 'Unknown', then runs formatOrigin on that value. After this change, formatOrigin returns an empty string for non-URL strings, so the origin row still renders (the prop is truthy) but the value is blank instead of Unknown.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 548af0c. Configure here.

}
}

/**
* Checks whether a parsed URL uses an HTTP(S) protocol.
*
* @param url - The parsed URL to check.
* @returns Whether the URL uses HTTP or HTTPS.
*/
function isHttpOrHttpsUrl(url: URL): boolean {
return url.protocol === 'http:' || url.protocol === 'https:';
}
Loading