Skip to content

Commit

Permalink
feat: show token value converted to USD (#1788)
Browse files Browse the repository at this point in the history
- Closes #1623
- Closes #1792 
- Closes FE-1380
- Closes FE-810

- Created the convertAsset utility, which returns the token amount
converted to USD.
- Token now also display their values in USD throughout Fuel Wallet.
- Moved asset endpoint data to global constants.

|
![Home](https://github.com/user-attachments/assets/4a4baf00-b547-4ad2-ac3e-c1252e577f84)
|
![](https://github.com/user-attachments/assets/6e36f2ad-60b2-46a3-a41c-1cc1c6014dfe)
|
![](https://github.com/user-attachments/assets/cd27b7ce-e799-40c8-b96e-12a8b71e2d49)
|

|----------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|

![](https://github.com/user-attachments/assets/fb477ce0-4df8-4ffa-80a9-123670514407)
| ![]() | |
  • Loading branch information
arthurgeron authored Feb 4, 2025
1 parent 37a5c22 commit fd1e342
Show file tree
Hide file tree
Showing 34 changed files with 749 additions and 200 deletions.
6 changes: 6 additions & 0 deletions .changeset/brown-wasps-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-wallet/types": patch
"fuels-wallet": patch
---

feat: show token value converted to USD
2 changes: 0 additions & 2 deletions .changeset/tall-suns-carry.md

This file was deleted.

141 changes: 116 additions & 25 deletions packages/app/jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import { webcrypto } from 'crypto';
// biome-ignore lint/style/useNodejsImportProtocol: <explanation>
import { TextDecoder, TextEncoder } from 'util';

import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { localStorageMock } from './src/mocks/localStorage';

// biome-ignore lint/suspicious/noExplicitAny: <explanation>
Expand All @@ -21,6 +22,120 @@ import 'whatwg-fetch';

import { act } from 'react';

// Initialize the MSW server with the necessary request handlers
const server = setupServer(
rest.get('/assets.json', (_req, res, ctx) => {
return res(
ctx.status(200),
ctx.json([
{
name: 'Ethereum',
symbol: 'ETH',
icon: 'https://verified-assets.fuel.network/images/eth.svg',
networks: [
{
type: 'ethereum',
chain: 'sepolia',
decimals: 18,
chainId: 11155111,
},
{
type: 'ethereum',
chain: 'foundry',
decimals: 18,
chainId: 31337,
},
{
type: 'ethereum',
chain: 'mainnet',
decimals: 18,
chainId: 1,
},
{
type: 'fuel',
chain: 'devnet',
decimals: 9,
assetId:
'0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07',
chainId: 0,
},
{
type: 'fuel',
chain: 'testnet',
decimals: 9,
assetId:
'0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07',
chainId: 0,
},
{
type: 'fuel',
chain: 'mainnet',
decimals: 9,
assetId:
'0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07',
chainId: 9889,
},
],
},
{
name: 'Fuel',
symbol: 'FUEL',
icon: 'https://verified-assets.fuel.network/images/fuel.svg',
networks: [
{
type: 'ethereum',
chain: 'sepolia',
address: '0xd7fc4e8fb2c05567c313f4c9b9e07641a361a550',
decimals: 9,
chainId: 11155111,
},
{
type: 'ethereum',
chain: 'mainnet',
address: '0x675b68aa4d9c2d3bb3f0397048e62e6b7192079c',
decimals: 9,
chainId: 1,
},
{
type: 'fuel',
chain: 'testnet',
decimals: 9,
chainId: 0,
contractId:
'0xd02112ef9c39f1cea7c8527c26242ca1f5d26bcfe8d1564bee054d3b04175471',
subId:
'0xede43647e2aad1c0f1696201d6ba913aa67c917c3ac9a4a7d95662962ab25c5b',
assetId:
'0x324d0c35a4299ef88138a656d5272c5a3a9ccde2630ae055dacaf9d13443d53b',
},
{
type: 'fuel',
chain: 'mainnet',
decimals: 9,
chainId: 9889,
contractId:
'0x4ea6ccef1215d9479f1024dff70fc055ca538215d2c8c348beddffd54583d0e8',
subId:
'0xe81c89b8cf795c7c25e79f6c4f2f1cd233290b58e217ed4e9b6b18538badddaf',
assetId:
'0x1d5d97005e41cae2187a895fd8eab0506111e0e2f3331cd3912c15c24e3c1d82',
},
],
},
])
);
})
);

// Establish API mocking before all tests
beforeAll(() => server.listen());

// Reset any request handlers that are declared as a part of our tests (i.e., for testing one-time error scenarios)
afterEach(() => server.resetHandlers());

// Clean up after the tests are finished
afterAll(() => server.close());

// Replace ReactDOMTestUtils.act with React.act
jest.mock('react-dom/test-utils', () => {
const originalModule = jest.requireActual('react-dom/test-utils');
Expand Down Expand Up @@ -81,27 +196,3 @@ if (process.env.CI) {
logErrorsBeforeRetry: true,
});
}

const _mockNetworks = [
{
asset_id: 'TKN',
name: 'Token',
type: 'token',
symbol: 'TKN',
decimals: 9,
},
{
asset_id: 'ETH',
name: 'Ethereum',
type: 'token',
symbol: 'ETH',
decimals: 18,
},
{
asset_id: 'Fuel',
name: 'Fuel',
type: 'token',
symbol: 'Fuel',
decimals: 9,
},
];
117 changes: 94 additions & 23 deletions packages/app/playwright/crx/assets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,40 +41,79 @@ test.describe('Check assets', () => {
});

test('should show valid asset value 0.002000', async () => {
await expect
.poll(
async () =>
await page
.getByLabel('ETH token balance', { exact: true })
.isVisible(),
{ timeout: 10000 }
)
.toBeTruthy();
expect(
await page.getByText('0.002000', { exact: true }).isVisible()
).toBeTruthy();
await page.getByLabel('ETH token balance', { exact: true }).textContent()
).toContain('0.002000 ETH');
});

test('should show USDCIcon AlertTriangle', async () => {
expect(
await page.getByText('USDCIcon AlertTriangle').isVisible()
).toBeTruthy();
await expect
.poll(
async () => await page.getByText('USDCIcon AlertTriangle').isVisible(),
{ timeout: 10000 }
)
.toBeTruthy();
});

test('should show 1 SCAM NFT', async () => {
expect(await page.getByText('1 SCAM').isVisible()).toBeTruthy();
await expect
.poll(async () => await page.getByText('1 SCAM').isVisible(), {
timeout: 10000,
})
.toBeTruthy();
});

// Verified assets should never show the (Add) button
test('should not show (Add) button for verified assets', async () => {
expect(
await page.getByRole('button', { name: '(Add)' }).isVisible()
).toBeFalsy();
await expect
.poll(
async () =>
await page.getByRole('button', { name: '(Add)' }).isVisible(),
{ timeout: 10000 }
)
.toBeFalsy();
});

// Verified assets will never be inside of "Hidden assets" part
test('should not show verified assets in hidden assets', async () => {
// get all h6 text from div.fuel_CardList as an array, and then click Show unknown assets button, and then check if the array added a new element with a name other than Unknown
const h6Texts = await page.$$eval('div.fuel_CardList h6', (els) =>
els.map((el) => el.textContent)
);
await page.getByRole('button', { name: 'Show unknown assets' }).click();
await page.waitForTimeout(1000);
const h6TextsAfter = await page.$$eval('div.fuel_CardList h6', (els) =>
els.map((el) => el.textContent)
);
expect(h6TextsAfter.length).toBeGreaterThan(h6Texts.length);
let h6Texts: string[] = [];
await expect
.poll(
async () => {
h6Texts = await page.$$eval('div.fuel_CardList h6', (els) =>
els.map((el) => el.textContent)
);
return h6Texts;
},
{ timeout: 10000 }
)
.toBeTruthy();

await page.getByLabel('Show unknown assets').click();

let h6TextsAfter: string[] = [];

await expect
.poll(
async () => {
h6TextsAfter = await page.$$eval('div.fuel_CardList h6', (els) =>
els.map((el) => el.textContent)
);
return h6TextsAfter.length;
},
{ timeout: 10000 }
)
.toBeGreaterThan(h6Texts.length);

for (const el of h6Texts) {
expect(el.includes('(Add)')).toBeFalsy();
Expand All @@ -96,17 +135,49 @@ test.describe('Check assets', () => {
});

test('Should add unknown asset', async () => {
await page.getByRole('button', { name: 'Show unknown assets' }).click();
await expect
.poll(async () => page.getByLabel('Show unknown assets'), {
timeout: 10000,
})
.toBeDefined();
await page.getByLabel('Show unknown assets').click();
await expect
.poll(async () => page.getByRole('button', { name: '(Add)' }).nth(1), {
timeout: 10000,
})
.toBeDefined();
await page.getByRole('button', { name: '(Add)' }).nth(1).click();

await expect
.poll(async () => await page.getByText('Token 2'), {
timeout: 10000,
})
.toBeDefined();
await page.getByPlaceholder('Asset name').fill('Token 2');
await page.getByPlaceholder('Asset symbol').fill('TKN2');
await page.getByLabel('Save Asset').click();
await page.waitForTimeout(1000);

await page.reload({ waitUntil: 'domcontentloaded' });
await page.waitForTimeout(1000);
await waitAriaLabel(page, 'Account 1 selected');
await page.waitForTimeout(1000);
expect(await page.getByText('1 TKN2').isVisible()).toBeTruthy();

await expect
.poll(
async () => {
return page.getByLabel('Account 1 selected').isVisible();
},
{ timeout: 10000 }
)
.toBeTruthy();

await expect
.poll(
async () => {
const text = await page.getByText('1 TKN2');
return text.isVisible();
},
{ timeout: 10000 }
)
.toBeTruthy();

// The following tests are disabled because the added tokens need a refresh to show up. Fix FE-1122 and enable these.

Expand Down
12 changes: 6 additions & 6 deletions packages/app/playwright/e2e/HomeWallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ test.describe('HomeWallet', () => {
await page.waitForTimeout(2000);
await page.reload();
await hasText(page, /Ethereum/i);
await hasText(page, /ETH.0\.002/i);
await hasText(page, /[$]\d{1,}\.\d{1,}/);
await getByAriaLabel(page, 'Selected Network').click();
await getByAriaLabel(page, 'fuel_network-item-2').click();
await hasText(page, "You don't have any assets");
Expand All @@ -55,14 +55,14 @@ test.describe('HomeWallet', () => {

test('should not show user balance when user sets it to hidden', async () => {
await visit(page, '/wallet');
await hasText(page, /ETH.+0/i);
await hasText(page, /[$]\d{1,}\.\d{2,}/i);
await getByAriaLabel(page, 'Hide balance').click(); // click on the hide balance
await hasText(page, /ETH.+/i); // should hide balance
await hasText(page, //i); // should hide balance
await reload(page); // reload the page
await hasText(page, /ETH.+/i); // should not show balance
await hasText(page, //i); // should not show balance
await getByAriaLabel(page, 'Show balance').click();
await hasText(page, /ETH.+0/i);
await hasText(page, /[$]\d{1,}\.\d{2,}/);
await reload(page); // reload the page
await hasText(page, /ETH.+0/i);
await hasText(page, /[$]\d{1,}\.\d{2,}/);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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';
import { UnknownAssetsButton } from '~/systems/Asset/components/UnknownAssetsButton/UnknownAssetsButton';

export type BalanceAssetListProp = {
balances?: CoinAsset[];
Expand Down Expand Up @@ -64,11 +65,12 @@ export const BalanceAssets = ({
/>
);
})}
{!!(!isLoading && unknownLength) && (
<Button size="xs" variant="link" onPress={toggle}>
{showUnknown ? 'Hide' : 'Show'} unknown assets ({unknownLength})
</Button>
)}
<UnknownAssetsButton
showUnknown={showUnknown}
unknownLength={unknownLength}
isLoading={!!isLoading}
toggle={toggle}
/>
</CardList>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const ACCOUNT: AccountWithBalance = {
balance: bn(12008943834),
balanceSymbol: '$',
balances: [],
amountInUsd: '$38,830.32',
totalBalanceInUsd: 38830.32,
};

export const Usage = (args: BalanceWidgetProps) => (
Expand Down
Loading

0 comments on commit fd1e342

Please sign in to comment.