diff --git a/.env b/.env deleted file mode 100644 index 499111b5ae..0000000000 --- a/.env +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLE_WALLET_LOGO_URL = https://templewallet.com/logo.png -TEMPLE_WALLET_SEGMENT_WRITE_KEY = N1pFDJgp6ZJ6s5zfTM0cDhUWWhnE1TkS -TEMPLE_WALLET_EXOLIX_API_KEY = -TEMPLE_WALLET_EVERSTAKE_API_KEY = -TEMPLE_WALLET_EVERSTAKE_LINK_ID = -TEMPLE_WALLET_UTORG_SID = diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000000..e4bd9bc71a --- /dev/null +++ b/.env.dist @@ -0,0 +1,10 @@ +TEMPLE_WALLET_SEGMENT_WRITE_KEY=N1pFDJgp6ZJ6s5zfTM0cDhUWWhnE1TkS + +TEMPLE_WALLET_EXOLIX_API_KEY= +TEMPLE_WALLET_EVERSTAKE_API_KEY= +TEMPLE_WALLET_EVERSTAKE_LINK_ID= +TEMPLE_WALLET_UTORG_SID= + +TEMPLE_WALLET_API_URL=https://temple-api-mainnet.prod.templewallet.com +TEMPLE_WALLET_METADATA_API_URL=https://metadata-api-mainnet.prod.templewallet.com +TEMPLE_WALLET_DEXES_API_URL=wss://dexes-api-mainnet.prod.templewallet.com diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 126e70aa3a..df483f6f81 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -6,26 +6,19 @@ on: - master - development -env: - TEMPLE_WALLET_SEGMENT_WRITE_KEY: ${{ secrets.TEMPLE_WALLET_SEGMENT_WRITE_KEY }} - TEMPLE_WALLET_EXOLIX_API_KEY: ${{ secrets.TEMPLE_WALLET_EXOLIX_API_KEY }} - TEMPLE_WALLET_EVERSTAKE_API_KEY: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_API_KEY }} - TEMPLE_WALLET_EVERSTAKE_LINK_ID: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_LINK_ID }} - TEMPLE_WALLET_UTORG_SID: ${{ secrets.TEMPLE_WALLET_UTORG_SID }} - jobs: pull-request-check: name: Checks if ts, lint, tests & build work runs-on: ubuntu-latest - environment: production + environment: development steps: - name: Clone repository uses: actions/checkout@v2 - - name: Use Node 14.x - uses: actions/setup-node@v2 + - name: Use Node 16.x + uses: actions/setup-node@v3 with: - node-version: '14.x' + node-version: '16.x' - name: Get yarn cache directory path id: yarn-cache-dir-path @@ -39,6 +32,21 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- + - name: Secrets setup + uses: ./.github/workflows/secrets-setup + with: + TEMPLE_WALLET_SEGMENT_WRITE_KEY: ${{ secrets.TEMPLE_WALLET_SEGMENT_WRITE_KEY }} + TEMPLE_WALLET_EXOLIX_API_KEY: ${{ secrets.TEMPLE_WALLET_EXOLIX_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_API_KEY: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_LINK_ID: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_LINK_ID }} + TEMPLE_WALLET_UTORG_SID: ${{ secrets.TEMPLE_WALLET_UTORG_SID }} + TEMPLE_WALLET_API_URL: ${{ vars.TEMPLE_WALLET_API_URL }} + TEMPLE_WALLET_METADATA_API_URL: ${{ vars.TEMPLE_WALLET_METADATA_API_URL }} + TEMPLE_WALLET_DEXES_API_URL: ${{ vars.TEMPLE_WALLET_DEXES_API_URL }} + DEFAULT_SEED_PHRASE: ${{ secrets.DEFAULT_SEED_PHRASE }} + DEFAULT_PASSWORD: ${{ secrets.DEFAULT_PASSWORD }} + DEFAULT_HD_ACCOUNT_PRIVATE_KEY: ${{ secrets.DEFAULT_HD_ACCOUNT_PRIVATE_KEY }} + - name: Install dependencies and code quality check uses: ./.github/workflows/code-quality-check @@ -47,10 +55,6 @@ jobs: - name: Perform end-to-end tests uses: ./.github/workflows/e2e - with: - DEFAULT_SEED_PHRASE: ${{ secrets.DEFAULT_SEED_PHRASE }} - DEFAULT_PASSWORD: ${{ secrets.DEFAULT_PASSWORD }} - DEFAULT_HD_ACCOUNT_PRIVATE_KEY: ${{ secrets.DEFAULT_HD_ACCOUNT_PRIVATE_KEY }} - name: Upload artifact uses: actions/upload-artifact@v2 diff --git a/.github/workflows/e2e/action.yml b/.github/workflows/e2e/action.yml index 451cc35111..57e00fcc07 100644 --- a/.github/workflows/e2e/action.yml +++ b/.github/workflows/e2e/action.yml @@ -2,14 +2,6 @@ name: End-to-end tests description: Prepares and runs e2e tests -inputs: - DEFAULT_SEED_PHRASE: - required: true - DEFAULT_PASSWORD: - required: true - DEFAULT_HD_ACCOUNT_PRIVATE_KEY: - required: true - runs: using: 'composite' steps: @@ -17,16 +9,6 @@ runs: shell: bash run: yarn install - - name: Secrets setup - working-directory: ./e2e - shell: bash - run: | - cat << EOF > .env - DEFAULT_SEED_PHRASE=${{ inputs.DEFAULT_SEED_PHRASE }} - DEFAULT_PASSWORD=${{ inputs.DEFAULT_PASSWORD }} - DEFAULT_HD_ACCOUNT_PRIVATE_KEY=${{ inputs.DEFAULT_HD_ACCOUNT_PRIVATE_KEY }} - EOF - - name: Run tests working-directory: ./e2e shell: bash diff --git a/.github/workflows/manual-builds.yml b/.github/workflows/manual-builds.yml index 5e995311e9..de27848b96 100644 --- a/.github/workflows/manual-builds.yml +++ b/.github/workflows/manual-builds.yml @@ -12,26 +12,19 @@ on: description: Firefox build required: false -env: - TEMPLE_WALLET_SEGMENT_WRITE_KEY: ${{ secrets.TEMPLE_WALLET_SEGMENT_WRITE_KEY }} - TEMPLE_WALLET_EXOLIX_API_KEY: ${{ secrets.TEMPLE_WALLET_EXOLIX_API_KEY }} - TEMPLE_WALLET_EVERSTAKE_API_KEY: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_API_KEY }} - TEMPLE_WALLET_EVERSTAKE_LINK_ID: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_LINK_ID }} - TEMPLE_WALLET_UTORG_SID: ${{ secrets.TEMPLE_WALLET_UTORG_SID }} - jobs: additional-builds: name: Creates builds for a specific browsers runs-on: ubuntu-latest - environment: production + environment: development steps: - name: Clone repository uses: actions/checkout@v2 - - name: Use Node 14.x - uses: actions/setup-node@v2 + - name: Use Node 16.x + uses: actions/setup-node@v3 with: - node-version: '14.x' + node-version: '16.x' - name: Get yarn cache directory path id: yarn-cache-dir-path @@ -45,6 +38,18 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- + - name: Secrets setup + uses: ./.github/workflows/secrets-setup + with: + TEMPLE_WALLET_SEGMENT_WRITE_KEY: ${{ secrets.TEMPLE_WALLET_SEGMENT_WRITE_KEY }} + TEMPLE_WALLET_EXOLIX_API_KEY: ${{ secrets.TEMPLE_WALLET_EXOLIX_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_API_KEY: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_LINK_ID: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_LINK_ID }} + TEMPLE_WALLET_UTORG_SID: ${{ secrets.TEMPLE_WALLET_UTORG_SID }} + TEMPLE_WALLET_API_URL: ${{ vars.TEMPLE_WALLET_API_URL }} + TEMPLE_WALLET_METADATA_API_URL: ${{ vars.TEMPLE_WALLET_METADATA_API_URL }} + TEMPLE_WALLET_DEXES_API_URL: ${{ vars.TEMPLE_WALLET_DEXES_API_URL }} + - name: Install dependencies and code quality uses: ./.github/workflows/code-quality-check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b89ddd50fe..9dd682fe8c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,12 +5,6 @@ on: tags: - '*' -env: - TEMPLE_WALLET_SEGMENT_WRITE_KEY: ${{ secrets.TEMPLE_WALLET_SEGMENT_WRITE_KEY }} - TEMPLE_WALLET_EXOLIX_API_KEY: ${{ secrets.TEMPLE_WALLET_EXOLIX_API_KEY }} - TEMPLE_WALLET_EVERSTAKE_API_KEY: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_API_KEY }} - TEMPLE_WALLET_UTORG_SID: ${{ secrets.TEMPLE_WALLET_UTORG_SID }} - jobs: create-release: name: Uploads release assets, generates changelogs @@ -22,10 +16,10 @@ jobs: with: ref: master - - name: Use Node 14.x - uses: actions/setup-node@v2 + - name: Use Node 16.x + uses: actions/setup-node@v3 with: - node-version: '14.x' + node-version: '16.x' - name: Get yarn cache directory path id: yarn-cache-dir-path @@ -39,6 +33,18 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- + - name: Secrets setup + uses: ./.github/workflows/secrets-setup + with: + TEMPLE_WALLET_SEGMENT_WRITE_KEY: ${{ secrets.TEMPLE_WALLET_SEGMENT_WRITE_KEY }} + TEMPLE_WALLET_EXOLIX_API_KEY: ${{ secrets.TEMPLE_WALLET_EXOLIX_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_API_KEY: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_LINK_ID: ${{ secrets.TEMPLE_WALLET_EVERSTAKE_LINK_ID }} + TEMPLE_WALLET_UTORG_SID: ${{ secrets.TEMPLE_WALLET_UTORG_SID }} + TEMPLE_WALLET_API_URL: ${{ vars.TEMPLE_WALLET_API_URL }} + TEMPLE_WALLET_METADATA_API_URL: ${{ vars.TEMPLE_WALLET_METADATA_API_URL }} + TEMPLE_WALLET_DEXES_API_URL: ${{ vars.TEMPLE_WALLET_DEXES_API_URL }} + - name: Install dependencies and code quality uses: ./.github/workflows/code-quality-check diff --git a/.github/workflows/secrets-setup/action.yml b/.github/workflows/secrets-setup/action.yml new file mode 100644 index 0000000000..c089fe33c5 --- /dev/null +++ b/.github/workflows/secrets-setup/action.yml @@ -0,0 +1,55 @@ +name: Secrets setup + +description: Writes secrets + +inputs: + TEMPLE_WALLET_SEGMENT_WRITE_KEY: + required: true + TEMPLE_WALLET_EXOLIX_API_KEY: + required: false + TEMPLE_WALLET_EVERSTAKE_API_KEY: + required: false + TEMPLE_WALLET_EVERSTAKE_LINK_ID: + required: false + TEMPLE_WALLET_UTORG_SID: + required: false + TEMPLE_WALLET_API_URL: + required: true + TEMPLE_WALLET_METADATA_API_URL: + required: true + TEMPLE_WALLET_DEXES_API_URL: + required: true + DEFAULT_SEED_PHRASE: + required: false + DEFAULT_PASSWORD: + required: false + DEFAULT_HD_ACCOUNT_PRIVATE_KEY: + required: false + +runs: + using: 'composite' + steps: + - name: Create .env file + shell: bash + run: | + cat << EOF > .env + TEMPLE_WALLET_SEGMENT_WRITE_KEY=${{ inputs.TEMPLE_WALLET_SEGMENT_WRITE_KEY }} + + TEMPLE_WALLET_EXOLIX_API_KEY=${{ inputs.TEMPLE_WALLET_EXOLIX_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_API_KEY=${{ inputs.TEMPLE_WALLET_EVERSTAKE_API_KEY }} + TEMPLE_WALLET_EVERSTAKE_LINK_ID=${{ inputs.TEMPLE_WALLET_EVERSTAKE_LINK_ID }} + TEMPLE_WALLET_UTORG_SID=${{ inputs.TEMPLE_WALLET_UTORG_SID }} + + TEMPLE_WALLET_API_URL=${{ inputs.TEMPLE_WALLET_API_URL }} + TEMPLE_WALLET_METADATA_API_URL=${{ inputs.TEMPLE_WALLET_METADATA_API_URL }} + TEMPLE_WALLET_DEXES_API_URL=${{ inputs.TEMPLE_WALLET_DEXES_API_URL }} + EOF + + - name: Create e2e/.env file + shell: bash + run: | + cat << EOF > e2e/.env + DEFAULT_SEED_PHRASE=${{ inputs.DEFAULT_SEED_PHRASE }} + DEFAULT_PASSWORD=${{ inputs.DEFAULT_PASSWORD }} + DEFAULT_HD_ACCOUNT_PRIVATE_KEY=${{ inputs.DEFAULT_HD_ACCOUNT_PRIVATE_KEY }} + EOF diff --git a/README.md b/README.md index b8c6f2001f..deeb74eea2 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,11 @@ git clone https://github.com/madfish-solutions/templewallet-extension && cd temp yarn ``` -### 3) Build +### 3) Create `.env` file + +Make copy of `.env.dist` and do changes if needed. + +### 4) Build Builds the extension for production to the `dist` folder.
It correctly bundles in production mode and optimizes the build for the best performance. @@ -62,7 +66,7 @@ yarn build:opera yarn build-all ``` -### 4) Load extension to your Browser +### 5) Load extension to your Browser ![TempleWallet_Load](https://user-images.githubusercontent.com/11996139/73763346-f8435a80-4779-11ea-9e9d-4c1db9560f64.gif) diff --git a/e2e/package.json b/e2e/package.json index f5d0bdab9b..30a5968a47 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -11,8 +11,11 @@ }, "dependencies": { "@cucumber/cucumber": "^8.7.0", + "async-retry": "^1.3.3", "puppeteer": "^19.4.0", "ts-node": "^10.9.1", - "dotenv": "^16.0.3" + "dotenv": "^16.0.3", + "@types/chai": "^4.3.4", + "chai": "^4.3.7" } } diff --git a/e2e/src/classes/browser-context.class.ts b/e2e/src/classes/browser-context.class.ts index c9e5db1838..9c11e12efe 100644 --- a/e2e/src/classes/browser-context.class.ts +++ b/e2e/src/classes/browser-context.class.ts @@ -8,8 +8,10 @@ const defaultPrivateKey = getEnv('DEFAULT_HD_ACCOUNT_PRIVATE_KEY'); if (!defaultSeedPhrase) throw new Error('process.env.DEFAULT_SEED_PHRASE not found.'); if (!defaultPassword) throw new Error('process.env.DEFAULT_PASSWORD not found.'); +if (!defaultPrivateKey) throw new Error('process.env.DEFAULT_PASSWORD not found.'); export class BrowserContext { + public static EXTENSION_ID: string; public static browser: Browser; public static page: Page; public static seedPhrase = defaultSeedPhrase; diff --git a/e2e/src/features/import-existing-wallet.feature b/e2e/src/features/import-existing-wallet.feature index a9018292a5..061ec17342 100644 --- a/e2e/src/features/import-existing-wallet.feature +++ b/e2e/src/features/import-existing-wallet.feature @@ -1,5 +1,4 @@ Feature: Import existing wallet - @dev Scenario: As a user, I'd like to import account with existing seed phrase Given I am on the Welcome page And I press Import Existing Wallet button on the Welcome page diff --git a/e2e/src/features/reveal-private-key.feature b/e2e/src/features/reveal-private-key.feature new file mode 100644 index 0000000000..e6f59c1c23 --- /dev/null +++ b/e2e/src/features/reveal-private-key.feature @@ -0,0 +1,17 @@ +Feature: Reveal private key +@dev + Scenario: As a user, I'd like to reveal my seed phrase + Given I have imported an existing account + + And I press AccountIcon on the Header page + And I am on the AccountsDropdown page + And I press SettingsButton on the AccountsDropdown page + + And I am on the Settings page + And I press RevealPrivateKeyButton on the Settings page + + And I am on the RevealSecrets page + And I enter password into Reveal Password Field on the RevealSecrets page + And I press Reveal Button on the RevealSecrets page + And I compare my Private Key to Revealed value + diff --git a/e2e/src/features/reveal-seed-phrase.feature b/e2e/src/features/reveal-seed-phrase.feature new file mode 100644 index 0000000000..cf575ec731 --- /dev/null +++ b/e2e/src/features/reveal-seed-phrase.feature @@ -0,0 +1,17 @@ +Feature: Reveal seed phrase + + Scenario: As a user, I'd like to reveal my seed phrase + Given I have imported an existing account + + And I press AccountIcon on the Header page + And I am on the AccountsDropdown page + And I press SettingsButton on the AccountsDropdown page + + And I am on the Settings page + And I press RevealSeedPhraseButton on the Settings page + + And I am on the RevealSecrets page + And I enter password into Reveal Password Field on the RevealSecrets page + And I press Reveal Button on the RevealSecrets page + And I compare my Seed Phrase to Revealed value + diff --git a/e2e/src/hooks/after-all.hook.ts b/e2e/src/hooks/after-all.hook.ts deleted file mode 100644 index 302c81b423..0000000000 --- a/e2e/src/hooks/after-all.hook.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AfterAll } from '@cucumber/cucumber'; - -import { BrowserContext } from '../classes/browser-context.class'; - -AfterAll(async () => { - await BrowserContext.browser.close(); -}); diff --git a/e2e/src/hooks/after.hook.ts b/e2e/src/hooks/after.hook.ts new file mode 100644 index 0000000000..a325d9b9e8 --- /dev/null +++ b/e2e/src/hooks/after.hook.ts @@ -0,0 +1,28 @@ +import { After } from '@cucumber/cucumber'; +import retry from 'async-retry'; + +import { E2eMessageType } from '../../../src/lib/e2e/types'; +import { BrowserContext } from '../classes/browser-context.class'; +import { MEDIUM_TIMEOUT, RETRY_OPTIONS } from '../utils/timing.utils'; + +const FAILED_RESET_ERROR = new Error('Failed to reset extension'); + +After({ timeout: MEDIUM_TIMEOUT }, async () => { + // [ Extension storages full reset ] + + await BrowserContext.page.evaluate( + // @ts-ignore + message => new Promise(res => chrome.runtime.sendMessage(message, res)), + { type: E2eMessageType.ResetRequest } + ); + await BrowserContext.page.evaluate(() => void localStorage.clear()); + + // [ Extension reload ] + + // @ts-ignore + await BrowserContext.page.evaluate(() => void chrome.runtime.reload()).catch(() => void 0); + + await retry(() => { + if (BrowserContext.page.isClosed() === false) throw FAILED_RESET_ERROR; + }, RETRY_OPTIONS); +}); diff --git a/e2e/src/hooks/before-all.hook.ts b/e2e/src/hooks/before-all.hook.ts index b551f5ea2c..d31224b3cf 100644 --- a/e2e/src/hooks/before-all.hook.ts +++ b/e2e/src/hooks/before-all.hook.ts @@ -2,14 +2,10 @@ import { BeforeAll } from '@cucumber/cucumber'; import { initBrowserContext } from '../utils/browser-context.utils'; import { initBrowser } from '../utils/browser.utils'; +import { LONG_TIMEOUT } from '../utils/timing.utils'; -const LONG_TIMEOUT = 20 * 1000; BeforeAll({ timeout: LONG_TIMEOUT }, async () => { const browser = await initBrowser(); - const [blankPage] = await browser.pages(); - await blankPage.goto('https://www.google.com/'); - await blankPage.close(); - await initBrowserContext(browser); }); diff --git a/e2e/src/hooks/before.hook.ts b/e2e/src/hooks/before.hook.ts index 7857b0a91f..33918ab939 100644 --- a/e2e/src/hooks/before.hook.ts +++ b/e2e/src/hooks/before.hook.ts @@ -1,8 +1,25 @@ import { Before } from '@cucumber/cucumber'; +import retry from 'async-retry'; import { BrowserContext } from '../classes/browser-context.class'; +import { MEDIUM_TIMEOUT, RETRY_OPTIONS } from '../utils/timing.utils'; -Before(async () => { - await BrowserContext.page.evaluate(() => void localStorage.clear()); - await BrowserContext.page.reload(); +Before({ timeout: MEDIUM_TIMEOUT }, async () => { + await BrowserContext.page.close().catch(() => void 0); + + const url = `chrome-extension://${BrowserContext.EXTENSION_ID}/fullpage.html`; + + const page = await retry(async () => { + const page = await BrowserContext.browser.newPage(); + try { + const response = await page.goto(url); + if (response == null || !response.ok) throw new Error('Failed to open page'); + return page; + } catch (error) { + await page.close(); + throw error; + } + }, RETRY_OPTIONS); + + BrowserContext.page = page; }); diff --git a/e2e/src/page-objects/index.ts b/e2e/src/page-objects/index.ts index 0f488faf20..b61fcc0512 100644 --- a/e2e/src/page-objects/index.ts +++ b/e2e/src/page-objects/index.ts @@ -1,5 +1,8 @@ +import { AccountsDropdown } from './pages/drop-down-lists/accounts.drop-down'; import { HeaderPage } from './pages/header.page'; import { ImportExistingWalletPage } from './pages/importing-existing-wallet.page'; +import { RevealSecretsPage } from './pages/reveal-secrets.page'; +import { SettingsPage } from './pages/settings.page'; import { setWalletPage } from './pages/setWalletPassword.page'; import { WelcomePage } from './pages/welcome.page'; @@ -7,5 +10,8 @@ export const Pages = { Welcome: new WelcomePage(), ImportExistingWallet: new ImportExistingWalletPage(), SetWallet: new setWalletPage(), - Header: new HeaderPage() + Header: new HeaderPage(), + AccountsDropdown: new AccountsDropdown(), + Settings: new SettingsPage(), + RevealSecrets: new RevealSecretsPage() }; diff --git a/e2e/src/page-objects/pages/drop-down-lists/accounts.drop-down.ts b/e2e/src/page-objects/pages/drop-down-lists/accounts.drop-down.ts new file mode 100644 index 0000000000..d4f1a2ee24 --- /dev/null +++ b/e2e/src/page-objects/pages/drop-down-lists/accounts.drop-down.ts @@ -0,0 +1,23 @@ +import { AccountDropdownSelectors } from '../../../../../src/app/layouts/PageLayout/Header/AccountDropdown.selectors'; +import { Page } from '../../../classes/page.class'; +import { createPageElement } from '../../../utils/search.utils'; + +export class AccountsDropdown extends Page { + accountItemButton = createPageElement(AccountDropdownSelectors.AccountItemButton); + logoutButton = createPageElement(AccountDropdownSelectors.LogoutButton); + createOrRestoreAccountButton = createPageElement(AccountDropdownSelectors.CreateOrRestoreAccountButton); + importAccountButton = createPageElement(AccountDropdownSelectors.ImportAccountButton); + connectLedgerButton = createPageElement(AccountDropdownSelectors.ConnectLedgerButton); + dappsButton = createPageElement(AccountDropdownSelectors.DAppsButton); + settingsButton = createPageElement(AccountDropdownSelectors.SettingsButton); + + async isVisible() { + await this.accountItemButton.waitForDisplayed(); + await this.logoutButton.waitForDisplayed(); + await this.createOrRestoreAccountButton.waitForDisplayed(); + await this.importAccountButton.waitForDisplayed(); + await this.connectLedgerButton.waitForDisplayed(); + await this.dappsButton.waitForDisplayed(); + await this.settingsButton.waitForDisplayed(); + } +} diff --git a/e2e/src/page-objects/pages/reveal-secrets.page.ts b/e2e/src/page-objects/pages/reveal-secrets.page.ts new file mode 100644 index 0000000000..25f0d64a90 --- /dev/null +++ b/e2e/src/page-objects/pages/reveal-secrets.page.ts @@ -0,0 +1,14 @@ +import { RevealSecretsTestIDS } from '../../../../src/app/templates/RevealSecrets/RevealSecrets.test-ids'; +import { Page } from '../../classes/page.class'; +import { createPageElement } from '../../utils/search.utils'; + +export class RevealSecretsPage extends Page { + revealButton = createPageElement(RevealSecretsTestIDS.RevealButton); + revealPasswordField = createPageElement(RevealSecretsTestIDS.RevealPasswordField); + revealSecretsValue = createPageElement(RevealSecretsTestIDS.RevealSecretsValue); + + async isVisible() { + await this.revealButton.waitForDisplayed(); + await this.revealPasswordField.waitForDisplayed(); + } +} diff --git a/e2e/src/page-objects/pages/settings.page.ts b/e2e/src/page-objects/pages/settings.page.ts new file mode 100644 index 0000000000..b876a5ff25 --- /dev/null +++ b/e2e/src/page-objects/pages/settings.page.ts @@ -0,0 +1,29 @@ +import { SettingsSelectors } from '../../../../src/app/pages/Settings.selectors'; +import { Page } from '../../classes/page.class'; +import { createPageElement } from '../../utils/search.utils'; + +export class SettingsPage extends Page { + generalButton = createPageElement(SettingsSelectors.GeneralButton); + synchronizationButton = createPageElement(SettingsSelectors.SynchronizationButton); + addressBookButton = createPageElement(SettingsSelectors.AddressBookButton); + revealPrivateKeyButton = createPageElement(SettingsSelectors.RevealPrivateKeyButton); + revealSeedPhraseButton = createPageElement(SettingsSelectors.RevealSeedPhraseButton); + dappsButton = createPageElement(SettingsSelectors.DAppsButton); + networksButton = createPageElement(SettingsSelectors.NetworksButton); + activateAccountButton = createPageElement(SettingsSelectors.ActivateAccountButton); + removeAccountButton = createPageElement(SettingsSelectors.RemoveAccountButton); + aboutButton = createPageElement(SettingsSelectors.AboutButton); + + async isVisible() { + await this.generalButton.waitForDisplayed(); + await this.synchronizationButton.waitForDisplayed(); + await this.addressBookButton.waitForDisplayed(); + await this.revealPrivateKeyButton.waitForDisplayed(); + await this.revealSeedPhraseButton.waitForDisplayed(); + await this.dappsButton.waitForDisplayed(); + await this.networksButton.waitForDisplayed(); + await this.activateAccountButton.waitForDisplayed(); + await this.removeAccountButton.waitForDisplayed(); + await this.aboutButton.waitForDisplayed(); + } +} diff --git a/e2e/src/step-definitions/common.steps.ts b/e2e/src/step-definitions/common.steps.ts index fba0ebc7df..9897f6ec1e 100644 --- a/e2e/src/step-definitions/common.steps.ts +++ b/e2e/src/step-definitions/common.steps.ts @@ -1,9 +1,11 @@ import { Given } from '@cucumber/cucumber'; +import { BrowserContext } from '../classes/browser-context.class'; import { Pages } from '../page-objects'; import { getInputText } from '../utils/input.utils'; import { createPageElement } from '../utils/search.utils'; import { enterMyMnemonicStep } from '../utils/shared-steps.utils'; +import { LONG_TIMEOUT } from '../utils/timing.utils'; Given(/^I am on the (\w+) page$/, async (page: keyof typeof Pages) => { await Pages[page].isVisible(); @@ -25,3 +27,21 @@ Given( await createPageElement(`${pageName}/${elementName}`).type(inputText); } ); + +Given(/I have imported an existing account/, { timeout: LONG_TIMEOUT }, async () => { + await Pages.Welcome.isVisible(); + await Pages.Welcome.importExistingWalletButton.click(); + + await Pages.ImportExistingWallet.isVisible(); + await enterMyMnemonicStep(); + await Pages.ImportExistingWallet.nextButton.click(); + + await Pages.SetWallet.isVisible(); + await Pages.SetWallet.passwordField.type(BrowserContext.password); + await Pages.SetWallet.repeatPasswordField.type(BrowserContext.password); + await Pages.SetWallet.skipOnboarding.click(); + await Pages.SetWallet.acceptTerms.click(); + await Pages.SetWallet.importButton.click(); + + await Pages.Header.isVisible(); +}); diff --git a/e2e/src/step-definitions/reveal-private-key.steps.ts b/e2e/src/step-definitions/reveal-private-key.steps.ts new file mode 100644 index 0000000000..44a273185c --- /dev/null +++ b/e2e/src/step-definitions/reveal-private-key.steps.ts @@ -0,0 +1,11 @@ +import { Given } from '@cucumber/cucumber'; +import { expect } from 'chai'; + +import { BrowserContext } from '../classes/browser-context.class'; +import { Pages } from '../page-objects'; + +Given(/I compare my Private Key to Revealed value/, async () => { + const revealedSecretsValue = await Pages.RevealSecrets.revealSecretsValue.getText(); + + expect(revealedSecretsValue).eql(BrowserContext.privateKey); +}); diff --git a/e2e/src/step-definitions/reveal-seed-phrase.steps.ts b/e2e/src/step-definitions/reveal-seed-phrase.steps.ts new file mode 100644 index 0000000000..ffdb878710 --- /dev/null +++ b/e2e/src/step-definitions/reveal-seed-phrase.steps.ts @@ -0,0 +1,11 @@ +import { Given } from '@cucumber/cucumber'; +import { expect } from 'chai'; + +import { BrowserContext } from '../classes/browser-context.class'; +import { Pages } from '../page-objects'; + +Given(/I compare my Seed Phrase to Revealed value/, async () => { + const revealedSecretsValue = await Pages.RevealSecrets.revealSecretsValue.getText(); + + expect(revealedSecretsValue).eql(BrowserContext.seedPhrase); +}); diff --git a/e2e/src/utils/browser-context.utils.ts b/e2e/src/utils/browser-context.utils.ts index 32ac1db8ea..7c442ad6af 100644 --- a/e2e/src/utils/browser-context.utils.ts +++ b/e2e/src/utils/browser-context.utils.ts @@ -1,10 +1,27 @@ +import retry from 'async-retry'; import { Browser } from 'puppeteer'; import { BrowserContext } from '../classes/browser-context.class'; +import { getExtensionId } from './browser.utils'; +import { RETRY_OPTIONS } from './timing.utils'; export const initBrowserContext = async (browser: Browser) => { - const [page] = await browser.pages(); + const extensionId = await getExtensionId(browser); + const url = `chrome-extension://${extensionId}`; + + /* Expecting for extension page to be opened by extension itself */ + const page = await retry(async () => { + const pages = await browser.pages(); + + const page = pages.find(p => p.url().startsWith(url)); + + if (page == null) throw new Error(`Initial extension page not found`); + + return page; + }, RETRY_OPTIONS); + + BrowserContext.EXTENSION_ID = extensionId; BrowserContext.browser = browser; BrowserContext.page = page; }; diff --git a/e2e/src/utils/browser.utils.ts b/e2e/src/utils/browser.utils.ts index 78839fe69b..837cc01068 100644 --- a/e2e/src/utils/browser.utils.ts +++ b/e2e/src/utils/browser.utils.ts @@ -1,6 +1,8 @@ +import retry from 'async-retry'; import path from 'path'; -import { launch } from 'puppeteer'; +import { Browser, launch } from 'puppeteer'; +import { RETRY_OPTIONS } from './timing.utils'; const EXTENSION_PATH = path.resolve(__dirname, '../../../dist/chrome_unpacked'); export const initBrowser = () => @@ -8,3 +10,21 @@ export const initBrowser = () => headless: false, args: [`--disable-extensions-except=${EXTENSION_PATH}`, `--load-extension=${EXTENSION_PATH}`] }); + +export const getExtensionId = async (browser: Browser) => { + const background = await retry(async () => { + const background = browser + .targets() + .find( + target => + target.url().startsWith('chrome-extension://') && + ['service_worker', 'background_page'].includes(target.type()) + ); + + if (background == null) throw new Error(`Extension not found`); + + return background; + }, RETRY_OPTIONS); + + return new URL(background.url()).hostname; +}; diff --git a/e2e/src/utils/timing.utils.ts b/e2e/src/utils/timing.utils.ts new file mode 100644 index 0000000000..4cab05d212 --- /dev/null +++ b/e2e/src/utils/timing.utils.ts @@ -0,0 +1,8 @@ +export const LONG_TIMEOUT = 20_000; + +export const MEDIUM_TIMEOUT = 10_000; + +export const RETRY_OPTIONS = { + minTimeout: 300, + maxRetryTime: 5_000 +}; diff --git a/e2e/yarn.lock b/e2e/yarn.lock index c52a1c1bee..b17cff0275 100644 --- a/e2e/yarn.lock +++ b/e2e/yarn.lock @@ -203,6 +203,11 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== +"@types/chai@^4.3.4": + version "4.3.4" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4" + integrity sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw== + "@types/lodash@^4.14.175": version "4.14.191" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" @@ -295,6 +300,18 @@ assertion-error-formatter@^3.0.0: pad-right "^0.2.2" repeat-string "^1.6.1" +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -354,6 +371,19 @@ capital-case@^1.0.4: tslib "^2.0.3" upper-case-first "^2.0.2" +chai@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" + integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^4.1.2" + get-func-name "^2.0.0" + loupe "^2.3.1" + pathval "^1.1.1" + type-detect "^4.0.5" + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -371,6 +401,11 @@ chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -471,6 +506,13 @@ debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.4: dependencies: ms "2.1.2" +deep-eql@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + devtools-protocol@0.0.1068969: version "0.0.1068969" resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1068969.tgz#8b9a4bc48aed1453bed08d62b07481f9abf4d6d8" @@ -603,6 +645,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== + get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -767,6 +814,13 @@ lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +loupe@^2.3.1: + version "2.3.6" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== + dependencies: + get-func-name "^2.0.0" + lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -883,6 +937,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -992,6 +1051,11 @@ resolve-pkg@^2.0.0: dependencies: resolve-from "^5.0.0" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + rimraf@3.0.2, rimraf@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -1164,6 +1228,11 @@ tslib@^2.0.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" diff --git a/package.json b/package.json index 2da01ef28d..c4bae84bf6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "temple-wallet", - "version": "1.16.1", + "version": "1.16.2", "private": true, "scripts": { "start-run": "cross-env TS_NODE_PROJECT=\"webpack/tsconfig.json\" webpack --watch --stats errors-warnings", @@ -21,6 +21,9 @@ "clear:lint": "rimraf node_modules/.cache/.eslintcache", "find-deadcode": "ts-prune --error" }, + "engines" : { + "node" : "16" + }, "dependencies": { "@apollo/client": "^3.7.2", "@babel/core": "7.19.3", diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index 9ff61f4365..ac6b7b5bec 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -97,6 +97,17 @@ "copyHashToClipboard": { "message": "Copy to clipboard" }, + "showInGasOrFiat": { + "message": "Show in $gasToken$/$fiatCurrency$", + "placeholders": { + "gasToken": { + "content": "$1" + }, + "fiatCurrency": { + "content": "$2" + } + } + }, "accounts": { "message": "Accounts" }, diff --git a/public/_locales/en_GB/messages.json b/public/_locales/en_GB/messages.json index b9cfda3406..7de1f43bf1 100644 --- a/public/_locales/en_GB/messages.json +++ b/public/_locales/en_GB/messages.json @@ -94,6 +94,17 @@ "copyHashToClipboard": { "message": "Copy to clipboard" }, + "showInGasOrFiat": { + "message": "Show in $gasToken$/$fiatCurrency$", + "placeholders": { + "gasToken": { + "content": "$1" + }, + "fiatCurrency": { + "content": "$2" + } + } + }, "accounts": { "message": "Accounts" }, diff --git a/public/_locales/ru/messages.json b/public/_locales/ru/messages.json index e1923fe312..b7f199e9a8 100644 --- a/public/_locales/ru/messages.json +++ b/public/_locales/ru/messages.json @@ -38,6 +38,17 @@ "copyHashToClipboard": { "message": "Скопировать хэш в буфер обмена" }, + "showInGasOrFiat": { + "message": "Показать в $gasToken$/$fiatCurrency$", + "placeholders": { + "gasToken": { + "content": "$1" + }, + "fiatCurrency": { + "content": "$2" + } + } + }, "defaultAccount": { "message": "Аккаунт по умолчанию (первый)" }, diff --git a/public/_locales/uk/messages.json b/public/_locales/uk/messages.json index b24cff6347..2f57103d7d 100644 --- a/public/_locales/uk/messages.json +++ b/public/_locales/uk/messages.json @@ -91,6 +91,17 @@ "copyHashToClipboard": { "message": "Копіювати в буфер обміну" }, + "showInGasOrFiat": { + "message": "Показати в $gasToken$/$fiatCurrency$", + "placeholders": { + "gasToken": { + "content": "$1" + }, + "fiatCurrency": { + "content": "$2" + } + } + }, "accounts": { "message": "Аккаунти" }, diff --git a/src/app/atoms/Button.tsx b/src/app/atoms/Button.tsx index fb765b6b44..a4b6308303 100644 --- a/src/app/atoms/Button.tsx +++ b/src/app/atoms/Button.tsx @@ -15,6 +15,7 @@ export const Button = React.forwardRef( return onClick !== undefined && onClick(e); }; + return + )} + +
+ {shouldShowFiatBanner ? ( + + ) : ( + <> + {gasTokenName} + + )} +
+ + +
+ {shouldShowFiatBanner ? ( + + ) : ( + + )} +
+ ); }; -interface TotalVolumeBannerBaseProps { - accountPkh: string; - titleNode: React.ReactNode; - balanceNode: React.ReactNode; +interface BalanceProps { + volume: number | string | BigNumber; + currency: string; } +const BalanceFiat: FC = ({ volume, currency }) => ( + <> + + + {volume} + + {currency} + +); -const TotalVolumeBannerBase: FC = ({ accountPkh, titleNode, balanceNode }) => ( -
-
-
{titleNode}
- - -
-
{balanceNode}
-
+const BalanceGas: FC = ({ volume, currency }) => ( + <> + {volume} + {currency} + ); interface AssetBannerProps { diff --git a/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx b/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx index a73887fb58..a010bd74f6 100644 --- a/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx +++ b/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx @@ -29,6 +29,7 @@ interface FormData extends TestIDProps { termsAccepted: boolean; analytics?: boolean; skipOnboarding?: boolean; + testID?: string; } interface SetWalletPasswordProps { diff --git a/src/app/pages/Onboarding/hooks/useOnboardingProgress.hook.ts b/src/app/pages/Onboarding/hooks/useOnboardingProgress.hook.ts index c107ceea9a..6277adc53c 100644 --- a/src/app/pages/Onboarding/hooks/useOnboardingProgress.hook.ts +++ b/src/app/pages/Onboarding/hooks/useOnboardingProgress.hook.ts @@ -1,4 +1,5 @@ -import { useLocalStorage, useStorage } from 'lib/temple/front'; +import { useStorage } from 'lib/temple/front'; +import { useLocalStorage } from 'lib/ui/local-storage'; export const useOnboardingProgress = () => { const [onBoarding, setOnboarding] = useLocalStorage('onboarding', false); diff --git a/src/app/pages/Settings.tsx b/src/app/pages/Settings.tsx index 0e7e87a3eb..70d7bd12f7 100644 --- a/src/app/pages/Settings.tsx +++ b/src/app/pages/Settings.tsx @@ -22,7 +22,7 @@ import DAppSettings from 'app/templates/DAppSettings'; import GeneralSettings from 'app/templates/GeneralSettings'; import HelpAndCommunity from 'app/templates/HelpAndCommunity'; import RemoveAccount from 'app/templates/RemoveAccount'; -import RevealSecret from 'app/templates/RevealSecret'; +import RevealSecret from 'app/templates/RevealSecrets/RevealSecret'; import SyncSettings from 'app/templates/SyncSettings'; import { TID, T } from 'lib/i18n'; import { Link } from 'lib/woozie'; diff --git a/src/app/pages/Unlock.tsx b/src/app/pages/Unlock.tsx index e8872abbd0..b1f7154af3 100644 --- a/src/app/pages/Unlock.tsx +++ b/src/app/pages/Unlock.tsx @@ -7,8 +7,9 @@ import { Alert, FormField, FormSubmitButton } from 'app/atoms'; import SimplePageLayout from 'app/layouts/SimplePageLayout'; import { useFormAnalytics } from 'lib/analytics'; import { T, t } from 'lib/i18n'; -import { useLocalStorage, useTempleClient } from 'lib/temple/front'; +import { useTempleClient } from 'lib/temple/front'; import { TempleSharedStorageKey } from 'lib/temple/types'; +import { useLocalStorage } from 'lib/ui/local-storage'; import { Link } from 'lib/woozie'; interface UnlockProps { diff --git a/src/app/pages/Withdraw/Debit/AliceBob/steps/InitialStep.tsx b/src/app/pages/Withdraw/Debit/AliceBob/steps/InitialStep.tsx index 36eb4d353b..8a7ab9decc 100644 --- a/src/app/pages/Withdraw/Debit/AliceBob/steps/InitialStep.tsx +++ b/src/app/pages/Withdraw/Debit/AliceBob/steps/InitialStep.tsx @@ -25,7 +25,7 @@ const NOT_UKRAINIAN_CARD_ERROR_MESSAGE = 'Ukrainian bank card is required.'; export const InitialStep: FC> = ({ isApiError, setOrderInfo, setStep, setIsApiError }) => { const { analyticsState } = useAnalyticsState(); - const [isLoading, setLoading] = useState(false); + const [orderIsProcessing, setOrderIsProcessing] = useState(false); const [isFormSubmitted, setIsFormSubmitted] = useState(false); const [inputAmount, setInputAmount] = useState(undefined); @@ -45,11 +45,10 @@ export const InitialStep: FC> = ({ isApiError, setO [disabledProceed, isApiError, cardNumberInput.isValid, cardNumberInput.isTouched] ); - const outputAmount = useOutputEstimation( + const { estimationIsLoading, outputAmount } = useOutputEstimation( inputAmount, isMinAmountError, isMaxAmountError, - setLoading, setIsApiError, true ); @@ -69,7 +68,7 @@ export const InitialStep: FC> = ({ isApiError, setO return; } - setLoading(true); + setOrderIsProcessing(true); createAliceBobOrder(true, inputAmount?.toString() ?? '0', analyticsState.userId, undefined, cardNumberInput.value) .then(response => { @@ -83,11 +82,13 @@ export const InitialStep: FC> = ({ isApiError, setO setIsApiError(true); } }) - .finally(() => setLoading(false)); + .finally(() => setOrderIsProcessing(false)); }; const handleInputAmountChange = (amount?: number) => setInputAmount(amount); + const isLoading = orderIsProcessing || estimationIsLoading || isMinMaxLoading; + return ( <>

@@ -156,7 +157,7 @@ export const InitialStep: FC> = ({ isApiError, setO paddingTop: '0.625rem', paddingBottom: '0.625rem' }} - loading={isLoading || isMinMaxLoading} + loading={isLoading} testID={WithdrawSelectors.AliceBobNextButton} onClick={handleSubmit} > diff --git a/src/app/store/balance-mode/actions.ts b/src/app/store/balance-mode/actions.ts new file mode 100644 index 0000000000..b4f3a7f089 --- /dev/null +++ b/src/app/store/balance-mode/actions.ts @@ -0,0 +1,5 @@ +import { createAction } from '@reduxjs/toolkit'; + +import { BalanceMode } from './state'; + +export const toggleBalanceMode = createAction('balance-mode/TOGGLE_BALANCE_MODE'); diff --git a/src/app/store/balance-mode/reducers.ts b/src/app/store/balance-mode/reducers.ts new file mode 100644 index 0000000000..6bef9a20b1 --- /dev/null +++ b/src/app/store/balance-mode/reducers.ts @@ -0,0 +1,10 @@ +import { createReducer } from '@reduxjs/toolkit'; + +import { toggleBalanceMode } from './actions'; +import { balanceModeInitialState, BalanceModeState } from './state'; + +export const balanceModeReducer = createReducer(balanceModeInitialState, builder => { + builder.addCase(toggleBalanceMode, (state, { payload }) => { + state.balanceMode = payload; + }); +}); diff --git a/src/app/store/balance-mode/selectors.ts b/src/app/store/balance-mode/selectors.ts new file mode 100644 index 0000000000..e6bf370ec3 --- /dev/null +++ b/src/app/store/balance-mode/selectors.ts @@ -0,0 +1,3 @@ +import { useSelector } from '../index'; + +export const useBalanceModeSelector = () => useSelector(({ balanceMode }) => balanceMode.balanceMode); diff --git a/src/app/store/balance-mode/state.mock.ts b/src/app/store/balance-mode/state.mock.ts new file mode 100644 index 0000000000..9d5e484cbb --- /dev/null +++ b/src/app/store/balance-mode/state.mock.ts @@ -0,0 +1,5 @@ +import { BalanceMode, BalanceModeState } from './state'; + +export const mockBalanceModeState: BalanceModeState = { + balanceMode: BalanceMode.Fiat +}; diff --git a/src/app/store/balance-mode/state.ts b/src/app/store/balance-mode/state.ts new file mode 100644 index 0000000000..8a58c4eb46 --- /dev/null +++ b/src/app/store/balance-mode/state.ts @@ -0,0 +1,10 @@ +export enum BalanceMode { + Fiat = 'fiat', + Gas = 'gas' +} +export interface BalanceModeState { + balanceMode: BalanceMode; +} +export const balanceModeInitialState: BalanceModeState = { + balanceMode: BalanceMode.Fiat +}; diff --git a/src/app/store/index.ts b/src/app/store/index.ts index 878bbff761..60c83deef7 100644 --- a/src/app/store/index.ts +++ b/src/app/store/index.ts @@ -8,6 +8,7 @@ import { createStore, GetStateType, rootStateReducer } from 'lib/store'; import { advertisingEpics } from './advertising/epics'; import { advertisingReducer } from './advertising/reducers'; +import { balanceModeReducer } from './balance-mode/reducers'; import { currencyEpics } from './currency/epics'; import { currencyReducer } from './currency/reducers'; import { dAppsEpics } from './d-apps/epics'; @@ -17,7 +18,8 @@ const baseReducer = rootStateReducer({ advertising: advertisingReducer, currency: currencyReducer, notifications: notificationsReducers, - dApps: dAppsReducer + dApps: dAppsReducer, + balanceMode: balanceModeReducer }); export type RootState = GetStateType; diff --git a/src/app/store/root-state.mock.ts b/src/app/store/root-state.mock.ts index 56e0622861..5a36d5a3c7 100644 --- a/src/app/store/root-state.mock.ts +++ b/src/app/store/root-state.mock.ts @@ -1,6 +1,7 @@ import { mockNotificationsState } from 'lib/notifications'; import { mockAdvertisingState } from './advertising/state.mock'; +import { mockBalanceModeState } from './balance-mode/state.mock'; import { mockCurrencyState } from './currency/state.mock'; import { mockDAppsState } from './d-apps/state.mock'; import { RootState } from './index'; @@ -10,5 +11,6 @@ export const mockRootState: RootState = { advertising: mockAdvertisingState, currency: mockCurrencyState, notifications: mockNotificationsState, - dApps: mockDAppsState + dApps: mockDAppsState, + balanceMode: mockBalanceModeState }; diff --git a/src/app/templates/AssetIcon.tsx b/src/app/templates/AssetIcon.tsx index a8bbc5eb2c..f216a8204b 100644 --- a/src/app/templates/AssetIcon.tsx +++ b/src/app/templates/AssetIcon.tsx @@ -4,8 +4,7 @@ import classNames from 'clsx'; import Identicon from 'app/atoms/Identicon'; import { ReactComponent as CollectiblePlaceholder } from 'app/icons/collectible-placeholder.svg'; -import { buildTokenIconURLs, buildCollectibleImageURLs } from 'lib/image-uri'; -import { useAssetMetadata } from 'lib/temple/front'; +import { useAssetMetadata, buildTokenIconURLs, buildCollectibleImageURLs } from 'lib/temple/front'; import { AssetMetadata, getAssetSymbol } from 'lib/temple/metadata'; import { Image } from 'lib/ui/Image'; diff --git a/src/app/templates/LedgerLiveSettings.tsx b/src/app/templates/LedgerLiveSettings.tsx index d70b81412b..affa544d5c 100644 --- a/src/app/templates/LedgerLiveSettings.tsx +++ b/src/app/templates/LedgerLiveSettings.tsx @@ -2,8 +2,8 @@ import React from 'react'; import { FormCheckbox } from 'app/atoms'; import { T, t } from 'lib/i18n'; -import { useLocalStorage } from 'lib/temple/front'; import { TempleSharedStorageKey } from 'lib/temple/types'; +import { useLocalStorage } from 'lib/ui/local-storage'; const LedgerLiveSettings: React.FC<{}> = () => { const [ledgerLiveEnabled, setLedgerLiveEnabled] = useLocalStorage( diff --git a/src/app/templates/LockUpSettings.tsx b/src/app/templates/LockUpSettings.tsx index 520c1bc0c1..3fbba6f6c0 100644 --- a/src/app/templates/LockUpSettings.tsx +++ b/src/app/templates/LockUpSettings.tsx @@ -2,10 +2,10 @@ import React, { FC } from 'react'; import { FormCheckbox } from 'app/atoms'; import { t, T } from 'lib/i18n'; -import { getIsLockUpEnabled, saveIsLockUpEnabled } from 'lib/lock-up'; +import { useIsLockUpEnabled } from 'lib/lock-up'; const LockUpSettings: FC<{}> = () => { - const isLockUpEnabled = getIsLockUpEnabled(); + const [isLockUpEnabled, saveIsLockUpEnabled] = useIsLockUpEnabled(); const handleLockUpChange = (evt: React.ChangeEvent) => { saveIsLockUpEnabled(evt.target.checked); diff --git a/src/app/templates/RevealSecret.tsx b/src/app/templates/RevealSecrets/RevealSecret.tsx similarity index 94% rename from src/app/templates/RevealSecret.tsx rename to src/app/templates/RevealSecrets/RevealSecret.tsx index 0ef527f383..21b149bfa8 100644 --- a/src/app/templates/RevealSecret.tsx +++ b/src/app/templates/RevealSecrets/RevealSecret.tsx @@ -10,6 +10,8 @@ import { T, t } from 'lib/i18n'; import { useAccount, useSecretState, useTempleClient } from 'lib/temple/front'; import { TempleAccountType } from 'lib/temple/types'; +import { RevealSecretsTestIDS } from './RevealSecrets.test-ids'; + const SUBMIT_ERROR_TYPE = 'submit-error'; type FormData = { @@ -224,6 +226,7 @@ const RevealSecret: FC = ({ reveal }) => { containerClassName="mb-4" className="resize-none notranslate" value={secret} + testID={RevealSecretsTestIDS.RevealSecretsValue} /> {texts.attention}

} className="my-4" /> @@ -244,9 +247,16 @@ const RevealSecret: FC = ({ reveal }) => { errorCaption={errors.password?.message} containerClassName="mb-4" onChange={() => clearError()} + testID={RevealSecretsTestIDS.RevealPasswordField} /> - {message => {message}} + + {message => ( + + {message} + + )} + ); }, [ diff --git a/src/app/templates/RevealSecrets/RevealSecrets.test-ids.ts b/src/app/templates/RevealSecrets/RevealSecrets.test-ids.ts new file mode 100644 index 0000000000..208da6e403 --- /dev/null +++ b/src/app/templates/RevealSecrets/RevealSecrets.test-ids.ts @@ -0,0 +1,5 @@ +export enum RevealSecretsTestIDS { + RevealButton = 'RevealSecrets/Reveal Button', + RevealPasswordField = 'RevealSecrets/Reveal Password Field', + RevealSecretsValue = 'RevealSecrets/Reveal Secrets Value' +} diff --git a/src/app/templates/SwapForm/SwapForm.tsx b/src/app/templates/SwapForm/SwapForm.tsx index 869c2c5203..97d428b0b6 100644 --- a/src/app/templates/SwapForm/SwapForm.tsx +++ b/src/app/templates/SwapForm/SwapForm.tsx @@ -24,12 +24,7 @@ import OperationStatus from 'app/templates/OperationStatus'; import { useFormAnalytics } from 'lib/analytics'; import { T, t } from 'lib/i18n'; import { getRoutingFeeTransferParams } from 'lib/swap-router'; -import { - ROUTING_FEE_ADDRESS, - ROUTING_FEE_PERCENT, - ROUTING_FEE_RATIO, - TEZOS_DEXES_API_URL -} from 'lib/swap-router/config'; +import { ROUTING_FEE_ADDRESS, ROUTING_FEE_PERCENT, ROUTING_FEE_RATIO } from 'lib/swap-router/config'; import { useAccount, useTezos, useAssetMetadata } from 'lib/temple/front'; import { atomsToTokens, tokensToAtoms } from 'lib/temple/helpers'; import useTippy from 'lib/ui/useTippy'; @@ -47,6 +42,12 @@ import { SwapMinimumReceived } from './SwapMinimumReceived/SwapMinimumReceived'; import { SwapPriceUpdateBar } from './SwapPriceUpdateBar/SwapPriceUpdateBar'; import { SwapRoute } from './SwapRoute/SwapRoute'; +const TEMPLE_WALLET_DEXES_API_URL = process.env.TEMPLE_WALLET_DEXES_API_URL; + +if (!TEMPLE_WALLET_DEXES_API_URL) { + throw new Error('TEMPLE_WALLET_DEXES_API_URL is not defined'); +} + const KNOWN_DEX_TYPES = [ DexTypeEnum.QuipuSwap, DexTypeEnum.QuipuSwap20, @@ -84,7 +85,7 @@ export const SwapForm: FC = () => { const inputAssetMetadata = useAssetMetadata(inputValue.assetSlug ?? 'tez')!; const outputAssetMetadata = useAssetMetadata(outputValue.assetSlug ?? 'tez')!; - const allRoutePairs = useAllRoutePairs(TEZOS_DEXES_API_URL); + const allRoutePairs = useAllRoutePairs(TEMPLE_WALLET_DEXES_API_URL); const filteredRoutePairs = useMemo( () => allRoutePairs.data.filter(routePair => KNOWN_DEX_TYPES.includes(routePair.dexType)), [allRoutePairs.data] diff --git a/src/contentScript.ts b/src/contentScript.ts index 31f807d1bb..989c1e3eba 100644 --- a/src/contentScript.ts +++ b/src/contentScript.ts @@ -36,7 +36,7 @@ type BeaconPageMessage = BeaconMessage | { message: BeaconMessage; sender: { id: const SENDER = { id: browser.runtime.id, name: 'Temple - Tezos Wallet', - iconUrl: process.env.TEMPLE_WALLET_LOGO_URL || undefined + iconUrl: 'https://templewallet.com/logo.png' }; window.addEventListener( diff --git a/src/lib/analytics/use-analytics-state.hook.ts b/src/lib/analytics/use-analytics-state.hook.ts index 7559b18bdf..9a54605e04 100644 --- a/src/lib/analytics/use-analytics-state.hook.ts +++ b/src/lib/analytics/use-analytics-state.hook.ts @@ -1,8 +1,9 @@ import { nanoid } from 'nanoid'; import { AnalyticsEventCategory } from 'lib/temple/analytics-types'; -import { useLocalStorage, assertResponse, request } from 'lib/temple/front'; +import { assertResponse, request } from 'lib/temple/front'; import { TempleMessageType } from 'lib/temple/types'; +import { useLocalStorage } from 'lib/ui/local-storage'; interface AnalyticsStateInterface { enabled?: boolean; diff --git a/src/lib/apis/temple/endpoints/templewallet.api.ts b/src/lib/apis/temple/endpoints/templewallet.api.ts index 580bae1951..cbc531d18b 100644 --- a/src/lib/apis/temple/endpoints/templewallet.api.ts +++ b/src/lib/apis/temple/endpoints/templewallet.api.ts @@ -1,3 +1,9 @@ import axios from 'axios'; -export const templeWalletApi = axios.create({ baseURL: 'https://temple-api-mainnet.prod.templewallet.com/api' }); +const TEMPLE_WALLET_API_URL = process.env.TEMPLE_WALLET_API_URL; + +if (!TEMPLE_WALLET_API_URL) { + throw new Error('TEMPLE_WALLET_API_URL is not defined'); +} + +export const templeWalletApi = axios.create({ baseURL: TEMPLE_WALLET_API_URL + '/api' }); diff --git a/src/lib/apis/temple/metadata.ts b/src/lib/apis/temple/metadata.ts index cd15b48f99..581b13a24f 100644 --- a/src/lib/apis/temple/metadata.ts +++ b/src/lib/apis/temple/metadata.ts @@ -2,7 +2,13 @@ import axios from 'axios'; import { DetailedAssetMetdata } from 'lib/temple/metadata'; -const api = axios.create({ baseURL: 'https://metadata-api-mainnet.prod.templewallet.com' }); +const TEMPLE_WALLET_METADATA_API_URL = process.env.TEMPLE_WALLET_METADATA_API_URL; + +if (!TEMPLE_WALLET_METADATA_API_URL) { + throw new Error('TEMPLE_WALLET_METADATA_API_URL is not defined'); +} + +const api = axios.create({ baseURL: TEMPLE_WALLET_METADATA_API_URL }); export async function getTokensMetadata(slugs: string[], timeout?: number) { if (slugs.length === 0) return []; diff --git a/src/lib/e2e/types.ts b/src/lib/e2e/types.ts new file mode 100644 index 0000000000..0d19fb9a38 --- /dev/null +++ b/src/lib/e2e/types.ts @@ -0,0 +1,4 @@ +export enum E2eMessageType { + ResetRequest = 'E2E/Reset/Request', + ResetResponse = 'E2E/Reset/Response' +} diff --git a/src/lib/icons/assets/tezos-logo.svg b/src/lib/icons/assets/tezos-logo.svg new file mode 100644 index 0000000000..a55b87c69c --- /dev/null +++ b/src/lib/icons/assets/tezos-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/lib/icons/index.ts b/src/lib/icons/index.ts index 30cd63c290..c20e84d045 100644 --- a/src/lib/icons/index.ts +++ b/src/lib/icons/index.ts @@ -8,3 +8,4 @@ export { ReactComponent as NewsIcon } from './assets/news.svg'; export { ReactComponent as NoResultIcon } from './assets/no-result.svg'; export { ReactComponent as NotificationDotIcon } from './assets/notification-dot.svg'; export { ReactComponent as UpdateIcon } from './assets/update.svg'; +export { ReactComponent as TezosLogoIcon } from './assets/tezos-logo.svg'; diff --git a/src/lib/lock-up/index.ts b/src/lib/lock-up/index.ts index ddcbf94c52..9bb856560d 100644 --- a/src/lib/lock-up/index.ts +++ b/src/lib/lock-up/index.ts @@ -1,4 +1,7 @@ -const STORAGE_KEY = 'lock_up'; +import { TempleSharedStorageKey } from 'lib/temple/types'; +import { useLocalStorage } from 'lib/ui/local-storage'; + +const STORAGE_KEY = TempleSharedStorageKey.LockUpEnabled; const DEFAULT_VALUE = true; export const getIsLockUpEnabled = () => { @@ -6,6 +9,4 @@ export const getIsLockUpEnabled = () => { return stored ? stored === 'true' : DEFAULT_VALUE; }; -export const saveIsLockUpEnabled = (value: boolean) => { - localStorage.setItem(STORAGE_KEY, String(value)); -}; +export const useIsLockUpEnabled = () => useLocalStorage(STORAGE_KEY, DEFAULT_VALUE); diff --git a/src/lib/swap-router/config.ts b/src/lib/swap-router/config.ts index c9b3bf44f5..59562fc608 100644 --- a/src/lib/swap-router/config.ts +++ b/src/lib/swap-router/config.ts @@ -1,5 +1,3 @@ -export const TEZOS_DEXES_API_URL = 'wss://dexes-api-mainnet.prod.templewallet.com'; - export const ROUTING_FEE_ADDRESS = 'tz1UbRzhYjQKTtWYvGUWcRtVT4fN3NESDVYT'; export const ROUTING_FEE_PERCENT = 0.5; diff --git a/src/lib/temple/back/analytics.ts b/src/lib/temple/back/analytics.ts index d131355acd..28a8e9f6b2 100644 --- a/src/lib/temple/back/analytics.ts +++ b/src/lib/temple/back/analytics.ts @@ -4,11 +4,13 @@ import Analytics from 'analytics-node'; import { TempleSendPageEventRequest, TempleSendTrackEventRequest } from 'lib/temple/analytics-types'; import { loadChainId } from 'lib/temple/helpers'; -if (!process.env.TEMPLE_WALLET_SEGMENT_WRITE_KEY) { +const WRITE_KEY = process.env.TEMPLE_WALLET_SEGMENT_WRITE_KEY; + +if (!WRITE_KEY) { throw new Error("Require a 'TEMPLE_WALLET_SEGMENT_WRITE_KEY' environment variable to be set"); } -const client = new Analytics(process.env.TEMPLE_WALLET_SEGMENT_WRITE_KEY, { +const client = new Analytics(WRITE_KEY, { axiosConfig: { adapter: fetchAdapter } } as {}); diff --git a/src/lib/temple/back/main.ts b/src/lib/temple/back/main.ts index 3c01bbec06..28b116913b 100644 --- a/src/lib/temple/back/main.ts +++ b/src/lib/temple/back/main.ts @@ -1,7 +1,9 @@ -import { Runtime } from 'webextension-polyfill'; +import browser, { Runtime } from 'webextension-polyfill'; +import { E2eMessageType } from 'lib/e2e/types'; import { BACKGROUND_IS_WORKER } from 'lib/env'; import { encodeMessage, encryptMessage, getSenderId, MessageType, Response } from 'lib/temple/beacon'; +import { clearAsyncStorages } from 'lib/temple/reset'; import { TempleMessageType, TempleRequest, TempleResponse } from 'lib/temple/types'; import * as Actions from './actions'; @@ -239,3 +241,13 @@ const processRequest = async (req: TempleRequest, port: Runtime.Port): Promise { + if (msg?.type === E2eMessageType.ResetRequest) { + return new Promise(async resolve => { + await clearAsyncStorages(); + resolve({ type: E2eMessageType.ResetResponse }); + }); + } + return; +}); diff --git a/src/lib/temple/beacon.ts b/src/lib/temple/beacon.ts index 8ba763a05f..f8511dd56a 100644 --- a/src/lib/temple/beacon.ts +++ b/src/lib/temple/beacon.ts @@ -229,7 +229,7 @@ export function formatOpParams(op: any) { export const PAIRING_RESPONSE_BASE: Partial = { type: MessageType.HandshakeResponse, name: 'Temple - Tezos Wallet', - icon: process.env.TEMPLE_WALLET_LOGO_URL || undefined, + icon: 'https://templewallet.com/logo.png', appUrl: browser.runtime.getURL('fullpage.html') }; diff --git a/src/lib/image-uri.ts b/src/lib/temple/front/image-uri.ts similarity index 100% rename from src/lib/image-uri.ts rename to src/lib/temple/front/image-uri.ts diff --git a/src/lib/temple/front/index.ts b/src/lib/temple/front/index.ts index 94baa6ddea..a84f19d00e 100644 --- a/src/lib/temple/front/index.ts +++ b/src/lib/temple/front/index.ts @@ -1,5 +1,3 @@ -export { useLocalStorage } from './local-storage'; - export { useStorage, fetchFromStorage, putToStorage } from './storage'; export { useTempleClient, request, assertResponse } from './client'; @@ -65,3 +63,5 @@ export { useSecretState } from './use-secret-state.hook'; export { useFilteredContacts } from './use-filtered-contacts.hook'; export { decryptKukaiSeedPhrase } from './kukai'; + +export { buildTokenIconURLs, buildCollectibleImageURLs } from './image-uri'; diff --git a/src/lib/temple/types.ts b/src/lib/temple/types.ts index b8cd9bcfcb..b2a8b740b9 100644 --- a/src/lib/temple/types.ts +++ b/src/lib/temple/types.ts @@ -129,8 +129,8 @@ export interface TempleSettings { export enum TempleSharedStorageKey { DAppEnabled = 'dappenabled', - LocaleCode = 'localecode', UseLedgerLive = 'useledgerlive', + LockUpEnabled = 'lock_up', PasswordAttempts = 'passwordAttempts', TimeLock = 'timelock' } diff --git a/src/lib/temple/front/local-storage.ts b/src/lib/ui/local-storage.ts similarity index 100% rename from src/lib/temple/front/local-storage.ts rename to src/lib/ui/local-storage.ts