diff --git a/e2e/pages/strategy.spec.ts b/e2e/pages/strategy.spec.ts index 5c1e2cd39..c5a502e78 100644 --- a/e2e/pages/strategy.spec.ts +++ b/e2e/pages/strategy.spec.ts @@ -1,65 +1,93 @@ import { test } from '@playwright/test'; +import { mockApi } from '../utils/mock-api'; +import { DebugDriver, removeFork, setupFork } from '../utils/DebugDriver'; +import { CreateStrategyTestCase } from '../utils/strategy'; import * as recurring from '../tests/strategy/recurring/'; import * as disposable from '../tests/strategy/disposable/'; import * as overlapping from '../tests/strategy/overlapping/'; -import { StrategyType } from './../utils/strategy/template'; -import { navigateTo, screenshot } from '../utils/operators'; -import { mockApi } from '../utils/mock-api'; -import { DebugDriver, removeFork, setupFork } from '../utils/DebugDriver'; -import { - MyStrategyDriver, - OverlappingStrategyTestCase, - RecurringStrategyTestCase, -} from '../utils/strategy'; - -type TestCase = (RecurringStrategyTestCase | OverlappingStrategyTestCase) & { - type: StrategyType; -}; - -const testCases: TestCase[] = [ +const testCases: CreateStrategyTestCase[] = [ { - type: 'recurring', - setting: 'limit_limit', - base: 'ETH', - quote: 'DAI', - buy: { - min: '1500', - max: '1500', - budget: '10', - budgetFiat: '10', + input: { + type: 'recurring', + setting: 'limit_limit', + base: 'ETH', + quote: 'DAI', + buy: { + min: '1500', + max: '1500', + budget: '10', + budgetFiat: '10', + }, + sell: { + min: '1700', + max: '1700', + budget: '2', + budgetFiat: '3334', + }, }, - sell: { - min: '1700', - max: '1700', - budget: '2', - budgetFiat: '3334', + output: { + create: { + totalFiat: '$3,344.42', + buy: { + min: '1,500.00 DAI', + max: '1,500.00 DAI', + budget: '10.00 DAI', + fiat: '$10.00', + }, + sell: { + min: '1,700.00 DAI', + max: '1,700.00 DAI', + budget: '2.00 ETH', + fiat: '$3,334.42', + }, + }, }, }, { - type: 'overlapping', - base: 'BNT', - quote: 'USDC', - buy: { - min: '0.3', - max: '0.545454', - budget: '12.501572', - budgetFiat: '12.5', + input: { + type: 'overlapping', + base: 'BNT', + quote: 'USDC', + buy: { + min: '0.3', + max: '0.545454', + budget: '12.501572', + budgetFiat: '12.5', + }, + sell: { + min: '0.33', + max: '0.6', + budget: '30', + budgetFiat: '12.61', + }, + spread: '10', // Need a large spread for tooltip test }, - sell: { - min: '0.33', - max: '0.6', - budget: '30', - budgetFiat: '12.61', + output: { + create: { + totalFiat: '$25.11', + buy: { + min: '0.30 USDC', + max: '0.545454 USDC', + budget: '12.50 USDC', + fiat: '$12.50', + }, + sell: { + min: '0.33 USDC', + max: '0.60 USDC', + budget: '30.00 BNT', + fiat: '$12.61', + }, + }, }, - spread: '10', // Need a large spread for tooltip test }, ]; -const testDescription = (testCase: TestCase) => { - if (testCase.type === 'overlapping') return 'Overlapping'; - if (testCase.type === 'disposable') return `Disposable ${testCase.setting}`; - return `Recurring ${testCase.setting.split('_').join(' ')}`; +const testDescription = (testCase: CreateStrategyTestCase) => { + const input = testCase.input; + if (input.type === 'overlapping') return 'Overlapping'; + if (input.type === 'disposable') return `Disposable ${input.setting}`; + return `Recurring ${input.setting.split('_').join(' ')}`; }; test.describe('Strategies', () => { @@ -75,13 +103,6 @@ test.describe('Strategies', () => { await removeFork(testInfo); }); - test('First Strategy Page', async ({ page }) => { - await navigateTo(page, '/'); - const driver = new MyStrategyDriver(page); - await driver.firstStrategy().waitFor({ state: 'visible' }); - await screenshot(page, 'first-strategy'); - }); - const testStrategies = { recurring, disposable, @@ -90,7 +111,7 @@ test.describe('Strategies', () => { for (const testCase of testCases) { test.describe(testDescription(testCase), () => { - const testSuite = testStrategies[testCase.type]; + const testSuite = testStrategies[testCase.input.type]; for (const [, testFn] of Object.entries(testSuite)) { testFn(testCase); } diff --git a/e2e/screenshots/[Create Overlapping Strategy] My Strategy.jpg b/e2e/screenshots/[Create Overlapping Strategy] My Strategy.jpg index 96408c712..cb711b37a 100644 Binary files a/e2e/screenshots/[Create Overlapping Strategy] My Strategy.jpg and b/e2e/screenshots/[Create Overlapping Strategy] My Strategy.jpg differ diff --git a/e2e/tests/strategy/disposable/delete.ts b/e2e/tests/strategy/disposable/delete.ts index e40fa8e96..69c8270bf 100644 --- a/e2e/tests/strategy/disposable/delete.ts +++ b/e2e/tests/strategy/disposable/delete.ts @@ -1,14 +1,17 @@ import { expect, test } from '@playwright/test'; -import { MyStrategyDriver } from './../../../utils/strategy'; +import { + CreateStrategyTestCase, + MyStrategyDriver, +} from './../../../utils/strategy'; import { waitModalOpen } from './../../../utils/modal'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; import { NotificationDriver } from './../../../utils/NotificationDriver'; import { ManageStrategyDriver } from './../../../utils/strategy/ManageStrategyDriver'; -export const deleteStrategyTest = (testCase: CreateStrategyTemplate) => { +export const deleteStrategyTest = (testCase: CreateStrategyTestCase) => { return test('Delete', async ({ page }) => { + const { input } = testCase; const manage = new ManageStrategyDriver(page); - const strategy = await manage.createStrategy(testCase); + const strategy = await manage.createStrategy(input); await strategy.clickManageEntry('manage-strategy-deleteStrategy'); const modal = await waitModalOpen(page); diff --git a/e2e/tests/strategy/overlapping/create.ts b/e2e/tests/strategy/overlapping/create.ts index e25b57a11..53da8b72e 100644 --- a/e2e/tests/strategy/overlapping/create.ts +++ b/e2e/tests/strategy/overlapping/create.ts @@ -1,24 +1,19 @@ import { expect, test } from '@playwright/test'; -import { CreateStrategyTemplate } from '../../../utils/strategy/template'; import { NotificationDriver } from '../../../utils/NotificationDriver'; -import { - fiatPrice, - navigateTo, - screenshot, - tokenPrice, - waitFor, -} from '../../../utils/operators'; +import { navigateTo, screenshot, waitFor } from '../../../utils/operators'; import { CreateStrategyDriver, + CreateStrategyTestCase, MyStrategyDriver, + assertOverlappingTestCase, } from '../../../utils/strategy'; import { MainMenuDriver } from '../../../utils/MainMenuDriver'; import { checkApproval } from '../../../utils/modal'; -export const createOverlappingStrategy = (testCase: CreateStrategyTemplate) => { - const { base, quote, buy, sell } = testCase; - const buyBudgetFiat = parseFloat(buy.budgetFiat ?? '0'); - const sellBudgetFiat = parseFloat(sell.budgetFiat ?? '0'); +export const createOverlappingStrategy = (testCase: CreateStrategyTestCase) => { + assertOverlappingTestCase(testCase); + const { base, quote, sell } = testCase.input; + const output = testCase.output.create; return test(`Create ${base}->${quote}`, async ({ page }) => { test.setTimeout(180_000); @@ -26,7 +21,7 @@ export const createOverlappingStrategy = (testCase: CreateStrategyTemplate) => { await navigateTo(page, '/'); const myStrategies = new MyStrategyDriver(page); - const createForm = new CreateStrategyDriver(page, testCase); + const createForm = new CreateStrategyDriver(page, testCase.input); await myStrategies.createStrategy(); await createForm.selectToken('base'); await createForm.selectToken('quote'); @@ -34,7 +29,7 @@ export const createOverlappingStrategy = (testCase: CreateStrategyTemplate) => { await createForm.nextStep(); const overlappingForm = await createForm.fillOverlapping(); - expect(overlappingForm.max()).toHaveValue(testCase.sell.max.toString()); + expect(overlappingForm.max()).toHaveValue(sell.max.toString()); const mainMenu = new MainMenuDriver(page); await mainMenu.hide(); @@ -61,26 +56,18 @@ export const createOverlappingStrategy = (testCase: CreateStrategyTemplate) => { const strategy = await myStrategies.getStrategy(1); await expect(strategy.pair()).toHaveText(`${base}/${quote}`); await expect(strategy.status()).toHaveText('Active'); - await expect(strategy.totalBudget()).toHaveText( - fiatPrice(buyBudgetFiat + sellBudgetFiat) - ); - await expect(strategy.buyBudget()).toHaveText( - tokenPrice(buy.budget, quote) - ); - await expect(strategy.buyBudgetFiat()).toHaveText(fiatPrice(buyBudgetFiat)); - await expect(strategy.sellBudget()).toHaveText( - tokenPrice(sell.budget, base) - ); - await expect(strategy.sellBudgetFiat()).toHaveText( - fiatPrice(sellBudgetFiat) - ); + await expect(strategy.totalBudget()).toHaveText(output.totalFiat); + await expect(strategy.buyBudget()).toHaveText(output.buy.budget); + await expect(strategy.buyBudgetFiat()).toHaveText(output.buy.fiat); + await expect(strategy.sellBudget()).toHaveText(output.sell.budget); + await expect(strategy.sellBudgetFiat()).toHaveText(output.sell.fiat); const sellTooltip = await strategy.priceTooltip('sell'); - await expect(sellTooltip.minPrice()).toHaveText( - tokenPrice(sell.min, quote) - ); + await expect(sellTooltip.minPrice()).toHaveText(output.sell.min); + await expect(sellTooltip.maxPrice()).toHaveText(output.sell.max); await sellTooltip.waitForDetached(); const buyTooltip = await strategy.priceTooltip('buy'); - await expect(buyTooltip.maxPrice()).toHaveText(tokenPrice(buy.max, quote)); + await expect(buyTooltip.minPrice()).toHaveText(output.buy.min); + await expect(buyTooltip.maxPrice()).toHaveText(output.buy.max); await buyTooltip.waitForDetached(); await notif.close(); await screenshot(page, `[Create Overlapping Strategy] My Strategy`); diff --git a/e2e/tests/strategy/recurring/create.ts b/e2e/tests/strategy/recurring/create.ts index d1d4fa949..38189e294 100644 --- a/e2e/tests/strategy/recurring/create.ts +++ b/e2e/tests/strategy/recurring/create.ts @@ -1,29 +1,25 @@ import { expect, test } from '@playwright/test'; -import { CreateStrategyTemplate } from '../../../utils/strategy/template'; import { checkApproval } from '../../../utils/modal'; import { NotificationDriver } from '../../../utils/NotificationDriver'; -import { - fiatPrice, - navigateTo, - tokenPrice, - waitFor, -} from '../../../utils/operators'; +import { navigateTo, tokenPrice, waitFor } from '../../../utils/operators'; import { CreateStrategyDriver, + CreateStrategyTestCase, MyStrategyDriver, + assertRecurringTestCase, } from '../../../utils/strategy'; -export const createRecurringStrategy = (testCase: CreateStrategyTemplate) => { - const { base, quote, buy, sell } = testCase; - const buyBudgetFiat = parseFloat(buy.budgetFiat ?? '0'); - const sellBudgetFiat = parseFloat(sell.budgetFiat ?? '0'); +export const createRecurringStrategy = (testCase: CreateStrategyTestCase) => { + assertRecurringTestCase(testCase); + const { base, quote, buy, sell } = testCase.input; + const output = testCase.output.create; return test(`Create`, async ({ page }) => { await waitFor(page, `balance-${quote}`, 30_000); await navigateTo(page, '/'); const myStrategies = new MyStrategyDriver(page); - const createForm = new CreateStrategyDriver(page, testCase); + const createForm = new CreateStrategyDriver(page, testCase.input); await myStrategies.createStrategy(); await createForm.selectToken('base'); await createForm.selectToken('quote'); @@ -35,7 +31,7 @@ export const createRecurringStrategy = (testCase: CreateStrategyTemplate) => { // Assert 100% outcome await expect(buyForm.outcomeValue()).toHaveText(`0.006666 ${base}`); await expect(buyForm.outcomeQuote()).toHaveText(tokenPrice(buy.min, quote)); - await expect(sellForm.outcomeValue()).toHaveText(`3,400 ${quote}`); + await expect(sellForm.outcomeValue()).toHaveText(`3,400.00 ${quote}`); await expect(sellForm.outcomeQuote()).toHaveText( tokenPrice(sell.min, quote) ); @@ -59,18 +55,10 @@ export const createRecurringStrategy = (testCase: CreateStrategyTemplate) => { const strategy = await myStrategies.getStrategy(1); await expect(strategy.pair()).toHaveText(`${base}/${quote}`); await expect(strategy.status()).toHaveText('Active'); - await expect(strategy.totalBudget()).toHaveText( - fiatPrice(buyBudgetFiat + sellBudgetFiat) - ); - await expect(strategy.buyBudget()).toHaveText( - tokenPrice(buy.budget, quote) - ); - await expect(strategy.buyBudgetFiat()).toHaveText(fiatPrice(buyBudgetFiat)); - await expect(strategy.sellBudget()).toHaveText( - tokenPrice(sell.budget, base) - ); - await expect(strategy.sellBudgetFiat()).toHaveText( - fiatPrice(sellBudgetFiat) - ); + await expect(strategy.totalBudget()).toHaveText(output.totalFiat); + await expect(strategy.buyBudget()).toHaveText(output.buy.budget); + await expect(strategy.buyBudgetFiat()).toHaveText(output.buy.fiat); + await expect(strategy.sellBudget()).toHaveText(output.sell.budget); + await expect(strategy.sellBudgetFiat()).toHaveText(output.sell.fiat); }); }; diff --git a/e2e/tests/strategy/recurring/delete.ts b/e2e/tests/strategy/recurring/delete.ts index 69c5fad73..ec9138ebd 100644 --- a/e2e/tests/strategy/recurring/delete.ts +++ b/e2e/tests/strategy/recurring/delete.ts @@ -1,16 +1,17 @@ import { expect, test } from '@playwright/test'; -import { MyStrategyDriver } from './../../../utils/strategy'; +import { + CreateStrategyTestCase, + MyStrategyDriver, +} from './../../../utils/strategy'; import { waitModalOpen } from './../../../utils/modal'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; import { NotificationDriver } from './../../../utils/NotificationDriver'; import { ManageStrategyDriver } from './../../../utils/strategy/ManageStrategyDriver'; -export const deleteStrategyTest = (testCase: CreateStrategyTemplate) => { +export const deleteStrategyTest = (testCase: CreateStrategyTestCase) => { + const { input } = testCase; return test('Delete', async ({ page }) => { - test.setTimeout(45_000); - const manage = new ManageStrategyDriver(page); - const strategy = await manage.createStrategy(testCase); + const strategy = await manage.createStrategy(input); await strategy.clickManageEntry('manage-strategy-deleteStrategy'); const modal = await waitModalOpen(page); diff --git a/e2e/tests/strategy/recurring/deposit.ts b/e2e/tests/strategy/recurring/deposit.ts index 09f37a4c5..194e13af6 100644 --- a/e2e/tests/strategy/recurring/deposit.ts +++ b/e2e/tests/strategy/recurring/deposit.ts @@ -1,12 +1,13 @@ import { expect, test } from '@playwright/test'; import { tokenPrice } from './../../../utils/operators'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; import { NotificationDriver } from './../../../utils/NotificationDriver'; import { ManageStrategyDriver } from './../../../utils/strategy/ManageStrategyDriver'; +import { CreateStrategyTestCase } from '../../../utils/strategy'; -export const depositStrategyTest = (testCase: CreateStrategyTemplate) => { +export const depositStrategyTest = (testCase: CreateStrategyTestCase) => { + const { input } = testCase; return test('Deposit', async ({ page }) => { - const { base, quote, buy, sell } = testCase; + const { base, quote, buy, sell } = input; const buyBudget = parseFloat(buy.budget); const sellBudget = parseFloat(sell.budget); @@ -16,7 +17,7 @@ export const depositStrategyTest = (testCase: CreateStrategyTemplate) => { const newSellBudget = (sellBudget + depositSellBudget).toString(); const manage = new ManageStrategyDriver(page); - const strategy = await manage.createStrategy(testCase); + const strategy = await manage.createStrategy(input); await strategy.clickManageEntry('manage-strategy-depositFunds'); await manage.waitForEditPage('deposit'); diff --git a/e2e/tests/strategy/recurring/duplicate.ts b/e2e/tests/strategy/recurring/duplicate.ts index e1d318404..373f79435 100644 --- a/e2e/tests/strategy/recurring/duplicate.ts +++ b/e2e/tests/strategy/recurring/duplicate.ts @@ -1,19 +1,20 @@ import { expect, test } from '@playwright/test'; -import { MyStrategyDriver } from './../../../utils/strategy'; -import { fiatPrice, tokenPrice } from './../../../utils/operators'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; +import { + CreateStrategyTestCase, + MyStrategyDriver, + assertRecurringTestCase, +} from './../../../utils/strategy'; import { NotificationDriver } from './../../../utils/NotificationDriver'; import { ManageStrategyDriver } from './../../../utils/strategy/ManageStrategyDriver'; import { waitModalOpen } from '../../../utils/modal'; -export const duplicateStrategyTest = (testCase: CreateStrategyTemplate) => { +export const duplicateStrategyTest = (testCase: CreateStrategyTestCase) => { + assertRecurringTestCase(testCase); + const { base, quote } = testCase.input; + const output = testCase.output.create; return test('Duplicate', async ({ page }) => { - const { base, quote, buy, sell } = testCase; - const buyBudgetFiat = parseFloat(buy.budgetFiat ?? '0'); - const sellBudgetFiat = parseFloat(sell.budgetFiat ?? '0'); - const manage = new ManageStrategyDriver(page); - const strategy = await manage.createStrategy(testCase); + const strategy = await manage.createStrategy(testCase.input); await strategy.clickManageEntry('manage-strategy-duplicateStrategy'); const modal = await waitModalOpen(page); @@ -39,20 +40,12 @@ export const duplicateStrategyTest = (testCase: CreateStrategyTemplate) => { const strategyDuplicate = await myStrategies.getStrategy(2); await expect(strategyDuplicate.pair()).toHaveText(`${base}/${quote}`); await expect(strategyDuplicate.status()).toHaveText('Active'); - await expect(strategyDuplicate.totalBudget()).toHaveText( - fiatPrice(buyBudgetFiat + sellBudgetFiat) - ); - await expect(strategyDuplicate.buyBudget()).toHaveText( - tokenPrice(buy.budget, quote) - ); - await expect(strategyDuplicate.buyBudgetFiat()).toHaveText( - fiatPrice(buyBudgetFiat) - ); - await expect(strategyDuplicate.sellBudget()).toHaveText( - tokenPrice(sell.budget, base) - ); + await expect(strategyDuplicate.totalBudget()).toHaveText(output.totalFiat); + await expect(strategyDuplicate.buyBudget()).toHaveText(output.buy.budget); + await expect(strategyDuplicate.buyBudgetFiat()).toHaveText(output.buy.fiat); + await expect(strategyDuplicate.sellBudget()).toHaveText(output.sell.budget); await expect(strategyDuplicate.sellBudgetFiat()).toHaveText( - fiatPrice(sellBudgetFiat) + output.sell.fiat ); }); }; diff --git a/e2e/tests/strategy/recurring/edit.ts b/e2e/tests/strategy/recurring/edit.ts index da2e948e2..658e9d938 100644 --- a/e2e/tests/strategy/recurring/edit.ts +++ b/e2e/tests/strategy/recurring/edit.ts @@ -1,18 +1,19 @@ import { expect, test } from '@playwright/test'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; import { NotificationDriver } from './../../../utils/NotificationDriver'; import { ManageStrategyDriver } from './../../../utils/strategy/ManageStrategyDriver'; +import { CreateStrategyTestCase } from '../../../utils/strategy'; -export const editPriceStrategyTest = (testCase: CreateStrategyTemplate) => { +export const editPriceStrategyTest = (testCase: CreateStrategyTestCase) => { + const { input } = testCase; return test('Edit Price', async ({ page }) => { const manage = new ManageStrategyDriver(page); - const strategy = await manage.createStrategy(testCase); + const strategy = await manage.createStrategy(input); await strategy.clickManageEntry('manage-strategy-editPrices'); await manage.waitForEditPage('editPrices'); - const newBuyPrice = (parseFloat(testCase.buy.max) / 2).toString(); - const newSellPrice = (parseFloat(testCase.sell.max) / 2).toString(); + const newBuyPrice = (parseFloat(input.buy.max) / 2).toString(); + const newSellPrice = (parseFloat(input.sell.max) / 2).toString(); await manage.fillLimitPrice('buy', newBuyPrice); await manage.fillLimitPrice('sell', newSellPrice); diff --git a/e2e/tests/strategy/recurring/pause.ts b/e2e/tests/strategy/recurring/pause.ts index f3b4f1432..248a0e0d2 100644 --- a/e2e/tests/strategy/recurring/pause.ts +++ b/e2e/tests/strategy/recurring/pause.ts @@ -1,13 +1,14 @@ import { expect, test } from '@playwright/test'; import { waitModalOpen } from './../../../utils/modal'; import { Page } from 'playwright-core'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; +import { CreateStrategyInput } from './../../../utils/strategy/template'; import { NotificationDriver } from './../../../utils/NotificationDriver'; import { ManageStrategyDriver } from './../../../utils/strategy/ManageStrategyDriver'; +import { CreateStrategyTestCase } from '../../../utils/strategy'; export const pauseStrategy = async ( page: Page, - testCase: CreateStrategyTemplate + testCase: CreateStrategyInput ) => { const manage = new ManageStrategyDriver(page); const strategy = await manage.createStrategy(testCase); @@ -27,8 +28,9 @@ export const pauseStrategy = async ( return { strategy, manage }; }; -export const pauseStrategyTest = (testCase: CreateStrategyTemplate) => { +export const pauseStrategyTest = (testCase: CreateStrategyTestCase) => { + const { input } = testCase; return test('Pause', async ({ page }) => { - await pauseStrategy(page, testCase); + await pauseStrategy(page, input); }); }; diff --git a/e2e/tests/strategy/recurring/renew.ts b/e2e/tests/strategy/recurring/renew.ts index cf7cc57a8..f673d44e3 100644 --- a/e2e/tests/strategy/recurring/renew.ts +++ b/e2e/tests/strategy/recurring/renew.ts @@ -1,16 +1,17 @@ import { expect, test } from '@playwright/test'; import { pauseStrategy } from './pause'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; import { NotificationDriver } from './../../../utils/NotificationDriver'; +import { CreateStrategyTestCase } from '../../../utils/strategy'; -export const renewStrategyTest = (testCase: CreateStrategyTemplate) => { +export const renewStrategyTest = (testCase: CreateStrategyTestCase) => { + const { input } = testCase; return test('Renew', async ({ page }) => { - const { strategy, manage } = await pauseStrategy(page, testCase); + const { strategy, manage } = await pauseStrategy(page, input); await strategy.clickManageEntry('manage-strategy-renewStrategy'); await manage.waitForEditPage('renew'); - await manage.fillLimitPrice('buy', testCase.buy.max); - await manage.fillLimitPrice('sell', testCase.sell.max); + await manage.fillLimitPrice('buy', input.buy.max); + await manage.fillLimitPrice('sell', input.sell.max); await page.getByTestId('edit-strategy-prices-submit').click(); await page.waitForURL('/', { timeout: 10_000 }); diff --git a/e2e/tests/strategy/recurring/withdraw.ts b/e2e/tests/strategy/recurring/withdraw.ts index a16aa5507..e7ea4b6ec 100644 --- a/e2e/tests/strategy/recurring/withdraw.ts +++ b/e2e/tests/strategy/recurring/withdraw.ts @@ -1,13 +1,14 @@ import { expect, test } from '@playwright/test'; import { waitModalOpen } from './../../../utils/modal'; import { tokenPrice } from './../../../utils/operators'; -import { CreateStrategyTemplate } from './../../../utils/strategy/template'; import { NotificationDriver } from './../../../utils/NotificationDriver'; import { ManageStrategyDriver } from './../../../utils/strategy/ManageStrategyDriver'; +import { CreateStrategyTestCase } from '../../../utils/strategy'; -export const withdrawStrategyTest = (testCase: CreateStrategyTemplate) => { +export const withdrawStrategyTest = (testCase: CreateStrategyTestCase) => { + const { input } = testCase; return test('Withdraw', async ({ page }) => { - const { base, quote, buy, sell } = testCase; + const { base, quote, buy, sell } = input; const buyBudget = parseFloat(buy.budget); const sellBudget = parseFloat(sell.budget); @@ -15,7 +16,7 @@ export const withdrawStrategyTest = (testCase: CreateStrategyTemplate) => { const withdrawSellBudget = sellBudget / 2; const manage = new ManageStrategyDriver(page); - const strategy = await manage.createStrategy(testCase); + const strategy = await manage.createStrategy(input); await strategy.clickManageEntry('manage-strategy-withdrawFunds'); const modal = await waitModalOpen(page); diff --git a/e2e/utils/DebugDriver.ts b/e2e/utils/DebugDriver.ts index 6934221a3..78d3262d8 100644 --- a/e2e/utils/DebugDriver.ts +++ b/e2e/utils/DebugDriver.ts @@ -8,7 +8,7 @@ import { } from './../utils/tenderly'; import { Wallet } from 'ethers'; import { checkApproval } from './modal'; -import { CreateStrategyTemplate } from './strategy/template'; +import { CreateStrategyInput } from './strategy/template'; const forkConfig: CreateForkBody = { network_id: '1', @@ -72,7 +72,7 @@ export class DebugDriver { return this.page.getByTestId(`balance-${token}`); } - async createStrategy(template: CreateStrategyTemplate) { + async createStrategy(template: CreateStrategyInput) { const { base, quote, buy, sell, spread, amount } = template; // TODO: use textarea shortcut instead of filling each field. // Currently this revert with Dai/insufficient-allowance for some reason diff --git a/e2e/utils/NotificationDriver.ts b/e2e/utils/NotificationDriver.ts index bbc11f3d3..8e28f12a9 100644 --- a/e2e/utils/NotificationDriver.ts +++ b/e2e/utils/NotificationDriver.ts @@ -26,9 +26,10 @@ export class NotificationDriver { return this.notif.getByTestId('notif-description'); } async close() { - const isVisible = await this.notif.isVisible(); + const btn = this.notif.getByTestId('notif-close'); + const isVisible = await btn.isVisible(); if (isVisible) { - this.notif.getByTestId('notif-close').click(); + btn.click(); return this.notif.waitFor({ state: 'detached' }); } } diff --git a/e2e/utils/strategy/CreateStrategyDriver.ts b/e2e/utils/strategy/CreateStrategyDriver.ts index d7a125dd0..ed789b630 100644 --- a/e2e/utils/strategy/CreateStrategyDriver.ts +++ b/e2e/utils/strategy/CreateStrategyDriver.ts @@ -1,34 +1,118 @@ import { Page } from '@playwright/test'; -import { CreateStrategyTemplate } from './../../utils/strategy/template'; +import { + CreateStrategyInput, + assertDebugToken, + debugTokens, +} from './../../utils/strategy/template'; import { waitModalClose, waitModalOpen } from '../modal'; +import { TestCase } from '../types'; -export interface RecurringStrategyTestCase extends CreateStrategyTemplate { - setting: 'limit_limit' | 'range_range' | 'limit_range' | 'range_limit'; +type Setting = 'limit' | 'range'; +type Direction = 'buy' | 'sell'; +type StrategySettings = + | `two-${Setting}s` + | `${Direction}-${Setting}` + | 'overlapping'; + +export interface RecurringStrategyInput extends CreateStrategyInput { + type: 'recurring'; + setting: `${Setting}_${Setting}`; +} +export interface RecurringStrategyOutput { + create: { + totalFiat: string; + buy: { + min: string; + max: string; + budget: string; + fiat: string; + }; + sell: { + min: string; + max: string; + budget: string; + fiat: string; + }; + }; } -export interface OverlappingStrategyTestCase extends CreateStrategyTemplate { +export type RecurringStrategyTestCase = TestCase< + RecurringStrategyInput, + RecurringStrategyOutput +>; + +export interface OverlappingStrategyInput extends CreateStrategyInput { type: 'overlapping'; spread: string; } +export interface OverlappingStrategyOutput { + create: { + totalFiat: string; + buy: { + min: string; + max: string; + budget: string; + fiat: string; + }; + sell: { + min: string; + max: string; + budget: string; + fiat: string; + }; + }; +} +export type OverlappingStrategyTestCase = TestCase< + OverlappingStrategyInput, + OverlappingStrategyOutput +>; + +export interface DisposableStrategyInput extends CreateStrategyInput { + type: 'disposable'; + setting: Setting; + direction: Direction; +} +export interface DisposableStrategyOutput {} +export type DisposableStrategyTestCase = TestCase< + DisposableStrategyInput, + DisposableStrategyOutput +>; export type CreateStrategyTestCase = + | DisposableStrategyTestCase | RecurringStrategyTestCase | OverlappingStrategyTestCase; -type Mode = 'buy' | 'sell'; -type StrategySettings = - | 'two-limits' - | 'two-ranges' - | 'overlapping' - | `${Mode}-range` - | `${Mode}-limit`; +export function assertDisposableTestCase( + testCase: CreateStrategyTestCase +): asserts testCase is DisposableStrategyTestCase { + if (testCase.input.type !== 'disposable') { + throw new Error('Test case should be disposable'); + } +} + +export function assertRecurringTestCase( + testCase: CreateStrategyTestCase +): asserts testCase is RecurringStrategyTestCase { + if (testCase.input.type !== 'recurring') { + throw new Error('Test case should be recurring'); + } +} + +export function assertOverlappingTestCase( + testCase: CreateStrategyTestCase +): asserts testCase is OverlappingStrategyTestCase { + if (testCase.input.type !== 'overlapping') { + throw new Error('Test case should be overlapping'); + } +} export class CreateStrategyDriver { - constructor(private page: Page, private testCase: CreateStrategyTemplate) {} + constructor(private page: Page, private testCase: CreateStrategyInput) {} - getRecurringLimitForm(mode: Mode) { - const form = this.page.getByTestId(`${mode}-section`); + getRecurringLimitForm(direction: Direction) { + const form = this.page.getByTestId(`${direction}-section`); return { - price: () => form.getByTestId(`input-limit-${mode}`), + price: () => form.getByTestId(`input-limit-${direction}`), budget: () => form.getByTestId('input-budget'), outcomeValue: () => form.getByTestId('outcome-value'), outcomeQuote: () => form.getByTestId('outcome-quote'), @@ -51,26 +135,28 @@ export class CreateStrategyDriver { } async selectToken(tokenType: 'base' | 'quote') { - const token = this.testCase[tokenType]; + const symbol = this.testCase[tokenType]; + assertDebugToken(symbol); + const token = debugTokens[symbol]; await this.page.getByTestId(`select-${tokenType}-token`).click(); await waitModalOpen(this.page); - await this.page.getByLabel('Select Token').fill(token); + await this.page.getByLabel('Select Token').fill(symbol); await this.page.getByTestId(`select-token-${token}`).click(); await waitModalClose(this.page); } selectSetting(strategySettings: StrategySettings) { return this.page.getByTestId(strategySettings).click(); } - async fillRecurringLimit(mode: Mode) { - const { min, budget } = this.testCase[mode]; - const form = this.getRecurringLimitForm(mode); + async fillRecurringLimit(direction: Direction) { + const { min, budget } = this.testCase[direction]; + const form = this.getRecurringLimitForm(direction); await form.setting('limit').click(); await form.price().fill(min.toString()); await form.budget().fill(budget.toString()); return form; } async fillOverlapping() { - const testCase = this.testCase as OverlappingStrategyTestCase; + const testCase = this.testCase as OverlappingStrategyInput; const form = this.getOverlappingForm(); await form.max().fill(testCase.sell.max.toString()); await form.min().fill(testCase.buy.min.toString()); diff --git a/e2e/utils/strategy/ManageStrategyDriver.ts b/e2e/utils/strategy/ManageStrategyDriver.ts index 4b9a36544..0d2578141 100644 --- a/e2e/utils/strategy/ManageStrategyDriver.ts +++ b/e2e/utils/strategy/ManageStrategyDriver.ts @@ -1,4 +1,4 @@ -import { CreateStrategyTemplate } from './../../utils/strategy/template'; +import { CreateStrategyInput } from './../../utils/strategy/template'; import { DebugDriver } from './../../utils/DebugDriver'; import { navigateTo } from './../../utils/operators'; import { MyStrategyDriver } from './../../utils/strategy/MyStrategyDriver'; @@ -7,7 +7,7 @@ import { Page } from 'playwright-core'; export class ManageStrategyDriver { constructor(private page: Page) {} - async createStrategy(testCase: CreateStrategyTemplate) { + async createStrategy(testCase: CreateStrategyInput) { const debug = new DebugDriver(this.page); await debug.createStrategy(testCase); await navigateTo(this.page, '/'); diff --git a/e2e/utils/strategy/template.ts b/e2e/utils/strategy/template.ts index 37d1e6ada..88d408c08 100644 --- a/e2e/utils/strategy/template.ts +++ b/e2e/utils/strategy/template.ts @@ -3,23 +3,36 @@ import { getSellMin, } from '../../../src/components/strategies/overlapping/utils'; -type DebugTokens = - | 'USDC' - | 'DAI' - | 'BNT' - | 'PARQ' - | 'WBTC' - | 'BNB' - | 'MATIC' - | 'SHIB' - | 'UNI' - | 'USDT' - | 'ETH'; +export const debugTokens = { + BNB: '0x418D75f65a02b3D53B2418FB8E1fe493759c7605', + BNT: '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', + DAI: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + ETH: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + MATIC: '0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0', + SHIB: '0xfcaF0e4498E78d65526a507360F755178b804Ba8', + UNI: '0x2730d6FdC86C95a74253BefFaA8306B40feDecbb', + USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + WBTC: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', +}; + +export function assertDebugToken( + symbol: string +): asserts symbol is DebugTokens { + const tokenList = Object.keys(debugTokens); + if (!tokenList.includes(symbol)) { + const msg = `Only use token from this list ${tokenList.join()}, got ${symbol}`; + throw new Error(msg); + } +} + +type DebugTokens = keyof typeof debugTokens; interface RangeOrder { min: string; max: string; budget: string; + // TODO: remove this budgetFiat?: string; } interface LimitOrder { @@ -35,7 +48,7 @@ export const STRATEGY_TYPES = [ export type StrategyType = (typeof STRATEGY_TYPES)[number]; -export interface CreateStrategyTemplate { +export interface CreateStrategyInput { base: DebugTokens; quote: DebugTokens; buy: RangeOrder; @@ -65,12 +78,12 @@ const fromLimitOrder = (order: LimitOrder): RangeOrder => ({ budget: order.budget, }); export const createDebugStrategy = { - limitBuy: (pair: TokenPair, buy: LimitOrder): CreateStrategyTemplate => ({ + limitBuy: (pair: TokenPair, buy: LimitOrder): CreateStrategyInput => ({ ...fromPair(pair), buy: fromLimitOrder(buy), sell: emptyOrder(), }), - limitSell: (pair: TokenPair, sell: LimitOrder): CreateStrategyTemplate => ({ + limitSell: (pair: TokenPair, sell: LimitOrder): CreateStrategyInput => ({ ...fromPair(pair), buy: emptyOrder(), sell: fromLimitOrder(sell), @@ -79,17 +92,17 @@ export const createDebugStrategy = { pair: TokenPair, buy: LimitOrder, sell: LimitOrder - ): CreateStrategyTemplate => ({ + ): CreateStrategyInput => ({ ...fromPair(pair), buy: fromLimitOrder(buy), sell: fromLimitOrder(sell), }), - rangeBuy: (pair: TokenPair, buy: RangeOrder): CreateStrategyTemplate => ({ + rangeBuy: (pair: TokenPair, buy: RangeOrder): CreateStrategyInput => ({ ...fromPair(pair), buy, sell: emptyOrder(), }), - rangeSell: (pair: TokenPair, sell: RangeOrder): CreateStrategyTemplate => ({ + rangeSell: (pair: TokenPair, sell: RangeOrder): CreateStrategyInput => ({ ...fromPair(pair), buy: emptyOrder(), sell, @@ -98,7 +111,7 @@ export const createDebugStrategy = { pair: TokenPair, buy: RangeOrder, sell: RangeOrder - ): CreateStrategyTemplate => ({ + ): CreateStrategyInput => ({ ...fromPair(pair), buy, sell, diff --git a/e2e/utils/types.ts b/e2e/utils/types.ts new file mode 100644 index 000000000..3fac25987 --- /dev/null +++ b/e2e/utils/types.ts @@ -0,0 +1,4 @@ +export type TestCase = { + input: I; + output: O; +}; diff --git a/src/components/core/menu/menuItems.ts b/src/components/core/menu/menuItems.ts index 18435816b..c8afb2837 100644 --- a/src/components/core/menu/menuItems.ts +++ b/src/components/core/menu/menuItems.ts @@ -26,7 +26,7 @@ export const menuItems: MenuItem[] = [ }, { label: 'Explorer', - href: PathNames.explorer('wallet'), + href: PathNames.explorer('token-pair'), hrefMatches: [ PathNames.explorer('wallet'), PathNames.explorer('token-pair'), diff --git a/src/components/strategies/FullOutcome.tsx b/src/components/strategies/FullOutcome.tsx index 0101a0a61..530b2e6e4 100644 --- a/src/components/strategies/FullOutcome.tsx +++ b/src/components/strategies/FullOutcome.tsx @@ -23,12 +23,18 @@ export const FullOutcome: FC = (props) => {

{hasBudgetUpdate && 'Based on updated budget, '} If the order is 100% filled, you will receive  - + {prettifyNumber(amount)}  {token.symbol}  at an average price of  - + {prettifyNumber(mean)}  {props.quote.symbol} diff --git a/src/components/strategies/edit/tooltip/TooltipTokenAmount.tsx b/src/components/strategies/edit/tooltip/TooltipTokenAmount.tsx index 8b14248c3..99166d20e 100644 --- a/src/components/strategies/edit/tooltip/TooltipTokenAmount.tsx +++ b/src/components/strategies/edit/tooltip/TooltipTokenAmount.tsx @@ -2,7 +2,7 @@ import { Tooltip } from 'components/common/tooltip/Tooltip'; import { TokenPrice } from 'components/strategies/overview/strategyBlock/TokenPrice'; import { Token } from 'libs/tokens'; import { FC } from 'react'; -import { cn, prettifyNumber, sanitizeNumber } from 'utils/helpers'; +import { cn, prettifyNumber } from 'utils/helpers'; import { useFiatValue } from 'hooks/useFiatValue'; import { LogoImager } from 'components/common/imager/Imager'; @@ -14,8 +14,11 @@ export interface TooltipPriceProps { export const TooltipTokenAmount: FC = (props) => { const { amount, token, className } = props; - const fiatPrice = useFiatValue({ price: amount, token }); - const fullAmount = sanitizeNumber(amount, token.decimals); + const fiatPrice = useFiatValue({ price: amount, token, highPrecision: true }); + const fullAmount = prettifyNumber(amount, { + highPrecision: true, + decimals: token.decimals, + }); return ( = ({ className, }) => { const { min, max } = range; - const minFiatPrice = useFiatValue({ price: min, token }); - const maxFiatPrice = useFiatValue({ price: max, token }); - const minFullPrice = sanitizeNumber(min, token.decimals); - const maxFullPrice = sanitizeNumber(max, token.decimals); + const options = { decimals: token.decimals, highPrecision: true }; + const minFiatPrice = useFiatValue({ price: min, token, highPrecision: true }); + const maxFiatPrice = useFiatValue({ price: max, token, highPrecision: true }); + const minFullPrice = prettifyNumber(min, options); + const maxFullPrice = prettifyNumber(max, options); return (

diff --git a/src/components/strategies/overlapping/OverlappingStrategyGraph.tsx b/src/components/strategies/overlapping/OverlappingStrategyGraph.tsx index 916ce69f9..fbba7e1b9 100644 --- a/src/components/strategies/overlapping/OverlappingStrategyGraph.tsx +++ b/src/components/strategies/overlapping/OverlappingStrategyGraph.tsx @@ -665,7 +665,7 @@ export const OverlappingStrategyGraph: FC = (props) => { x={price.toString()} {...priceIndicator} > - {prettifySignedNumber(price.div(xFactor))} + {prettifySignedNumber(price.div(xFactor), { abbreviate: true })} ))} diff --git a/src/components/strategies/overview/strategyBlock/StrategyBlockBuySell.tsx b/src/components/strategies/overview/strategyBlock/StrategyBlockBuySell.tsx index ed37bd96f..e6f65be49 100644 --- a/src/components/strategies/overview/strategyBlock/StrategyBlockBuySell.tsx +++ b/src/components/strategies/overview/strategyBlock/StrategyBlockBuySell.tsx @@ -19,9 +19,7 @@ export const StrategyBlockBuySell: FC<{ const active = strategy.status === 'active'; const otherTokenFiat = useFiatCurrency(otherToken); const currency = otherTokenFiat.selectedFiatCurrency; - const prettifiedBudget = prettifyNumber(order.balance, { - abbreviate: order.balance.length > 10, - }); + const prettifiedBudget = prettifyNumber(order.balance, { abbreviate: true }); const hasFiatValue = otherTokenFiat.hasFiatValue(); const fiatBudget = buy ? strategy.fiatBudget.quote : strategy.fiatBudget.base; const fiatBudgetValue = getFiatDisplayValue(fiatBudget, currency); @@ -101,7 +99,7 @@ export const StrategyBlockBuySell: FC<{ src={otherToken.logoURI} alt="token" /> - {order.balance.toString()} + {prettifyNumber(order.balance, { highPrecision: true })} } > diff --git a/src/components/strategies/overview/strategyBlock/StrategyGraph.module.css b/src/components/strategies/overview/strategyBlock/StrategyGraph.module.css index 8b1396b9f..7d2394dbb 100644 --- a/src/components/strategies/overview/strategyBlock/StrategyGraph.module.css +++ b/src/components/strategies/overview/strategyBlock/StrategyGraph.module.css @@ -1,9 +1,8 @@ .strategy-graph { - font-family: GT America; width: 100%; height: unset; aspect-ratio: 400 / 130; - font-size: 12px; /* Used as a ref for rect's width */ + font-size: 16px; /* Used as a ref for rect's width */ } .strategy-graph g.buySellAreas:hover g.buy:not(:hover) { diff --git a/src/components/strategies/overview/strategyBlock/StrategyGraph.tsx b/src/components/strategies/overview/strategyBlock/StrategyGraph.tsx index 6a94ef2af..ef9482a02 100644 --- a/src/components/strategies/overview/strategyBlock/StrategyGraph.tsx +++ b/src/components/strategies/overview/strategyBlock/StrategyGraph.tsx @@ -68,11 +68,10 @@ export const StrategyGraph: FC = ({ strategy }) => { const to = center + delta * 1.25; const pricePoints = [ - from + (1 / 3) * (center - from), - from + (2 / 3) * (center - from), - center, - to - (2 / 3) * (to - center), - to - (1 / 3) * (to - center), + from + (1 / 4) * (center - from), + from + (3 / 4) * (center - from), + to - (3 / 4) * (to - center), + to - (1 / 4) * (to - center), ]; // X position @@ -142,7 +141,7 @@ export const StrategyGraph: FC = ({ strategy }) => { return ( = ({ strategy }) => { y={baseline + 10} dominantBaseline="hanging" textAnchor="middle" - fontSize="12" + fontSize="16" opacity="60%" > {prettifyNumber(point, { abbreviate: true, round: true })} @@ -412,7 +411,7 @@ export const CurrentPrice: FC = ({ // Out of Range const maxChar = Math.max(formattedPrice.length, '(off-scale)'.length); - const outRangeWidth = `${maxChar + 2}ch`; + const outRangeWidth = `${maxChar + 6}ch`; // In Range const inRangeWidth = `${formattedPrice.length + 2}ch`; const baseDelta = `${(formattedPrice.length + 2) / 2}ch`; // 6ch @@ -422,7 +421,6 @@ export const CurrentPrice: FC = ({ const translateStart = `min(${baseDelta}, ${deltaStart}px)`; const translateEnd = `max((${inRangeWidth} / 2) - ${deltaEnd}px, 0px)`; const translateRect = `translateX(calc(-1 * (${translateStart} + ${translateEnd})))`; - const translateText = `translateX(calc(-1 * (${translateStart} + ${translateEnd} - 1.5ch)))`; return ( @@ -448,10 +446,10 @@ export const CurrentPrice: FC = ({ = ({ = ({ x={price} y="6" width={inRangeWidth} - height="20" + height="22" rx="4" style={{ transform: translateRect, @@ -488,13 +486,13 @@ export const CurrentPrice: FC = ({ /> {formattedPrice} @@ -517,10 +515,10 @@ export const CurrentPrice: FC = ({ = ({ = ({ strategy, buy }) => { const order = buy ? strategy.order0 : strategy.order1; const limit = order.startRate === order.endRate; const priceOption = { - abbreviate: order.endRate.length > 10, + abbreviate: true, round: true, + useSubscript: false, }; const startPrice = prettifyNumber(order.startRate, priceOption); const endPrice = prettifyNumber(order.endRate, priceOption); @@ -565,7 +564,7 @@ const OrderTooltip: FC = ({ strategy, buy }) => { const color = buy ? 'text-green' : 'text-red'; return (

@@ -586,7 +585,7 @@ const OrderTooltip: FC = ({ strategy, buy }) => { )} {!limit && ( - +
diff --git a/src/components/strategies/overview/strategyBlock/utils.ts b/src/components/strategies/overview/strategyBlock/utils.ts index bbc1918a3..661f4209e 100644 --- a/src/components/strategies/overview/strategyBlock/utils.ts +++ b/src/components/strategies/overview/strategyBlock/utils.ts @@ -76,12 +76,12 @@ export const getPrice = ({ }: getPriceParams) => { if (prettified) { return `${prettifyNumber(order.startRate, { - abbreviate: order.startRate.length > 10, + abbreviate: true, round: true, })} ${ !limit ? ` - ${prettifyNumber(order.endRate, { - abbreviate: order.endRate.length > 10, + abbreviate: true, round: true, })}` : '' diff --git a/src/components/strategies/portfolio/utils.ts b/src/components/strategies/portfolio/utils.ts index 77c12be4b..2836b2799 100644 --- a/src/components/strategies/portfolio/utils.ts +++ b/src/components/strategies/portfolio/utils.ts @@ -14,10 +14,6 @@ export const buildPercentageString = (percentage: SafeDecimal) => { return `${percentage.toFixed(2)}%`; }; -export const buildAmountString = ( - amount: SafeDecimal, - { symbol }: Token, - highPrecision: boolean = true -) => { - return `${prettifyNumber(amount, { highPrecision })} ${symbol}`; +export const buildAmountString = (amount: SafeDecimal, { symbol }: Token) => { + return `${prettifyNumber(amount)} ${symbol}`; }; diff --git a/src/components/trade/depthChartWidget/useDepthChartWidget.ts b/src/components/trade/depthChartWidget/useDepthChartWidget.ts index b5eb6a467..cdec9f165 100644 --- a/src/components/trade/depthChartWidget/useDepthChartWidget.ts +++ b/src/components/trade/depthChartWidget/useDepthChartWidget.ts @@ -4,6 +4,7 @@ import { useStore } from 'store'; import { Options } from 'libs/charts'; import { OrderRow, useGetOrderBook } from 'libs/queries'; import { Token } from 'libs/tokens'; +import { prettifyNumber } from 'utils/helpers'; export const useDepthChartWidget = (base?: Token, quote?: Token) => { const { @@ -88,8 +89,13 @@ export const useDepthChartWidget = (base?: Token, quote?: Token) => { tickWidth: 0, lineWidth: 0, labels: { + formatter: ({ value }) => { + return prettifyNumber(value, { abbreviate: true }); + }, style: { color: 'rgba(255, 255, 255, 0.6)', + fontFamily: + 'GT America Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace', }, }, crosshair: { @@ -130,8 +136,13 @@ export const useDepthChartWidget = (base?: Token, quote?: Token) => { tickLength: 5, tickPosition: 'inside', labels: { + formatter: ({ value }) => { + return prettifyNumber(value, { abbreviate: true }); + }, style: { color: 'rgba(255, 255, 255, 0.6)', + fontFamily: + 'GT America Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace', }, }, }, @@ -155,7 +166,14 @@ export const useDepthChartWidget = (base?: Token, quote?: Token) => { }, tooltip: { headerFormat: ' ', - pointFormat: `Amount: {point.y} ${base?.symbol}
Price: {point.x} ${quote?.symbol}`, + formatter: function () { + if (typeof this.x !== 'number' || typeof this.y !== 'number') { + return ''; + } + const x = prettifyNumber(this.x, { highPrecision: true }); + const y = prettifyNumber(this.y, { highPrecision: true }); + return `Amount: ${y} ${base?.symbol}
Price: ${x} ${quote?.symbol}`; + }, valueDecimals: undefined, borderRadius: 12, backgroundColor: '#212123', diff --git a/src/components/trade/orderWidget/OrderBookWidgetRate.tsx b/src/components/trade/orderWidget/OrderBookWidgetRate.tsx index e44908ece..a7db012b0 100644 --- a/src/components/trade/orderWidget/OrderBookWidgetRate.tsx +++ b/src/components/trade/orderWidget/OrderBookWidgetRate.tsx @@ -2,6 +2,7 @@ import { FC } from 'react'; import { Tooltip } from 'components/common/tooltip/Tooltip'; import { prettifyNumber } from 'utils/helpers'; import { ReactComponent as IconArrow } from 'assets/icons/arrowDown.svg'; +import { useFiatCurrency } from 'hooks/useFiatCurrency'; type Props = { rate: string; @@ -16,11 +17,12 @@ export const OrderBookWidgetRate: FC = ({ fiatRate, isLoading, }) => { + const { selectedFiatCurrency: currentCurrency } = useFiatCurrency(); return (
- {prettifyNumber(rate)} + {prettifyNumber(rate, { decimals: 6 })} {!isLoading && (
= ({ />
)} - {fiatRate && {fiatRate}} + {fiatRate && ( + + {prettifyNumber(fiatRate, { decimals: 6, currentCurrency })} + + )}
diff --git a/src/components/trade/orderWidget/OrderBookWidgetRow.tsx b/src/components/trade/orderWidget/OrderBookWidgetRow.tsx index 1b8b1cc08..1a31da703 100644 --- a/src/components/trade/orderWidget/OrderBookWidgetRow.tsx +++ b/src/components/trade/orderWidget/OrderBookWidgetRow.tsx @@ -18,25 +18,34 @@ export const OrderBookWidgetRow: FC = ({ base, quote, }) => { + const baseOptions = { highPrecision: true, decimals: base.decimals }; + const quoteOptions = { highPrecision: true, decimals: quote.decimals }; + const rowOptions = { decimals: 6 }; return ( <>
- - {prettifyNumber(rate, { highPrecision: true })} + + {prettifyNumber(rate, rowOptions)}
-
- - {prettifyNumber(amount, { highPrecision: true })} +
+ + {prettifyNumber(amount, rowOptions)}
-
- - {prettifyNumber(total, { highPrecision: true })} +
+ + {prettifyNumber(total, rowOptions)}
diff --git a/src/components/trade/orderWidget/useOrderBookWidget.ts b/src/components/trade/orderWidget/useOrderBookWidget.ts index 478226c0a..63f4b5569 100644 --- a/src/components/trade/orderWidget/useOrderBookWidget.ts +++ b/src/components/trade/orderWidget/useOrderBookWidget.ts @@ -38,25 +38,15 @@ const _subtractPrevAmount = ( }; }; -const buildOrders = ( - data: OrderRow[], - baseDecimals: number, - quoteDecimals: number, - buckets: number -): OrderRow[] => { +const buildOrders = (data: OrderRow[], buckets: number): OrderRow[] => { return data - .map(({ amount, rate, total }, i) => - _subtractPrevAmount(data, amount, rate, total, i) - ) - .filter(({ amount }) => - new SafeDecimal(amount).gte(ROW_AMOUNT_MIN_THRESHOLD) - ) - .splice(0, buckets) - .map(({ amount, rate, total }) => ({ - rate: new SafeDecimal(rate).toFixed(quoteDecimals, 1), - amount: new SafeDecimal(amount).toFixed(baseDecimals, 1), - total: new SafeDecimal(total).toFixed(quoteDecimals, 1), - })); + .map(({ amount, rate, total }, i) => { + return _subtractPrevAmount(data, amount, rate, total, i); + }) + .filter(({ amount }) => { + return new SafeDecimal(amount).gte(ROW_AMOUNT_MIN_THRESHOLD); + }) + .splice(0, buckets); }; export const useOrderBookWidget = (base?: string, quote?: string) => { @@ -70,31 +60,20 @@ export const useOrderBookWidget = (base?: string, quote?: string) => { const { getTokenById } = useTokens(); const { data } = orderBookQuery; - const baseToken = getTokenById(base!); - const baseDecimals = baseToken?.decimals || 0; const quoteToken = getTokenById(quote!); - const quoteDecimals = quoteToken?.decimals || 0; - const { getFiatAsString } = useFiatCurrency(quoteToken); + const { getFiatValue } = useFiatCurrency(quoteToken); const orders = useMemo(() => { const buy = orderBy(data?.buy || [], ({ rate }) => +rate, 'desc'); const sell = orderBy(data?.sell || [], ({ rate }) => +rate, 'asc'); return { - buy: buildOrders(buy, baseDecimals, quoteDecimals, orderBookBuckets), - sell: buildOrders(sell, baseDecimals, quoteDecimals, orderBookBuckets), + buy: buildOrders(buy, orderBookBuckets), + sell: buildOrders(sell, orderBookBuckets), middleRate: data?.middleRate || '0', - middleRateFiat: getFiatAsString(data?.middleRate || ''), + middleRateFiat: getFiatValue(data?.middleRate || '').toString(), }; - }, [ - baseDecimals, - data?.buy, - data?.middleRate, - data?.sell, - getFiatAsString, - orderBookBuckets, - quoteDecimals, - ]); + }, [data?.buy, data?.middleRate, data?.sell, getFiatValue, orderBookBuckets]); return { ...orderBookQuery, diff --git a/src/components/trade/tradeWidget/TradeWidgetBuySell.tsx b/src/components/trade/tradeWidget/TradeWidgetBuySell.tsx index 7c4e96ee8..6c1b1fe3c 100644 --- a/src/components/trade/tradeWidget/TradeWidgetBuySell.tsx +++ b/src/components/trade/tradeWidget/TradeWidgetBuySell.tsx @@ -156,12 +156,12 @@ export const TradeWidgetBuySell = (props: TradeWidgetBuySellProps) => { if (buy) { return `1 ${target.symbol} = ${ rate && rate !== '0' - ? prettifyNumber(new SafeDecimal(1).div(rate)) + ? prettifyNumber(new SafeDecimal(1).div(rate), { decimals: 6 }) : '--' } ${source.symbol}`; } return `1 ${source.symbol} = - ${rate ? prettifyNumber(rate) : '--'} + ${rate ? prettifyNumber(rate, { decimals: 6 }) : '--'} ${target.symbol}`; }; diff --git a/src/hooks/useFiatValue.ts b/src/hooks/useFiatValue.ts index 013f4db4d..e827f5afe 100644 --- a/src/hooks/useFiatValue.ts +++ b/src/hooks/useFiatValue.ts @@ -1,17 +1,22 @@ import { SafeDecimal } from 'libs/safedecimal'; import { useFiatCurrency } from './useFiatCurrency'; import { Token } from 'libs/tokens'; -import { getFiatDisplayValue } from 'utils/helpers'; +import { prettifyNumber } from 'utils/helpers'; interface FiatValueParams { token: Token; price?: string; + highPrecision?: boolean; } -export const useFiatValue = ({ price, token }: FiatValueParams) => { +export const useFiatValue = (params: FiatValueParams) => { + const { price, token, highPrecision } = params; const { selectedFiatCurrency, useGetTokenPrice } = useFiatCurrency(); const { data: fiatPriceMap } = useGetTokenPrice(token.address); const fiatPrice = fiatPriceMap?.[selectedFiatCurrency] || 0; const value = new SafeDecimal(price || 0).times(fiatPrice); - return getFiatDisplayValue(value, selectedFiatCurrency); + return prettifyNumber(value, { + currentCurrency: selectedFiatCurrency, + highPrecision, + }); }; diff --git a/src/libs/modals/Modal.tsx b/src/libs/modals/Modal.tsx index 76ef9bab4..29da35edc 100644 --- a/src/libs/modals/Modal.tsx +++ b/src/libs/modals/Modal.tsx @@ -51,7 +51,7 @@ export const Modal: FC = ({ >
{isLoading && (
diff --git a/src/libs/modals/modals/ModalImportToken.tsx b/src/libs/modals/modals/ModalImportToken.tsx index d5b2de5cb..69f5aaa83 100644 --- a/src/libs/modals/modals/ModalImportToken.tsx +++ b/src/libs/modals/modals/ModalImportToken.tsx @@ -47,7 +47,7 @@ export const ModalImportToken: ModalFC = ({
{isLoading && ( -
+
)} {isError && (
= ({ > Import Token - diff --git a/src/libs/modals/modals/ModalTokenList/ModalTokenListContent.tsx b/src/libs/modals/modals/ModalTokenList/ModalTokenListContent.tsx index 735b24f82..9b7276680 100644 --- a/src/libs/modals/modals/ModalTokenList/ModalTokenListContent.tsx +++ b/src/libs/modals/modals/ModalTokenList/ModalTokenListContent.tsx @@ -110,7 +110,7 @@ export const ModalTokenListContent: FC = ({