From bf18d61bad572371136f447cdd82a0429d15e40b Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 22 Feb 2024 12:08:35 -0500 Subject: [PATCH] Release/5.17.0 (#1127) * fix error in string translation (#1125) * adds invoker auth warning in signing flow * Added translations * update variant and copy for invoker auth warning * enabling mainnet access to Soroban (#1123) * splits logic for auth entry invocations to account for contract creation (#1126) * fixes display for scvBytes in preview helper * Feature/token allowlist copy update (#1132) * legal copy updates for allowlist warnings * Added translations * match style of destination acct not found error * update account creation warning copy * Feature/token allowlist copy update (#1133) * legal copy updates for allowlist warnings * Added translations * match style of destination acct not found error * update account creation warning copy * add space * change link styling to bold instead of underline (#1134) --------- Co-authored-by: Aristides Staffieri --- @shared/api/internal.ts | 3 +- @shared/api/types.ts | 5 + @shared/constants/stellar.ts | 3 + extension/src/background/helpers/account.ts | 5 - .../src/background/helpers/dataStorage.ts | 32 +++++++ .../messageListener/popupMessageListener.ts | 11 +++ .../components/WarningMessages/index.tsx | 56 ++++++++++-- .../components/WarningMessages/styles.scss | 9 +- .../manageAssets/AddToken/index.tsx | 30 +++++- .../manageAssets/AddToken/styles.scss | 4 + .../SendAmount/AssetSelect/index.tsx | 22 ++++- .../SendConfirm/SubmitResult/index.tsx | 4 +- .../components/sendPayment/SendTo/index.tsx | 4 +- .../Operations/KeyVal/index.tsx | 2 +- extension/src/popup/ducks/settings.ts | 30 ++++-- extension/src/popup/helpers/soroban.ts | 91 +++++++++++++++++++ .../src/popup/locales/en/translation.json | 14 +-- .../src/popup/locales/pt/translation.json | 14 +-- .../src/popup/views/AccountHistory/index.tsx | 25 ++--- .../src/popup/views/ReviewAuth/index.tsx | 79 ++++++++++++---- 20 files changed, 357 insertions(+), 86 deletions(-) diff --git a/@shared/api/internal.ts b/@shared/api/internal.ts index 17042fa293..031d71fcd7 100644 --- a/@shared/api/internal.ts +++ b/@shared/api/internal.ts @@ -11,6 +11,7 @@ import { MigratableAccount, MigratedAccount, Settings, + IndexerSettings, } from "./types"; import { MAINNET_NETWORK_DETAILS, @@ -922,7 +923,7 @@ export const editCustomNetwork = async ({ return response; }; -export const loadSettings = (): Promise => +export const loadSettings = (): Promise => sendMessageToBackground({ type: SERVICE_TYPES.LOAD_SETTINGS, }); diff --git a/@shared/api/types.ts b/@shared/api/types.ts index f1bb5a2ba6..74cae53c08 100644 --- a/@shared/api/types.ts +++ b/@shared/api/types.ts @@ -50,6 +50,7 @@ export interface Response { isSafetyValidationEnabled: boolean; isValidatingSafeAssetsEnabled: boolean; isExperimentalModeEnabled: boolean; + isSorobanPublicEnabled: boolean; networkDetails: NetworkDetails; sorobanRpcUrl: string; networksList: NetworkDetails[]; @@ -139,6 +140,10 @@ export interface Preferences { isExperimentalModeEnabled: boolean; } +export interface IndexerSettings { + isSorobanPublicEnabled: boolean; +} + export type Settings = { allowList: string[]; networkDetails: NetworkDetails; diff --git a/@shared/constants/stellar.ts b/@shared/constants/stellar.ts index 5e1437cac0..d046af3946 100644 --- a/@shared/constants/stellar.ts +++ b/@shared/constants/stellar.ts @@ -24,6 +24,8 @@ export enum FRIENDBOT_URLS { } export const SOROBAN_RPC_URLS: { [key in NETWORKS]?: string } = { + [NETWORKS.PUBLIC]: + "http://soroban-rpc-pubnet-prd.soroban-rpc-pubnet-prd.svc.cluster.local:8000", [NETWORKS.TESTNET]: "https://soroban-testnet.stellar.org/", [NETWORKS.FUTURENET]: "https://rpc-futurenet.stellar.org/", }; @@ -42,6 +44,7 @@ export const MAINNET_NETWORK_DETAILS: NetworkDetails = { networkName: NETWORK_NAMES.PUBNET, networkUrl: NETWORK_URLS.PUBLIC, networkPassphrase: Networks.PUBLIC, + sorobanRpcUrl: SOROBAN_RPC_URLS.PUBLIC, }; export const TESTNET_NETWORK_DETAILS: NetworkDetails = { diff --git a/extension/src/background/helpers/account.ts b/extension/src/background/helpers/account.ts index 9574cb52be..dea9ea3cac 100644 --- a/extension/src/background/helpers/account.ts +++ b/extension/src/background/helpers/account.ts @@ -126,11 +126,6 @@ export const getNetworksList = async () => { return networksList; }; -export const getIsSorobanSupported = async () => { - const networkDetails = await getNetworkDetails(); - return !!networkDetails.sorobanRpcUrl; -}; - export const subscribeAccount = async (publicKey: string) => { // if pub key already has a subscription setup, skip this const keyId = await localStore.getItem(KEY_ID); diff --git a/extension/src/background/helpers/dataStorage.ts b/extension/src/background/helpers/dataStorage.ts index ee1bc8d2eb..b8ee54caec 100644 --- a/extension/src/background/helpers/dataStorage.ts +++ b/extension/src/background/helpers/dataStorage.ts @@ -12,6 +12,7 @@ import { DEFAULT_NETWORKS, NetworkDetails, NETWORKS, + MAINNET_NETWORK_DETAILS, TESTNET_NETWORK_DETAILS, FUTURENET_NETWORK_DETAILS, SOROBAN_RPC_URLS, @@ -193,12 +194,43 @@ export const migrateToAccountSubscriptions = async () => { } }; +const migrateMainnetSorobanRpcUrlNetworkDetails = async () => { + const localStore = dataStorageAccess(browserLocalStorage); + const storageVersion = (await localStore.getItem(STORAGE_VERSION)) as string; + + if (!storageVersion || semver.lt(storageVersion, "4.0.0")) { + const networksList: NetworkDetails[] = + (await localStore.getItem(NETWORKS_LIST_ID)) || DEFAULT_NETWORKS; + + const migratedNetworkList = networksList.map((network) => { + if (network.network === NETWORKS.PUBLIC) { + return { + ...MAINNET_NETWORK_DETAILS, + sorobanRpcUrl: SOROBAN_RPC_URLS[NETWORKS.PUBLIC], + }; + } + + return network; + }); + + const currentNetwork = await localStore.getItem(NETWORK_ID); + + if (currentNetwork && currentNetwork.network === NETWORKS.PUBLIC) { + await localStore.setItem(NETWORK_ID, MAINNET_NETWORK_DETAILS); + } + + await localStore.setItem(NETWORKS_LIST_ID, migratedNetworkList); + await migrateDataStorageVersion("4.0.0"); + } +}; + export const versionedMigration = async () => { // sequentially call migrations in order to enforce smooth schema upgrades await migrateTokenIdList(); await migrateTestnetSorobanRpcUrlNetworkDetails(); await migrateToAccountSubscriptions(); + await migrateMainnetSorobanRpcUrlNetworkDetails(); }; // Updates storage version diff --git a/extension/src/background/messageListener/popupMessageListener.ts b/extension/src/background/messageListener/popupMessageListener.ts index 676b7cb00f..452a801826 100644 --- a/extension/src/background/messageListener/popupMessageListener.ts +++ b/extension/src/background/messageListener/popupMessageListener.ts @@ -13,6 +13,7 @@ import browser from "webextension-polyfill"; import { fromMnemonic, generateMnemonic } from "stellar-hd-wallet"; import { BigNumber } from "bignumber.js"; +import { INDEXER_URL } from "@shared/constants/mercury"; import { SERVICE_TYPES } from "@shared/constants/services"; import { APPLICATION_STATE } from "@shared/constants/applicationState"; import { WalletType } from "@shared/constants/hardwareWallet"; @@ -1213,6 +1214,15 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => { const isDataSharingAllowed = (await localStore.getItem(DATA_SHARING_ID)) ?? true; + let resJson = { useSorobanPublic: false }; + + try { + const res = await fetch(`${INDEXER_URL}/feature-flags`); + resJson = await res.json(); + } catch (e) { + console.error(e); + } + return { allowList: await getAllowList(), isDataSharingAllowed, @@ -1222,6 +1232,7 @@ export const popupMessageListener = (request: Request, sessionStore: Store) => { isExperimentalModeEnabled: await getIsExperimentalModeEnabled(), networkDetails: await getNetworkDetails(), networksList: await getNetworksList(), + isSorobanPublicEnabled: resJson.useSorobanPublic, }; }; diff --git a/extension/src/popup/components/WarningMessages/index.tsx b/extension/src/popup/components/WarningMessages/index.tsx index 9d88afbb88..dd3a8e7d03 100644 --- a/extension/src/popup/components/WarningMessages/index.tsx +++ b/extension/src/popup/components/WarningMessages/index.tsx @@ -1,7 +1,13 @@ import React, { useState, useRef, useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { createPortal } from "react-dom"; -import { Button, Icon, Loader, Notification } from "@stellar/design-system"; +import { + Button, + Icon, + Loader, + Link, + Notification, +} from "@stellar/design-system"; import { useTranslation } from "react-i18next"; import { POPUP_HEIGHT } from "constants/dimensions"; import { @@ -757,7 +763,7 @@ export const UnverifiedTokenWarning = ({ "Before you add this asset, please double-check its information and characteristics. This can help you identify fraudulent assets.", )} variant="warning" - > + />
{t("Asset Info")} @@ -768,13 +774,30 @@ export const UnverifiedTokenWarning = ({
- {t("Asset not in the asset list")} -
-
{t( - `This asset is not part of the asset list by stellar.expert (${networkDetails.network})`, + "The asset is not part of Stellar Expert's top 50 assets list", )}
+
+ {t("This asset is not part of")}{" "} + + Stellar Expert's top 50 assets list + +
+ + {t("Learn more")} + +
@@ -828,7 +851,7 @@ export const TransferWarning = ({ return (
@@ -849,6 +872,25 @@ export const TransferWarning = ({ ); }; +export const InvokerAuthWarning = () => { + const { t } = useTranslation(); + + return ( + +
+

+ {t( + "This authorization uses the source account's credentials, so you are implicitly authorizing this when you sign the transaction.", + )} +

+
+
+ ); +}; + export const UnverifiedTokenTransferWarning = ({ details, }: { diff --git a/extension/src/popup/components/WarningMessages/styles.scss b/extension/src/popup/components/WarningMessages/styles.scss index 2a28668bdd..09885dc09b 100644 --- a/extension/src/popup/components/WarningMessages/styles.scss +++ b/extension/src/popup/components/WarningMessages/styles.scss @@ -67,11 +67,12 @@ &__icon { color: #6432f1; - width: 0.875rem; + width: 24px; } &__default-icon { color: var(--color-purple-50); + width: 24px; } &__link-wrapper { @@ -342,7 +343,7 @@ margin-bottom: 1.5rem; column-gap: 0.5rem; &__header { - color: var(--color-purple-50); + color: var(--color-white); font-size: 0.875rem; margin-bottom: 0.25rem; } @@ -386,3 +387,7 @@ } } } + +.InvokerAuthWarning { + overflow-wrap: break-word; +} diff --git a/extension/src/popup/components/manageAssets/AddToken/index.tsx b/extension/src/popup/components/manageAssets/AddToken/index.tsx index 43bf34c3cd..274df0c3a6 100644 --- a/extension/src/popup/components/manageAssets/AddToken/index.tsx +++ b/extension/src/popup/components/manageAssets/AddToken/index.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useCallback, useRef, useState } from "react"; import { useSelector } from "react-redux"; import { Redirect } from "react-router-dom"; import { Formik, Form, Field, FieldProps } from "formik"; -import { Icon, Input, Loader } from "@stellar/design-system"; +import { Icon, Input, Link, Loader } from "@stellar/design-system"; import debounce from "lodash/debounce"; import { useTranslation } from "react-i18next"; import { INDEXER_URL } from "@shared/constants/mercury"; @@ -40,14 +40,38 @@ const VerificationBadge = ({ isVerified }: { isVerified: boolean }) => { <> - {t("Part of the asset list")} + {t("This asset is part of")}{" "} + + Stellar Expert's top 50 assets list + + .{" "} + + {t("Learn more")} + ) : ( <> unverified icon - {t("Not part of the asset list")} + {t("This asset is not part of")}{" "} + + Stellar Expert's top 50 assets list + + .{" "} + + {t("Learn more")} + )} diff --git a/extension/src/popup/components/manageAssets/AddToken/styles.scss b/extension/src/popup/components/manageAssets/AddToken/styles.scss index 4f06c0facb..5903bcacbd 100644 --- a/extension/src/popup/components/manageAssets/AddToken/styles.scss +++ b/extension/src/popup/components/manageAssets/AddToken/styles.scss @@ -8,6 +8,10 @@ color: var(--color-gray-70); font-size: 0.875rem; margin-left: 0.15625rem; + + a { + font-weight: var(--font-weight-semi-bold); + } } } diff --git a/extension/src/popup/components/sendPayment/SendAmount/AssetSelect/index.tsx b/extension/src/popup/components/sendPayment/SendAmount/AssetSelect/index.tsx index 4ddb6a76d0..4fa9261e82 100644 --- a/extension/src/popup/components/sendPayment/SendAmount/AssetSelect/index.tsx +++ b/extension/src/popup/components/sendPayment/SendAmount/AssetSelect/index.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from "react"; import { useSelector, useDispatch } from "react-redux"; -import { Icon, Notification } from "@stellar/design-system"; +import { Icon, Link, Notification } from "@stellar/design-system"; +import { useTranslation } from "react-i18next"; import { ROUTES } from "popup/constants/routes"; import { navigateTo } from "popup/helpers/navigate"; @@ -28,6 +29,7 @@ export function AssetSelect({ assetCode: string; issuerKey: string; }) { + const { t } = useTranslation(); const dispatch = useDispatch(); const { assetIcons } = useSelector(transactionSubmissionSelector); const networkDetails = useSelector(settingsNetworkDetailsSelector); @@ -68,9 +70,23 @@ export function AssetSelect({ {isUnverifiedToken ? (
+ > + {t("This asset is not part of")}{" "} + + Stellar Expert's top 50 assets list + + .{" "} + + {t("Learn more")} + +
) : null}
{ title={t("The destination account doesn’t exist")} >
- {t( - "The destination account doesn’t exist. Make sure it is a funded Stellar account and try again.", - )} + {t("Make sure it is a funded Stellar account and try again.")}, { title={t("The destination account doesn’t exist")} >
- {t( - "The destination account doesn’t exist. Send at least 1 XLM to create account.", - )}{" "} + {t("Send at least 1 XLM to create account.")}{" "} { } case xdr.ScValType.scvBytes(): { - return scVal.bytes().toString(); + return JSON.stringify(scVal.bytes().toJSON().data); } case xdr.ScValType.scvContractInstance(): { diff --git a/extension/src/popup/ducks/settings.ts b/extension/src/popup/ducks/settings.ts index f93cbe7d62..377c5c2f0b 100644 --- a/extension/src/popup/ducks/settings.ts +++ b/extension/src/popup/ducks/settings.ts @@ -20,13 +20,13 @@ import { MAINNET_NETWORK_DETAILS, } from "@shared/constants/stellar"; -import { Settings } from "@shared/api/types"; +import { Settings, IndexerSettings } from "@shared/api/types"; interface ErrorMessage { errorMessage: string; } -const initialState: Settings = { +const settingsInitialState: Settings = { allowList: [], isDataSharingAllowed: false, networkDetails: { @@ -44,6 +44,15 @@ const initialState: Settings = { error: "", }; +const indexerInitialState: IndexerSettings = { + isSorobanPublicEnabled: false, +}; + +const initialState = { + ...settingsInitialState, + ...indexerInitialState, +}; + export const loadSettings = createAsyncThunk("settings/loadSettings", () => loadSettingsService(), ); @@ -55,7 +64,7 @@ export const saveAllowList = createAsyncThunk< }, { rejectValue: ErrorMessage } >("settings/saveAllowList", async ({ allowList }, thunkApi) => { - let res = { allowList: initialState.allowList }; + let res = { allowList: settingsInitialState.allowList }; try { res = await saveAllowListService({ @@ -93,7 +102,7 @@ export const saveSettings = createAsyncThunk< }, thunkApi, ) => { - let res = { ...initialState }; + let res = { ...settingsInitialState }; try { res = await saveSettingsService({ @@ -212,7 +221,7 @@ const settingsSlice = createSlice({ ); builder.addCase( loadSettings.fulfilled, - (state, action: PayloadAction) => { + (state, action: PayloadAction) => { const { allowList, isDataSharingAllowed, @@ -222,6 +231,7 @@ const settingsSlice = createSlice({ isSafetyValidationEnabled, isValidatingSafeAssetsEnabled, isExperimentalModeEnabled, + isSorobanPublicEnabled, } = action?.payload || { ...initialState, }; @@ -236,6 +246,7 @@ const settingsSlice = createSlice({ isSafetyValidationEnabled, isValidatingSafeAssetsEnabled, isExperimentalModeEnabled, + isSorobanPublicEnabled, }; }, ); @@ -322,8 +333,9 @@ export const { reducer } = settingsSlice; export const { clearSettingsError } = settingsSlice.actions; -export const settingsSelector = (state: { settings: Settings }) => - state.settings; +export const settingsSelector = (state: { + settings: Settings & IndexerSettings; +}) => state.settings; export const settingsDataSharingSelector = createSelector( settingsSelector, @@ -338,7 +350,9 @@ export const settingsExperimentalModeSelector = createSelector( export const settingsSorobanSupportedSelector = createSelector( settingsSelector, (settings) => - settings.isExperimentalModeEnabled || settings.networkDetails.sorobanRpcUrl, + settings.networkDetails.network !== MAINNET_NETWORK_DETAILS.network + ? true + : settings.isSorobanPublicEnabled, ); export const settingsNetworkDetailsSelector = createSelector( diff --git a/extension/src/popup/helpers/soroban.ts b/extension/src/popup/helpers/soroban.ts index 051a76c1e0..b567f50954 100644 --- a/extension/src/popup/helpers/soroban.ts +++ b/extension/src/popup/helpers/soroban.ts @@ -323,3 +323,94 @@ export function pickTransfers(invocationTree: InvocationTree) { })); return [...transfers, ...subTransfers]; } + +export function getInvocationDetails( + invocation: xdr.SorobanAuthorizedInvocation, +) { + const invocations = [ + getInvocationArgs(invocation), + ...invocation.subInvocations().map(getInvocationArgs), + ]; + return invocations.filter(isInvocationArg); +} + +export interface FnArgsInvoke { + type: "invoke"; + fnName: string; + contractId: string; + args: xdr.ScVal[]; +} + +export interface FnArgsCreateWasm { + type: "wasm"; + salt: string; + hash: string; + address: string; +} + +export interface FnArgsCreateSac { + type: "sac"; + asset: string; +} + +type InvocationArgs = FnArgsInvoke | FnArgsCreateWasm | FnArgsCreateSac; + +const isInvocationArg = ( + invocation: InvocationArgs | undefined, +): invocation is InvocationArgs => !!invocation; + +function getInvocationArgs( + invocation: xdr.SorobanAuthorizedInvocation, +): InvocationArgs | undefined { + const fn = invocation.function(); + + switch (fn.switch().value) { + // sorobanAuthorizedFunctionTypeContractFn + case 0: { + const _invocation = fn.contractFn(); + const contractId = StrKey.encodeContract( + _invocation.contractAddress().contractId(), + ); + const fnName = _invocation.functionName().toString(); + const args = _invocation.args(); + return { fnName, contractId, args, type: "invoke" }; + } + + // sorobanAuthorizedFunctionTypeCreateContractHostFn + case 1: { + const _invocation = fn.createContractHostFn(); + const [exec, preimage] = [ + _invocation.executable(), + _invocation.contractIdPreimage(), + ]; + + switch (exec.switch().value) { + // contractExecutableWasm + case 0: { + const details = preimage.fromAddress(); + + return { + type: "wasm", + salt: details.salt().toString("hex"), + hash: exec.wasmHash().toString("hex"), + address: Address.fromScAddress(details.address()).toString(), + }; + } + + // contractExecutableStellarAsset + case 1: + return { + type: "sac", + asset: Asset.fromOperation(preimage.fromAsset()).toString(), + }; + + default: + throw new Error(`unknown creation type: ${JSON.stringify(exec)}`); + } + } + + default: { + return undefined; + } + } +} diff --git a/extension/src/popup/locales/en/translation.json b/extension/src/popup/locales/en/translation.json index d95f1773e0..035e2c2a42 100644 --- a/extension/src/popup/locales/en/translation.json +++ b/extension/src/popup/locales/en/translation.json @@ -62,7 +62,6 @@ "Asset home domain doesn’t exist, TOML file format is invalid, or asset doesn't match currency description": "Asset home domain doesn’t exist, TOML file format is invalid, or asset doesn't match currency description", "Asset Info": "Asset Info", "Asset not found": "Asset not found", - "Asset not in the asset list": "Asset not in the asset list", "Assets found in this domain": "Assets found in this domain", "At least one uppercase letter": "At least one uppercase letter", "At the end of this process, Freighter will only display accounts related to the new backup phrase": { @@ -108,6 +107,7 @@ "Connect device to computer": "Connect device to computer", "CONNECTION ERROR": "CONNECTION ERROR", "Continue": "Continue", + "Contract Address": "Contract Address", "Contract ID": "Contract ID", "Conversion rate": "Conversion rate", "Conversion rate changed": "Conversion rate changed", @@ -250,6 +250,7 @@ "Log In": "Log In", "Log Out": "Log Out", "Low Threshold": "Low Threshold", + "Make sure it is a funded Stellar account and try again": "Make sure it is a funded Stellar account and try again.", "Make sure you have your 12 word backup phrase": "Make sure you have your 12 word backup phrase", "Make sure you have your current 12 words backup phrase before continuing": "Make sure you have your current 12 words backup phrase before continuing.", "Malicious": "Malicious", @@ -303,7 +304,6 @@ "Not enough lumens": "Not enough lumens", "Not funded": "Not funded", "Not migrated": "Not migrated", - "Not part of the asset list": "Not part of the asset list", "Not recommended asset": "Not recommended asset", "Now, let’s create a new mnemonic phrase": "Now, let’s create a new mnemonic phrase", "Offer ID": "Offer ID", @@ -318,7 +318,6 @@ "Operation": "Operation", "Operations": "Operations", "Optional": "Optional", - "Part of the asset list": "Part of the asset list", "Passphrase": "Passphrase", "Paths": "Paths", "Please check if the network information is correct and try again": { @@ -374,6 +373,7 @@ "Send": "Send", "SEND": "SEND", "Send Amount": "Send Amount", + "Send at least 1 XLM to create account": "Send at least 1 XLM to create account.", "Send Max": "Send Max", "Send Payment": "Send Payment", "Send Type": "Send Type", @@ -417,13 +417,12 @@ "Terms of Use": "Terms of Use", "The application is requesting a specific account": "The application is requesting a specific account", "The asset creator can revoke your access to this asset at anytime": "The asset creator can revoke your access to this asset at anytime", + "The asset is not part of Stellar Expert's top 50 assets list": "The asset is not part of Stellar Expert's top 50 assets list", "The destination account can receive a different asset, the received amount is defined by the available conversion rates": "The destination account can receive a different asset, the received amount is defined by the available conversion rates", "The destination account does not accept the asset you’re sending": { " The destination account must opt to accept this asset before receiving it": "The destination account does not accept the asset you’re sending. The destination account must opt to accept this asset before receiving it." }, - "The destination account doesn’t exist": { - " Make sure it is a funded Stellar account and try again": "The destination account doesn’t exist. Make sure it is a funded Stellar account and try again." - }, + "The destination account doesn’t exist": "The destination account doesn’t exist.", "The destination account receives the same asset and amount sent": "The destination account receives the same asset and amount sent", "The final amount is approximate and may change": "The final amount is approximate and may change", "The transaction you’re trying to sign is on": "The transaction you’re trying to sign is on", @@ -437,9 +436,12 @@ "this alert by going to": "this alert by going to", "This asset has a balance": "This asset has a balance", "This asset has a balance of": "This asset has a balance of", + "This asset is not part of": "This asset is not part of", + "This asset is part of": "This asset is part of", "This asset was tagged as fraudulent by stellar": { "expert, a reliable community-maintained directory": "This asset was tagged as fraudulent by stellar.expert, a reliable community-maintained directory." }, + "This authorization uses the source account's credentials, so you are implicitly authorizing this when you sign the transaction": "This authorization uses the source account's credentials, so you are implicitly authorizing this when you sign the transaction.", "This invocation authorizes the following transfers, please review the invocation tree and confirm that you want to proceed": "This invocation authorizes the following transfers, please review the invocation tree and confirm that you want to proceed.", "This is a relatively new asset": "This is a relatively new asset.", "This new backup phrase will be used for your new accounts": "This new backup phrase will be used for your new accounts.", diff --git a/extension/src/popup/locales/pt/translation.json b/extension/src/popup/locales/pt/translation.json index d4c7cf24c1..1a42f373e3 100644 --- a/extension/src/popup/locales/pt/translation.json +++ b/extension/src/popup/locales/pt/translation.json @@ -62,7 +62,6 @@ "Asset home domain doesn’t exist, TOML file format is invalid, or asset doesn't match currency description": "Asset home domain doesn’t exist, TOML file format is invalid, or asset doesn't match currency description", "Asset Info": "Asset Info", "Asset not found": "Asset not found", - "Asset not in the asset list": "Asset not in the asset list", "Assets found in this domain": "Assets found in this domain", "At least one uppercase letter": "At least one uppercase letter", "At the end of this process, Freighter will only display accounts related to the new backup phrase": { @@ -108,6 +107,7 @@ "Connect device to computer": "Connect device to computer", "CONNECTION ERROR": "CONNECTION ERROR", "Continue": "Continue", + "Contract Address": "Contract Address", "Contract ID": "Contract ID", "Conversion rate": "Conversion rate", "Conversion rate changed": "Conversion rate changed", @@ -250,6 +250,7 @@ "Log In": "Log In", "Log Out": "Log Out", "Low Threshold": "Low Threshold", + "Make sure it is a funded Stellar account and try again": "Make sure it is a funded Stellar account and try again.", "Make sure you have your 12 word backup phrase": "Make sure you have your 12 word backup phrase", "Make sure you have your current 12 words backup phrase before continuing": "Make sure you have your current 12 words backup phrase before continuing.", "Malicious": "Malicious", @@ -303,7 +304,6 @@ "Not enough lumens": "Not enough lumens", "Not funded": "Not funded", "Not migrated": "Not migrated", - "Not part of the asset list": "Not part of the asset list", "Not recommended asset": "Not recommended asset", "Now, let’s create a new mnemonic phrase": "Now, let’s create a new mnemonic phrase", "Offer ID": "Offer ID", @@ -318,7 +318,6 @@ "Operation": "Operation", "Operations": "Operations", "Optional": "Optional", - "Part of the asset list": "Part of the asset list", "Passphrase": "Passphrase", "Paths": "Paths", "Please check if the network information is correct and try again": { @@ -374,6 +373,7 @@ "Send": "Send", "SEND": "SEND", "Send Amount": "Send Amount", + "Send at least 1 XLM to create account": "Send at least 1 XLM to create account.", "Send Max": "Send Max", "Send Payment": "Send Payment", "Send Type": "Send Type", @@ -417,13 +417,12 @@ "Terms of Use": "Terms of Use", "The application is requesting a specific account": "The application is requesting a specific account", "The asset creator can revoke your access to this asset at anytime": "The asset creator can revoke your access to this asset at anytime", + "The asset is not part of Stellar Expert's top 50 assets list": "The asset is not part of Stellar Expert's top 50 assets list", "The destination account can receive a different asset, the received amount is defined by the available conversion rates": "The destination account can receive a different asset, the received amount is defined by the available conversion rates", "The destination account does not accept the asset you’re sending": { " The destination account must opt to accept this asset before receiving it": "The destination account does not accept the asset you’re sending. The destination account must opt to accept this asset before receiving it." }, - "The destination account doesn’t exist": { - " Make sure it is a funded Stellar account and try again": "The destination account doesn’t exist. Make sure it is a funded Stellar account and try again." - }, + "The destination account doesn’t exist": "The destination account doesn’t exist.", "The destination account receives the same asset and amount sent": "The destination account receives the same asset and amount sent", "The final amount is approximate and may change": "The final amount is approximate and may change", "The transaction you’re trying to sign is on": "The transaction you’re trying to sign is on", @@ -437,9 +436,12 @@ "this alert by going to": "this alert by going to", "This asset has a balance": "This asset has a balance", "This asset has a balance of": "This asset has a balance of", + "This asset is not part of": "This asset is not part of", + "This asset is part of": "This asset is part of", "This asset was tagged as fraudulent by stellar": { "expert, a reliable community-maintained directory": "This asset was tagged as fraudulent by stellar.expert, a reliable community-maintained directory." }, + "This authorization uses the source account's credentials, so you are implicitly authorizing this when you sign the transaction": "This authorization uses the source account's credentials, so you are implicitly authorizing this when you sign the transaction.", "This invocation authorizes the following transfers, please review the invocation tree and confirm that you want to proceed": "This invocation authorizes the following transfers, please review the invocation tree and confirm that you want to proceed.", "This is a relatively new asset": "This is a relatively new asset.", "This new backup phrase will be used for your new accounts": "This new backup phrase will be used for your new accounts.", diff --git a/extension/src/popup/views/AccountHistory/index.tsx b/extension/src/popup/views/AccountHistory/index.tsx index 04524606c9..dc089c9df1 100644 --- a/extension/src/popup/views/AccountHistory/index.tsx +++ b/extension/src/popup/views/AccountHistory/index.tsx @@ -9,10 +9,7 @@ import { ActionStatus, HorizonOperation } from "@shared/api/types"; import { SorobanTokenInterface } from "@shared/constants/soroban/token"; import { publicKeySelector } from "popup/ducks/accountServices"; -import { - settingsNetworkDetailsSelector, - settingsSorobanSupportedSelector, -} from "popup/ducks/settings"; +import { settingsNetworkDetailsSelector } from "popup/ducks/settings"; import { transactionSubmissionSelector } from "popup/ducks/transactionSubmission"; import { getIsPayment, @@ -62,7 +59,6 @@ export const AccountHistory = () => { const { accountBalances, accountBalanceStatus } = useSelector( transactionSubmissionSelector, ); - const isSorobanSuported = useSelector(settingsSorobanSupportedSelector); const [selectedSegment, setSelectedSegment] = useState(SELECTOR_OPTIONS.ALL); const [historySegments, setHistorySegments] = useState( @@ -90,15 +86,10 @@ export const AccountHistory = () => { const isSupportedSorobanAccountItem = (operation: HorizonOperation) => getIsSupportedSorobanOp(operation, networkDetails); - const createSegments = ( - operations: HorizonOperation[], - showSorobanTxs = false, - ) => { - const _operations = showSorobanTxs - ? operations.filter( - (op) => op.type_i !== 24 || isSupportedSorobanAccountItem(op), - ) - : operations.filter((op) => op.type_i !== 24); + const createSegments = (operations: HorizonOperation[]) => { + const _operations = operations.filter( + (op) => op.type_i !== 24 || isSupportedSorobanAccountItem(op), + ); const segments = { [SELECTOR_OPTIONS.ALL]: [] as HistoryItemOperation[], [SELECTOR_OPTIONS.SENT]: [] as HistoryItemOperation[], @@ -145,9 +136,7 @@ export const AccountHistory = () => { publicKey, networkDetails, }); - setHistorySegments( - createSegments(operations, isSorobanSuported as boolean), - ); + setHistorySegments(createSegments(operations)); } catch (e) { console.error(e); } @@ -160,7 +149,7 @@ export const AccountHistory = () => { }; getData(); - }, [publicKey, networkDetails, isSorobanSuported, dispatch]); + }, [publicKey, networkDetails, dispatch]); return isDetailViewShowing ? ( diff --git a/extension/src/popup/views/ReviewAuth/index.tsx b/extension/src/popup/views/ReviewAuth/index.tsx index 7c70f58a26..aa34faca8f 100644 --- a/extension/src/popup/views/ReviewAuth/index.tsx +++ b/extension/src/popup/views/ReviewAuth/index.tsx @@ -3,7 +3,6 @@ import { useLocation } from "react-router-dom"; import { MemoType, Operation, - StrKey, Transaction, TransactionBuilder, xdr, @@ -23,12 +22,19 @@ import { import { useTranslation } from "react-i18next"; import { truncateString } from "helpers/stellar"; import { FlaggedKeys } from "types/transactions"; +import { + FnArgsCreateSac, + FnArgsCreateWasm, + FnArgsInvoke, + getInvocationDetails, +} from "popup/helpers/soroban"; import { KeyIdenticon } from "popup/components/identicons/KeyIdenticon"; import { useSetupSigningFlow } from "popup/helpers/useSetupSigningFlow"; import { Tabs } from "popup/components/Tabs"; import { SlideupModal } from "popup/components/SlideupModal"; import { AccountList } from "popup/components/account/AccountList"; import { + InvokerAuthWarning, TransferWarning, UnverifiedTokenTransferWarning, } from "popup/components/WarningMessages"; @@ -187,23 +193,6 @@ export const ReviewAuth = () => { ); }; -function getInvocationDetails(invocation: xdr.SorobanAuthorizedInvocation) { - return [ - getInvocationArgs(invocation), - ...invocation.subInvocations().map(getInvocationArgs), - ]; -} - -function getInvocationArgs(invocation: xdr.SorobanAuthorizedInvocation) { - const _invocation = invocation.function().contractFn(); - const contractId = StrKey.encodeContract( - _invocation.contractAddress().contractId(), - ); - const fnName = _invocation.functionName().toString(); - const args = _invocation.args(); - return { fnName, contractId, args }; -} - const AuthDetail = ({ authEntry, }: { @@ -211,11 +200,25 @@ const AuthDetail = ({ }) => { const { t } = useTranslation(); const details = getInvocationDetails(authEntry.rootInvocation()); + const invocations = details.filter( + (detail) => detail.type === "invoke", + ) as FnArgsInvoke[]; + const createWasms = details.filter( + (detail) => detail.type === "wasm", + ) as FnArgsCreateWasm[]; + const createSacs = details.filter( + (detail) => detail.type === "sac", + ) as FnArgsCreateSac[]; + return (
- - {details.map((detail) => ( + + {authEntry.credentials().switch() === + xdr.SorobanCredentialsType.sorobanCredentialsSourceAccount() && ( + + )} + {invocations.map((detail) => (
@@ -234,6 +237,42 @@ const AuthDetail = ({
))} + {createWasms.map((detail) => ( + +
+ +
Contract Creation
+
+
+ + + +
+
+ ))} + {createSacs.map((detail) => ( + +
+ +
Contract Creation
+
+
+ +
+
+ ))}
); };