Skip to content

Commit

Permalink
Merge branch 'main' into snap-review-screen
Browse files Browse the repository at this point in the history
  • Loading branch information
NidhiKJha authored Feb 4, 2025
2 parents 7abb5f8 + 11addf5 commit d5c2667
Show file tree
Hide file tree
Showing 35 changed files with 1,068 additions and 178 deletions.
10 changes: 9 additions & 1 deletion app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion app/scripts/controllers/permissions/specifications.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('PermissionController specifications', () => {
describe('caveat specifications', () => {
it('getCaveatSpecifications returns the expected specifications object', () => {
const caveatSpecifications = getCaveatSpecifications({});
expect(Object.keys(caveatSpecifications)).toHaveLength(12);
expect(Object.keys(caveatSpecifications)).toHaveLength(13);
expect(caveatSpecifications[Caip25CaveatType].type).toStrictEqual(
Caip25CaveatType,
);
Expand Down Expand Up @@ -54,6 +54,9 @@ describe('PermissionController specifications', () => {
expect(caveatSpecifications.lookupMatchers.type).toStrictEqual(
SnapCaveatType.LookupMatchers,
);
expect(caveatSpecifications.protocolSnapScopes.type).toStrictEqual(
SnapCaveatType.ProtocolSnapScopes,
);
});
});

Expand Down
8 changes: 4 additions & 4 deletions builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ buildTypes:
- ALLOW_LOCAL_SNAPS: false
- REQUIRE_SNAPS_ALLOWLIST: true
- REJECT_INVALID_SNAPS_PLATFORM_VERSION: true
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.13.0/index.html
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.14.0/index.html
- ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management
# Main build uses the default browser manifest
manifestOverrides: false
Expand All @@ -48,7 +48,7 @@ buildTypes:
- ALLOW_LOCAL_SNAPS: false
- REQUIRE_SNAPS_ALLOWLIST: true
- REJECT_INVALID_SNAPS_PLATFORM_VERSION: true
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.13.0/index.html
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.14.0/index.html
- ACCOUNT_SNAPS_DIRECTORY_URL: https://snaps.metamask.io/account-management
# Modifies how the version is displayed.
# eg. instead of 10.25.0 -> 10.25.0-beta.2
Expand All @@ -72,7 +72,7 @@ buildTypes:
- ALLOW_LOCAL_SNAPS: true
- REQUIRE_SNAPS_ALLOWLIST: false
- REJECT_INVALID_SNAPS_PLATFORM_VERSION: false
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.13.0/index.html
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.14.0/index.html
- SUPPORT_LINK: https://support.metamask.io/
- SUPPORT_REQUEST_LINK: https://support.metamask.io/
- INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID
Expand All @@ -96,7 +96,7 @@ buildTypes:
- ALLOW_LOCAL_SNAPS: false
- REQUIRE_SNAPS_ALLOWLIST: true
- REJECT_INVALID_SNAPS_PLATFORM_VERSION: true
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.13.0/index.html
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/iframe/6.14.0/index.html
- MMI_CONFIGURATION_SERVICE_URL: https://configuration.metamask-institutional.io/v2/configuration/default
- SUPPORT_LINK: https://support.metamask-institutional.io
- SUPPORT_REQUEST_LINK: https://support.metamask-institutional.io
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@
"@trezor/schema-utils@npm:1.0.2": "patch:@trezor/schema-utils@npm%3A1.0.2#~/.yarn/patches/@trezor-schema-utils-npm-1.0.2-7dd48689b2.patch",
"lavamoat-core@npm:^15.1.1": "patch:lavamoat-core@npm%3A15.1.1#~/.yarn/patches/lavamoat-core-npm-15.1.1-51fbe39988.patch",
"lavamoat-core@npm:^16.2.2": "patch:lavamoat-core@npm%3A16.2.2#~/.yarn/patches/lavamoat-core-npm-16.2.2-e361ff1f8a.patch",
"@metamask/snaps-sdk": "^6.16.0",
"@metamask/snaps-sdk": "^6.17.0",
"@swc/[email protected]": "^0.1.6",
"@babel/core": "patch:@babel/core@npm%3A7.25.9#~/.yarn/patches/@babel-core-npm-7.25.9-4ae3bff7f3.patch",
"@babel/runtime": "patch:@babel/runtime@npm%3A7.25.9#~/.yarn/patches/@babel-runtime-npm-7.25.9-fe8c62510a.patch",
Expand Down Expand Up @@ -348,11 +348,11 @@
"@metamask/selected-network-controller": "^19.0.0",
"@metamask/signature-controller": "^23.1.0",
"@metamask/smart-transactions-controller": "^16.0.1",
"@metamask/snaps-controllers": "^9.18.0",
"@metamask/snaps-execution-environments": "^6.13.0",
"@metamask/snaps-rpc-methods": "^11.10.0",
"@metamask/snaps-sdk": "^6.16.0",
"@metamask/snaps-utils": "^8.9.1",
"@metamask/snaps-controllers": "^9.19.0",
"@metamask/snaps-execution-environments": "^6.14.0",
"@metamask/snaps-rpc-methods": "^11.11.0",
"@metamask/snaps-sdk": "^6.17.0",
"@metamask/snaps-utils": "^8.10.0",
"@metamask/solana-wallet-snap": "^1.2.0",
"@metamask/transaction-controller": "^43.0.0",
"@metamask/user-operation-controller": "^22.0.0",
Expand Down
1 change: 1 addition & 0 deletions shared/constants/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const PermissionWeight = Object.freeze({
wallet_snap: 4,
endowment_networkAccess: 3,
endowment_assets: 3,
endowment_protocol: 3,
endowment_webassembly: 4,
endowment_transactionInsight: 4,
endowment_cronjob: 4,
Expand Down
1 change: 1 addition & 0 deletions shared/constants/snaps/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const EndowmentPermissions = Object.freeze({
'endowment:signature-insight': 'endowment:signature-insight',
'endowment:name-lookup': 'endowment:name-lookup',
'endowment:assets': 'endowment:assets',
'endowment:protocol': 'endowment:protocol',
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
'endowment:keyring': 'endowment:keyring',
///: END:ONLY_INCLUDE_IF
Expand Down
6 changes: 5 additions & 1 deletion test/e2e/flask/solana/check-balance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ describe('Check balance', function (this: Suite) {
this.timeout(300000);
it('Just created Solana account shows 0 SOL when native token is enabled', async function () {
await withSolanaAccountSnap(
{ title: this.test?.fullTitle(), showNativeTokenAsMainBalance: true },
{
title: this.test?.fullTitle(),
solanaSupportEnabled: true,
showNativeTokenAsMainBalance: true,
},
async (driver) => {
await driver.refresh();
const homePage = new NonEvmHomepage(driver);
Expand Down
64 changes: 52 additions & 12 deletions ui/components/app/assets/nfts/nft-grid/nft-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,56 @@ import { NftItem } from '../../../../multichain/nft-item';
import { NFT } from '../../../../multichain/asset-picker-amount/asset-picker-modal/types';
import {
getCurrentNetwork,
getIpfsGateway,
getNftIsStillFetchingIndication,
} from '../../../../../selectors';
import useGetAssetImageUrl from '../../../../../hooks/useGetAssetImageUrl';

const NFTGridItem = (props: {
nft: NFT;
onClick: () => void;
privacyMode?: boolean;
currentChain: {
chainId: Hex;
nickname: string;
rpcPrefs?: {
imageUrl: string;
};
};
}) => {
const { nft, onClick, privacyMode, currentChain } = props;

const { image, imageOriginal } = nft;

const ipfsGateway = useSelector(getIpfsGateway);
const nftImageURL = useGetAssetImageUrl(
imageOriginal ?? image ?? undefined,
ipfsGateway,
);

const isImageHosted =
image?.startsWith('https:') || image?.startsWith('http:');
const nftItemSrc = isImageHosted ? image : nftImageURL;

const nftImageAlt = getNftImageAlt(nft);

const nftSrcUrl = imageOriginal ?? image;
const isIpfsURL = nftSrcUrl?.startsWith('ipfs:');

return (
<NftItem
nft={nft}
alt={nftImageAlt}
src={nftItemSrc}
networkName={currentChain.nickname}
networkSrc={currentChain.rpcPrefs?.imageUrl}
onClick={onClick}
isIpfsURL={isIpfsURL}
privacyMode={privacyMode}
clickable
/>
);
};

export default function NftGrid({
nfts,
Expand All @@ -34,27 +82,19 @@ export default function NftGrid({
<Box style={{ margin: 16 }}>
<Box display={Display.Grid} gap={4} className="nft-items__wrapper">
{nfts.map((nft: NFT) => {
const { image, imageOriginal, tokenURI } = nft;
const nftImageAlt = getNftImageAlt(nft);
const isIpfsURL = (imageOriginal ?? image ?? tokenURI)?.startsWith(
'ipfs:',
);
const { tokenURI } = nft;

return (
<Box
data-testid="nft-wrapper"
key={tokenURI}
className="nft-items__image-wrapper"
>
<NftItem
<NFTGridItem
currentChain={currentChain}
nft={nft}
alt={nftImageAlt}
src={image ?? ''}
networkName={currentChain.nickname}
networkSrc={currentChain.rpcPrefs?.imageUrl}
onClick={() => handleNftClick(nft)}
isIpfsURL={isIpfsURL}
privacyMode={privacyMode}
clickable
/>
</Box>
);
Expand Down
110 changes: 110 additions & 0 deletions ui/components/app/multichain-transaction-details-modal/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { DateTime } from 'luxon';
import {
MULTICHAIN_NETWORK_BLOCK_EXPLORER_URL_MAP,
MultichainNetworks,
} from '../../../../shared/constants/multichain/networks';
import {
formatDateWithYearContext,
shortenAddress,
} from '../../../helpers/utils/util';

/**
* Creates a transaction URL for block explorer based on network type
* Different networks have different URL patterns:
* Bitcoin Mainnet: https://blockstream.info/tx/{txId}
* Bitcoin Testnet: https://blockstream.info/testnet/tx/{txId}
* Solana Mainnet: https://explorer.solana.com/tx/{txId}
* Solana Devnet: https://explorer.solana.com/tx/{txId}?cluster=devnet
*
* @param txId - Transaction ID
* @param chainId - Network chain ID
* @returns Full URL to transaction in block explorer, or empty string if no explorer URL
*/
export const getTransactionUrl = (txId: string, chainId: string): string => {
const explorerBaseUrl =
MULTICHAIN_NETWORK_BLOCK_EXPLORER_URL_MAP[chainId as MultichainNetworks];
if (!explorerBaseUrl) {
return '';
}

// Change address URL to transaction URL for Bitcoin
if (chainId.startsWith('bip122:')) {
return `${explorerBaseUrl.replace('/address', '/tx')}/${txId}`;
}

const baseUrl = explorerBaseUrl.split('?')[0];
if (chainId === MultichainNetworks.SOLANA) {
return `${baseUrl}tx/${txId}`;
}
if (chainId === MultichainNetworks.SOLANA_DEVNET) {
return `${baseUrl}tx/${txId}?cluster=devnet`;
}

return '';
};

/**
* Creates an address URL for block explorer based on network type
* Different networks have different URL patterns:
* Bitcoin Mainnet: https://blockstream.info/address/{address}
* Bitcoin Testnet: https://blockstream.info/testnet/address/{address}
* Solana Mainnet: https://explorer.solana.com/address/{address}
* Solana Devnet: https://explorer.solana.com/address/{address}?cluster=devnet
*
* @param address - Wallet address
* @param chainId - Network chain ID
* @returns Full URL to address in block explorer, or empty string if no explorer URL
*/
export const getAddressUrl = (address: string, chainId: string): string => {
const explorerBaseUrl =
MULTICHAIN_NETWORK_BLOCK_EXPLORER_URL_MAP[chainId as MultichainNetworks];

if (!explorerBaseUrl) {
return '';
}

const baseUrl = explorerBaseUrl.split('?')[0];
if (chainId === MultichainNetworks.SOLANA) {
return `${baseUrl}address/${address}`;
}
if (chainId === MultichainNetworks.SOLANA_DEVNET) {
return `${baseUrl}address/${address}?cluster=devnet`;
}

// Bitcoin networks already have the correct address URL format
return `${explorerBaseUrl}/${address}`;
};

/**
* Formats a timestamp into a localized date and time string
* Example outputs: "Mar 15, 2024, 14:30" or "Dec 25, 2023, 09:45"
*
* @param timestamp - Unix timestamp in milliseconds
* @returns Formatted date and time string, or empty string if timestamp is null
*/
export const formatTimestamp = (timestamp: number | null) => {
if (!timestamp) {
return '';
}

// It's typical for Solana timestamps to use seconds, while JS Dates and most EVM chains use milliseconds.
// Hence we needed to use the conversion `timestamp < 1e12 ? timestamp * 1000 : timestamp` for it to work.
const timestampMs = timestamp < 1e12 ? timestamp * 1000 : timestamp;

const dateTime = DateTime.fromMillis(timestampMs);
const date = formatDateWithYearContext(timestampMs, 'MMM d, y', 'MMM d');
const time = dateTime.toFormat('HH:mm');

return `${date}, ${time}`;
};

/**
* Formats a shorten version of a transaction ID.
*
* @param txId - Transaction ID.
* @returns Formatted transaction ID.
*/
export function shortenTransactionId(txId: string) {
// For transactions we use a similar output for now, but shortenTransactionId will be added later.
return shortenAddress(txId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { MultichainTransactionDetailsModal } from './multichain-transaction-details-modal';
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { MultichainTransactionDetailsModal } from './multichain-transaction-details-modal';

export default {
title: 'Components/App/MultichainTransactionDetailsModal',
component: MultichainTransactionDetailsModal,
};

const mockTransaction = {
type: 'Send BTC',
status: 'Confirmed',
timestamp: new Date('Sep 30 2023 12:56').getTime(),
id: 'b93ea2cb4eed0f9e13284ed8860bcfc45de2488bb6a8b0b2a843c4b2fbce40f3',
from: [{
address: "bc1p7atgm33ak04ntsq9366mvym42ecrk4y34ssysc99340a39eq9arq0pu9uj",
asset: {
amount: '1.2',
unit: 'BTC',
}
}],
to: [{
address: "bc1p3t7744qewy262ym5afgeuqlwswtpfe22y7c4lwv0a7972p2k73msee7rr3",
asset: {
amount: '1.2',
unit: 'BTC',
}
}],
fees: [{
type: 'base',
asset: {
amount: '1.0001',
unit: 'BTC',
}
}]
};

export const Default = {
args: {
transaction: mockTransaction,
onClose: () => console.log('Modal closed'),
addressLink: 'https://explorer.bitcoin.com/btc/tx/3302...90c1',
multichainNetwork: {
nickname: 'Bitcoin',
isEvmNetwork: false,
chainId: 'bip122:000000000019d6689c085ae165831e93',
network: {
chainId: 'bip122:000000000019d6689c085ae165831e93',
ticker: 'BTC',
},
},
},
};
Loading

0 comments on commit d5c2667

Please sign in to comment.