diff --git a/.changeset/fresh-poets-count.md b/.changeset/fresh-poets-count.md
new file mode 100644
index 000000000..2abfe6b2b
--- /dev/null
+++ b/.changeset/fresh-poets-count.md
@@ -0,0 +1,6 @@
+---
+"@fuel-wallet/types": patch
+"fuels-wallet": patch
+---
+
+feat: improve nft support + dont allow sending funds to assetId address
diff --git a/packages/app/package.json b/packages/app/package.json
index 318602ca1..1635ec088 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -26,6 +26,7 @@
"@fuel-ui/test-utils": "0.17.0",
"@fuel-wallet/connections": "workspace:*",
"@fuels/local-storage": "0.20.0",
+ "@fuels/playwright-utils": "workspace:*",
"@fuels/react-xstore": "0.20.0",
"@hookform/resolvers": "3.9.0",
"@react-aria/utils": "3.21.0",
diff --git a/packages/app/playwright.config.ts b/packages/app/playwright.config.ts
index 42d69f9ac..1d5a6a594 100644
--- a/packages/app/playwright.config.ts
+++ b/packages/app/playwright.config.ts
@@ -8,7 +8,7 @@ const IS_CI = process.env.CI;
export const playwrightConfig: PlaywrightTestConfig = {
workers: 1,
- retries: 1,
+ retries: IS_CI ? 1 : 0,
testMatch: join(__dirname, './playwright/**/*.test.ts'),
testDir: join(__dirname, './playwright/'),
outputDir: join(__dirname, './playwright-results/'),
@@ -30,6 +30,7 @@ export const playwrightConfig: PlaywrightTestConfig = {
trace: 'on-first-retry',
actionTimeout: 5000,
screenshot: 'only-on-failure',
+ headless: false,
},
// ignore lock test because it takes too long and it will be tested in a separate config
testIgnore: [join(__dirname, './playwright/crx/lock.test.ts')],
diff --git a/packages/app/playwright/e2e/SendTransaction.test.ts b/packages/app/playwright/e2e/SendTransaction.test.ts
index db3c00e08..7dc3ea27a 100644
--- a/packages/app/playwright/e2e/SendTransaction.test.ts
+++ b/packages/app/playwright/e2e/SendTransaction.test.ts
@@ -1,14 +1,8 @@
import type { Account } from '@fuel-wallet/types';
+import { expectButtonToBeEnabled } from '@fuels/playwright-utils';
import type { Browser, Page } from '@playwright/test';
import test, { chromium, expect } from '@playwright/test';
-import {
- type Bech32Address,
- Provider,
- Wallet,
- bn,
- fromBech32,
- toB256,
-} from 'fuels';
+import { Provider, Wallet, bn } from 'fuels';
import {
getButtonByText,
@@ -62,7 +56,13 @@ test.describe('SendTransaction', () => {
await getInputByName(page, 'amount').fill('0.001');
// Submit transaction
- await getButtonByText(page, 'Review').click();
+
+ const btnLocator = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocator);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocator);
+ await btnLocator.click();
await getButtonByText(page, 'Approve').click();
await hasText(page, '0.001 ETH');
@@ -92,7 +92,13 @@ test.describe('SendTransaction', () => {
await getInputByName(page, 'amount').fill('0.001');
// Submit transaction
- await getButtonByText(page, 'Review').click();
+ // make sure the button is enabled
+ const btnLocator = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocator);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocator);
+ await btnLocator.click();
// Approve transaction
await hasText(page, '0.001 ETH');
@@ -131,7 +137,13 @@ test.describe('SendTransaction', () => {
await hasText(page, 'Balance: 1,000,000.000');
// Submit transaction
- await getButtonByText(page, 'Review').click();
+
+ const btnLocator = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocator);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocator);
+ await btnLocator.click();
// Approve transaction
await hasText(page, `0.01 ${ALT_ASSET.symbol}`);
@@ -163,7 +175,12 @@ test.describe('SendTransaction', () => {
await page.waitForSelector('button:has-text("Review")');
await page.waitForTimeout(1000);
- await getButtonByText(page, 'Review').click();
+ const btnLocator = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocator);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocator);
+ await btnLocator.click();
await hasText(page, '0.001 ETH');
@@ -200,7 +217,12 @@ test.describe('SendTransaction', () => {
await page.waitForSelector('button:has-text("Review")');
await page.waitForTimeout(1000);
- await getButtonByText(page, 'Review').click();
+ const btnLocator = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocator);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocator);
+ await btnLocator.click();
await hasText(page, '0.001 ETH');
@@ -241,7 +263,12 @@ test.describe('SendTransaction', () => {
await page.waitForSelector('button:has-text("Review")');
await page.waitForTimeout(1000);
- await getButtonByText(page, 'Review').click();
+ const btnLocatorBeforeApprv = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocatorBeforeApprv);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocatorBeforeApprv);
+ await btnLocatorBeforeApprv.click();
// Waiting button change to Approve in order to get updated fee amount
await page.waitForSelector('button:has-text("Approve")');
@@ -258,7 +285,12 @@ test.describe('SendTransaction', () => {
await page.waitForSelector('button:has-text("Review")');
await page.waitForTimeout(1000);
- await getButtonByText(page, 'Review').click();
+ const btnLocator = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocator);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocator);
+ await btnLocator.click();
// Waiting button change to Approve in order to get updated fee amount
await page.waitForSelector('button:has-text("Approve")');
@@ -308,7 +340,13 @@ test.describe('SendTransaction', () => {
const maxAmountAfterFee = await getInputByName(page, 'amount').inputValue();
// Submit transaction
- await getButtonByText(page, 'Review').click();
+
+ const btnLocator = getButtonByText(page, 'Review');
+
+ await expectButtonToBeEnabled(btnLocator);
+ await page.waitForTimeout(5000);
+ await expectButtonToBeEnabled(btnLocator);
+ await btnLocator.click();
// Approve transaction
await hasText(page, `${maxAmountAfterFee} ETH`);
diff --git a/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx b/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx
index 7956c3c25..8250942b1 100644
--- a/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx
+++ b/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx
@@ -1,6 +1,7 @@
import { Button, CardList } from '@fuel-ui/react';
import type { CoinAsset } from '@fuel-wallet/types';
import { useMemo, useState } from 'react';
+import { isUnknownAsset } from '~/systems/Asset';
import { AssetItem, AssetList } from '~/systems/Asset/components';
import type { AssetListEmptyProps } from '~/systems/Asset/components/AssetList/AssetListEmpty';
@@ -21,7 +22,10 @@ export const BalanceAssets = ({
}: BalanceAssetListProp) => {
const [showUnknown, setShowUnknown] = useState(false);
const unknownLength = useMemo(
- () => balances?.filter((balance) => !balance.asset?.name).length,
+ () =>
+ balances?.filter(
+ (balance) => balance.asset && isUnknownAsset(balance.asset)
+ ).length,
[balances]
);
@@ -29,7 +33,8 @@ export const BalanceAssets = ({
const isEmpty = !balances || !balances.length;
if (isEmpty) return ;
const balancesToShow = balances.filter(
- (balance) => showUnknown || balance.asset?.name
+ (balance) =>
+ showUnknown || (balance.asset && !isUnknownAsset(balance.asset))
);
function toggle() {
@@ -37,15 +42,22 @@ export const BalanceAssets = ({
}
return (
- {balancesToShow.map((balance) => (
-
- ))}
+ {balancesToShow.map((balance) => {
+ if (!balance.asset) return null;
+
+ const shouldShowAddAssetBtn = isUnknownAsset(balance.asset);
+
+ return (
+
+ );
+ })}
{!!(!isLoading && unknownLength) && (