diff --git a/extension/e2e-tests/sendPayment.test.ts b/extension/e2e-tests/sendPayment.test.ts index 77e686231b..cd2873a226 100644 --- a/extension/e2e-tests/sendPayment.test.ts +++ b/extension/e2e-tests/sendPayment.test.ts @@ -221,6 +221,31 @@ test("Send doesn't throw error when creating muxed account", async ({ }); }); +test("Send can review formatted inputs", async ({ page, extensionId }) => { + test.slow(); + await loginAndFund({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByText("Send")).toBeVisible(); + await page + .getByTestId("send-to-input") + .fill( + "MAUPPMNJUS76SG5NA6UXVCSO5HYVAJT422LBISV6LMCX37OIEPDJGAAAAAAAAAAAAF54C", + ); + await expect( + page.getByText("The destination account doesn’t exist."), + ).toBeVisible(); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Send"); + await page.getByTestId(`SendRow-native`).click({ force: true }); + await page.getByTestId("send-amount-amount-input").fill("1000"); + await page.getByText("Review Send").click({ force: true }); + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); +}); + test("Send XLM payments to recent federated addresses", async ({ page, extensionId, diff --git a/extension/src/popup/components/manageAssets/ManageAssetRowButton/index.tsx b/extension/src/popup/components/manageAssets/ManageAssetRowButton/index.tsx index a445fe03ac..3dc455b7de 100644 --- a/extension/src/popup/components/manageAssets/ManageAssetRowButton/index.tsx +++ b/extension/src/popup/components/manageAssets/ManageAssetRowButton/index.tsx @@ -14,6 +14,7 @@ interface ManageAssetRowButtonProps { code: string; issuer: string; isTrustlineActive: boolean; + isSac: boolean; isLoading: boolean; onClick: () => void; } @@ -22,6 +23,7 @@ export const ManageAssetRowButton = ({ code, issuer, isTrustlineActive, + isSac, isLoading, onClick, }: ManageAssetRowButtonProps) => { @@ -69,28 +71,30 @@ export const ManageAssetRowButton = ({ -
- -
+ {!isSac && ( +
+ +
+ )} {createPortal(
- + Failed! )} diff --git a/extension/src/popup/components/manageAssets/ManageAssetRows/ToggleTokenInternal/index.tsx b/extension/src/popup/components/manageAssets/ManageAssetRows/ToggleTokenInternal/index.tsx index 665e37e458..2314446b5a 100644 --- a/extension/src/popup/components/manageAssets/ManageAssetRows/ToggleTokenInternal/index.tsx +++ b/extension/src/popup/components/manageAssets/ManageAssetRows/ToggleTokenInternal/index.tsx @@ -13,6 +13,8 @@ import { navigateTo } from "popup/helpers/navigate"; import { ROUTES } from "popup/constants/routes"; import "./styles.scss"; +import { isSacContract } from "popup/helpers/soroban"; +import { truncateString } from "helpers/stellar"; interface ToggleTokenInternalProps { asset: { @@ -57,6 +59,10 @@ export const ToggleTokenInternal = ({ } navigateTo(ROUTES.account, nav); }; + const isSac = + !!asset.name && + !!asset.contract && + isSacContract(asset.name, asset.contract, networkDetails.networkPassphrase); return (
@@ -88,7 +94,7 @@ export const ToggleTokenInternal = ({ )} - {asset.name || asset.code} + {isSac ? asset.code : asset.name || truncateString(asset.contract!)}
( @@ -112,6 +116,7 @@ export const ManageAssetRows = ({ code={code} issuer={issuer} isTrustlineActive={!!isTrustlineActive} + isSac={isSac} isLoading={false} onClick={async () => { setSelectedAsset({ @@ -178,11 +183,13 @@ const AssetRows = ({ shouldSplitAssetsByVerificationStatus, unverifiedAssetRows, verifiedAssetRows, + networkDetails, }: { accountBalances: AccountBalances; shouldSplitAssetsByVerificationStatus?: boolean; unverifiedAssetRows: ManageAssetCurrency[]; verifiedAssetRows: ManageAssetCurrency[]; + networkDetails: NetworkDetails; renderAssetRow: ({ code, domain, @@ -193,6 +200,7 @@ const AssetRows = ({ isContract, isTrustlineActive, isSuspicious, + isSac, }: { code: string; domain: string; @@ -203,6 +211,7 @@ const AssetRows = ({ isContract: boolean; isTrustlineActive: boolean; isSuspicious?: boolean; + isSac: boolean; }) => React.ReactNode; }) => { const { t } = useTranslation(); @@ -242,12 +251,22 @@ const AssetRows = ({ if (!accountBalances.balances) { return null; } + const nativeContract = getNativeContractDetails(networkDetails); const isContract = isContractId(contract); const canonicalAsset = getCanonicalFromAsset(code, issuer); const isTrustlineActive = findAssetBalance( accountBalances.balances, { code, issuer }, ); + const isSac = + contract === nativeContract.contract || + (!!name && + !!contract && + isSacContract( + name, + contract, + networkDetails.networkPassphrase, + )); return (
@@ -301,12 +323,23 @@ const AssetRows = ({ if (!accountBalances.balances) { return null; } + const nativeContract = getNativeContractDetails(networkDetails); const isContract = isContractId(contract); const canonicalAsset = getCanonicalFromAsset(code, issuer); const isTrustlineActive = findAssetBalance( accountBalances.balances, { code, issuer }, ); + const isSac = + contract === nativeContract.contract || + (!!name && + !!contract && + isSacContract( + name, + contract, + networkDetails.networkPassphrase, + )); + return (
@@ -347,12 +383,18 @@ const AssetRows = ({ if (!accountBalances.balances) { return null; } + const nativeContract = getNativeContractDetails(networkDetails); const isContract = isContractId(contract); const canonicalAsset = getCanonicalFromAsset(code, issuer); const isTrustlineActive = findAssetBalance(accountBalances.balances, { code, issuer, }); + const isSac = + contract === nativeContract.contract || + (!!name && + !!contract && + isSacContract(name, contract, networkDetails.networkPassphrase)); return (
diff --git a/extension/src/popup/components/manageAssets/SearchAsset/hooks/useAssetLookup.ts b/extension/src/popup/components/manageAssets/SearchAsset/hooks/useAssetLookup.ts index 5bbf273173..85dd2382a8 100644 --- a/extension/src/popup/components/manageAssets/SearchAsset/hooks/useAssetLookup.ts +++ b/extension/src/popup/components/manageAssets/SearchAsset/hooks/useAssetLookup.ts @@ -150,8 +150,10 @@ const useAssetLookup = () => { assetRows = [ { code: nativeContractDetails.code, - issuer: contractId, + issuer: nativeContractDetails.issuer, + contract: contractId, domain: nativeContractDetails.domain, + name: `${nativeContractDetails.code}:${nativeContractDetails.issuer}`, }, ]; @@ -325,12 +327,6 @@ const useAssetLookup = () => { dispatch({ type: "FETCH_DATA_ERROR", payload: DEFAULT_PAYLOAD }); return; } - - // Only show records that have a domain and domains that don't have just whitespace - // We omit these results as a safety precaution and to encourage asset issuers to add a domain to their asset - assetRows = assetRows.filter( - (record) => record.domain && /\S/.test(record.domain), - ); } const assetsListsData = await getCombinedAssetListData({ diff --git a/extension/src/popup/components/sendPayment/SendAmount/hooks/useSimulateTxData.tsx b/extension/src/popup/components/sendPayment/SendAmount/hooks/useSimulateTxData.tsx index e3c4c98fcc..7892bd2bf7 100644 --- a/extension/src/popup/components/sendPayment/SendAmount/hooks/useSimulateTxData.tsx +++ b/extension/src/popup/components/sendPayment/SendAmount/hooks/useSimulateTxData.tsx @@ -42,6 +42,7 @@ import { import { findAddressBalance } from "popup/helpers/balance"; import { AppDispatch } from "popup/App"; import { useScanTx } from "popup/helpers/blockaid"; +import { cleanAmount } from "popup/helpers/formatters"; interface SimClassic { type: "classic"; @@ -375,7 +376,7 @@ function useSimulateTxData({ ? Asset.native().contractId(networkDetails.networkPassphrase) : assetAddress; const parsedAmount = parseTokenAmount( - amount, + cleanAmount(amount), Number("decimals" in assetBalance ? assetBalance.decimals : 7), ); @@ -426,7 +427,7 @@ function useSimulateTxData({ { sourceAsset, destAsset, - amount, + amount: cleanAmount(amount), destinationAmount, destination, allowedSlippage, diff --git a/extension/src/popup/components/swap/SwapAmount/index.tsx b/extension/src/popup/components/swap/SwapAmount/index.tsx index 6b33b628a1..f43a830c8a 100644 --- a/extension/src/popup/components/swap/SwapAmount/index.tsx +++ b/extension/src/popup/components/swap/SwapAmount/index.tsx @@ -147,8 +147,12 @@ export const SwapAmount = ({ const handleContinue = async (values: { amount: string }) => { const amount = inputType === "crypto" ? values.amount : priceValue!; - dispatch(saveAmount(cleanAmount(amount))); - await fetchSimulationData({ amount, destinationRate: dstAssetPrice }); + const cleanedAmount = cleanAmount(amount); + dispatch(saveAmount(cleanedAmount)); + await fetchSimulationData({ + amount: cleanedAmount, + destinationRate: dstAssetPrice, + }); setIsReviewingTx(true); };