diff --git a/.github/workflows/amplitude.yml b/.github/workflows/amplitude.yml new file mode 100644 index 000000000..c56fcae72 --- /dev/null +++ b/.github/workflows/amplitude.yml @@ -0,0 +1,14 @@ +name: Ampli Implementation Check +on: pull_request + +jobs: + build: + runs-on: ubuntu-latest + container: + image: amplitudeinc/ampli + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Verify analytics implementation and update status in Data + run: ampli status -t ${{secrets.AMPLI_TOKEN}} [--update] diff --git a/.github/workflows/changeset.yml b/.github/workflows/changeset.yml index 35cd31c9b..65572d1f0 100644 --- a/.github/workflows/changeset.yml +++ b/.github/workflows/changeset.yml @@ -37,7 +37,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml new file mode 100644 index 000000000..de845fe8c --- /dev/null +++ b/.github/workflows/chromatic.yml @@ -0,0 +1,55 @@ +name: Chromatic + +on: + push: + branches: + - develop + pull_request: + +jobs: + chromatic: + env: + SAFE_ENV_VARS: true + ARGENT_API_BASE_URL: ${{ vars.ARGENT_API_BASE_URL }} + ARGENT_TESTNET_RPC_URL: ${{ vars.ARGENT_TESTNET_RPC_URL }} + ARGENT_HEALTHCHECK_BASE_URL: ${{ vars.ARGENT_HEALTHCHECK_BASE_URL }} + ARGENT_X_STATUS_URL: ${{ vars.ARGENT_X_STATUS_URL }} + ARGENT_X_NEWS_URL: ${{ vars.ARGENT_X_NEWS_URL }} + ARGENT_X_ENVIRONMENT: "prod" + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Setup project + run: pnpm run setup + + - name: Publish to Chromatic + uses: chromaui/action@latest + with: + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + workingDir: packages/storybook diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 893c67e74..8d84bff18 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -78,7 +78,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} @@ -101,7 +101,7 @@ jobs: run: pnpm bundlewatch - name: Use Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-${{ matrix.extension_type }}-${{ matrix.env }} @@ -158,7 +158,7 @@ jobs: cache: "pnpm" - name: Restore pnpm cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.pnpm-store key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} @@ -166,7 +166,7 @@ jobs: ${{ runner.os }}-pnpm-store- - name: Restore cached build - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-chrome-hydrogen # test-unit is always run against chrome-hydrogen build @@ -199,6 +199,7 @@ jobs: E2E_TESTNET_SEED1: ${{ secrets.E2E_TESTNET_SEED1 }} E2E_TESTNET_SEED2: ${{ secrets.E2E_TESTNET_SEED2 }} E2E_TESTNET_SEED3: ${{ secrets.E2E_TESTNET_SEED3 }} + E2E_TESTNET_SEED4: ${{ secrets.E2E_TESTNET_SEED4 }} E2E_ACCOUNT_1_SEED2: ${{ secrets.E2E_ACCOUNT_1_SEED2 }} E2E_ACCOUNT_1_SEED3: ${{ secrets.E2E_ACCOUNT_1_SEED3 }} ## BANK ACCOUNT, USED FOR FUND OTHER ACCOUNTS @@ -211,12 +212,19 @@ jobs: ARGENT_HEALTHCHECK_BASE_URL: ${{ secrets.ARGENT_HEALTHCHECK_BASE_URL }} E2E_SPOK_CAMPAIGN_URL: ${{ secrets.E2E_SPOK_CAMPAIGN_URL }} E2E_SPOK_CAMPAIGN_NAME: ${{ secrets.E2E_SPOK_CAMPAIGN_NAME }} + ##slack config + SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} + SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }} # Refresh intervals REFRESH_INTERVAL_FAST: 1 # 1s REFRESH_INTERVAL_MEDIUM: 5 # 5s REFRESH_INTERVAL_SLOW: 20 # 20s REFRESH_INTERVAL_VERY_SLOW: 60 * 10 # 10m + ##webwallet default account config + WW_EMAIL: ${{ secrets.WW_EMAIL }} + WW_PIN: ${{ secrets.WW_PIN }} + WW_LOGIN_PASSWORD: ${{ secrets.WW_LOGIN_PASSWORD }} steps: - uses: actions/checkout@v4 @@ -233,7 +241,7 @@ jobs: cache: "pnpm" - name: Restore pnpm cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.pnpm-store key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} @@ -241,7 +249,7 @@ jobs: ${{ runner.os }}-pnpm-store- - name: Restore cached build - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-chrome-${{ env.ARGENT_X_ENVIRONMENT }} # test-e2e is always run against chrome-hydrogen build @@ -270,6 +278,70 @@ jobs: path: packages/e2e/blob-report/ retention-days: 5 + test-notify-low-balance: + runs-on: ubuntu-latest + if: always() + needs: [build-all-artifacts, test-e2e] + env: + ARGENT_X_ENVIRONMENT: "hydrogen" + ARGENT_API_BASE_URL: ${{ secrets.ARGENT_API_BASE_URL }} + E2E_TESTNET_SEED1: ${{ secrets.E2E_TESTNET_SEED1 }} + E2E_TESTNET_SEED2: ${{ secrets.E2E_TESTNET_SEED2 }} + E2E_TESTNET_SEED3: ${{ secrets.E2E_TESTNET_SEED3 }} + E2E_TESTNET_SEED4: ${{ secrets.E2E_TESTNET_SEED4 }} + E2E_ACCOUNT_1_SEED2: ${{ secrets.E2E_ACCOUNT_1_SEED2 }} + E2E_ACCOUNT_1_SEED3: ${{ secrets.E2E_ACCOUNT_1_SEED3 }} + ## BANK ACCOUNT, USED FOR FUND OTHER ACCOUNTS + E2E_SENDER_ADDRESSES: ${{ secrets.E2E_SENDER_ADDRESSES }} + E2E_SENDER_PRIVATEKEYS: ${{ secrets.E2E_SENDER_PRIVATEKEYS }} + E2E_SENDER_SEED: ${{ secrets.E2E_SENDER_SEED }} + STARKNET_TESTNET_URL: ${{ secrets.STARKNET_TESTNET_URL }} + STARKSCAN_TESTNET_URL: ${{ secrets.STARKSCAN_TESTNET_URL }} + ARGENT_TESTNET_RPC_URL: ${{ secrets.ARGENT_TESTNET_RPC_URL }} + ARGENT_HEALTHCHECK_BASE_URL: ${{ secrets.ARGENT_HEALTHCHECK_BASE_URL }} + E2E_SPOK_CAMPAIGN_URL: ${{ secrets.E2E_SPOK_CAMPAIGN_URL }} + E2E_SPOK_CAMPAIGN_NAME: ${{ secrets.E2E_SPOK_CAMPAIGN_NAME }} + ##slack config + SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} + SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }} + # Refresh intervals + REFRESH_INTERVAL_FAST: 1 # 1s + REFRESH_INTERVAL_MEDIUM: 5 # 5s + REFRESH_INTERVAL_SLOW: 20 # 20s + REFRESH_INTERVAL_VERY_SLOW: 60 * 10 # 10m + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v2 + name: Install pnpm + id: pnpm-install + with: + version: 8 + run_install: false + + - uses: actions/setup-node@v4 + with: + node-version: "18.x" + cache: "pnpm" + + - name: Restore pnpm cache + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Restore cached build + uses: actions/cache@v4 + with: + path: ./* + key: ${{ github.sha }}-chrome-${{ env.ARGENT_X_ENVIRONMENT }} # test-e2e is always run against chrome-hydrogen build + + - name: Slack notifications + run: pnpm run test:e2e:slack-notifications + merge-reports: needs: [test-e2e, test-webwallet] if: always() @@ -291,7 +363,7 @@ jobs: cache: "pnpm" - name: Restore pnpm cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.pnpm-store key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} @@ -336,7 +408,7 @@ jobs: cache: "pnpm" - name: Restore pnpm cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.pnpm-store key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} @@ -376,7 +448,7 @@ jobs: cache: "pnpm" - name: Restore cached build - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }}-chrome-hydrogen @@ -426,6 +498,7 @@ jobs: E2E_TESTNET_SEED1: ${{ secrets.E2E_TESTNET_SEED1 }} E2E_TESTNET_SEED2: ${{ secrets.E2E_TESTNET_SEED2 }} E2E_TESTNET_SEED3: ${{ secrets.E2E_TESTNET_SEED3 }} + E2E_TESTNET_SEED4: ${{ secrets.E2E_TESTNET_SEED4 }} E2E_ACCOUNT_1_SEED2: ${{ secrets.E2E_ACCOUNT_1_SEED2 }} E2E_ACCOUNT_1_SEED3: ${{ secrets.E2E_ACCOUNT_1_SEED3 }} ## BANK ACCOUNT, USED FOR FUND OTHER ACCOUNTS @@ -438,6 +511,14 @@ jobs: ARGENT_HEALTHCHECK_BASE_URL: ${{ secrets.ARGENT_HEALTHCHECK_BASE_URL }} E2E_SPOK_CAMPAIGN_URL: ${{ secrets.E2E_SPOK_CAMPAIGN_URL }} E2E_SPOK_CAMPAIGN_NAME: ${{ secrets.E2E_SPOK_CAMPAIGN_NAME }} + ##slack config + SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }} + SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }} + + ##webwallet default account config + WW_EMAIL: ${{ secrets.WW_EMAIL }} + WW_PIN: ${{ secrets.WW_PIN }} + WW_LOGIN_PASSWORD: ${{ secrets.WW_LOGIN_PASSWORD }} steps: - uses: actions/checkout@v4 @@ -455,7 +536,7 @@ jobs: cache: "pnpm" - name: Restore cached build - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ./* key: ${{ github.sha }} @@ -477,7 +558,7 @@ jobs: uses: actions/upload-artifact@v4 if: always() with: - name: test-artifacts-${{ matrix.shardIndex }} + name: test-artifacts-webwallet path: | packages/e2e/artifacts/playwright/ retention-days: 5 @@ -486,7 +567,7 @@ jobs: if: always() uses: actions/upload-artifact@v4 with: - name: all-blob-reports-webwallet-${{ matrix.shardIndex }} + name: all-blob-reports-webwallet-webwallet path: packages/e2e/blob-report/ retention-days: 5 @@ -497,7 +578,7 @@ jobs: steps: - name: Send notification to Slack - uses: 8398a7/action-slack@v3.15.1 + uses: 8398a7/action-slack@v3.16.2 with: status: custom custom_payload: | @@ -506,7 +587,7 @@ jobs: attachments: [{ fallback: 'fallback', color: '${{ env.BUILD_STATUS }}', - title: 'Artifacts for testing ${{ env.BUILD_TYPE }} <${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.number }}|${{ github.event.number }} ${{ github.event.pull_request.title }}>', + title: `Artifacts for testing ${{ env.BUILD_TYPE }} <${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.number }}|${{ github.event.number }} ${{ github.event.pull_request.title }}>`, text: '<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}#artifacts|Artifacts link>', fields: [{},], actions: [{}]}] diff --git a/.nvmrc b/.nvmrc index 8b0beab16..2dbbe00e6 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.11.0 +20.11.1 diff --git a/.vscode/settings.json b/.vscode/settings.json index 96f6a5305..a90b461b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,7 +11,7 @@ "vitest.enable": true, "vitest.commandLine": "npx vitest -r packages/extension/", "explorer.fileNesting.patterns": { - "*.tsx": "${capture}.ts, ${capture}.typegen.ts, ${capture}Container.tsx, ${capture}.container.tsx, ${capture}.test.tsx, ${capture}.spec.tsx, ${capture}.test.ts, ${capture}.spec.ts", + "*.tsx": "${capture}.ts, ${capture}.typegen.ts, ${capture}Container.tsx, ${capture}.container.tsx, ${capture}.stories.tsx, ${capture}.test.tsx, ${capture}.spec.tsx, ${capture}.test.ts, ${capture}.spec.ts", "*.ts": "${capture}.ts, ${capture}.typegen.ts, ${capture}Container.tsx, ${capture}.container.tsx, ${capture}.test.tsx, ${capture}.spec.tsx, ${capture}.test.ts, ${capture}.spec.ts" } } diff --git a/package.json b/package.json index ecf4144f8..8cafcd947 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,12 @@ "@lavamoat/allow-scripts": "^3.0.0", "@lavamoat/preinstall-always-fail": "^2.0.0", "bundlewatch": "^0.3.3", - "husky": "^8.0.3", + "husky": "^9.0.0", "import-sort-style-module": "^6.0.0", "lint-staged": "^15.0.0", - "nx": "^17.0.0", + "nx": "^18.0.0", "patch-package": "^8.0.0", - "prettier": ">=2.8.8", + "prettier": "^3.2.5", "prettier-plugin-import-sort": "^0.0.7", "ts-node": "^10.9.1" }, @@ -38,6 +38,7 @@ "test:watch": "pnpm run -r --parallel; --stream test:watch", "test:e2e:extension": "pnpm run --filter @argent-x/e2e test:extension", "test:e2e:webwallet": "pnpm run --filter @argent-x/e2e test:webwallet", + "test:e2e:slack-notifications": "pnpm run --filter @argent-x/e2e test:slack-notifications", "setup": "pnpm install --frozen-lockfile && pnpm allow-scripts && husky install && patch-package && pnpm run -r --stream setup", "test:ci": "pnpm run --stream --parallel test:ci", "storybook": "cd packages/storybook && pnpm run storybook", diff --git a/packages/dapp/package.json b/packages/dapp/package.json index 7b73d2c99..cac1a4498 100644 --- a/packages/dapp/package.json +++ b/packages/dapp/package.json @@ -10,12 +10,12 @@ "lint": "next lint" }, "dependencies": { - "@argent/shared": "^6.3.1", - "@argent/ui": "^6.3.1", + "@argent/x-shared": "1.1.7", + "@argent/x-ui": "^1.0.2", "@argent/x-sessions": "^6.3.1", - "@chakra-ui/react": "^2.6.1", - "@starknet-react/chains": "0.1.5", - "@starknet-react/core": "2.2.2", + "@chakra-ui/react": "^2.8.2", + "@starknet-react/chains": "0.1.7", + "@starknet-react/core": "2.2.5", "micro-starknet": "^0.2.3", "next": "^13.4.6", "react": "^18.0.0", @@ -24,7 +24,7 @@ "starknetkit": "^1.1.0" }, "devDependencies": { - "@types/node": "20.11.0", + "@types/node": "20.11.20", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "eslint": "8", diff --git a/packages/dapp/src/components/AddNetwork.tsx b/packages/dapp/src/components/AddNetwork.tsx index 03416dc0e..a9e80f66e 100644 --- a/packages/dapp/src/components/AddNetwork.tsx +++ b/packages/dapp/src/components/AddNetwork.tsx @@ -1,4 +1,4 @@ -import { H2 } from "@argent/ui" +import { H2 } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { addNetwork } from "../services/wallet.service" import { useState } from "react" diff --git a/packages/dapp/src/components/AddToken.tsx b/packages/dapp/src/components/AddToken.tsx index 75ab0d8db..22de0cfe4 100644 --- a/packages/dapp/src/components/AddToken.tsx +++ b/packages/dapp/src/components/AddToken.tsx @@ -1,4 +1,4 @@ -import { Button, H2 } from "@argent/ui" +import { Button, H2 } from "@argent/x-ui" import { truncateAddress } from "../services/address.service" import { DAITokenAddress, ETHTokenAddress } from "../services/token.service" import { addToken } from "../services/wallet.service" diff --git a/packages/dapp/src/components/Declare.tsx b/packages/dapp/src/components/Declare.tsx index 5dcf1d68e..a4d75ad41 100644 --- a/packages/dapp/src/components/Declare.tsx +++ b/packages/dapp/src/components/Declare.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input } from "@argent/ui" +import { Button, H2, Input } from "@argent/x-ui" import { CompiledSierraCasm, DeclareContractPayload, @@ -6,7 +6,7 @@ import { isSierra, } from "starknet" -import { readFileAsString } from "@argent/shared" +import { readFileAsString } from "@argent/x-shared" import { Flex } from "@chakra-ui/react" import { FC, useMemo, useState } from "react" import { declare, declareAndDeploy } from "../services/wallet.service" diff --git a/packages/dapp/src/components/Deploy.tsx b/packages/dapp/src/components/Deploy.tsx index df17d4abd..37e28dc07 100644 --- a/packages/dapp/src/components/Deploy.tsx +++ b/packages/dapp/src/components/Deploy.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input } from "@argent/ui" +import { Button, H2, Input } from "@argent/x-ui" import { UniversalDeployerContractPayload } from "starknet" import { Flex } from "@chakra-ui/react" diff --git a/packages/dapp/src/components/Header.tsx b/packages/dapp/src/components/Header.tsx index 830d39fb9..ac2a8f253 100644 --- a/packages/dapp/src/components/Header.tsx +++ b/packages/dapp/src/components/Header.tsx @@ -1,5 +1,5 @@ import { Divider, Flex, Text } from "@chakra-ui/react" -import { Button } from "@argent/ui" +import { Button } from "@argent/x-ui" import { useRouter } from "next/router" import Link from "next/link" import { FC } from "react" diff --git a/packages/dapp/src/components/InfoRow.tsx b/packages/dapp/src/components/InfoRow.tsx index bc9e77200..6f2548624 100644 --- a/packages/dapp/src/components/InfoRow.tsx +++ b/packages/dapp/src/components/InfoRow.tsx @@ -1,4 +1,4 @@ -import { H4 } from "@argent/ui" +import { H4 } from "@argent/x-ui" import { Code, Flex } from "@chakra-ui/react" import { FC, ReactNode } from "react" diff --git a/packages/dapp/src/components/Mint.tsx b/packages/dapp/src/components/Mint.tsx index ed32a99b3..9cb1a4b33 100644 --- a/packages/dapp/src/components/Mint.tsx +++ b/packages/dapp/src/components/Mint.tsx @@ -1,4 +1,4 @@ -import { H2, Input } from "@argent/ui" +import { H2, Input } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, useState } from "react" import { AccountInterface } from "starknet" diff --git a/packages/dapp/src/components/MintWithStarknetReact.tsx b/packages/dapp/src/components/MintWithStarknetReact.tsx index 9790c2275..33b71ded5 100644 --- a/packages/dapp/src/components/MintWithStarknetReact.tsx +++ b/packages/dapp/src/components/MintWithStarknetReact.tsx @@ -1,5 +1,5 @@ -import { bigDecimal } from "@argent/shared" -import { H2, Input } from "@argent/ui" +import { bigDecimal } from "@argent/x-shared" +import { H2, Input } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { useContractWrite } from "@starknet-react/core" import { FC, useMemo, useState } from "react" diff --git a/packages/dapp/src/components/OffchainSessionKeys.tsx b/packages/dapp/src/components/OffchainSessionKeys.tsx index 3811600f8..13ca5a817 100644 --- a/packages/dapp/src/components/OffchainSessionKeys.tsx +++ b/packages/dapp/src/components/OffchainSessionKeys.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input } from "@argent/ui" +import { Button, H2, Input } from "@argent/x-ui" import { OffchainSessionAccount } from "@argent/x-sessions" import { FC, useState } from "react" import { Abi, AccountInterface, Contract } from "starknet" diff --git a/packages/dapp/src/components/OffchainSessionKeysExecute.tsx b/packages/dapp/src/components/OffchainSessionKeysExecute.tsx index 7d0463678..958cf4b50 100644 --- a/packages/dapp/src/components/OffchainSessionKeysExecute.tsx +++ b/packages/dapp/src/components/OffchainSessionKeysExecute.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input } from "@argent/ui" +import { Button, H2, Input } from "@argent/x-ui" import { OffchainSessionAccount } from "@argent/x-sessions" import { FC, useState } from "react" import { Abi, AccountInterface, Contract } from "starknet" diff --git a/packages/dapp/src/components/OffchainSessionKeysSign.tsx b/packages/dapp/src/components/OffchainSessionKeysSign.tsx index 16eccf7ac..0e2e7523d 100644 --- a/packages/dapp/src/components/OffchainSessionKeysSign.tsx +++ b/packages/dapp/src/components/OffchainSessionKeysSign.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input } from "@argent/ui" +import { Button, H2, Input } from "@argent/x-ui" import { OffchainSessionAccount } from "@argent/x-sessions" import { FC, useState } from "react" import { AccountInterface, RpcProvider } from "starknet" diff --git a/packages/dapp/src/components/SignMessage.tsx b/packages/dapp/src/components/SignMessage.tsx index 828240322..19107b8d0 100644 --- a/packages/dapp/src/components/SignMessage.tsx +++ b/packages/dapp/src/components/SignMessage.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input, Textarea } from "@argent/ui" +import { Button, H2, Input, Textarea } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, useState } from "react" import { stark } from "starknet" diff --git a/packages/dapp/src/components/SignMessageWithStarknetReact.tsx b/packages/dapp/src/components/SignMessageWithStarknetReact.tsx index 5c2d7c5f1..2056e745c 100644 --- a/packages/dapp/src/components/SignMessageWithStarknetReact.tsx +++ b/packages/dapp/src/components/SignMessageWithStarknetReact.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input, Textarea } from "@argent/ui" +import { Button, H2, Input, Textarea } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { useSignTypedData } from "@starknet-react/core" import { FC, useEffect, useMemo, useState } from "react" diff --git a/packages/dapp/src/components/TokenDapp.tsx b/packages/dapp/src/components/TokenDapp.tsx index 10722b924..927803f81 100644 --- a/packages/dapp/src/components/TokenDapp.tsx +++ b/packages/dapp/src/components/TokenDapp.tsx @@ -1,4 +1,4 @@ -import { H2, H4, Input, Textarea } from "@argent/ui" +import { H2, H4, Input, Textarea } from "@argent/x-ui" import { SessionAccount, createSession } from "@argent/x-sessions" import { FC, useEffect, useState } from "react" import { Abi, AccountInterface, Contract, GatewayError } from "starknet" diff --git a/packages/dapp/src/components/Transfer.tsx b/packages/dapp/src/components/Transfer.tsx index 0b3ce7bec..92bcfab85 100644 --- a/packages/dapp/src/components/Transfer.tsx +++ b/packages/dapp/src/components/Transfer.tsx @@ -1,4 +1,4 @@ -import { Button, H2, Input } from "@argent/ui" +import { Button, H2, Input } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, useState } from "react" import { transfer } from "../services/token.service" diff --git a/packages/dapp/src/components/TransferWithStarknetReact.tsx b/packages/dapp/src/components/TransferWithStarknetReact.tsx index f1d21e7c2..7b52f8111 100644 --- a/packages/dapp/src/components/TransferWithStarknetReact.tsx +++ b/packages/dapp/src/components/TransferWithStarknetReact.tsx @@ -1,5 +1,5 @@ -import { bigDecimal } from "@argent/shared" -import { Button, H2, Input } from "@argent/ui" +import { bigDecimal } from "@argent/x-shared" +import { Button, H2, Input } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { useContractWrite } from "@starknet-react/core" import { FC, useMemo, useState } from "react" diff --git a/packages/dapp/src/pages/_app.tsx b/packages/dapp/src/pages/_app.tsx index 727172a27..70e08ed9b 100644 --- a/packages/dapp/src/pages/_app.tsx +++ b/packages/dapp/src/pages/_app.tsx @@ -1,5 +1,5 @@ import type { AppProps } from "next/app" -import { ThemeProvider } from "@argent/ui" +import { ThemeProvider } from "@argent/x-ui" import { FC } from "react" const GlobalStyle: FC = () => { diff --git a/packages/dapp/src/pages/_document.tsx b/packages/dapp/src/pages/_document.tsx index 1acf6f887..0ea322793 100644 --- a/packages/dapp/src/pages/_document.tsx +++ b/packages/dapp/src/pages/_document.tsx @@ -1,4 +1,4 @@ -import { theme } from "@argent/ui" +import { theme } from "@argent/x-ui" import { ColorModeScript } from "@chakra-ui/react" import NextDocument, { Head, Html, Main, NextScript } from "next/document" diff --git a/packages/dapp/src/pages/index.tsx b/packages/dapp/src/pages/index.tsx index ea3dd1343..b66e03260 100644 --- a/packages/dapp/src/pages/index.tsx +++ b/packages/dapp/src/pages/index.tsx @@ -1,5 +1,5 @@ import { supportsSessions } from "@argent/x-sessions" -import type { StarknetWindowObject } from "get-starknet-core" +import type { StarknetWindowObject } from "get-starknet-coreV3" import { useCallback, useEffect, useMemo, useState } from "react" import { AccountInterface } from "starknet" import { Header } from "../components/Header" @@ -85,7 +85,7 @@ const StarknetKitDapp = () => { removeWalletAccountsChangedListener(onAccountsChanged) removeWalletNetworkChangedListener(onNetworkChanged) } - }, []) + }, [isConnected]) const handleNetworkClick = useCallback(async (chainId: string) => { try { @@ -97,11 +97,11 @@ const StarknetKitDapp = () => { const handleConnectClick = useCallback( ( - connectWallet: ( - enableWebWallet: boolean, - ) => Promise, - enableWebWallet = true, - ) => + connectWallet: ( + enableWebWallet: boolean, + ) => Promise, + enableWebWallet = true, + ) => async () => { const wallet = await connectWallet(enableWebWallet) const chainId = await getChainId(wallet?.provider as any) diff --git a/packages/dapp/src/pages/starknetReactDapp.tsx b/packages/dapp/src/pages/starknetReactDapp.tsx index e26549725..faa712033 100644 --- a/packages/dapp/src/pages/starknetReactDapp.tsx +++ b/packages/dapp/src/pages/starknetReactDapp.tsx @@ -16,7 +16,7 @@ import { InjectedConnector } from "starknetkit/injected" import { WebWalletConnector } from "starknetkit/webwallet" import { Header } from "../components/Header" -import { H2 } from "@argent/ui" +import { H2 } from "@argent/x-ui" import { Flex, Image } from "@chakra-ui/react" import React, { useEffect, useState } from "react" import { useStarknetkitConnectModal } from "starknetkit" diff --git a/packages/dapp/src/services/token.service.ts b/packages/dapp/src/services/token.service.ts index 549f6636e..df6e58b30 100644 --- a/packages/dapp/src/services/token.service.ts +++ b/packages/dapp/src/services/token.service.ts @@ -1,4 +1,4 @@ -import { bigDecimal } from "@argent/shared" +import { bigDecimal } from "@argent/x-shared" import { Abi, Contract, num, uint256 } from "starknet" import Erc20Abi from "../../abi/ERC20.json" diff --git a/packages/dapp/src/services/wallet.service.ts b/packages/dapp/src/services/wallet.service.ts index f081a5c2a..f58884e21 100644 --- a/packages/dapp/src/services/wallet.service.ts +++ b/packages/dapp/src/services/wallet.service.ts @@ -2,7 +2,7 @@ import { createOffchainSession } from "@argent/x-sessions" import type { AddStarknetChainParameters, StarknetWindowObject, -} from "get-starknet-core" +} from "get-starknet-coreV3" import { AccountInterface, DeclareContractPayload, @@ -15,7 +15,7 @@ import { import { connect, disconnect } from "starknetkit" import { ETHTokenAddress } from "./token.service" import getConfig from "next/config" -import { Hex, bigDecimal } from "@argent/shared" +import { Hex, bigDecimal } from "@argent/x-shared" export type StarknetWindowObjectV5 = StarknetWindowObject & { account: AccountInterface diff --git a/packages/e2e/.gitignore b/packages/e2e/.gitignore index 44898dfcf..04f109329 100644 --- a/packages/e2e/.gitignore +++ b/packages/e2e/.gitignore @@ -1 +1,2 @@ -artifacts \ No newline at end of file +artifacts +blob-report \ No newline at end of file diff --git a/packages/e2e/extension/src/languages/en/index.ts b/packages/e2e/extension/src/languages/en/index.ts index f5927ac21..4fc846908 100644 --- a/packages/e2e/extension/src/languages/en/index.ts +++ b/packages/e2e/extension/src/languages/en/index.ts @@ -39,7 +39,7 @@ const texts = { account: { noAccounts: "You have no accounts on", createAccount: "Create account", - addFunds: "Add funds", + addFunds: "Fund", fundsFromStarkNet: "From another Starknet wallet", fullAccountAddress: "Full account address", send: "Send", diff --git a/packages/e2e/extension/src/page-objects/Account.ts b/packages/e2e/extension/src/page-objects/Account.ts index f47c077ba..de06477fe 100644 --- a/packages/e2e/extension/src/page-objects/Account.ts +++ b/packages/e2e/extension/src/page-objects/Account.ts @@ -530,13 +530,12 @@ export default class Account extends Activity { .fill(signers[index]) } } - //remove empty inputs - const locs = await tabs[1].locator('[name^="signerKeys"]').all() + const locs = await tabs[1].locator('[data-testid^="signerContainer"]').all() if (locs.length > signers.length) { - for (let index = locs.length; index > signers.length + 1; index--) { + for (let index = locs.length; index > signers.length; index--) { await tabs[1] - .locator(`[data-testid="closeButton.${index - 2}"]`) + .locator(`[data-testid="closeButton.${index - 1}"]`) .click() } } @@ -735,9 +734,8 @@ export default class Account extends Activity { expect(this.selectedFeeTokenLoc("ETH")).toBeVisible(), expect(this.selectedFeeTokenLoc("STRK")).toBeVisible(), ]) - const tokenAlreadySelected = await this.selectedFeeTokenLoc( - token, - ).isVisible() + const tokenAlreadySelected = + await this.selectedFeeTokenLoc(token).isVisible() if (!tokenAlreadySelected) { await this.feeTokenPickerLoc.click() await this.feeTokenLoc(token).click() diff --git a/packages/e2e/extension/src/page-objects/Dapps.ts b/packages/e2e/extension/src/page-objects/Dapps.ts index 4aba31f2a..d61442699 100644 --- a/packages/e2e/extension/src/page-objects/Dapps.ts +++ b/packages/e2e/extension/src/page-objects/Dapps.ts @@ -14,7 +14,7 @@ export default class Dapps extends Navigation { } account(accountName: string) { - return this.page.locator(`[data-testid="${accountName}"]`) + return this.page.locator(`[data-testid="${accountName}"]`).first() } connectedDapps(accountName: string, nbrConnectedDapps: number) { @@ -93,6 +93,16 @@ export default class Dapps extends Navigation { await expect(dapp.locator("text=Argent X")).toBeVisible() await dapp.locator("text=Argent X").click() } else { + // assert that if the connect button is visible click on it + const connectButton = dapp.getByRole("button", { name: "connect" }) + await expect(connectButton) + .toBeVisible({ timeout: 5 * 1000 }) + .then(async () => { + await connectButton.click() + }) + .catch(async () => { + null + }) await expect(dapp.getByRole("button", { name: "Argent X" })).toBeVisible() await dapp.getByRole("button", { name: "Argent X" }).click() } diff --git a/packages/e2e/extension/src/page-objects/ExtensionPage.ts b/packages/e2e/extension/src/page-objects/ExtensionPage.ts index e0bc7feeb..7616da942 100644 --- a/packages/e2e/extension/src/page-objects/ExtensionPage.ts +++ b/packages/e2e/extension/src/page-objects/ExtensionPage.ts @@ -80,6 +80,7 @@ export default class ExtensionPage { async recoverWallet(seed: string, password?: string) { await this.wallet.restoreExistingWallet.click() + await this.wallet.agreeLoc.click() await this.setClipBoardContent(seed) await this.pasteSeed() await this.navigation.continueLocator.click() diff --git a/packages/e2e/extension/src/page-objects/Wallet.ts b/packages/e2e/extension/src/page-objects/Wallet.ts index bc523eb28..a5d6fb5b7 100644 --- a/packages/e2e/extension/src/page-objects/Wallet.ts +++ b/packages/e2e/extension/src/page-objects/Wallet.ts @@ -82,6 +82,9 @@ export default class Wallet extends Navigation { return this.page.locator(`button:text-is("${lang.wallet.finish}")`) } + get agreeLoc() { + return this.page.locator('[data-testid="agree-button"]') + } async newWalletOnboarding() { await Promise.all([ expect(this.banner).toBeVisible(), @@ -89,7 +92,7 @@ export default class Wallet extends Navigation { expect(this.restoreExistingWallet).toBeVisible(), ]) await this.createNewWallet.click() - + await this.agreeLoc.click() await Promise.all([ expect(this.banner3).toBeVisible(), expect(this.description3).toBeVisible(), diff --git a/packages/e2e/extension/src/specs/dapps.spec.ts b/packages/e2e/extension/src/specs/dapps.spec.ts index af6c651a5..b3bfdd4ed 100644 --- a/packages/e2e/extension/src/specs/dapps.spec.ts +++ b/packages/e2e/extension/src/specs/dapps.spec.ts @@ -4,7 +4,10 @@ import test from "../test" import { lang } from "../languages" test.describe("Dapps", () => { - test("connect from starknet.id", async ({ extension, browserContext }) => { + test.skip("connect from starknet.id", async ({ + extension, + browserContext, + }) => { //setup wallet await extension.wallet.newWalletOnboarding() await extension.open() @@ -12,7 +15,7 @@ test.describe("Dapps", () => { browserContext, "https://goerli.app.starknet.id", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() //check connect dapps await extension.navigation.showSettingsLocator.click() @@ -24,7 +27,7 @@ test.describe("Dapps", () => { await expect( extension.dapps.connected("https://goerli.app.starknet.id"), ).toBeVisible() - //disconnect dapp from ArgentX + //disconnect dapp from Argent X await extension.dapps.disconnect("https://goerli.app.starknet.id").click() await expect( extension.dapps.connected("https://dapp-argentlabs.vercel.app"), @@ -40,7 +43,7 @@ test.describe("Dapps", () => { browserContext, "https://dapp-argentlabs.vercel.app", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() //check connect dapps await extension.navigation.showSettingsLocator.click() @@ -52,7 +55,7 @@ test.describe("Dapps", () => { await expect( extension.dapps.connected("https://dapp-argentlabs.vercel.app"), ).toBeVisible() - //disconnect dapp from ArgentX + //disconnect dapp from Argent X await extension.dapps .disconnect("https://dapp-argentlabs.vercel.app") .click() @@ -62,7 +65,7 @@ test.describe("Dapps", () => { await expect(extension.dapps.noConnectedDapps.first()).toBeVisible() }) - test("reset all connections", async ({ extension, browserContext }) => { + test.skip("reset all connections", async ({ extension, browserContext }) => { //setup wallet await extension.wallet.newWalletOnboarding() await extension.open() @@ -70,13 +73,13 @@ test.describe("Dapps", () => { browserContext, "https://goerli.app.starknet.id", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() await extension.dapps.requestConnectionFromDapp( browserContext, "https://dapp-argentlabs.vercel.app", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() await extension.navigation.showSettingsLocator.click() await extension.settings.connectedDapps.click() @@ -106,7 +109,7 @@ test.describe("Dapps", () => { await expect(extension.dapps.noConnectedDapps.first()).toBeVisible() }) - test("disconnect only one connected dapp", async ({ + test.skip("disconnect only one connected dapp", async ({ extension, browserContext, }) => { @@ -117,13 +120,13 @@ test.describe("Dapps", () => { browserContext, "https://goerli.app.starknet.id", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() await extension.dapps.requestConnectionFromDapp( browserContext, "https://dapp-argentlabs.vercel.app", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() await extension.navigation.showSettingsLocator.click() await extension.settings.connectedDapps.click() @@ -158,7 +161,10 @@ test.describe("Dapps", () => { ).toBeVisible() }) - test("connect dapps by account", async ({ extension, browserContext }) => { + test.skip("connect dapps by account", async ({ + extension, + browserContext, + }) => { //setup wallet await extension.setupWallet({ accountsToSetup: [ @@ -170,18 +176,19 @@ test.describe("Dapps", () => { await extension.open() await extension.account.selectAccount(extension.account.accountName1) - await extension.dapps.requestConnectionFromDapp( + const dapp = await extension.dapps.requestConnectionFromDapp( browserContext, "https://goerli.app.starknet.id", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() + await dapp.close() await extension.account.selectAccount(extension.account.accountName2) await extension.dapps.requestConnectionFromDapp( browserContext, "https://dapp-argentlabs.vercel.app", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() await extension.navigation.showSettingsLocator.click() await extension.settings.connectedDapps.click() @@ -227,7 +234,7 @@ test.describe("Dapps", () => { browserContext, "https://dapp-argentlabs.vercel.app", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() await dapp.locator('[id="short-text"]').fill("Test message!") await dapp.locator('button:text-is("Sign")').click() @@ -259,7 +266,7 @@ test.describe("Dapps", () => { browserContext, "https://dapp-argentlabs.vercel.app", ) - //accept connection from ArgentX + //accept connection from Argent X await extension.dapps.accept.click() await dapp.locator('[id="short-text"]').fill("Test message!") await dapp.locator('button:text-is("Sign")').click() diff --git a/packages/e2e/extension/src/specs/multisig.spec.ts b/packages/e2e/extension/src/specs/multisig.spec.ts index b5c266106..140c0e91f 100644 --- a/packages/e2e/extension/src/specs/multisig.spec.ts +++ b/packages/e2e/extension/src/specs/multisig.spec.ts @@ -41,7 +41,9 @@ test.describe("Multisig", () => { await extension.navigation.menuTokensLocator.click() //ensure that balance is updated - await expect(extension.account.currentBalance("ETH")).toContainText("0.000") + await expect(extension.account.currentBalance("ETH")).not.toContainText( + "0.002", + ) }) test("add and activate 1/2 multisig", async ({ @@ -99,9 +101,11 @@ test.describe("Multisig", () => { //ensure that balance is updated await Promise.all([ - expect(extension.account.currentBalance("ETH")).toContainText("0.000"), - expect(secondExtension.account.currentBalance("ETH")).toContainText( - "0.000", + expect(extension.account.currentBalance("ETH")).not.toContainText( + "0.002", + ), + expect(secondExtension.account.currentBalance("ETH")).not.toContainText( + "0.002", ), ]) await secondExtension.validateTx({ @@ -182,9 +186,9 @@ test.describe("Multisig", () => { //ensure that balance is updated await Promise.all([ - expect(extension.account.currentBalance("ETH")).toContainText("0.000"), - expect(secondExtension.account.currentBalance("ETH")).toContainText( - "0.000", + expect(extension.account.currentBalance("ETH")).not.toContainText("0.02"), + expect(secondExtension.account.currentBalance("ETH")).not.toContainText( + "0.02", ), ]) }) @@ -299,9 +303,9 @@ test.describe("Multisig", () => { //ensure that balance is updated await Promise.all([ - expect(extension.account.currentBalance("ETH")).toContainText("0.000"), - expect(secondExtension.account.currentBalance("ETH")).toContainText( - "0.000", + expect(extension.account.currentBalance("ETH")).not.toContainText("0.02"), + expect(secondExtension.account.currentBalance("ETH")).not.toContainText( + "0.02", ), ]) }) @@ -514,7 +518,7 @@ test.describe("Multisig", () => { originAccountName: extension.account.accountNameMulti1, recipientAddress: config.destinationAddress!, token: "ETH", - amount: 0.001, + amount: 0.0015, }) const txHash = await extension.activity.getLastTxHash() await extension.navigation.menuTokensLocator.click() @@ -561,11 +565,14 @@ test.describe("Multisig", () => { //ensure that balance is updated await Promise.all([ - expect(extension.account.currentBalance("ETH")).toContainText("0.000", { - timeout: 120000, - }), - expect(secondExtension.account.currentBalance("ETH")).toContainText( - "0.000", + expect(extension.account.currentBalance("ETH")).not.toContainText( + "0.002", + { + timeout: 120000, + }, + ), + expect(secondExtension.account.currentBalance("ETH")).not.toContainText( + "0.002", { timeout: 120000 }, ), ]) diff --git a/packages/e2e/extension/src/specs/nfts.spec.ts b/packages/e2e/extension/src/specs/nfts.spec.ts index 8c1fef13c..79bc0a8e4 100644 --- a/packages/e2e/extension/src/specs/nfts.spec.ts +++ b/packages/e2e/extension/src/specs/nfts.spec.ts @@ -9,12 +9,13 @@ for (const feeToken of ["STRK", "ETH"] as const) { extension, browserContext, }) => { + test.slow() const { accountAddresses } = await extension.setupWallet({ accountsToSetup: [ { assets: [ { token: "ETH", balance: 0.01 }, - { token: "STRK", balance: 0.005 }, + { token: "STRK", balance: 0.8 }, ], deploy: true, feeToken, @@ -40,7 +41,7 @@ for (const feeToken of ["STRK", "ETH"] as const) { await expect( extension.activity.menuPendingTransactionsIndicatorLocator, ).toBeHidden() - + await dapp.close() await extension.navigation.menuNTFsLocator.click() await extension.nfts.collection(spokCampaignName).click() await extension.nfts.nftByPosition().click() diff --git a/packages/e2e/extension/src/specs/recovery.spec.ts b/packages/e2e/extension/src/specs/recovery.spec.ts index e09531a0e..c424424d5 100644 --- a/packages/e2e/extension/src/specs/recovery.spec.ts +++ b/packages/e2e/extension/src/specs/recovery.spec.ts @@ -40,9 +40,7 @@ test.describe("Recovery Wallet", () => { await expect(extension.network.networkSelector).toBeVisible() await extension.network.selectDefaultNetwork() await extension.account.selectAccount("Account 33") - await expect(extension.account.currentBalance("ETH")).toContainText( - "0.0000097 ETH", - ) + await expect(extension.account.currentBalance("ETH")).toContainText("0.000") }) test("Copy phrase from account view when creating new wallet", async ({ @@ -72,4 +70,19 @@ test.describe("Recovery Wallet", () => { expect(accountAddress).toMatch(/^0x0/) await expect(extension.account.showAccountRecovery).toBeHidden() }) + + test("User should be able to recover wallet with only one account with founds", async ({ + extension, + }) => { + await extension.open() + await extension.recoverWallet(config.testNetSeed4!) + await expect(extension.network.networkSelector).toBeVisible() + await extension.network.selectDefaultNetwork() + await extension.account.accountListSelector.click() + await expect(extension.account.account("")).toHaveCount(1) + await extension.account.account("Account 12").click() + await expect(extension.account.currentBalance("ETH")).toContainText( + "0.002 ETH", + ) + }) }) diff --git a/packages/e2e/extension/src/specs/sendMaxFunds.spec.ts b/packages/e2e/extension/src/specs/sendMaxFunds.spec.ts index 9406b215a..d6ff9f7bf 100644 --- a/packages/e2e/extension/src/specs/sendMaxFunds.spec.ts +++ b/packages/e2e/extension/src/specs/sendMaxFunds.spec.ts @@ -6,14 +6,14 @@ for (const feeToken of ["STRK", "ETH"] as const) { test.describe(`Send MAX funds fee ${feeToken}`, () => { test.slow() //using STRK to pay fee, user should be able to transfer all ETH funds - const expectedUpdatedBalance = feeToken === "STRK" ? "0.0 ETH" : "0.00" + const expectedUpdatedBalance = feeToken === "STRK" ? "0.0 ETH" : "0.000" test("send MAX funds to other self account", async ({ extension }) => { const { accountAddresses } = await extension.setupWallet({ accountsToSetup: [ { assets: [ { token: "ETH", balance: 0.01 }, - { token: "STRK", balance: 0.005 }, + { token: "STRK", balance: 0.8 }, ], }, { assets: [{ token: "ETH", balance: 0 }] }, @@ -46,7 +46,7 @@ for (const feeToken of ["STRK", "ETH"] as const) { extension.account.accountName2, ) await expect(extension.account.currentBalance("ETH")).toContainText( - "0.01", + sendAmountFE, ) balance = await extension.account.currentBalance("ETH").innerText() expect(parseFloat(balance)).toBeGreaterThan(0.0001) @@ -58,7 +58,7 @@ for (const feeToken of ["STRK", "ETH"] as const) { { assets: [ { token: "ETH", balance: 0.002 }, - { token: "STRK", balance: 0.005 }, + { token: "STRK", balance: 0.8 }, ], }, ], @@ -97,7 +97,7 @@ for (const feeToken of ["STRK", "ETH"] as const) { { assets: [ { token: "ETH", balance: 0.01 }, - { token: "STRK", balance: 0.005 }, + { token: "STRK", balance: 0.8 }, ], }, ], diff --git a/packages/e2e/extension/src/specs/sendPartialFunds.spec.ts b/packages/e2e/extension/src/specs/sendPartialFunds.spec.ts index 3712b7c40..175199cd8 100644 --- a/packages/e2e/extension/src/specs/sendPartialFunds.spec.ts +++ b/packages/e2e/extension/src/specs/sendPartialFunds.spec.ts @@ -11,7 +11,7 @@ for (const feeToken of ["STRK", "ETH"] as const) { { assets: [ { token: "ETH", balance: 0.01 }, - { token: "STRK", balance: 0.005 }, + { token: "STRK", balance: 0.8 }, ], }, { assets: [{ token: "ETH", balance: 0 }] }, @@ -56,7 +56,7 @@ for (const feeToken of ["STRK", "ETH"] as const) { { assets: [ { token: "ETH", balance: 0.01 }, - { token: "STRK", balance: 0.005 }, + { token: "STRK", balance: 0.8 }, ], }, ], @@ -104,7 +104,7 @@ for (const feeToken of ["STRK", "ETH"] as const) { { assets: [ { token: "ETH", balance: 0.01 }, - { token: "STRK", balance: 0.005 }, + { token: "STRK", balance: 0.8 }, ], }, ], diff --git a/packages/e2e/extension/src/test.ts b/packages/e2e/extension/src/test.ts index db27af857..2a27ec4eb 100644 --- a/packages/e2e/extension/src/test.ts +++ b/packages/e2e/extension/src/test.ts @@ -44,11 +44,15 @@ const createBrowserContext = () => { "--disable-gpu", ], ignoreDefaultArgs: ["--disable-component-extensions-with-background-pages"], + screen: { + width: 300, + height: 600, + }, recordVideo: { dir: artifactsDir, size: { width: 800, - height: 700, + height: 900, }, }, }) diff --git a/packages/e2e/package.json b/packages/e2e/package.json index 40bd4e31d..cb8b2ff05 100644 --- a/packages/e2e/package.json +++ b/packages/e2e/package.json @@ -5,16 +5,18 @@ "main": "index.js", "license": "MIT", "devDependencies": { - "@argent/shared": "workspace:^", + "@argent/x-shared": "1.1.7", "@playwright/test": "^1.40.1", "@types/node": "^20.5.7", "@types/uuid": "^9.0.3", "dotenv": "^16.3.1", "starknet": "6.0.0-beta.13", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "@slack/web-api": "^7.0.0" }, "scripts": { "test:extension": "pnpm playwright test --config=./extension", - "test:webwallet": "pnpm playwright test --config=./webwallet" + "test:webwallet": "pnpm playwright test --config=./webwallet", + "test:slack-notifications": "pnpm playwright test shared/src/slack.spec.ts " } } diff --git a/packages/e2e/shared/config.ts b/packages/e2e/shared/config.ts index 8f024471d..910034f92 100644 --- a/packages/e2e/shared/config.ts +++ b/packages/e2e/shared/config.ts @@ -12,6 +12,7 @@ const config = { testNetSeed1: process.env.E2E_TESTNET_SEED1, //wallet with 32 deployed accounts testNetSeed2: process.env.E2E_TESTNET_SEED2, //wallet with 1 deployed account testNetSeed3: process.env.E2E_TESTNET_SEED3, //wallet with 1 deployed account + testNetSeed4: process.env.E2E_TESTNET_SEED4, //wallet with non deployed account but with funds senderSeed: process.env.E2E_SENDER_SEED, account1Seed2: process.env.E2E_ACCOUNT_1_SEED2, account1Seed3: process.env.E2E_ACCOUNT_1_SEED3, @@ -26,11 +27,14 @@ const config = { //webwallet validLogin: { - email: "testuser@mail.com", - pin: "1111111", - password: "myNewPass12!", + email: process.env.WW_EMAIL!, + pin: process.env.WW_PIN!, + password: process.env.WW_LOGIN_PASSWORD!, }, url: "http://localhost:3005", + //slack + slackToken: process.env.SLACK_TOKEN, + slackChannelId: process.env.SLACK_CHANNEL_ID, } // check that no value of config is undefined, otherwise throw error diff --git a/packages/e2e/shared/src/assets.ts b/packages/e2e/shared/src/assets.ts index 30d1f2cc8..b59bc8ff1 100644 --- a/packages/e2e/shared/src/assets.ts +++ b/packages/e2e/shared/src/assets.ts @@ -6,12 +6,20 @@ import { constants, TransactionFinalityStatus, } from "starknet" -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import config from "../config" import { expect } from "@playwright/test" import { sleep } from "./common" +import { sendSlackMessage } from "./slack" -export type TokenSymbol = "ETH" | "WBTC" | "STRK" | "AST" +export type TokenSymbol = "ETH" | "WBTC" | "STRK" | "AST" | "USDC" | "DAI" +export type TokenName = + | "Ethereum" + | "Wrapped BTC" + | "Starknet" + | "Astraly" + | "USD Coin" + | "DAI" export type FeeTokens = "ETH" | "STRK" export interface AccountsToSetup { assets: { @@ -286,3 +294,19 @@ export function convertScientificToDecimal(num: number) { const exponent = String(num).split("e")[1] return Number(num).toFixed(Math.abs(Number(exponent))) } + +export async function notifyLowBalance() { + let msg: string = "" + for (const acc of config.senderAddrs!) { + for (const token of ["ETH", "STRK"]) { + const balance = await getBalance(acc, token as TokenSymbol) + if (parseFloat(balance) < 0.1) { + console.log(`###### Low balance for ${acc} ${balance}`) + msg += "`" + acc + "` *" + balance + " " + token + "*\n" + } + } + } + if (msg) { + await sendSlackMessage(`*Low balance for:*\n\n ${msg}\n`) + } +} diff --git a/packages/e2e/shared/src/slack.spec.ts b/packages/e2e/shared/src/slack.spec.ts new file mode 100644 index 000000000..6a8458c29 --- /dev/null +++ b/packages/e2e/shared/src/slack.spec.ts @@ -0,0 +1,6 @@ +import { test } from "@playwright/test" +import { notifyLowBalance } from "./assets" + +test("Slack notifications", async () => { + await notifyLowBalance() +}) diff --git a/packages/e2e/shared/src/slack.ts b/packages/e2e/shared/src/slack.ts new file mode 100644 index 000000000..67b343c4c --- /dev/null +++ b/packages/e2e/shared/src/slack.ts @@ -0,0 +1,16 @@ +import { WebClient } from "@slack/web-api" +import config from "../config" + +const options = {} +const web = new WebClient(config.slackToken, options) + +export async function sendSlackMessage(message: string) { + const channelId = config.slackChannelId + if (!channelId) { + throw new Error("SLACK_CHANNEL_ID is not defined") + } + await web.chat.postMessage({ + text: message, + channel: channelId, + }) +} diff --git a/packages/e2e/webwallet/src/fixtures.ts b/packages/e2e/webwallet/src/fixtures.ts index e5e30c187..f9bf060e9 100644 --- a/packages/e2e/webwallet/src/fixtures.ts +++ b/packages/e2e/webwallet/src/fixtures.ts @@ -1,7 +1,8 @@ -import { BrowserContext } from "@playwright/test" +import { BrowserContext, Page } from "@playwright/test" import type WebWalletPage from "./page-objects/WebWalletPage" export interface TestPages { webWallet: WebWalletPage + dApp: Page browserContext: BrowserContext } diff --git a/packages/e2e/webwallet/src/page-objects/Assets.ts b/packages/e2e/webwallet/src/page-objects/Assets.ts new file mode 100644 index 000000000..e71cbd5f3 --- /dev/null +++ b/packages/e2e/webwallet/src/page-objects/Assets.ts @@ -0,0 +1,81 @@ +import type { Page } from "@playwright/test" +import { expect } from "@playwright/test" +import { TokenSymbol, TokenName } from "../../../shared/src/assets" + +export default class Assets { + page: Page + constructor(page: Page) { + this.page = page + } + + get yourAssetsTitle() { + return this.page.getByRole("heading", { name: "Your assets" }).first() + } + + get YourCoinsTitle() { + return this.page.getByRole("heading", { name: "Your coins" }).first() + } + + tokenSymbolLoc(token: TokenSymbol) { + return this.page.locator(`[data-testid="token-${token}"]`) + } + + tokenNameLoc(tokenName: TokenName) { + return this.page.getByRole("heading", { name: tokenName }).first() + } + + get yourNFTTitle() { + return this.page.getByRole("heading", { name: "Your NFTs" }) + } + + get nftName() { + return this.page.getByRole("heading", { name: "Starknet ID: 394352173364" }) + } + + get numberOfNFTs() { + return this.page.locator('p:text-is("1 NFT")') + } + + get send() { + return this.page.locator(`button:text-is("Send")`) + } + async hoverElements() { + await this.yourAssetsTitle.click() + await this.tokenSymbolLoc("ETH").hover() + await expect(this.send).toBeVisible() + await this.yourAssetsTitle.click() + await this.tokenSymbolLoc("USDC").hover() + await expect(this.send).toBeVisible() + await this.yourAssetsTitle.click() + await this.tokenSymbolLoc("DAI").hover() + await expect(this.send).toBeVisible() + await this.yourAssetsTitle.click() + await this.tokenSymbolLoc("WBTC").hover() + await expect(this.send).toBeVisible() + await this.yourAssetsTitle.click() + await this.nftName.hover() + await expect(this.send).toBeVisible() + } + + async assetPageHasLoaded() { + await Promise.all([ + expect(this.yourAssetsTitle).toBeVisible(), + expect(this.YourCoinsTitle).toBeVisible(), + expect(this.tokenNameLoc("Ethereum")).toBeVisible(), + expect(this.tokenSymbolLoc("ETH")).toBeVisible(), + expect(this.tokenNameLoc("DAI")).toBeVisible(), + expect(this.tokenSymbolLoc("DAI")).toBeVisible(), + expect(this.tokenNameLoc("Wrapped BTC")).toBeVisible(), + expect(this.tokenSymbolLoc("WBTC")).toBeVisible(), + expect(this.tokenNameLoc("USD Coin")).toBeVisible(), + expect(this.tokenSymbolLoc("USDC")).toBeVisible(), + expect(this.tokenNameLoc("Starknet")).toBeVisible(), + expect(this.tokenSymbolLoc("STRK")).toBeVisible(), + expect(this.yourNFTTitle).toBeVisible(), + expect(this.nftName).toBeVisible(), + expect(this.numberOfNFTs).toBeVisible(), + ]) + await this.yourAssetsTitle.click() + expect(this.hoverElements) + } +} diff --git a/packages/e2e/webwallet/src/page-objects/Dapps.ts b/packages/e2e/webwallet/src/page-objects/Dapps.ts index f858e0413..dc7ddce82 100644 --- a/packages/e2e/webwallet/src/page-objects/Dapps.ts +++ b/packages/e2e/webwallet/src/page-objects/Dapps.ts @@ -1,6 +1,8 @@ -import { ChromiumBrowserContext, Page, expect } from "@playwright/test" +import { Page, expect } from "@playwright/test" import { ICredentials } from "./Login" import Navigation from "./Navigation" +import { artifactsDir } from "../../../shared/cfg/test" +import { randomUUID } from "crypto" type DappUrl = | "https://goerli.app.starknet.id" @@ -13,35 +15,33 @@ export default class Dapps extends Navigation { } async requestConnectionFromDapp({ - browserContext, + dApp, dappUrl, credentials, newAccount = false, }: { - browserContext: ChromiumBrowserContext + dApp: Page dappUrl: DappUrl credentials: ICredentials newAccount: boolean }) { //open dapp page - const dapp = await browserContext.newPage() - await dapp.setViewportSize({ width: 1080, height: 720 }) - await dapp.goto(dappUrl) + await dApp.goto(dappUrl) if ( dappUrl === "https://dapp-argentlabs.vercel.app" || dappUrl === "https://starknetkit-blacked-listed.vercel.app" ) { - await expect(dapp.locator('button:has-text("Connect")')).toHaveCount(1) - await dapp.locator('button:has-text("Connect")').first().click() + await expect(dApp.locator('button:has-text("Connect")')).toHaveCount(1) + await dApp.locator('button:has-text("Connect")').first().click() } else { - await expect(dapp.locator("text=CONNECT ARGENT")).toBeVisible() - await dapp.locator("text=CONNECT ARGENT").click() + await expect(dApp.locator("text=CONNECT ARGENT")).toBeVisible() + await dApp.locator("text=CONNECT ARGENT").click() } - const popupPromise = dapp.waitForEvent("popup") - await expect(dapp.locator("p:text-is('Email')")).toBeVisible() - await dapp.locator("p:text-is('Email')").click() + const popupPromise = dApp.waitForEvent("popup") + await expect(dApp.locator("p:text-is('Email')")).toBeVisible() + await dApp.locator("p:text-is('Email')").click() const popup = await popupPromise // Wait for the popup to load. await popup.waitForLoadState() @@ -58,10 +58,13 @@ export default class Dapps extends Navigation { } await popup.locator('button[type="submit"]').click() await popup.waitForLoadState() - await expect( - popup.locator(`p:text-is("${credentials.email}")`), - ).toBeVisible() + await expect(popup.locator(`text="${credentials.email}"`)) + .toBeVisible() + .catch(async () => { + await popup.screenshot({ path: `${artifactsDir}/${randomUUID()}.png` }) + throw new Error("Email not visible") + }) await popup.locator('button[type="submit"]').click() - return dapp + return dApp } } diff --git a/packages/e2e/webwallet/src/page-objects/WebWalletPage.ts b/packages/e2e/webwallet/src/page-objects/WebWalletPage.ts index d0765254c..bcc43ff77 100644 --- a/packages/e2e/webwallet/src/page-objects/WebWalletPage.ts +++ b/packages/e2e/webwallet/src/page-objects/WebWalletPage.ts @@ -8,17 +8,20 @@ import Navigation from "./Navigation" export const generateEmail = () => `newWallet_${uuid()}@mail.com` import Dapps from "./Dapps" +import Assets from "./Assets" export default class WebWalletPage { page: Page login: Login navigation: Navigation dapps: Dapps + assets: Assets constructor(page: Page) { this.page = page this.login = new Login(page) this.navigation = new Navigation(page) this.dapps = new Dapps(page) + this.assets = new Assets(page) } open() { diff --git a/packages/e2e/webwallet/src/specs/assets.spec.ts b/packages/e2e/webwallet/src/specs/assets.spec.ts new file mode 100644 index 000000000..5d4902273 --- /dev/null +++ b/packages/e2e/webwallet/src/specs/assets.spec.ts @@ -0,0 +1,8 @@ +import test from "../test" + +test.describe(`Assets page`, () => { + test("Assets page has loaded", async ({ webWallet }) => { + await webWallet.login.success() + await webWallet.assets.assetPageHasLoaded() + }) +}) diff --git a/packages/e2e/webwallet/src/specs/dapps.spec.ts b/packages/e2e/webwallet/src/specs/dapps.spec.ts index 316a16727..a5919b631 100644 --- a/packages/e2e/webwallet/src/specs/dapps.spec.ts +++ b/packages/e2e/webwallet/src/specs/dapps.spec.ts @@ -2,7 +2,7 @@ import test from "../test" import config from "../../../shared/config" test.describe(`Dapps`, () => { - test("Create wallet from Dapp", async ({ webWallet, browserContext }) => { + test("Create wallet from Dapp", async ({ webWallet, dApp }) => { const email = webWallet.generateEmail() const credentials = { email, @@ -11,7 +11,7 @@ test.describe(`Dapps`, () => { } await webWallet.dapps.requestConnectionFromDapp({ - browserContext, + dApp, dappUrl: "https://dapp-argentlabs.vercel.app", credentials, newAccount: true, @@ -19,9 +19,9 @@ test.describe(`Dapps`, () => { await webWallet.login.success(credentials) }) - test("Connect from Dapp", async ({ webWallet, browserContext }) => { + test("Connect from Dapp", async ({ webWallet, dApp }) => { await webWallet.dapps.requestConnectionFromDapp({ - browserContext, + dApp, dappUrl: "https://dapp-argentlabs.vercel.app", credentials: config.validLogin, newAccount: false, diff --git a/packages/e2e/webwallet/src/specs/login.spec.ts b/packages/e2e/webwallet/src/specs/login.spec.ts index 86a3e9ce2..2bc553a6f 100644 --- a/packages/e2e/webwallet/src/specs/login.spec.ts +++ b/packages/e2e/webwallet/src/specs/login.spec.ts @@ -19,6 +19,11 @@ test.describe(`Login page`, () => { await webWallet.login.success() }) + test("Assets page has loaded", async ({ webWallet }) => { + await webWallet.login.success() + await webWallet.assets.assetPageHasLoaded() + }) + test("wrong password", async ({ webWallet }) => { await webWallet.login.email.fill(config.validLogin.email) await webWallet.login.fillPin(config.validLogin.pin) diff --git a/packages/e2e/webwallet/src/test.ts b/packages/e2e/webwallet/src/test.ts index 5d2e57b53..02cca95fd 100644 --- a/packages/e2e/webwallet/src/test.ts +++ b/packages/e2e/webwallet/src/test.ts @@ -45,7 +45,7 @@ async function createContext({ return context } -function createPage() { +function createPage(pageType: "WebWallet" | "DApp" = "WebWallet") { return async ( { browser }: { browser: Browser }, use: any, @@ -56,20 +56,24 @@ function createPage() { const context = await createContext({ browser, testInfo, - name: "WebWallet", + name: pageType, baseURL: url, }) const page = await context.newPage() - - const webWalletPage = new WebWalletPage(page) - await webWalletPage.open() browserCtx = context - await use(webWalletPage) + if (pageType === "WebWallet") { + const webWalletPage = new WebWalletPage(page) + await webWalletPage.open() + await use(webWalletPage) + } else { + await use(page) + } + const keepArtifacts = isKeepArtifacts(testInfo) if (keepArtifacts) { - await saveHtml(testInfo, page, "WebWallet") + await saveHtml(testInfo, page, pageType) await context.close() - await keepVideos(testInfo, page, "WebWallet") + await keepVideos(testInfo, page, pageType) } else { await context.close() } @@ -84,6 +88,7 @@ function getContext() { const test = testBase.extend({ webWallet: createPage(), browserContext: getContext(), + dApp: createPage("DApp"), }) export default test diff --git a/packages/eslint-plugin-local/src/code-import-patterns.ts b/packages/eslint-plugin-local/src/code-import-patterns.ts index fb31562ad..8217337f9 100644 --- a/packages/eslint-plugin-local/src/code-import-patterns.ts +++ b/packages/eslint-plugin-local/src/code-import-patterns.ts @@ -72,7 +72,10 @@ function checkImport( const rootBasedImportPath = path.relative(REPO_ROOT, fullImportPath) for (const pattern of option.disallow) { - if (minimatch(rootBasedImportPath, pattern)) { + if ( + minimatch(rootBasedImportPath, pattern) || + minimatch(importPath, pattern) + ) { const defaultMessage = `import ${option.disallow.join(" or ")} from ${ option.target } is disallowed` diff --git a/packages/extension/.eslintrc.js b/packages/extension/.eslintrc.js index 6d0205de9..825c45c93 100644 --- a/packages/extension/.eslintrc.js +++ b/packages/extension/.eslintrc.js @@ -16,23 +16,15 @@ module.exports = { ], "@argent/local/code-import-patterns": [ "error", - { - target: "packages/extension/src/ui/**", - disallow: ["packages/extension/src/background/**"], - message: "import background from ui is disallowed", - }, { target: "packages/extension/src/background/**", - disallow: ["packages/extension/src/ui/**"], - message: "import ui from background is disallowed", + disallow: ["@argent/x-ui"], + message: "import @argent/x-ui from background is disallowed", }, { target: "packages/extension/src/shared/**", - disallow: [ - "packages/extension/src/ui/**", - "packages/extension/src/background/**", - ], - message: "import ui or background from shared is disallowed", + disallow: ["@argent/x-ui", "packages/extension/src/background/**"], + message: "import @argent/x-ui or background from shared is disallowed", }, ], }, diff --git a/packages/extension/CHANGELOG.md b/packages/extension/CHANGELOG.md index 3bbca7b10..374dcec58 100644 --- a/packages/extension/CHANGELOG.md +++ b/packages/extension/CHANGELOG.md @@ -1,5 +1,59 @@ # @argent-x/extension +## 6.14.4 + +### Patch Changes + +- 5f66f543d: Release + +## 6.14.3 + +### Patch Changes + +- aedfe8346: Release + +## 6.14.2 + +### Patch Changes + +- 0d7ea7bd8: Release + +## 6.14.1 + +### Patch Changes + +- daf3f9026: Release + +## 6.14.0 + +### Minor Changes + +- 7f839da37: Release + +## 6.13.8 + +### Patch Changes + +- 930d23f69: Release + +## 6.13.7 + +### Patch Changes + +- ab2e6c587: Release + +## 6.13.6 + +### Patch Changes + +- dedbdcb8d: Release + +## 6.13.5 + +### Patch Changes + +- 9179772ad: Release + ## 6.13.4 ### Patch Changes diff --git a/packages/extension/ampli.json b/packages/extension/ampli.json new file mode 100644 index 000000000..094606d06 --- /dev/null +++ b/packages/extension/ampli.json @@ -0,0 +1,14 @@ +{ + "Zone": "eu", + "OrgId": "100001676", + "WorkspaceId": "d898dc13-a4ff-4261-bcbd-66d96e65841a", + "SourceId": "c0973ae9-a369-4593-943f-1129ee98144d", + "Branch": "main", + "Version": "2.0.0", + "VersionId": "21095e9a-a2da-4853-9336-042690b8c4c0", + "Runtime": "browser:typescript-ampli-v2", + "Platform": "Browser", + "Language": "TypeScript", + "SDK": "@amplitude/analytics-browser@^1.0", + "Path": "./src/ampli" +} diff --git a/packages/extension/manifest/v2.json b/packages/extension/manifest/v2.json index aded2d052..3a2d37c05 100644 --- a/packages/extension/manifest/v2.json +++ b/packages/extension/manifest/v2.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/chrome-manifest.json", "name": "Argent X - Starknet Wallet", "description": "7 out of 10 Starknet users choose Argent X as their Starknet wallet. Join 2m+ Argent users now.", - "version": "5.13.4", + "version": "5.14.4", "manifest_version": 2, "browser_action": { "default_icon": { diff --git a/packages/extension/manifest/v3.json b/packages/extension/manifest/v3.json index ddec98bfc..ed74e47ac 100644 --- a/packages/extension/manifest/v3.json +++ b/packages/extension/manifest/v3.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/chrome-manifest.json", "name": "Argent X - Starknet Wallet", "description": "7 out of 10 Starknet users choose Argent X as their Starknet wallet. Join 2m+ Argent users now.", - "version": "5.13.4", + "version": "5.14.4", "manifest_version": 3, "action": { "default_icon": { diff --git a/packages/extension/package.json b/packages/extension/package.json index c788c90ea..50b00fb7b 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,6 +1,6 @@ { "name": "@argent-x/extension", - "version": "6.13.4", + "version": "6.14.4", "main": "index.js", "private": true, "license": "MIT", @@ -9,8 +9,9 @@ "@svgr/webpack": "^8.0.1", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.5.2", "@types/async-retry": "^1.4.5", - "@types/chrome": "^0.0.256", + "@types/chrome": "^0.0.262", "@types/fs-extra": "^11.0.1", "@types/lodash-es": "^4.17.6", "@types/object-hash": "^3.0.2", @@ -22,13 +23,13 @@ "@types/styled-components": "^5.1.25", "@types/url-join": "^4.0.1", "@types/ws": "^8.5.3", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", "@vitejs/plugin-react-swc": "^3.3.1", - "@vitest/browser": "1.2.0", + "@vitest/browser": "1.3.1", "@vitest/coverage-istanbul": "^1.0.0", - "@vitest/coverage-v8": "1.2.0", - "@vitest/ui": "1.2.0", + "@vitest/coverage-v8": "1.3.1", + "@vitest/ui": "1.3.1", "chokidar": "^3.5.2", "concurrently": "^8.0.1", "copy-webpack-plugin": "^12.0.0", @@ -55,7 +56,7 @@ "typescript-styled-plugin": "^0.18.2", "url-loader": "^4.1.1", "vite": "^5.0.0", - "vitest": "1.2.0", + "vitest": "1.3.1", "wait-for-expect": "^3.0.2", "webpack": "^5.88.0", "webpack-cli": "^5.1.1", @@ -72,18 +73,22 @@ "test": "vitest run", "test:watch": "vitest", "test:ci": "vitest run --coverage", - "export": "ts-node ./scripts/export.ts" + "export": "ts-node ./scripts/export.ts", + "gen:theme-typings": "chakra-cli tokens ./node_modules/@argent/x-ui/dist/x-ui.es.js", + "setup": "pnpm gen:theme-typings" }, "dependencies": { + "@amplitude/analytics-browser": "^2.4.1", "@argent/guardian": "^6.3.1", - "@argent/shared": "^6.3.3", + "@argent/x-shared": "1.1.7", "@argent/stack-router": "^6.3.1", - "@argent/ui": "^6.3.1", + "@argent/x-ui": "^1.0.2", "@argent/x-multicall": "^7.0.12", "@argent/x-sessions": "^6.5.2", "@argent/x-window": "^6.3.1", + "@chakra-ui/cli": "^2.4.1", "@chakra-ui/icons": "^2.0.15", - "@chakra-ui/react": "^2.6.1", + "@chakra-ui/react": "^2.8.2", "@ethersproject/bignumber": "^5.7.0", "@extend-chrome/messages": "^1.2.2", "@google/model-viewer": "^3.0.0", @@ -95,14 +100,11 @@ "@noble/hashes": "^1.3.1", "@scure/bip32": "^1.3.1", "@scure/bip39": "^1.2.1", - "@sentry/react": "^7.6.0", - "@sentry/tracing": "^7.6.0", "@tippyjs/react": "^4.2.6", "@trpc/client": "^10.28.0", "@trpc/server": "^10.31.0", "@vitest/coverage-istanbul": "^1.0.0", "async-retry": "^1.3.3", - "bignumber.js": "^9.1.2", "colord": "^2.9.3", "dexie": "^3.2.2", "dexie-react-hooks": "^1.1.1", @@ -128,9 +130,9 @@ "react-textarea-autosize": "^8.3.4", "semver": "^7.5.2", "starknet": "5.25.0", - "starknet6": "npm:starknet@6.0.0-beta.11", "starknet4": "npm:starknet@4.22.0", "starknet4-deprecated": "npm:starknet@4.4.0", + "starknet6": "npm:starknet@6.0.0-beta.13", "styled-components": "^5.3.5", "styled-normalize": "^8.0.7", "superjson": "^2.2.1", diff --git a/packages/extension/src/ampli/index.ts b/packages/extension/src/ampli/index.ts new file mode 100644 index 000000000..2abe83a2d --- /dev/null +++ b/packages/extension/src/ampli/index.ts @@ -0,0 +1,416 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * Ampli - A strong typed wrapper for your Analytics + * + * This file is generated by Amplitude. + * To update run 'ampli pull argent-x' + * + * Required dependencies: @amplitude/analytics-browser@^1.3.0 + * Tracking Plan Version: 2 + * Build: 1.0.0 + * Runtime: browser:typescript-ampli-v2 + * + * [View Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest) + * + * [Full Setup Instructions](https://data.eu.amplitude.com/argent/Argent%20(dev)/implementation/argent-x) + */ + +import * as amplitude from "@amplitude/analytics-browser" + +export type Environment = "argentdev" + +export const ApiKey: Record = { + argentdev: "2588167f290d46029e53ddfa3e6f4353", +} + +/** + * Default Amplitude configuration options. Contains tracking plan information. + */ +export const DefaultConfiguration: BrowserOptions = { + plan: { + version: "2", + branch: "main", + source: "argent-x", + versionId: "21095e9a-a2da-4853-9336-042690b8c4c0", + }, + ...{ + ingestionMetadata: { + sourceName: "browser-typescript-ampli", + sourceVersion: "2.0.0", + }, + }, + serverZone: amplitude.Types.ServerZone.EU, +} + +export interface LoadOptionsBase { + disabled?: boolean +} + +export type LoadOptionsWithEnvironment = LoadOptionsBase & { + environment: Environment + client?: { configuration?: BrowserOptions } +} +export type LoadOptionsWithApiKey = LoadOptionsBase & { + client: { apiKey: string; configuration?: BrowserOptions } +} +export type LoadOptionsWithClientInstance = LoadOptionsBase & { + client: { instance: BrowserClient } +} + +export type LoadOptions = + | LoadOptionsWithEnvironment + | LoadOptionsWithApiKey + | LoadOptionsWithClientInstance + +export interface AccountCreatedProperties { + "account index": string + "account type": string +} + +export interface AccountDeployedProperties { + "account index": string + "account type": string +} + +export interface DappPreauthorizedProperties { + host: string +} + +export interface OnboardingAnalyticsDecidedProperties { + "analytics activated": boolean +} + +export interface OnboardingCompletedProperties { + "account type": string +} + +export class AccountCreated implements BaseEvent { + event_type = "Account Created" + + constructor(public event_properties: AccountCreatedProperties) { + this.event_properties = event_properties + } +} + +export class AccountDeployed implements BaseEvent { + event_type = "Account Deployed" + + constructor(public event_properties: AccountDeployedProperties) { + this.event_properties = event_properties + } +} + +export class ApplicationOpened implements BaseEvent { + event_type = "Application Opened" +} + +export class DappPreauthorized implements BaseEvent { + event_type = "Dapp Preauthorized" + + constructor(public event_properties: DappPreauthorizedProperties) { + this.event_properties = event_properties + } +} + +export class OnboardingAnalyticsDecided implements BaseEvent { + event_type = "Onboarding Analytics Decided" + + constructor(public event_properties: OnboardingAnalyticsDecidedProperties) { + this.event_properties = event_properties + } +} + +export class OnboardingCompleted implements BaseEvent { + event_type = "Onboarding Completed" + + constructor(public event_properties: OnboardingCompletedProperties) { + this.event_properties = event_properties + } +} + +export class OnboardingStarted implements BaseEvent { + event_type = "Onboarding Started" +} + +export class WalletLocalStorageCleared implements BaseEvent { + event_type = "Wallet Local Storage Cleared" +} + +export class WalletRestored implements BaseEvent { + event_type = "Wallet Restored" +} + +export type PromiseResult = { promise: Promise } + +const getVoidPromiseResult = () => ({ promise: Promise.resolve() }) + +// prettier-ignore +export class Ampli { + private disabled: boolean = false; + private amplitude?: BrowserClient; + + get client(): BrowserClient { + this.isInitializedAndEnabled(); + return this.amplitude!; + } + + get isLoaded(): boolean { + return this.amplitude != null; + } + + private isInitializedAndEnabled(): boolean { + if (!this.amplitude) { + console.error('ERROR: Ampli is not yet initialized. Have you called ampli.load() on app start?'); + return false; + } + return !this.disabled; + } + + /** + * Initialize the Ampli SDK. Call once when your application starts. + * + * @param options Configuration options to initialize the Ampli SDK with. + */ + load(options: LoadOptions): PromiseResult { + this.disabled = options.disabled ?? false; + + if (this.amplitude) { + console.warn('WARNING: Ampli is already intialized. Ampli.load() should be called once at application startup.'); + return getVoidPromiseResult(); + } + + let apiKey: string | null = null; + if (options.client && 'apiKey' in options.client) { + apiKey = options.client.apiKey; + } else if ('environment' in options) { + apiKey = ApiKey[options.environment]; + } + + if (options.client && 'instance' in options.client) { + this.amplitude = options.client.instance; + } else if (apiKey) { + this.amplitude = amplitude.createInstance(); + const configuration = (options.client && 'configuration' in options.client) ? options.client.configuration : {}; + return this.amplitude.init(apiKey, undefined, { ...DefaultConfiguration, ...configuration }); + } else { + console.error("ERROR: ampli.load() requires 'environment', 'client.apiKey', or 'client.instance'"); + } + + return getVoidPromiseResult(); + } + + /** + * Identify a user and set user properties. + * + * @param userId The user's id. + * @param options Optional event options. + */ + identify( + userId: string | undefined, + options?: EventOptions, + ): PromiseResult { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + + if (userId) { + options = {...options, user_id: userId}; + } + + const amplitudeIdentify = new amplitude.Identify(); + return this.amplitude!.identify( + amplitudeIdentify, + options, + ); + } + + /** + * Flush the event. + */ + flush() : PromiseResult { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + + return this.amplitude!.flush(); + } + + /** + * Track event + * + * @param event The event to track. + * @param options Optional event options. + */ + track(event: Event, options?: EventOptions): PromiseResult { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + + return this.amplitude!.track(event, undefined, options); + } + + /** + * Account Created + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Account%20Created) + * + * Event indicating when a new "mainnet" account is successfully created on the platform. It's undeploeyd and unfunded. + * + * 2 places this is fired: 1/ Onboarding: will be fired once. 2/ Add Account (see screenshot): + * + * + * + * + * @param properties The event's properties (e.g. account index) + * @param options Amplitude event options. + */ + accountCreated( + properties: AccountCreatedProperties, + options?: EventOptions, + ) { + return this.track(new AccountCreated(properties), options); + } + + /** + * Account Deployed + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Account%20Deployed) + * + * Event to track when a user successfully deploys their account + * + * @param properties The event's properties (e.g. account index) + * @param options Amplitude event options. + */ + accountDeployed( + properties: AccountDeployedProperties, + options?: EventOptions, + ) { + return this.track(new AccountDeployed(properties), options); + } + + /** + * Application Opened + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Application%20Opened) + * + * Event to track when users open the application + * + * @param options Amplitude event options. + */ + applicationOpened( + options?: EventOptions, + ) { + return this.track(new ApplicationOpened(), options); + } + + /** + * Dapp Preauthorized + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Dapp%20Preauthorized) + * + * Event has no description in tracking plan. + * + * @param properties The event's properties (e.g. host) + * @param options Amplitude event options. + */ + dappPreauthorized( + properties: DappPreauthorizedProperties, + options?: EventOptions, + ) { + return this.track(new DappPreauthorized(properties), options); + } + + /** + * Onboarding Analytics Decided + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Onboarding%20Analytics%20Decided) + * + * Event to track user decisions and interactions during the onboarding process + * + * @param properties The event's properties (e.g. analytics activated) + * @param options Amplitude event options. + */ + onboardingAnalyticsDecided( + properties: OnboardingAnalyticsDecidedProperties, + options?: EventOptions, + ) { + return this.track(new OnboardingAnalyticsDecided(properties), options); + } + + /** + * Onboarding Completed + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Onboarding%20Completed) + * + * User completes the onboarding + * + * @param properties The event's properties (e.g. account type) + * @param options Amplitude event options. + */ + onboardingCompleted( + properties: OnboardingCompletedProperties, + options?: EventOptions, + ) { + return this.track(new OnboardingCompleted(properties), options); + } + + /** + * Onboarding Started + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Onboarding%20Started) + * + * This starts when user click "Create Wallet" Event to track when a user begins the onboarding process + * + * @param options Amplitude event options. + */ + onboardingStarted( + options?: EventOptions, + ) { + return this.track(new OnboardingStarted(), options); + } + + /** + * Wallet Local Storage Cleared + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Wallet%20Local%20Storage%20Cleared) + * + * User clears local storage. It is fired when the user access "delete local storage" buton on Settings. + * + * @param options Amplitude event options. + */ + walletLocalStorageCleared( + options?: EventOptions, + ) { + return this.track(new WalletLocalStorageCleared(), options); + } + + /** + * Wallet Restored + * + * [View in Tracking Plan](https://data.eu.amplitude.com/argent/Argent%20(dev)/events/main/latest/Wallet%20Restored) + * + * This event tracks when a user restores their wallet + * + * @param options Amplitude event options. + */ + walletRestored( + options?: EventOptions, + ) { + return this.track(new WalletRestored(), options); + } +} + +export const ampli = new Ampli() + +// BASE TYPES +type BrowserOptions = amplitude.Types.BrowserOptions + +export type BrowserClient = amplitude.Types.BrowserClient +export type BaseEvent = amplitude.Types.BaseEvent +export type IdentifyEvent = amplitude.Types.IdentifyEvent +export type GroupEvent = amplitude.Types.GroupIdentifyEvent +export type Event = amplitude.Types.Event +export type EventOptions = amplitude.Types.EventOptions +export type Result = amplitude.Types.Result diff --git a/packages/extension/src/background/__new/middleware/analytics.ts b/packages/extension/src/background/__new/middleware/analytics.ts deleted file mode 100644 index 0acc9e7ef..000000000 --- a/packages/extension/src/background/__new/middleware/analytics.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - AnyRootConfig, - MiddlewareFunction, - ProcedureParams, - TRPCError, -} from "@trpc/server" - -import type { Events } from "../../../shared/analytics" -import { analytics } from "../../analytics" - -type AnyProduceParams = ProcedureParams< - AnyRootConfig, - unknown, - unknown, - unknown, - unknown, - unknown, - unknown -> - -type SuccessArg = { - input: T["_input_out"] - ctx: T["_ctx_out"] - output: T["_output_out"] -} -type ErrorArg = { - input: T["_input_out"] - ctx: T["_ctx_out"] - error: TRPCError -} - -export function trackMiddleware< - T extends keyof Events, - Params extends AnyProduceParams, ->( - event: T, - ...[successFn, errorFn]: Events[T] extends undefined // this simplification needs a body, otherwise you can not differentiate between error and success - ? never - : [ - successFn: (arg: SuccessArg) => Events[T], - error?: (arg: ErrorArg) => Events[T], - ] -): MiddlewareFunction { - return async ({ next, ...ctx }) => { - const result = await next() - - try { - if (result.ok) { - const successPayload = successFn?.({ ...ctx, output: result.data }) - if (successPayload) { - void analytics.track(event, successPayload) - } - } else { - const errorPayload = errorFn?.({ ...ctx, error: result.error }) - if (errorPayload) { - void analytics.track(event, errorPayload) - } - } - } catch { - console.warn("Error in trackMiddleware", event) - } - - return result - } -} diff --git a/packages/extension/src/background/__new/procedures/account/create.ts b/packages/extension/src/background/__new/procedures/account/create.ts index bd2084c5e..6e5ab76ea 100644 --- a/packages/extension/src/background/__new/procedures/account/create.ts +++ b/packages/extension/src/background/__new/procedures/account/create.ts @@ -3,7 +3,6 @@ import { z } from "zod" // TODO: ⬇ should be a service which get injected in ctx import { tryToMintFeeToken } from "../../../../shared/devnet/mintFeeToken" import { createWalletAccountSchema } from "../../../../shared/wallet.model" -import { trackMiddleware } from "../../middleware/analytics" import { openSessionMiddleware } from "../../middleware/session" import { extensionOnlyProcedure } from "../permissions" @@ -20,22 +19,6 @@ export const createAccountProcedure = extensionOnlyProcedure .use(openSessionMiddleware) .input(createAccountInputSchema) .output(createWalletAccountSchema) - .use( - trackMiddleware( - "createAccount", - ({ output, input }) => ({ - status: "success", - networkId: output.networkId, - type: input.type, - }), - ({ input: { networkId, type }, error }) => ({ - status: "failure", - networkId, - type, - errorMessage: error.message, - }), - ), - ) .mutation( async ({ input: { networkId: network, type }, diff --git a/packages/extension/src/background/__new/procedures/account/upgrade.ts b/packages/extension/src/background/__new/procedures/account/upgrade.ts index 037358304..e423bc432 100644 --- a/packages/extension/src/background/__new/procedures/account/upgrade.ts +++ b/packages/extension/src/background/__new/procedures/account/upgrade.ts @@ -9,7 +9,7 @@ import { openSessionMiddleware } from "../../middleware/session" import { extensionOnlyProcedure } from "../permissions" import { getAccountClassHashFromChain } from "../../../../shared/account/details" import { networkService } from "../../../../shared/network/service" -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" const upgradeAccountSchema = z.object({ account: walletAccountSchema, diff --git a/packages/extension/src/background/__new/procedures/accountMessaging/changeGuardian.ts b/packages/extension/src/background/__new/procedures/accountMessaging/changeGuardian.ts index 2d2adc420..b41c3f862 100644 --- a/packages/extension/src/background/__new/procedures/accountMessaging/changeGuardian.ts +++ b/packages/extension/src/background/__new/procedures/accountMessaging/changeGuardian.ts @@ -5,7 +5,7 @@ import { baseWalletAccountSchema } from "../../../../shared/wallet.model" import { constants, num } from "starknet" import { getEntryPointSafe } from "../../../../shared/utils/transactions" import { AccountMessagingError } from "../../../../shared/errors/accountMessaging" -import { changeGuardianCalldataSchema } from "@argent/shared" +import { changeGuardianCalldataSchema } from "@argent/x-shared" const changeGuardianSchema = z.object({ guardian: z.string(), diff --git a/packages/extension/src/background/__new/procedures/accountMessaging/escapeAndChangeGuardian.ts b/packages/extension/src/background/__new/procedures/accountMessaging/escapeAndChangeGuardian.ts index 51a931b7c..18c306509 100644 --- a/packages/extension/src/background/__new/procedures/accountMessaging/escapeAndChangeGuardian.ts +++ b/packages/extension/src/background/__new/procedures/accountMessaging/escapeAndChangeGuardian.ts @@ -10,7 +10,7 @@ import { changeGuardianCalldataSchema, escapeGuardianCalldataSchema, isEqualAddress, -} from "@argent/shared" +} from "@argent/x-shared" const escapeAndChangeGuardianSchema = z.object({ account: baseWalletAccountSchema, diff --git a/packages/extension/src/background/__new/procedures/accountMessaging/getAccountDeploymentPayload.ts b/packages/extension/src/background/__new/procedures/accountMessaging/getAccountDeploymentPayload.ts index 39dc2a950..94283794f 100644 --- a/packages/extension/src/background/__new/procedures/accountMessaging/getAccountDeploymentPayload.ts +++ b/packages/extension/src/background/__new/procedures/accountMessaging/getAccountDeploymentPayload.ts @@ -12,7 +12,7 @@ import { addressSchema, bigNumberishSchema, rawArgsSchema, -} from "@argent/shared" +} from "@argent/x-shared" const getAccountDeploymentPayloadInputSchema = z .object({ diff --git a/packages/extension/src/background/__new/procedures/address/getAddressFromDomainName.ts b/packages/extension/src/background/__new/procedures/address/getAddressFromDomainName.ts index c9d9e87c9..9afb7f0cd 100644 --- a/packages/extension/src/background/__new/procedures/address/getAddressFromDomainName.ts +++ b/packages/extension/src/background/__new/procedures/address/getAddressFromDomainName.ts @@ -1,4 +1,4 @@ -import { addressSchema, starknetDomainNameSchema } from "@argent/shared" +import { addressSchema, starknetDomainNameSchema } from "@argent/x-shared" import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" diff --git a/packages/extension/src/background/__new/procedures/address/parseAddressOrDomain.ts b/packages/extension/src/background/__new/procedures/address/parseAddressOrDomain.ts index 7fcbfe32d..8904a84c7 100644 --- a/packages/extension/src/background/__new/procedures/address/parseAddressOrDomain.ts +++ b/packages/extension/src/background/__new/procedures/address/parseAddressOrDomain.ts @@ -1,4 +1,4 @@ -import { addressSchema, addressOrDomainSchema } from "@argent/shared" +import { addressSchema, addressOrDomainSchema } from "@argent/x-shared" import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" diff --git a/packages/extension/src/background/__new/procedures/feeToken/preferFeeToken.ts b/packages/extension/src/background/__new/procedures/feeToken/preferFeeToken.ts index a4b81b147..7ecf32d9b 100644 --- a/packages/extension/src/background/__new/procedures/feeToken/preferFeeToken.ts +++ b/packages/extension/src/background/__new/procedures/feeToken/preferFeeToken.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { extensionOnlyProcedure } from "../permissions" export const preferFeeTokenProcedure = extensionOnlyProcedure diff --git a/packages/extension/src/background/__new/procedures/swap/getSwapOrderFromTrade.ts b/packages/extension/src/background/__new/procedures/swap/getSwapOrderFromTrade.ts index a954e7a8a..10ac51075 100644 --- a/packages/extension/src/background/__new/procedures/swap/getSwapOrderFromTrade.ts +++ b/packages/extension/src/background/__new/procedures/swap/getSwapOrderFromTrade.ts @@ -2,7 +2,7 @@ import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" import { SwapOrderResponseSchema } from "../../../../shared/swap/model/order.model" import { TradeSchema } from "../../../../shared/swap/model/trade.model" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" const SwapOrderFromTradeSchema = z.object({ trade: TradeSchema, diff --git a/packages/extension/src/background/__new/procedures/swap/makeSwap.ts b/packages/extension/src/background/__new/procedures/swap/makeSwap.ts index 91f2fd44c..b9009b628 100644 --- a/packages/extension/src/background/__new/procedures/swap/makeSwap.ts +++ b/packages/extension/src/background/__new/procedures/swap/makeSwap.ts @@ -1,4 +1,4 @@ -import { callSchema } from "@argent/shared" +import { callSchema } from "@argent/x-shared" import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" diff --git a/packages/extension/src/background/__new/procedures/tokens/fetchAccountBalance.ts b/packages/extension/src/background/__new/procedures/tokens/fetchAccountBalance.ts index 7ed30b4da..2fd997de8 100644 --- a/packages/extension/src/background/__new/procedures/tokens/fetchAccountBalance.ts +++ b/packages/extension/src/background/__new/procedures/tokens/fetchAccountBalance.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" import { tokenService } from "../../../../shared/token/__new/service" diff --git a/packages/extension/src/background/__new/procedures/tokens/getAccountBalance.ts b/packages/extension/src/background/__new/procedures/tokens/getAccountBalance.ts index d8221f324..88e04d654 100644 --- a/packages/extension/src/background/__new/procedures/tokens/getAccountBalance.ts +++ b/packages/extension/src/background/__new/procedures/tokens/getAccountBalance.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" import { tokenService } from "../../../../shared/token/__new/service" diff --git a/packages/extension/src/background/__new/procedures/tokens/getAllTokenBalances.ts b/packages/extension/src/background/__new/procedures/tokens/getAllTokenBalances.ts index a327d554e..fd5d1db18 100644 --- a/packages/extension/src/background/__new/procedures/tokens/getAllTokenBalances.ts +++ b/packages/extension/src/background/__new/procedures/tokens/getAllTokenBalances.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" diff --git a/packages/extension/src/background/__new/procedures/transactionEstimate/accountDeploy.ts b/packages/extension/src/background/__new/procedures/transactionEstimate/accountDeploy.ts index 947174261..aff2081a6 100644 --- a/packages/extension/src/background/__new/procedures/transactionEstimate/accountDeploy.ts +++ b/packages/extension/src/background/__new/procedures/transactionEstimate/accountDeploy.ts @@ -3,7 +3,7 @@ import { z } from "zod" import { openSessionMiddleware } from "../../middleware/session" import { extensionOnlyProcedure } from "../permissions" import { baseWalletAccountSchema } from "../../../../shared/wallet.model" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { estimatedFeeSchema } from "../../../../shared/transactionSimulation/fees/fees.model" import { AccountError } from "../../../../shared/errors/account" import { getErrorObject } from "../../../../shared/utils/error" diff --git a/packages/extension/src/background/__new/procedures/transactionEstimate/estimate.ts b/packages/extension/src/background/__new/procedures/transactionEstimate/estimate.ts index c5e48b275..eb660d068 100644 --- a/packages/extension/src/background/__new/procedures/transactionEstimate/estimate.ts +++ b/packages/extension/src/background/__new/procedures/transactionEstimate/estimate.ts @@ -3,7 +3,7 @@ import { z } from "zod" import { openSessionMiddleware } from "../../middleware/session" import { extensionOnlyProcedure } from "../permissions" import { baseWalletAccountSchema } from "../../../../shared/wallet.model" -import { addressSchema, callSchema, ensureArray } from "@argent/shared" +import { addressSchema, callSchema, ensureArray } from "@argent/x-shared" import { callsToInvocation, extendInvocationsByAccountDeploy, diff --git a/packages/extension/src/background/__new/procedures/transactionEstimate/helpers.ts b/packages/extension/src/background/__new/procedures/transactionEstimate/helpers.ts index 84d990f3f..858d3a170 100644 --- a/packages/extension/src/background/__new/procedures/transactionEstimate/helpers.ts +++ b/packages/extension/src/background/__new/procedures/transactionEstimate/helpers.ts @@ -9,7 +9,7 @@ import { isAccountDeployed } from "../../../accountDeploy" import type { EstimatedFees } from "../../../../shared/transactionSimulation/fees/fees.model" import type { WalletAccount } from "../../../../shared/wallet.model" import type { Wallet } from "../../../wallet" -import type { Address } from "@argent/shared" +import type { Address } from "@argent/x-shared" type Invocation = Invocations[number] diff --git a/packages/extension/src/background/__new/procedures/transactionReview/simulateAndReview.ts b/packages/extension/src/background/__new/procedures/transactionReview/simulateAndReview.ts index 14ed57ea3..6eed9ca0f 100644 --- a/packages/extension/src/background/__new/procedures/transactionReview/simulateAndReview.ts +++ b/packages/extension/src/background/__new/procedures/transactionReview/simulateAndReview.ts @@ -4,7 +4,7 @@ import { openSessionMiddleware } from "../../middleware/session" import { extensionOnlyProcedure } from "../permissions" import { transactionReviewTransactionsSchema } from "../../../../shared/transactionReview/interface" import { enrichedSimulateAndReviewSchema } from "../../../../shared/transactionReview/schema" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" const simulateAndReviewSchema = z.object({ feeTokenAddress: addressSchema, diff --git a/packages/extension/src/background/__new/procedures/transfer/send.ts b/packages/extension/src/background/__new/procedures/transfer/send.ts index 0cd43e775..92b53496f 100644 --- a/packages/extension/src/background/__new/procedures/transfer/send.ts +++ b/packages/extension/src/background/__new/procedures/transfer/send.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" import { extensionOnlyProcedure } from "../permissions" diff --git a/packages/extension/src/background/__new/services/account/worker/implementation.test.ts b/packages/extension/src/background/__new/services/account/worker/implementation.test.ts index cae33e6e1..01f0d89a4 100644 --- a/packages/extension/src/background/__new/services/account/worker/implementation.test.ts +++ b/packages/extension/src/background/__new/services/account/worker/implementation.test.ts @@ -1,5 +1,5 @@ import { Mocked, describe, expect, it, vi } from "vitest" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { getMockWalletAccount } from "../../../../../../test/walletAccount.mock" import { IAccountService } from "../../../../../shared/account/service/interface" diff --git a/packages/extension/src/background/__new/services/account/worker/implementation.ts b/packages/extension/src/background/__new/services/account/worker/implementation.ts index e331f3b3d..0598aa767 100644 --- a/packages/extension/src/background/__new/services/account/worker/implementation.ts +++ b/packages/extension/src/background/__new/services/account/worker/implementation.ts @@ -1,4 +1,4 @@ -import { getAccountIdentifier } from "@argent/shared" +import { getAccountIdentifier } from "@argent/x-shared" import { IScheduleService } from "../../../../../shared/schedule/interface" import { WalletAccount } from "../../../../../shared/wallet.model" import { getAccountClassHashFromChain } from "../../../../../shared/account/details/getAccountClassHashFromChain" @@ -139,9 +139,8 @@ export class AccountWorker { async updateAccountCairoVersion(): Promise { const accounts = await this.accountService.get() - const accountsWithCairoVersion = await getAccountCairoVersionFromChain( - accounts, - ) + const accountsWithCairoVersion = + await getAccountCairoVersionFromChain(accounts) // Create a map to store accountWithCairoVersion with key as unique account id. const accountsWithCairoVersionMap = keyBy( @@ -160,9 +159,8 @@ export class AccountWorker { } async onSignerChanged(payload: AccountActivityPayload) { - const accounts = await this.accountService.getFromBaseWalletAccounts( - payload, - ) + const accounts = + await this.accountService.getFromBaseWalletAccounts(payload) const results = await Promise.allSettled( accounts.map((account) => { return getOwnerForAccount(account) @@ -180,9 +178,8 @@ export class AccountWorker { } async onGuardianChanged(payload: AccountActivityPayload) { - const accounts = await this.accountService.getFromBaseWalletAccounts( - payload, - ) + const accounts = + await this.accountService.getFromBaseWalletAccounts(payload) const results = await Promise.allSettled( accounts.map((account) => { return getGuardianForAccount(account) diff --git a/packages/extension/src/background/__new/services/activity/implementation.test.ts b/packages/extension/src/background/__new/services/activity/implementation.test.ts index 93ecdc523..40261d96d 100644 --- a/packages/extension/src/background/__new/services/activity/implementation.test.ts +++ b/packages/extension/src/background/__new/services/activity/implementation.test.ts @@ -1,6 +1,6 @@ import { Mocked, describe, expect, test, vi } from "vitest" -import { IHttpService, Token } from "@argent/shared" +import { IHttpService, Token } from "@argent/x-shared" import Emittery from "emittery" import type { IAccountService } from "../../../../shared/account/service/interface" @@ -128,7 +128,7 @@ describe("ActivityService", () => { ({ address, networkId, - } as WalletAccount), + }) as WalletAccount, ), ) @@ -138,7 +138,7 @@ describe("ActivityService", () => { ({ address, networkId, - } as Token), + }) as Token, ), ) @@ -148,7 +148,7 @@ describe("ActivityService", () => { ({ contractAddress, networkId, - } as ContractAddress), + }) as ContractAddress, ), ) diff --git a/packages/extension/src/background/__new/services/activity/implementation.ts b/packages/extension/src/background/__new/services/activity/implementation.ts index 6c0733715..50678b550 100644 --- a/packages/extension/src/background/__new/services/activity/implementation.ts +++ b/packages/extension/src/background/__new/services/activity/implementation.ts @@ -4,7 +4,7 @@ import { stripAddressZeroPadding, type Address, type IHttpService, -} from "@argent/shared" +} from "@argent/x-shared" import type Emittery from "emittery" import type { IAccountService } from "../../../../shared/account/service/interface" diff --git a/packages/extension/src/background/__new/services/activity/interface.ts b/packages/extension/src/background/__new/services/activity/interface.ts index d6ebe1993..ccae80183 100644 --- a/packages/extension/src/background/__new/services/activity/interface.ts +++ b/packages/extension/src/background/__new/services/activity/interface.ts @@ -1,4 +1,4 @@ -import type { Token } from "@argent/shared" +import type { Token } from "@argent/x-shared" import type Emittery from "emittery" import type { ContractAddress } from "../../../../shared/storage/__new/repositories/nft" diff --git a/packages/extension/src/background/__new/services/address/index.ts b/packages/extension/src/background/__new/services/address/index.ts index fb4a796e8..e0a97b1f1 100644 --- a/packages/extension/src/background/__new/services/address/index.ts +++ b/packages/extension/src/background/__new/services/address/index.ts @@ -1,4 +1,4 @@ -import { StarknetAddressService } from "@argent/shared" +import { StarknetAddressService } from "@argent/x-shared" import { ARGENT_API_BASE_URL } from "../../../../shared/api/constants" import { httpService } from "../../../../shared/http/singleton" import { getDefaultNetworkId } from "../../../../shared/network/utils" diff --git a/packages/extension/src/background/__new/services/analytics/index.ts b/packages/extension/src/background/__new/services/analytics/index.ts index 7f4dadaa5..16c46fc48 100644 --- a/packages/extension/src/background/__new/services/analytics/index.ts +++ b/packages/extension/src/background/__new/services/analytics/index.ts @@ -1,8 +1,8 @@ -import { activeStore } from "../../../../shared/analytics" +import { analyticsService } from "../../../../shared/analytics" import { backgroundUIService } from "../ui" -import { AnalyticsWorker } from "./worker" +import { AnalyticsWoker } from "./worker" -export const analyticsWorker = new AnalyticsWorker( - activeStore, +export const analyticsWorker = new AnalyticsWoker( + analyticsService, backgroundUIService, ) diff --git a/packages/extension/src/background/__new/services/analytics/worker.ts b/packages/extension/src/background/__new/services/analytics/worker.ts index abff3111f..8bc177374 100644 --- a/packages/extension/src/background/__new/services/analytics/worker.ts +++ b/packages/extension/src/background/__new/services/analytics/worker.ts @@ -1,15 +1,15 @@ -import type { IActiveStore } from "../../../../shared/analytics" -import type { IBackgroundUIService } from "../ui/interface" -import { onClose } from "../worker/schedule/decorators" +import { AnalyticsService } from "../../../../shared/analytics/implementation" +import { IBackgroundUIService } from "../ui/interface" +import { onOpen } from "../worker/schedule/decorators" import { pipe } from "../worker/schedule/pipe" -export class AnalyticsWorker { +export class AnalyticsWoker { constructor( - private readonly activeStore: IActiveStore, + private readonly analyticsService: AnalyticsService, private readonly backgroundUIService: IBackgroundUIService, ) {} - onClose = pipe(onClose(this.backgroundUIService))(async () => { - await this.activeStore.update("lastClosed") + onClose = pipe(onOpen(this.backgroundUIService))(async () => { + this.analyticsService.applicationOpened() }) } diff --git a/packages/extension/src/background/__new/services/argentAccount/implementation.ts b/packages/extension/src/background/__new/services/argentAccount/implementation.ts index 3ba06541f..27b100bba 100644 --- a/packages/extension/src/background/__new/services/argentAccount/implementation.ts +++ b/packages/extension/src/background/__new/services/argentAccount/implementation.ts @@ -23,7 +23,7 @@ import { PreferencesPayload, preferencesEndpointPayload, } from "../../../../shared/argentAccount/schema" -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import urlJoin from "url-join" import { ARGENT_ACCOUNT_URL } from "../../../../shared/api/constants" import { generateJwt } from "../../../../shared/shield/jwt" @@ -32,7 +32,10 @@ import { BaseError } from "../../../../shared/errors/baseError" export default class BackgroundArgentAccountService implements IArgentAccountServiceBackground { - constructor(private wallet: Wallet, private httpService: IHttpService) {} + constructor( + private wallet: Wallet, + private httpService: IHttpService, + ) {} async addAccount() { if (!ARGENT_SHIELD_NETWORK_ID) { @@ -151,9 +154,8 @@ export default class BackgroundArgentAccountService const localAccounts = await accountService.get( getNetworkSelector(ARGENT_SHIELD_NETWORK_ID), ) - const localAccountsWithGuardian = await accountService.get( - withGuardianSelector, - ) + const localAccountsWithGuardian = + await accountService.get(withGuardianSelector) const backendAccounts = await getBackendAccounts() /** Validate email against account state */ diff --git a/packages/extension/src/background/__new/services/discover/implementation.ts b/packages/extension/src/background/__new/services/discover/implementation.ts index 1f2d0e344..f16077018 100644 --- a/packages/extension/src/background/__new/services/discover/implementation.ts +++ b/packages/extension/src/background/__new/services/discover/implementation.ts @@ -1,4 +1,4 @@ -import { type IHttpService } from "@argent/shared" +import { type IHttpService } from "@argent/x-shared" import { RefreshInterval } from "../../../../shared/config" import type { IDebounceService } from "../../../../shared/debounce" @@ -39,18 +39,31 @@ export class DiscoverService implements IDiscoverService { if (!ARGENT_X_NEWS_URL) { return this.resetData() } - /** FIXME: cacheBust param is a temporary fix to force fresh content from static server */ - const cacheBust = Date.now() - const result = await this.httpService.get( - `${ARGENT_X_NEWS_URL}?v=${cacheBust}`, - ) + + const result = await this.httpService.get(ARGENT_X_NEWS_URL) const parsedResult = newsApiReponseSchema.safeParse(result) if (!parsedResult.success) { // on failure, ensure we don't show stale data to end user return this.resetData() } + + const { news, lastModified } = parsedResult.data + + const sortedNews = news.sort((a, b) => { + if (!a.created || !b.created) { + return 0 + } + const dateA = new Date(a.created) + const dateB = new Date(b.created) + + return dateB.getTime() - dateA.getTime() + }) + await this.discoverStore.set({ - data: parsedResult.data, + data: { + lastModified, + news: sortedNews, + }, }) } diff --git a/packages/extension/src/background/__new/services/knownDapps/implementation.ts b/packages/extension/src/background/__new/services/knownDapps/implementation.ts deleted file mode 100644 index eacaec958..000000000 --- a/packages/extension/src/background/__new/services/knownDapps/implementation.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { KnownDapp, KnownDapps, KnownDappsBackendService } from "@argent/shared" -import type { IKnownDappService } from "../../../../shared/knownDapps/interface" -import type { IKnownDappsRepository } from "../../../../shared/storage/__new/repositories/knownDapp" - -export class KnownDappService implements IKnownDappService { - constructor( - private readonly knownDappsRepository: IKnownDappsRepository, - private readonly argentKnownDappsService: KnownDappsBackendService, - ) {} - - async getDapps(): Promise { - return await this.argentKnownDappsService.getAll() - } - - async getDappByHost(host: string): Promise { - const knownDapps = await this.knownDappsRepository.get() - - const dapp = knownDapps?.find( - (knownDapp) => - knownDapp.dappUrl && - new URL(knownDapp.dappUrl).host === new URL(host).host, - ) - - return dapp ?? null - } - - async getDappByContractAddress( - contractAddress: string, - ): Promise { - const knownDapps = await this.knownDappsRepository.get() - - const dapp = knownDapps?.find((knownDapp) => - knownDapp.contracts?.some( - (contract) => - contract.address === contractAddress && contract.chain === "starknet", - ), - ) - - return dapp ?? null - } - - async upsert(dapps: KnownDapps) { - await this.knownDappsRepository.upsert(dapps) - } -} diff --git a/packages/extension/src/background/__new/services/knownDapps/index.ts b/packages/extension/src/background/__new/services/knownDapps/index.ts index 034455aab..a9e402707 100644 --- a/packages/extension/src/background/__new/services/knownDapps/index.ts +++ b/packages/extension/src/background/__new/services/knownDapps/index.ts @@ -1,14 +1,7 @@ -import { ArgentKnownDappsBackendService } from "@argent/shared" +import { ArgentKnownDappsBackendService } from "@argent/x-shared" -import { KnownDappService } from "./implementation" import { ARGENT_API_BASE_URL } from "../../../../shared/api/constants" -import { knownDappsRepository } from "../../../../shared/storage/__new/repositories/knownDapp" export const argentKnownDappsService = new ArgentKnownDappsBackendService( ARGENT_API_BASE_URL, ) - -export const knownDappsService = new KnownDappService( - knownDappsRepository, - argentKnownDappsService, -) diff --git a/packages/extension/src/background/__new/services/multisig/implementation.ts b/packages/extension/src/background/__new/services/multisig/implementation.ts index 6a0e0a46a..2b479ef94 100644 --- a/packages/extension/src/background/__new/services/multisig/implementation.ts +++ b/packages/extension/src/background/__new/services/multisig/implementation.ts @@ -3,7 +3,6 @@ import { IMultisigService, } from "../../../../shared/multisig/service/messaging/interface" import { tryToMintFeeToken } from "../../../../shared/devnet/mintFeeToken" -import { analytics } from "../../../analytics" import { getMultisigAccounts } from "../../../../shared/multisig/utils/baseMultisig" import { AddAccountPayload, @@ -29,7 +28,7 @@ import { decodeBase58Array, removeOwnersCalldataSchema, replaceSignerCalldataSchema, -} from "@argent/shared" +} from "@argent/x-shared" import { AccountError } from "../../../../shared/errors/account" import { getMultisigPendingTransaction } from "../../../../shared/multisig/pendingTransactionsStore" import { MultisigError } from "../../../../shared/errors/multisig" @@ -42,37 +41,21 @@ export default class BackgroundMultisigService implements IMultisigService { async addAccount(payload: AddAccountPayload): Promise { const { networkId, signers, threshold, creator, publicKey, updatedAt } = payload - try { - const account = await this.wallet.newAccount(networkId, "multisig", { - signers, - threshold, - creator, - publicKey, - updatedAt, - }) - await tryToMintFeeToken(account) - - void analytics.track("createAccount", { - status: "success", - networkId, - type: "multisig", - }) - const accounts = await getMultisigAccounts() + const account = await this.wallet.newAccount(networkId, "multisig", { + signers, + threshold, + creator, + publicKey, + updatedAt, + }) + await tryToMintFeeToken(account) - return { - account, - accounts, - } - } catch (error) { - void analytics.track("createAccount", { - status: "failure", - networkId: networkId, - type: "multisig", - errorMessage: `${error}`, - }) + const accounts = await getMultisigAccounts() - throw error + return { + account, + accounts, } } @@ -191,9 +174,8 @@ export default class BackgroundMultisigService implements IMultisigService { throw new AccountError({ code: "NOT_SELECTED" }) } - const multisigStarknetAccount = await this.wallet.getStarknetAccount( - selectedAccount, - ) + const multisigStarknetAccount = + await this.wallet.getStarknetAccount(selectedAccount) if (!MultisigAccount.isMultisig(multisigStarknetAccount)) { throw new AccountError({ code: "NOT_MULTISIG" }) diff --git a/packages/extension/src/background/__new/services/network/background.test.ts b/packages/extension/src/background/__new/services/network/background.test.ts index 768ebe2bd..83d6a1739 100644 --- a/packages/extension/src/background/__new/services/network/background.test.ts +++ b/packages/extension/src/background/__new/services/network/background.test.ts @@ -7,7 +7,7 @@ import { networksEqual } from "../../../../shared/network/store" import { InMemoryRepository } from "../../../../shared/storage/__new/__test__/inmemoryImplementations" import BackgroundNetworkService from "./background" import { NetworkWithStatus } from "../../../../shared/network/type" -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import { ETH_TOKEN_ADDRESS } from "../../../../shared/network/constants" describe("BackgroundNetworkService", () => { diff --git a/packages/extension/src/background/__new/services/network/background.ts b/packages/extension/src/background/__new/services/network/background.ts index d8f540a47..fcb4c1705 100644 --- a/packages/extension/src/background/__new/services/network/background.ts +++ b/packages/extension/src/background/__new/services/network/background.ts @@ -1,10 +1,10 @@ import { uniqWith } from "lodash-es" -import { Network, NetworkStatus } from "../../../../shared/network" +import { Network, ColorStatus } from "../../../../shared/network" import { INetworkRepo, networksEqual } from "../../../../shared/network/store" import { IBackgroundNetworkService } from "./interface" import { INetworkWithStatusRepo } from "../../../../shared/network/statusStore" -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import urlJoin from "url-join" import { argentApiNetworkForNetwork } from "../../../../shared/api/headers" import { ARGENT_NETWORK_STATUS } from "../../../../shared/api/constants" @@ -39,14 +39,14 @@ export default class BackgroundNetworkService if (!backendNetworkId) { return { id: network.id, - status: "unknown" as NetworkStatus, + status: "unknown" as ColorStatus, } } const url = urlJoin(ARGENT_NETWORK_STATUS, backendNetworkId) try { const response = await this.httpService.get<{ - state: NetworkStatus + state: ColorStatus }>(url) return { @@ -56,7 +56,7 @@ export default class BackgroundNetworkService } catch (error) { return { id: network.id, - status: "unknown" as NetworkStatus, + status: "unknown" as ColorStatus, } } }), diff --git a/packages/extension/src/background/__new/services/network/interface.ts b/packages/extension/src/background/__new/services/network/interface.ts index 7c68df6a9..3d32aef37 100644 --- a/packages/extension/src/background/__new/services/network/interface.ts +++ b/packages/extension/src/background/__new/services/network/interface.ts @@ -1,4 +1,4 @@ -import { Network, NetworkStatus } from "../../../../shared/network" +import { Network, ColorStatus } from "../../../../shared/network" export interface IBackgroundNetworkService { updateStatuses(): Promise @@ -6,4 +6,4 @@ export interface IBackgroundNetworkService { export type GetNetworkStatusesFn = ( networks: Network[], -) => Promise> +) => Promise> diff --git a/packages/extension/src/background/__new/services/nft/worker/implementation.ts b/packages/extension/src/background/__new/services/nft/worker/implementation.ts index 077765e4d..46b4d585e 100644 --- a/packages/extension/src/background/__new/services/nft/worker/implementation.ts +++ b/packages/extension/src/background/__new/services/nft/worker/implementation.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema, isArgentNetworkId } from "@argent/x-shared" import { uniq } from "lodash-es" import { IBackgroundUIService } from "../../ui/interface" @@ -61,6 +61,9 @@ export class NftsWorker { if (!account) { return } + if (!isArgentNetworkId(account.networkId)) { + return + } try { const nfts = await this.nftsService.getAssets( diff --git a/packages/extension/src/background/__new/services/provision/implementation.ts b/packages/extension/src/background/__new/services/provision/implementation.ts index e045b47f1..a667e8f39 100644 --- a/packages/extension/src/background/__new/services/provision/implementation.ts +++ b/packages/extension/src/background/__new/services/provision/implementation.ts @@ -1,4 +1,4 @@ -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import { IProvisionService } from "../../../../shared/provision/interface" import { ProvisionStatus } from "../../../../shared/provision/types" import { PROVISION_STATUS_ENDPOINT } from "../../../../shared/api/constants" diff --git a/packages/extension/src/background/__new/services/recovery/implementation.ts b/packages/extension/src/background/__new/services/recovery/implementation.ts index f0eb7bc21..e32209920 100644 --- a/packages/extension/src/background/__new/services/recovery/implementation.ts +++ b/packages/extension/src/background/__new/services/recovery/implementation.ts @@ -1,3 +1,4 @@ +import { analyticsService } from "../../../../shared/analytics" import { IRecoveryService } from "../../../../shared/recovery/service/interface" import { recoveredAtKeyValueStore } from "../../../../shared/recovery/storage" import { IRecoveryStorage } from "../../../../shared/recovery/types" @@ -32,6 +33,7 @@ export class BackgroundRecoveryService implements IRecoveryService { } finally { await this.updateLastRecoveredAt() await this.setIsRecovering(false) + analyticsService.walletRestored() } } @@ -57,6 +59,7 @@ export class BackgroundRecoveryService implements IRecoveryService { } finally { await this.updateLastRecoveredAt() await this.setIsRecovering(false) + analyticsService.walletRestored() } } diff --git a/packages/extension/src/background/__new/services/riskAssessment/background.ts b/packages/extension/src/background/__new/services/riskAssessment/background.ts index c0fd2e195..ce50721b6 100644 --- a/packages/extension/src/background/__new/services/riskAssessment/background.ts +++ b/packages/extension/src/background/__new/services/riskAssessment/background.ts @@ -1,4 +1,4 @@ -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import { DappContext, IRiskAssessmentService, diff --git a/packages/extension/src/background/__new/services/schedule/worker/implementation.test.ts b/packages/extension/src/background/__new/services/schedule/worker/implementation.test.ts new file mode 100644 index 000000000..6cc21ed4a --- /dev/null +++ b/packages/extension/src/background/__new/services/schedule/worker/implementation.test.ts @@ -0,0 +1,62 @@ +import { describe, expect, test, vi } from "vitest" + +import { ScheduleWorker } from "./implementation" + +describe("ScheduleWorker", () => { + const makeWorker = () => { + const alarmVersion = "v1.2.3" + + const browser = { + alarms: { + getAll: vi.fn(), + clear: vi.fn(), + }, + } + const scheduleService = { + registerImplementation: vi.fn(), + in: vi.fn(), + every: vi.fn(), + delete: vi.fn(), + onInstallAndUpgrade: vi.fn(), + onStartup: vi.fn(), + } + const scheduleWorker = new ScheduleWorker( + browser, + scheduleService, + alarmVersion, + ) + return { + scheduleWorker, + browser, + scheduleService, + alarmVersion, + } + } + test("prunes alarms with a different version", async () => { + const otherVerson = "v0.0.1" + const { scheduleWorker, browser, alarmVersion } = makeWorker() + + browser.alarms.getAll.mockResolvedValue([ + { name: `${otherVerson}::test::run1` }, + { name: `${otherVerson}::other::run1` }, + { name: `${alarmVersion}::test::run1` }, + { name: `${alarmVersion}::other::run1` }, + ]) + + await scheduleWorker.pruneAlarms() + + expect(browser.alarms.clear).toHaveBeenCalledWith( + `${otherVerson}::test::run1`, + ) + expect(browser.alarms.clear).toHaveBeenCalledWith( + `${otherVerson}::other::run1`, + ) + + expect(browser.alarms.clear).not.toHaveBeenCalledWith( + `${alarmVersion}::test::run1`, + ) + expect(browser.alarms.clear).not.toHaveBeenCalledWith( + `${alarmVersion}::other::run1`, + ) + }) +}) diff --git a/packages/extension/src/background/__new/services/schedule/worker/implementation.ts b/packages/extension/src/background/__new/services/schedule/worker/implementation.ts new file mode 100644 index 000000000..5ad3975d8 --- /dev/null +++ b/packages/extension/src/background/__new/services/schedule/worker/implementation.ts @@ -0,0 +1,46 @@ +import { ALARM_VERSION } from "../../../../../shared/schedule/constants" +import { IScheduleService } from "../../../../../shared/schedule/interface" +import { DeepPick } from "../../../../../shared/types/deepPick" +import { IS_DEV } from "../../../../../shared/utils/dev" +import { onInstallAndUpgrade } from "../../worker/schedule/decorators" +import { pipe } from "../../worker/schedule/pipe" + +export type MinimalBrowser = DeepPick< + typeof chrome, + "alarms.getAll" | "alarms.clear" +> + +export class ScheduleWorker { + constructor( + private readonly browser: MinimalBrowser, + private readonly scheduleService: IScheduleService, + private readonly alarmVersion = ALARM_VERSION, + ) {} + + runOnInstallAndUpgrade = pipe(onInstallAndUpgrade(this.scheduleService))( + async (): Promise => { + await this.pruneAlarms() + }, + ) + + async pruneAlarms() { + const allAlarms = await this.browser.alarms.getAll() + const alarmsToDelete = allAlarms + .filter((alarm) => !alarm.name.startsWith(`${this.alarmVersion}::`)) + .map((alarm) => alarm.name) + + if (!alarmsToDelete.length) { + return + } + if (IS_DEV) { + console.warn( + "Deleting browser.alarms that do not have the current ALARM_VERSION_PREFIX:", + alarmsToDelete.join(", "), + ) + } + + await Promise.allSettled( + alarmsToDelete.map((alarm) => this.browser.alarms.clear(alarm)), + ) + } +} diff --git a/packages/extension/src/background/__new/services/schedule/worker/index.ts b/packages/extension/src/background/__new/services/schedule/worker/index.ts new file mode 100644 index 000000000..b9afbd5ba --- /dev/null +++ b/packages/extension/src/background/__new/services/schedule/worker/index.ts @@ -0,0 +1,6 @@ +import browser from "webextension-polyfill" + +import { ScheduleWorker } from "./implementation" +import { chromeScheduleService } from "../../../../../shared/schedule" + +export const scheduleWorker = new ScheduleWorker(browser, chromeScheduleService) diff --git a/packages/extension/src/background/__new/services/sentry/index.ts b/packages/extension/src/background/__new/services/sentry/index.ts deleted file mode 100644 index e89bce14e..000000000 --- a/packages/extension/src/background/__new/services/sentry/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { baseSentryOptions } from "../../../../shared/sentry/options" -import { settingsStore } from "../../../../shared/settings" -import { SentryWorker } from "./worker" - -export const sentryWorker = new SentryWorker(baseSentryOptions, settingsStore) diff --git a/packages/extension/src/background/__new/services/sentry/worker.ts b/packages/extension/src/background/__new/services/sentry/worker.ts deleted file mode 100644 index 3bee666bc..000000000 --- a/packages/extension/src/background/__new/services/sentry/worker.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as Sentry from "@sentry/browser" - -import { ISettingsStorage } from "../../../../shared/settings/types" -import { KeyValueStorage } from "../../../../shared/storage" - -export class SentryWorker { - constructor( - private readonly baseSentryOptions: Sentry.BrowserOptions, - private readonly settingsStore: KeyValueStorage, - ) { - // init Sentry immediately to capture any exceptions on startup - Sentry.init({ - ...this.baseSentryOptions, - enabled: true, - }) - this.settingsStore.subscribe( - "privacyErrorReporting", - this.onSettingsStoreChange.bind(this), - ) - this.settingsStore.subscribe( - "privacyAutomaticErrorReporting", - this.onSettingsStoreChange.bind(this), - ) - // re-init with async preferences - void this.initSentry() - } - - onSettingsStoreChange() { - void this.initSentry() - } - - async initSentry() { - const privacyErrorReporting = await this.settingsStore.get( - "privacyErrorReporting", - ) - const privacyAutomaticErrorReporting = await this.settingsStore.get( - "privacyAutomaticErrorReporting", - ) - Sentry.init({ - ...this.baseSentryOptions, - enabled: privacyErrorReporting, - beforeSend(event) { - if (privacyAutomaticErrorReporting) { - return event - } - return null - }, - }) - } -} diff --git a/packages/extension/src/background/__new/services/token/worker/implementation.test.ts b/packages/extension/src/background/__new/services/token/worker/implementation.test.ts index 62d0aac7b..0d1faf241 100644 --- a/packages/extension/src/background/__new/services/token/worker/implementation.test.ts +++ b/packages/extension/src/background/__new/services/token/worker/implementation.test.ts @@ -22,7 +22,7 @@ import { getMockToken, getMockTokenPriceDetails, } from "../../../../../../test/token.mock" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { stark } from "starknet" import { BaseWalletAccount } from "../../../../../shared/wallet.model" import { BaseTokenWithBalance } from "../../../../../shared/token/__new/types/tokenBalance.model" @@ -275,12 +275,18 @@ describe("TokenWorker", () => { const mockTokenPrices: TokenPriceDetails[] = [ getMockTokenPriceDetails({ pricingId: 1 }), ] + const mockNetworks = [ + getMockNetwork({ id: "mainnet-alpha" }), + getMockNetwork({ id: "invalid-backend-network" }), + ] + + mockNetworkService.get.mockResolvedValue(mockNetworks) mockTokenService.getTokens.mockResolvedValue(mockTokens) mockTokenService.fetchTokenPricesFromBackend.mockResolvedValue( mockTokenPrices, ) - await tokenWorker.runFetchAndUpdateTokenPricesFromBackend() + await tokenWorker.runFetchAndUpdateTokensAndTokenPricesFromBackend() // Assert expect(mockTokenService.getTokens).toHaveBeenCalledWith( diff --git a/packages/extension/src/background/__new/services/token/worker/implementation.ts b/packages/extension/src/background/__new/services/token/worker/implementation.ts index 82eae4db2..1f3b69cd9 100644 --- a/packages/extension/src/background/__new/services/token/worker/implementation.ts +++ b/packages/extension/src/background/__new/services/token/worker/implementation.ts @@ -2,7 +2,7 @@ import { isArgentNetworkId, includesAddress, isEqualAddress, -} from "@argent/shared" +} from "@argent/x-shared" import { RefreshInterval } from "../../../../../shared/config" import type { IDebounceService } from "../../../../../shared/debounce" import { defaultNetwork } from "../../../../../shared/network" @@ -31,11 +31,7 @@ import { ProvisionActivity, } from "../../activity/interface" import type { IBackgroundUIService } from "../../ui/interface" -import { - every, - everyWhenOpen, - onInstallAndUpgrade, -} from "../../worker/schedule/decorators" +import { everyWhenOpen } from "../../worker/schedule/decorators" import { pipe } from "../../worker/schedule/pipe" import { mergeTokensWithDefaults } from "../../../../../shared/token/__new/repository/mergeTokens" import { ProvisionActivityPayload } from "../../../../../shared/activity/types" @@ -93,21 +89,6 @@ export class TokenWorker { return selectedAccount } - /** - * Update tokens - * Fetches tokens for all networks and updates the token service - */ - runRefreshTokenRepoWithTokensInfoFromBackend = pipe( - onInstallAndUpgrade(this.scheduleService), // This will run the function on update - every( - this.scheduleService, - RefreshInterval.SLOW, - "TokenWorker.refreshTokenRepoWithTokensInfoFromBackend", - ), // This will run the function every 5 mins - )(async (): Promise => { - await this.refreshTokenRepoWithTokensInfoFromBackend() - }) - /** * Update token balances for custom networks */ @@ -125,9 +106,10 @@ export class TokenWorker { /** * Update token prices + * Fetches tokens for all networks and updates the token service * Fetches token prices for the default network and updates the token service */ - runFetchAndUpdateTokenPricesFromBackend = pipe( + runFetchAndUpdateTokensAndTokenPricesFromBackend = pipe( everyWhenOpen( this.backgroundUIService, this.scheduleService, @@ -136,6 +118,7 @@ export class TokenWorker { "TokenWorker.fetchAndUpdateTokenPricesFromBackend", ), // This will run the function every minute when the UI is open )(async (): Promise => { + await this.refreshTokenRepoWithTokensInfoFromBackend() await this.fetchAndUpdateTokenPricesFromBackend() }) diff --git a/packages/extension/src/background/__new/services/transactionReview/background.test.ts b/packages/extension/src/background/__new/services/transactionReview/background.test.ts index 6bd9eda32..f39f57b2a 100644 --- a/packages/extension/src/background/__new/services/transactionReview/background.test.ts +++ b/packages/extension/src/background/__new/services/transactionReview/background.test.ts @@ -1,4 +1,4 @@ -import { Address, IHttpService } from "@argent/shared" +import { Address, IHttpService } from "@argent/x-shared" import { Account, EstimateFee } from "starknet6" import { Mocked, describe, expect, test, vi } from "vitest" @@ -126,7 +126,7 @@ describe("BackgroundTransactionReviewService", () => { }) }) describe("and there are errors", () => { - test("falls back to on-chain simulation", async () => { + test("do not fallback to on-chain simulation", async () => { const { backgroundTransactionReviewService, httpService, @@ -156,20 +156,9 @@ describe("BackgroundTransactionReviewService", () => { feeTokenAddress, }) - expect(fallbackToOnchainFeeEstimationSpy).toHaveBeenCalledOnce() - - expect(starknetAccount.estimateFee).toHaveBeenCalledOnce() + expect(fallbackToOnchainFeeEstimationSpy).not.toHaveBeenCalledOnce() - expect(result).toMatchObject({ - isBackendDown: true, - enrichedFeeEstimation: { - transactions: { - amount: 123n, - feeTokenAddress, - pricePerUnit: 456n, - }, - }, - }) + expect(starknetAccount.estimateFee).not.toHaveBeenCalledOnce() }) }) describe("when backend fails with error", () => { diff --git a/packages/extension/src/background/__new/services/transactionReview/background.ts b/packages/extension/src/background/__new/services/transactionReview/background.ts index adfcdbb0d..9a1f0b6f1 100644 --- a/packages/extension/src/background/__new/services/transactionReview/background.ts +++ b/packages/extension/src/background/__new/services/transactionReview/background.ts @@ -1,6 +1,6 @@ import urlJoin from "url-join" -import { type IHttpService, ensureArray, Address } from "@argent/shared" +import { type IHttpService, ensureArray, Address } from "@argent/x-shared" import { Account, CairoVersion, @@ -22,6 +22,7 @@ import { SimulateAndReview, isTransactionSimulationError, simulateAndReviewSchema, + EnrichedSimulateAndReview, } from "../../../../shared/transactionReview/schema" import { ReviewError } from "../../../../shared/errors/review" import { addEstimatedFee } from "../../../../shared/transactionSimulation/fees/estimatedFeesRepository" @@ -96,9 +97,8 @@ export default class BackgroundTransactionReviewService const bulkTransactions: Invocations = [ { type: TransactionType.DEPLOY_ACCOUNT, - payload: await this.wallet.getAccountDeploymentPayload( - selectedAccount, - ), + payload: + await this.wallet.getAccountDeploymentPayload(selectedAccount), }, { type: TransactionType.INVOKE, @@ -242,7 +242,7 @@ export default class BackgroundTransactionReviewService }: { transactions: TransactionReviewTransactions[] feeTokenAddress: Address - }) { + }): Promise { const selectedAccount = await this.wallet.getSelectedAccount() const account = await this.wallet.getSelectedStarknetAccount() const isDeploymentTransaction = transactions.some( @@ -312,18 +312,14 @@ export default class BackgroundTransactionReviewService simulateAndReviewSchema, ) - // if there is any simulation error then we should fall-back to on-chain so the user is not blocked + // if there is a simulation error then there is also no actual simulation + // or fee information, and no way to proceed with fee estimation + // returning the result will surface the error to the user in the ui const hasSimulationError = result.transactions.some((transaction) => isTransactionSimulationError(transaction), ) if (hasSimulationError) { - console.warn( - `Falling back to onchain fee estimation as there was an error in the backend simulation response:`, - result, - ) - throw new ReviewError({ - code: "BACKEND_SIMULATION_ERROR", - }) + return result } const enrichedFeeEstimation = await this.getEnrichedFeeEstimation( diff --git a/packages/extension/src/background/__new/services/transactionReview/worker/implementation.test.ts b/packages/extension/src/background/__new/services/transactionReview/worker/implementation.test.ts index 04db799ae..50f71dd9a 100644 --- a/packages/extension/src/background/__new/services/transactionReview/worker/implementation.test.ts +++ b/packages/extension/src/background/__new/services/transactionReview/worker/implementation.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test, vi } from "vitest" -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import { KeyValueStorage } from "../../../../../shared/storage" import { ITransactionReviewLabelsStore } from "../../../../../shared/transactionReview/interface" import { TransactionReviewWorker } from "./implementation" diff --git a/packages/extension/src/background/__new/services/transactionReview/worker/implementation.ts b/packages/extension/src/background/__new/services/transactionReview/worker/implementation.ts index caf2a0785..ba1fd87a2 100644 --- a/packages/extension/src/background/__new/services/transactionReview/worker/implementation.ts +++ b/packages/extension/src/background/__new/services/transactionReview/worker/implementation.ts @@ -1,4 +1,4 @@ -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import urlJoin from "url-join" import { RefreshInterval } from "../../../../../shared/config" @@ -51,9 +51,8 @@ export class TransactionReviewWorker implements ITransactionReviewWorker { async updateLabels() { try { - const labels = await this.httpService.get( - labelsEndpoint, - ) + const labels = + await this.httpService.get(labelsEndpoint) const updatedAt = Date.now() await this.labelsStore.set("labels", labels) await this.labelsStore.set("updatedAt", updatedAt) diff --git a/packages/extension/src/background/__new/services/ui/background.ts b/packages/extension/src/background/__new/services/ui/background.ts index 07f45cc56..764fbb034 100644 --- a/packages/extension/src/background/__new/services/ui/background.ts +++ b/packages/extension/src/background/__new/services/ui/background.ts @@ -8,6 +8,7 @@ import { Locked } from "../../../wallet/session/interface" import type { WalletSessionService } from "../../../wallet/session/session.service" import type { Events, IBackgroundUIService } from "./interface" import { Opened } from "./interface" +import { analyticsService } from "../../../../shared/analytics" type MinimalBrowser = DeepPick< typeof chrome, diff --git a/packages/extension/src/background/__new/trpc.ts b/packages/extension/src/background/__new/trpc.ts index ce45d4384..def746543 100644 --- a/packages/extension/src/background/__new/trpc.ts +++ b/packages/extension/src/background/__new/trpc.ts @@ -2,14 +2,14 @@ import { initTRPC } from "@trpc/server" import type { IArgentAccountServiceBackground } from "../../shared/argentAccount/interface" import { BaseError } from "../../shared/errors/baseError" -import { BaseError as SharedBaseError } from "@argent/shared" +import { BaseError as SharedBaseError } from "@argent/x-shared" import type { IMultisigService } from "../../shared/multisig/service/messaging/interface" import { MessagingKeys } from "../keys/messagingKeys" import { Wallet } from "../wallet" import type { IBackgroundActionService } from "./services/action/interface" import type { ITransactionReviewService } from "../../shared/transactionReview/interface" import type { IRecoveryService } from "../../shared/recovery/service/interface" -import type { IStarknetAddressService } from "@argent/shared" +import type { IStarknetAddressService } from "@argent/x-shared" import type { INetworkService } from "../../shared/network/service/interface" import { ISharedSwapService } from "../../shared/swap/service/interface" import superjson from "superjson" diff --git a/packages/extension/src/background/accountUpgrade.ts b/packages/extension/src/background/accountUpgrade.ts index 465e04b8d..6ac1ed0bb 100644 --- a/packages/extension/src/background/accountUpgrade.ts +++ b/packages/extension/src/background/accountUpgrade.ts @@ -5,7 +5,7 @@ import { ArgentAccountType, BaseWalletAccount } from "../shared/wallet.model" import { IBackgroundActionService } from "./__new/services/action/interface" import { Wallet } from "./wallet" import { AccountError } from "../shared/errors/account" -import { addressSchema, isAccountV5 } from "@argent/shared" +import { addressSchema, isAccountV5 } from "@argent/x-shared" export interface IUpgradeAccount { account: BaseWalletAccount wallet: Wallet diff --git a/packages/extension/src/background/actionHandlers.ts b/packages/extension/src/background/actionHandlers.ts index 516be5b49..56e502120 100644 --- a/packages/extension/src/background/actionHandlers.ts +++ b/packages/extension/src/background/actionHandlers.ts @@ -7,7 +7,7 @@ import { networkService } from "../shared/network/service" import { isEqualWalletAddress } from "../shared/wallet.service" import { assertNever } from "../shared/utils/assertNever" import { accountDeployAction } from "./accountDeployAction" -import { analytics } from "./analytics" + import { addMultisigDeployAction } from "./multisig/multisigDeployAction" import { openUi } from "./openUi" import { @@ -20,44 +20,26 @@ import { preAuthorizationService } from "../shared/preAuthorization/service" import { networkSchema } from "../shared/network" import { encodeChainId } from "../shared/utils/encodeChainId" import { IFeeTokenService } from "../shared/feeToken/service/interface" +import { analyticsService } from "../shared/analytics" const handleTransactionAction = async ({ action, - networkId, wallet, }: { action: TransactionAction networkId: string wallet: Wallet }): Promise => { - const host = action.meta.origin const actionHash = action.meta.hash try { - // void analytics.track("signedTransaction", { - // networkId, - // host, - // }) // TODO: temporary disabled - const response = await executeTransactionAction(action, wallet) - void analytics.track("sentTransaction", { - success: true, - networkId, - host, - }) - return { type: "TRANSACTION_SUBMITTED", data: { txHash: response.transaction_hash, actionHash }, } } catch (error) { - void analytics.track("sentTransaction", { - success: false, - networkId, - host, - }) - return { type: "TRANSACTION_FAILED", data: { actionHash, error: `${error}` }, @@ -82,16 +64,13 @@ export const handleActionApproval = async ( return } - void analytics.track("preauthorizeDapp", { - host, - networkId, - }) - await preAuthorizationService.add({ account: selectedAccount, host, }) - + analyticsService.dappPreauthorized({ + host, + }) return { type: "CONNECT_DAPP_RES", data: selectedAccount } } @@ -105,27 +84,12 @@ export const handleActionApproval = async ( case "DEPLOY_ACCOUNT": { try { - // void analytics.track("signedTransaction", { - // networkId, - // }) // TODO: temporary disabled - const txHash = await accountDeployAction( action, wallet, feeTokenService, ) - void analytics.track("deployAccount", { - status: "success", - trigger: "sign", - networkId: action.payload.account.networkId, - }) - - void analytics.track("sentTransaction", { - success: true, - networkId, - }) - return { type: "DEPLOY_ACCOUNT_ACTION_SUBMITTED", data: { txHash, actionHash }, @@ -136,17 +100,6 @@ export const handleActionApproval = async ( error = `${error}\n\nA 403 error means there's already something running on the selected port. On macOS, AirPlay is using port 5000 by default, so please try running your node on another port and changing the port in Argent X settings.` } - void analytics.track("sentTransaction", { - success: false, - networkId, - }) - - void analytics.track("deployAccount", { - status: "failure", - networkId: action.payload.account.networkId, - errorMessage: `${error}`, - }) - return { type: "DEPLOY_ACCOUNT_ACTION_FAILED", data: { actionHash, error: `${error}` }, @@ -156,22 +109,8 @@ export const handleActionApproval = async ( case "DEPLOY_MULTISIG": { try { - // void analytics.track("signedTransaction", { - // networkId, - // }) // TODO: temporary disabled - await addMultisigDeployAction(action, wallet) - void analytics.track("deployMultisig", { - status: "success", - trigger: "transaction", - networkId: action.payload.account.networkId, - }) - - void analytics.track("sentTransaction", { - success: true, - networkId, - }) break } catch (exception) { let error = `${exception}` @@ -180,16 +119,6 @@ export const handleActionApproval = async ( error = `${error}\n\nA 403 error means there's already something running on the selected port. On macOS, AirPlay is using port 5000 by default, so please try running your node on another port and changing the port in Argent X settings.` } - void analytics.track("sentTransaction", { - success: false, - networkId, - }) - - void analytics.track("deployMultisig", { - status: "failure", - networkId: action.payload.account.networkId, - errorMessage: `${error}`, - }) break } } @@ -231,19 +160,26 @@ export const handleActionApproval = async ( } } - const signature = await starknetAccount.signMessage(typedData) - const formattedSignature = stark.signatureToDecimalArray(signature) - - await analytics.track("signedMessage", { - networkId: selectedAccount?.networkId || "unknown", - }) + try { + const signature = await starknetAccount.signMessage(typedData) + const formattedSignature = stark.signatureToDecimalArray(signature) - return { - type: "SIGNATURE_SUCCESS", - data: { - signature: formattedSignature, - actionHash, - }, + return { + type: "SIGNATURE_SUCCESS", + data: { + signature: formattedSignature, + actionHash, + }, + } + } catch (error) { + console.error(error) + return { + type: "SIGNATURE_FAILURE", + data: { + error: `${error}`, + actionHash, + }, + } } } @@ -318,17 +254,7 @@ export const handleActionApproval = async ( case "DECLARE_CONTRACT": { try { - void analytics.track("signedDeclareTransaction", { - networkId, - }) - const { classHash, txHash } = await udcDeclareContract(action, wallet) - - void analytics.track("sentTransaction", { - success: true, - networkId, - }) - return { type: "DECLARE_CONTRACT_ACTION_SUBMITTED", data: { txHash, actionHash, classHash }, @@ -339,11 +265,6 @@ export const handleActionApproval = async ( error = `${error}\n\nA 403 error means there's already something running on the selected port. On macOS, AirPlay is using port 5000 by default, so please try running your node on another port and changing the port in Argent X settings.` } - void analytics.track("sentTransaction", { - success: false, - networkId, - }) - return { type: "DECLARE_CONTRACT_ACTION_FAILED", data: { actionHash, error: `${error}` }, @@ -353,20 +274,11 @@ export const handleActionApproval = async ( case "DEPLOY_CONTRACT": { try { - void analytics.track("signedDeployTransaction", { - networkId, - }) - const { txHash, contractAddress } = await udcDeployContract( action, wallet, ) - void analytics.track("sentTransaction", { - success: true, - networkId, - }) - return { type: "DEPLOY_CONTRACT_ACTION_SUBMITTED", data: { @@ -381,11 +293,6 @@ export const handleActionApproval = async ( error = `${error}\n\nA 403 error means there's already something running on the selected port. On macOS, AirPlay is using port 5000 by default, so please try running your node on another port and changing the port in Argent X settings.` } - void analytics.track("sentTransaction", { - success: false, - networkId, - }) - return { type: "DEPLOY_CONTRACT_ACTION_FAILED", data: { actionHash, error: `${error}` }, diff --git a/packages/extension/src/background/analytics.ts b/packages/extension/src/background/analytics.ts deleted file mode 100644 index 0ce06d879..000000000 --- a/packages/extension/src/background/analytics.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { getAnalytics } from "../shared/analytics" -import { fetchWithTimeout } from "./utils/fetchWithTimeout" - -export const analytics = getAnalytics(fetchWithTimeout) diff --git a/packages/extension/src/background/index.ts b/packages/extension/src/background/index.ts index cc72db17e..08d0797d9 100644 --- a/packages/extension/src/background/index.ts +++ b/packages/extension/src/background/index.ts @@ -1,14 +1,11 @@ -import * as Sentry from "@sentry/browser" -import browser from "webextension-polyfill" - -import { getBrowserAction } from "../shared/browser" -import { sentryWorker } from "./__new/services/sentry" +import { initAmplitude } from "../shared/analytics/init" try { - // Try to start Sentry immediately - initSentryWorker() -} catch (error) { - console.error("Exception while initialising sentryWorker", error) + initAmplitude().catch((error) => { + console.error("Error loading amplitude", error) + }) +} catch (e) { + console.error("Error loading ampli", e) } try { @@ -16,19 +13,4 @@ try { require("./init") } catch (error) { console.error("Fatal exception in background/init.ts", error) - Sentry.captureException(error) - // run on next event loop to override changes by any successful services - setTimeout(() => { - // clicking icon will start on the error screen - void getBrowserAction(browser).setPopup({ - popup: "index.html?goto=background-error", - }) - }, 0) -} - -// Prevent tree-shaking unused worker variables -function initSentryWorker() { - return { - sentryWorker, - } } diff --git a/packages/extension/src/background/messageHandling/handle.ts b/packages/extension/src/background/messageHandling/handle.ts index 382f46c26..ddcae24c7 100644 --- a/packages/extension/src/background/messageHandling/handle.ts +++ b/packages/extension/src/background/messageHandling/handle.ts @@ -26,6 +26,7 @@ import { walletSingleton } from "../walletSingleton" import { safeMessages, safeIfPreauthorizedMessages } from "./messages" import browser from "webextension-polyfill" import { feeTokenService } from "../../shared/feeToken/service" +import { z } from "zod" const handlers = [ handleAccountMessage, @@ -38,10 +39,21 @@ const handlers = [ handleUdcMessaging, ] as Array> +const argentXMessageSchema = z.object({ + type: z.string(), + payload: z.unknown().optional(), +}) + export const handleMessage = async ( [msg, sender]: [MessageType, browser.runtime.MessageSender], port?: browser.runtime.Port, ) => { + const { success } = argentXMessageSchema.safeParse(msg) + if (!success) { + console.warn("Invalid message schema received. Ignoring.") + return + } + await Promise.all([migrateWallet()]) // do migrations before handling messages const messagingKeys = await getMessagingKeys() diff --git a/packages/extension/src/background/messageHandling/messages.ts b/packages/extension/src/background/messageHandling/messages.ts index 43ebbd705..0c00e407f 100644 --- a/packages/extension/src/background/messageHandling/messages.ts +++ b/packages/extension/src/background/messageHandling/messages.ts @@ -16,10 +16,14 @@ export const safeMessages: MessageType["type"][] = [ "REQUEST_TOKEN_RES", "APPROVE_REQUEST_TOKEN", "REJECT_REQUEST_TOKEN", + "REQUEST_SELECTED_NETWORK_RES", + "REQUEST_SELECTED_NETWORK_REJ", "REQUEST_ADD_CUSTOM_NETWORK_RES", + "REQUEST_ADD_CUSTOM_NETWORK_REJ", "APPROVE_REQUEST_ADD_CUSTOM_NETWORK", "REJECT_REQUEST_ADD_CUSTOM_NETWORK", "REQUEST_SWITCH_CUSTOM_NETWORK_RES", + "REQUEST_SWITCH_CUSTOM_NETWORK_REJ", "APPROVE_REQUEST_SWITCH_CUSTOM_NETWORK", "REJECT_REQUEST_SWITCH_CUSTOM_NETWORK", "CONNECT_DAPP_RES", @@ -33,7 +37,9 @@ export const safeMessages: MessageType["type"][] = [ export const safeIfPreauthorizedMessages: MessageType["type"][] = [ "EXECUTE_TRANSACTION", "SIGN_MESSAGE", + "REQUEST_DECLARE_CONTRACT", "REQUEST_TOKEN", + "REQUEST_SELECTED_NETWORK", "REQUEST_ADD_CUSTOM_NETWORK", "REQUEST_SWITCH_CUSTOM_NETWORK", ] diff --git a/packages/extension/src/background/migrations/wallet/v5.8.1.ts b/packages/extension/src/background/migrations/wallet/v5.8.1.ts index 39c53b6ef..015e5bd11 100644 --- a/packages/extension/src/background/migrations/wallet/v5.8.1.ts +++ b/packages/extension/src/background/migrations/wallet/v5.8.1.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { STANDARD_CAIRO_0_ACCOUNT_CLASS_HASH } from "../../../shared/network/constants" import { IObjectStore, diff --git a/packages/extension/src/background/multisig/worker/implementation.ts b/packages/extension/src/background/multisig/worker/implementation.ts index 39b4d1937..a994aeafd 100644 --- a/packages/extension/src/background/multisig/worker/implementation.ts +++ b/packages/extension/src/background/multisig/worker/implementation.ts @@ -1,6 +1,6 @@ import { flatMap, isEmpty, partition } from "lodash-es" import { hash, transaction } from "starknet" -import { getChainIdFromNetworkId } from "@argent/shared" +import { getChainIdFromNetworkId } from "@argent/x-shared" import { IBackgroundUIService } from "../../../background/__new/services/ui/interface" import { IScheduleService } from "../../../shared/schedule/interface" @@ -166,9 +166,8 @@ export class MultisigWorker { address: multisig.address, networkId: multisig.networkId, } - const data = await this.multisigBackendService.fetchMultisigRequests( - account, - ) + const data = + await this.multisigBackendService.fetchMultisigRequests(account) return { ...data, account, diff --git a/packages/extension/src/background/networkMessaging.ts b/packages/extension/src/background/networkMessaging.ts index 1238e2c77..3a6fbd9ef 100644 --- a/packages/extension/src/background/networkMessaging.ts +++ b/packages/extension/src/background/networkMessaging.ts @@ -4,35 +4,65 @@ import { NetworkMessage } from "../shared/messages/NetworkMessage" import { networkService } from "../shared/network/service" import { UnhandledMessage } from "./background" import { HandleMessage } from "./background" +import { networkSchema } from "../shared/network" export const handleNetworkMessage: HandleMessage = async ({ msg, origin, - background: { actionService }, + background: { actionService, wallet }, respond, }) => { switch (msg.type) { - case "REQUEST_ADD_CUSTOM_NETWORK": { - const exists = await networkService.getByChainId(msg.data.chainId) + case "REQUEST_SELECTED_NETWORK": { + const account = await wallet.getSelectedAccount() + if (!account) { + return respond({ + type: "REQUEST_SELECTED_NETWORK_REJ", + data: { + error: "No account selected", + }, + }) + } - if (exists) { + return respond({ + type: "REQUEST_SELECTED_NETWORK_RES", + data: { + network: account.network, + }, + }) + } + + case "REQUEST_ADD_CUSTOM_NETWORK": { + const parsedCustomNetwork = networkSchema.safeParse(msg.data) + if (!parsedCustomNetwork.success) { return respond({ type: "REQUEST_ADD_CUSTOM_NETWORK_REJ", data: { - error: `Network with chainId ${msg.data.chainId} already exists`, + error: parsedCustomNetwork.error.message, }, }) } - const { meta } = await actionService.add({ - type: "REQUEST_ADD_CUSTOM_NETWORK", - payload: msg.data, - }) + const network = await networkService.getByChainId( + parsedCustomNetwork.data.chainId, + ) + + const exists = Boolean(network) + let actionHash: string | undefined + if (!exists) { + const { meta } = await actionService.add({ + type: "REQUEST_ADD_CUSTOM_NETWORK", + payload: parsedCustomNetwork.data, + }) + + actionHash = meta.hash + } return respond({ type: "REQUEST_ADD_CUSTOM_NETWORK_RES", data: { - actionHash: meta.hash, + exists, + actionHash, }, }) } @@ -45,29 +75,28 @@ export const handleNetworkMessage: HandleMessage = async ({ isHexChainId ? shortString.decodeShortString(chainId) : chainId, ) - if (!network) { - return respond({ - type: "REQUEST_SWITCH_CUSTOM_NETWORK_REJ", - data: { - error: `Network with chainId ${chainId} does not exist. Please add the network with wallet_addStarknetChain request`, + const exists = Boolean(network) + let actionHash: string | undefined + if (exists) { + // Switch only if network exists + const { meta } = await actionService.add( + { + type: "REQUEST_SWITCH_CUSTOM_NETWORK", + payload: network, }, - }) - } + { + origin, + }, + ) - const { meta } = await actionService.add( - { - type: "REQUEST_SWITCH_CUSTOM_NETWORK", - payload: network, - }, - { - origin, - }, - ) + actionHash = meta.hash + } return respond({ type: "REQUEST_SWITCH_CUSTOM_NETWORK_RES", data: { - actionHash: meta.hash, + actionHash, + exists, }, }) } diff --git a/packages/extension/src/background/preAuthorizationMessaging.ts b/packages/extension/src/background/preAuthorizationMessaging.ts index 107125591..eaebffefa 100644 --- a/packages/extension/src/background/preAuthorizationMessaging.ts +++ b/packages/extension/src/background/preAuthorizationMessaging.ts @@ -26,6 +26,28 @@ export const handlePreAuthorizationMessage: HandleMessage< let selectedAccount = await wallet.getSelectedAccount() let didOpenProgramatically = false + const silent = msg.data?.silent ?? false + if (silent) { + /** If asked for silent connection, just check if an account is selected and isPreAuthorized + * Do not open the UI to unlock the wallet or prompt the user to connect to the dapp + */ + if ( + selectedAccount && + (await preAuthorizationService.isPreAuthorized({ + account: selectedAccount, + host: origin, + })) + ) { + return respond({ + type: "CONNECT_DAPP_RES", + data: selectedAccount, + }) + } + return respond({ + type: "REJECT_PREAUTHORIZATION", + }) + } + if (!selectedAccount) { didOpenProgramatically = true const openAndUnlocked = await backgroundUIService.openUiAndUnlock() diff --git a/packages/extension/src/background/tokenMessaging.ts b/packages/extension/src/background/tokenMessaging.ts index 71ab85d1b..734dce7ef 100644 --- a/packages/extension/src/background/tokenMessaging.ts +++ b/packages/extension/src/background/tokenMessaging.ts @@ -18,6 +18,7 @@ export const handleTokenMessaging: HandleMessage = async ({ selectedAccount?.networkId ?? msg.data.networkId ?? defaultNetwork.id, }) const exists = Boolean(token) + let actionHash: string | undefined if (!exists) { const { meta } = await actionService.add( @@ -30,17 +31,15 @@ export const handleTokenMessaging: HandleMessage = async ({ }, ) - return respond({ - type: "REQUEST_TOKEN_RES", - data: { - actionHash: meta.hash, - }, - }) + actionHash = meta.hash } return respond({ type: "REQUEST_TOKEN_RES", - data: {}, + data: { + exists, + actionHash, + }, }) } diff --git a/packages/extension/src/background/transactions/service/starknet.service.test.ts b/packages/extension/src/background/transactions/service/starknet.service.test.ts new file mode 100644 index 000000000..4eddb4c33 --- /dev/null +++ b/packages/extension/src/background/transactions/service/starknet.service.test.ts @@ -0,0 +1,162 @@ +import { describe, vi } from "vitest" +import { TransactionTrackerWorker } from "./starknet.service" +import { mockChainService } from "../../../shared/chain/service/__test__/mock" +import { MockFnRepository } from "../../../shared/storage/__new/__test__/mockFunctionImplementation" +import { Transaction } from "../../../shared/transactions" +import { createScheduleServiceMock } from "../../../shared/schedule/mock" +import { IScheduleService } from "../../../shared/schedule/interface" +import { IBackgroundUIService } from "../../__new/services/ui/interface" +import { IDebounceService } from "../../../shared/debounce" +import { emitterMock } from "../../wallet/test.utils" +import { getMockDebounceService } from "../../../shared/debounce/mock" + +describe("TransactionTrackerWorker", () => { + let transactionsRepo: MockFnRepository + let transactionTracker: TransactionTrackerWorker + let mockScheduleService: IScheduleService + let mockBackgroundUIService: IBackgroundUIService + let mockDebounceService: IDebounceService + + beforeEach(() => { + const [, _mockScheduleService] = createScheduleServiceMock() + mockScheduleService = _mockScheduleService + + mockBackgroundUIService = { + opened: true, + emitter: emitterMock, + openUiAndUnlock: vi.fn(), + } + mockDebounceService = getMockDebounceService() + + transactionsRepo = new MockFnRepository() + transactionTracker = new TransactionTrackerWorker( + mockScheduleService, + mockChainService, + transactionsRepo, + mockBackgroundUIService, + mockDebounceService, + ) + }) + + const getMockTransaction = ( + finality_status: string, + execution_status: string, + ) => { + return { + hash: "0x01", + meta: { + isMaxSend: false, + title: "Transfer", + transactions: { + calldata: [ + "102948199182882721567420365830557897298787755780269406003718127961150842515", + "100000000000", + "0", + ], + contractAddress: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + entrypoint: "transfer", + }, + type: "INVOKE", + }, + status: { + execution_status: execution_status, + finality_status: finality_status, + }, + timestamp: Math.floor(Date.now() / 1000), + } as Transaction + } + + describe("getStaleTransactions", () => { + describe("when is has a completed status", () => { + describe("and is fresh", () => { + it.each([ + { finality_status: "RECEIVED", execution_status: "SUCCEEDED" }, + { finality_status: "REJECTED", execution_status: "SUCCEEDED" }, + { finality_status: "ACCEPTED_ON_L2", execution_status: "SUCCEEDED" }, + { finality_status: "ACCEPTED_ON_L2", execution_status: "REVERTED" }, + { finality_status: "ACCEPTED_ON_L1", execution_status: "SUCCEEDED" }, + ])( + "should return false", + async ({ finality_status, execution_status }) => { + const transaction = getMockTransaction( + finality_status, + execution_status, + ) + const isStale = transactionTracker.getStaleTransactions( + transaction, + Math.floor(Date.now() / 1000), + ) + expect(isStale).toBe(false) + }, + ) + }) + describe("and is stale", () => { + it.each([ + { finality_status: "REJECTED", execution_status: "SUCCEEDED" }, + { finality_status: "ACCEPTED_ON_L2", execution_status: "SUCCEEDED" }, + { finality_status: "ACCEPTED_ON_L2", execution_status: "REVERTED" }, + { finality_status: "ACCEPTED_ON_L1", execution_status: "SUCCEEDED" }, + ])( + "should return true", + async ({ finality_status, execution_status }) => { + const transaction = { + ...getMockTransaction(finality_status, execution_status), + timestamp: Math.floor((Date.now() - 1000 * 120) / 1000), + } as Transaction + const isStale = transactionTracker.getStaleTransactions( + transaction, + Math.floor(Date.now() / 1000), + ) + expect(isStale).toBe(true) + }, + ) + }) + }) + describe("when it has an incomplete status", () => { + describe("and is fresh", () => { + it("should return false", async () => { + const transaction = getMockTransaction("RECEIVED", "SUCCEEDED") + + const isStale = transactionTracker.getStaleTransactions( + transaction, + Math.floor(Date.now() / 1000), + ) + expect(isStale).toBe(false) + }) + }) + describe("and is stale", () => { + it("should return true", async () => { + const transaction = { + ...getMockTransaction("RECEIVED", "SUCCEEDED"), + + timestamp: Math.floor((Date.now() - 1000 * 120) / 1000), + } as Transaction + const isStale = transactionTracker.getStaleTransactions( + transaction, + Math.floor(Date.now() / 1000), + ) + expect(isStale).toBe(false) + }) + }) + }) + }) + + describe("cleanupTransactionStore", () => { + describe("when there are no transactions", () => { + it("does nothing", async () => { + transactionsRepo.get.mockResolvedValue([]) + await transactionTracker.cleanupTransactionStore() + expect(transactionsRepo.remove).toHaveBeenCalledWith([]) + }) + }) + describe("when there are stale transactions", () => { + it("does remove them", async () => { + const mockTransaction = getMockTransaction("RECEIVED", "SUCCEEDED") + transactionsRepo.get.mockResolvedValue([mockTransaction]) + await transactionTracker.cleanupTransactionStore() + expect(transactionsRepo.remove).toHaveBeenCalledWith([mockTransaction]) + }) + }) + }) +}) diff --git a/packages/extension/src/background/transactions/service/starknet.service.ts b/packages/extension/src/background/transactions/service/starknet.service.ts index ec1c0f5bc..f4f8fd27f 100644 --- a/packages/extension/src/background/transactions/service/starknet.service.ts +++ b/packages/extension/src/background/transactions/service/starknet.service.ts @@ -84,6 +84,29 @@ export class TransactionTrackerWorker await this.transactionsRepo.remove(staleTransactions) } + getStaleTransactions = (transaction: Transaction, now: number) => { + const { finality_status, execution_status } = + getTransactionStatus(transaction) + const isFailed = + execution_status === "REVERTED" || finality_status === "REJECTED" + const isSuccessful = + finality_status === "ACCEPTED_ON_L2" || + finality_status === "ACCEPTED_ON_L1" + + const isCompleted = isFailed || isSuccessful + const isStale = now - transaction.timestamp > 60 // we keep the transaction for 1 minute after it's completed, so the subscribers can react to it + return isCompleted && isStale + } + + async cleanupTransactionStore() { + const now = Math.floor(Date.now() / 1000) + + const staleTransactions = await this.transactionsRepo.get((transaction) => + this.getStaleTransactions(transaction, now), + ) + await this.transactionsRepo.remove(staleTransactions) + } + async trackTransactionsUpdates() { await this.syncTransactionRepo() } @@ -98,6 +121,7 @@ export class TransactionTrackerWorker ), )(async () => { try { + await this.cleanupTransactionStore() await this.trackTransactionsUpdates() await this.update() } catch (error) { diff --git a/packages/extension/src/background/transactions/sources/onchain.spec.ts b/packages/extension/src/background/transactions/sources/onchain.spec.ts index 5b021a465..67308312f 100644 --- a/packages/extension/src/background/transactions/sources/onchain.spec.ts +++ b/packages/extension/src/background/transactions/sources/onchain.spec.ts @@ -1,6 +1,6 @@ import { describe, expect, test, vi } from "vitest" -import { Hex } from "@argent/shared" +import { Hex } from "@argent/x-shared" import { getTransactionsUpdate } from "./onchain" import { WalletAccount } from "../../../shared/wallet.model" import { ExtendedFinalityStatus } from "../../../shared/transactions" diff --git a/packages/extension/src/background/transactions/sources/onchain.ts b/packages/extension/src/background/transactions/sources/onchain.ts index 13e49e386..8fc1bb7e2 100644 --- a/packages/extension/src/background/transactions/sources/onchain.ts +++ b/packages/extension/src/background/transactions/sources/onchain.ts @@ -1,11 +1,13 @@ import { getProvider } from "../../../shared/network" import { + SUCCESS_STATUSES, Transaction, getInFlightTransactions, - SUCCESS_STATUSES, } from "../../../shared/transactions" -import { getTransactionsStatusUpdate } from "../determineUpdates" import { getTransactionStatus } from "../../../shared/transactions/utils" +import { getTransactionsStatusUpdate } from "../determineUpdates" + +const TXN_HASH_NOT_FOUND_MSG = "Transaction hash not found" export async function getTransactionsUpdate(transactions: Transaction[]) { const transactionsToCheck = getInFlightTransactions(transactions) @@ -15,8 +17,20 @@ export async function getTransactionsUpdate(transactions: Transaction[]) { const fetchedTransactions = await Promise.allSettled( transactionsToCheck.map(async (transaction) => { const provider = getProvider(transaction.account.network) - const { finality_status, execution_status } = - await provider.getTransactionStatus(transaction.hash) + + const txStatus = await provider.getTransactionStatus(transaction.hash) + + const { finality_status, execution_status } = txStatus + + // we do not want to return the transaction if it's rejected just yet, + // as in some cases it is temporary, and don't want to show the user a false positive + if ( + finality_status === "REJECTED" && + "revert_reason" in txStatus && + txStatus.revert_reason === TXN_HASH_NOT_FOUND_MSG + ) { + return transaction + } // getTransactionStatus goes straight to the sequencer, hence it's much faster than the RPC nodes // because of that we need to wait for the RPC nodes to have a receipt as well @@ -43,8 +57,8 @@ export async function getTransactionsUpdate(transactions: Transaction[]) { ...transaction, revertReason: receipt.revert_reason, status: { - finality_status, - execution_status, + finality_status: finality_status, + execution_status: execution_status, }, } } @@ -59,8 +73,8 @@ export async function getTransactionsUpdate(transactions: Transaction[]) { return { ...transaction, status: { - finality_status, - execution_status, + finality_status: finality_status, + execution_status: execution_status, }, } }), @@ -84,6 +98,5 @@ export async function getTransactionsUpdate(transactions: Transaction[]) { }, [], ) - return getTransactionsStatusUpdate(transactions, updatedTransactions) // filter out transactions that have not changed } diff --git a/packages/extension/src/background/transactions/sources/voyager.ts b/packages/extension/src/background/transactions/sources/voyager.ts index 36668dbc3..bca3c10b4 100644 --- a/packages/extension/src/background/transactions/sources/voyager.ts +++ b/packages/extension/src/background/transactions/sources/voyager.ts @@ -4,7 +4,7 @@ import { Network } from "../../../shared/network" import { Transaction, compareTransactions } from "../../../shared/transactions" import { urlWithQuery } from "../../../shared/utils/url" import { WalletAccount } from "../../../shared/wallet.model" -import { stripAddressZeroPadding } from "@argent/shared" +import { stripAddressZeroPadding } from "@argent/x-shared" import { fetchWithTimeout } from "../../utils/fetchWithTimeout" import { mapVoyagerTransactionToTransaction } from "../transformers" import { VoyagerTransaction } from "./voyager.model" diff --git a/packages/extension/src/background/transactions/transactionExecution.ts b/packages/extension/src/background/transactions/transactionExecution.ts index ca836a5e4..544fe72f5 100644 --- a/packages/extension/src/background/transactions/transactionExecution.ts +++ b/packages/extension/src/background/transactions/transactionExecution.ts @@ -10,8 +10,7 @@ import { } from "../../shared/transactions" import { accountsEqual } from "../../shared/utils/accountsEqual" import { isAccountDeployed } from "../accountDeploy" -import { analytics } from "../analytics" -import { getNonce, increaseStoredNonce, resetStoredNonce } from "../nonce" +import { getNonce, increaseStoredNonce } from "../nonce" import { Wallet } from "../wallet" import { getEstimatedFees } from "../../shared/transactionSimulation/fees/estimatedFeesRepository" import { @@ -23,7 +22,7 @@ import { checkTransactionHash, getTransactionStatus, } from "../../shared/transactions/utils" -import { isAccountV5 } from "@argent/shared" +import { isAccountV5 } from "@argent/x-shared" import { estimatedFeeToMaxResourceBounds } from "../../shared/transactionSimulation/utils" import { SessionError } from "../../shared/errors/session" import { AccountError } from "../../shared/errors/account" @@ -51,10 +50,6 @@ export const executeTransactionAction = async ( throw new TransactionError({ code: "NO_PRE_COMPUTED_FEES" }) } - // void analytics.track("executeTransaction", { - // usesCachedFees: Boolean(preComputedFees), - // }) // TODO: temporary disabled - if (!(await wallet.isSessionOpen())) { throw new SessionError({ code: "NO_OPEN_SESSION" }) } @@ -96,8 +91,8 @@ export const executeTransactionAction = async ( const nonce = accountNeedsDeploy ? num.toHex(1) : nonceWasProvidedByUI - ? num.toHex(transactionsDetail?.nonce || 0) - : await getNonce(selectedAccount, starknetAccount) + ? num.toHex(transactionsDetail?.nonce || 0) + : await getNonce(selectedAccount, starknetAccount) const version = getTxVersionFromFeeToken( preComputedFees.transactions.feeTokenAddress, @@ -114,12 +109,6 @@ export const executeTransactionAction = async ( ) } - void analytics.track("deployAccount", { - status: "success", - trigger: "transaction", - networkId: account.networkId, - }) - await addTransaction({ hash: txHash, account, diff --git a/packages/extension/src/background/transactions/transactionMessaging.ts b/packages/extension/src/background/transactions/transactionMessaging.ts index 07a6a13a2..19b834cd7 100644 --- a/packages/extension/src/background/transactions/transactionMessaging.ts +++ b/packages/extension/src/background/transactions/transactionMessaging.ts @@ -17,7 +17,7 @@ import { AccountError } from "../../shared/errors/account" import { fetchTransactionBulkSimulation } from "../../shared/transactionSimulation/transactionSimulation.service" import { TransactionError } from "../../shared/errors/transaction" import { getEstimatedFeeFromBulkSimulation } from "../../shared/transactionSimulation/utils" -import { isAccountV4, isAccountV5 } from "@argent/shared" +import { isAccountV4, isAccountV5 } from "@argent/x-shared" import { EstimatedFees } from "../../shared/transactionSimulation/fees/fees.model" import { addEstimatedFee } from "../../shared/transactionSimulation/fees/estimatedFeesRepository" import { @@ -214,9 +214,8 @@ export const handleTransactionMessage: HandleMessage< const bulkTransactions: Invocations = [ { type: TransactionType.DEPLOY_ACCOUNT, - payload: await wallet.getAccountDeploymentPayload( - selectedAccount, - ), + payload: + await wallet.getAccountDeploymentPayload(selectedAccount), }, { type: TransactionType.DEPLOY, @@ -321,9 +320,8 @@ export const handleTransactionMessage: HandleMessage< const chainId = await starknetAccount.getChainId() - const bestFeeToken = await feeTokenService.getBestFeeToken( - selectedAccount, - ) + const bestFeeToken = + await feeTokenService.getBestFeeToken(selectedAccount) const version = getSimulationTxVersionFromFeeToken(bestFeeToken.address) const calldata = transaction.getExecuteCalldata( @@ -348,9 +346,8 @@ export const handleTransactionMessage: HandleMessage< } if (!isDeployed) { - const accountDeployPayload = await wallet.getAccountDeploymentPayload( - selectedAccount, - ) + const accountDeployPayload = + await wallet.getAccountDeploymentPayload(selectedAccount) accountDeployTransaction = { type: TransactionType.DEPLOY_ACCOUNT, @@ -441,9 +438,8 @@ export const handleTransactionMessage: HandleMessage< } if (!isDeployed) { - const accountDeployPayload = await wallet.getAccountDeploymentPayload( - selectedAccount, - ) + const accountDeployPayload = + await wallet.getAccountDeploymentPayload(selectedAccount) accountDeployTransaction = { type: TransactionType.DEPLOY_ACCOUNT, @@ -464,6 +460,7 @@ export const handleTransactionMessage: HandleMessage< const result = await fetchTransactionBulkSimulation({ invocations, + networkId: selectedAccount.networkId, chainId: chainId as any, // TODO: migrate to snjsv6 completely }) diff --git a/packages/extension/src/background/udcAction.ts b/packages/extension/src/background/udcAction.ts index 079dea2da..653f1bf3d 100644 --- a/packages/extension/src/background/udcAction.ts +++ b/packages/extension/src/background/udcAction.ts @@ -9,7 +9,6 @@ import { import { ExtQueueItem } from "../shared/actionQueue/types" import { isAccountDeployed } from "./accountDeploy" -import { analytics } from "./analytics" import { getNonce, increaseStoredNonce } from "./nonce" import { addTransaction } from "../shared/transactions/store" import { Wallet } from "./wallet" @@ -95,12 +94,6 @@ export const udcDeclareContract = async ( throw new UdcError({ code: "DEPLOY_TX_NOT_ADDED" }) } - void analytics.track("deployAccount", { - status: "success", - trigger: "transaction", - networkId: account.networkId, - }) - await addTransaction({ hash: accountDeployTxHash, account, @@ -198,12 +191,6 @@ export const udcDeployContract = async ( throw new UdcError({ code: "DEPLOY_TX_NOT_ADDED" }) } - void analytics.track("deployAccount", { - status: "success", - trigger: "transaction", - networkId: account.networkId, - }) - await addTransaction({ hash: accountDeployTxHash, account, diff --git a/packages/extension/src/background/wallet/account/starknet.service.test.ts b/packages/extension/src/background/wallet/account/starknet.service.test.ts index 6d398ffe8..5b48aab79 100644 --- a/packages/extension/src/background/wallet/account/starknet.service.test.ts +++ b/packages/extension/src/background/wallet/account/starknet.service.test.ts @@ -1,6 +1,6 @@ import { WalletAccountStarknetService } from "./starknet.service" import { WalletSessionService } from "../session/session.service" -import { WalletAccountSharedService } from "./shared.service" +import { WalletAccountSharedService } from "../../../shared/account/service/shared.service" import { WalletCryptoStarknetService } from "../crypto/starknet.service" import { MultisigAccount } from "../../../shared/multisig/account" import { diff --git a/packages/extension/src/background/wallet/account/starknet.service.ts b/packages/extension/src/background/wallet/account/starknet.service.ts index bfdff71bf..a3c7677e0 100644 --- a/packages/extension/src/background/wallet/account/starknet.service.ts +++ b/packages/extension/src/background/wallet/account/starknet.service.ts @@ -13,7 +13,7 @@ import { import { isKeyPair } from "../../keys/keyDerivation" import { WalletCryptoStarknetService } from "../crypto/starknet.service" import { WalletSessionService } from "../session/session.service" -import { WalletAccountSharedService } from "./shared.service" +import { WalletAccountSharedService } from "../../../shared/account/service/shared.service" import { SessionError } from "../../../shared/errors/session" import { AccountError } from "../../../shared/errors/account" import { IMultisigBackendService } from "../../../shared/multisig/service/backend/interface" diff --git a/packages/extension/src/background/wallet/crypto/starknet.service.ts b/packages/extension/src/background/wallet/crypto/starknet.service.ts index 89490b7b9..b00eeaf57 100644 --- a/packages/extension/src/background/wallet/crypto/starknet.service.ts +++ b/packages/extension/src/background/wallet/crypto/starknet.service.ts @@ -1,4 +1,4 @@ -import { Hex, isEqualAddress } from "@argent/shared" +import { Hex, isEqualAddress } from "@argent/x-shared" import { CairoVersion, CallData, hash } from "starknet" import { withHiddenSelector } from "../../../shared/account/selectors" import { MultisigSigner } from "../../../shared/multisig/signer" @@ -18,7 +18,7 @@ import { getPathForIndex, } from "../../../shared/utils/derivationPath" -import { WalletAccountSharedService } from "../account/shared.service" +import { WalletAccountSharedService } from "../../../shared/account/service/shared.service" import { getMultisigAccountFromBaseWallet } from "../../../shared/multisig/utils/baseMultisig" import type { WalletSession } from "../session/walletSession.model" import { Network } from "../../../shared/network" @@ -31,7 +31,7 @@ import { IObjectStore, IRepository, } from "../../../shared/storage/__new/interface" -import { decodeBase58Array } from "@argent/shared" +import { decodeBase58Array } from "@argent/x-shared" import { MULTISIG_DERIVATION_PATH } from "../../../shared/wallet.service" import { sortMultisigByDerivationPath } from "../../../shared/utils/accountsMultisigSort" import { SessionError } from "../../../shared/errors/session" @@ -116,9 +116,8 @@ export class WalletCryptoStarknetService { throw new SessionError({ code: "NO_OPEN_SESSION" }) } - const account = await this.accountSharedService.getAccount( - baseWalletAccount, - ) + const account = + await this.accountSharedService.getAccount(baseWalletAccount) if (!account) { throw new AccountError({ code: "NOT_SELECTED" }) @@ -297,9 +296,8 @@ export class WalletCryptoStarknetService { public async getCalculatedMultisigAddress( baseMultisigAccount: BaseMultisigWalletAccount, ): Promise { - const multisigAccount = await getMultisigAccountFromBaseWallet( - baseMultisigAccount, - ) + const multisigAccount = + await getMultisigAccountFromBaseWallet(baseMultisigAccount) if (!multisigAccount) { throw new AccountError({ code: "MULTISIG_NOT_FOUND" }) diff --git a/packages/extension/src/background/wallet/deployment/interface.ts b/packages/extension/src/background/wallet/deployment/interface.ts index 75064f7ef..87980ddfa 100644 --- a/packages/extension/src/background/wallet/deployment/interface.ts +++ b/packages/extension/src/background/wallet/deployment/interface.ts @@ -10,7 +10,7 @@ import { WalletAccount, } from "../../../shared/wallet.model" import { EstimatedFee } from "../../../shared/transactionSimulation/fees/fees.model" -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" // Extend to support multichain type InvocationsDetails = StarknetInvocationDetails diff --git a/packages/extension/src/background/wallet/deployment/starknet.service.ts b/packages/extension/src/background/wallet/deployment/starknet.service.ts index 70fda3bbe..57e0f920c 100644 --- a/packages/extension/src/background/wallet/deployment/starknet.service.ts +++ b/packages/extension/src/background/wallet/deployment/starknet.service.ts @@ -4,7 +4,7 @@ import { isAccountV5, isContractDeployed, isEqualAddress, -} from "@argent/shared" +} from "@argent/x-shared" import { CallData, DeployAccountContractTransaction, @@ -29,13 +29,13 @@ import { WalletAccount, } from "../../../shared/wallet.model" -import { WalletAccountSharedService } from "../account/shared.service" +import { WalletAccountSharedService } from "../../../shared/account/service/shared.service" import { MULTISIG_DERIVATION_PATH, STANDARD_DERIVATION_PATH, } from "../../../shared/wallet.service" -import { getStarkPair } from "../../keys/keyDerivation" +import { getIndexForPath, getStarkPair } from "../../keys/keyDerivation" import { getNextPathIndex, getPathForIndex, @@ -59,13 +59,14 @@ import { import { AccountError } from "../../../shared/errors/account" import { EstimatedFee } from "../../../shared/transactionSimulation/fees/fees.model" import { estimatedFeeToMaxResourceBounds } from "../../../shared/transactionSimulation/utils" -import { BigNumberish, num, constants, CairoVersion } from "starknet" +import { BigNumberish, num, constants } from "starknet" import { getTxVersionFromFeeToken } from "../../../shared/utils/getTransactionVersion" import { Implementation, findImplementationForAccount, getAccountDeploymentPayload, } from "../findImplementationForAddress" +import { AnalyticsService } from "../../../shared/analytics/implementation" const { calculateContractAddressFromHash } = hash @@ -103,6 +104,7 @@ export class WalletDeploymentStarknetService private readonly cryptoStarknetService: WalletCryptoStarknetService, private readonly backupService: WalletBackupService, private readonly networkService: Pick, + private readonly analyticsService: AnalyticsService, ) {} public async deployAccount( @@ -143,7 +145,17 @@ export class WalletDeploymentStarknetService ...maxFeeOrBounds, }, ) - + const baseDerivationPath = + walletAccount.type === "multisig" + ? MULTISIG_DERIVATION_PATH + : STANDARD_DERIVATION_PATH + this.analyticsService.accountDeployed({ + "account index": getIndexForPath( + walletAccount.signer.derivationPath, + baseDerivationPath, + ).toString(), + "account type": walletAccount.type, + }) await this.accountSharedService.selectAccount(walletAccount) return { account: walletAccount, txHash: transaction_hash } @@ -249,7 +261,7 @@ export class WalletDeploymentStarknetService return { ...getAccountDeploymentPayload(cairoVersion, accountClassHash, starkPub), - version: cairoVersion as CairoVersion, + version: cairoVersion, contractAddress: walletAccount.address, } } @@ -257,9 +269,8 @@ export class WalletDeploymentStarknetService public async getMultisigDeploymentPayload( walletAccount: WalletAccount, ): Promise> { - const multisigAccount = await getMultisigAccountFromBaseWallet( - walletAccount, - ) + const multisigAccount = + await getMultisigAccountFromBaseWallet(walletAccount) if (!multisigAccount) { throw new AccountError({ code: "MULTISIG_NOT_FOUND" }) @@ -497,6 +508,7 @@ export class WalletDeploymentStarknetService classHash: addressSchema.parse(payload.classHash), // This is only true for new Cairo 1 accounts. For Cairo 0, this is the proxy contract class hash cairoVersion: type === "standardCairo0" ? "0" : "1", needsDeploy: !isDeployed, + index, } await this.walletStore.upsert([account]) @@ -510,6 +522,7 @@ export class WalletDeploymentStarknetService creator: multisigPayload.creator, publicKey: multisigPayload.publicKey, updatedAt: Date.now(), + index, }) } diff --git a/packages/extension/src/background/wallet/findImplementationForAddress.ts b/packages/extension/src/background/wallet/findImplementationForAddress.ts index 8aec29aff..cf70759fd 100644 --- a/packages/extension/src/background/wallet/findImplementationForAddress.ts +++ b/packages/extension/src/background/wallet/findImplementationForAddress.ts @@ -1,4 +1,4 @@ -import { hexSchema, isEqualAddress } from "@argent/shared" +import { hexSchema, isEqualAddress } from "@argent/x-shared" import { WalletAccount, cairoVersionSchema } from "../../shared/wallet.model" import { z } from "zod" import { diff --git a/packages/extension/src/background/wallet/index.ts b/packages/extension/src/background/wallet/index.ts index 160989f68..7934cb7a1 100644 --- a/packages/extension/src/background/wallet/index.ts +++ b/packages/extension/src/background/wallet/index.ts @@ -9,7 +9,7 @@ import { import { PendingMultisig } from "../../shared/multisig/types" import { Network } from "../../shared/network" import { BaseWalletAccount, WalletAccount } from "../../shared/wallet.model" -import { WalletAccountSharedService } from "./account/shared.service" +import { WalletAccountSharedService } from "../../shared/account/service/shared.service" import { WalletAccountStarknetService } from "./account/starknet.service" import { WalletBackupService } from "./backup/backup.service" import { WalletCryptoSharedService } from "./crypto/shared.service" @@ -19,7 +19,7 @@ import { WalletRecoverySharedService } from "./recovery/shared.service" import { WalletSessionService } from "./session/session.service" import { WalletRecoveryStarknetService } from "./recovery/starknet.service" import { ProgressCallback } from "ethers" -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" export class Wallet { constructor( diff --git a/packages/extension/src/background/wallet/recovery/shared.service.test.ts b/packages/extension/src/background/wallet/recovery/shared.service.test.ts index 19107a988..1f494c658 100644 --- a/packages/extension/src/background/wallet/recovery/shared.service.test.ts +++ b/packages/extension/src/background/wallet/recovery/shared.service.test.ts @@ -12,7 +12,7 @@ import { IRepository, } from "../../../shared/storage/__new/interface" import { WalletAccount } from "../../../shared/wallet.model" -import { WalletSession } from "../account/shared.service" +import { WalletSession } from "../../../shared/account/service/shared.service" import { emitterMock, getSessionStoreMock, diff --git a/packages/extension/src/background/wallet/recovery/starknet.service.ts b/packages/extension/src/background/wallet/recovery/starknet.service.ts index 37aa220ca..7f9234cae 100644 --- a/packages/extension/src/background/wallet/recovery/starknet.service.ts +++ b/packages/extension/src/background/wallet/recovery/starknet.service.ts @@ -1,7 +1,7 @@ -import { WalletAccountSharedService } from "./../account/shared.service" +import { WalletAccountSharedService } from "../../../shared/account/service/shared.service" import { networkIdToStarknetNetwork } from "./../../../shared/utils/starknetNetwork" import { union, partition, memoize } from "lodash-es" -import { num } from "starknet" +import { num, RpcProvider } from "starknet" import { BaseMultisigWalletAccount } from "../../../shared/wallet.model" import { @@ -41,11 +41,14 @@ import { ApiMultisigDataForSignerSchema, } from "../../../shared/multisig/multisig.model" import { RecoveryError } from "../../../shared/errors/recovery" -import { Address, isContractDeployed } from "@argent/shared" +import { Address, isContractDeployed } from "@argent/x-shared" import { getAccountContractAddress } from "../findImplementationForAddress" -import { argentApiNetworkForNetwork } from "../../../shared/api/headers" +import { + argentApiNetworkForNetwork, + argentXHeaders, +} from "../../../shared/api/headers" -const INITIAL_PUB_KEY_COUNT = 5 +const INITIAL_PUB_KEY_COUNT = 20 interface TempAccountData { account: WalletAccount @@ -87,7 +90,12 @@ export class WalletRecoveryStarknetService implements IWalletRecoveryService { STANDARD_DERIVATION_PATH, MULTISIG_DERIVATION_PATH, ].map((derivationPath) => - generatePublicKeys(secret, lastCheck, pubKeyCount, derivationPath), + generatePublicKeys( + secret, + lastCheck, + initialPubKeyCount, + derivationPath, + ), ) const tempAccountsData = await this.buildTempAccounts( @@ -104,9 +112,9 @@ export class WalletRecoveryStarknetService implements IWalletRecoveryService { accounts.push(...validAccounts, ...validMultisigs) - lastCheck += pubKeyCount + lastCheck += initialPubKeyCount - pubKeyCount = validAccounts.length + pubKeyCount = validAccounts.length + validMultisigs.length } const accountsWithDetails = await this.getAccountDetails(accounts) @@ -267,6 +275,15 @@ export class WalletRecoveryStarknetService implements IWalletRecoveryService { ) } + private async isNetworkAvailable(provider: RpcProvider) { + try { + await provider.getSpecVersion() + return true + } catch (e) { + return false + } + } + private async fetchValidAccountsFromBackend( addresses: string[], discoveryUrl: string, @@ -277,6 +294,7 @@ export class WalletRecoveryStarknetService implements IWalletRecoveryService { headers: { Accept: "application/json", "Content-Type": "application/json", + ...argentXHeaders, }, }) @@ -297,6 +315,11 @@ export class WalletRecoveryStarknetService implements IWalletRecoveryService { network: Network, ): Promise { const provider = getProvider(network) + const isNetworkAvailable = await this.isNetworkAvailable(provider) + + if (!isNetworkAvailable) { + return [] + } const validAccounts = await Promise.all( addresses.map(async (address) => @@ -323,6 +346,7 @@ export class WalletRecoveryStarknetService implements IWalletRecoveryService { headers: { Accept: "application/json", "Content-Type": "application/json", + ...argentXHeaders, }, }) diff --git a/packages/extension/src/background/wallet/session/session.service.ts b/packages/extension/src/background/wallet/session/session.service.ts index ab2a5311d..3c5c2f1a6 100644 --- a/packages/extension/src/background/wallet/session/session.service.ts +++ b/packages/extension/src/background/wallet/session/session.service.ts @@ -8,9 +8,7 @@ import { import { noop, throttle } from "lodash-es" import { SessionError } from "../../../shared/errors/session" -import { ObjectStorage } from "../../../shared/storage" import { IObjectStore } from "../../../shared/storage/__new/interface" -import { adaptObjectStorage } from "../../../shared/storage/__new/object" import { WalletBackupService, WalletStorageProps, @@ -19,16 +17,6 @@ import { WalletRecoverySharedService } from "../recovery/shared.service" import { walletToKeystore } from "../utils" import { Events, Locked } from "./interface" -/** - * @deprecated use `sessionRepo` instead - */ -export const sessionStore = new ObjectStorage(null, { - namespace: "core:wallet:session", - areaName: "session", -}) - -export const sessionRepo = adaptObjectStorage(sessionStore) - export interface WalletSession { secret: string password: string diff --git a/packages/extension/src/background/wallet/test.utils.ts b/packages/extension/src/background/wallet/test.utils.ts index 28bab549c..0985aa042 100644 --- a/packages/extension/src/background/wallet/test.utils.ts +++ b/packages/extension/src/background/wallet/test.utils.ts @@ -11,7 +11,7 @@ import { import { WalletAccountSharedService, WalletSession, -} from "./account/shared.service" +} from "../../shared/account/service/shared.service" import { WalletAccountStarknetService } from "./account/starknet.service" import { WalletBackupService } from "./backup/backup.service" import { WalletCryptoSharedService } from "./crypto/shared.service" @@ -23,6 +23,9 @@ import { WalletSessionService } from "./session/session.service" import { Wallet } from "." import { MultisigBackendService } from "../../shared/multisig/service/backend/implementation" import { WalletStorageProps } from "../../shared/wallet/walletStore" +import { AnalyticsService } from "../../shared/analytics/implementation" +import { KeyValueStorage } from "../../shared/storage" +import { ISettingsStorage } from "../../shared/settings/types" const isDev = true const isTest = true @@ -176,6 +179,11 @@ export const accountStarknetServiceMock = new WalletAccountStarknetService( multisigBackendServiceMock, ) +const analyticsServiceMock = new AnalyticsService( + accountSharedServiceMock, + getKeyValueStorage() as unknown as KeyValueStorage, +) + export const deployStarknetServiceMock = new WalletDeploymentStarknetService( getWalletStoreMock(), getMultisigStoreMock(), @@ -187,6 +195,7 @@ export const deployStarknetServiceMock = new WalletDeploymentStarknetService( cryptoStarknetServiceMock, backupServiceMock, networkServiceMock, + analyticsServiceMock, ) export const cryptoSharedServiceMock = new WalletCryptoSharedService( diff --git a/packages/extension/src/background/walletSingleton.ts b/packages/extension/src/background/walletSingleton.ts index 9b68daf79..44bddf92f 100644 --- a/packages/extension/src/background/walletSingleton.ts +++ b/packages/extension/src/background/walletSingleton.ts @@ -8,7 +8,6 @@ import { import { networkService } from "../shared/network/service" import { walletStore } from "../shared/wallet/walletStore" import { Wallet } from "./wallet" -import { WalletAccountSharedService } from "./wallet/account/shared.service" import { WalletAccountStarknetService } from "./wallet/account/starknet.service" import { WalletBackupService } from "./wallet/backup/backup.service" import { WalletCryptoSharedService } from "./wallet/crypto/shared.service" @@ -18,13 +17,13 @@ import { loadContracts } from "./wallet/loadContracts" import { WalletRecoverySharedService } from "./wallet/recovery/shared.service" import { WalletRecoveryStarknetService } from "./wallet/recovery/starknet.service" import { Events as SessionEvents } from "./wallet/session/interface" -import { - WalletSessionService, - sessionRepo, -} from "./wallet/session/session.service" +import { WalletSessionService } from "./wallet/session/session.service" import { MultisigBackendService } from "../shared/multisig/service/backend/implementation" import { ARGENT_MULTISIG_URL } from "../shared/api/constants" import { Events as RecoverySharedEvents } from "./wallet/recovery/interface" +import { accountSharedService } from "../shared/account/service" +import { sessionRepo } from "../shared/account/store/session" +import { analyticsService } from "../shared/analytics" const isDev = process.env.NODE_ENV === "development" const isTest = process.env.NODE_ENV === "test" @@ -41,14 +40,6 @@ const backupService = new WalletBackupService( networkService, ) -const accountSharedService = new WalletAccountSharedService( - walletStore, - accountRepo, - sessionRepo, - multisigBaseWalletRepo, - pendingMultisigRepo, -) - export const cryptoStarknetService = new WalletCryptoStarknetService( accountRepo, sessionRepo, @@ -106,6 +97,7 @@ const deployStarknetService = new WalletDeploymentStarknetService( cryptoStarknetService, backupService, networkService, + analyticsService, ) const cryptoSharedService = new WalletCryptoSharedService( diff --git a/packages/extension/src/background/workers.ts b/packages/extension/src/background/workers.ts index f00aeb35e..1cfcda2d9 100644 --- a/packages/extension/src/background/workers.ts +++ b/packages/extension/src/background/workers.ts @@ -1,6 +1,5 @@ import { multisigWorker } from "./multisig/worker" import { nftsWorker } from "./__new/services/nft/worker" -import { analyticsWorker } from "./__new/services/analytics" import { networkWorker } from "./__new/services/network" import { onboardingWorker } from "./__new/services/onboarding" import { tokenWorker } from "./__new/services/token/worker" @@ -10,6 +9,8 @@ import { transactionReviewWorker } from "./__new/services/transactionReview/work import { walletSessionWorker } from "./wallet/session/worker" import { preAuthorisationWorker } from "./__new/services/preAuthorization/worker" import { transactionsWorker } from "./__new/services/transactions/worker" +import { scheduleWorker } from "./__new/services/schedule/worker" +import { analyticsWorker } from "./__new/services/analytics" /** TODO: refactor: remove this facade */ export function initWorkers() { @@ -21,10 +22,11 @@ export function initWorkers() { multisigWorker, networkWorker, knownDappsWorker, - analyticsWorker, transactionReviewWorker, walletSessionWorker, preAuthorisationWorker, transactionsWorker, + scheduleWorker, + analyticsWorker, } } diff --git a/packages/extension/src/inpage/ArgentXProvider.ts b/packages/extension/src/inpage/ArgentXProvider.ts index 6aa332713..b2e77b8e3 100644 --- a/packages/extension/src/inpage/ArgentXProvider.ts +++ b/packages/extension/src/inpage/ArgentXProvider.ts @@ -1,4 +1,4 @@ -import { getChainIdFromNetworkId } from "@argent/shared" +import { getChainIdFromNetworkId } from "@argent/x-shared" import { BlockIdentifier, Call, Provider, ProviderInterface } from "starknet" import { Network, getProvider } from "../shared/network" diff --git a/packages/extension/src/inpage/index.ts b/packages/extension/src/inpage/index.ts index 4c8dfd1a0..881c84e6c 100644 --- a/packages/extension/src/inpage/index.ts +++ b/packages/extension/src/inpage/index.ts @@ -4,8 +4,10 @@ import { getProvider } from "../shared/network/provider" import { disconnectAccount } from "./account" import { ArgentXAccount } from "./ArgentXAccount" import { sendMessage, waitForMessage } from "./messageActions" -import { getIsPreauthorized } from "./messaging" import { starknetWindowObject, userEventHandlers } from "./starknetWindowObject" +import { BackwardsCompatibleStarknetWindowObject } from "@argent/x-window" +import { shortString } from "starknet" +import { isArgentNetwork } from "../shared/network/utils" const INJECT_NAMES = ["starknet", "starknet_argentX"] @@ -46,14 +48,16 @@ document.addEventListener("readystatechange", () => attachHandler()) window.addEventListener( "message", + // eslint-disable-next-line @typescript-eslint/no-misused-promises async ({ data }: MessageEvent) => { - const { starknet } = window - if (!starknet) { + if (!window.starknet) { return } + const starknet = window.starknet as BackwardsCompatibleStarknetWindowObject + if ( - (starknet.account && data.type === "CONNECT_ACCOUNT_RES") || + data.type === "CONNECT_ACCOUNT_RES" || data.type === "APPROVE_REQUEST_SWITCH_CUSTOM_NETWORK" ) { const account = @@ -61,44 +65,43 @@ window.addEventListener( ? data.data : data.data.selectedAccount - const isPreauthorized = await getIsPreauthorized() - if (!isPreauthorized) { - // disconnect so the user can see they are no longer connected - // TODO: better UX would be to also re-connect when user selects pre-authorized account - await disconnectAccount() - } else { - const walletAccountP = waitForMessage( - "CONNECT_DAPP_RES", - 10 * 60 * 1000, - ) + if ( + account && + (account.address !== starknet.selectedAddress || + account.network.chainId !== starknet.chainId) + ) { sendMessage({ type: "CONNECT_DAPP", }) + const walletAccountP = Promise.race([ + waitForMessage("CONNECT_DAPP_RES", 10 * 60 * 1000), + waitForMessage("REJECT_PREAUTHORIZATION", 10 * 60 * 1000).then( + () => "USER_ABORTED" as const, + ), + ]) const walletAccount = await walletAccountP - if (!walletAccount) { + if (!walletAccount || walletAccount === "USER_ABORTED") { return disconnectAccount() } - if ( - account && - (account.address !== starknet.selectedAddress || - account.network.chainId !== starknet.chainId) - ) { - const { address, network } = account + const { address, network } = account + const provider = getProvider(network) - starknet.selectedAddress = address - starknet.chainId = network.chainId - starknet.provider = getProvider(network) - starknet.account = new ArgentXAccount(address, starknet.provider) - for (const userEvent of userEventHandlers) { - if (userEvent.type === "accountsChanged") { - userEvent.handler([address]) - } else if (userEvent.type === "networkChanged") { - userEvent.handler(network.chainId) - } else { - assertNever(userEvent) - } + starknet.selectedAddress = address + starknet.chainId = network.chainId + starknet.provider = provider + starknet.account = new ArgentXAccount(address, provider) + for (const userEvent of userEventHandlers) { + if (userEvent.type === "accountsChanged") { + userEvent.handler([address]) + } else if (userEvent.type === "networkChanged") { + const chainId = isArgentNetwork(network) + ? shortString.encodeShortString(network.chainId) + : network.chainId + userEvent.handler(chainId as any) + } else { + assertNever(userEvent) } } } diff --git a/packages/extension/src/inpage/messaging.ts b/packages/extension/src/inpage/messaging.ts index 1183bb635..f3989d279 100644 --- a/packages/extension/src/inpage/messaging.ts +++ b/packages/extension/src/inpage/messaging.ts @@ -6,7 +6,10 @@ export const getIsPreauthorized = async () => { sendMessage({ type: "IS_PREAUTHORIZED", }) - const isPreauthorized = await waitForMessage("IS_PREAUTHORIZED_RES", 1000) + const isPreauthorized = await waitForMessage( + "IS_PREAUTHORIZED_RES", + 10 * 1000, // 10 seconds, temporary + ) return isPreauthorized } catch (e) { // ignore timeout or other error diff --git a/packages/extension/src/inpage/requestMessageHandlers.ts b/packages/extension/src/inpage/requestMessageHandlers.ts deleted file mode 100644 index 025eaa173..000000000 --- a/packages/extension/src/inpage/requestMessageHandlers.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { Address, isAddress } from "@argent/shared" -import type { - AddStarknetChainParameters, - WatchAssetParameters, -} from "@argent/x-window" - -import type { Network } from "../shared/network/type" -import { sendMessage, waitForMessage } from "./messageActions" -import { ETH_TOKEN_ADDRESS } from "../shared/network/constants" -import { inpageMessageClient } from "./trpcClient" -import { CairoVersion } from "starknet" - -export async function handleAddTokenRequest( - callParams: WatchAssetParameters, -): Promise { - if (isAddress(callParams.options.address)) { - sendMessage({ - type: "REQUEST_TOKEN", - data: { - address: callParams.options.address as Address, - symbol: callParams.options.symbol, - decimals: callParams.options.decimals, - name: callParams.options.name, - }, - }) - } - const { actionHash } = await waitForMessage("REQUEST_TOKEN_RES", 1000) - - if (!actionHash) { - // token already exists - return false - } - - sendMessage({ type: "OPEN_UI" }) - - const result = await Promise.race([ - waitForMessage( - "APPROVE_REQUEST_TOKEN", - 11 * 60 * 1000, - (x) => x.data.actionHash === actionHash, - ), - waitForMessage( - "REJECT_REQUEST_TOKEN", - 10 * 60 * 1000, - (x) => x.data.actionHash === actionHash, - ) - .then(() => "error" as const) - .catch(() => { - sendMessage({ type: "REJECT_REQUEST_TOKEN", data: { actionHash } }) - return "timeout" as const - }), - ]) - - if (result === "error") { - throw Error("User abort") - } - if (result === "timeout") { - throw Error("User action timed out") - } - - return true -} - -export async function handleAddNetworkRequest( - callParams: AddStarknetChainParameters, -): Promise { - sendMessage({ - type: "REQUEST_ADD_CUSTOM_NETWORK", - data: { - id: callParams.id, - name: callParams.chainName, - chainId: callParams.chainId, - rpcUrl: callParams.rpcUrls?.[0] ?? "", - explorerUrl: callParams.blockExplorerUrls?.[0], - accountClassHash: (callParams as any).accountImplementation, - possibleFeeTokenAddresses: [ - (callParams.nativeCurrency?.address as Address) ?? ETH_TOKEN_ADDRESS, - ], - }, - }) - - const req = await Promise.race([ - waitForMessage("REQUEST_ADD_CUSTOM_NETWORK_RES", 1000), - waitForMessage("REQUEST_ADD_CUSTOM_NETWORK_REJ", 1000), - ]) - - if ("error" in req) { - throw Error(req.error) - } - - const { actionHash } = req - - sendMessage({ type: "OPEN_UI" }) - - const result = await Promise.race([ - waitForMessage( - "APPROVE_REQUEST_ADD_CUSTOM_NETWORK", - 11 * 60 * 1000, - (x) => x.data.actionHash === actionHash, - ), - waitForMessage( - "REJECT_REQUEST_ADD_CUSTOM_NETWORK", - 10 * 60 * 1000, - (x) => x.data.actionHash === actionHash, - ) - .then(() => "error" as const) - .catch(() => { - sendMessage({ - type: "REJECT_REQUEST_ADD_CUSTOM_NETWORK", - data: { actionHash }, - }) - return "timeout" as const - }), - ]) - - if (result === "error") { - throw Error("User abort") - } - if (result === "timeout") { - throw Error("User action timed out") - } - - return true -} - -export async function handleSwitchNetworkRequest(callParams: { - chainId: Network["chainId"] -}): Promise { - sendMessage({ - type: "REQUEST_SWITCH_CUSTOM_NETWORK", - data: { chainId: callParams.chainId }, - }) - - const req = await Promise.race([ - waitForMessage("REQUEST_SWITCH_CUSTOM_NETWORK_RES", 1000), - waitForMessage("REQUEST_SWITCH_CUSTOM_NETWORK_REJ", 1000), - ]) - - if ("error" in req) { - throw Error(req.error) - } - - const { actionHash } = req - - sendMessage({ type: "OPEN_UI" }) - - const result = await Promise.race([ - waitForMessage( - "APPROVE_REQUEST_SWITCH_CUSTOM_NETWORK", - 11 * 60 * 1000, - (x) => x.data.actionHash === actionHash, - ), - waitForMessage( - "REJECT_REQUEST_SWITCH_CUSTOM_NETWORK", - 10 * 60 * 1000, - (x) => x.data.actionHash === actionHash, - ) - .then(() => "error" as const) - .catch(() => { - sendMessage({ - type: "REJECT_REQUEST_SWITCH_CUSTOM_NETWORK", - data: { actionHash }, - }) - return "timeout" as const - }), - ]) - - if (result === "error") { - throw Error("User abort") - } - if (result === "timeout") { - throw Error("User action timed out") - } - - return true -} - -interface GetDeploymentDataResult { - address: string // Represented as 'felt252' - class_hash: string // Represented as 'felt252' - salt: string // Represented as 'felt252' - calldata: string[] // Array of 'felt252', length := calldata_len - version: CairoVersion -} - -const toHex = (x: bigint) => `0x${x.toString(16)}` - -const isStringArray = (x: any): x is string[] => - x.every((y: any) => typeof y === "string") - -export async function handleDeploymentData(): Promise { - const deploymentData = - await inpageMessageClient.accountMessaging.getAccountDeploymentPayload.query() - - if (!deploymentData) { - return deploymentData - } - - const { - version, - classHash, - constructorCalldata, - addressSalt, - contractAddress, - } = deploymentData - - if (!classHash || !constructorCalldata || !addressSalt || !contractAddress) { - throw new Error("Deployment data not found") - } - - if (!isStringArray(constructorCalldata)) { - throw new Error("Constructor calldata is not an array of hex strings") - } - - const _addressSalt = toHex(BigInt(addressSalt)) - const _callData = constructorCalldata.map((x) => toHex(BigInt(x))) - - return { - address: contractAddress, - class_hash: classHash, - salt: _addressSalt, - calldata: _callData, - version, - } -} diff --git a/packages/extension/src/inpage/requestMessageHandlers/addDeclareTransaction.ts b/packages/extension/src/inpage/requestMessageHandlers/addDeclareTransaction.ts new file mode 100644 index 000000000..839df5fe0 --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/addDeclareTransaction.ts @@ -0,0 +1,60 @@ +import { + AddDeclareTransactionParameters, + AddDeclareTransactionResult, +} from "@argent/x-window" +import { sendMessage, waitForMessage } from "../messageActions" +import { json } from "starknet" + +export async function addDeclareTransactionHandler( + params: AddDeclareTransactionParameters, +): Promise { + const { contract_class, compiled_class_hash } = params + + if (!contract_class.abi) { + throw new Error("Missing ABI") + } + + sendMessage({ + type: "REQUEST_DECLARE_CONTRACT", + data: { + payload: { + contract: json.stringify(contract_class), // FIXME: this is a hack. It won't work + compiledClassHash: compiled_class_hash, + }, + }, + }) + const { actionHash } = await waitForMessage( + "REQUEST_DECLARE_CONTRACT_RES", + 1000, + ) + sendMessage({ type: "OPEN_UI" }) + + const result = await Promise.race([ + waitForMessage( + "DECLARE_CONTRACT_ACTION_SUBMITTED", + 11 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ), + waitForMessage( + "DECLARE_CONTRACT_ACTION_FAILED", + 10 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ) + .then(() => "error" as const) + .catch(() => { + return "timeout" as const + }), + ]) + + if (result === "error") { + throw Error("User abort") + } + if (result === "timeout") { + throw Error("User action timed out") + } + + return { + transaction_hash: result.txHash, + class_hash: result.classHash, + } +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/addStarknetChain.ts b/packages/extension/src/inpage/requestMessageHandlers/addStarknetChain.ts new file mode 100644 index 000000000..0fb2482a5 --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/addStarknetChain.ts @@ -0,0 +1,75 @@ +import { AddStarknetChainParameters } from "@argent/x-window" +import { sendMessage, waitForMessage } from "../messageActions" +import { Address } from "@argent/x-shared" +import { ETH_TOKEN_ADDRESS } from "../../shared/network/constants" + +export async function addStarknetChainHandler( + callParams: AddStarknetChainParameters, +): Promise { + sendMessage({ + type: "REQUEST_ADD_CUSTOM_NETWORK", + data: { + id: callParams.id, + name: callParams.chainName, + chainId: callParams.chainId, + rpcUrl: callParams.rpcUrls?.[0], + explorerUrl: callParams.blockExplorerUrls?.[0], + accountClassHash: (callParams as any).accountImplementation, + possibleFeeTokenAddresses: [ + (callParams.nativeCurrency?.address as Address) ?? ETH_TOKEN_ADDRESS, + ], + }, + }) + + const req = await Promise.race([ + waitForMessage("REQUEST_ADD_CUSTOM_NETWORK_RES", 1000), + waitForMessage("REQUEST_ADD_CUSTOM_NETWORK_REJ", 1000), + ]) + + if ("error" in req) { + throw Error(req.error) + } + + const { exists, actionHash } = req + + if (exists) { + // network already exists + return true + } + + if (!actionHash) { + throw Error("Unexpected error: actionHash is undefined") + } + + sendMessage({ type: "OPEN_UI" }) + + const result = await Promise.race([ + waitForMessage( + "APPROVE_REQUEST_ADD_CUSTOM_NETWORK", + 11 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ), + waitForMessage( + "REJECT_REQUEST_ADD_CUSTOM_NETWORK", + 10 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ) + .then(() => "error" as const) + .catch(() => { + sendMessage({ + type: "REJECT_REQUEST_ADD_CUSTOM_NETWORK", + data: { actionHash }, + }) + return "timeout" as const + }), + ]) + + if (result === "error") { + throw Error("User abort") + } + if (result === "timeout") { + throw Error("User action timed out") + } + + return true +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/deploymentData.ts b/packages/extension/src/inpage/requestMessageHandlers/deploymentData.ts new file mode 100644 index 000000000..cf14b992c --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/deploymentData.ts @@ -0,0 +1,47 @@ +import { GetDeploymentDataResult } from "@argent/x-window" +import { inpageMessageClient } from "../trpcClient" + +const toHex = (x: bigint) => `0x${x.toString(16)}` + +const isStringArray = (x: any): x is string[] => + x.every((y: any) => typeof y === "string") + +export async function deploymentDataHandler(): Promise { + const deploymentData = + await inpageMessageClient.accountMessaging.getAccountDeploymentPayload.query() + + if (!deploymentData) { + throw new Error("Deployment data not found") + } + + const { + version, + classHash, + constructorCalldata, + addressSalt, + contractAddress, + } = deploymentData + + if (!classHash || !constructorCalldata || !addressSalt || !contractAddress) { + throw new Error("Deployment data not found") + } + + if (!isStringArray(constructorCalldata)) { + throw new Error("Constructor calldata is not an array of hex strings") + } + + const _addressSalt = toHex(BigInt(addressSalt)) + const _callData = constructorCalldata.map((x) => toHex(BigInt(x))) + + if (!version) { + throw new Error("Account's Cairo Version not found") + } + + return { + address: contractAddress, + class_hash: classHash, + salt: _addressSalt, + calldata: _callData, + version: Number(version) as 0 | 1, // so bad :( + } +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/getPermissionsHandler.ts b/packages/extension/src/inpage/requestMessageHandlers/getPermissionsHandler.ts new file mode 100644 index 000000000..1954a4ab7 --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/getPermissionsHandler.ts @@ -0,0 +1,6 @@ +import { Permission } from "@argent/x-window" +import { getIsPreauthorized } from "../messaging" + +export async function getPermissionsHandler() { + return (await getIsPreauthorized()) ? [Permission.Accounts] : [] +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/index.ts b/packages/extension/src/inpage/requestMessageHandlers/index.ts new file mode 100644 index 000000000..ef45824cf --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/index.ts @@ -0,0 +1,46 @@ +import { type RpcMessage } from "@argent/x-window" + +import { watchAssetHandler } from "./watchAsset" +import { requestAccountsHandler } from "./requestAccounts" +import { addInvokeTransactionHandler } from "./invokeTransaction" +import { switchStarknetChainHandler } from "./switchStarknetChain" +import { addStarknetChainHandler } from "./addStarknetChain" +import { addDeclareTransactionHandler } from "./addDeclareTransaction" +import { signTypedDataHandler } from "./signTypedData" +import { requestChainIdHandler } from "./requestChainIdHandler" +import { getPermissionsHandler } from "./getPermissionsHandler" +import { deploymentDataHandler } from "./deploymentData" +import { supportedSpecsHandler } from "./supportedSpecs" + +export async function requestMessageHandler( + call: Omit, +): Promise { + const handlerMap: Record Promise> = { + // Wallet requests + wallet_addStarknetChain: addStarknetChainHandler, + wallet_switchStarknetChain: switchStarknetChainHandler, + wallet_watchAsset: watchAssetHandler, + wallet_requestAccounts: requestAccountsHandler, + wallet_getPermissions: getPermissionsHandler, + wallet_requestChainId: requestChainIdHandler, + wallet_deploymentData: deploymentDataHandler, + // Starknet requests + starknet_addDeclareTransaction: addDeclareTransactionHandler, + starknet_addInvokeTransaction: addInvokeTransactionHandler, + starknet_signTypedData: signTypedDataHandler, + starknet_supportedSpecs: supportedSpecsHandler, + } + + const notImplementedTypes = new Set(["starknet_addDeployAccountTransaction"]) + + if (notImplementedTypes.has(call.type)) { + throw new Error("Not implemented") + } + + const handler = handlerMap[call.type] + if (handler) { + return "params" in call ? handler(call.params) : handler() + } + + throw new Error(`Unknown request type: ${call.type}`) +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/invokeTransaction.ts b/packages/extension/src/inpage/requestMessageHandlers/invokeTransaction.ts new file mode 100644 index 000000000..514608f6b --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/invokeTransaction.ts @@ -0,0 +1,69 @@ +import { + AddInvokeTransactionParameters, + AddInvokeTransactionResult, + BigNumberishSchema, +} from "@argent/x-window" +import { sendMessage, waitForMessage } from "../messageActions" +import { z } from "zod" + +const CallSchema = z + .object({ + contract_address: z.string(), + entrypoint: z.string(), + calldata: z.array(BigNumberishSchema).optional(), + }) + .transform(({ contract_address, entrypoint, calldata }) => ({ + contractAddress: contract_address, + entrypoint, + calldata: calldata || [], + })) + +const CallsArraySchema = z.array(CallSchema).nonempty() + +export async function addInvokeTransactionHandler( + params: AddInvokeTransactionParameters, +): Promise { + const parsedTransaction = CallsArraySchema.safeParse(params.calls) + + if (!parsedTransaction.success) { + throw Error(`Invalid transaction: ${parsedTransaction.error.message}`) + } + + sendMessage({ + type: "EXECUTE_TRANSACTION", + data: { + transactions: parsedTransaction.data, + }, + }) + const { actionHash } = await waitForMessage("EXECUTE_TRANSACTION_RES", 1000) + sendMessage({ type: "OPEN_UI" }) + + const result = await Promise.race([ + waitForMessage( + "TRANSACTION_SUBMITTED", + 11 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ), + waitForMessage( + "TRANSACTION_FAILED", + 10 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ) + .then(() => "error" as const) + .catch(() => { + sendMessage({ type: "TRANSACTION_FAILED", data: { actionHash } }) + return "timeout" as const + }), + ]) + + if (result === "error") { + throw Error("User abort") + } + if (result === "timeout") { + throw Error("User action timed out") + } + + return { + transaction_hash: result.txHash, + } +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/requestAccounts.ts b/packages/extension/src/inpage/requestMessageHandlers/requestAccounts.ts new file mode 100644 index 000000000..e78541ff4 --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/requestAccounts.ts @@ -0,0 +1,28 @@ +import { RequestAccountsParameters } from "@argent/x-window" +import { sendMessage, waitForMessage } from "../messageActions" + +export async function requestAccountsHandler( + params?: RequestAccountsParameters, +) { + sendMessage({ + type: "CONNECT_DAPP", + data: { silent: params?.silentMode }, + }) + const result = await Promise.race([ + waitForMessage("CONNECT_DAPP_RES", 10 * 60 * 1000), + waitForMessage("REJECT_PREAUTHORIZATION", 10 * 60 * 1000).then( + () => "USER_ABORTED" as const, + ), + ]) + + if (!result) { + throw Error("No wallet account (should not be possible)") + } + if (result === "USER_ABORTED") { + throw Error("User aborted") + } + + const { address } = result + + return [address] +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/requestChainIdHandler.ts b/packages/extension/src/inpage/requestMessageHandlers/requestChainIdHandler.ts new file mode 100644 index 000000000..80d705b19 --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/requestChainIdHandler.ts @@ -0,0 +1,37 @@ +import { shortString } from "starknet" +import { getProvider } from "../../shared/network" +import { isArgentNetwork } from "../../shared/network/utils" +import { sendMessage, waitForMessage } from "../messageActions" +import { getIsPreauthorized } from "../messaging" + +export async function requestChainIdHandler() { + const isPreauthorized = await getIsPreauthorized() + + if (!isPreauthorized) { + throw new Error("Not preauthorized") + } + + void sendMessage({ type: "REQUEST_SELECTED_NETWORK" }) + const result = await Promise.race([ + waitForMessage("REQUEST_SELECTED_NETWORK_RES", 10 * 60 * 1000), + waitForMessage("REQUEST_SELECTED_NETWORK_REJ", 10 * 60 * 1000).catch( + () => "timeout" as const, + ), + ]) + + if (result === "timeout") { + throw new Error("Timeout") + } + + if ("error" in result) { + throw Error(result.error) + } + + // For Argent network, we return the chainId directly + if (isArgentNetwork(result.network)) { + return shortString.encodeShortString(result.network.chainId) + } + + // For other networks, we return the chainId from the rpc + return getProvider(result.network).getChainId() +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/signTypedData.ts b/packages/extension/src/inpage/requestMessageHandlers/signTypedData.ts new file mode 100644 index 000000000..11363f5cc --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/signTypedData.ts @@ -0,0 +1,44 @@ +import { TypedData } from "starknet" +import { sendMessage, waitForMessage } from "../messageActions" + +export async function signTypedDataHandler(params: TypedData) { + const skipDeploy = "skipDeploy" in params ? !!params.skipDeploy : false + + sendMessage({ + type: "SIGN_MESSAGE", + data: { typedData: params, options: { skipDeploy } }, + }) + const { actionHash } = await waitForMessage("SIGN_MESSAGE_RES", 1000) + sendMessage({ type: "OPEN_UI" }) + + const result = await Promise.race([ + waitForMessage( + "SIGNATURE_SUCCESS", + 11 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ), + waitForMessage( + "SIGNATURE_FAILURE", + 10 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ) + .then((x) => x) + .catch((e) => { + sendMessage({ + type: "SIGNATURE_FAILURE", + data: { actionHash, error: e.message }, // this error will be thrown by waitForMessage after the timeout + }) + return "timeout" as const + }), + ]) + + if (result === "timeout") { + throw Error("User action timed out") + } + + if ("error" in result) { + throw Error(result.error) + } + + return result.signature +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/supportedSpecs.ts b/packages/extension/src/inpage/requestMessageHandlers/supportedSpecs.ts new file mode 100644 index 000000000..79148a18f --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/supportedSpecs.ts @@ -0,0 +1,3 @@ +export function supportedSpecsHandler() { + return Promise.resolve(["0.6.0"]) +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/switchStarknetChain.ts b/packages/extension/src/inpage/requestMessageHandlers/switchStarknetChain.ts new file mode 100644 index 000000000..4bd38f551 --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/switchStarknetChain.ts @@ -0,0 +1,64 @@ +import { SwitchStarknetChainParameters } from "@argent/x-window" +import { sendMessage, waitForMessage } from "../messageActions" + +export async function switchStarknetChainHandler({ + chainId, +}: SwitchStarknetChainParameters): Promise { + sendMessage({ + type: "REQUEST_SWITCH_CUSTOM_NETWORK", + data: { chainId }, + }) + + const req = await Promise.race([ + waitForMessage("REQUEST_SWITCH_CUSTOM_NETWORK_RES", 1000), + waitForMessage("REQUEST_SWITCH_CUSTOM_NETWORK_REJ", 1000), + ]) + + if ("error" in req) { + throw Error(req.error) + } + + const { actionHash, exists } = req + + if (!exists) { + // If network does not exist, we cannot switch to it + return false + } + + sendMessage({ type: "OPEN_UI" }) + + if (!actionHash) { + throw Error("Unexpected error: actionHash is undefined") + } + + const result = await Promise.race([ + waitForMessage( + "APPROVE_REQUEST_SWITCH_CUSTOM_NETWORK", + 11 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ), + waitForMessage( + "REJECT_REQUEST_SWITCH_CUSTOM_NETWORK", + 10 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ) + .then(() => "error" as const) + .catch(() => { + sendMessage({ + type: "REJECT_REQUEST_SWITCH_CUSTOM_NETWORK", + data: { actionHash }, + }) + return "timeout" as const + }), + ]) + + if (result === "error") { + throw Error("User abort") + } + + if (result === "timeout") { + throw Error("User action timed out") + } + + return true +} diff --git a/packages/extension/src/inpage/requestMessageHandlers/watchAsset.ts b/packages/extension/src/inpage/requestMessageHandlers/watchAsset.ts new file mode 100644 index 000000000..e8dcbf5b2 --- /dev/null +++ b/packages/extension/src/inpage/requestMessageHandlers/watchAsset.ts @@ -0,0 +1,60 @@ +import { WatchAssetParameters } from "@argent/x-window" +import { sendMessage, waitForMessage } from "../messageActions" +import { addressSchema } from "@argent/x-shared" + +export async function watchAssetHandler( + callParams: WatchAssetParameters, +): Promise { + const parsedAddress = addressSchema.safeParse(callParams.options.address) + + if (parsedAddress.success && callParams.type === "ERC20") { + sendMessage({ + type: "REQUEST_TOKEN", + data: { + address: parsedAddress.data, + symbol: callParams.options.symbol, + decimals: callParams.options.decimals, + name: callParams.options.name, + }, + }) + } + const { exists, actionHash } = await waitForMessage("REQUEST_TOKEN_RES", 1000) + + if (exists) { + // token already exists + return true + } + + if (!actionHash) { + throw Error("Unexpected error: actionHash is undefined") + } + + sendMessage({ type: "OPEN_UI" }) + + const result = await Promise.race([ + waitForMessage( + "APPROVE_REQUEST_TOKEN", + 11 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ), + waitForMessage( + "REJECT_REQUEST_TOKEN", + 10 * 60 * 1000, + (x) => x.data.actionHash === actionHash, + ) + .then(() => "error" as const) + .catch(() => { + sendMessage({ type: "REJECT_REQUEST_TOKEN", data: { actionHash } }) + return "timeout" as const + }), + ]) + + if (result === "error") { + throw Error("User abort") + } + if (result === "timeout") { + throw Error("User action timed out") + } + + return true +} diff --git a/packages/extension/src/inpage/starknetWindowObject.ts b/packages/extension/src/inpage/starknetWindowObject.ts index 377770e3b..6d42533aa 100644 --- a/packages/extension/src/inpage/starknetWindowObject.ts +++ b/packages/extension/src/inpage/starknetWindowObject.ts @@ -1,7 +1,7 @@ import type { AccountChangeEventHandler, + BackwardsCompatibleStarknetWindowObject, NetworkChangeEventHandler, - StarknetWindowObject, WalletEvents, } from "@argent/x-window" @@ -9,12 +9,7 @@ import { assertNever } from "../shared/utils/assertNever" import { ArgentXAccount } from "./ArgentXAccount" import { sendMessage, waitForMessage } from "./messageActions" import { getIsPreauthorized } from "./messaging" -import { - handleAddNetworkRequest, - handleAddTokenRequest, - handleDeploymentData, - handleSwitchNetworkRequest, -} from "./requestMessageHandlers" +import { requestMessageHandler } from "./requestMessageHandlers" import { ArgentXAccount4 } from "./ArgentXAccount4" import { ArgentXProvider } from "./ArgentXProvider" import { ArgentXProviderV4 } from "./ArgentXProvider4" @@ -24,7 +19,7 @@ const VERSION = `${process.env.VERSION}` export const userEventHandlers: WalletEvents[] = [] // window.ethereum like -export const starknetWindowObject: StarknetWindowObject = { +export const starknetWindowObject: BackwardsCompatibleStarknetWindowObject = { id: "argentX", // if ever changed you need to change it in get-starknet aswell name: "Argent X", icon: "data:image/svg+xml;base64,Cjxzdmcgd2lkdGg9IjQwIiBoZWlnaHQ9IjM2IiB2aWV3Qm94PSIwIDAgNDAgMzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0yNC43NTgyIC0zLjk3MzY0ZS0wN0gxNC42MjM4QzE0LjI4NTEgLTMuOTczNjRlLTA3IDE0LjAxMzggMC4yODExNzggMTQuMDA2NCAwLjYzMDY4M0MxMy44MDE3IDEwLjQ1NDkgOC44MjIzNCAxOS43NzkyIDAuMjUxODkzIDI2LjM4MzdDLTAuMDIwMjA0NiAyNi41OTMzIC0wLjA4MjE5NDYgMjYuOTg3MiAwLjExNjczNCAyNy4yNzA5TDYuMDQ2MjMgMzUuNzM0QzYuMjQ3OTYgMzYuMDIyIDYuNjQwOTkgMzYuMDg3IDYuOTE3NjYgMzUuODc1NEMxMi4yNzY1IDMxLjc3MjggMTYuNTg2OSAyNi44MjM2IDE5LjY5MSAyMS4zMzhDMjIuNzk1MSAyNi44MjM2IDI3LjEwNTcgMzEuNzcyOCAzMi40NjQ2IDM1Ljg3NTRDMzIuNzQxIDM2LjA4NyAzMy4xMzQxIDM2LjAyMiAzMy4zMzYxIDM1LjczNEwzOS4yNjU2IDI3LjI3MDlDMzkuNDY0MiAyNi45ODcyIDM5LjQwMjIgMjYuNTkzMyAzOS4xMzA0IDI2LjM4MzdDMzAuNTU5NyAxOS43NzkyIDI1LjU4MDQgMTAuNDU0OSAyNS4zNzU5IDAuNjMwNjgzQzI1LjM2ODUgMC4yODExNzggMjUuMDk2OSAtMy45NzM2NGUtMDcgMjQuNzU4MiAtMy45NzM2NGUtMDdaIiBmaWxsPSIjRkY4NzVCIi8+Cjwvc3ZnPgo=", @@ -34,31 +29,9 @@ export const starknetWindowObject: StarknetWindowObject = { chainId: undefined, isConnected: false, version: VERSION, - request: async (call) => { - if ( - call.type === "wallet_watchAsset" && - "type" in call.params && - call.params.type === "ERC20" - ) { - return await handleAddTokenRequest(call.params) - } else if (call.type === "wallet_addStarknetChain" && "id" in call.params) { - return await handleAddNetworkRequest(call.params) - } else if ( - call.type === "wallet_switchStarknetChain" && - "chainId" in call.params - ) { - return await handleSwitchNetworkRequest(call.params) - } else if ( - // Currently not part of the spec - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - call.type === "wallet_deploymentData" - ) { - console.warn("Using non-standard wallet_deploymentData") - return (await handleDeploymentData()) as any - } - throw Error("Not implemented") - }, + request: requestMessageHandler, + + // @deprecated enable: async ({ starknetVersion = "v5" } = {}) => { const walletAccountP = Promise.race([ waitForMessage("CONNECT_DAPP_RES", 10 * 60 * 1000), @@ -77,11 +50,13 @@ export const starknetWindowObject: StarknetWindowObject = { if (walletAccount === "USER_ABORTED") { throw Error("User aborted") } - const { starknet } = window - if (!starknet) { + + if (!window.starknet) { throw Error("No starknet object detected") } + const starknet = window.starknet as BackwardsCompatibleStarknetWindowObject + const { address, network } = walletAccount if (starknetVersion === "v5") { @@ -104,6 +79,10 @@ export const starknetWindowObject: StarknetWindowObject = { starknet.chainId = network.chainId starknet.isConnected = true + console.warn( + `Connecting to ArgentX with "enable" is deprecated. Please update get-starknet or use "request" instead.`, + ) + return [address] }, isPreauthorized: async () => { diff --git a/packages/extension/src/shared/account/details/getAccountClassHashFromChain.test.ts b/packages/extension/src/shared/account/details/getAccountClassHashFromChain.test.ts index fb5868749..f291af565 100644 --- a/packages/extension/src/shared/account/details/getAccountClassHashFromChain.test.ts +++ b/packages/extension/src/shared/account/details/getAccountClassHashFromChain.test.ts @@ -9,7 +9,7 @@ import { MULTISIG_ACCOUNT_CLASS_HASH, TXV1_ACCOUNT_CLASS_HASH, } from "../../network/constants" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { getMockNetwork, getMockNetworkWithoutMulticall, diff --git a/packages/extension/src/shared/account/details/getAccountClassHashFromChain.ts b/packages/extension/src/shared/account/details/getAccountClassHashFromChain.ts index f986772b6..ddb9bb841 100644 --- a/packages/extension/src/shared/account/details/getAccountClassHashFromChain.ts +++ b/packages/extension/src/shared/account/details/getAccountClassHashFromChain.ts @@ -7,7 +7,7 @@ import { networkService } from "../../network/service" import { mapImplementationToArgentAccountType } from "../../network/utils" import { ArgentAccountType, WalletAccount } from "../../wallet.model" import { accountsEqual } from "../../utils/accountsEqual" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { tryGetClassHash } from "./tryGetClassHash" import { MULTISIG_ACCOUNT_CLASS_HASH, diff --git a/packages/extension/src/shared/account/details/getAccountDeployStatusFromChain.ts b/packages/extension/src/shared/account/details/getAccountDeployStatusFromChain.ts index e07145977..56589d54e 100644 --- a/packages/extension/src/shared/account/details/getAccountDeployStatusFromChain.ts +++ b/packages/extension/src/shared/account/details/getAccountDeployStatusFromChain.ts @@ -1,4 +1,4 @@ -import { isContractDeployed } from "@argent/shared" +import { isContractDeployed } from "@argent/x-shared" import { getProvider } from "../../network" import { WalletAccount } from "../../wallet.model" diff --git a/packages/extension/src/shared/account/details/tryGetClassHash.ts b/packages/extension/src/shared/account/details/tryGetClassHash.ts index 98c5d48e1..354825ea1 100644 --- a/packages/extension/src/shared/account/details/tryGetClassHash.ts +++ b/packages/extension/src/shared/account/details/tryGetClassHash.ts @@ -1,6 +1,6 @@ import { Call, ProviderInterface } from "starknet" import { TXV1_ACCOUNT_CLASS_HASH } from "../../network/constants" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" export async function tryGetClassHash( call: Call, diff --git a/packages/extension/src/shared/account/optimisticImplUpdate.ts b/packages/extension/src/shared/account/optimisticImplUpdate.ts index 8921d5b51..32c31ccc8 100644 --- a/packages/extension/src/shared/account/optimisticImplUpdate.ts +++ b/packages/extension/src/shared/account/optimisticImplUpdate.ts @@ -1,4 +1,4 @@ -import { Address, isEqualAddress } from "@argent/shared" +import { Address, isEqualAddress } from "@argent/x-shared" import { WalletAccount } from "../wallet.model" import { ARGENT_ACCOUNT_CONTRACT_CLASS_HASHES } from "./starknet.constants" @@ -15,8 +15,8 @@ export const optimisticImplUpdate = ( const cairoVersion = CAIRO_1.some((c1) => isEqualAddress(c1, newClassHash)) ? "1" : CAIRO_0.some((c0) => isEqualAddress(c0, newClassHash)) - ? "0" - : account.cairoVersion // fallback to the current account's cairo version + ? "0" + : account.cairoVersion // fallback to the current account's cairo version return { ...account, classHash: newClassHash, cairoVersion } } diff --git a/packages/extension/src/shared/account/service/index.ts b/packages/extension/src/shared/account/service/index.ts index d99622832..89f06d767 100644 --- a/packages/extension/src/shared/account/service/index.ts +++ b/packages/extension/src/shared/account/service/index.ts @@ -1,8 +1,23 @@ import { starknetChainService } from "../../chain/service" +import { + multisigBaseWalletRepo, + pendingMultisigRepo, +} from "../../multisig/repository" +import { walletStore } from "../../wallet/walletStore" import { accountRepo } from "../store" +import { sessionRepo } from "../store/session" import { AccountService } from "./implementation" +import { WalletAccountSharedService } from "./shared.service" export const accountService = new AccountService( starknetChainService, accountRepo, ) + +export const accountSharedService = new WalletAccountSharedService( + walletStore, + accountRepo, + sessionRepo, + multisigBaseWalletRepo, + pendingMultisigRepo, +) diff --git a/packages/extension/src/background/wallet/account/shared.service.test.ts b/packages/extension/src/shared/account/service/shared.service.test.ts similarity index 95% rename from packages/extension/src/background/wallet/account/shared.service.test.ts rename to packages/extension/src/shared/account/service/shared.service.test.ts index 0c9b2c25d..877b44161 100644 --- a/packages/extension/src/background/wallet/account/shared.service.test.ts +++ b/packages/extension/src/shared/account/service/shared.service.test.ts @@ -1,21 +1,20 @@ import { WalletAccountSharedService, WalletSession } from "./shared.service" -import { WalletStorageProps } from "../../../shared/wallet/walletStore" +import { WalletStorageProps } from "../../wallet/walletStore" -import { BaseMultisigWalletAccount } from "../../../shared/wallet.model" -import { PendingMultisig } from "../../../shared/multisig/types" +import { BaseMultisigWalletAccount } from "../../wallet.model" +import { PendingMultisig } from "../../multisig/types" -import { WalletAccount } from "../../../shared/wallet.model" +import { WalletAccount } from "../../wallet.model" import { getMultisigStoreMock, getPendingMultisigStoreMock, getSessionStoreMock, getStoreMock, getWalletStoreMock, -} from "../test.utils" -import { - IObjectStore, - IRepository, -} from "../../../shared/storage/__new/interface" + // Doesnt matter for tests + // eslint-disable-next-line @argent/local/code-import-patterns +} from "../../../background/wallet/test.utils" +import { IObjectStore, IRepository } from "../../storage/__new/interface" describe("WalletAccountSharedService", () => { let service: WalletAccountSharedService diff --git a/packages/extension/src/background/wallet/account/shared.service.ts b/packages/extension/src/shared/account/service/shared.service.ts similarity index 85% rename from packages/extension/src/background/wallet/account/shared.service.ts rename to packages/extension/src/shared/account/service/shared.service.ts index a3ae06cd2..277bd50f3 100644 --- a/packages/extension/src/background/wallet/account/shared.service.ts +++ b/packages/extension/src/shared/account/service/shared.service.ts @@ -4,24 +4,21 @@ import { BaseMultisigWalletAccount, CreateAccountType, MultisigWalletAccount, -} from "../../../shared/wallet.model" -import { withHiddenSelector } from "../../../shared/account/selectors" -import { PendingMultisig } from "../../../shared/multisig/types" -import { defaultNetwork } from "../../../shared/network" -import { BaseWalletAccount, WalletAccount } from "../../../shared/wallet.model" +} from "../../wallet.model" +import { withHiddenSelector } from "../selectors" +import { PendingMultisig } from "../../multisig/types" +import { defaultNetwork } from "../../network" +import { BaseWalletAccount, WalletAccount } from "../../wallet.model" import { MULTISIG_DERIVATION_PATH, STANDARD_DERIVATION_PATH, -} from "../../../shared/wallet.service" -import { - IObjectStore, - IRepository, -} from "../../../shared/storage/__new/interface" -import { accountsEqual } from "./../../../shared/utils/accountsEqual" -import { getPathForIndex } from "../../../shared/utils/derivationPath" -import { AccountError } from "../../../shared/errors/account" -import { MULTISIG_ACCOUNT_CLASS_HASH } from "../../../shared/network/constants" -import type { WalletStorageProps } from "../../../shared/wallet/walletStore" +} from "../../wallet.service" +import { IObjectStore, IRepository } from "../../storage/__new/interface" +import { accountsEqual } from "../../utils/accountsEqual" +import { getPathForIndex } from "../../utils/derivationPath" +import { AccountError } from "../../errors/account" +import { MULTISIG_ACCOUNT_CLASS_HASH } from "../../network/constants" +import type { WalletStorageProps } from "../../wallet/walletStore" export interface WalletSession { secret: string diff --git a/packages/extension/src/shared/account/store/session.ts b/packages/extension/src/shared/account/store/session.ts new file mode 100644 index 000000000..34579ddd4 --- /dev/null +++ b/packages/extension/src/shared/account/store/session.ts @@ -0,0 +1,13 @@ +import { ObjectStorage } from "../../storage" +import { adaptObjectStorage } from "../../storage/__new/object" +import { WalletSession } from "../service/shared.service" + +/** + * @deprecated use `sessionRepo` instead + */ +export const sessionStore = new ObjectStorage(null, { + namespace: "core:wallet:session", + areaName: "session", +}) + +export const sessionRepo = adaptObjectStorage(sessionStore) diff --git a/packages/extension/src/shared/actionQueue/schema.ts b/packages/extension/src/shared/actionQueue/schema.ts index 5b2e185e0..593789085 100644 --- a/packages/extension/src/shared/actionQueue/schema.ts +++ b/packages/extension/src/shared/actionQueue/schema.ts @@ -1,5 +1,7 @@ import { z } from "zod" -import { icons } from "@argent/ui" +// just using types here +// eslint-disable-next-line @argent/local/code-import-patterns +import { icons } from "@argent/x-ui" export const actionHashSchema = z.string() export type ActionHash = z.infer diff --git a/packages/extension/src/shared/activity/schema.ts b/packages/extension/src/shared/activity/schema.ts index 86ab8cbc1..3bc998ae7 100644 --- a/packages/extension/src/shared/activity/schema.ts +++ b/packages/extension/src/shared/activity/schema.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" const transactionSchema = z.object({ diff --git a/packages/extension/src/shared/activity/utils/isProvisionWithDeploymentActivity.ts b/packages/extension/src/shared/activity/utils/isProvisionWithDeploymentActivity.ts index a5d8a5d99..42647fdb6 100644 --- a/packages/extension/src/shared/activity/utils/isProvisionWithDeploymentActivity.ts +++ b/packages/extension/src/shared/activity/utils/isProvisionWithDeploymentActivity.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { Activity } from "../schema" export const isProvisionWithDeploymentActivity = (activity: Activity) => { diff --git a/packages/extension/src/shared/activity/utils/parseAccountActivities.test.ts b/packages/extension/src/shared/activity/utils/parseAccountActivities.test.ts index 7171aa0e3..0752c7909 100644 --- a/packages/extension/src/shared/activity/utils/parseAccountActivities.test.ts +++ b/packages/extension/src/shared/activity/utils/parseAccountActivities.test.ts @@ -1,4 +1,4 @@ -import type { Address } from "@argent/shared" +import type { Address } from "@argent/x-shared" import { describe, expect, test } from "vitest" import activities from "../__fixtures__/activities.json" diff --git a/packages/extension/src/shared/activity/utils/parseAccountActivities.ts b/packages/extension/src/shared/activity/utils/parseAccountActivities.ts index 2f1494d97..db62991e1 100644 --- a/packages/extension/src/shared/activity/utils/parseAccountActivities.ts +++ b/packages/extension/src/shared/activity/utils/parseAccountActivities.ts @@ -1,4 +1,4 @@ -import { type Address, ensureArray, includesAddress } from "@argent/shared" +import { type Address, ensureArray, includesAddress } from "@argent/x-shared" import type { Activity, ActivityDetailsAction } from "../schema" import { isProvisionWithDeploymentActivity } from "./isProvisionWithDeploymentActivity" diff --git a/packages/extension/src/shared/activity/utils/parseFinanceActivities.test.ts b/packages/extension/src/shared/activity/utils/parseFinanceActivities.test.ts index 5951e8914..5280858c7 100644 --- a/packages/extension/src/shared/activity/utils/parseFinanceActivities.test.ts +++ b/packages/extension/src/shared/activity/utils/parseFinanceActivities.test.ts @@ -1,4 +1,4 @@ -import type { Address } from "@argent/shared" +import type { Address } from "@argent/x-shared" import { describe, expect, test } from "vitest" import type { Activity } from "../schema" diff --git a/packages/extension/src/shared/activity/utils/parseFinanceActivities.ts b/packages/extension/src/shared/activity/utils/parseFinanceActivities.ts index 2ac7fedbd..aada750d6 100644 --- a/packages/extension/src/shared/activity/utils/parseFinanceActivities.ts +++ b/packages/extension/src/shared/activity/utils/parseFinanceActivities.ts @@ -1,4 +1,4 @@ -import { type Address, includesAddress } from "@argent/shared" +import { type Address, includesAddress } from "@argent/x-shared" import type { Activity } from "../schema" diff --git a/packages/extension/src/shared/addressBook/schema.ts b/packages/extension/src/shared/addressBook/schema.ts index 79bc4c8ab..6b5678167 100644 --- a/packages/extension/src/shared/addressBook/schema.ts +++ b/packages/extension/src/shared/addressBook/schema.ts @@ -1,4 +1,4 @@ -import { addressOrDomainInputSchema } from "@argent/shared" +import { addressOrDomainInputSchema } from "@argent/x-shared" import { z } from "zod" export const addressBookContactSchema = z.object({ diff --git a/packages/extension/src/shared/analytics.ts b/packages/extension/src/shared/analytics.ts deleted file mode 100644 index 08b3ca00c..000000000 --- a/packages/extension/src/shared/analytics.ts +++ /dev/null @@ -1,343 +0,0 @@ -import { base64 } from "@scure/base" -import { encode } from "starknet" - -import { CreateAccountType } from "./wallet.model" -import { KeyValueStorage } from "./storage" -import { isEmpty } from "lodash-es" -import { settingsStore } from "./settings" - -const SEGMENT_TRACK_URL = "https://api.segment.io/v1/track" - -// dont use destructuring here -const SEGMENT_WRITE_KEY = process.env.SEGMENT_WRITE_KEY -const VERSION = process.env.VERSION - -export type AddFundsServices = - | "banxa" - | "layerswap" - | "starkgate" - | "orbiter" - | "ramp" - -export type UserFeedbackAction = - | "REVIEWED_ON_CHROME_STORE" - | "REVIEWED_ON_ZENDESK" - | "RATING_DISMISSED" - | "FEEDBACK_DISMISSED" - -export interface Events { - sessionStart: undefined - sessionEnded: { - length: number - } - openedExtensionToday: undefined - unlockedExtensionToday: undefined - unlockedExtensionWeekly: undefined - unlockedExtensionMonthly: undefined - createWallet: - | { - status: "success" - networkId: string - } - | { - status: "failure" - errorMessage: string - networkId: string - } - createAccount: - | { - status: "success" - networkId: string - type: CreateAccountType - } - | { - status: "failure" - errorMessage: string - networkId: string - type: CreateAccountType - } - deployAccount: - | { - status: "success" - trigger: "sign" | "transaction" - networkId: string - } - | { - status: "failure" - errorMessage: string - networkId: string - } - deployMultisig: - | { - status: "success" - trigger: "sign" | "transaction" - networkId: string - } - | { - status: "failure" - errorMessage: string - networkId: string - } - preauthorizeDapp: { - host: string - networkId: string - } - signedTransaction: { - networkId: string - host?: string - } - sentTransaction: { - success: boolean - networkId: string - host?: string - } - rejectedTransaction: { - networkId: string - host?: string - } - signedMessage: { - networkId: string - } - addFunds: { - networkId: string - service: AddFundsServices - } - userRating: { - rating: number - } - userFeedbackAction: { - action: UserFeedbackAction - } - signedDeclareTransaction: { - networkId: string - } - signedDeployTransaction: { - networkId: string - } - swapInitiated: { - networkId: string - pair: string - } - executeTransaction: { - usesCachedFees: boolean - } - onboardingStepFinished: { - timeSpent?: number - successful?: boolean - stepId: - | "welcome" - | "disclaimer" - | "restoreSeedphrase" - | "newWalletPassword" - | "finish" - } - argentShieldOnboardingStepFinished: { - timeSpent?: number - successful?: boolean - stepId: - | "welcome" - | "enterEmail" - | "enterPasscode" - | "addArgentShield" - | "addArgentShieldFinish" - accountsWith2fa?: number - authenticated?: boolean - } - argentShieldRemovalStepFinished: { - timeSpent?: number - successful?: boolean - stepId: - | "welcome" - | "enterEmail" - | "enterPasscode" - | "removeArgentShield" - | "removeArgentShieldFinish" - accountsWith2fa?: number - authenticated?: boolean - } - argentShieldError: { - errorId: "emailNotMatch" | "emailAlreadyInUseForOtherSeedphrase" - accountsWith2fa?: number - authenticated?: boolean - } - argentShieldEscapeScreenSeen: { - escapeId: "escapeGuardian" | "escapeSigner" - remainingTime: number - } - argentShieldEscapeScreenAction: - | { - remainingTime: number - } & ( - | { - escapeId: "escapeGuardian" - action: - | "dismiss" - | "detailedInstructions" - | "keepArgentShield" - | "continueWithRemoval" - | "removeArgentShield" - } - | { - escapeId: "escapeSigner" - action: - | "dismiss" - | "detailedInstructions" - | "contactArgentSupport" - | "cancelKeyChange" - | "startRemoval" - } - ) -} - -export interface Pages { - welcome: undefined - disclaimer: undefined - createWallet: undefined - restoreWallet: undefined - restoreWalletWithFile: undefined - signMessage: undefined - signTransaction: { - networkId: string - } - signDeclareTransaction: { - networkId: string - } - signDeployTransaction: { - networkId: string - } - addFunds: { - networkId: string - } - addFundsFromOtherAccount: { - networkId: string - } - swap: { - networkId: string - } -} - -interface Analytics { - track( - event: T, - ...rest: Events[T] extends undefined // makes sure that the argument is optional if the event is not defined - ? [data?: Events[T]] - : [data: Events[T]] - ): Promise -} - -const versionRegex = /(\d+[._]\d+)([._]\d+)*/g // https://regex101.com/r/TgejzT/1 -export function anonymizeUserAgent(userAgent?: string): string { - if (!userAgent) { - return "unknown" - } - return userAgent.replace(versionRegex, "$1") -} - -export type Fetch = (url: string, init?: RequestInit) => Promise - -const defaultPayload = { - userId: "00000", - context: { - ip: "0.0.0.0", - app: { - name: "Argent X", - version: VERSION, - }, - library: { - name: "argent-x", - version: VERSION, - }, - }, -} -const headers = { - "Content-Type": "application/json", - Authorization: `Basic ${base64.encode( - encode.utf8ToArray(`${SEGMENT_WRITE_KEY}:`), - )}`, -} - -const isBrowser = typeof window !== "undefined" -const defaultUserAgent = isBrowser ? window.navigator.userAgent : "unknown" - -export function getAnalytics( - fetch: Fetch, - userAgent = defaultUserAgent, -): Analytics { - const prebuiltPayload = { - ...defaultPayload, - context: { - ...defaultPayload.context, - userAgent: anonymizeUserAgent(userAgent), - }, - } - return { - track: async (event, ...[data]) => { - const privacyShareAnalyticsData = await settingsStore.get( - "privacyShareAnalyticsData", - ) - if (!privacyShareAnalyticsData) { - return - } - if (isEmpty(SEGMENT_WRITE_KEY)) { - console.groupCollapsed(`Analytics: ${event}`) - console.log("You see this log because no SEGMENT_WRITE_KEY is set") - console.log(data) - console.groupEnd() - return - } - const payload = { - ...prebuiltPayload, - event, - properties: data, - timestamp: new Date().toISOString(), - } - - try { - return await fetch(SEGMENT_TRACK_URL, { - method: "POST", - headers, - body: JSON.stringify(payload), - }) - } catch { - // ignore - } - }, - } -} - -interface ActiveStoreValues { - lastOpened: number - lastUnlocked: number - lastSession: number - lastClosed: number -} - -interface ActiveStoreMethods { - update: (key: keyof ActiveStoreValues) => Promise -} - -class ActiveStore - extends KeyValueStorage - implements ActiveStoreMethods -{ - constructor() { - super( - { - lastOpened: 0, // defaults to tracking once when no value set yet - lastUnlocked: 0, // defaults to tracking once when no value set yet - lastSession: 0, // defaults to tracking once when no value set yet - lastClosed: 0, // defaults to tracking once when no value set yet - }, - { - namespace: "analytics:active", - }, - ) - } - - update(key: keyof ActiveStoreValues) { - return this.set(key, Date.now()) - } -} - -export const activeStore = new ActiveStore() -export type IActiveStore = typeof activeStore diff --git a/packages/extension/src/shared/analytics/implementation.ts b/packages/extension/src/shared/analytics/implementation.ts new file mode 100644 index 000000000..6365507fd --- /dev/null +++ b/packages/extension/src/shared/analytics/implementation.ts @@ -0,0 +1,48 @@ +import { Ampli, Event, EventOptions, PromiseResult, Result } from "../../ampli" +import { WalletAccountSharedService } from "../account/service/shared.service" +import { isProd } from "../api/constants" +import { ISettingsStorage } from "../settings/types" +import { KeyValueStorage } from "../storage" + +const getVoidPromiseResult = () => ({ promise: Promise.resolve() }) + +export class AnalyticsService extends Ampli { + constructor( + private accountSharedService: WalletAccountSharedService, + private readonly settingsStore: KeyValueStorage, + ) { + super() + } + + track(event: Event, options?: EventOptions): PromiseResult { + if (!super.isLoaded) { + return getVoidPromiseResult() + } + + return { + promise: this.accountSharedService + .getSelectedAccount() + .then((account) => { + this.settingsStore + .get("privacyShareAnalyticsData") + .then((isShareAnalyticsDataEnabled) => { + if ( + isShareAnalyticsDataEnabled && + isProd && + ((account && account.networkId === "mainnet-alpha") || !account) + ) { + return super.track(event, options).promise + } else { + return + } + }) + .catch((_error) => { + return + }) + }) + .catch((_error) => { + return + }), + } + } +} diff --git a/packages/extension/src/shared/analytics/index.ts b/packages/extension/src/shared/analytics/index.ts new file mode 100644 index 000000000..b9280ebb2 --- /dev/null +++ b/packages/extension/src/shared/analytics/index.ts @@ -0,0 +1,8 @@ +import { accountSharedService } from "../account/service" +import { settingsStore } from "../settings" +import { AnalyticsService } from "./implementation" + +export const analyticsService = new AnalyticsService( + accountSharedService, + settingsStore, +) diff --git a/packages/extension/src/shared/analytics/init.ts b/packages/extension/src/shared/analytics/init.ts new file mode 100644 index 000000000..07408b228 --- /dev/null +++ b/packages/extension/src/shared/analytics/init.ts @@ -0,0 +1,38 @@ +import { analyticsService } from "." +import { Environment } from "../../ampli" +import { settingsStore } from "../settings" +import { StoreDexie } from "../shield/idb" + +export const initAmplitude = async () => { + try { + const idb = new StoreDexie() + const privacyShareAnalyticsData = await settingsStore.get( + "privacyShareAnalyticsData", + ) + + const deviceId = await idb.ids.get("deviceId") + + const analyticsConfig = { + environment: "argentdev" as Environment, + disabled: privacyShareAnalyticsData === false, + client: { + configuration: { + defaultTracking: false, + ...(deviceId && { deviceId: deviceId.id }), + }, + }, + } + if (!analyticsService.isLoaded) { + analyticsService.load(analyticsConfig) + } + + if (!deviceId && analyticsService.isLoaded) { + const newDeviceId = analyticsService.client.getDeviceId() + if (newDeviceId) { + await idb.ids.add({ key: "deviceId", id: newDeviceId }) + } + } + } catch (e) { + console.error("Error loading ampli", e) + } +} diff --git a/packages/extension/src/shared/api/constants.ts b/packages/extension/src/shared/api/constants.ts index 3ffed45ee..4c4a6e5a1 100644 --- a/packages/extension/src/shared/api/constants.ts +++ b/packages/extension/src/shared/api/constants.ts @@ -101,22 +101,28 @@ export const PROVISION_STATUS_ENDPOINT = ARGENT_HEALTHCHECK_ENABLED ? urlJoin(ARGENT_HEALTHCHECK_BASE_URL, "provision-status.json") : undefined -// GOERLI only, mainnet ones are still unknown -export const PROVISION_CONTRACT_ADDRESSES = - process.env.ARGENT_X_ENVIRONMENT === "prod" - ? [ - "0x03ce54e2104cd65bb2117c8d401b0ce30139fafffb2ebf8811f70b362d8fac6e", - "0x0128492AB86D97475CDC074A06A827014E6AA10DA9BD745B26CCAFB8C1A54A9A", - "0x06793D9E6ED7182978454C79270E5B14D2655204BA6565CE9B0AA8A3C3121025", - "0x0517daba3622259ae4fffab72bb716d89c30df0994c6ab25ede61bd139639724", - ] - : [ - "0x02b2e8b8eb3429540c58c0dc69ebb2981267196fe0ca2e361056b852445ee766", - "0x0512e19eb3daa35c94592a251f939c8bb7e81795b6eca6148964b5778bf7dd6d", - "0x0761357121b07055dae758496c210da9ab7b422a831a6b90efa3704d85d128d0", - "0x0524983b9b9322fa94d94758d9d8cdd94c936479c77775babcc921bf1e1ad2b6", - ] +export const isProd = process.env.ARGENT_X_ENVIRONMENT === "prod" + +export const PROVISION_CONTRACT_ADDRESSES = isProd + ? [ + "0x071808540ed1139bcc8bb55eb975e8168758f2a342ce3f22c512a1c8da1b84dc", + "0x0128492AB86D97475CDC074A06A827014E6AA10DA9BD745B26CCAFB8C1A54A9A", + "0x06793D9E6ED7182978454C79270E5B14D2655204BA6565CE9B0AA8A3C3121025", + "0x0517daba3622259ae4fffab72bb716d89c30df0994c6ab25ede61bd139639724", + ] + : [ + "0x02b2e8b8eb3429540c58c0dc69ebb2981267196fe0ca2e361056b852445ee766", + "0x0512e19eb3daa35c94592a251f939c8bb7e81795b6eca6148964b5778bf7dd6d", + "0x0761357121b07055dae758496c210da9ab7b422a831a6b90efa3704d85d128d0", + "0x0524983b9b9322fa94d94758d9d8cdd94c936479c77775babcc921bf1e1ad2b6", + ] export const ARGENT_NETWORK_STATUS = ARGENT_API_ENABLED ? urlJoin(ARGENT_API_BASE_URL, "status/starknet") : undefined + +export const isCI = Boolean(process.env.CI) +export const ARGENT_PORTFOLIO_MAINNET_BASE_URL = + "https://portfolio.argent.xyz/overview/" +export const ARGENT_PORTFOLIO_GOERLI_BASE_URL = + "https://portfolio.hydrogen.argent47.net/overview/" diff --git a/packages/extension/src/shared/api/headers.ts b/packages/extension/src/shared/api/headers.ts index 51fb24833..8342e586f 100644 --- a/packages/extension/src/shared/api/headers.ts +++ b/packages/extension/src/shared/api/headers.ts @@ -1,4 +1,4 @@ -import type { ArgentBackendNetworkId, ArgentNetworkId } from "@argent/shared" +import type { ArgentBackendNetworkId, ArgentNetworkId } from "@argent/x-shared" const makeArgentXHeaders = () => ({ "argent-version": process.env.VERSION || "Unknown version", diff --git a/packages/extension/src/shared/call/erc20Call.ts b/packages/extension/src/shared/call/erc20Call.ts index 7c7f6ab1d..fff7594ea 100644 --- a/packages/extension/src/shared/call/erc20Call.ts +++ b/packages/extension/src/shared/call/erc20Call.ts @@ -1,4 +1,4 @@ -import { normalizeAddress } from "@argent/shared" +import { normalizeAddress } from "@argent/x-shared" import { Call, constants, validateAndParseAddress } from "starknet" import { num, uint256 } from "starknet" diff --git a/packages/extension/src/shared/call/nftTransferCall.ts b/packages/extension/src/shared/call/nftTransferCall.ts index 42b475a19..6977b519c 100644 --- a/packages/extension/src/shared/call/nftTransferCall.ts +++ b/packages/extension/src/shared/call/nftTransferCall.ts @@ -1,4 +1,4 @@ -import { normalizeAddress } from "@argent/shared" +import { normalizeAddress } from "@argent/x-shared" import { Call, CallData, num, uint256, validateAndParseAddress } from "starknet" const { uint256ToBN } = uint256 diff --git a/packages/extension/src/shared/call/udcDeclareCall.ts b/packages/extension/src/shared/call/udcDeclareCall.ts index 478c59246..4385da0fd 100644 --- a/packages/extension/src/shared/call/udcDeclareCall.ts +++ b/packages/extension/src/shared/call/udcDeclareCall.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { Call, constants, validateAndParseAddress } from "starknet" const { UDC } = constants diff --git a/packages/extension/src/shared/call/udcDeployCall.ts b/packages/extension/src/shared/call/udcDeployCall.ts index d5170de0b..2266c5fe6 100644 --- a/packages/extension/src/shared/call/udcDeployCall.ts +++ b/packages/extension/src/shared/call/udcDeployCall.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { Call, constants, validateAndParseAddress } from "starknet" const { UDC } = constants diff --git a/packages/extension/src/shared/chain/service/implementation.test.ts b/packages/extension/src/shared/chain/service/implementation.test.ts index 05327fc4d..4a897a67c 100644 --- a/packages/extension/src/shared/chain/service/implementation.test.ts +++ b/packages/extension/src/shared/chain/service/implementation.test.ts @@ -3,7 +3,7 @@ import { describe, expect, test, vi } from "vitest" import { INetworkService } from "../../network/service/interface" import { Network } from "../../network" import { StarknetChainService } from "./implementation" -import { Hex } from "@argent/shared" +import { Hex } from "@argent/x-shared" const mocks = vi.hoisted(() => { return { @@ -55,9 +55,8 @@ describe("StarknetChainService", () => { getTransactionReceipt: () => ({ finality_status: status }), }) - const txWithStatus = await starknetChainService.getTransactionStatus( - mockTransaction, - ) + const txWithStatus = + await starknetChainService.getTransactionStatus(mockTransaction) expect(txWithStatus.status.status).toEqual("confirmed") expect(getTransactionReceipt).not.toHaveBeenCalled() @@ -84,9 +83,8 @@ describe("StarknetChainService", () => { getTransactionReceipt, }) - const txWithStatus = await starknetChainService.getTransactionStatus( - mockTransaction, - ) + const txWithStatus = + await starknetChainService.getTransactionStatus(mockTransaction) expect(txWithStatus.status.status).toEqual("failed") expect(getTransactionReceipt).not.toHaveBeenCalled() @@ -114,9 +112,8 @@ describe("StarknetChainService", () => { getTransactionReceipt, }) - const txWithStatus = await starknetChainService.getTransactionStatus( - mockTransaction, - ) + const txWithStatus = + await starknetChainService.getTransactionStatus(mockTransaction) expect(txWithStatus.status.status).toEqual("failed") expect(getTransactionReceipt).toHaveBeenCalledWith(mockTransaction.hash) @@ -142,9 +139,8 @@ describe("StarknetChainService", () => { getTransactionReceipt, }) - const txWithStatus = await starknetChainService.getTransactionStatus( - mockTransaction, - ) + const txWithStatus = + await starknetChainService.getTransactionStatus(mockTransaction) expect(txWithStatus.status.status).toEqual("failed") expect(getTransactionReceipt).toHaveBeenCalledWith(mockTransaction.hash) diff --git a/packages/extension/src/shared/chain/service/implementation.ts b/packages/extension/src/shared/chain/service/implementation.ts index 27a700be4..31356d4a9 100644 --- a/packages/extension/src/shared/chain/service/implementation.ts +++ b/packages/extension/src/shared/chain/service/implementation.ts @@ -6,7 +6,7 @@ import { TransactionWithStatus, } from "../../transactions/interface" import { BaseContract, IChainService } from "./interface" -import { isContractDeployed } from "@argent/shared" +import { isContractDeployed } from "@argent/x-shared" import { SUCCESS_STATUSES } from "../../transactions" export class StarknetChainService implements IChainService { @@ -65,8 +65,8 @@ export class StarknetChainService implements IChainService { reason: new Error(error_reason), } : isSuccessful - ? { status: "confirmed" } - : { status: "pending" } + ? { status: "confirmed" } + : { status: "pending" } return { ...transaction, diff --git a/packages/extension/src/shared/errors/review.ts b/packages/extension/src/shared/errors/review.ts index f9023a4c7..a038bbf5f 100644 --- a/packages/extension/src/shared/errors/review.ts +++ b/packages/extension/src/shared/errors/review.ts @@ -4,7 +4,6 @@ export enum REVIEW_ERROR_MESSAGE { SIMULATE_AND_REVIEW_FAILED = "Something went wrong fetching review", NO_CALLS_FOUND = "No calls found", ONCHAIN_FEE_ESTIMATION_FAILED = "Failed to estimate fees onchain", - BACKEND_SIMULATION_ERROR = "There was an error in the backend simulation response", } export type ReviewErrorMessage = keyof typeof REVIEW_ERROR_MESSAGE diff --git a/packages/extension/src/shared/feeToken/service/implementation.test.ts b/packages/extension/src/shared/feeToken/service/implementation.test.ts index 81e9e3e7c..1308d28b4 100644 --- a/packages/extension/src/shared/feeToken/service/implementation.test.ts +++ b/packages/extension/src/shared/feeToken/service/implementation.test.ts @@ -18,7 +18,7 @@ import { STRK_TOKEN_ADDRESS, TXV3_ACCOUNT_CLASS_HASH, } from "../../network/constants" -import { Address, IHttpService, addressSchema } from "@argent/shared" +import { Address, IHttpService, addressSchema } from "@argent/x-shared" import { stark } from "starknet" import { defaultNetwork } from "../../network" import { getMockNetwork } from "../../../../test/network.mock" diff --git a/packages/extension/src/shared/feeToken/service/implementation.ts b/packages/extension/src/shared/feeToken/service/implementation.ts index 7d79661ad..5f46edb76 100644 --- a/packages/extension/src/shared/feeToken/service/implementation.ts +++ b/packages/extension/src/shared/feeToken/service/implementation.ts @@ -5,7 +5,7 @@ import { TokenWithBalance } from "../../token/__new/types/tokenBalance.model" import { BaseWalletAccount, WalletAccount } from "../../wallet.model" import { IFeeTokenService } from "./interface" import { INetworkService } from "../../network/service/interface" -import { Address, isEqualAddress } from "@argent/shared" +import { Address, isEqualAddress } from "@argent/x-shared" import { classHashSupportsTxV3, feeTokenNeedsTxV3Support, diff --git a/packages/extension/src/shared/feeToken/types/preference.model.ts b/packages/extension/src/shared/feeToken/types/preference.model.ts index c3b45472a..bead1e38a 100644 --- a/packages/extension/src/shared/feeToken/types/preference.model.ts +++ b/packages/extension/src/shared/feeToken/types/preference.model.ts @@ -1,5 +1,5 @@ import { z } from "zod" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" export const FeeTokenPreferenceSchema = z.object({ prefer: addressSchema, diff --git a/packages/extension/src/shared/feeToken/utils.test.ts b/packages/extension/src/shared/feeToken/utils.test.ts index f7b9b7387..408a3642a 100644 --- a/packages/extension/src/shared/feeToken/utils.test.ts +++ b/packages/extension/src/shared/feeToken/utils.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from "vitest" -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" import { BaseTokenWithBalance } from "../token/__new/types/tokenBalance.model" import { STRK_TOKEN_ADDRESS } from "../network/constants" import { pickBestFeeToken } from "./utils" diff --git a/packages/extension/src/shared/feeToken/utils.ts b/packages/extension/src/shared/feeToken/utils.ts index 30069657c..d0d370f4a 100644 --- a/packages/extension/src/shared/feeToken/utils.ts +++ b/packages/extension/src/shared/feeToken/utils.ts @@ -1,4 +1,4 @@ -import { Address, isEqualAddress } from "@argent/shared" +import { Address, isEqualAddress } from "@argent/x-shared" import { FeeTokenPreferenceOption } from "./types/preference.model" import { num } from "starknet" import { arrayOrderWith } from "../utils/arrayOrderWith" diff --git a/packages/extension/src/shared/http/singleton.ts b/packages/extension/src/shared/http/singleton.ts index c121f874f..55c8a9051 100644 --- a/packages/extension/src/shared/http/singleton.ts +++ b/packages/extension/src/shared/http/singleton.ts @@ -1,4 +1,4 @@ -import { HTTPService } from "@argent/shared" +import { HTTPService } from "@argent/x-shared" import { argentXHeaders } from "../api/headers" diff --git a/packages/extension/src/shared/knownDapps.ts b/packages/extension/src/shared/knownDapps.ts index 49303e9ee..eaf1f456a 100644 --- a/packages/extension/src/shared/knownDapps.ts +++ b/packages/extension/src/shared/knownDapps.ts @@ -1,4 +1,4 @@ -import { includesAddress } from "@argent/shared" +import { includesAddress } from "@argent/x-shared" import untypedKnownDapps from "../assets/known-dapps.json" diff --git a/packages/extension/src/shared/knownDapps/implementation.ts b/packages/extension/src/shared/knownDapps/implementation.ts index 6f95e991f..6d96e6e60 100644 --- a/packages/extension/src/shared/knownDapps/implementation.ts +++ b/packages/extension/src/shared/knownDapps/implementation.ts @@ -1,4 +1,8 @@ -import { KnownDapp, KnownDapps, KnownDappsBackendService } from "@argent/shared" +import { + KnownDapp, + KnownDapps, + KnownDappsBackendService, +} from "@argent/x-shared" import { IKnownDappsRepository } from "../storage/__new/repositories/knownDapp" import { IKnownDappService } from "./interface" diff --git a/packages/extension/src/shared/knownDapps/index.ts b/packages/extension/src/shared/knownDapps/index.ts index 272b834f6..3d7fc910a 100644 --- a/packages/extension/src/shared/knownDapps/index.ts +++ b/packages/extension/src/shared/knownDapps/index.ts @@ -1,4 +1,4 @@ -import { ArgentKnownDappsBackendService } from "@argent/shared" +import { ArgentKnownDappsBackendService } from "@argent/x-shared" import { ARGENT_API_BASE_URL } from "../api/constants" import { KnownDappService } from "./implementation" import { knownDappsRepository } from "../storage/__new/repositories/knownDapp" diff --git a/packages/extension/src/shared/knownDapps/interface.ts b/packages/extension/src/shared/knownDapps/interface.ts index ea0e1401f..8d77fdcd0 100644 --- a/packages/extension/src/shared/knownDapps/interface.ts +++ b/packages/extension/src/shared/knownDapps/interface.ts @@ -1,4 +1,4 @@ -import { KnownDapp, KnownDapps } from "@argent/shared" +import { KnownDapp, KnownDapps } from "@argent/x-shared" export interface IKnownDappService { getDapps: () => Promise diff --git a/packages/extension/src/shared/messages/NetworkMessage.ts b/packages/extension/src/shared/messages/NetworkMessage.ts index 2e75002ad..bd69896fc 100644 --- a/packages/extension/src/shared/messages/NetworkMessage.ts +++ b/packages/extension/src/shared/messages/NetworkMessage.ts @@ -2,9 +2,15 @@ import { Network } from "../network" import { WalletAccount } from "../wallet.model" export type NetworkMessage = + | { type: "REQUEST_SELECTED_NETWORK" } + | { type: "REQUEST_SELECTED_NETWORK_RES"; data: { network: Network } } + | { type: "REQUEST_SELECTED_NETWORK_REJ"; data: { error: string } } // - used by dapps to request addition of custom network - | { type: "REQUEST_ADD_CUSTOM_NETWORK"; data: Network } - | { type: "REQUEST_ADD_CUSTOM_NETWORK_RES"; data: { actionHash: string } } + | { type: "REQUEST_ADD_CUSTOM_NETWORK"; data: Partial } + | { + type: "REQUEST_ADD_CUSTOM_NETWORK_RES" + data: { exists: boolean; actionHash?: string } + } | { type: "REQUEST_ADD_CUSTOM_NETWORK_REJ" data: { error: string } @@ -17,7 +23,10 @@ export type NetworkMessage = type: "REQUEST_SWITCH_CUSTOM_NETWORK" data: { chainId: Network["chainId"] } } - | { type: "REQUEST_SWITCH_CUSTOM_NETWORK_RES"; data: { actionHash: string } } + | { + type: "REQUEST_SWITCH_CUSTOM_NETWORK_RES" + data: { exists: boolean; actionHash?: string } + } | { type: "REQUEST_SWITCH_CUSTOM_NETWORK_REJ" data: { error: string } diff --git a/packages/extension/src/shared/messages/PreAuthorisationMessage.ts b/packages/extension/src/shared/messages/PreAuthorisationMessage.ts index f18de74f5..43eb4758a 100644 --- a/packages/extension/src/shared/messages/PreAuthorisationMessage.ts +++ b/packages/extension/src/shared/messages/PreAuthorisationMessage.ts @@ -1,7 +1,7 @@ import { WalletAccount } from "../wallet.model" export type PreAuthorisationMessage = - | { type: "CONNECT_DAPP" } + | { type: "CONNECT_DAPP"; data?: { silent?: boolean } } | { type: "CONNECT_DAPP_RES"; data: WalletAccount } | { type: "IS_PREAUTHORIZED" } | { type: "IS_PREAUTHORIZED_RES"; data: boolean } diff --git a/packages/extension/src/shared/messages/TokenMessage.ts b/packages/extension/src/shared/messages/TokenMessage.ts index e109048fb..5d81b54ce 100644 --- a/packages/extension/src/shared/messages/TokenMessage.ts +++ b/packages/extension/src/shared/messages/TokenMessage.ts @@ -3,6 +3,9 @@ import { RequestToken } from "../token/__new/types/token.model" export type TokenMessage = // - used by dapps to request tokens | { type: "REQUEST_TOKEN"; data: RequestToken } - | { type: "REQUEST_TOKEN_RES"; data: { actionHash?: string } } // returns no actionHash if the token already exists + | { + type: "REQUEST_TOKEN_RES" + data: { exists: boolean; actionHash?: string } + } // returns no actionHash if the token already exists | { type: "REJECT_REQUEST_TOKEN"; data: { actionHash: string } } | { type: "APPROVE_REQUEST_TOKEN"; data: { actionHash: string } } diff --git a/packages/extension/src/shared/messages/TransactionMessage.ts b/packages/extension/src/shared/messages/TransactionMessage.ts index a1ac8d23e..c922296c3 100644 --- a/packages/extension/src/shared/messages/TransactionMessage.ts +++ b/packages/extension/src/shared/messages/TransactionMessage.ts @@ -8,7 +8,7 @@ import { import { DeclareContract, DeployContract } from "../udc/schema" import { TransactionError } from "../errors/transaction" import { EstimatedFees } from "../transactionSimulation/fees/fees.model" -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" export interface ExecuteTransactionRequest { transactions: Call | Call[] diff --git a/packages/extension/src/shared/multisig/account.ts b/packages/extension/src/shared/multisig/account.ts index 54d59758f..550582c4c 100644 --- a/packages/extension/src/shared/multisig/account.ts +++ b/packages/extension/src/shared/multisig/account.ts @@ -15,7 +15,7 @@ import { import { MultisigPendingTransaction } from "./pendingTransactionsStore" import { MultisigSigner } from "./signer" import { IMultisigBackendService } from "./service/backend/interface" -import { isAccountV5 } from "@argent/shared" +import { isAccountV5 } from "@argent/x-shared" import { txVersionSchema, TransactionVersion, diff --git a/packages/extension/src/shared/multisig/repository.ts b/packages/extension/src/shared/multisig/repository.ts index 4da367085..64c703a28 100644 --- a/packages/extension/src/shared/multisig/repository.ts +++ b/packages/extension/src/shared/multisig/repository.ts @@ -6,7 +6,7 @@ import { PendingMultisig, } from "./types" import { ChromeRepository } from "../storage/__new/chrome" -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import browser from "webextension-polyfill" import { accountsEqual } from "../utils/accountsEqual" import { pendingMultisigEqual } from "./utils/selectors" @@ -33,6 +33,6 @@ export const multisigMetadataRepo: IMultisigMetadataRepository = areaName: "local", namespace: "core:multisig:signerNames", compare(a: MultisigMetadata, b: MultisigMetadata) { - return isEqualAddress(a.creator, b.creator) + return isEqualAddress(a.multisigPublicKey, b.multisigPublicKey) }, }) diff --git a/packages/extension/src/shared/multisig/service/backend/implementation.test.ts b/packages/extension/src/shared/multisig/service/backend/implementation.test.ts index cad394b9a..236c8ef00 100644 --- a/packages/extension/src/shared/multisig/service/backend/implementation.test.ts +++ b/packages/extension/src/shared/multisig/service/backend/implementation.test.ts @@ -78,6 +78,8 @@ describe("MultisigBackendService", () => { headers: { Accept: "application/json", "Content-Type": "application/json", + "argent-client": "argent-x", + "argent-version": "Unknown version", }, method: "GET", body: undefined, @@ -142,6 +144,8 @@ describe("MultisigBackendService", () => { headers: { Accept: "application/json", "Content-Type": "application/json", + "argent-client": "argent-x", + "argent-version": "Unknown version", }, method: "GET", body: undefined, @@ -216,6 +220,8 @@ describe("MultisigBackendService", () => { headers: { Accept: "application/json", "Content-Type": "application/json", + "argent-client": "argent-x", + "argent-version": "Unknown version", }, method: "GET", body: undefined, @@ -330,6 +336,8 @@ describe("MultisigBackendService", () => { headers: { Accept: "application/json", "Content-Type": "application/json", + "argent-client": "argent-x", + "argent-version": "Unknown version", }, method: "POST", body: JSON.stringify(payload), @@ -429,6 +437,8 @@ describe("MultisigBackendService", () => { headers: { Accept: "application/json", "Content-Type": "application/json", + "argent-client": "argent-x", + "argent-version": "Unknown version", }, method: "POST", body: JSON.stringify(payload), @@ -557,6 +567,8 @@ describe("MultisigBackendService", () => { headers: { Accept: "application/json", "Content-Type": "application/json", + "argent-client": "argent-x", + "argent-version": "Unknown version", }, method: "POST", }, diff --git a/packages/extension/src/shared/multisig/service/backend/implementation.ts b/packages/extension/src/shared/multisig/service/backend/implementation.ts index 6a1fd57c9..71bfb20d1 100644 --- a/packages/extension/src/shared/multisig/service/backend/implementation.ts +++ b/packages/extension/src/shared/multisig/service/backend/implementation.ts @@ -49,6 +49,7 @@ import { multisigPendingTransactionToTransaction, } from "../../pendingTransactionsStore" import { MultisigError } from "../../../errors/multisig" +import { argentXHeaders } from "../../../api/headers" export class MultisigBackendService implements IMultisigBackendService { public readonly baseUrl: string @@ -106,6 +107,7 @@ export class MultisigBackendService implements IMultisigBackendService { headers: { Accept: "application/json", "Content-Type": "application/json", + ...argentXHeaders, }, body, }) diff --git a/packages/extension/src/shared/multisig/types.ts b/packages/extension/src/shared/multisig/types.ts index 00ee67e31..3d73c0d84 100644 --- a/packages/extension/src/shared/multisig/types.ts +++ b/packages/extension/src/shared/multisig/types.ts @@ -36,7 +36,7 @@ export interface SignerMetadata { name: string } export interface MultisigMetadata { - creator: string + multisigPublicKey: string signers: SignerMetadata[] } diff --git a/packages/extension/src/shared/multisig/utils/pendingMultisig.ts b/packages/extension/src/shared/multisig/utils/pendingMultisig.ts index 49ae9b9e6..e2e8eb13c 100644 --- a/packages/extension/src/shared/multisig/utils/pendingMultisig.ts +++ b/packages/extension/src/shared/multisig/utils/pendingMultisig.ts @@ -45,7 +45,13 @@ export async function removePendingMultisig( throw new Error("Pending multisig to remove not found") } - return pendingMultisigRepo.remove(pendingMultisig) + return pendingMultisigRepo.remove( + // pendingMultisigEqual(pendingMultisig, basePendingMultisig), + (multisig) => pendingMultisigEqual(multisig, basePendingMultisig), + // multisig.name === pendingMultisig.name && + // multisig.networkId === pendingMultisig.networkId && + // multisig.publicKey === pendingMultisig.publicKey, + ) } export async function pendingMultisigToMultisig( @@ -106,6 +112,12 @@ export async function hidePendingMultisig(base: BasePendingMultisig) { }) } +export async function deletePendingMultisig(base: BasePendingMultisig) { + await pendingMultisigRepo.remove((pendingMultisig) => + pendingMultisigEqual(pendingMultisig, base), + ) +} + export async function unhidePendingMultisig( base: BasePendingMultisig, hidden: boolean, diff --git a/packages/extension/src/shared/network/index.ts b/packages/extension/src/shared/network/index.ts index 42c2320a7..66f6f9d26 100644 --- a/packages/extension/src/shared/network/index.ts +++ b/packages/extension/src/shared/network/index.ts @@ -5,4 +5,4 @@ export { } from "./defaults" export { getProvider, getProvider6 } from "./provider" export { networkSchema } from "./schema" -export type { Network, NetworkStatus } from "./type" +export type { Network, ColorStatus } from "./type" diff --git a/packages/extension/src/shared/network/makeSafeNetworks.ts b/packages/extension/src/shared/network/makeSafeNetworks.ts index e271f56cd..26e165149 100644 --- a/packages/extension/src/shared/network/makeSafeNetworks.ts +++ b/packages/extension/src/shared/network/makeSafeNetworks.ts @@ -1,4 +1,4 @@ -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" import type { Network } from "./type" import { ETH_TOKEN_ADDRESS } from "./constants" import { networkSchema } from "." diff --git a/packages/extension/src/shared/network/schema.test.ts b/packages/extension/src/shared/network/schema.test.ts new file mode 100644 index 000000000..33dfeafaa --- /dev/null +++ b/packages/extension/src/shared/network/schema.test.ts @@ -0,0 +1,97 @@ +import { describe, test, expect } from "vitest" + +import { + mainnetChainIdSchema, + notMainnetChainIdSchema, + notMainnetChainIdNetworkSchema, +} from "./schema" + +describe("shared/network/schema", () => { + describe("mainnetChainIdSchema", () => { + describe("when valid", () => { + test("parses", () => { + expect(() => mainnetChainIdSchema.parse("SN_MAIN")).not.toThrow() + expect(() => mainnetChainIdSchema.parse("sn_Main")).not.toThrow() + }) + }) + describe("when invalid", () => { + test("throws", () => { + expect(() => mainnetChainIdSchema.parse("SN_GOERLI")).toThrowError( + "Invalid enum value. Expected 'SN_MAIN' | '0X534E5F4D41494E', received 'SN_GOERLI'", + ) + }) + }) + }) + describe("notMainnetChainIdSchema", () => { + describe("when valid", () => { + test("parses", () => { + expect(() => notMainnetChainIdSchema.parse("SN_GOERLI")).not.toThrow() + }) + }) + describe("when invalid", () => { + test("throws", () => { + expect(() => + notMainnetChainIdSchema.parse("0x534e5F4D41494E"), + ).toThrowError("Chain ID is reserved") + expect(() => notMainnetChainIdSchema.parse("SN_MAIN")).toThrowError( + "Chain ID is reserved", + ) + expect(() => + notMainnetChainIdSchema.parse("0x534e5f4d41494e"), + ).toThrowError("Chain ID is reserved") + expect(() => notMainnetChainIdSchema.parse("sn_Main")).toThrowError( + "Chain ID is reserved", + ) + }) + }) + }) + describe("notMainnetChainIdNetworkSchema", () => { + describe("when valid", () => { + test("parses", () => { + expect(() => + notMainnetChainIdNetworkSchema.parse({ + name: "Test", + id: "dapp-test", + chainId: "SN_DAPP_TEST", + chainName: "Test chain name", + baseUrl: "http://localhost:5050", + rpcUrl: "http://localhost:5050/rpc", + possibleFeeTokenAddresses: [ + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + ], + }), + ).not.toThrow() + }) + }) + describe("when invalid", () => { + test("throws", () => { + expect(() => + notMainnetChainIdNetworkSchema.parse({ + name: "Test", + id: "dapp-test", + chainId: "SN_MAIN", + chainName: "Test chain name", + baseUrl: "http://localhost:5050", + rpcUrl: "http://localhost:5050/rpc", + possibleFeeTokenAddresses: [ + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + ], + }), + ).toThrowError("Chain ID is reserved") + expect(() => + notMainnetChainIdNetworkSchema.parse({ + name: "Test", + id: "dapp-test", + chainId: "0x534e5f4d41494e", + chainName: "Test chain name", + baseUrl: "http://localhost:5050", + rpcUrl: "http://localhost:5050/rpc", + possibleFeeTokenAddresses: [ + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + ], + }), + ).toThrowError("Chain ID is reserved") + }) + }) + }) +}) diff --git a/packages/extension/src/shared/network/schema.ts b/packages/extension/src/shared/network/schema.ts index 2f8e86d9c..4898d6e66 100644 --- a/packages/extension/src/shared/network/schema.ts +++ b/packages/extension/src/shared/network/schema.ts @@ -1,5 +1,6 @@ -import { addressOrEmptyUndefinedSchema, addressSchema } from "@argent/shared" +import { addressOrEmptyUndefinedSchema, addressSchema } from "@argent/x-shared" import { z } from "zod" +import { constants } from "starknet" const REGEX_HEXSTRING = /^0x[a-f0-9]+$/i @@ -7,18 +8,39 @@ export const baseNetworkSchema = z.object({ id: z.string().min(2).max(31), }) -export const networkStatusSchema = z.enum(["red", "amber", "green", "unknown"]) +export const colorStatusSchema = z.enum(["red", "amber", "green", "unknown"]) + +export const mainnetChainIdSchema = z + .string() + .transform((t) => t.toUpperCase()) + .pipe( + z.enum([ + constants.NetworkName.SN_MAIN, + constants.StarknetChainId.SN_MAIN.toUpperCase(), + ]), + ) + +export const chainIdSchema = z + .string() + .min(2, "ChainId must be at least 2 characters") + .max(31, "ChainId cannot be longer than 31 characters") // max 31 characters as required by starknet short strings + .regex(/^[a-zA-Z0-9_]+$/, { + message: + "chain id must be hexadecimal string, uppercase alphanumeric or underscore, like 'SN_ABCXYZ'", + }) + +export const notMainnetChainIdSchema = chainIdSchema.refine( + (value) => { + return !mainnetChainIdSchema.safeParse(value).success + }, + { + message: "Chain ID is reserved", + }, +) export const networkSchema = baseNetworkSchema.extend({ name: z.string().min(2).max(128), - chainId: z - .string() - .min(2, "ChainId must be at least 2 characters") - .max(31, "ChainId cannot be longer than 31 characters") // max 31 characters as required by starknet short strings - .regex(/^[a-zA-Z0-9_]+$/, { - message: - "chain id must be hexadecimal string, uppercase alphanumeric or underscore, like 'SN_GOERLI'", - }), + chainId: chainIdSchema, rpcUrl: z.string().url("RPC url must be a valid URL"), possibleFeeTokenAddresses: z.array(addressSchema).nonempty(), // z.array(addressSchema).min(1) but with better type accountImplementation: z.optional( @@ -85,7 +107,11 @@ export const networkSchema = baseNetworkSchema.extend({ readonly: z.optional(z.boolean()), }) +export const notMainnetChainIdNetworkSchema = networkSchema.extend({ + chainId: notMainnetChainIdSchema, +}) + export const networkWithStatusSchema = z.object({ id: z.string(), - status: networkStatusSchema, + status: colorStatusSchema, }) diff --git a/packages/extension/src/shared/network/txv3.ts b/packages/extension/src/shared/network/txv3.ts index f274452a3..f1feda51e 100644 --- a/packages/extension/src/shared/network/txv3.ts +++ b/packages/extension/src/shared/network/txv3.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { STRK_TOKEN_ADDRESS, TXV3_ACCOUNT_CLASS_HASH } from "./constants" import { BaseToken } from "../token/__new/types/token.model" diff --git a/packages/extension/src/shared/network/type.ts b/packages/extension/src/shared/network/type.ts index 50ba049be..0a08eab14 100644 --- a/packages/extension/src/shared/network/type.ts +++ b/packages/extension/src/shared/network/type.ts @@ -1,10 +1,10 @@ -import type { ArgentNetworkId, ArgentBackendNetworkId } from "@argent/shared" +import type { ArgentNetworkId, ArgentBackendNetworkId } from "@argent/x-shared" import { z } from "zod" import { baseNetworkSchema, networkSchema, - networkStatusSchema, + colorStatusSchema, networkWithStatusSchema, } from "./schema" @@ -14,7 +14,7 @@ export type Network = z.infer export type NetworkWithStatus = z.infer -export type NetworkStatus = z.infer +export type ColorStatus = z.infer export type DefaultNetworkId = ArgentNetworkId | "localhost" | "integration" diff --git a/packages/extension/src/shared/network/utils.ts b/packages/extension/src/shared/network/utils.ts index b9adb9e03..bfca8aae7 100644 --- a/packages/extension/src/shared/network/utils.ts +++ b/packages/extension/src/shared/network/utils.ts @@ -3,10 +3,10 @@ import { isEqualAddress, type ArgentNetworkId, isArgentNetworkId, -} from "@argent/shared" +} from "@argent/x-shared" import type { ArgentAccountType } from "../wallet.model" -import type { DefaultNetworkId, Network, PublicRpcNode } from "./type" +import type { DefaultNetworkId, Network } from "./type" import { PUBLIC_RPC_NODES } from "./constants" import { argentApiNetworkForNetwork } from "../api/headers" diff --git a/packages/extension/src/shared/nft/implementation.ts b/packages/extension/src/shared/nft/implementation.ts index 545ff44e0..2ca50b55b 100644 --- a/packages/extension/src/shared/nft/implementation.ts +++ b/packages/extension/src/shared/nft/implementation.ts @@ -6,8 +6,9 @@ import { type NftItem, type PaginatedItems, isEqualAddress, + isArgentNetworkId, PaginatedCollections, -} from "@argent/shared" +} from "@argent/x-shared" import { differenceWith, groupBy, isEqual } from "lodash-es" import { AllowArray, constants, num, shortString } from "starknet" import type { INFTService } from "./interface" @@ -56,6 +57,9 @@ export class NFTService implements INFTService { isSupported(network: Network) { try { + if (!isArgentNetworkId(network.id)) { + return false + } chainIdToPandoraNetwork(network.chainId) // throws if not supported return true } catch { @@ -252,9 +256,8 @@ export class NFTService implements INFTService { if (isEkuboNft(nft)) { nftMarketplace = ekuboMarketplace } else { - const nftMarketplaceKey = await this.settingsStore.get( - "nftMarketplaceKey", - ) + const nftMarketplaceKey = + await this.settingsStore.get("nftMarketplaceKey") nftMarketplace = defaultNftMarketplaces[nftMarketplaceKey] } if (!nftMarketplace.url[networkId]) { diff --git a/packages/extension/src/shared/nft/index.ts b/packages/extension/src/shared/nft/index.ts index 4c5c38a2b..7e729d027 100644 --- a/packages/extension/src/shared/nft/index.ts +++ b/packages/extension/src/shared/nft/index.ts @@ -1,4 +1,4 @@ -import { ArgentBackendNftService } from "@argent/shared" +import { ArgentBackendNftService } from "@argent/x-shared" import { networkService } from "../network/service" import { nftsCollectionsRepository, diff --git a/packages/extension/src/shared/nft/interface.ts b/packages/extension/src/shared/nft/interface.ts index 590edd5e1..fd649b220 100644 --- a/packages/extension/src/shared/nft/interface.ts +++ b/packages/extension/src/shared/nft/interface.ts @@ -1,4 +1,4 @@ -import { Address, Collection, NftItem } from "@argent/shared" +import { Address, Collection, NftItem } from "@argent/x-shared" import { ContractAddress } from "../storage/__new/repositories/nft" import { AllowArray } from "../storage/types" import { Network } from "../network" diff --git a/packages/extension/src/shared/nft/marketplaces/defaultNftMarketplaces.ts b/packages/extension/src/shared/nft/marketplaces/defaultNftMarketplaces.ts index 56e0d2c0f..25c6e7fd4 100644 --- a/packages/extension/src/shared/nft/marketplaces/defaultNftMarketplaces.ts +++ b/packages/extension/src/shared/nft/marketplaces/defaultNftMarketplaces.ts @@ -1,4 +1,4 @@ -import type { Address } from "@argent/shared" +import type { Address } from "@argent/x-shared" import type { NftMarketplaces } from "./types" export const defaultNftMarketplaces: NftMarketplaces = { @@ -15,7 +15,7 @@ export const defaultNftMarketplaces: NftMarketplaces = { logo: "FlexLogo", url: { "mainnet-alpha": (contractAddress: Address, tokenId: string) => - `https://flexing.gg/starknet/asset/${contractAddress}/${tokenId}`, + `https://hyperflex.market/starknet/asset/${contractAddress}/${tokenId}`, }, }, pyramid: { diff --git a/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.test.ts b/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.test.ts index 36e150923..c5505fe74 100644 --- a/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.test.ts +++ b/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "vitest" import { isEkuboNft } from "./ekuboMarketplace" -import { NftItem } from "@argent/shared" +import { NftItem } from "@argent/x-shared" const mockEkuboNft: Partial = { token_id: "231988", diff --git a/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.ts b/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.ts index a5faa1def..709012f04 100644 --- a/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.ts +++ b/packages/extension/src/shared/nft/marketplaces/ekuboMarketplace.ts @@ -1,4 +1,4 @@ -import { Address, NftItem, isEqualAddress } from "@argent/shared" +import { Address, NftItem, isEqualAddress } from "@argent/x-shared" import { constants } from "starknet" import { z } from "zod" diff --git a/packages/extension/src/shared/nft/marketplaces/types.ts b/packages/extension/src/shared/nft/marketplaces/types.ts index 33d9eab75..a8d44fb73 100644 --- a/packages/extension/src/shared/nft/marketplaces/types.ts +++ b/packages/extension/src/shared/nft/marketplaces/types.ts @@ -1,5 +1,8 @@ -import type { Address } from "@argent/shared" -import { logos } from "@argent/ui" +import type { Address } from "@argent/x-shared" +// just using types here +// eslint-disable-next-line @argent/local/code-import-patterns +import { logos } from "@argent/x-ui" + import { defaultNftMarketplaces } from "./defaultNftMarketplaces" export type NftMarketplaceKey = keyof typeof defaultNftMarketplaces diff --git a/packages/extension/src/shared/nft/test/index.test.ts b/packages/extension/src/shared/nft/test/index.test.ts index 9816bab47..f397b5a36 100644 --- a/packages/extension/src/shared/nft/test/index.test.ts +++ b/packages/extension/src/shared/nft/test/index.test.ts @@ -1,4 +1,4 @@ -import { ArgentBackendNftService } from "@argent/shared" +import { ArgentBackendNftService } from "@argent/x-shared" import { rest } from "msw" import { setupServer } from "msw/node" import { beforeEach, describe, expect, vi, Mocked } from "vitest" diff --git a/packages/extension/src/shared/schedule/chromeService.test.ts b/packages/extension/src/shared/schedule/chromeService.test.ts index b2c27330c..98b55b168 100644 --- a/packages/extension/src/shared/schedule/chromeService.test.ts +++ b/packages/extension/src/shared/schedule/chromeService.test.ts @@ -35,6 +35,7 @@ function getMockBrowser() { } describe("ChromeScheduleService", () => { + const alarmVersion = "v1.2.3" let waitFn = vi.fn() let service: ChromeScheduleService let mockBrowser = getMockBrowser() @@ -42,7 +43,7 @@ describe("ChromeScheduleService", () => { beforeEach(() => { waitFn = vi.fn() mockBrowser = getMockBrowser() - service = new ChromeScheduleService(mockBrowser, waitFn) + service = new ChromeScheduleService(mockBrowser, alarmVersion, waitFn) }) test("every creates an alarm", async () => { @@ -58,11 +59,16 @@ describe("ChromeScheduleService", () => { id: "test", } mockBrowser.alarms.getAll.mockResolvedValue([ - { name: "test::run1" }, - { name: "other::run1" }, + { name: `${alarmVersion}::test::run1` }, + { name: `${alarmVersion}::other::run1` }, ]) await service.delete(task) - expect(mockBrowser.alarms.clear).toBeCalledWith("test::run1") + expect(mockBrowser.alarms.clear).toBeCalledWith( + `${alarmVersion}::test::run1`, + ) + expect(mockBrowser.alarms.clear).not.toBeCalledWith( + `${alarmVersion}::other::run1`, + ) }) test("registerImplementation adds alarm listener", async () => { @@ -73,14 +79,14 @@ describe("ChromeScheduleService", () => { await service.registerImplementation(task) expect(mockBrowser.alarms.onAlarm.addListener).toBeCalled() const callback = mockBrowser.alarms.onAlarm.addListener.mock.calls[0][0] - callback({ name: "test::run1" }) + callback({ name: `${alarmVersion}::test::run1` }) expect(task.callback).toBeCalled() }) test("registerImplementation runs callback once per minute", async () => { let cb: ((alarm: { name: string }) => void) | undefined = undefined const task: ImplementedScheduledTask = { - id: "test", + id: `test`, callback: vi.fn(), } mockBrowser.alarms.onAlarm.addListener.mockImplementationOnce( @@ -92,7 +98,7 @@ describe("ChromeScheduleService", () => { expect(mockBrowser.alarms.onAlarm.addListener).toBeCalled() expect(cb).toBeDefined() mockBrowser.alarms.create.mockImplementationOnce((name, options) => { - expect(name).toBe("test::run1") + expect(name).toBe(`${alarmVersion}::test::run1`) expect(options).toEqual({ periodInMinutes: 1 }) cb?.({ name }) }) @@ -119,7 +125,7 @@ describe("ChromeScheduleService", () => { const mockBrowserAlarmFired = vi.fn() mockBrowser.alarms.create.mockImplementationOnce((name, options) => { - expect(name).toBe("test::run5") + expect(name).toBe(`${alarmVersion}::test::run5`) expect(options).toEqual({ periodInMinutes: 1 }) // simulate the 1-minute delay in browser alarms setTimeout(() => { diff --git a/packages/extension/src/shared/schedule/chromeService.ts b/packages/extension/src/shared/schedule/chromeService.ts index b9ef9a85b..a0fede0bc 100644 --- a/packages/extension/src/shared/schedule/chromeService.ts +++ b/packages/extension/src/shared/schedule/chromeService.ts @@ -1,4 +1,5 @@ import { DeepPick } from "../types/deepPick" +import { ALARM_VERSION } from "./constants" import { BaseScheduledTask, IScheduleService, @@ -20,9 +21,6 @@ const wait: WaitFn = (ms: number) => { return new Promise((resolve) => setTimeout(resolve, ms)) } -function isEqualAlarmId(a: string, b?: string) { - return a === b || (b && a.startsWith(`${b}::`)) -} function getFrequency(id: string) { const match = id.match(/::run(\d+)$/) return match ? parseInt(match[1]) : 1 @@ -34,6 +32,7 @@ async function runWithTimer(fn: () => Promise): Promise { const duration = Date.now() - start return duration } + async function runXTimesPerMinute( timesPerMinute: number, fn: () => Promise, @@ -52,18 +51,26 @@ export class ChromeScheduleService implements IScheduleService { constructor( private readonly browser: MinimalBrowser, + private readonly alarmVersion = ALARM_VERSION, private readonly waitFn: (ms: number) => Promise = wait, ) {} + isEqualAlarmId(a: string, b?: string) { + return a === b || (b && a.startsWith(`${this.alarmVersion}::${b}::`)) + } + async every(seconds: number, task: BaseScheduledTask): Promise { const isSubMinute = seconds < 60 const timesPerMinute = isSubMinute ? Math.max(Math.floor(60 / seconds - 1), 1) : 1 const periodInMinutes = Math.max(Math.round(seconds / 60), 1) - await this.browser.alarms.create(`${task.id}::run${timesPerMinute}`, { - periodInMinutes, - }) + await this.browser.alarms.create( + `${this.alarmVersion}::${task.id}::run${timesPerMinute}`, + { + periodInMinutes, + }, + ) if (isSubMinute) { const taskImpl = this.taskImplementationById[task.id] void runXTimesPerMinute(timesPerMinute, taskImpl.callback, this.waitFn) @@ -72,7 +79,7 @@ export class ChromeScheduleService implements IScheduleService { async in(seconds: number, task: BaseScheduledTask): Promise { const delayInMinutes = Math.max(Math.round(seconds / 60), 1) - await this.browser.alarms.create(`${task.id}::run1`, { + await this.browser.alarms.create(`${this.alarmVersion}::${task.id}::run1`, { delayInMinutes, }) } @@ -81,7 +88,7 @@ export class ChromeScheduleService implements IScheduleService { delete this.taskImplementationById[task.id] const allAlarms = await this.browser.alarms.getAll() const alarmsToDelete = allAlarms - .filter((alarm) => isEqualAlarmId(alarm.name, task.id)) + .filter((alarm) => this.isEqualAlarmId(alarm.name, task.id)) .map((alarm) => alarm.name) await Promise.allSettled( @@ -92,7 +99,7 @@ export class ChromeScheduleService implements IScheduleService { async registerImplementation(task: ImplementedScheduledTask): Promise { this.taskImplementationById[task.id] = task this.browser.alarms.onAlarm.addListener((alarm) => { - if (isEqualAlarmId(alarm.name, task.id)) { + if (this.isEqualAlarmId(alarm.name, task.id)) { const frequency = getFrequency(alarm.name) void runXTimesPerMinute(frequency, task.callback, this.waitFn) } diff --git a/packages/extension/src/shared/schedule/constants.ts b/packages/extension/src/shared/schedule/constants.ts new file mode 100644 index 000000000..4482d0920 --- /dev/null +++ b/packages/extension/src/shared/schedule/constants.ts @@ -0,0 +1 @@ +export const ALARM_VERSION = `v${process.env.VERSION}` diff --git a/packages/extension/src/shared/sentry/options.ts b/packages/extension/src/shared/sentry/options.ts deleted file mode 100644 index 619c1ed88..000000000 --- a/packages/extension/src/shared/sentry/options.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as Sentry from "@sentry/browser" - -const environment = process.env.SENTRY_ENVIRONMENT ?? process.env.NODE_ENV - -const release = getRelease() - -export const baseSentryOptions: Sentry.BrowserOptions = { - dsn: process.env.SENTRY_DSN, - environment, - release, - autoSessionTracking: false, // don't want to track user sessions. -} - -function getRelease() { - const commitHash = process.env.COMMIT_HASH - const release = process.env.npm_package_version - if (environment === "staging" && commitHash) { - return `${release}-rc__${commitHash}` - } - return release -} diff --git a/packages/extension/src/shared/settings/defaultBlockExplorers.ts b/packages/extension/src/shared/settings/defaultBlockExplorers.ts index 6c69e5613..42079ed41 100644 --- a/packages/extension/src/shared/settings/defaultBlockExplorers.ts +++ b/packages/extension/src/shared/settings/defaultBlockExplorers.ts @@ -1,4 +1,6 @@ -import { logos } from "@argent/ui" +// just using types here +// eslint-disable-next-line @argent/local/code-import-patterns +import { logos } from "@argent/x-ui" export interface BlockExplorer { title: string diff --git a/packages/extension/src/shared/settings/index.ts b/packages/extension/src/shared/settings/index.ts index b6bbae079..74ad1af99 100644 --- a/packages/extension/src/shared/settings/index.ts +++ b/packages/extension/src/shared/settings/index.ts @@ -1,4 +1,4 @@ -import { isFeatureEnabled } from "@argent/shared" +import { isFeatureEnabled } from "@argent/x-shared" export const isPrivacySettingsEnabled = isFeatureEnabled( process.env.FEATURE_PRIVACY_SETTINGS, diff --git a/packages/extension/src/shared/shield/GuardianSignerArgentX.ts b/packages/extension/src/shared/shield/GuardianSignerArgentX.ts index 6a146e2f8..1dda517fd 100644 --- a/packages/extension/src/shared/shield/GuardianSignerArgentX.ts +++ b/packages/extension/src/shared/shield/GuardianSignerArgentX.ts @@ -1,7 +1,7 @@ import { GuardianSigner } from "@argent/guardian" import type { CosignerMessage, CosignerOffchainMessage } from "@argent/guardian" import { Signature, hash, num } from "starknet6" -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { isTokenExpired } from "./backend/account" diff --git a/packages/extension/src/shared/shield/idb.ts b/packages/extension/src/shared/shield/idb.ts index 08e69e12d..d86cc5c3b 100644 --- a/packages/extension/src/shared/shield/idb.ts +++ b/packages/extension/src/shared/shield/idb.ts @@ -4,11 +4,12 @@ import Dexie from "dexie" export class StoreDexie extends Dexie { devices!: Table - + ids!: Table<{ key: string; id: string }> constructor() { super("store") - this.version(1).stores({ + this.version(2).stores({ devices: "id, signingKey, verifiedEmail, verifiedAt", + ids: "key, id", }) } } diff --git a/packages/extension/src/shared/storage/__new/chrome.ts b/packages/extension/src/shared/storage/__new/chrome.ts index 9c07ab2ef..0a97ee598 100644 --- a/packages/extension/src/shared/storage/__new/chrome.ts +++ b/packages/extension/src/shared/storage/__new/chrome.ts @@ -1,4 +1,4 @@ -import { isFunction, partition } from "lodash-es" +import { isArray, isFunction, partition } from "lodash-es" import { mergeArrayStableWith, optionsWithDefaults } from "./base" import type { @@ -70,14 +70,18 @@ export class ChromeRepository implements IRepository { async remove(value: SelectorFn | AllowArray): Promise { const items = await this.getStorage() - const values = Array.isArray(value) ? value : [value] - const removeSelector = isFunction(value) - ? value - : (item: T) => values.includes(item) + const compareFn = this.options.compare.bind(this) - const [newValues, removedValues] = partition(items, removeSelector) - await this.set(newValues) + const selector = isFunction(value) + ? (item: T) => !value(item) + : isArray(value) + ? (item: T) => value.some((v) => !compareFn(v, item)) + : (item: T) => !compareFn(value, item) + + const [keptValues, removedValues] = partition(items, selector) + + await this.set(keptValues) return removedValues } diff --git a/packages/extension/src/shared/storage/__new/repositories/knownDapp.ts b/packages/extension/src/shared/storage/__new/repositories/knownDapp.ts index 910adb68c..5ef017856 100644 --- a/packages/extension/src/shared/storage/__new/repositories/knownDapp.ts +++ b/packages/extension/src/shared/storage/__new/repositories/knownDapp.ts @@ -1,4 +1,4 @@ -import { KnownDapp } from "@argent/shared" +import { KnownDapp } from "@argent/x-shared" import browser from "webextension-polyfill" import { ChromeRepository } from "../chrome" diff --git a/packages/extension/src/shared/storage/__new/repositories/nft.ts b/packages/extension/src/shared/storage/__new/repositories/nft.ts index 95bfdead6..fc9bce093 100644 --- a/packages/extension/src/shared/storage/__new/repositories/nft.ts +++ b/packages/extension/src/shared/storage/__new/repositories/nft.ts @@ -1,4 +1,4 @@ -import { Collection, NftItem, isEqualAddress } from "@argent/shared" +import { Collection, NftItem, isEqualAddress } from "@argent/x-shared" import browser from "webextension-polyfill" import { ChromeRepository } from "../chrome" diff --git a/packages/extension/src/shared/swap/model/order.model.ts b/packages/extension/src/shared/swap/model/order.model.ts index b28e67bb3..85962b3ab 100644 --- a/packages/extension/src/shared/swap/model/order.model.ts +++ b/packages/extension/src/shared/swap/model/order.model.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" import { SwapDataSchema } from "./quote.model" import { CallSchema } from "@argent/x-window" diff --git a/packages/extension/src/shared/swap/model/quote.model.ts b/packages/extension/src/shared/swap/model/quote.model.ts index 96506916b..72160757e 100644 --- a/packages/extension/src/shared/swap/model/quote.model.ts +++ b/packages/extension/src/shared/swap/model/quote.model.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" export const SwapDataSchema = z.object({ diff --git a/packages/extension/src/shared/swap/service/implementation.test.ts b/packages/extension/src/shared/swap/service/implementation.test.ts index ad2747f37..b4ca8652b 100644 --- a/packages/extension/src/shared/swap/service/implementation.test.ts +++ b/packages/extension/src/shared/swap/service/implementation.test.ts @@ -9,7 +9,7 @@ import { getMockToken } from "../../../../test/token.mock" import { SwapError } from "../../errors/swap" import { SwapQuoteResponseSchema } from "../model/quote.model" import { stark } from "starknet" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { sampleOrderResponse } from "./order.mock" import { httpService } from "../../http/singleton" import { TradeType } from "../model/trade.model" diff --git a/packages/extension/src/shared/swap/service/implementation.ts b/packages/extension/src/shared/swap/service/implementation.ts index 5c176106c..060a18922 100644 --- a/packages/extension/src/shared/swap/service/implementation.ts +++ b/packages/extension/src/shared/swap/service/implementation.ts @@ -1,5 +1,5 @@ import urlJoin from "url-join" -import { IHttpService } from "@argent/shared" +import { IHttpService } from "@argent/x-shared" import { INetworkService } from "../../network/service/interface" import { ITokenService } from "../../token/__new/service/interface" import { urlWithQuery } from "../../utils/url" diff --git a/packages/extension/src/shared/swap/utils/totalFee.ts b/packages/extension/src/shared/swap/utils/totalFee.ts index 87b94c216..37bdc78a2 100644 --- a/packages/extension/src/shared/swap/utils/totalFee.ts +++ b/packages/extension/src/shared/swap/utils/totalFee.ts @@ -1,4 +1,4 @@ -import { bigDecimal } from "@argent/shared" +import { bigDecimal } from "@argent/x-shared" import { SwapQuoteResponse } from "../model/quote.model" import { Trade } from "../model/trade.model" @@ -21,20 +21,20 @@ export function calculateTotalFee(quote: QuoteFee): TotalTradeFee { // This can be done because backend returns a token formatted amount const totalFee = BigInt(quote.providerFee) + BigInt(quote.argentFee) - // const totalFeeInCurrencyBig = bigDecimal.add( - // bigDecimal.parseCurrency(quote.argentFeeInCurrency), - // bigDecimal.parseCurrency(quote.providerFeeInCurrency), - // ) + const totalFeeInCurrencyBig = bigDecimal.add( + bigDecimal.parseCurrency(quote.argentFeeInCurrency), + bigDecimal.parseCurrency(quote.providerFeeInCurrency), + ) - // const totalFeeInCurrency = bigDecimal.formatCurrency( - // totalFeeInCurrencyBig.value, - // ) + const totalFeeInCurrency = bigDecimal.formatCurrency( + totalFeeInCurrencyBig.value, + ) const totalFeePercentage = quote.argentFeePercentage + quote.providerFeePercentage return { totalFee: totalFee.toString(), totalFeePercentage, - // totalFeeInCurrency, Use once backend fixes "3.0E-17" issue + totalFeeInCurrency, } } diff --git a/packages/extension/src/shared/token/__deprecated/type.ts b/packages/extension/src/shared/token/__deprecated/type.ts index 462bd8279..2624d7925 100644 --- a/packages/extension/src/shared/token/__deprecated/type.ts +++ b/packages/extension/src/shared/token/__deprecated/type.ts @@ -1,6 +1,11 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" +// NOTE: these deprecated types are currently used by `runV59TokenMigration` + +/** + * @deprecated use new schema instead + */ export const BaseTokenSchema = z.object( { address: addressSchema, @@ -9,9 +14,12 @@ export const BaseTokenSchema = z.object( { required_error: "BaseToken is required" }, ) +/** + * @deprecated use new schema instead + */ export type BaseToken = z.infer -export const RequestTokenSchema = z.object({ +const RequestTokenSchema = z.object({ address: addressSchema, networkId: z.string().optional(), name: z.string().optional(), @@ -19,12 +27,7 @@ export const RequestTokenSchema = z.object({ decimals: z.coerce.number().optional(), }) -export type RequestToken = z.infer - -/** - * @deprecated use new schema instead - */ -export const TokenSchema = RequestTokenSchema.required().extend({ +const TokenSchema = RequestTokenSchema.required().extend({ image: z.string().optional(), showAlways: z.boolean().optional(), }) diff --git a/packages/extension/src/shared/token/__deprecated/utils.ts b/packages/extension/src/shared/token/__deprecated/utils.ts index 06aca6ab7..7f64226e8 100644 --- a/packages/extension/src/shared/token/__deprecated/utils.ts +++ b/packages/extension/src/shared/token/__deprecated/utils.ts @@ -1,4 +1,4 @@ -import { addressSchema, isEqualAddress } from "@argent/shared" +import { addressSchema, isEqualAddress } from "@argent/x-shared" import defaultTokens from "../../../assets/default-tokens.json" import { BaseToken, Token } from "./type" diff --git a/packages/extension/src/shared/token/__fixtures__/mockTokensWithBalance.ts b/packages/extension/src/shared/token/__fixtures__/mockTokensWithBalance.ts new file mode 100644 index 000000000..bb08d35e8 --- /dev/null +++ b/packages/extension/src/shared/token/__fixtures__/mockTokensWithBalance.ts @@ -0,0 +1,16 @@ +import { Address } from "@argent/x-shared" + +import mockTokensWithBalanceRaw from "../../../../test/__fixtures__/tokens-with-balance.mock.json" +import type { TokenWithOptionalBigIntBalance } from "../__new/types/tokenBalance.model" + +/** convert to expected types */ + +export const mockTokensWithBalance: TokenWithOptionalBigIntBalance[] = + mockTokensWithBalanceRaw.map((token) => { + return { + ...token, + address: token.address as Address, + decimals: Number(token.decimals), + balance: BigInt(token.balance), + } + }) diff --git a/packages/extension/src/shared/token/__new/service/implementation.test.ts b/packages/extension/src/shared/token/__new/service/implementation.test.ts index a7d013cef..31474b15e 100644 --- a/packages/extension/src/shared/token/__new/service/implementation.test.ts +++ b/packages/extension/src/shared/token/__new/service/implementation.test.ts @@ -20,7 +20,7 @@ import { } from "../../../../../test/network.mock" import { INetworkRepo } from "../../../network/store" import { GatewayError, shortString, stark } from "starknet" -import { IHttpService, addressSchema } from "@argent/shared" +import { IHttpService, addressSchema } from "@argent/x-shared" import { TokenError } from "../../../errors/token" import { IObjectStore } from "../../../storage/__new/interface" import { TokenInfoByNetwork } from "../types/tokenInfo.model" @@ -148,9 +148,8 @@ describe("TokenService", () => { it("should fetch tokens from backend", async () => { mockTokenInfoStore.get.mockResolvedValueOnce({}) mockHttpService.get.mockResolvedValueOnce({ tokens: mockTokens }) - const result = await tokenService.getTokensInfoFromBackendForNetwork( - mockNetworkId, - ) + const result = + await tokenService.getTokensInfoFromBackendForNetwork(mockNetworkId) expect(mockTokenInfoStore.get).toHaveBeenCalledOnce() expect(mockHttpService.get).toHaveBeenCalledOnce() expect(mockTokenInfoStore.set).toHaveBeenCalledOnce() @@ -167,9 +166,8 @@ describe("TokenService", () => { }, }) mockHttpService.get.mockResolvedValueOnce({ tokens: mockTokens }) - const result = await tokenService.getTokensInfoFromBackendForNetwork( - mockNetworkId, - ) + const result = + await tokenService.getTokensInfoFromBackendForNetwork(mockNetworkId) expect(mockTokenInfoStore.get).toHaveBeenCalledOnce() expect(mockHttpService.get).not.toHaveBeenCalled() expect(mockTokenInfoStore.set).not.toHaveBeenCalled() @@ -186,9 +184,8 @@ describe("TokenService", () => { }, }) mockHttpService.get.mockResolvedValueOnce({ tokens: mockTokens }) - const result = await tokenService.getTokensInfoFromBackendForNetwork( - mockNetworkId, - ) + const result = + await tokenService.getTokensInfoFromBackendForNetwork(mockNetworkId) expect(mockTokenInfoStore.get).toHaveBeenCalledOnce() expect(mockHttpService.get).toHaveBeenCalledOnce() expect(mockTokenInfoStore.set).toHaveBeenCalledOnce() @@ -304,9 +301,8 @@ describe("TokenService", () => { describe("fetch tokens from backend", () => { it("should return without fetching tokens if it is not a default network", async () => { const mockNetworkId = "mockNetworkId" - const result = await tokenService.getTokensInfoFromBackendForNetwork( - mockNetworkId, - ) + const result = + await tokenService.getTokensInfoFromBackendForNetwork(mockNetworkId) expect(mockTokenInfoStore.get).not.toHaveBeenCalled() expect(result).toBeUndefined() }) @@ -392,9 +388,8 @@ describe("TokenService", () => { }, ]) - const result = await tokenService.fetchTokenBalancesFromOnChain( - mockAccount, - ) + const result = + await tokenService.fetchTokenBalancesFromOnChain(mockAccount) expect(result).toEqual(mockTokenBalances) }) @@ -459,9 +454,8 @@ describe("TokenService", () => { }, ]) - const result = await tokenService.fetchTokenBalancesFromOnChain( - mockAccounts, - ) + const result = + await tokenService.fetchTokenBalancesFromOnChain(mockAccounts) expect(result).toEqual(mockTokenBalances) }) }) @@ -801,9 +795,8 @@ describe("TokenService", () => { mockTokenBalanceRepo.get.mockResolvedValueOnce(mockTokensWithBalances) mockTokenPriceRepo.get.mockResolvedValueOnce(mockTokenPrices) mockTokenRepo.get.mockResolvedValueOnce(mockTokensWithBalances) - const result = await tokenService.getTotalCurrencyBalanceForAccounts( - mockAccounts, - ) + const result = + await tokenService.getTotalCurrencyBalanceForAccounts(mockAccounts) expect(result).toEqual({ [`${randomAddress1}:${defaultNetwork.id}`]: "2000", [`${randomAddress2}:${defaultNetwork.id}`]: "200", diff --git a/packages/extension/src/shared/token/__new/service/implementation.ts b/packages/extension/src/shared/token/__new/service/implementation.ts index 30c42f9a5..3950847d5 100644 --- a/packages/extension/src/shared/token/__new/service/implementation.ts +++ b/packages/extension/src/shared/token/__new/service/implementation.ts @@ -10,7 +10,7 @@ import { Token, apiAccountTokenBalancesSchema, } from "../types/token.model" -import { convertTokenAmountToCurrencyValue, equalToken } from "../utils" +import { equalToken } from "../utils" import { BaseTokenWithBalance } from "../types/tokenBalance.model" import { BaseWalletAccount } from "../../../wallet.model" import { @@ -27,7 +27,8 @@ import { bigDecimal, ensureArray, stripAddressZeroPadding, -} from "@argent/shared" + convertTokenAmountToCurrencyValue, +} from "@argent/x-shared" import { INetworkService } from "../../../network/service/interface" import { getMulticallForNetwork } from "../../../multicall" import { getProvider } from "../../../network/provider" @@ -260,8 +261,10 @@ export class TokenService implements ITokenService { const token = tokensOnCurrentNetwork[Math.floor(i / accounts.length)] const account = accounts[i % accounts.length] if (result.status === "fulfilled") { - const [low, high] = result.value.result - const balance = uint256.uint256ToBN({ low, high }).toString() + const [low, high] = ensureArray(result.value.result) + const balance = uint256 + .uint256ToBN({ low: low || "0", high: high || "0" }) + .toString() tokenBalances.push({ account, ...token, @@ -534,9 +537,8 @@ export class TokenService implements ITokenService { accounts.some((a) => accountsEqual(a, tb.account)), ) - const tokensWithBalanceAndPrice = await this.getCurrencyValueForTokens( - tokenBalances, - ) + const tokensWithBalanceAndPrice = + await this.getCurrencyValueForTokens(tokenBalances) const groupedBalances = groupBy( tokensWithBalanceAndPrice, diff --git a/packages/extension/src/shared/token/__new/types/token.model.ts b/packages/extension/src/shared/token/__new/types/token.model.ts index 414c38203..cd5761f53 100644 --- a/packages/extension/src/shared/token/__new/types/token.model.ts +++ b/packages/extension/src/shared/token/__new/types/token.model.ts @@ -1,4 +1,4 @@ -import { addressSchema, addressSchemaArgentBackend } from "@argent/shared" +import { addressSchema, addressSchemaArgentBackend } from "@argent/x-shared" import { z } from "zod" export const BaseTokenSchema = z.object( diff --git a/packages/extension/src/shared/token/__new/types/tokenInfo.model.ts b/packages/extension/src/shared/token/__new/types/tokenInfo.model.ts index fd17c369e..a76bddf59 100644 --- a/packages/extension/src/shared/token/__new/types/tokenInfo.model.ts +++ b/packages/extension/src/shared/token/__new/types/tokenInfo.model.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { z } from "zod" export const apiTokenInfoSchema = z.object({ diff --git a/packages/extension/src/shared/token/__new/utils/index.ts b/packages/extension/src/shared/token/__new/utils/index.ts index 256cce638..bd0e7aebc 100644 --- a/packages/extension/src/shared/token/__new/utils/index.ts +++ b/packages/extension/src/shared/token/__new/utils/index.ts @@ -1,12 +1,6 @@ -import { - addressSchema, - bigDecimal, - isEqualAddress, - isNumeric, - DEFAULT_TOKEN_DECIMALS, -} from "@argent/shared" +import { addressSchema, isEqualAddress } from "@argent/x-shared" + import { BaseToken, Token } from "../types/token.model" -import { BigNumberish } from "starknet" import defaultTokens from "../../../../assets/default-tokens.json" export const equalToken = (a?: BaseToken, b?: BaseToken) => { @@ -16,48 +10,6 @@ export const equalToken = (a?: BaseToken, b?: BaseToken) => { return a.networkId === b.networkId && isEqualAddress(a.address, b.address) } -export interface IConvertTokenAmountToCurrencyValue { - /** the token decimal amount */ - amount: BigNumberish - /** number of decimals used in token amount */ - decimals: BigNumberish - /** the currency value of 1 unit of token */ - unitCurrencyValue: number | string -} - -/** - * Converts a token amount and decimals into a final currency value, returning a raw string with many decimals - */ - -export const convertTokenAmountToCurrencyValue = ({ - amount, - decimals, - unitCurrencyValue, -}: IConvertTokenAmountToCurrencyValue) => { - if ( - !isNumeric(amount) || - !isNumeric(decimals) || - !isNumeric(unitCurrencyValue) - ) { - return - } - - /** decimal is numeric, hence can be converted to Number */ - const decimalsNumber = Number(decimals) - - /** multiply to convert to currency */ - const currencyValue = - BigInt(amount) * - bigDecimal.parseUnits(unitCurrencyValue.toString(), DEFAULT_TOKEN_DECIMALS) - .value - - /** keep as string to avoid loss of precision elsewhere */ - return bigDecimal.formatUnits({ - value: currencyValue, - decimals: decimalsNumber + DEFAULT_TOKEN_DECIMALS, - }) -} - export const parsedDefaultTokens: Token[] = defaultTokens.map((token) => ({ ...token, address: addressSchema.parse(token.address), diff --git a/packages/extension/src/shared/token/lookupTokenPriceDetails.test.ts b/packages/extension/src/shared/token/lookupTokenPriceDetails.test.ts new file mode 100644 index 000000000..856fee49a --- /dev/null +++ b/packages/extension/src/shared/token/lookupTokenPriceDetails.test.ts @@ -0,0 +1,52 @@ +import { convertTokenAmountToCurrencyValue } from "@argent/x-shared" +import { describe, expect, test } from "vitest" + +import { lookupTokenPriceDetails } from "./lookupTokenPriceDetails" +import mockApiPricesData from "../../../test/__fixtures__/argent-api-prices.mock.json" +import mockApiTokenData from "../../../test/__fixtures__/argent-api-tokens.mock.json" +import { mockTokensWithBalance } from "./__fixtures__/mockTokensWithBalance" + +describe("lookupTokenPriceDetails()", () => { + describe("when valid", () => { + test("should find token price details in API response", () => { + const token = mockTokensWithBalance[0] + const price = lookupTokenPriceDetails({ + token, + pricesData: mockApiPricesData as any, + tokenData: mockApiTokenData as any, + }) + expect(price).toEqual({ + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + networkId: "goerli-alpha", + ccyDayChange: "0.001484", + ccyValue: "1102.594564", + ethDayChange: "0", + ethValue: "1", + pricingId: 1, + }) + expect( + convertTokenAmountToCurrencyValue({ + amount: token.balance || 0, + decimals: token.decimals || 0, + unitCurrencyValue: price?.ccyValue || 0, + }), + ).toEqual("1102.594564") + }) + }) + describe("when invalid", () => { + test("should return undefined without throwing", () => { + const token = mockTokensWithBalance[0] + const price = lookupTokenPriceDetails({ + token, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + pricesData: null, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + tokenData: null, + }) + expect(price).toBeUndefined() + }) + }) +}) diff --git a/packages/extension/src/shared/token/lookupTokenPriceDetails.ts b/packages/extension/src/shared/token/lookupTokenPriceDetails.ts new file mode 100644 index 000000000..d9b0d9137 --- /dev/null +++ b/packages/extension/src/shared/token/lookupTokenPriceDetails.ts @@ -0,0 +1,42 @@ +import type { TokenPriceDetails } from "./__new/types/tokenPrice.model" +import type { BaseToken, Token } from "./__new/types/token.model" +import { equalToken } from "./__new/utils" +import { isArray } from "lodash-es" + +export interface ILookupTokenPriceDetails { + /** the token to query */ + token: BaseToken + /** reponse from `/tokens/prices` endpoint */ + pricesData: TokenPriceDetails[] | undefined + /** reponse from `/tokens/info` endpoint */ + tokenData: Token[] | undefined +} +/** + * Given `token`, find the token in the `tokenData` and then the price details in `priceData` + */ + +export const lookupTokenPriceDetails = ({ + token: baseToken, + pricesData, + tokenData, +}: ILookupTokenPriceDetails) => { + if ( + !tokenData || + !isArray(tokenData) || + !pricesData || + !isArray(pricesData) + ) { + return + } + /** find token from tokenData by matching address */ + const tokenInPriceData = tokenData.find((token) => + equalToken(baseToken, token), + ) + if (!tokenInPriceData) { + return + } + /** find token price details from pricesData by matching priceId */ + return pricesData.find( + ({ pricingId }) => pricingId === tokenInPriceData.pricingId, + ) +} diff --git a/packages/extension/src/shared/token/prettifyTokenBalance.ts b/packages/extension/src/shared/token/prettifyTokenBalance.ts new file mode 100644 index 000000000..f6d12be73 --- /dev/null +++ b/packages/extension/src/shared/token/prettifyTokenBalance.ts @@ -0,0 +1,21 @@ +import { prettifyTokenAmount } from "@argent/x-shared" +import { TokenWithOptionalBigIntBalance } from "./__new/types/tokenBalance.model" + +/** + * Returns a string of token balance with symbol if available e.g. + */ + +export const prettifyTokenBalance = ( + token: TokenWithOptionalBigIntBalance, + withSymbol = true, +) => { + const { balance, decimals, symbol } = token + if (balance === undefined || decimals === undefined) { + return null + } + return prettifyTokenAmount({ + amount: balance, + decimals, + symbol: withSymbol ? symbol : "", + }) +} diff --git a/packages/extension/src/shared/token/price.ts b/packages/extension/src/shared/token/price.ts deleted file mode 100644 index cd0e5b9d4..000000000 --- a/packages/extension/src/shared/token/price.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { uint256, BigNumberish } from "starknet" - -import { - IPrettifyNumberConfig, - isNumeric, - prettifyCurrencyNumber, - prettifyTokenNumber, -} from "../utils/number" -import { bigDecimal, DEFAULT_TOKEN_DECIMALS } from "@argent/shared" -import { TokenPriceDetails } from "./__new/types/tokenPrice.model" -import { BaseToken, Token } from "./__new/types/token.model" -import { equalToken } from "./__new/utils" -import { TokenWithOptionalBigIntBalance } from "./__new/types/tokenBalance.model" -import { isArray, isUndefined } from "lodash-es" - -const { UINT_256_MAX } = uint256 - -/** shape of individual entity in the /tokens/info endpoint */ -export interface ApiTokenDetails { - id: number - address: string - pricingId: number -} - -export interface ApiTokenDataResponse { - tokens: ApiTokenDetails[] -} - -/** shape of individual entity in the /tokens/prices endpoint */ -export interface ApiPriceDetails { - pricingId: number - ethValue: string - ccyValue: string - ethDayChange: string - ccyDayChange: string -} - -export interface ApiPriceDataResponse { - prices: ApiPriceDetails[] -} - -export interface ILookupTokenPriceDetails { - /** the token to query */ - token: BaseToken - /** reponse from `/tokens/prices` endpoint */ - pricesData: TokenPriceDetails[] | undefined - /** reponse from `/tokens/info` endpoint */ - tokenData: Token[] | undefined -} - -/** - * Given `token`, find the token in the `tokenData` and then the price details in `priceData` - */ - -export const lookupTokenPriceDetails = ({ - token: baseToken, - pricesData, - tokenData, -}: ILookupTokenPriceDetails) => { - if ( - !tokenData || - !isArray(tokenData) || - !pricesData || - !isArray(pricesData) - ) { - return - } - /** find token from tokenData by matching address */ - const tokenInPriceData = tokenData.find((token) => - equalToken(baseToken, token), - ) - if (!tokenInPriceData) { - return - } - /** find token price details from pricesData by matching priceId */ - return pricesData.find( - ({ pricingId }) => pricingId === tokenInPriceData.pricingId, - ) -} - -export interface ISumTokenBalancesToCurrencyValue { - /** the tokens to sum */ - tokens: TokenWithOptionalBigIntBalance[] - /** reponse from `/tokens/prices` endpoint */ - pricesData: TokenPriceDetails[] - /** reponse from `/tokens/info` endpoint */ - tokenData: Token[] -} - -export const sumTokenBalancesToCurrencyValue = ({ - tokens, - pricesData, - tokenData, -}: ISumTokenBalancesToCurrencyValue) => { - let sumTokenBalance = BigInt(0) - let didGetValidConversion = false - tokens.forEach((token) => { - const priceDetails = lookupTokenPriceDetails({ - token, - pricesData, - tokenData, - }) - if ( - priceDetails && - // 0n is considered false otherwise - !isUndefined(token.balance) && - !isUndefined(token.decimals) - ) { - const currencyValue = convertTokenAmountToCurrencyValue({ - amount: token.balance, - decimals: token.decimals, - unitCurrencyValue: priceDetails.ccyValue, - }) - /** zero is a valid value here */ - if (currencyValue !== undefined) { - didGetValidConversion = true - sumTokenBalance = - sumTokenBalance + bigDecimal.parseCurrency(currencyValue).value - } - } - }) - /** undefined if there were no valid conversions */ - if (!didGetValidConversion) { - return - } - /** keep as string to avoid loss of precision elsewhere */ - return bigDecimal.formatCurrency(sumTokenBalance) -} - -export interface IConvertTokenAmountToCurrencyValue { - /** the token decimal amount */ - amount: BigNumberish - /** number of decimals used in token amount */ - decimals: BigNumberish - /** the currency value of 1 unit of token */ - unitCurrencyValue: number | string -} - -/** - * Converts a token amount and decimals into a final currency value, returning a raw string with many decimals - */ - -export const convertTokenAmountToCurrencyValue = ({ - amount, - decimals, - unitCurrencyValue, -}: IConvertTokenAmountToCurrencyValue) => { - if ( - !isNumeric(amount) || - !isNumeric(decimals) || - !isNumeric(unitCurrencyValue) - ) { - return - } - - /** decimal is numeric, hence can be converted to Number */ - const decimalsNumber = Number(decimals) - - /** multiply to convert to currency */ - const currencyValue = - BigInt(amount) * - bigDecimal.parseCurrency(unitCurrencyValue.toString()).value - /** keep as string to avoid loss of precision elsewhere */ - return bigDecimal.formatUnits({ - value: currencyValue, - decimals: decimalsNumber + DEFAULT_TOKEN_DECIMALS, - }) -} - -/** - * Prettify a raw currency string value e.g. '1.23456' => '$1.23' - */ - -export const prettifyCurrencyValue = ( - currencyValue?: string | number, - currencySymbol = "$", -) => { - if (currencyValue === undefined || !isNumeric(currencyValue)) { - return null - } - const prettyValue = prettifyCurrencyNumber(currencyValue) - const prettyValueWithSymbol = [currencySymbol, prettyValue] - .filter(Boolean) - .join("") - return prettyValueWithSymbol -} - -/** - * Returns a string of token balance with symbol if available e.g. - */ - -export const prettifyTokenBalance = ( - token: TokenWithOptionalBigIntBalance, - withSymbol = true, -) => { - const { balance, decimals, symbol } = token - if (balance === undefined || decimals === undefined) { - return null - } - return prettifyTokenAmount({ - amount: balance, - decimals, - symbol: withSymbol ? symbol : "", - }) -} - -export const PRETTY_UNLIMITED = "Unlimited" - -export const isUnlimitedAmount = (amount: BigNumberish) => { - return String(amount) === String(UINT_256_MAX) -} - -export interface IPrettifyTokenAmount { - amount: BigNumberish - decimals: BigNumberish - symbol?: string - showPlusSign?: boolean - withSymbol?: boolean - unlimitedText?: string - prettyConfigOverrides?: Partial -} - -export const prettifyTokenAmount = ({ - amount, - decimals, - symbol, - showPlusSign = false, - withSymbol = true, - unlimitedText = PRETTY_UNLIMITED, - prettyConfigOverrides, -}: IPrettifyTokenAmount) => { - if (!isNumeric(amount)) { - return null - } - let prettyValue - let isPositiveValue = false - if (isUnlimitedAmount(amount)) { - prettyValue = unlimitedText - } else { - const decimalsNumber = Number(decimals) - const balance = BigInt(amount) - isPositiveValue = balance > 0n - const balanceFullString = - decimalsNumber > 0 - ? bigDecimal.formatUnits({ value: balance, decimals: decimalsNumber }) - : balance.toString() - prettyValue = - decimalsNumber > 0 - ? prettifyTokenNumber(balanceFullString, prettyConfigOverrides) - : balanceFullString - } - - const prettyValueWithSymbol = [prettyValue, withSymbol && symbol] - .filter(Boolean) - .join(" ") - - return showPlusSign && isPositiveValue - ? `+${prettyValueWithSymbol}` - : prettyValueWithSymbol -} - -export interface IConvertTokenAmount { - unitAmount?: BigNumberish - decimals?: BigNumberish -} - -/** - * Convert a unit amount of token into native amount, useful for user input - * - * @example - * ```ts - * // Prints '1000000000000000000' - * convertTokenUnitAmountWithDecimals({ unitAmount: 1, decimals: 18 }), - * ``` - * - * @example - * ```ts - * // Prints '123' - * convertTokenUnitAmountWithDecimals({ unitAmount: 1.23, decimals: 2 }), - * ``` - */ - -export const convertTokenUnitAmountWithDecimals = ({ - unitAmount, - decimals, -}: IConvertTokenAmount) => { - if ( - unitAmount === undefined || - !isNumeric(unitAmount) || - decimals === undefined || - !isNumeric(decimals) - ) { - return - } - - /** decimal is numeric, hence can be converted to Number */ - const decimalsNumber = Number(decimals) - - // keep as string to avoid loss of precision elsewhere - return bigDecimal - .parseUnits(unitAmount.toString(), decimalsNumber) - .value.toString() -} diff --git a/packages/extension/src/shared/token/sumTokenBalancesToCurrencyValue.test.ts b/packages/extension/src/shared/token/sumTokenBalancesToCurrencyValue.test.ts new file mode 100644 index 000000000..f566c1fdf --- /dev/null +++ b/packages/extension/src/shared/token/sumTokenBalancesToCurrencyValue.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, test } from "vitest" + +import { sumTokenBalancesToCurrencyValue } from "./sumTokenBalancesToCurrencyValue" +import mockApiPricesDataInvalid from "../../../test/__fixtures__/argent-api-prices-invalid.mock.json" +import mockApiPricesData from "../../../test/__fixtures__/argent-api-prices.mock.json" +import mockApiTokenDataInvalid from "../../../test/__fixtures__/argent-api-tokens-invalid.mock.json" +import mockApiTokenData from "../../../test/__fixtures__/argent-api-tokens.mock.json" +import { mockTokensWithBalance } from "./__fixtures__/mockTokensWithBalance" + +describe("sumTokenBalancesToCurrencyValue()", () => { + describe("when valid", () => { + test("should sum an array of tokens to currency value", () => { + const result = sumTokenBalancesToCurrencyValue({ + tokens: mockTokensWithBalance, + pricesData: mockApiPricesData as any, + tokenData: mockApiTokenData as any, + }) + expect(result).toEqual("1103.596564") + }) + }) + describe("when invalid", () => { + test("should return undefined without throwing", () => { + const result = sumTokenBalancesToCurrencyValue({ + tokens: mockTokensWithBalance, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + pricesData: mockApiPricesDataInvalid, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + tokenData: mockApiTokenDataInvalid, + }) + expect(result).toBeUndefined() + }) + }) +}) diff --git a/packages/extension/src/shared/token/sumTokenBalancesToCurrencyValue.ts b/packages/extension/src/shared/token/sumTokenBalancesToCurrencyValue.ts new file mode 100644 index 000000000..04de8f601 --- /dev/null +++ b/packages/extension/src/shared/token/sumTokenBalancesToCurrencyValue.ts @@ -0,0 +1,55 @@ +import { bigDecimal, convertTokenAmountToCurrencyValue } from "@argent/x-shared" +import type { TokenPriceDetails } from "./__new/types/tokenPrice.model" +import type { Token } from "./__new/types/token.model" +import type { TokenWithOptionalBigIntBalance } from "./__new/types/tokenBalance.model" +import { isUndefined } from "lodash-es" +import { lookupTokenPriceDetails } from "./lookupTokenPriceDetails" + +export interface ISumTokenBalancesToCurrencyValue { + /** the tokens to sum */ + tokens: TokenWithOptionalBigIntBalance[] + /** reponse from `/tokens/prices` endpoint */ + pricesData: TokenPriceDetails[] + /** reponse from `/tokens/info` endpoint */ + tokenData: Token[] +} + +export const sumTokenBalancesToCurrencyValue = ({ + tokens, + pricesData, + tokenData, +}: ISumTokenBalancesToCurrencyValue) => { + let sumTokenBalance = BigInt(0) + let didGetValidConversion = false + tokens.forEach((token) => { + const priceDetails = lookupTokenPriceDetails({ + token, + pricesData, + tokenData, + }) + if ( + priceDetails && + // 0n is considered false otherwise + !isUndefined(token.balance) && + !isUndefined(token.decimals) + ) { + const currencyValue = convertTokenAmountToCurrencyValue({ + amount: token.balance, + decimals: token.decimals, + unitCurrencyValue: priceDetails.ccyValue, + }) + /** zero is a valid value here */ + if (currencyValue !== undefined) { + didGetValidConversion = true + sumTokenBalance = + sumTokenBalance + bigDecimal.parseCurrency(currencyValue).value + } + } + }) + /** undefined if there were no valid conversions */ + if (!didGetValidConversion) { + return + } + /** keep as string to avoid loss of precision elsewhere */ + return bigDecimal.formatCurrency(sumTokenBalance) +} diff --git a/packages/extension/src/shared/token/types.ts b/packages/extension/src/shared/token/types.ts new file mode 100644 index 000000000..82efff5bd --- /dev/null +++ b/packages/extension/src/shared/token/types.ts @@ -0,0 +1,23 @@ +/** shape of individual entity in the /tokens/info endpoint */ +export interface ApiTokenDetails { + id: number + address: string + pricingId: number +} + +export interface ApiTokenDataResponse { + tokens: ApiTokenDetails[] +} + +/** shape of individual entity in the /tokens/prices endpoint */ +export interface ApiPriceDetails { + pricingId: number + ethValue: string + ccyValue: string + ethDayChange: string + ccyDayChange: string +} + +export interface ApiPriceDataResponse { + prices: ApiPriceDetails[] +} diff --git a/packages/extension/src/shared/transactionReview.service.test.ts b/packages/extension/src/shared/transactionReview.service.test.ts new file mode 100644 index 000000000..39ad27cbd --- /dev/null +++ b/packages/extension/src/shared/transactionReview.service.test.ts @@ -0,0 +1,44 @@ +import send from "./transactionReview/__fixtures__/send.json" +import swap from "./transactionReview/__fixtures__/swap.json" +import { + transactionReviewHasSwap, + transactionReviewHasTransfer, +} from "./transactionReview.service" + +describe("transactionReviewService", () => { + it("should return transaction review is transfer", () => { + const result = transactionReviewHasTransfer( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + send.transactions[0].reviewOfTransaction, + ) + expect(result).toBe(true) + }) + + it("should return transaction review is not transfer", () => { + const result = transactionReviewHasTransfer( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + swap.transactions[0].reviewOfTransaction, + ) + expect(result).toBe(false) + }) + + it("should return transaction review is swap", () => { + const result = transactionReviewHasSwap( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + swap.transactions[0].reviewOfTransaction, + ) + expect(result).toBe(true) + }) + + it("should return transaction review is not swap", () => { + const result = transactionReviewHasSwap( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + send.transactions[0].reviewOfTransaction, + ) + expect(result).toBe(false) + }) +}) diff --git a/packages/extension/src/shared/transactionReview.service.ts b/packages/extension/src/shared/transactionReview.service.ts index dd93c3e1f..87eb03fad 100644 --- a/packages/extension/src/shared/transactionReview.service.ts +++ b/packages/extension/src/shared/transactionReview.service.ts @@ -1,9 +1,11 @@ -import { Address, ArgentBackendNetworkId } from "@argent/shared" +import { Address, ArgentBackendNetworkId } from "@argent/x-shared" import { isArray, lowerCase } from "lodash-es" import { Call } from "starknet" import { ARGENT_TRANSACTION_REVIEW_STARKNET_URL } from "./api/constants" import { Fetcher, fetcher } from "./api/fetcher" +import { ReviewOfTransaction, Action } from "./transactionReview/schema" +import { argentXHeaders } from "./api/headers" export type ApiTransactionReviewAssessment = | "warn" @@ -153,6 +155,7 @@ export const fetchTransactionReview = ({ headers: { Accept: "application/json", "Content-Type": "application/json", + ...argentXHeaders, }, body: JSON.stringify(body), }, @@ -240,3 +243,48 @@ export const getTransactionReviewWithType = ( } } } + +export const transactionReviewHasSwap = ( + transactionReview?: ReviewOfTransaction, +) => { + if (!transactionReview) { + return false + } + for (const review of transactionReview.reviews) { + if ( + review.action.name === "multi_route_swap" || + review.action.name === "Jediswap_swap" + ) { + return true + } + } + return false +} + +export const transactionReviewHasTransfer = ( + transactionReview?: ReviewOfTransaction, +) => { + if (!transactionReview) { + return false + } + for (const review of transactionReview.reviews) { + if (review.action.name === "ERC20_transfer") { + return true + } + } + return false +} + +export const getTransactionActionByType = ( + actionName?: string, + transactionReview?: ReviewOfTransaction, +): Action | undefined => { + if (!transactionReview || !actionName) { + return + } + for (const review of transactionReview.reviews) { + if (review.action?.name.includes(actionName)) { + return review.action + } + } +} diff --git a/packages/extension/src/shared/transactionReview/interface.ts b/packages/extension/src/shared/transactionReview/interface.ts index 63f543247..c6fe74d11 100644 --- a/packages/extension/src/shared/transactionReview/interface.ts +++ b/packages/extension/src/shared/transactionReview/interface.ts @@ -1,7 +1,7 @@ import { z } from "zod" import { EnrichedSimulateAndReview } from "./schema" -import { Address, callSchema, hexSchema } from "@argent/shared" +import { Address, callSchema, hexSchema } from "@argent/x-shared" export const transactionReviewTransactionsSchema = z.object({ type: z diff --git a/packages/extension/src/shared/transactionReview/schema.ts b/packages/extension/src/shared/transactionReview/schema.ts index 0a00760c4..a3c8abf61 100644 --- a/packages/extension/src/shared/transactionReview/schema.ts +++ b/packages/extension/src/shared/transactionReview/schema.ts @@ -1,4 +1,4 @@ -import { addressSchema, addressSchemaArgentBackend } from "@argent/shared" +import { addressSchema, addressSchemaArgentBackend } from "@argent/x-shared" import { z } from "zod" import { estimatedFeesSchema } from "../transactionSimulation/fees/fees.model" import { reasonsSchema, severitySchema } from "../warning/schema" @@ -13,7 +13,7 @@ const tokenSchema = z.object({ address: z.string(), name: z.string(), symbol: z.string().optional(), - decimals: z.number(), + decimals: z.number().optional(), unknown: z.boolean(), iconUrl: z.string().optional(), type: z.string(), @@ -57,6 +57,11 @@ export const propertySchema = z.union([ label: z.string(), text: z.string(), }), + z.object({ + type: z.literal("nft"), + label: z.string(), + token: tokenSchema, + }), ]) export const actionSchema = z.object({ @@ -261,6 +266,8 @@ export const enrichedSimulateAndReviewSchema = z.object({ isBackendDown: z.boolean().default(false).optional(), }) +export type ReviewItem = z.infer + export type EnrichedSimulateAndReview = z.infer< typeof enrichedSimulateAndReviewSchema > diff --git a/packages/extension/src/shared/transactionSimulation/fees/estimatedFeesRepository.ts b/packages/extension/src/shared/transactionSimulation/fees/estimatedFeesRepository.ts index a26828b38..4ebe01432 100644 --- a/packages/extension/src/shared/transactionSimulation/fees/estimatedFeesRepository.ts +++ b/packages/extension/src/shared/transactionSimulation/fees/estimatedFeesRepository.ts @@ -1,5 +1,5 @@ import browser from "webextension-polyfill" -import { TransactionAction, ensureArray } from "@argent/shared" +import { TransactionAction, ensureArray } from "@argent/x-shared" import { deserialize, serialize } from "superjson" import { TransactionType } from "starknet" diff --git a/packages/extension/src/shared/transactionSimulation/fees/fees.model.ts b/packages/extension/src/shared/transactionSimulation/fees/fees.model.ts index 0487af683..cfc7ba2fe 100644 --- a/packages/extension/src/shared/transactionSimulation/fees/fees.model.ts +++ b/packages/extension/src/shared/transactionSimulation/fees/fees.model.ts @@ -1,6 +1,6 @@ import { z } from "zod" import { ChromeRepository } from "../../storage/__new/chrome" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" const maxFeeSchema = z .object({ diff --git a/packages/extension/src/shared/transactionSimulation/transactionSimulation.service.ts b/packages/extension/src/shared/transactionSimulation/transactionSimulation.service.ts index dacf11de2..d2db4301c 100644 --- a/packages/extension/src/shared/transactionSimulation/transactionSimulation.service.ts +++ b/packages/extension/src/shared/transactionSimulation/transactionSimulation.service.ts @@ -1,3 +1,4 @@ +import { isArgentNetworkId } from "@argent/x-shared" import { ARGENT_TRANSACTION_BULK_SIMULATION_URL } from "../api/constants" import { fetcher } from "../api/fetcher" import { TransactionError } from "../errors/transaction" @@ -6,9 +7,11 @@ import { IFetchTransactionSimulationBulk, ApiTransactionBulkSimulationResponse, } from "./types" +import { argentXHeaders } from "../api/headers" export const fetchTransactionBulkSimulation = async ({ invocations, + networkId, chainId, fetcher: fetcherImpl = fetcher, }: IFetchTransactionSimulationBulk): Promise< @@ -19,6 +22,9 @@ export const fetchTransactionBulkSimulation = async ({ code: "SIMULATION_DISABLED", }) } + if (!isArgentNetworkId(networkId)) { + return + } try { const backendSimulation = await fetcherImpl( @@ -28,6 +34,7 @@ export const fetchTransactionBulkSimulation = async ({ headers: { Accept: "application/json", "Content-Type": "application/json", + ...argentXHeaders, }, body: JSON.stringify({ chainId, diff --git a/packages/extension/src/shared/transactionSimulation/types.ts b/packages/extension/src/shared/transactionSimulation/types.ts index f07ad8721..03f48fd42 100644 --- a/packages/extension/src/shared/transactionSimulation/types.ts +++ b/packages/extension/src/shared/transactionSimulation/types.ts @@ -38,14 +38,9 @@ export type SimulateTransactionsRequest = ( | SimulateInvokeRequest )[] -export interface IFetchTransactionSimulation { - invocation: SimulateInvokeRequest - chainId: constants.StarknetChainId - fetcher?: Fetcher -} - export interface IFetchTransactionSimulationBulk { invocations: SimulateTransactionsRequest + networkId: string chainId: constants.StarknetChainId fetcher?: Fetcher } diff --git a/packages/extension/src/shared/transactionSimulation/utils.ts b/packages/extension/src/shared/transactionSimulation/utils.ts index 04cdffe64..bc4d4e2b8 100644 --- a/packages/extension/src/shared/transactionSimulation/utils.ts +++ b/packages/extension/src/shared/transactionSimulation/utils.ts @@ -2,7 +2,7 @@ import { num } from "starknet" import { EstimatedFee, EstimatedFees } from "./fees/fees.model" import { ApiTransactionSimulationResponse, FRI, WEI } from "./types" import { ETH_TOKEN_ADDRESS, STRK_TOKEN_ADDRESS } from "../network/constants" -import { Address, isEqualAddress } from "@argent/shared" +import { Address, isEqualAddress } from "@argent/x-shared" import { SimulateAndReview, feeEstimationSchema, diff --git a/packages/extension/src/shared/transactions.ts b/packages/extension/src/shared/transactions.ts index 1c7d12367..ea6189761 100644 --- a/packages/extension/src/shared/transactions.ts +++ b/packages/extension/src/shared/transactions.ts @@ -7,7 +7,7 @@ import { MultisigTransactionType, } from "./multisig/types" import { getTransactionStatus } from "./transactions/utils" -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" export type FinaliyStatus = RPC.SPEC.TXN_STATUS export type ExecutionStatus = RPC.SPEC.TXN_EXECUTION_STATUS diff --git a/packages/extension/src/shared/transactions/interface.ts b/packages/extension/src/shared/transactions/interface.ts index 21f642e13..89e372e9b 100644 --- a/packages/extension/src/shared/transactions/interface.ts +++ b/packages/extension/src/shared/transactions/interface.ts @@ -1,4 +1,4 @@ -import { TxHash } from "@argent/shared" +import { TxHash } from "@argent/x-shared" export interface BaseTransaction { hash: TxHash diff --git a/packages/extension/src/shared/transactions/utils.ts b/packages/extension/src/shared/transactions/utils.ts index 9b36fc8c8..c9d46de06 100644 --- a/packages/extension/src/shared/transactions/utils.ts +++ b/packages/extension/src/shared/transactions/utils.ts @@ -1,4 +1,4 @@ -import { hexSchema } from "@argent/shared" +import { hexSchema } from "@argent/x-shared" import { constants, num } from "starknet" import { TransactionError } from "../errors/transaction" diff --git a/packages/extension/src/shared/udc/schema.ts b/packages/extension/src/shared/udc/schema.ts index a940fabdd..3d74ebe85 100644 --- a/packages/extension/src/shared/udc/schema.ts +++ b/packages/extension/src/shared/udc/schema.ts @@ -2,7 +2,7 @@ import { Address, cairoAssemblySchema, compiledContractClassSchema, -} from "@argent/shared" +} from "@argent/x-shared" import { CairoVersion, DeclareContractPayload, diff --git a/packages/extension/src/shared/utils/accountsEqual.ts b/packages/extension/src/shared/utils/accountsEqual.ts index 11bf5bd90..b6506f01e 100644 --- a/packages/extension/src/shared/utils/accountsEqual.ts +++ b/packages/extension/src/shared/utils/accountsEqual.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import type { BaseWalletAccount, WalletAccount } from "../wallet.model" export const accountsEqual = (a?: BaseWalletAccount, b?: BaseWalletAccount) => { diff --git a/packages/extension/src/shared/utils/getTransactionVersion.ts b/packages/extension/src/shared/utils/getTransactionVersion.ts index 077070fb0..d2e6811c0 100644 --- a/packages/extension/src/shared/utils/getTransactionVersion.ts +++ b/packages/extension/src/shared/utils/getTransactionVersion.ts @@ -1,4 +1,4 @@ -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" import { feeTokenNeedsTxV3Support } from "../network/txv3" import { TransactionInvokeVersion, diff --git a/packages/extension/src/shared/utils/isUpgradeTransaction.ts b/packages/extension/src/shared/utils/isUpgradeTransaction.ts index 05523f39b..165e33238 100644 --- a/packages/extension/src/shared/utils/isUpgradeTransaction.ts +++ b/packages/extension/src/shared/utils/isUpgradeTransaction.ts @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { Transaction } from "../transactions" // This function checks if a transaction is a safe upgrade transaction diff --git a/packages/extension/src/shared/utils/number.ts b/packages/extension/src/shared/utils/number.ts deleted file mode 100644 index 26f000a7c..000000000 --- a/packages/extension/src/shared/utils/number.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * BigDecimalNumber is to be used ONLY for arbitrary-precision decimal and non-decimal arithmetic - * This is good for converting and multiplying currency values - * - * Not to be confused with BigInt - */ -import BigDecimalNumber from "bignumber.js" -import type { BigNumberish } from "starknet" - -/** Checks if a value is numeric, ie. possible to coerce to a number, e.g. 123 or '123.0' */ - -export const isNumeric = (numToCheck: any): boolean => - !isNaN(parseFloat(numToCheck)) && isFinite(Number(numToCheck)) - -export interface IPrettifyNumberConfig { - minDecimalPlaces: number - maxDecimalPlaces: number - /** significants digits to show in decimals while respecting decimal places */ - minDecimalSignificantDigits: number - /** special case for zero, e.g. we may want to display $0.00 or 0.0 ETH */ - decimalPlacesWhenZero: number -} - -export const prettifyNumberConfig: Record = { - CURRENCY: { - minDecimalPlaces: 2, - maxDecimalPlaces: 10, - minDecimalSignificantDigits: 2, - decimalPlacesWhenZero: 2, - }, - TOKEN: { - minDecimalPlaces: 4, - maxDecimalPlaces: 16, - minDecimalSignificantDigits: 2, - decimalPlacesWhenZero: 1, - }, -} - -export const prettifyCurrencyNumber = ( - number: BigNumberish, - overrides?: Partial, -) => { - return prettifyNumber(number, { - ...prettifyNumberConfig.CURRENCY, - ...(overrides || {}), - }) -} - -export const prettifyTokenNumber = ( - number: BigNumberish, - overrides?: Partial, -) => { - return prettifyNumber(number, { - ...prettifyNumberConfig.TOKEN, - ...(overrides || {}), - }) -} - -/** - * Prettify an input number for display according to the config - * - * @see test suite `number.test.ts` for examples - */ - -export const prettifyNumber = ( - number: BigNumberish, - { - minDecimalPlaces, - maxDecimalPlaces, - minDecimalSignificantDigits: minDecimalSignificantDigits, - decimalPlacesWhenZero, - }: IPrettifyNumberConfig = prettifyNumberConfig.CURRENCY, -) => { - if (!isNumeric(number)) { - return null - } - const numberBDN = new BigDecimalNumber( - typeof number === "bigint" ? number.toString() : number, - ) - let untrimmed - if (numberBDN.gte(1)) { - /** simplest case, formatting to minDecimalPlaces will look good */ - untrimmed = numberBDN.toFormat(minDecimalPlaces) - } else { - /** now need to interrogate the appearance of decimal number < 1 */ - /** longest case - max decimal places e.g. 0.0008923088123 -> 0.0008923088 */ - const maxDecimalPlacesString = numberBDN.toFormat(maxDecimalPlaces) - /** count the zeros, which will then allow us to know the final length with desired significant digits */ - const decimalPart = maxDecimalPlacesString.split(".")[1] - const zeroMatches = decimalPart.match(/^0+/) - const leadingZerosInDecimalPart = - zeroMatches && zeroMatches.length ? zeroMatches[0].length : 0 - /** now we can re-format with leadingZerosInDecimalPart + maxDecimalSignificanDigits to give us the pretty version */ - /** e.g. 0.0008923088123 -> 0.00089 */ - const prettyDecimalPlaces = Math.max( - leadingZerosInDecimalPart + minDecimalSignificantDigits, - minDecimalPlaces, - ) - untrimmed = numberBDN.toFormat(prettyDecimalPlaces) - } - /** the untrimmed string may have trailing zeros, e.g. 0.0890 */ - /** trim to a minimum specified by the config, e.g. we may want to display $0.00 or 0.0 ETH */ - let trimmed = untrimmed.replace(/0+$/, "") - const minLength = 1 + untrimmed.indexOf(".") + decimalPlacesWhenZero - if (trimmed.length < minLength) { - trimmed = untrimmed.substring(0, minLength) - } - return trimmed -} diff --git a/packages/extension/src/shared/wallet.model.ts b/packages/extension/src/shared/wallet.model.ts index f9254c4d2..321d41038 100644 --- a/packages/extension/src/shared/wallet.model.ts +++ b/packages/extension/src/shared/wallet.model.ts @@ -2,7 +2,7 @@ import { z } from "zod" import { escapeSchema } from "./account/details/escape.model" import { networkSchema } from "./network" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" export const argentAccountTypeSchema = z.enum([ "standard", @@ -45,6 +45,7 @@ export const walletAccountSchema = z owner: z.string().optional(), provisionAmount: z.string().optional(), provisionDate: z.number().optional(), + index: z.number().optional(), }) .merge(withSignerSchema) .merge(baseWalletAccountSchema) @@ -59,6 +60,7 @@ export const multisigDataSchema = z.object({ threshold: z.number(), creator: z.string().optional(), // Creator is the public key of the account that created the multisig account updatedAt: z.number(), + index: z.number().optional(), }) export const baseMultisigWalletAccountSchema = diff --git a/packages/extension/src/shared/wallet.service.ts b/packages/extension/src/shared/wallet.service.ts index a5e910923..f9c3763b9 100644 --- a/packages/extension/src/shared/wallet.service.ts +++ b/packages/extension/src/shared/wallet.service.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { BaseWalletAccount, WalletAccount } from "./wallet.model" // from https://community.starknet.io/t/account-keys-and-addresses-derivation-standard/1230 @@ -19,11 +19,16 @@ export const DEPRECATED_TX_V0_ACCOUNT_IMPLEMENTATION_CLASS_HASH = [ export const hasNewDerivationPath = (derivationPath?: string): boolean => Boolean(derivationPath?.startsWith(STANDARD_DERIVATION_PATH)) +export const hasMultisigDerivationPath = (derivationPath?: string): boolean => + Boolean(derivationPath?.startsWith(MULTISIG_DERIVATION_PATH)) export const isDeprecated = ({ signer, network }: WalletAccount): boolean => { - return ( + const isOldPathDeprecated = Boolean(network.accountClassHash) && !hasNewDerivationPath(signer.derivationPath) - ) + + const isNotMultisig = !hasMultisigDerivationPath(signer.derivationPath) + + return isOldPathDeprecated && isNotMultisig } export const isDeprecatedTxV0 = (account: WalletAccount): boolean => { diff --git a/packages/extension/src/ui/App.tsx b/packages/extension/src/ui/App.tsx index a341ab5f9..ec9a20023 100644 --- a/packages/extension/src/ui/App.tsx +++ b/packages/extension/src/ui/App.tsx @@ -1,13 +1,10 @@ -import { EventEmitterProvider } from "@argent/shared" -import { - ThemeProvider as ArgentTheme, - NavigationContainerSkeleton, - SetDarkMode, -} from "@argent/ui" +import { EventEmitterProvider } from "@argent/x-shared" +import { theme, NavigationContainerSkeleton, SetDarkMode } from "@argent/x-ui" import { ThemeProvider as MuiThemeProvider } from "@mui/material" import Emittery from "emittery" import { FC, Suspense, useRef } from "react" import { SWRConfig } from "swr" +import { ChakraProvider } from "@chakra-ui/react" import AppErrorBoundaryFallback from "./AppErrorBoundaryFallback" import { AppRoutes } from "./AppRoutes" @@ -15,16 +12,60 @@ import { ErrorBoundary } from "./components/ErrorBoundary" import { AppDimensions } from "./components/Responsive" import DevUI from "./features/dev/DevUI" import { useCaptureEntryRouteRestorationState } from "./features/stateRestoration/useRestorationState" -import { useTracking } from "./services/analytics" import SoftReloadProvider from "./services/resetAndReload" -import { useSentryInit } from "./services/sentry" import { onErrorRetry, swrCacheProvider } from "./services/swr.service" import { ThemeProvider, muiTheme } from "./theme" +import { useAnalytics } from "./hooks/useAnalytics" + +console.warn( + "HACK: patching theme with remapped old -> new colours - this hack must be removed", +) + +/** TODO: remove - temporarily remap old values to new values */ +const patchedTheme = { + ...theme, + colors: { + ...theme.colors, + "neutrals.100": theme.colors["neutrals.200"], + "neutrals.200": theme.colors["neutrals.300"], + "neutrals.300": theme.colors["neutrals.400"], + "neutrals.400": theme.colors["neutrals.500"], + "neutrals.500": theme.colors["neutrals.600"], + "neutrals.600": theme.colors["neutrals.700"], + "neutrals.700": theme.colors["neutrals.800"], + "neutrals.800": theme.colors["neutrals.900"], + "neutrals.900": theme.colors["neutrals.1000"], + // neutrals: { + // 100: "#b7b7b9", + // 200: "#9f9fa1", + // 300: "#88888a", + // 400: "#707072", + // 500: "#58585b", + // 600: "#404043", + // 700: "#28282c", + // 800: "#1d1f22", + // 900: "#101014", + // }, + }, + // back these colours the other way; + semanticTokens: { + colors: { + ...theme.semanticTokens.colors, + "surface-default": { + default: "neutrals.100", + _dark: "neutrals.900", + }, + "surface-elevated": { + default: "white.white", + _dark: "neutrals.800", + }, + }, + }, +} export const App: FC = () => { const emitter = useRef(new Emittery()).current - useTracking() - useSentryInit() + useAnalytics() useCaptureEntryRouteRestorationState() return ( @@ -42,7 +83,7 @@ export const App: FC = () => { rel="stylesheet" /> - + {process.env.SHOW_DEV_UI && } @@ -54,7 +95,7 @@ export const App: FC = () => { - + diff --git a/packages/extension/src/ui/AppBackgroundError.tsx b/packages/extension/src/ui/AppBackgroundError.tsx index a24ff9b04..14fa3570a 100644 --- a/packages/extension/src/ui/AppBackgroundError.tsx +++ b/packages/extension/src/ui/AppBackgroundError.tsx @@ -1,7 +1,7 @@ import { Button, Center, Flex, useDisclosure } from "@chakra-ui/react" import { FC } from "react" -import { H4, P3 } from "@argent/ui" +import { H4, P3 } from "@argent/x-ui" import { SupportFooter } from "./features/settings/ui/SupportFooter" import { useClearLocalStorage } from "./features/settings/developerSettings/clearLocalStorage/useClearLocalStorage" import { useHardResetAndReload } from "./services/resetAndReload" diff --git a/packages/extension/src/ui/AppRoutes.tsx b/packages/extension/src/ui/AppRoutes.tsx index ecfcd303a..0a6239685 100644 --- a/packages/extension/src/ui/AppRoutes.tsx +++ b/packages/extension/src/ui/AppRoutes.tsx @@ -68,7 +68,7 @@ import { ShieldAccountFinishScreen } from "./features/shield/ShieldAccountFinish import { ShieldAccountOTPScreen } from "./features/shield/ShieldAccountOTPScreen" import { ShieldAccountStartScreen } from "./features/shield/ShieldAccountStartScreen" import { WithArgentShieldVerified } from "./features/shield/WithArgentShieldVerified" -import { ReviewFeedbackScreen } from "./features/userReview/ReviewFeedbackScreen" +import { ReviewFeedbackScreenContainer } from "./features/userReview/ReviewFeedbackScreenContainer" import { ReviewRatingScreen } from "./features/userReview/ReviewRatingScreen" import { useOnAppRoutesAnimationComplete } from "./hooks/useOnAppRoutesAnimationComplete" import { routes } from "./routes" @@ -99,8 +99,7 @@ import { NetworkSettingsScreenContainer } from "./features/settings/developerSet import { AccountOwnerWarningScreen } from "./features/accountTokens/warning/AccountOwnerWarningScreen" import { ExportPrivateKeyScreenContainer } from "./features/settings/account/ExportPrivateKeyScreenContainer" import { ClearLocalStorageScreen } from "./features/settings/developerSettings/clearLocalStorage/ClearLocalStorageScreen" -import { useProvisionAnnouncement } from "./services/provision/useProvisionAnnouncement" -import { ProvisionAnnouncement } from "./features/provision/ProvisionAnnouncement" +import { OnboardingPrivacyScreenContainer } from "./features/onboarding/OnboardingPrivacyScreenContainer" import { DeploymentDataScreen } from "./features/settings/developerSettings/deploymentData/DeploymentDataScreen" interface LocationWithState extends Location { @@ -301,7 +300,11 @@ const walletRoutes = ( } + element={ + + + + } /> } + element={ + + + + } /> } /> + } + /> } @@ -623,7 +634,7 @@ const fullscreenRoutes = ( } /> } + element={} /> { const hasActions = useView(hasActionsView) const isRecovering = useView(isRecoveringView) const isClearingStorage = useView(isClearingStorageView) - const provisionAnnouncement = useProvisionAnnouncement() /** TODO: refactor: this should maybe be invoked by service + worker pattern */ const showActions = useMemo(() => { @@ -677,14 +687,6 @@ export const AppRoutes: FC = () => { ) } - if (provisionAnnouncement) { - return ( - - ) - } - return ( = ({ address }) => { > diff --git a/packages/extension/src/ui/components/ClearStorageModal.tsx b/packages/extension/src/ui/components/ClearStorageModal.tsx index c54910f49..4b43579a0 100644 --- a/packages/extension/src/ui/components/ClearStorageModal.tsx +++ b/packages/extension/src/ui/components/ClearStorageModal.tsx @@ -1,4 +1,4 @@ -import { H5, P3 } from "@argent/ui" +import { H5 } from "@argent/x-ui" import { Button, Flex, diff --git a/packages/extension/src/ui/components/ControlledInput.tsx b/packages/extension/src/ui/components/ControlledInput.tsx index f286bc7a5..5e4b705a9 100644 --- a/packages/extension/src/ui/components/ControlledInput.tsx +++ b/packages/extension/src/ui/components/ControlledInput.tsx @@ -1,4 +1,4 @@ -import { FieldError } from "@argent/ui" +import { FieldError } from "@argent/x-ui" import { Input, InputProps } from "@chakra-ui/react" import { FC } from "react" import { Control, Controller, FieldPath, FieldValues } from "react-hook-form" diff --git a/packages/extension/src/ui/components/ControlledTextArea.tsx b/packages/extension/src/ui/components/ControlledTextArea.tsx index c7b46594d..a0f0591f5 100644 --- a/packages/extension/src/ui/components/ControlledTextArea.tsx +++ b/packages/extension/src/ui/components/ControlledTextArea.tsx @@ -1,4 +1,4 @@ -import { FieldError } from "@argent/ui" +import { FieldError } from "@argent/x-ui" import { Textarea, TextareaProps } from "@chakra-ui/react" import { FC } from "react" import { Control, Controller, FieldPath, FieldValues } from "react-hook-form" diff --git a/packages/extension/src/ui/components/CustomButtonCell.tsx b/packages/extension/src/ui/components/CustomButtonCell.tsx index e754b90e2..7448b1495 100644 --- a/packages/extension/src/ui/components/CustomButtonCell.tsx +++ b/packages/extension/src/ui/components/CustomButtonCell.tsx @@ -1,4 +1,4 @@ -import { Button } from "@argent/ui" +import { Button } from "@argent/x-ui" import { ButtonProps } from "@chakra-ui/react" import { FC } from "react" @@ -15,8 +15,8 @@ export const CustomButtonCell: FC = ({ const colorScheme = transparent ? "transparent" : highlighted - ? "tertiary" - : "neutrals" + ? "tertiary" + : "neutrals" return ( )} {showSendButton && ( @@ -57,6 +61,18 @@ export const AccountTokensButtons: FC = ({ Send )} + {portfolioUrl && showSendButton && ( + + )} {account?.type === "plugin" && ( )} - + + + {envLabel && ( + + {envLabel} + + )} {showNetworkSwitcher && } {showSettingsButton && ( = (props) => { @@ -32,6 +34,8 @@ export const AccountNavigationBarContainer: FC< const accountName = account && account.name + const envLabel = argentXEnv === "hydrogen" ? "Hydrogen" : undefined + return ( ) diff --git a/packages/extension/src/ui/features/accounts/AccountScreenEmpty.tsx b/packages/extension/src/ui/features/accounts/AccountScreenEmpty.tsx index 6fba9dc44..1a14b6df3 100644 --- a/packages/extension/src/ui/features/accounts/AccountScreenEmpty.tsx +++ b/packages/extension/src/ui/features/accounts/AccountScreenEmpty.tsx @@ -1,4 +1,4 @@ -import { Empty, EmptyButton, icons } from "@argent/ui" +import { Empty, EmptyButton, icons } from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { HiddenAccountsBarContainer } from "./HiddenAccountsBar" diff --git a/packages/extension/src/ui/features/accounts/AccountSelect.tsx b/packages/extension/src/ui/features/accounts/AccountSelect.tsx index 0857be6a7..cc86f962f 100644 --- a/packages/extension/src/ui/features/accounts/AccountSelect.tsx +++ b/packages/extension/src/ui/features/accounts/AccountSelect.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { Box, Flex } from "@chakra-ui/react" import { FC, useCallback } from "react" import ReactSelect, { diff --git a/packages/extension/src/ui/features/accounts/AddNewAccountScreen.tsx b/packages/extension/src/ui/features/accounts/AddNewAccountScreen.tsx index 2dace5319..7eb7de3e9 100644 --- a/packages/extension/src/ui/features/accounts/AddNewAccountScreen.tsx +++ b/packages/extension/src/ui/features/accounts/AddNewAccountScreen.tsx @@ -4,7 +4,7 @@ import { H6, NavigationContainer, P4, -} from "@argent/ui" +} from "@argent/x-ui" import { Center, Flex, Spinner } from "@chakra-ui/react" import { FC, ReactEventHandler } from "react" diff --git a/packages/extension/src/ui/features/accounts/AddNewAccountScreenContainer.tsx b/packages/extension/src/ui/features/accounts/AddNewAccountScreenContainer.tsx index 8471f7fde..98d1401a2 100644 --- a/packages/extension/src/ui/features/accounts/AddNewAccountScreenContainer.tsx +++ b/packages/extension/src/ui/features/accounts/AddNewAccountScreenContainer.tsx @@ -1,4 +1,4 @@ -import { useNavigateBack } from "@argent/ui" +import { useNavigateBack } from "@argent/x-ui" import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/accounts/AddressBookMenu.tsx b/packages/extension/src/ui/features/accounts/AddressBookMenu.tsx index a187c0893..d548dd6df 100644 --- a/packages/extension/src/ui/features/accounts/AddressBookMenu.tsx +++ b/packages/extension/src/ui/features/accounts/AddressBookMenu.tsx @@ -1,4 +1,4 @@ -import { B3 } from "@argent/ui" +import { B3 } from "@argent/x-ui" import { Box, Tab, diff --git a/packages/extension/src/ui/features/accounts/ClickableShieldBanner.tsx b/packages/extension/src/ui/features/accounts/ClickableShieldBanner.tsx index a5dabb88e..8ecd2a0fd 100644 --- a/packages/extension/src/ui/features/accounts/ClickableShieldBanner.tsx +++ b/packages/extension/src/ui/features/accounts/ClickableShieldBanner.tsx @@ -1,4 +1,4 @@ -import { L2, icons } from "@argent/ui" +import { L2, icons } from "@argent/x-ui" import { Button, Flex, Text } from "@chakra-ui/react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/accounts/DeployAccountScreen.tsx b/packages/extension/src/ui/features/accounts/DeployAccountScreen.tsx index 2bd6500ca..2131b214e 100644 --- a/packages/extension/src/ui/features/accounts/DeployAccountScreen.tsx +++ b/packages/extension/src/ui/features/accounts/DeployAccountScreen.tsx @@ -1,4 +1,4 @@ -import { Button, P3, icons } from "@argent/ui" +import { Button, P3, icons } from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { DeployAccountScreenContainerProps } from "./deployAccountScreen.model" diff --git a/packages/extension/src/ui/features/accounts/DeprecatedAccountsWarning.tsx b/packages/extension/src/ui/features/accounts/DeprecatedAccountsWarning.tsx index 569bc3e29..c1ffab48f 100644 --- a/packages/extension/src/ui/features/accounts/DeprecatedAccountsWarning.tsx +++ b/packages/extension/src/ui/features/accounts/DeprecatedAccountsWarning.tsx @@ -1,4 +1,4 @@ -import { H6, P4, icons } from "@argent/ui" +import { H6, P4, icons } from "@argent/x-ui" import { Flex, HStack } from "@chakra-ui/react" // FIXME: remove when depricated accounts do not longer work import { FC } from "react" diff --git a/packages/extension/src/ui/features/accounts/GroupedAccountList.tsx b/packages/extension/src/ui/features/accounts/GroupedAccountList.tsx index 1edba40c0..789d111cb 100644 --- a/packages/extension/src/ui/features/accounts/GroupedAccountList.tsx +++ b/packages/extension/src/ui/features/accounts/GroupedAccountList.tsx @@ -1,4 +1,4 @@ -import { H6 } from "@argent/ui" +import { H6 } from "@argent/x-ui" import { Box, Flex } from "@chakra-ui/react" import { isEmpty } from "lodash-es" import { FC } from "react" diff --git a/packages/extension/src/ui/features/accounts/HiddenAccountsBarContainer.tsx b/packages/extension/src/ui/features/accounts/HiddenAccountsBarContainer.tsx index fedd24522..2ba0d18dc 100644 --- a/packages/extension/src/ui/features/accounts/HiddenAccountsBarContainer.tsx +++ b/packages/extension/src/ui/features/accounts/HiddenAccountsBarContainer.tsx @@ -1,7 +1,7 @@ /** * Why is this a container? */ -import { Button, icons } from "@argent/ui" +import { Button, icons } from "@argent/x-ui" import { Center, chakra } from "@chakra-ui/react" import { FC, ReactEventHandler } from "react" @@ -29,7 +29,7 @@ export const HiddenAccountsBar: FC = ({ onClick }) => { leftIcon={} size="sm" colorScheme="transparent" - color="white50" + color="white.50" > Hidden accounts diff --git a/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreen.tsx b/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreen.tsx index 4a9923d42..8cd4ffe1b 100644 --- a/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreen.tsx +++ b/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreen.tsx @@ -1,10 +1,10 @@ -import { H5, P3 } from "@argent/ui" +import { H5, P3 } from "@argent/x-ui" import { Center, VStack } from "@chakra-ui/react" import { FC } from "react" import { ConfirmScreen } from "../actions/transaction/ApproveTransactionScreen/ConfirmScreen" import { HideOrDeleteAccountConfirmScreenProps } from "./hideOrDeleteAccountConfirmScreen.model" -import { formatFullAddress } from "@argent/shared" +import { formatFullAddress } from "@argent/x-shared" export const HideOrDeleteAccountConfirmScreen: FC< HideOrDeleteAccountConfirmScreenProps diff --git a/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreenContainer.tsx b/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreenContainer.tsx index 7fb57c73d..0f97a607f 100644 --- a/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreenContainer.tsx +++ b/packages/extension/src/ui/features/accounts/HideOrDeleteAccountConfirmScreenContainer.tsx @@ -1,4 +1,4 @@ -import { useNavigateBack } from "@argent/ui" +import { useNavigateBack } from "@argent/x-ui" import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/accounts/PrettyAccountAddressArgentX.tsx b/packages/extension/src/ui/features/accounts/PrettyAccountAddressArgentX.tsx index 28c8aeeb2..2b3632581 100644 --- a/packages/extension/src/ui/features/accounts/PrettyAccountAddressArgentX.tsx +++ b/packages/extension/src/ui/features/accounts/PrettyAccountAddressArgentX.tsx @@ -1,11 +1,11 @@ -import { PrettyAccountAddress, PrettyAccountAddressProps } from "@argent/ui" +import { PrettyAccountAddress, PrettyAccountAddressProps } from "@argent/x-ui" import { FC, useMemo } from "react" import type { AddressBookContact } from "../../../shared/addressBook/type" import { useAddressBook } from "../../hooks/useAddressBook" import { accountFindFamily } from "../../views/account" import { useView } from "../../views/implementation/react" -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" const getContactNameForAddress = ( accountAddress: string, diff --git a/packages/extension/src/ui/features/accounts/WarningScreen.tsx b/packages/extension/src/ui/features/accounts/WarningScreen.tsx index 25a242124..0ac21b5c7 100644 --- a/packages/extension/src/ui/features/accounts/WarningScreen.tsx +++ b/packages/extension/src/ui/features/accounts/WarningScreen.tsx @@ -5,7 +5,7 @@ import { P3, StickyGroup, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Box, Center, Circle, Flex } from "@chakra-ui/react" import { FC, isValidElement, useCallback, useState } from "react" import Measure, { ContentRect } from "react-measure" diff --git a/packages/extension/src/ui/features/accounts/accountNavigationBar.model.ts b/packages/extension/src/ui/features/accounts/accountNavigationBar.model.ts index ba8f89d0b..9182095be 100644 --- a/packages/extension/src/ui/features/accounts/accountNavigationBar.model.ts +++ b/packages/extension/src/ui/features/accounts/accountNavigationBar.model.ts @@ -1,4 +1,4 @@ -import { NavigationBarProps } from "@argent/ui" +import { NavigationBarProps } from "@argent/x-ui" import { ReactEventHandler } from "react" export interface AccountNavigationBarProps @@ -8,6 +8,7 @@ export interface AccountNavigationBarProps isMultisig?: boolean onAccountList?: ReactEventHandler onSettings?: ReactEventHandler + envLabel?: string } export interface AccountNavigationBarContainerProps diff --git a/packages/extension/src/ui/features/accounts/accountTransactions.state.ts b/packages/extension/src/ui/features/accounts/accountTransactions.state.ts index 2d5380bb4..a71438d91 100644 --- a/packages/extension/src/ui/features/accounts/accountTransactions.state.ts +++ b/packages/extension/src/ui/features/accounts/accountTransactions.state.ts @@ -6,7 +6,7 @@ import { useArrayStorage } from "../../hooks/useStorage" import { Transaction } from "../../../shared/transactions" import { BaseWalletAccount } from "../../../shared/wallet.model" import { accountsEqual } from "../../../shared/utils/accountsEqual" -import { getAccountIdentifier } from "@argent/shared" +import { getAccountIdentifier } from "@argent/x-shared" import { getTransactionStatus } from "../../../shared/transactions/utils" import { isSafeUpgradeTransaction } from "../../../shared/utils/isUpgradeTransaction" @@ -21,7 +21,7 @@ const byAccountSelector = memoize( (account) => (account ? getAccountIdentifier(account) : "unknown-account"), ) -export const useAccountTransactions: UseAccountTransactions = (account) => { +const useSortedTransactions = (account?: BaseWalletAccount) => { const transactions = useArrayStorage( transactionsStore, byAccountSelector(account), @@ -32,6 +32,12 @@ export const useAccountTransactions: UseAccountTransactions = (account) => { [transactions], ) + return { transactions, sortedTransactions } +} + +export const useAccountTransactions: UseAccountTransactions = (account) => { + const { transactions, sortedTransactions } = useSortedTransactions(account) + const pendingTransactions = sortedTransactions.filter((transaction) => { const { finality_status } = getTransactionStatus(transaction) return finality_status === "RECEIVED" && !transaction.meta?.isDeployAccount @@ -43,15 +49,7 @@ export const useAccountTransactions: UseAccountTransactions = (account) => { export const useDeployAccountTransactions: UseAccountTransactions = ( account, ) => { - const transactions = useArrayStorage( - transactionsStore, - byAccountSelector(account), - ) - - const sortedTransactions = useMemo( - () => transactions.sort((a, b) => b.timestamp - a.timestamp), - [transactions], - ) + const { transactions, sortedTransactions } = useSortedTransactions(account) const pendingTransactions = sortedTransactions.filter((transaction) => { const { finality_status } = getTransactionStatus(transaction) @@ -64,15 +62,7 @@ export const useDeployAccountTransactions: UseAccountTransactions = ( export const useUpgradeAccountTransactions: UseAccountTransactions = ( account, ) => { - const transactions = useArrayStorage( - transactionsStore, - byAccountSelector(account), - ) - - const sortedTransactions = useMemo( - () => transactions.sort((a, b) => b.timestamp - a.timestamp), - [transactions], - ) + const { transactions, sortedTransactions } = useSortedTransactions(account) const pendingTransactions = sortedTransactions.filter((transaction) => { const { finality_status } = getTransactionStatus(transaction) diff --git a/packages/extension/src/ui/features/accounts/accounts.service.ts b/packages/extension/src/ui/features/accounts/accounts.service.ts index 4b14cc61d..870dde5c6 100644 --- a/packages/extension/src/ui/features/accounts/accounts.service.ts +++ b/packages/extension/src/ui/features/accounts/accounts.service.ts @@ -8,7 +8,7 @@ import { generateAvatarImage, id, stripAddressZeroPadding, -} from "@argent/shared" +} from "@argent/x-shared" import { BaseWalletAccount } from "../../../shared/wallet.model" import { accountsEqual } from "../../../shared/utils/accountsEqual" import { withPolling } from "../../services/swr.service" @@ -28,7 +28,7 @@ const argentColorsArray = [ "FF5C72", ] -export const getColor = (name: string) => { +export const getColor = (name: string = "") => { const hash = id(name).slice(-2) const index = parseInt(hash, 16) % argentColorsArray.length return argentColorsArray[index] diff --git a/packages/extension/src/ui/features/accounts/ui/StarknetAccountMessage.tsx b/packages/extension/src/ui/features/accounts/ui/StarknetAccountMessage.tsx index e58b29f95..ddc947621 100644 --- a/packages/extension/src/ui/features/accounts/ui/StarknetAccountMessage.tsx +++ b/packages/extension/src/ui/features/accounts/ui/StarknetAccountMessage.tsx @@ -3,7 +3,7 @@ import { H3, NavigationContainer, typographyStyles, -} from "@argent/ui" +} from "@argent/x-ui" import { Box, Circle, Flex, Link } from "@chakra-ui/react" import { FC, PropsWithChildren, ReactEventHandler, ReactNode } from "react" diff --git a/packages/extension/src/ui/features/accounts/useAccountOrContact.ts b/packages/extension/src/ui/features/accounts/useAccountOrContact.ts index e48e72725..cffea0399 100644 --- a/packages/extension/src/ui/features/accounts/useAccountOrContact.ts +++ b/packages/extension/src/ui/features/accounts/useAccountOrContact.ts @@ -3,7 +3,7 @@ import { isEqualAddress, isEqualStarknetDomainName, isStarknetDomainName, -} from "@argent/shared" +} from "@argent/x-shared" import { useMemo } from "react" import { useAppState } from "../../app.state" import { visibleAccountsOnNetworkFamily } from "../../views/account" diff --git a/packages/extension/src/ui/features/accounts/useAccountOwner.ts b/packages/extension/src/ui/features/accounts/useAccountOwner.ts index 715882510..eab5a7c6c 100644 --- a/packages/extension/src/ui/features/accounts/useAccountOwner.ts +++ b/packages/extension/src/ui/features/accounts/useAccountOwner.ts @@ -1,4 +1,4 @@ -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { useRef } from "react" import useSWR from "swr" diff --git a/packages/extension/src/ui/features/accounts/useAccountTypesForNetwork.tsx b/packages/extension/src/ui/features/accounts/useAccountTypesForNetwork.tsx index c854d35f3..4a9e9dbd8 100644 --- a/packages/extension/src/ui/features/accounts/useAccountTypesForNetwork.tsx +++ b/packages/extension/src/ui/features/accounts/useAccountTypesForNetwork.tsx @@ -1,7 +1,7 @@ -import { isFeatureEnabled } from "@argent/shared" +import { isFeatureEnabled } from "@argent/x-shared" import { isFunction } from "lodash-es" import { useMemo } from "react" -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { type Network } from "../../../shared/network" import { AccountTypeId, type AccountType } from "./AddNewAccountScreen" diff --git a/packages/extension/src/ui/features/accounts/useOnSettingsAccountNavigate.ts b/packages/extension/src/ui/features/accounts/useOnSettingsAccountNavigate.ts new file mode 100644 index 000000000..00eac97b0 --- /dev/null +++ b/packages/extension/src/ui/features/accounts/useOnSettingsAccountNavigate.ts @@ -0,0 +1,6 @@ +import { WalletAccount } from "../../../shared/wallet.model" +import { useOnSettingsNavigate } from "./useOnSettingsNavigate" + +export const useOnSettingsAccountNavigate = (account?: WalletAccount) => { + return useOnSettingsNavigate(account, true) +} diff --git a/packages/extension/src/ui/features/accounts/useOnSettingsNavigate.ts b/packages/extension/src/ui/features/accounts/useOnSettingsNavigate.ts index e9281230e..1011f29b7 100644 --- a/packages/extension/src/ui/features/accounts/useOnSettingsNavigate.ts +++ b/packages/extension/src/ui/features/accounts/useOnSettingsNavigate.ts @@ -8,7 +8,10 @@ import { selectedAccountView } from "../../views/account" import { clientAccountService } from "../../services/account" import { useView } from "../../views/implementation/react" -export const useOnSettingsNavigate = (account?: WalletAccount) => { +export const useOnSettingsNavigate = ( + account?: WalletAccount, + settingsAccount = false, +) => { const selectedAccount = useView(selectedAccountView) const multisig = useMultisig(account) const signerIsInMultisig = useIsSignerInMultisig(multisig) @@ -22,41 +25,19 @@ export const useOnSettingsNavigate = (account?: WalletAccount) => { if (multisig && !signerIsInMultisig) { navigate(routes.multisigRemovedSettings(multisig.address, returnTo)) } else { - navigate(routes.settings(returnTo)) + if (settingsAccount) { + navigate(routes.settingsAccount(account?.address, returnTo)) + } else { + navigate(routes.settings(returnTo)) + } } }, [ account, multisig, navigate, returnTo, - selectedAccount, - signerIsInMultisig, - ]) - return onSettings -} - -export const useOnSettingsAccountNavigate = (account?: WalletAccount) => { - const selectedAccount = useView(selectedAccountView) - const multisig = useMultisig(account) - const signerIsInMultisig = useIsSignerInMultisig(multisig) - const navigate = useNavigate() - const returnTo = useCurrentPathnameWithQuery() - - const onSettings = useCallback(async () => { - if (account && selectedAccount?.address !== account.address) { - await clientAccountService.select(account) - } - if (multisig && !signerIsInMultisig) { - navigate(routes.multisigRemovedSettings(multisig.address, returnTo)) - } else { - navigate(routes.settingsAccount(account?.address, returnTo)) - } - }, [ - account, - multisig, - navigate, - returnTo, - selectedAccount, + selectedAccount?.address, + settingsAccount, signerIsInMultisig, ]) return onSettings diff --git a/packages/extension/src/ui/features/accounts/usePublicKey.ts b/packages/extension/src/ui/features/accounts/usePublicKey.ts index 413621382..b8045dc34 100644 --- a/packages/extension/src/ui/features/accounts/usePublicKey.ts +++ b/packages/extension/src/ui/features/accounts/usePublicKey.ts @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from "react" import { BaseWalletAccount } from "../../../shared/wallet.model" import { accountMessagingService } from "../../services/accountMessaging" -import { encodeBase58 } from "@argent/shared" +import { encodeBase58 } from "@argent/x-shared" export const usePublicKey = (account?: BaseWalletAccount) => { const [pubKey, setPubKey] = useState() diff --git a/packages/extension/src/ui/features/actions/AddNetworkScreen.tsx b/packages/extension/src/ui/features/actions/AddNetworkScreen.tsx index 06f204c53..22efaf935 100644 --- a/packages/extension/src/ui/features/actions/AddNetworkScreen.tsx +++ b/packages/extension/src/ui/features/actions/AddNetworkScreen.tsx @@ -4,7 +4,7 @@ import { FieldError, HeaderCell, NavigationContainer, -} from "@argent/ui" +} from "@argent/x-ui" import { Flex, FormControl, Input } from "@chakra-ui/react" import { FC, ReactNode } from "react" diff --git a/packages/extension/src/ui/features/actions/AddTokenActionScreenContainer.tsx b/packages/extension/src/ui/features/actions/AddTokenActionScreenContainer.tsx index 9333dc03b..33d1e212b 100644 --- a/packages/extension/src/ui/features/actions/AddTokenActionScreenContainer.tsx +++ b/packages/extension/src/ui/features/actions/AddTokenActionScreenContainer.tsx @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { FC } from "react" import { AddTokenScreenContainer } from "./AddTokenScreenContainer" diff --git a/packages/extension/src/ui/features/actions/AddTokenScreen.tsx b/packages/extension/src/ui/features/actions/AddTokenScreen.tsx index cd82c2543..ecd41eb25 100644 --- a/packages/extension/src/ui/features/actions/AddTokenScreen.tsx +++ b/packages/extension/src/ui/features/actions/AddTokenScreen.tsx @@ -1,4 +1,4 @@ -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" import { Alert, BarBackButton, @@ -7,7 +7,7 @@ import { HeaderCell, NavigationContainer, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Flex, FormControl } from "@chakra-ui/react" import { zodResolver } from "@hookform/resolvers/zod" import { FC, ReactNode, useEffect, useMemo } from "react" diff --git a/packages/extension/src/ui/features/actions/AddTokenScreenContainer.tsx b/packages/extension/src/ui/features/actions/AddTokenScreenContainer.tsx index 306200899..5ceb102a0 100644 --- a/packages/extension/src/ui/features/actions/AddTokenScreenContainer.tsx +++ b/packages/extension/src/ui/features/actions/AddTokenScreenContainer.tsx @@ -1,5 +1,5 @@ -import { Address, addressSchema, isEqualAddress } from "@argent/shared" -import { useToast } from "@argent/ui" +import { Address, addressSchema, isEqualAddress } from "@argent/x-shared" +import { useToast } from "@argent/x-ui" import { debounce } from "lodash-es" import { FC, Suspense, useCallback, useMemo, useState } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/actions/ApproveDeployAccount.tsx b/packages/extension/src/ui/features/actions/ApproveDeployAccount.tsx index dfe75c937..8a18c7383 100644 --- a/packages/extension/src/ui/features/actions/ApproveDeployAccount.tsx +++ b/packages/extension/src/ui/features/actions/ApproveDeployAccount.tsx @@ -16,7 +16,6 @@ import { } from "./transactionV2/TransactionHeader" import { TransactionReviewActions } from "./transactionV2/action/TransactionReviewActions" import { ReviewOfTransaction } from "../../../shared/transactionReview/schema" -import { ETH_TOKEN_ADDRESS } from "../../../shared/network/constants" import { useBestFeeToken } from "./useBestFeeToken" export interface ApproveDeployAccountScreenProps diff --git a/packages/extension/src/ui/features/actions/ApproveSignatureScreen.tsx b/packages/extension/src/ui/features/actions/ApproveSignatureScreen.tsx index 1bcbf745f..52ce45486 100644 --- a/packages/extension/src/ui/features/actions/ApproveSignatureScreen.tsx +++ b/packages/extension/src/ui/features/actions/ApproveSignatureScreen.tsx @@ -1,4 +1,4 @@ -import { H3, P3, PreBoxJsonStringify } from "@argent/ui" +import { H3, P3, PreBoxJsonStringify } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, ReactNode } from "react" import { typedData } from "starknet" diff --git a/packages/extension/src/ui/features/actions/DeprecatedConfirmScreen.tsx b/packages/extension/src/ui/features/actions/DeprecatedConfirmScreen.tsx index 6ed26ebd9..deeed7882 100644 --- a/packages/extension/src/ui/features/actions/DeprecatedConfirmScreen.tsx +++ b/packages/extension/src/ui/features/actions/DeprecatedConfirmScreen.tsx @@ -1,4 +1,4 @@ -import { ScrollContainer } from "@argent/ui" +import { ScrollContainer } from "@argent/x-ui" import { Box } from "@chakra-ui/react" import { FC, ReactNode, useState } from "react" import Measure from "react-measure" diff --git a/packages/extension/src/ui/features/actions/ErrorScreen.tsx b/packages/extension/src/ui/features/actions/ErrorScreen.tsx index 9cc3b7a16..9b6b93171 100644 --- a/packages/extension/src/ui/features/actions/ErrorScreen.tsx +++ b/packages/extension/src/ui/features/actions/ErrorScreen.tsx @@ -1,4 +1,4 @@ -import { H3, PreBox } from "@argent/ui" +import { H3, PreBox } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/actions/ErrorScreenContainer.tsx b/packages/extension/src/ui/features/actions/ErrorScreenContainer.tsx index 0750a8781..46166109b 100644 --- a/packages/extension/src/ui/features/actions/ErrorScreenContainer.tsx +++ b/packages/extension/src/ui/features/actions/ErrorScreenContainer.tsx @@ -1,4 +1,4 @@ -import { useNavigateBack } from "@argent/ui" +import { useNavigateBack } from "@argent/x-ui" import { FC } from "react" import { coerceErrorToString } from "../../../shared/utils/error" diff --git a/packages/extension/src/ui/features/actions/LoadingScreen.tsx b/packages/extension/src/ui/features/actions/LoadingScreen.tsx index e974adfb0..d0ac4430a 100644 --- a/packages/extension/src/ui/features/actions/LoadingScreen.tsx +++ b/packages/extension/src/ui/features/actions/LoadingScreen.tsx @@ -35,7 +35,7 @@ export const LoadingScreen: FC = ({ max={1} value={progress} trackColor={"transparent"} - color={"text.primary"} + color={"text-primary"} capIsRound /> diff --git a/packages/extension/src/ui/features/actions/SignatureRequestRejectedScreen.tsx b/packages/extension/src/ui/features/actions/SignatureRequestRejectedScreen.tsx index 95670d5e1..5be899e8a 100644 --- a/packages/extension/src/ui/features/actions/SignatureRequestRejectedScreen.tsx +++ b/packages/extension/src/ui/features/actions/SignatureRequestRejectedScreen.tsx @@ -2,7 +2,7 @@ import React, { FC } from "react" import { ConfirmScreen } from "../actions/transaction/ApproveTransactionScreen/ConfirmScreen" import { Circle, Flex } from "@chakra-ui/react" -import { H5, P4, icons } from "@argent/ui" +import { H5, P4, icons } from "@argent/x-ui" import { WalletAccount } from "../../../shared/wallet.model" const { AlertFillIcon, SignIcon } = icons @@ -45,9 +45,14 @@ export const SignatureRequestRejectedScreen: FC< A dapp is requesting to sign a message - - - + + + {error} diff --git a/packages/extension/src/ui/features/actions/SwitchNetworkScreen.tsx b/packages/extension/src/ui/features/actions/SwitchNetworkScreen.tsx index 70f56acba..5b8bac17f 100644 --- a/packages/extension/src/ui/features/actions/SwitchNetworkScreen.tsx +++ b/packages/extension/src/ui/features/actions/SwitchNetworkScreen.tsx @@ -1,4 +1,4 @@ -import { B3, icons } from "@argent/ui" +import { B3, icons } from "@argent/x-ui" import { Center, Flex, Text } from "@chakra-ui/react" import { FC, PropsWithChildren } from "react" diff --git a/packages/extension/src/ui/features/actions/SwitchNetworkScreenContainer.tsx b/packages/extension/src/ui/features/actions/SwitchNetworkScreenContainer.tsx index bf1028858..8b8e9cd4e 100644 --- a/packages/extension/src/ui/features/actions/SwitchNetworkScreenContainer.tsx +++ b/packages/extension/src/ui/features/actions/SwitchNetworkScreenContainer.tsx @@ -1,6 +1,5 @@ import { FC } from "react" import { useActionScreen } from "./hooks/useActionScreen" -import { useAppState } from "../../app.state" import { useDappDisplayAttributes } from "./connectDapp/useDappDisplayAttributes" import { AccountNavigationBarContainer } from "../accounts/AccountNavigationBarContainer" import { SwitchNetworkScreen } from "./SwitchNetworkScreen" @@ -15,7 +14,6 @@ export const SwitchNetworkScreenContainer: FC = () => { } const host = action.meta.origin || "" const requestedNetwork = action.payload - const { switcherNetworkId } = useAppState() const dappDisplayAttributes = useDappDisplayAttributes(host) const fromNetworkTitle = selectedAccount?.network.name diff --git a/packages/extension/src/ui/features/actions/__fixtures__/aspect.ts b/packages/extension/src/ui/features/actions/__fixtures__/aspect.ts index 654b2c20b..1ba5bb9d7 100644 --- a/packages/extension/src/ui/features/actions/__fixtures__/aspect.ts +++ b/packages/extension/src/ui/features/actions/__fixtures__/aspect.ts @@ -1,17 +1,16 @@ import { TransactionActionFixture } from "./types" export const aspect: TransactionActionFixture = { - actionHash: "a16b5b24e79859e094a31a6c30aa8202b74bb2a0", aggregatedData: [ { token: { address: - "0x4a3621276a83251b557a8140e915599ae8e7b6207b067ea701635c0d509801e", - name: "Mint Square Storefront", - symbol: "MINTSQ", + "0x031f9085c75917a4860da8628ffc3b4d4587da88dc2ee664516a9271a94cf266", + name: "Xplorer", + symbol: "XPLORER", decimals: 0, - networkId: "mainnet-alpha", - tokenId: "47458", + networkId: "goerli-alpha", + tokenId: "1002606", type: "erc721", }, approvals: [], @@ -20,7 +19,7 @@ export const aspect: TransactionActionFixture = { recipients: [ { address: - "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", + "0x325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", amount: BigInt("1"), }, ], @@ -59,153 +58,106 @@ export const aspect: TransactionActionFixture = { }, ], transactionReview: { - assessment: "neutral", - reviews: [ + transactions: [ { - assessment: "neutral", - assessmentDetails: { - contract_address: - "0x02a92f0f860bf7c63fb9ef42cff4137006b309e0e6e1484e42d0b5511959414d", + reviewOfTransaction: { + assessment: "neutral", + warnings: [], + reviews: [ + { + assessment: "neutral", + warnings: [], + action: { + name: "mint", + properties: [], + defaultProperties: [ + { + type: "address", + label: "default_contract", + address: + "0x031f9085c75917a4860da8628ffc3b4d4587da88dc2ee664516a9271a94cf266", + verified: false, + }, + { + type: "calldata", + label: "default_call", + entrypoint: "mint", + calldata: [ + "0x0325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + "0x00000000000000000000000000000000000000000000000000000000000f4c6e", + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x00000000000000000000000000000000000000000000000000000000000f4240", + "0x00000000000000000000000000000000000000000000000000000000688c50d8", + "0x03dc421f118edcd7c0a3b9913b4b40d40d8309dde29953210ec85ba365eb2d99", + "0x0132188b9576cf7eea5e25dc9aabee55cf131d4867b70880a20eceaed5358b76", + ], + }, + ], + }, + }, + ], + }, + simulation: { + approvals: [], + transfers: [ + { + tokenAddress: + "0x31f9085c75917a4860da8628ffc3b4d4587da88dc2ee664516a9271a94cf266", + from: "0x0", + to: "0x325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + tokenId: "1002606", + details: { + address: + "0x31f9085c75917a4860da8628ffc3b4d4587da88dc2ee664516a9271a94cf266", + name: "Xplorer", + symbol: "XPLORER", + unknown: false, + type: "ERC721", + }, + }, + ], + summary: [ + { + type: "transfer", + label: "simulation_summary_receive", + tokenId: "1002606", + token: { + address: + "0x31f9085c75917a4860da8628ffc3b4d4587da88dc2ee664516a9271a94cf266", + name: "Xplorer", + symbol: "XPLORER", + unknown: false, + type: "ERC721", + }, + sent: false, + }, + ], + calculatedNonce: "0x1", + feeEstimation: { + overallFee: 5786000040502, + gasPrice: 1000000007, + gasUsage: 5786, + unit: "WEI", + maxFee: 17358006159710, + }, }, }, ], - targetedDapp: { - name: "Lorem Ipsum", - description: "Lorem ipsum dolor sit amet", - logoUrl: "https://www.dappland.com/dapps/jediswap/dapp-icon-jediswap.png", - links: [ - { - name: "website", - url: "https://jediswap.xyz", - position: 1, - }, - { - name: "twitter", - url: "https://twitter.com/jediswap", - position: 2, - }, - { - name: "discord", - url: "https://discord.gg/jediswap", - position: 3, - }, - ], - }, }, transactions: [ { calldata: [ - "1203547651708349271448768365881041305352887755542740175005943917204658012493", - "2997881207313980570241347267220574957273773683696432153748258537092592926903", - "0", - "1681661074", - "257877205755718", - "1", - "1", - "2097924334809010151269254159849064348527709275410586009206231441117935140894", - "47458", - "0", - "1", - "0", - "2", - "0", - "2087021424722619777119509474943472645767659996348769578120564519014510906823", - "0", - "0", - "97000000000000", - "0", - "2997881207313980570241347267220574957273773683696432153748258537092592926903", - "0", - "2087021424722619777119509474943472645767659996348769578120564519014510906823", - "0", - "0", - "3000000000000", - "0", - "2163043529925802864713042203646866750762128402292550239405067396543711442586", - "193537044949007465058234585984543106941963984792689474213073467382301419967", - "3123624182172242132799495490982949304040176803825006418688666371482845520789", + "0x0325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + "0x00000000000000000000000000000000000000000000000000000000000f4c6e", + "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x00000000000000000000000000000000000000000000000000000000000f4240", + "0x00000000000000000000000000000000000000000000000000000000688c50d8", + "0x03dc421f118edcd7c0a3b9913b4b40d40d8309dde29953210ec85ba365eb2d99", + "0x0132188b9576cf7eea5e25dc9aabee55cf131d4867b70880a20eceaed5358b76", ], contractAddress: - "0x02a92f0f860bf7c63fb9ef42cff4137006b309e0e6e1484e42d0b5511959414d", - entrypoint: "fillOrder", - }, - ], - transactionSimulation: [ - { - approvals: [ - { - tokenAddress: - "0x4a3621276a83251b557a8140e915599ae8e7b6207b067ea701635c0d509801e", - owner: - "0x6a0bd9a21ca429395565127efca751660b503c3966b964bdda5029e031380b7", - spender: "0x0", - tokenId: "47458", - details: { - symbol: "MINTSQ", - name: "Mint Square Storefront", - tokenURI: - "ipfs://QmNrLm3JL7DtryfwWjC9vdZm2mbGSwnkS4o4GSWZwqyFCt\u0000", - tokenType: "erc721", - decimals: "0", - usdValue: "0", - }, - }, - ], - transfers: [ - { - tokenAddress: - "0x4a3621276a83251b557a8140e915599ae8e7b6207b067ea701635c0d509801e", - from: "0x6a0bd9a21ca429395565127efca751660b503c3966b964bdda5029e031380b7", - to: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - tokenId: "47458", - details: { - symbol: "MINTSQ", - name: "Mint Square Storefront", - tokenURI: - "ipfs://QmNrLm3JL7DtryfwWjC9vdZm2mbGSwnkS4o4GSWZwqyFCt\u0000", - tokenType: "erc721", - decimals: "0", - usdValue: "0", - }, - }, - { - tokenAddress: - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - from: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - to: "0x6a0bd9a21ca429395565127efca751660b503c3966b964bdda5029e031380b7", - value: "97000000000000", - details: { - decimals: "18", - symbol: "ETH", - name: "Ether", - tokenType: "erc20", - usdValue: "0.161117", - tokenURI: "", - }, - }, - { - tokenAddress: - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - from: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - to: "0x4c83d3fa770187d7b0a23b3aa7132c7c8273fb4ec3db416f86e4a385596769a", - value: "3000000000000", - details: { - decimals: "18", - symbol: "ETH", - name: "Ether", - tokenType: "erc20", - usdValue: "0.004983", - tokenURI: "", - }, - }, - ], - feeEstimation: { - overallFee: 3744000037440, - gasPrice: 1000000010, - gasUsage: 3744, - unit: "WEI", - maxFee: 6744000037440, - }, + "0x031f9085c75917a4860da8628ffc3b4d4587da88dc2ee664516a9271a94cf266", + entrypoint: "mint", }, ], } diff --git a/packages/extension/src/ui/features/actions/__fixtures__/jediswap.ts b/packages/extension/src/ui/features/actions/__fixtures__/jediswap.ts index 1c447df16..26449848a 100644 --- a/packages/extension/src/ui/features/actions/__fixtures__/jediswap.ts +++ b/packages/extension/src/ui/features/actions/__fixtures__/jediswap.ts @@ -1,7 +1,6 @@ import { TransactionActionFixture } from "./types" export const jediswap: TransactionActionFixture = { - actionHash: "abc123", aggregatedData: [ { token: { @@ -73,93 +72,382 @@ export const jediswap: TransactionActionFixture = { }, ], transactionReview: { - assessment: "neutral", - targetedDapp: { - name: "JediSwap", - description: - "A community-led fully permissionless and composable AMM on Starknet.", - logoUrl: "https://www.dappland.com/dapps/jediswap/dapp-icon-jediswap.png", - links: [ - { - name: "website", - url: "https://jediswap.xyz", - position: 1, - }, - { - name: "twitter", - url: "https://twitter.com/jediswap", - position: 2, - }, - { - name: "discord", - url: "https://discord.gg/jediswap", - position: 3, - }, - ], - }, - reviews: [ + transactions: [ { - assessment: "neutral", - assessmentDetails: { - contract_address: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - }, - activity: { - value: { - token: { - address: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - name: "Ether", - symbol: "ETH", - decimals: 18, - unknown: false, - type: "ERC20", - }, - amount: "8812345773212", - usd: 0.01, - slippage: "equal", + reviewOfTransaction: { + assessment: "neutral", + warnings: [], + targetedDapp: { + name: "JediSwap", + description: + "A community-led fully permissionless and composable AMM on Starknet.", + logoUrl: + "https://www.dappland.com/dapps/jediswap/dapp-icon-jediswap.png", + iconUrl: + "https://www.dappland.com/dapps/jediswap/dapp-icon-jediswap.png", + links: [ + { + name: "website", + url: "https://jediswap.xyz", + position: 1, + }, + { + name: "twitter", + url: "https://twitter.com/jediswap", + position: 2, + }, + { + name: "discord", + url: "https://discord.gg/jediswap", + position: 3, + }, + ], + argentVerified: true, }, - spender: - "1865474183096745675831575676844391349131672372457503153362467315114684543011", - type: "approve", - }, - }, - { - assessment: "neutral", - assessmentDetails: { - contract_address: - "0x41fd22b238fa21cfcf5dd45a8548974d8263b3a531a60388411c5e230f97023", + + reviews: [ + { + assessment: "neutral", + warnings: [], + action: { + name: "ERC20_approve", + properties: [ + { + type: "amount", + label: "ERC20_approve_amount", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + amount: "1000000000000000", + usd: "3.45", + editable: true, + }, + { + type: "address", + label: "ERC20_approve_to", + address: + "0x07e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + verified: false, + }, + ], + defaultProperties: [ + { + type: "token_address", + label: "default_contract", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + type: "calldata", + label: "default_call", + entrypoint: "approve", + calldata: [ + "0x07e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + "0x00000000000000000000000000000000000000000000000000038d7ea4c68000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ], + }, + ], + }, + }, + { + assessment: "neutral", + warnings: [], + action: { + name: "multi_route_swap", + properties: [], + defaultProperties: [ + { + type: "address", + label: "default_contract", + address: + "0x07e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + verified: false, + }, + { + type: "calldata", + label: "default_call", + entrypoint: "multi_route_swap", + calldata: [ + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "0x00000000000000000000000000000000000000000000000000038d7ea4c68000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x005a643907b9a4bc6a55e9069c4fd5fd1f5c79a22470690f75556c4736e34426", + "0x00000000000000000000000000000000000000000000000000000021b6205d65", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000021236a0dfb", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + "0x0000000000000000000000000000000000000000000000000000000000000064", + "0x03e90652c3fe1f5f42578ffefca7fb00c88d4d18b5fb2bbeeee1a0d0d7d7d82d", + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "0x02bcc885342ebbcbcd170ae6cafa8a4bed22bb993479f49806e72d96af94c965", + "0x0000000000000000000000000000000000000000000000000000000000000064", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "0x005a643907b9a4bc6a55e9069c4fd5fd1f5c79a22470690f75556c4736e34426", + "0x0436924c4ed166d3c283d516adc424976cfccba108e3a0e3f3fc1ef319e23aa7", + "0x0000000000000000000000000000000000000000000000000000000000000064", + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0138e908d3e2bfce75c2c108136428f90447c321b9fa1b2fddf25c741e8dbbf1", + "0x000000000000000000000000000000000000009ebbfa808e40fa6010b04239a8", + ], + }, + ], + }, + }, + ], }, - activity: { - src: { - token: { - address: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - name: "Ether", - symbol: "ETH", - decimals: 18, - unknown: false, - type: "ERC20", + simulation: { + approvals: [ + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + owner: + "0x325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + spender: + "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + value: "1000000000000000", + approvalForAll: false, + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, }, - amount: "8812345773212", - usd: 0.01, - slippage: "equal", - }, - dst: { - token: { - address: - "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", - name: "USD Coin", - symbol: "USDC", - decimals: 6, - unknown: false, - type: "ERC20", + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + owner: + "0x325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + spender: + "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + value: "0", + approvalForAll: false, + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + owner: + "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + spender: + "0x2bcc885342ebbcbcd170ae6cafa8a4bed22bb993479f49806e72d96af94c965", + value: "1000000000000000", + approvalForAll: false, + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + owner: + "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + spender: + "0x2bcc885342ebbcbcd170ae6cafa8a4bed22bb993479f49806e72d96af94c965", + value: "0", + approvalForAll: false, + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + tokenAddress: + "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + owner: + "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + spender: + "0x436924c4ed166d3c283d516adc424976cfccba108e3a0e3f3fc1ef319e23aa7", + value: "557226183292359", + approvalForAll: false, + details: { + address: + "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + name: "Starknet Token", + symbol: "STRK", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/strk.png", + type: "ERC20", + }, + }, + { + tokenAddress: + "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + owner: + "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + spender: + "0x436924c4ed166d3c283d516adc424976cfccba108e3a0e3f3fc1ef319e23aa7", + value: "0", + approvalForAll: false, + details: { + address: + "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + name: "Starknet Token", + symbol: "STRK", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/strk.png", + type: "ERC20", + }, + }, + ], + transfers: [ + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + from: "0x325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + to: "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + value: "1000000000000000", + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + from: "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + to: "0x4e021092841c1b01907f42e7058f97e5a22056e605dce08a22868606ad675e0", + value: "1000000000000000", + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + tokenAddress: + "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + from: "0x4e021092841c1b01907f42e7058f97e5a22056e605dce08a22868606ad675e0", + to: "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + value: "557226183292359", + details: { + address: + "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + name: "Starknet Token", + symbol: "STRK", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/strk.png", + type: "ERC20", + }, }, - amount: "14709", - usd: 0.01, - slippage: "at_least", + { + tokenAddress: + "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + from: "0x7e36202ace0ab52bf438bd8a8b64b3731c48d09f0d8879f5b006384c2f35032", + to: "0x436924c4ed166d3c283d516adc424976cfccba108e3a0e3f3fc1ef319e23aa7", + value: "557226183292359", + details: { + address: + "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + name: "Starknet Token", + symbol: "STRK", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/strk.png", + type: "ERC20", + }, + }, + ], + summary: [ + { + type: "transfer", + label: "simulation_summary_send", + value: "1000000000000000", + usdValue: "3.44", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + sent: true, + }, + ], + calculatedNonce: "0x1", + feeEstimation: { + overallFee: 30351000212457, + gasPrice: 1000000007, + gasUsage: 30351, + unit: "WEI", + maxFee: 91053000052888, }, - type: "swap", }, }, ], @@ -192,68 +480,6 @@ export const jediswap: TransactionActionFixture = { entrypoint: "swap_exact_tokens_for_tokens", }, ], - transactionSimulation: [ - { - approvals: [ - { - tokenAddress: - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - owner: - "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - spender: - "0x41fd22b238fa21cfcf5dd45a8548974d8263b3a531a60388411c5e230f97023", - value: "8812345773212", - details: { - decimals: "18", - symbol: "ETH", - name: "Ether", - tokenType: "erc20", - usdValue: "0.014761", - tokenURI: "", - }, - }, - ], - transfers: [ - { - tokenAddress: - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - from: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - to: "0x4d0390b777b424e43839cd1e744799f3de6c176c7e32c1812a41dbd9c19db6a", - value: "8812345773212", - details: { - decimals: "18", - symbol: "ETH", - name: "Ether", - tokenType: "erc20", - usdValue: "0.014761", - tokenURI: "", - }, - }, - { - tokenAddress: - "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", - from: "0x4d0390b777b424e43839cd1e744799f3de6c176c7e32c1812a41dbd9c19db6a", - to: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - value: "14764", - details: { - decimals: "6", - symbol: "USDC", - name: "USD Coin", - tokenType: "erc20", - usdValue: "0.014737", - tokenURI: "", - }, - }, - ], - feeEstimation: { - overallFee: 3744000037440, - gasPrice: 1000000010, - gasUsage: 3744, - unit: "WEI", - maxFee: 6744000037440, - }, - }, - ], } export const jediswapUnsafe: TransactionActionFixture = { diff --git a/packages/extension/src/ui/features/actions/__fixtures__/transfer.ts b/packages/extension/src/ui/features/actions/__fixtures__/transfer.ts index a0781c819..b4b753d14 100644 --- a/packages/extension/src/ui/features/actions/__fixtures__/transfer.ts +++ b/packages/extension/src/ui/features/actions/__fixtures__/transfer.ts @@ -1,7 +1,6 @@ import { TransactionActionFixture } from "./types" export const transfer: TransactionActionFixture = { - actionHash: "abc123", aggregatedData: [ { token: { @@ -16,73 +15,142 @@ export const transfer: TransactionActionFixture = { type: "erc20", }, approvals: [], - amount: BigInt("-4835920881083088"), - usdValue: "0", + amount: BigInt("-1000000000000000"), + usdValue: "3.438859", recipients: [ { address: - "0x5417fc252d9b7b6ea311485a9e946cc814e3aa4d00f740f7e5f6b11ce0db9fa", - amount: BigInt("-4835920881083088"), + "0x624b60bb6e9fa65f5a6879c496d1c6f48e49c53e8bb7ff0218c37988b003673", + amount: BigInt("-1000000000000000"), + usdValue: "3.438859", }, ], safe: true, }, ], transactionReview: { - assessment: "warn", - reviews: [ + transactions: [ { - assessment: "warn", - assessmentDetails: { - contract_address: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + reviewOfTransaction: { + assessment: "neutral", + warnings: [], + reviews: [ + { + assessment: "neutral", + warnings: [], + action: { + name: "ERC20_transfer", + properties: [ + { + type: "amount", + label: "ERC20_transfer_amount", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + amount: "100000000000000", + usd: "0.34", + editable: false, + }, + { + type: "address", + label: "ERC20_transfer_recipient", + address: + "0x00146ab475f565af0277640952c2cf4c9bb05b6932a7bb454b92746bb9715911", + verified: false, + }, + ], + defaultProperties: [ + { + type: "token_address", + label: "default_contract", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + type: "calldata", + label: "default_call", + entrypoint: "transfer", + calldata: [ + "0x00146ab475f565af0277640952c2cf4c9bb05b6932a7bb454b92746bb9715911", + "0x00000000000000000000000000000000000000000000000000005af3107a4000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ], + }, + ], + }, + }, + ], }, - activity: { - value: { - token: { - address: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - name: "Ether", - symbol: "ETH", - decimals: 18, - unknown: false, - type: "ERC20", + simulation: { + approvals: [], + transfers: [ + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + from: "0x325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + to: "0x146ab475f565af0277640952c2cf4c9bb05b6932a7bb454b92746bb9715911", + value: "100000000000000", + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + ], + summary: [ + { + type: "transfer", + label: "simulation_summary_send", + value: "100000000000000", + usdValue: "0.34", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + sent: true, }, - amount: "4835920881083088", - usd: 8, - slippage: "equal", + ], + calculatedNonce: "0x1", + feeEstimation: { + overallFee: 2788000019516, + gasPrice: 1000000007, + gasUsage: 2788, + unit: "WEI", + maxFee: 8363998255470, }, - recipient: - "2377291062867794509008003741341082264125447210642161352160499804006396049914", - type: "transfer", }, - assessmentReason: "contract_is_not_verified", }, ], - reason: "contract_is_not_verified", - targetedDapp: { - name: "JediSwap", - description: - "A community-led fully permissionless and composable AMM on Starknet.", - logoUrl: "https://www.dappland.com/dapps/jediswap/dapp-icon-jediswap.png", - links: [ - { - name: "website", - url: "https://jediswap.xyz", - position: 1, - }, - { - name: "twitter", - url: "https://twitter.com/jediswap", - position: 2, - }, - { - name: "discord", - url: "https://discord.gg/jediswap", - position: 3, - }, - ], - }, }, transactions: [ { @@ -96,33 +164,30 @@ export const transfer: TransactionActionFixture = { entrypoint: "transfer", }, ], - transactionSimulation: [ - { - approvals: [], - transfers: [ - { - tokenAddress: - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - from: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - to: "0x5417fc252d9b7b6ea311485a9e946cc814e3aa4d00f740f7e5f6b11ce0db9fa", - value: "4835920881083088", - details: { - decimals: "18", - symbol: "ETH", - name: "Ether", - tokenType: "erc20", - usdValue: "0.014761", - tokenURI: "", +} + +export const transferWithWarnings: TransactionActionFixture = { + ...transfer, + transactionReview: { + ...transfer.transactionReview, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + transactions: transfer.transactionReview?.transactions.map( + (transaction) => { + return { + ...transaction, + reviewOfTransaction: { + ...transaction.reviewOfTransaction, + assessment: "warn", + warnings: [ + { + reason: "undeployed_account", + severity: "caution", + }, + ], }, - }, - ], - feeEstimation: { - overallFee: 3744000037440, - gasPrice: 1000000010, - gasUsage: 3744, - unit: "WEI", - maxFee: 6744000037440, + } }, - }, - ], + ), + }, } diff --git a/packages/extension/src/ui/features/actions/__fixtures__/transferV3.ts b/packages/extension/src/ui/features/actions/__fixtures__/transferV3.ts index 0d417002f..9f77fa97b 100644 --- a/packages/extension/src/ui/features/actions/__fixtures__/transferV3.ts +++ b/packages/extension/src/ui/features/actions/__fixtures__/transferV3.ts @@ -1,7 +1,6 @@ import { TransactionActionFixture } from "./types" export const transferV3: TransactionActionFixture = { - actionHash: "abc123", aggregatedData: [ { token: { @@ -16,73 +15,142 @@ export const transferV3: TransactionActionFixture = { type: "erc20", }, approvals: [], - amount: BigInt("-4835920881083088"), - usdValue: "0", + amount: BigInt("-1000000000000000"), + usdValue: "3.438859", recipients: [ { address: - "0x5417fc252d9b7b6ea311485a9e946cc814e3aa4d00f740f7e5f6b11ce0db9fa", - amount: BigInt("-4835920881083088"), + "0x624b60bb6e9fa65f5a6879c496d1c6f48e49c53e8bb7ff0218c37988b003673", + amount: BigInt("-1000000000000000"), + usdValue: "3.438859", }, ], safe: true, }, ], transactionReview: { - assessment: "warn", - reviews: [ + transactions: [ { - assessment: "warn", - assessmentDetails: { - contract_address: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + reviewOfTransaction: { + assessment: "neutral", + warnings: [], + reviews: [ + { + assessment: "neutral", + warnings: [], + action: { + name: "ERC20_transfer", + properties: [ + { + type: "amount", + label: "ERC20_transfer_amount", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + amount: "100000000000000", + usd: "0.34", + editable: false, + }, + { + type: "address", + label: "ERC20_transfer_recipient", + address: + "0x00146ab475f565af0277640952c2cf4c9bb05b6932a7bb454b92746bb9715911", + verified: false, + }, + ], + defaultProperties: [ + { + type: "token_address", + label: "default_contract", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + { + type: "calldata", + label: "default_call", + entrypoint: "transfer", + calldata: [ + "0x00146ab475f565af0277640952c2cf4c9bb05b6932a7bb454b92746bb9715911", + "0x00000000000000000000000000000000000000000000000000005af3107a4000", + "0x0000000000000000000000000000000000000000000000000000000000000000", + ], + }, + ], + }, + }, + ], }, - activity: { - value: { - token: { - address: - "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - name: "Ether", - symbol: "ETH", - decimals: 18, - unknown: false, - type: "ERC20", + simulation: { + approvals: [], + transfers: [ + { + tokenAddress: + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + from: "0x325c46cdbf81d35020f95a82a4dc4d043599f58cfb979b03e2efffdeab20477", + to: "0x146ab475f565af0277640952c2cf4c9bb05b6932a7bb454b92746bb9715911", + value: "100000000000000", + details: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + }, + ], + summary: [ + { + type: "transfer", + label: "simulation_summary_send", + value: "100000000000000", + usdValue: "0.34", + token: { + address: + "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + name: "Ether", + symbol: "ETH", + decimals: 18, + unknown: false, + iconUrl: + "https://dv3jj1unlp2jl.cloudfront.net/128/color/eth.png", + type: "ERC20", + }, + sent: true, }, - amount: "4835920881083088", - usd: 8, - slippage: "equal", + ], + calculatedNonce: "0x1", + feeEstimation: { + overallFee: 2788000019516, + gasPrice: 1000000007, + gasUsage: 2788, + unit: "WEI", + maxFee: 8363998255470, }, - recipient: - "2377291062867794509008003741341082264125447210642161352160499804006396049914", - type: "transfer", }, - assessmentReason: "contract_is_not_verified", }, ], - reason: "contract_is_not_verified", - targetedDapp: { - name: "JediSwap", - description: - "A community-led fully permissionless and composable AMM on Starknet.", - logoUrl: "https://www.dappland.com/dapps/jediswap/dapp-icon-jediswap.png", - links: [ - { - name: "website", - url: "https://jediswap.xyz", - position: 1, - }, - { - name: "twitter", - url: "https://twitter.com/jediswap", - position: 2, - }, - { - name: "discord", - url: "https://discord.gg/jediswap", - position: 3, - }, - ], - }, }, transactions: [ { @@ -96,34 +164,4 @@ export const transferV3: TransactionActionFixture = { entrypoint: "transfer", }, ], - transactionSimulation: [ - { - approvals: [], - transfers: [ - { - tokenAddress: - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - from: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - to: "0x5417fc252d9b7b6ea311485a9e946cc814e3aa4d00f740f7e5f6b11ce0db9fa", - value: "4835920881083088", - details: { - decimals: "18", - symbol: "ETH", - name: "Ether", - tokenType: "erc20", - usdValue: "0.014761", - tokenURI: "", - }, - }, - ], - feeEstimation: { - overallFee: 374400003744, - gasPrice: 100000001, - gasUsage: 3744, - unit: "FRI", - maxAmount: 7018, - maxPricePerUnit: 19999989162, - }, - }, - ], } diff --git a/packages/extension/src/ui/features/actions/__fixtures__/types.ts b/packages/extension/src/ui/features/actions/__fixtures__/types.ts index 4e0ad61d6..ca1dd2041 100644 --- a/packages/extension/src/ui/features/actions/__fixtures__/types.ts +++ b/packages/extension/src/ui/features/actions/__fixtures__/types.ts @@ -2,10 +2,8 @@ import { ApproveTransactionScreenProps } from "../transaction/ApproveTransaction export type TransactionActionFixture = Pick< ApproveTransactionScreenProps, - | "actionHash" | "aggregatedData" | "transactionReview" | "transactions" - | "transactionSimulation" | "transactionActionsType" > diff --git a/packages/extension/src/ui/features/actions/connectDapp/ConnectDappScreen.tsx b/packages/extension/src/ui/features/actions/connectDapp/ConnectDappScreen.tsx index 5b53b8498..44be6d2c9 100644 --- a/packages/extension/src/ui/features/actions/connectDapp/ConnectDappScreen.tsx +++ b/packages/extension/src/ui/features/actions/connectDapp/ConnectDappScreen.tsx @@ -1,13 +1,5 @@ -import { H5, H6, KnownDappButton, L2, P4, icons } from "@argent/ui" -import { - Box, - Center, - Flex, - List, - ListIcon, - ListItem, - Text, -} from "@chakra-ui/react" +import { H6, L2, P4, icons } from "@argent/x-ui" +import { Box, Flex, List, ListIcon, ListItem, Text } from "@chakra-ui/react" import { FC, PropsWithChildren, ReactNode } from "react" import { @@ -16,7 +8,6 @@ import { } from "../../../../shared/wallet.model" import { ConfirmScreen } from "../transaction/ApproveTransactionScreen/ConfirmScreen" import { ConnectDappAccountSelect } from "./ConnectDappAccountSelect" -import { DappIcon } from "./DappIcon" import { DappDisplayAttributes } from "./useDappDisplayAttributes" import { DappActionHeader } from "./DappActionHeader" @@ -59,8 +50,6 @@ export const ConnectDappScreen: FC = ({ const confirmButtonText = isConnected ? "Continue" : "Connect" const rejectButtonText = isConnected ? "Disconnect" : "Cancel" - const hostName = new URL(host).hostname - return ( <> = ({ {...rest} > {!dappDisplayAttributes?.iconUrl && ( - + )} ) diff --git a/packages/extension/src/ui/features/actions/connectDapp/KnownDappButtonWrapper.tsx b/packages/extension/src/ui/features/actions/connectDapp/KnownDappButtonWrapper.tsx index 322e6b48f..5558f949f 100644 --- a/packages/extension/src/ui/features/actions/connectDapp/KnownDappButtonWrapper.tsx +++ b/packages/extension/src/ui/features/actions/connectDapp/KnownDappButtonWrapper.tsx @@ -1,4 +1,4 @@ -import { KnownDappButton } from "@argent/ui" +import { KnownDappButton } from "@argent/x-ui" import { useDappDisplayAttributes } from "./useDappDisplayAttributes" export const KnownDappButtonWrapper = ({ dappHost }: { dappHost: string }) => { diff --git a/packages/extension/src/ui/features/actions/connectDapp/useDappDisplayAttributes.ts b/packages/extension/src/ui/features/actions/connectDapp/useDappDisplayAttributes.ts index a62539bca..83467a032 100644 --- a/packages/extension/src/ui/features/actions/connectDapp/useDappDisplayAttributes.ts +++ b/packages/extension/src/ui/features/actions/connectDapp/useDappDisplayAttributes.ts @@ -1,4 +1,4 @@ -import { generateAvatarImage } from "@argent/shared" +import { generateAvatarImage } from "@argent/x-shared" import { getKnownDappForHost } from "../../../../shared/knownDapps" import { getColor } from "../../accounts/accounts.service" import { useDappFromKnownDappsByHost } from "../../../services/knownDapps" diff --git a/packages/extension/src/ui/features/actions/feeEstimation/CombinedFeeEstimation.tsx b/packages/extension/src/ui/features/actions/feeEstimation/CombinedFeeEstimation.tsx index 773cba5a6..99003e5ce 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/CombinedFeeEstimation.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/CombinedFeeEstimation.tsx @@ -1,12 +1,13 @@ -import { TokenWithBalance, bigDecimal } from "@argent/shared" -import { L1, P4, TextWithAmount } from "@argent/ui" -import { Flex } from "@chakra-ui/react" -import { FC, useMemo } from "react" - import { + TokenWithBalance, + bigDecimal, prettifyCurrencyValue, prettifyTokenAmount, -} from "../../../../shared/token/price" +} from "@argent/x-shared" +import { L1, P4, TextWithAmount } from "@argent/x-ui" +import { Flex } from "@chakra-ui/react" +import { FC, useMemo } from "react" + import { ParsedFeeError } from "./feeError" import { FeeEstimationBox } from "./ui/FeeEstimationBox" import { FeeEstimationText } from "./ui/FeeEstimationText" @@ -213,8 +214,8 @@ const TooltipText: FC = ({ } return ( - Insufficient balance to pay network fees. You need at least $ - {bigDecimal.formatEther(BigInt(totalMaxFee) - feeToken.balance)} ETH more. + Insufficient balance to pay network fees. You need to add more funds to be + able to execute the transaction. ) } diff --git a/packages/extension/src/ui/features/actions/feeEstimation/FeeEstimation.tsx b/packages/extension/src/ui/features/actions/feeEstimation/FeeEstimation.tsx index 35211aea7..a72fe6fb3 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/FeeEstimation.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/FeeEstimation.tsx @@ -1,11 +1,8 @@ -import { TextWithAmount } from "@argent/ui" +import { TextWithAmount } from "@argent/x-ui" import { FC, useMemo } from "react" import { isUndefined } from "lodash-es" -import { - prettifyCurrencyValue, - prettifyTokenAmount, -} from "../../../../shared/token/price" +import { prettifyCurrencyValue, prettifyTokenAmount } from "@argent/x-shared" import { FeeEstimationBox, FeeEstimationBoxWithDeploy, diff --git a/packages/extension/src/ui/features/actions/feeEstimation/feeEstimation.model.ts b/packages/extension/src/ui/features/actions/feeEstimation/feeEstimation.model.ts index 306a8d4cb..ca59d2fe6 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/feeEstimation.model.ts +++ b/packages/extension/src/ui/features/actions/feeEstimation/feeEstimation.model.ts @@ -1,4 +1,4 @@ -import { TokenWithBalance } from "@argent/shared" +import { TokenWithBalance } from "@argent/x-shared" import { EstimatedFees } from "../../../../shared/transactionSimulation/fees/fees.model" import { ParsedFeeError } from "./feeError" diff --git a/packages/extension/src/ui/features/actions/feeEstimation/types.ts b/packages/extension/src/ui/features/actions/feeEstimation/types.ts index c0c2672c7..d9b887c24 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/types.ts +++ b/packages/extension/src/ui/features/actions/feeEstimation/types.ts @@ -1,6 +1,6 @@ import { ApiTransactionBulkSimulationResponse } from "../../../../shared/transactionSimulation/types" import { EstimatedFees } from "../../../../shared/transactionSimulation/fees/fees.model" -import { TokenWithBalance, TransactionAction } from "@argent/shared" +import { TokenWithBalance, TransactionAction } from "@argent/x-shared" export interface TransactionsFeeEstimationProps { feeToken: TokenWithBalance transactionAction: TransactionAction diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/CopyErrorIcon.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/CopyErrorIcon.tsx index b38622e94..ed782992d 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/CopyErrorIcon.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/CopyErrorIcon.tsx @@ -1,21 +1,21 @@ -import { CopyTooltip, icons } from "@argent/ui" +import { CopyTooltip, icons } from "@argent/x-ui" import { Box, Fade, useAccordionItemState } from "@chakra-ui/react" import { FC } from "react" -import { FeeEstimationProps } from "../feeEstimation.model" - const { CopyIcon } = icons -export const CopyErrorIcon: FC< - Pick -> = ({ parsedFeeEstimationError }) => { +interface CopyErrorIconProps { + copyValue?: string +} + +export const CopyErrorIcon: FC = ({ copyValue }) => { const { isOpen } = useAccordionItemState() - if (!parsedFeeEstimationError || !isOpen) { + if (!copyValue || !isOpen) { return null } return ( - + { /** prevent accordion from collapsing */ diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationBox.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationBox.tsx index 5f05345fa..cb563553d 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationBox.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationBox.tsx @@ -1,4 +1,4 @@ -import { L2 } from "@argent/ui" +import { L2 } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, PropsWithChildren } from "react" @@ -9,7 +9,8 @@ export const FeeEstimationBox: FC = (props) => { backgroundColor="white" border="1px" borderColor="transparent" - px={3} + pl={3} + pr={2} py={2} _dark={{ backgroundColor: "neutrals.900", @@ -67,7 +68,7 @@ export const FeeEstimationBoxWithInsufficientFunds: FC< flexDir={"column"} _dark={{ backgroundColor: "neutrals.900", - borderColor: "redText", + borderColor: "primary.red.600", boxShadow: "menu", }} > @@ -75,13 +76,13 @@ export const FeeEstimationBoxWithInsufficientFunds: FC< {children} - + {userClickedAddFunds ? "Waiting for funds..." : "Insufficient funds to pay fee"} diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationText.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationText.tsx index c561bd601..d4381b7d2 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationText.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeEstimationText.tsx @@ -1,5 +1,6 @@ -import { B3, L2, P4, icons } from "@argent/ui" +import { B3, L2, P4, icons } from "@argent/x-ui" import { + Center, Flex, Img, Spinner, @@ -80,6 +81,7 @@ export const FeeEstimationText: FC = ({ alignItems="center" cursor={allowFeeTokenSelection ? "pointer" : "default"} onClick={() => allowFeeTokenSelection && onOpenFeeTokenPicker?.()} + role="group" > {primaryText && ( @@ -96,10 +98,26 @@ export const FeeEstimationText: FC = ({ )} {secondaryText && ( - {secondaryText} + + {secondaryText} + )} - {allowFeeTokenSelection && } + {allowFeeTokenSelection && ( +
+ +
+ )} )} diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeTokenPickerModal.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeTokenPickerModal.tsx index a0cded091..13bea41ef 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeTokenPickerModal.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/FeeTokenPickerModal.tsx @@ -7,7 +7,7 @@ import { ModalContent, ModalHeader, } from "@chakra-ui/react" -import { H6 } from "@argent/ui" +import { H6 } from "@argent/x-ui" import { TokenWithBalance } from "../../../../../shared/token/__new/types/tokenBalance.model" import { MinBalances, TokenOptionContainer } from "./TokenOptionContainer" diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/InsufficientFundsAccordion.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/InsufficientFundsAccordion.tsx index 7c215fa8b..4687ee09f 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/InsufficientFundsAccordion.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/InsufficientFundsAccordion.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { Accordion, AccordionButton, diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenOptionContainer.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenOptionContainer.tsx index a361f8dbb..b22c1a5f7 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenOptionContainer.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenOptionContainer.tsx @@ -7,19 +7,17 @@ import { useCurrencyDisplayEnabled, useTokenBalanceToCurrencyValue, } from "../../../accountTokens/tokenPriceHooks" -import { Address, prettifyCurrencyValue } from "@argent/shared" import { - classHashSupportsTxV3, - feeTokenNeedsTxV3Support, -} from "../../../../../shared/network/txv3" + Address, + prettifyCurrencyValue, + prettifyTokenAmount, +} from "@argent/x-shared" +import { feeTokenNeedsTxV3Support } from "../../../../../shared/network/txv3" import { useAccount } from "../../../accounts/accounts.state" import { clientAccountService } from "../../../../services/account" import { AccountError } from "../../../../../shared/errors/account" import { isEmpty } from "lodash-es" -import { prettifyTokenAmount } from "../../../../../shared/token/price" import { useUpgradeAccountTransactions } from "../../../accounts/accountTransactions.state" -import { accountService } from "../../../../../shared/account/service" -import { accountsEqual } from "../../../../../shared/utils/accountsEqual" import { useRequiresTxV3Upgrade } from "../useRequiresTxV3Upgrade" function toTokenView(token: TokenWithBalance): { diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPicker.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPicker.tsx index b81c14d3b..ef55f8c89 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPicker.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPicker.tsx @@ -1,5 +1,5 @@ -import { Token } from "@argent/shared" -import { icons } from "@argent/ui" +import { Token } from "@argent/x-shared" +import { icons } from "@argent/x-ui" import { Flex, Img } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPickerScreen.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPickerScreen.tsx index d8a991ee1..23c4d79c2 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPickerScreen.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/TokenPickerScreen.tsx @@ -1,5 +1,5 @@ -import { TokenWithBalance } from "@argent/shared" -import { NavigationContainer } from "@argent/ui" +import { TokenWithBalance } from "@argent/x-shared" +import { NavigationContainer } from "@argent/x-ui" import { FC, ReactNode } from "react" import { PageWrapper } from "../../../../components/Page" import { Grid } from "@chakra-ui/react" diff --git a/packages/extension/src/ui/features/actions/feeEstimation/ui/TransactionFailureAccordion.tsx b/packages/extension/src/ui/features/actions/feeEstimation/ui/TransactionFailureAccordion.tsx index 9d3367a83..e683fe7da 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/ui/TransactionFailureAccordion.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/ui/TransactionFailureAccordion.tsx @@ -1,4 +1,4 @@ -import { AccordionIcon, P4, icons } from "@argent/ui" +import { AccordionIcon, P4, icons } from "@argent/x-ui" import { Accordion, AccordionButton, @@ -37,9 +37,7 @@ export const TransactionFailureAccordion: FC< {title || "Transaction failure predicted"} - + @@ -49,7 +47,7 @@ export const TransactionFailureAccordion: FC< overflow: "auto", }} > - + {message} diff --git a/packages/extension/src/ui/features/actions/feeEstimation/useEstimatedFees.ts b/packages/extension/src/ui/features/actions/feeEstimation/useEstimatedFees.ts index 79fdd4229..631d6dd71 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/useEstimatedFees.ts +++ b/packages/extension/src/ui/features/actions/feeEstimation/useEstimatedFees.ts @@ -1,4 +1,4 @@ -import { TransactionAction } from "@argent/shared" +import { TransactionAction } from "@argent/x-shared" import { estimatedFeesAtom } from "../../../views/estimatedFees" import { useView } from "../../../views/implementation/react" diff --git a/packages/extension/src/ui/features/actions/feeEstimation/useRequiresTxV3Upgrade.ts b/packages/extension/src/ui/features/actions/feeEstimation/useRequiresTxV3Upgrade.ts index 5b43247e1..27dadaadc 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/useRequiresTxV3Upgrade.ts +++ b/packages/extension/src/ui/features/actions/feeEstimation/useRequiresTxV3Upgrade.ts @@ -7,18 +7,20 @@ import { feeTokenNeedsTxV3Support, } from "../../../../shared/network/txv3" import { Token } from "../../../../shared/token/__new/types/token.model" -import { getAccountIdentifier } from "@argent/shared" +import { getAccountIdentifier } from "@argent/x-shared" export function useRequiresTxV3Upgrade( account: Account | undefined, token: Token, ) { return useSWR( - [ - "requiresTxV3Upgrade", - getAccountIdentifier(account), - getAccountIdentifier(token), - ], + account + ? [ + "requiresTxV3Upgrade", + getAccountIdentifier(account), + getAccountIdentifier(token), + ] + : null, async () => { const [selectedAccount] = await accountService.get((acc) => accountsEqual(acc, account), diff --git a/packages/extension/src/ui/features/actions/feeEstimation/utils.tsx b/packages/extension/src/ui/features/actions/feeEstimation/utils.tsx index 6a32a70f7..93c8ad73d 100644 --- a/packages/extension/src/ui/features/actions/feeEstimation/utils.tsx +++ b/packages/extension/src/ui/features/actions/feeEstimation/utils.tsx @@ -3,7 +3,7 @@ import { TransactionAction, bigDecimal, useConditionallyEnabledSWR, -} from "@argent/shared" +} from "@argent/x-shared" import { TransactionType, UniversalDeployerContractPayload } from "starknet" import useSWR from "swr" @@ -22,6 +22,7 @@ import { } from "../../../../shared/transactionSimulation/fees/fees.model" import { ApiTransactionBulkSimulationResponse } from "../../../../shared/transactionSimulation/types" import { RefreshInterval } from "../../../../shared/config" +import { isString } from "lodash-es" interface UseMaxFeeEstimationReturnProps { fee: EstimatedFees | undefined @@ -169,9 +170,7 @@ export function getCombinedFeeTooltipText( } return { status: "error", - message: `Insufficient balance to pay network fees. You need at least ${bigDecimal.formatEther( - maxFee - feeTokenBalance, - )} ETH more.`, + message: `Insufficient balance to pay network fees. You need to add more funds to be able to execute the transaction.`, } } @@ -179,10 +178,12 @@ export function getTooltipText(maxFee?: bigint, feeTokenBalance?: bigint) { if (!maxFee || !feeTokenBalance) { return "Network fee is still loading." } + if (isString(feeTokenBalance)) { + // FIXME: this is string '0' if the fee token is not deployed? + feeTokenBalance = BigInt(feeTokenBalance) + } if (feeTokenBalance >= maxFee) { return "Network fees are paid to the network to include transactions in blocks" } - return `Insufficient balance to pay network fees. You need at least ${bigDecimal.formatEther( - maxFee - feeTokenBalance, - )} ETH more.` + return `Insufficient balance to pay network fees. You need to add more funds to be able to execute the transaction.` } diff --git a/packages/extension/src/ui/features/actions/hooks/useActionScreen.ts b/packages/extension/src/ui/features/actions/hooks/useActionScreen.ts index b8ec647b1..f14836224 100644 --- a/packages/extension/src/ui/features/actions/hooks/useActionScreen.ts +++ b/packages/extension/src/ui/features/actions/hooks/useActionScreen.ts @@ -3,12 +3,10 @@ import { useCallback, useEffect } from "react" import { uiService } from "../../../../shared/__new/services/ui" import { clientActionService } from "../../../services/action" -import { analytics } from "../../../services/analytics" import { selectedAccountView } from "../../../views/account" import { currentActionView, isLastActionView } from "../../../views/actions" import { useView } from "../../../views/implementation/react" import { focusExtensionTab, useExtensionIsInTab } from "../../browser/tabs" -import { getOriginatingHost } from "../../browser/useOriginatingHost" export const useActionScreen = () => { const selectedAccount = useView(selectedAccountView) @@ -40,13 +38,8 @@ export const useActionScreen = () => { }, [closePopupIfLastAction, approve]) const reject = useCallback(async () => { - /** TODO: refactor: move tracking into service or action handler */ - void analytics.track("rejectedTransaction", { - networkId: selectedAccount?.networkId || "unknown", - host: await getOriginatingHost(), - }) action && void clientActionService.reject(action.meta.hash) - }, [action, selectedAccount?.networkId]) + }, [action]) const rejectAndClose = useCallback(async () => { await reject() diff --git a/packages/extension/src/ui/features/actions/hooks/usePortfolioUrl.ts b/packages/extension/src/ui/features/actions/hooks/usePortfolioUrl.ts new file mode 100644 index 000000000..01f8cb99a --- /dev/null +++ b/packages/extension/src/ui/features/actions/hooks/usePortfolioUrl.ts @@ -0,0 +1,31 @@ +import { + ARGENT_PORTFOLIO_GOERLI_BASE_URL, + ARGENT_PORTFOLIO_MAINNET_BASE_URL, +} from "../../../../shared/api/constants" +import { Account } from "../../accounts/Account" +import { useIsDefaultNetwork } from "../../networks/hooks/useIsDefaultNetwork" + +export const usePortfolioUrl = (account: Account) => { + const isDefaultNetwork = useIsDefaultNetwork() + + if (!isDefaultNetwork) { + return null + } + + let portfolioBaseUrl: string | null + switch (account.networkId) { + case "mainnet-alpha": + portfolioBaseUrl = ARGENT_PORTFOLIO_MAINNET_BASE_URL + break + case "goerli-alpha": + portfolioBaseUrl = ARGENT_PORTFOLIO_GOERLI_BASE_URL + break + default: + portfolioBaseUrl = null + } + + const portfolioUrl = portfolioBaseUrl + ? `${portfolioBaseUrl}/${account.address}` + : null + return portfolioUrl +} diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/AccountNetworkInfoArgentX.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/AccountNetworkInfoArgentX.tsx index 17c2ecec4..20562eea7 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/AccountNetworkInfoArgentX.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/AccountNetworkInfoArgentX.tsx @@ -1,9 +1,9 @@ -import { P4, typographyStyles } from "@argent/ui" +import { P4, typographyStyles } from "@argent/x-ui" import { Flex, VStack } from "@chakra-ui/react" import { WalletAccount } from "../../../../../shared/wallet.model" import { PrettyAccountAddressArgentX } from "../../../accounts/PrettyAccountAddressArgentX" -import { formatTruncatedAddress } from "@argent/shared" +import { formatTruncatedAddress } from "@argent/x-shared" interface AccountNetworkInfoArgentXProps { account: WalletAccount diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ActionScreenErrorFooter.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ActionScreenErrorFooter.tsx new file mode 100644 index 000000000..dad5bfbc6 --- /dev/null +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ActionScreenErrorFooter.tsx @@ -0,0 +1,61 @@ +import { icons } from "@argent/x-ui" +import { + Accordion, + AccordionButton, + AccordionIcon, + AccordionItem, + AccordionPanel, + AccordionProps, + Flex, +} from "@chakra-ui/react" +import { FC, ReactNode } from "react" +import { CopyErrorIcon } from "../../feeEstimation/ui/CopyErrorIcon" + +const { AlertIcon } = icons + +interface ActionScreenErrorFooterProps extends Omit { + errorMessage?: string + title: ReactNode +} + +export const ActionScreenErrorFooter: FC = ({ + errorMessage = "Unknown error", + title, + ...rest +}) => { + const parsedFeeEstimationError = { title, message: errorMessage } + return ( + + + + + + {title} + + + + + + + + {errorMessage} + + + + ) +} diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.test.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.test.tsx index 04a8cff52..09c5c2722 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.test.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.test.tsx @@ -11,25 +11,23 @@ import { jediswapUnsafe, transfer, transferV3, + transferWithWarnings, } from "../../__fixtures__" import { TransactionActionFixture } from "../../__fixtures__/types" import { ApproveScreenType } from "../types" import { ApproveTransactionScreen } from "./ApproveTransactionScreen" -import { getDisplayWarnAndReasonForTransactionReview } from "../../../../../shared/transactionReview.service" import { ApproveTransactionScreenProps } from "./approveTransactionScreen.model" import { TransactionType } from "starknet" +import userEvent from "@testing-library/user-event" const renderWithProps = async ( props: TransactionActionFixture & Pick, ) => { - const assessment = getDisplayWarnAndReasonForTransactionReview( - props.transactionReview, - ) - await act(async () => { renderWithLegacyProviders( undefined, @@ -39,15 +37,13 @@ const renderWithProps = async ( getButtonProps: () => undefined, getDisclosureProps: () => undefined, }} - showFraudMonitorBanner={true} multisigBannerProps={{ account: accounts[0], confirmations: 0, onClick: noop, }} + showTransactionActions={false} hasBalanceChange={true} - showTransactionActions={true} - assessmentReason={assessment.reason} disableConfirm={false} isMainnet isSimulationLoading={false} @@ -71,7 +67,6 @@ describe("ApproveTransactionScreen", () => { it("should render jediswap scenario as expected", async () => { const onReject = vi.fn() const onSubmit = vi.fn() - await renderWithProps({ ...jediswap, transactionActionsType: { @@ -81,29 +76,21 @@ describe("ApproveTransactionScreen", () => { onReject, onSubmit, }) - - expect(screen.getByText(/Confirm transactions/)).toBeInTheDocument() + expect(screen.getByText(/Confirm/)).toBeInTheDocument() expect(screen.getByText(/https:\/\/jediswap.xyz/)).toBeInTheDocument() - expect(screen.getByText(/Estimated balance change/)).toBeInTheDocument() expect(screen.getByText(/USD Coin/)).toBeInTheDocument() expect(screen.getByText(/\+0.0148 USDC/)).toBeInTheDocument() - expect(screen.getByText(/Swap exact tokens for tokens/)).toBeInTheDocument() - fireEvent.click(screen.getByText("Cancel")) expect(onReject).toHaveBeenCalled() - fireEvent.click(screen.getByText("Confirm")) expect(onSubmit).toHaveBeenCalled() }) - it("should render jediswapUnsafe scenario as expected", async () => { window.scrollTo = vi.fn(noop) - const onReject = vi.fn() const onSubmit = vi.fn() - await renderWithProps({ ...jediswapUnsafe, transactionActionsType: { @@ -113,7 +100,6 @@ describe("ApproveTransactionScreen", () => { onReject, onSubmit, }) - expect( screen.getByText(/Warning: Approved spending limit/), ).toBeInTheDocument() @@ -123,53 +109,42 @@ describe("ApproveTransactionScreen", () => { ), ).toBeInTheDocument() }) - it("should render transfer scenario as expected", async () => { window.scrollTo = vi.fn(noop) - const onReject = vi.fn() const onSubmit = vi.fn() - await renderWithProps({ ...transfer, transactionActionsType: { type: "INVOKE_FUNCTION", - payload: jediswap.transactions, + payload: transfer.transactions, }, onReject, onSubmit, }) + expect(screen.getByText(/Balance change/)).toBeInTheDocument() - expect( - screen.getByText(/This transaction has been flagged as dangerous/), - ).toBeInTheDocument() + expect(screen.getByText("-0.001 ETH")).toBeInTheDocument() }) - it("should render transfer v3 scenario as expected", async () => { window.scrollTo = vi.fn(noop) - const onReject = vi.fn() const onSubmit = vi.fn() - await renderWithProps({ ...transferV3, transactionActionsType: { type: "INVOKE_FUNCTION", - payload: jediswap.transactions, + payload: transferV3.transactions, }, onReject, onSubmit, }) - - expect( - screen.getByText(/This transaction has been flagged as dangerous/), - ).toBeInTheDocument() + expect(screen.getByText(/Balance change/)).toBeInTheDocument() + expect(screen.getByText("-0.001 ETH")).toBeInTheDocument() }) - it("should render aspect scenario as expected", async () => { const onReject = vi.fn() const onSubmit = vi.fn() - await renderWithProps({ ...aspect, transactionActionsType: { @@ -179,9 +154,40 @@ describe("ApproveTransactionScreen", () => { onReject, onSubmit, }) - expect(screen.getByText(/Unknown NFT/)).toBeInTheDocument() - expect(screen.getByText(/\+1 NFT/)).toBeInTheDocument() }) + it("should render warning for transfer", async () => { + window.scrollTo = vi.fn(noop) + const onReject = vi.fn() + const onSubmit = vi.fn() + await renderWithProps({ + ...transferWithWarnings, + transactionActionsType: { + type: "INVOKE_FUNCTION", + payload: transferWithWarnings.transactions, + }, + onReject, + onSubmit, + }) + expect(screen.getByText(/Caution/)).toBeInTheDocument() + expect( + screen.getByText(/Sending to the correct account?/), + ).toBeInTheDocument() + + expect(screen.getByRole("button", { name: "Review" })).toBeInTheDocument() + + const actionsAccordion = screen.getByTestId( + "transaction-review-action-ERC20_transfer", + ) + expect(actionsAccordion).toBeInTheDocument() + + await userEvent.click(actionsAccordion) + + expect(screen.getByText("Erc 20 transfer amount")).toBeInTheDocument() + expect(screen.getByText("0.0001 ETH")).toBeInTheDocument() + + expect(screen.getByText("Erc 20 transfer recipient")).toBeInTheDocument() + expect(screen.getAllByText(/0x0014…5911/)).toHaveLength(2) + }) }) diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.tsx index ee0489eb3..4e1987a10 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ApproveTransactionScreen.tsx @@ -1,25 +1,32 @@ -import { P4 } from "@argent/ui" -import { WarningIcon } from "@chakra-ui/icons" -import { Center, Collapse } from "@chakra-ui/react" -import { FC, Suspense } from "react" +import { FC, Suspense, useEffect, useMemo, useState } from "react" +import { normalizeAddress } from "@argent/x-shared" +import { isEmpty } from "lodash-es" +import { z } from "zod" +import { getTransactionActionByType } from "../../../../../shared/transactionReview.service" +import { + Property, + ReviewOfTransaction, + warningSchema, +} from "../../../../../shared/transactionReview/schema" import { MultisigPendingTxModal } from "../../../multisig/MultisigPendingTxModal" +import { TransactionReviewActions } from "../../transactionV2/action/TransactionReviewActions" +import { WarningBanner } from "../../warning/WarningBanner" import { AccountNetworkInfoArgentX } from "./AccountNetworkInfoArgentX" import { BalanceChangeOverviewArgentX } from "./BalanceChangeOverviewArgentX" import { ConfirmScreen } from "./ConfirmScreen" import { DappHeaderArgentX } from "./DappHeader/DappHeaderArgentX" import { MultisigBanner } from "./MultisigBanner" import { SimulationLoadingBanner } from "./SimulationLoadingBanner" -import { TransactionActions } from "./TransactionActions" -import { TransactionBanner } from "./TransactionBanner" import { ApproveTransactionScreenProps } from "./approveTransactionScreen.model" -import { normalizeAddress } from "@argent/shared" +import { getHighestSeverity } from "../../warning/helper" +import { Center, Collapse } from "@chakra-ui/react" +import { TransactionActions } from "./TransactionActions" +import { P4 } from "@argent/x-ui" export const ApproveTransactionScreen: FC = ({ - actionHash, actionIsApproving, aggregatedData, - declareOrDeployType, disableConfirm, isMainnet, isSimulationLoading, @@ -28,16 +35,13 @@ export const ApproveTransactionScreen: FC = ({ multisig, transactionReview, transactions, - transactionSimulation, approveScreenType, hasPendingMultisigTransactions, onReject, multisigModalDisclosure, - showFraudMonitorBanner, hasBalanceChange, showTransactionActions, transactionActionsType, - assessmentReason, showTxDetails, setShowTxDetails, confirmButtonText = "Confirm", @@ -46,8 +50,99 @@ export const ApproveTransactionScreen: FC = ({ transactionAction, ...rest }) => { - const showTxActions = - !isSimulationLoading && showTransactionActions && transactionActionsType + const [hasAcceptedRisk, setHasAcceptedRisk] = useState(false) + const [isHighRisk, setIsHighRisk] = useState(false) + + const reviewOfTransaction: ReviewOfTransaction = useMemo(() => { + if (transactionReview) { + return transactionReview.transactions[0].reviewOfTransaction + } + }, [transactionReview]) + + const recipientAddress = useMemo(() => { + const action = getTransactionActionByType( + "ERC20_transfer", + reviewOfTransaction, + ) + if (action) { + const recipientProperty = [ + ...action.properties, + ...(action.defaultProperties || []), + ].find((p) => p.type === "address") + if (recipientProperty) { + const recipient = recipientProperty as Extract< + Property, + { type: "address" } + > + return normalizeAddress(recipient.address) + } + } + + return undefined + }, [reviewOfTransaction]) + + const transactionReviewActions = useMemo(() => { + return transactionReview?.transactions.map((transaction, index) => { + return ( + + ) + }) + }, [transactionReview]) + + const warnings = useMemo( + () => + transactionReview?.transactions.flatMap((transaction) => { + return transaction.reviewOfTransaction?.warnings + }), + [transactionReview], + ) + + const warningsWithoutUndefined = useMemo( + () => + z + .array(warningSchema) + .safeParse( + warnings?.filter( + (warning) => !isEmpty(warning) && warning !== undefined, + ), + ), + [warnings], + ) + + const highestSeverityWarning = useMemo( + () => + warningsWithoutUndefined.success && + getHighestSeverity(warningsWithoutUndefined.data), + [warningsWithoutUndefined], + ) + + useEffect(() => { + if ( + highestSeverityWarning && + (highestSeverityWarning.severity === "critical" || + highestSeverityWarning.severity === "high") + ) { + setIsHighRisk(true) + } + }, [highestSeverityWarning]) + + const transactionReviewWarnings = useMemo(() => { + if (!warningsWithoutUndefined.success) { + return null + } + return ( + onReject && void onReject()} + onConfirm={() => setHasAcceptedRisk(true)} + /> + ) + }, [warningsWithoutUndefined, onReject]) + return ( = ({ confirmButtonIsLoading={actionIsApproving} confirmButtonLoadingText={confirmButtonText} rejectButtonText="Cancel" - confirmButtonDisabled={disableConfirm} + confirmButtonDisabled={ + disableConfirm || (isHighRisk && !hasAcceptedRisk) + } selectedAccount={selectedAccount} onSubmit={() => { if (hasPendingMultisigTransactions) { @@ -71,44 +168,32 @@ export const ApproveTransactionScreen: FC = ({ {/** Use Transaction Review to get DappHeader */} - {showFraudMonitorBanner && ( - - )} - {multisig && } - + {transactionReviewWarnings} {hasBalanceChange ? ( ) : ( isSimulationLoading && )} - - - {showTxActions && ( + + {transactionActionsType && ( )} - + {transactionReviewActions} {multisig && multisigModalDisclosure.isOpen && ( = ({ noOfOwners={multisig.threshold} /> )} - - {hasBalanceChange && ( + {hasBalanceChange && !transactionReview && (
{ @@ -154,6 +144,13 @@ export const ApproveTransactionScreenContainer: FC< [transactionAction.payload, transactionAction.type], ) + const { data: transactionReview } = useTransactionReviewV2({ + calls: transactionsArray, + actionHash, + feeTokenAddress: feeToken.address, + selectedAccount, + }) + const txnHasTransfers = useMemo( () => ensureArray(transactionSimulation).some((txn) => !isEmpty(txn.transfers)), @@ -173,45 +170,17 @@ export const ApproveTransactionScreenContainer: FC< [approveScreenType], ) - const isChangeGuardianTx = useMemo( - () => - approveScreenType === ApproveScreenType.ADD_ARGENT_SHIELD || - approveScreenType === ApproveScreenType.REMOVE_ARGENT_SHIELD, - [approveScreenType], - ) - const transactionActionsType: TransactionActionsType | undefined = useMemo(() => { if (!selectedAccount) { return } - if (approveScreenType === ApproveScreenType.ADD_ARGENT_SHIELD) { - return { - type: "ADD_ARGENT_SHIELD", - payload: { - accountAddress: selectedAccount.address, - }, - } - } - - if (approveScreenType === ApproveScreenType.REMOVE_ARGENT_SHIELD) { - return { - type: "REMOVE_ARGENT_SHIELD", - payload: { - accountAddress: selectedAccount.address, - }, - } - } - return { type: "INVOKE_FUNCTION", payload: transactionsArray, } - }, [approveScreenType, selectedAccount, transactionsArray]) - - const { warn, reason } = - getDisplayWarnAndReasonForTransactionReview(transactionReview) + }, [selectedAccount, transactionsArray]) // Show balance change if there is a transaction simulation and there are approvals or transfers const hasBalanceChange = Boolean( @@ -226,8 +195,6 @@ export const ApproveTransactionScreenContainer: FC< [hasBalanceChange, isUdcAction, showTxDetails], ) - const showFraudMonitorBanner = Boolean(warn && !isChangeGuardianTx) - // Disable fee token selection if the transaction is a Cairo0 declare transaction const declareSupportTokenSelection = useMemo( () => @@ -274,7 +241,6 @@ export const ApproveTransactionScreenContainer: FC< transactionReview={transactionReview} transactions={transactionsArray} transactionAction={transactionAction} - transactionSimulation={transactionSimulation} hasPendingMultisigTransactions={hasPendingMultisigTransactions} multisig={multisig} multisigModalDisclosure={ @@ -285,12 +251,10 @@ export const ApproveTransactionScreenContainer: FC< onConfirmAnyway={onConfirmAnyway} approveScreenType={approveScreenType} hasBalanceChange={hasBalanceChange} - showFraudMonitorBanner={showFraudMonitorBanner} showTransactionActions={showTransactionActions} transactionActionsType={transactionActionsType} showTxDetails={showTxDetails} setShowTxDetails={setShowTxDetails} - assessmentReason={reason} multisigBannerProps={bannerProps} confirmButtonText={ hasInsufficientFunds && !userClickedAddFunds ? "Add funds" : "Confirm" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/BalanceChangeOverviewArgentX.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/BalanceChangeOverviewArgentX.tsx index bfea8a8ed..7eaeba34a 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/BalanceChangeOverviewArgentX.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/BalanceChangeOverviewArgentX.tsx @@ -10,7 +10,7 @@ import { P4, TextWithAmount, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Box, Divider, Flex, Image, Text, Tooltip } from "@chakra-ui/react" import { motion } from "framer-motion" import { isEmpty, isString } from "lodash-es" @@ -19,45 +19,37 @@ import { FC, useMemo } from "react" import { bigDecimal, formatTruncatedAddress, - normalizeAddress, -} from "@argent/shared" -import { isUnlimitedAmount, + normalizeAddress, prettifyCurrencyValue, prettifyTokenAmount, -} from "../../../../../shared/token/price" -import { - ApiTransactionReviewResponse, - getTransactionReviewWithType, -} from "../../../../../shared/transactionReview.service" +} from "@argent/x-shared" +import { transactionReviewHasTransfer } from "../../../../../shared/transactionReview.service" +import { ReviewOfTransaction } from "../../../../../shared/transactionReview/schema" import { useCurrentNetwork } from "../../../networks/hooks/useCurrentNetwork" import { useIsDefaultNetwork } from "../../../networks/hooks/useIsDefaultNetwork" +import { AggregatedSimData } from "../useTransactionSimulatedData" import { UnknownTokenIcon } from "./DappHeader/TransactionIcon/UnknownTokenIcon" import { NftDetailsArgentXContainer } from "./NftDetailsArgentXContainer" -import { AggregatedSimData } from "../useTransactionSimulatedData" const { InfoIcon, AlertIcon } = icons interface BalanceChangeOverviewArgentXProps { aggregatedData: AggregatedSimData[] - transactionReview?: ApiTransactionReviewResponse + transactionReview?: ReviewOfTransaction } export const BalanceChangeOverviewArgentX: FC< BalanceChangeOverviewArgentXProps > = ({ aggregatedData, transactionReview }) => { const network = useCurrentNetwork() - const transactionReviewWithType = useMemo( - () => getTransactionReviewWithType(transactionReview), - [transactionReview], - ) const allTransferSafe = useMemo( () => aggregatedData.every((t) => t.safe), [aggregatedData], ) const isDefaultNetwork = useIsDefaultNetwork() - const isTransfer = transactionReviewWithType?.type === "transfer" + const isTransfer = transactionReviewHasTransfer(transactionReview) if (aggregatedData.length === 0) { return null diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ConfirmScreen.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ConfirmScreen.tsx index f16b9dbb0..b41ae70e0 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ConfirmScreen.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/ConfirmScreen.tsx @@ -5,8 +5,7 @@ import { ScrollContainer, StickyGroup, useNavigateBack, - icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Box, Flex } from "@chakra-ui/react" import { FC, @@ -19,9 +18,7 @@ import { import Measure, { ContentRect } from "react-measure" import { WalletAccount } from "../../../../../shared/wallet.model" -import { formatTruncatedAddress } from "@argent/shared" - -const { AlertFillIcon } = icons +import { formatTruncatedAddress } from "@argent/x-shared" export interface ConfirmPageProps { onSubmit?: (e: FormEvent) => void diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/DappHeaderArgentX.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/DappHeaderArgentX.tsx index 01007f526..97164ab36 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/DappHeaderArgentX.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/DappHeaderArgentX.tsx @@ -1,18 +1,18 @@ -import { H5, P4 } from "@argent/ui" +import { H5, P4 } from "@argent/x-ui" import { Box, Flex } from "@chakra-ui/react" import { FC, useMemo } from "react" import { Call } from "starknet" -import { ApiTransactionReviewResponse } from "../../../../../../shared/transactionReview.service" +import { ReviewOfTransaction } from "../../../../../../shared/transactionReview/schema" +import { KnownDappButtonWrapper } from "../../../connectDapp/KnownDappButtonWrapper" import { ApproveScreenType } from "../../types" import { AggregatedSimData } from "../../useTransactionSimulatedData" import { TransactionIcon } from "./TransactionIcon" import { TransactionTitleArgentX } from "./TransactionTitleArgentX" -import { KnownDappButtonWrapper } from "../../../connectDapp/KnownDappButtonWrapper" export interface DappHeaderArgentXProps { transactions?: Call[] - transactionReview?: ApiTransactionReviewResponse + transactionReview?: ReviewOfTransaction aggregatedData?: AggregatedSimData[] approveScreenType: ApproveScreenType } diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateAccountIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateAccountIcon.tsx index c9e11cf1b..440814189 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateAccountIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateAccountIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateMultisigIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateMultisigIcon.tsx index da087187f..1e17497cc 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateMultisigIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ActivateMultisigIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddArgentShieldIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddArgentShieldIcon.tsx index 70cde3d74..290663275 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddArgentShieldIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddArgentShieldIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddOwnerIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddOwnerIcon.tsx index 057f505e1..c5d5b58db 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddOwnerIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/AddOwnerIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/DeclareTransactionIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/DeclareTransactionIcon.tsx index 2fa930a00..4b81aafee 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/DeclareTransactionIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/DeclareTransactionIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveArgentShieldIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveArgentShieldIcon.tsx index 6aa0d0e3a..df6bf7f3a 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveArgentShieldIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveArgentShieldIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveOwnerIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveOwnerIcon.tsx index 4cb42e15c..da09d67a0 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveOwnerIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/RemoveOwnerIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ReplaceOwnerIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ReplaceOwnerIcon.tsx index 34977dce5..649cc3fe6 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ReplaceOwnerIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/ReplaceOwnerIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SendTransactionIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SendTransactionIcon.tsx index 590934a20..5c1662e3a 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SendTransactionIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SendTransactionIcon.tsx @@ -1,22 +1,28 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { Box, Center, Image } from "@chakra-ui/react" +import { AggregatedSimData } from "@argent/x-shared" +import { useMemo } from "react" import { Network } from "../../../../../../../shared/network" -import { TransactionReviewWithType } from "../../../../../../../shared/transactionReview.service" import { useToken } from "../../../../../accountTokens/tokens.state" import { UnknownTokenIcon } from "./UnknownTokenIcon" const { SendIcon } = icons export const SendTransactionIcon = ({ - transaction, + aggregatedData, network, }: { - transaction: TransactionReviewWithType + aggregatedData?: AggregatedSimData[] network: Network }) => { + const srcAddress = useMemo( + () => aggregatedData?.find((ag) => ag.recipients.length > 0)?.token.address, + [aggregatedData], + ) + const srcToken = useToken({ - address: transaction?.activity?.value?.token.address || "0x0", + address: srcAddress || "0x0", networkId: network.id, }) return ( diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SwapTransactionIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SwapTransactionIcon.tsx index 8bff33987..a77ad65da 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SwapTransactionIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/SwapTransactionIcon.tsx @@ -1,24 +1,36 @@ import { Box, Center, Image, SystemStyleObject } from "@chakra-ui/react" +import { AggregatedSimData } from "@argent/x-shared" +import { isEmpty } from "lodash-es" +import { useMemo } from "react" import { Network } from "../../../../../../../shared/network" -import { ApiTransactionReview } from "../../../../../../../shared/transactionReview.service" import { useToken } from "../../../../../accountTokens/tokens.state" import { UnknownTokenIcon } from "./UnknownTokenIcon" export const SwapTransactionIcon = ({ - transaction, + aggregatedData, network, }: { - transaction: ApiTransactionReview + aggregatedData?: AggregatedSimData[] network: Network }) => { + const srcAddress = useMemo( + () => aggregatedData?.find((ag) => ag.recipients.length > 0)?.token.address, + [aggregatedData], + ) + + const dstAddress = useMemo( + () => aggregatedData?.find((ag) => isEmpty(ag.recipients))?.token.address, + [aggregatedData], + ) + const srcToken = useToken({ - address: transaction.activity?.src?.token.address || "0x0", + address: srcAddress || "0x0", networkId: network.id, }) const dstToken = useToken({ - address: transaction.activity?.dst?.token.address || "0x0", + address: dstAddress || "0x0", networkId: network.id, }) const token1Styling: SystemStyleObject = { diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownDappIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownDappIcon.tsx index 2158c0ec8..97c85586c 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownDappIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownDappIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownTokenIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownTokenIcon.tsx index 2a48c932d..c7f7fe1b2 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownTokenIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UnknownTokenIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { BoxProps, Center } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UpdateThresholdIcon.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UpdateThresholdIcon.tsx index 013cfa458..76bcb99e1 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UpdateThresholdIcon.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/UpdateThresholdIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { IconWrapper } from "./IconWrapper" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.test.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.test.tsx index faa1a4f05..d229910a2 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.test.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.test.tsx @@ -45,12 +45,18 @@ describe("TransactionIcon", () => { it("should render SendTransactionIcon if type is apiTransactionReviewActivityType.transfer", async () => { vi.spyOn( transactionReviewService, - "getTransactionReviewWithType", + "transactionReviewHasTransfer", ).mockImplementation(() => - vi.fn(() => { - return { - type: "transfer", - } as transactionReviewService.TransactionReviewWithType + vi.fn((): boolean => { + return true + })(), + ) + vi.spyOn( + transactionReviewService, + "transactionReviewHasSwap", + ).mockImplementation(() => + vi.fn((): boolean => { + return false })(), ) const props: TransactionIconProps = { @@ -68,10 +74,19 @@ describe("TransactionIcon", () => { vi.spyOn( transactionReviewService, - "getTransactionReviewSwap", + "transactionReviewHasTransfer", + ).mockImplementation(() => + vi.fn((): boolean => { + return false + })(), + ) + + vi.spyOn( + transactionReviewService, + "transactionReviewHasSwap", ).mockImplementation(() => - vi.fn(() => { - return mockSwapTransactionReview as transactionReviewService.ApiTransactionReview + vi.fn((): boolean => { + return true })(), ) diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.tsx index 63d63c9b0..6e69c8fc2 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionIcon/index.tsx @@ -1,15 +1,14 @@ -import { useERC721Transactions } from "@argent/shared" +import { useERC721Transactions } from "@argent/x-shared" import { FC } from "react" import { - ApiTransactionReviewResponse, ApiTransactionReviewTargettedDapp, - getTransactionReviewSwap, - getTransactionReviewWithType, + transactionReviewHasSwap, + transactionReviewHasTransfer, } from "../../../../../../../shared/transactionReview.service" import { useCurrentNetwork } from "../../../../../networks/hooks/useCurrentNetwork" import { ApproveScreenType } from "../../../types" -import { AggregatedSimData } from "@argent/shared" +import { AggregatedSimData } from "@argent/x-shared" import { ActivateAccountIcon } from "./ActivateAccountIcon" import { ActivateMultisigIcon } from "./ActivateMultisigIcon" import { AddArgentShieldIcon } from "./AddArgentShieldIcon" @@ -24,9 +23,10 @@ import { UnknownDappIcon } from "./UnknownDappIcon" import { UpdateThresholdIcon } from "./UpdateThresholdIcon" import { VerifiedDappIcon } from "./VerifiedDappIcon" import { ReplaceOwnerIcon } from "./ReplaceOwnerIcon" +import { ReviewOfTransaction } from "../../../../../../../shared/transactionReview/schema" export interface TransactionIconProps { - transactionReview?: ApiTransactionReviewResponse + transactionReview?: ReviewOfTransaction aggregatedData?: AggregatedSimData[] verifiedDapp?: ApiTransactionReviewTargettedDapp approveScreenType: ApproveScreenType @@ -41,9 +41,8 @@ export const TransactionIcon: FC = ({ const network = useCurrentNetwork() const nftTransfers = useERC721Transactions(aggregatedData) - const swapTxnReview = getTransactionReviewSwap(transactionReview) - const transactionReviewWithType = - getTransactionReviewWithType(transactionReview) + const isSwap = transactionReviewHasSwap(transactionReview) + const isTransfer = transactionReviewHasTransfer(transactionReview) // Check approve screen type and return appropriate icon switch (approveScreenType) { @@ -69,9 +68,12 @@ export const TransactionIcon: FC = ({ return default: // Check if swap transaction review is available - if (swapTxnReview) { + if (isSwap) { return ( - + ) } @@ -80,11 +82,11 @@ export const TransactionIcon: FC = ({ // Here the assumption is that if the transaction is a transfer, it is a send transaction // and that it will be done in-app without approval // If there is approval, this will not render - if (transactionReviewWithType?.type === "transfer") { + if (isTransfer) { return ( ) } diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionTitleArgentX.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionTitleArgentX.tsx index dae158215..9cd12b57f 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionTitleArgentX.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/DappHeader/TransactionTitleArgentX.tsx @@ -1,11 +1,22 @@ -import { useERC20Transactions, useERC721Transactions } from "@argent/shared" -import { TextWithAmount, icons } from "@argent/ui" +import { + prettifyTokenAmount, + useERC20Transactions, + useERC721Transactions, +} from "@argent/x-shared" +import { TextWithAmount, icons } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, Fragment, PropsWithChildren, useMemo } from "react" -import { prettifyTokenAmount } from "../../../../../../shared/token/price" -import { getTransactionReviewWithType } from "../../../../../../shared/transactionReview.service" -import { ApiTransactionReviewResponse } from "../../../../../../shared/transactionReview.service" +import { isEmpty } from "lodash-es" +import { + getTransactionActionByType, + transactionReviewHasSwap, + transactionReviewHasTransfer, +} from "../../../../../../shared/transactionReview.service" +import { + Property, + ReviewOfTransaction, +} from "../../../../../../shared/transactionReview/schema" import { useRemoteNft } from "../../../../accountNfts/useRemoteNft" import { useCurrentNetwork } from "../../../../networks/hooks/useCurrentNetwork" import { ApproveScreenType } from "../../types" @@ -14,7 +25,7 @@ import { AggregatedSimData } from "../../useTransactionSimulatedData" const { ArrowRightIcon } = icons export interface TransactionTitleArgentXProps { - transactionReview?: ApiTransactionReviewResponse + transactionReview?: ReviewOfTransaction aggregatedData?: AggregatedSimData[] fallback?: string approveScreenType: ApproveScreenType @@ -37,10 +48,8 @@ export const TransactionTitleArgentX: FC = ({ const erc20Transfers = useERC20Transactions(aggregatedData) const hasErc20Transfers = Boolean(erc20Transfers.length) - const transactionReviewWithType = useMemo( - () => getTransactionReviewWithType(transactionReview), - [transactionReview], - ) + const isSwap = transactionReviewHasSwap(transactionReview) + const isTransfer = transactionReviewHasTransfer(transactionReview) // Check for specific approve screen types switch (approveScreenType) { @@ -67,9 +76,11 @@ export const TransactionTitleArgentX: FC = ({ } // Check for specific transaction types - if (transactionReviewWithType?.type === "swap") { - const srcSymbol = transactionReviewWithType.activity?.src?.token.symbol - const dstSymbol = transactionReviewWithType.activity?.dst?.token.symbol + if (isSwap) { + const srcSymbol = aggregatedData?.find((ag) => ag.recipients.length > 0) + ?.token.symbol + const dstSymbol = aggregatedData?.find((ag) => isEmpty(ag.recipients)) + ?.token.symbol return ( @@ -80,26 +91,39 @@ export const TransactionTitleArgentX: FC<TransactionTitleArgentXProps> = ({ ) } - if ( - transactionReviewWithType?.type === "transfer" && - transactionReviewWithType?.activity?.value?.amount - ) { - const amount = transactionReviewWithType.activity.value.amount - const decimals = transactionReviewWithType.activity.value.token.decimals - const symbol = transactionReviewWithType.activity.value.token.symbol - - return ( - <TextWithAmount amount={amount} decimals={decimals}> - <Title data-testid="send-title"> - Send{" "} - {prettifyTokenAmount({ - amount, - decimals, - })}{" "} - {symbol} - - + if (isTransfer) { + const action = getTransactionActionByType( + "ERC20_transfer", + transactionReview, ) + if (action) { + const amountProperty = [ + ...action.properties, + ...(action.defaultProperties || []), + ].find((p) => p.type === "amount") + + if (amountProperty) { + const property = amountProperty as Extract + const amount = property.amount + const decimals = property.token.decimals + const symbol = property.token.symbol + + if (amount && decimals) { + return ( + + + Send{" "} + {prettifyTokenAmount({ + amount, + decimals, + })}{" "} + {symbol} + + + ) + } + } + } } // Display NFT transfers if applicable diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/MultisigBanner.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/MultisigBanner.tsx index acf828336..278215e1c 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/MultisigBanner.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/MultisigBanner.tsx @@ -1,4 +1,4 @@ -import { P4, SplitProgress, icons } from "@argent/ui" +import { P4, SplitProgress, icons } from "@argent/x-ui" import { Box, Flex, Progress } from "@chakra-ui/react" import { WalletAccount } from "../../../../../shared/wallet.model" @@ -21,14 +21,14 @@ export const MultisigBanner = ({ return ( { diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionActions.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionActions.tsx index 25095355e..09517bb2a 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionActions.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionActions.tsx @@ -5,7 +5,7 @@ import { DetailAccordionItem, DetailAccordionPanel, DetailAccordionRow, -} from "@argent/ui" +} from "@argent/x-ui" import { Box } from "@chakra-ui/react" import { FC } from "react" import { CallData, num } from "starknet" @@ -13,7 +13,8 @@ import { CallData, num } from "starknet" import { entryPointToHumanReadable } from "../../../../../shared/transactions" import { TransactionActionsType } from "../types" import { formatCalldataSafe } from "../../utils" -import { formatTruncatedAddress } from "@argent/shared" +import { formatTruncatedAddress } from "@argent/x-shared" +import { TransactionReviewProperty } from "../../transactionV2/action/properties/TransactionReviewProperty" export interface TransactionActionsProps { action: TransactionActionsType @@ -86,10 +87,14 @@ export const TransactionActions: FC = ({ action }) => { !transaction.calldata || transaction.calldata?.length === 0 } > - + + + {CallData.toCalldata( formatCalldataSafe(transaction.calldata), diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionBanner.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionBanner.tsx index 965fea47d..d8b2fcc0f 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionBanner.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/TransactionBanner.tsx @@ -1,4 +1,4 @@ -import { L1 } from "@argent/ui" +import { L1 } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, ReactNode } from "react" diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/WithActionScreenErrorFooter.tsx b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/WithActionScreenErrorFooter.tsx index 5bcc47a3b..089004f9e 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/WithActionScreenErrorFooter.tsx +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/WithActionScreenErrorFooter.tsx @@ -1,20 +1,10 @@ -import { icons } from "@argent/ui" -import { - Accordion, - AccordionButton, - AccordionIcon, - AccordionItem, - AccordionPanel, - Box, -} from "@chakra-ui/react" -import React, { FC, PropsWithChildren } from "react" +import { FC, PropsWithChildren } from "react" import { useActionScreen } from "../../hooks/useActionScreen" import { usePrettyError } from "../../hooks/usePrettyError" +import { ActionScreenErrorFooter } from "./ActionScreenErrorFooter" -const { AlertIcon } = icons - -export interface WithActionScreenErrorFooterProps extends PropsWithChildren { +interface WithActionScreenErrorFooterProps extends PropsWithChildren { isTransaction?: boolean } @@ -32,18 +22,7 @@ export const WithActionScreenErrorFooter: FC< return ( <> {children} - - - - {" "} - - {title} - - - - {errorMessage} - - + ) } diff --git a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/approveTransactionScreen.model.ts b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/approveTransactionScreen.model.ts index c0503e827..6a6503af4 100644 --- a/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/approveTransactionScreen.model.ts +++ b/packages/extension/src/ui/features/actions/transaction/ApproveTransactionScreen/approveTransactionScreen.model.ts @@ -1,19 +1,15 @@ import { UseDisclosureReturn } from "@chakra-ui/react" -import React from "react" import { Call } from "starknet" -import { - ApiTransactionReviewResponse, - ApiTransactionReviewTargettedDapp, -} from "../../../../../shared/transactionReview.service" -import { ApiTransactionBulkSimulationResponse } from "../../../../../shared/transactionSimulation/types" +import { TransactionAction } from "@argent/x-shared" +import { ApiTransactionReviewTargettedDapp } from "../../../../../shared/transactionReview.service" +import { EnrichedSimulateAndReview } from "../../../../../shared/transactionReview/schema" import { WalletAccount } from "../../../../../shared/wallet.model" import { Multisig } from "../../../multisig/Multisig" import { ApproveScreenType, TransactionActionsType } from "../types" import { AggregatedSimData } from "../useTransactionSimulatedData" import { ConfirmScreenProps } from "./ConfirmScreen" import { MultisigBannerProps } from "./MultisigBanner" -import { TransactionAction } from "@argent/shared" export interface ApproveTransactionScreenContainerProps extends Omit { @@ -39,8 +35,8 @@ export interface ApproveTransactionScreenProps aggregatedData: AggregatedSimData[] isMainnet: boolean isSimulationLoading: boolean - transactionReview?: ApiTransactionReviewResponse - transactionSimulation?: ApiTransactionBulkSimulationResponse + transactionReview?: EnrichedSimulateAndReview + transactionActionsType?: TransactionActionsType selectedAccount: WalletAccount disableConfirm: boolean verifiedDapp?: ApiTransactionReviewTargettedDapp @@ -49,11 +45,8 @@ export interface ApproveTransactionScreenProps confirmButtonText?: string transactions: Call[] multisigModalDisclosure: UseDisclosureReturn - showFraudMonitorBanner: boolean hasBalanceChange: boolean showTransactionActions: boolean - transactionActionsType?: TransactionActionsType - assessmentReason: React.ReactNode showTxDetails: boolean setShowTxDetails: (viewMoreDetails: boolean) => void multisigBannerProps: MultisigBannerProps diff --git a/packages/extension/src/ui/features/actions/transaction/executeFromOutside/model.ts b/packages/extension/src/ui/features/actions/transaction/executeFromOutside/model.ts index 0ac4f8fc4..1a74dc3aa 100644 --- a/packages/extension/src/ui/features/actions/transaction/executeFromOutside/model.ts +++ b/packages/extension/src/ui/features/actions/transaction/executeFromOutside/model.ts @@ -2,7 +2,7 @@ import { addressSchema, bigNumberishSchema, isEqualAddress, -} from "@argent/shared" +} from "@argent/x-shared" import { z } from "zod" import { getWhitelistedContracts } from "./whitelist" diff --git a/packages/extension/src/ui/features/actions/transaction/executeFromOutside/utils.test.ts b/packages/extension/src/ui/features/actions/transaction/executeFromOutside/utils.test.ts index 534ef7841..021b222d3 100644 --- a/packages/extension/src/ui/features/actions/transaction/executeFromOutside/utils.test.ts +++ b/packages/extension/src/ui/features/actions/transaction/executeFromOutside/utils.test.ts @@ -2,7 +2,7 @@ import { validateOutsideExecution } from "./utils" import { stark, typedData } from "starknet" import * as whitelist from "./whitelist" import { getMockNetwork } from "../../../../../../test/network.mock" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" vi.mock("./whitelist") diff --git a/packages/extension/src/ui/features/actions/transaction/executeFromOutside/whitelist.ts b/packages/extension/src/ui/features/actions/transaction/executeFromOutside/whitelist.ts index 9f37a320e..c9e4d01f8 100644 --- a/packages/extension/src/ui/features/actions/transaction/executeFromOutside/whitelist.ts +++ b/packages/extension/src/ui/features/actions/transaction/executeFromOutside/whitelist.ts @@ -1,4 +1,4 @@ -import { Address, addressSchema } from "@argent/shared" +import { Address, addressSchema } from "@argent/x-shared" // Contracts to be whitelisted for execute_from_outside const OUTSIDE_EXEC_WHITELIST = [ diff --git a/packages/extension/src/ui/features/actions/transaction/fields/ContractField.tsx b/packages/extension/src/ui/features/actions/transaction/fields/ContractField.tsx index 2b678e4e4..703787879 100644 --- a/packages/extension/src/ui/features/actions/transaction/fields/ContractField.tsx +++ b/packages/extension/src/ui/features/actions/transaction/fields/ContractField.tsx @@ -3,7 +3,7 @@ import { FC } from "react" import { CopyTooltip } from "../../../../components/CopyTooltip" import { Field, FieldKey, FieldValue } from "../../../../components/Fields" import { ContentCopyIcon } from "../../../../components/Icons/MuiIcons" -import { formatTruncatedAddress } from "@argent/shared" +import { formatTruncatedAddress } from "@argent/x-shared" interface ContractFieldProps { contractAddress?: string diff --git a/packages/extension/src/ui/features/actions/transaction/fields/FeeField.tsx b/packages/extension/src/ui/features/actions/transaction/fields/FeeField.tsx index 9dcaf7107..1c9ea52f5 100644 --- a/packages/extension/src/ui/features/actions/transaction/fields/FeeField.tsx +++ b/packages/extension/src/ui/features/actions/transaction/fields/FeeField.tsx @@ -1,11 +1,11 @@ -import { L1, TextWithAmount } from "@argent/ui" +import { L1, TextWithAmount } from "@argent/x-ui" import { Box } from "@chakra-ui/react" import { FC } from "react" import { Field, FieldKey, LeftPaddedField } from "../../../../components/Fields" import { useDisplayTokenAmountAndCurrencyValue } from "../../../accountTokens/useDisplayTokenAmountAndCurrencyValue" import { useToken } from "../../../accountTokens/tokens.state" -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" interface FeeFieldProps { title?: string diff --git a/packages/extension/src/ui/features/actions/transaction/fields/ParameterField.tsx b/packages/extension/src/ui/features/actions/transaction/fields/ParameterField.tsx index e148c784b..09fa89f50 100644 --- a/packages/extension/src/ui/features/actions/transaction/fields/ParameterField.tsx +++ b/packages/extension/src/ui/features/actions/transaction/fields/ParameterField.tsx @@ -1,4 +1,4 @@ -import { formatTruncatedAddress, isValidAddress } from "@argent/shared" +import { formatTruncatedAddress, isValidAddress } from "@argent/x-shared" import { chakra } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/actions/transaction/fields/TokenField.tsx b/packages/extension/src/ui/features/actions/transaction/fields/TokenField.tsx index 6ac89f176..048bedb41 100644 --- a/packages/extension/src/ui/features/actions/transaction/fields/TokenField.tsx +++ b/packages/extension/src/ui/features/actions/transaction/fields/TokenField.tsx @@ -1,8 +1,7 @@ -import { TextWithAmount } from "@argent/ui" +import { TextWithAmount } from "@argent/x-ui" import { BigNumberish } from "starknet" import { FC } from "react" -import { prettifyTokenAmount } from "../../../../../shared/token/price" import { Field, FieldKey, @@ -11,7 +10,7 @@ import { } from "../../../../components/Fields" import { TokenIcon } from "../../../accountTokens/TokenIcon" import { Token } from "../../../../../shared/token/__new/types/token.model" -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress, prettifyTokenAmount } from "@argent/x-shared" interface TokenFieldProps { label: string diff --git a/packages/extension/src/ui/features/actions/transaction/useTransactionSimulatedData.ts b/packages/extension/src/ui/features/actions/transaction/useTransactionSimulatedData.ts index c4dbf8c76..3a02f7390 100644 --- a/packages/extension/src/ui/features/actions/transaction/useTransactionSimulatedData.ts +++ b/packages/extension/src/ui/features/actions/transaction/useTransactionSimulatedData.ts @@ -1,4 +1,4 @@ -import { addressSchema, isEqualAddress } from "@argent/shared" +import { addressSchema, isEqualAddress } from "@argent/x-shared" import type { Dictionary } from "lodash" import { flatten, @@ -24,7 +24,7 @@ import { Account } from "../../accounts/Account" import { useSelectedAccount } from "../../accounts/accounts.state" import { useTokensRecord } from "../../accountTokens/tokens.state" import { useCurrentNetwork } from "../../networks/hooks/useCurrentNetwork" -import { bigDecimal } from "@argent/shared" +import { bigDecimal } from "@argent/x-shared" import { EstimatedFees } from "../../../../shared/transactionSimulation/fees/fees.model" import { Token } from "../../../../shared/token/__new/types/token.model" import { diff --git a/packages/extension/src/ui/features/actions/transaction/useTransactionSimulation.ts b/packages/extension/src/ui/features/actions/transaction/useTransactionSimulation.ts index 185e7fef5..5c652edc1 100644 --- a/packages/extension/src/ui/features/actions/transaction/useTransactionSimulation.ts +++ b/packages/extension/src/ui/features/actions/transaction/useTransactionSimulation.ts @@ -2,7 +2,7 @@ import { Address, TransactionAction, swrRefetchDisabledConfig, -} from "@argent/shared" +} from "@argent/x-shared" import { useCallback } from "react" import { TransactionType } from "starknet" diff --git a/packages/extension/src/ui/features/actions/transactionV2/AmountEditModalForm.tsx b/packages/extension/src/ui/features/actions/transactionV2/AmountEditModalForm.tsx index e2af36e5a..013eaf68e 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/AmountEditModalForm.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/AmountEditModalForm.tsx @@ -1,5 +1,5 @@ -import { BigDecimal, bigDecimal } from "@argent/shared" -import { ModalDialog, icons, Input, FieldError, P3 } from "@argent/ui" +import { BigDecimal, bigDecimal } from "@argent/x-shared" +import { ModalDialog, icons, Input, FieldError, P3 } from "@argent/x-ui" import { Button, Flex, InputGroup, InputRightElement } from "@chakra-ui/react" import { zodResolver } from "@hookform/resolvers/zod" import { FC } from "react" diff --git a/packages/extension/src/ui/features/actions/transactionV2/FeeEstimationContainerV2.tsx b/packages/extension/src/ui/features/actions/transactionV2/FeeEstimationContainerV2.tsx index 2ecfdb2e0..90fd3d62e 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/FeeEstimationContainerV2.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/FeeEstimationContainerV2.tsx @@ -1,6 +1,6 @@ import { isFunction } from "lodash-es" import { FC, useEffect, useMemo } from "react" -import { TokenWithBalance } from "@argent/shared" +import { TokenWithBalance } from "@argent/x-shared" import { useAccount } from "../../accounts/accounts.state" import { useCurrencyDisplayEnabled, diff --git a/packages/extension/src/ui/features/actions/transactionV2/ReviewFallback.tsx b/packages/extension/src/ui/features/actions/transactionV2/ReviewFallback.tsx index 679a1e3ac..364482904 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/ReviewFallback.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/ReviewFallback.tsx @@ -1,25 +1,35 @@ -import { P4, icons } from "@argent/ui" -import { Flex, useDisclosure } from "@chakra-ui/react" +import { P4, icons } from "@argent/x-ui" +import { Flex, FlexProps, useDisclosure } from "@chakra-ui/react" import { Call } from "starknet" -import { CallDataModal } from "./action/properties/TransactionReviewProperty" +import { CallDataModal } from "./action/properties/ui/CallDataModal" +import { FC } from "react" const { AlertFillIcon } = icons -export const ReviewFallback = ({ calls }: { calls: Call[] }) => { + +interface ReviewFallbackProps extends FlexProps { + calls: Call[] + message?: string +} + +export const ReviewFallback: FC = ({ + calls, + message = "Failed to load transaction details and fraud warnings. Continue at your own risk, or contact support", + ...rest +}) => { const { isOpen, onOpen, onClose } = useDisclosure() const calldata = JSON.stringify(calls, null, 2) return ( - + - - - Failed to load transaction details and fraud warnings. Continue at - your own risk, or contact support + + + {message} { const { action, selectedAccount, - approveAndClose, + approve, reject, rejectWithoutClose, + closePopupIfLastAction, } = useActionScreen() if (action?.type !== "SIGN") { throw new Error( @@ -38,6 +40,15 @@ export const SignActionScreenContainerV2: FC = () => { const dataToSign = action.payload.typedData const skipDeployWarning = action.payload.options?.skipDeploy + const onSubmit = useCallback(async () => { + const result = await approve() + if (isObject(result) && "error" in result) { + // stay on error screen + } else { + closePopupIfLastAction() + } + }, [closePopupIfLastAction, approve]) + if ( !skipDeployWarning && selectedAccount?.needsDeploy && @@ -92,7 +103,7 @@ export const SignActionScreenContainerV2: FC = () => { dappLogoUrl={dappDisplayAttributes.iconUrl} dappHost={action.meta.origin || ""} dataToSign={dataToSign} - onSubmit={() => void approveAndClose()} + onSubmit={() => void onSubmit()} footer={} onReject={() => void reject()} actionIsApproving={Boolean(action.meta.startedApproving)} diff --git a/packages/extension/src/ui/features/actions/transactionV2/TransactionActionScreenContainerV2.tsx b/packages/extension/src/ui/features/actions/transactionV2/TransactionActionScreenContainerV2.tsx index 02f82b35a..736bb4eac 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/TransactionActionScreenContainerV2.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/TransactionActionScreenContainerV2.tsx @@ -1,79 +1,67 @@ -import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react" - -import { useTransactionReviewV2 } from "./useTransactionReviewV2" -import { useActionScreen } from "../hooks/useActionScreen" -import { TransactionReviewActions } from "./action/TransactionReviewActions" -import { AccountDetails } from "./TransactionHeader/AccountDetails" import { - Accordion, - AccordionButton, - AccordionItem, - AccordionPanel, - Box, - Divider, - useDisclosure, -} from "@chakra-ui/react" -import { isArray } from "lodash-es" -import { TransactionHeader } from "./TransactionHeader" -import { WarningBanner } from "../warning/WarningBanner" -import { FeeEstimationContainerV2 } from "./FeeEstimationContainerV2" + Address, + ensureArray, + formatAddress, + getUint256CalldataFromBN, + isEqualAddress, + nonNullable, + prettifyTokenNumber, + transferCalldataSchema, +} from "@argent/x-shared" +import { Divider, useDisclosure } from "@chakra-ui/react" +import { formatUnits } from "ethers" +import { useAtom } from "jotai" import { isEmpty, isObject } from "lodash-es" -import { routes } from "../../../routes" +import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react" import { useNavigate } from "react-router-dom" -import { ReviewFallback } from "./ReviewFallback" -import { - ConfirmScreen, - ConfirmScreenProps, -} from "../transaction/ApproveTransactionScreen/ConfirmScreen" -import { WithActionScreenErrorFooter } from "../transaction/ApproveTransactionScreen/WithActionScreenErrorFooter" -import { RemovedMultisigWarningScreen } from "../../multisig/RemovedMultisigWarningScreen" -import { WithArgentShieldVerified } from "../../shield/WithArgentShieldVerified" -import { useAtom } from "jotai" -import { userClickedAddFundsAtom } from "../../../views/actions" -import { WaitingForFunds } from "../feeEstimation/ui/WaitingForFunds" -import { useMultisigActionScreen } from "./useMultisigActionScreen" -import { TransactionReviewSimulation } from "./simulation/TransactionReviewSimulation" -import { ListSkeleton } from "../../../components/ScreenSkeleton" -import { TransactionReviewSummaryStack } from "./simulation/summary/TransactionReviewSummaryStack" -import { AccordionIcon, B3, P4, icons } from "@argent/ui" +import { z } from "zod" + +import { isTransactionActionItem } from "../../../../shared/actionQueue/types" import { getMessageFromTrpcError } from "../../../../shared/errors/schema" +import { BaseToken } from "../../../../shared/token/__new/types/token.model" import { getMessageFromSimulationError, isNotTransactionSimulationError, isTransactionSimulationError, + warningSchema, } from "../../../../shared/transactionReview/schema" -import { TransactionReviewLabel } from "./TransactionReviewLabel" - -const { AlertIcon } = icons -import { warningSchema } from "../../../../shared/transactionReview/schema" -import { z } from "zod" -import { useBestFeeToken } from "../useBestFeeToken" -import { ConfirmationModal } from "../warning/ConfirmationModal" -import { getHighestSeverity } from "../warning/helper" -import { ReviewFooter } from "../warning/ReviewFooter" -import { useRejectDeployIfPresent } from "../hooks/useRejectDeployAction" -import { FeeTokenPickerModal } from "../feeEstimation/ui/FeeTokenPickerModal" -import { useFeeTokenBalances } from "../../accountTokens/useFeeTokenBalance" -import { useUpgradeAccountTransactions } from "../../accounts/accountTransactions.state" -import { useTxnsHasV3UpgradeCallback } from "./useTxnsHasV3Upgrade" -import { BaseToken } from "../../../../shared/token/__new/types/token.model" +import { isSafeUpgradeTransaction } from "../../../../shared/utils/isUpgradeTransaction" +import { ListSkeleton } from "../../../components/ScreenSkeleton" +import { routes } from "../../../routes" import { feeTokenService } from "../../../services/feeToken" -import { isTransactionActionItem } from "../../../../shared/actionQueue/types" +import { tokenService } from "../../../services/tokens" +import { userClickedAddFundsAtom } from "../../../views/actions" import { useNetworkFeeTokens } from "../../accountTokens/tokens.state" -import { - Address, - formatAddress, - getUint256CalldataFromBN, - isEqualAddress, - nonNullable, - transferCalldataSchema, -} from "@argent/shared" +import { useFeeTokenBalances } from "../../accountTokens/useFeeTokenBalance" import { maxFeeEstimateForTransfer } from "../../accountTokens/useMaxFeeForTransfer" -import { tokenService } from "../../../services/tokens" -import { formatUnits } from "ethers" -import { parseTransferTokenCall } from "./utils" -import { prettifyTokenNumber } from "../../../../shared/utils/number" -import { isSafeUpgradeTransaction } from "../../../../shared/utils/isUpgradeTransaction" +import { RemovedMultisigWarningScreen } from "../../multisig/RemovedMultisigWarningScreen" +import { WithArgentShieldVerified } from "../../shield/WithArgentShieldVerified" +import { FeeTokenPickerModal } from "../feeEstimation/ui/FeeTokenPickerModal" +import { WaitingForFunds } from "../feeEstimation/ui/WaitingForFunds" +import { useActionScreen } from "../hooks/useActionScreen" +import { useRejectDeployIfPresent } from "../hooks/useRejectDeployAction" +import { + ConfirmScreen, + ConfirmScreenProps, +} from "../transaction/ApproveTransactionScreen/ConfirmScreen" +import { WithActionScreenErrorFooter } from "../transaction/ApproveTransactionScreen/WithActionScreenErrorFooter" +import { useBestFeeToken } from "../useBestFeeToken" +import { ConfirmationModal } from "../warning/ConfirmationModal" +import { ReviewFooter } from "../warning/ReviewFooter" +import { WarningBanner } from "../warning/WarningBanner" +import { getHighestSeverity } from "../warning/helper" +import { FeeEstimationContainerV2 } from "./FeeEstimationContainerV2" +import { ReviewFallback } from "./ReviewFallback" +import { TransactionHeader } from "./TransactionHeader" +import { AccountDetails } from "./TransactionHeader/AccountDetails" +import { TransactionReviewLabel } from "./TransactionReviewLabel" +import { TransactionReviewActions } from "./action/TransactionReviewActions" +import { TransactionReviewSimulation } from "./simulation/TransactionReviewSimulation" +import { useMultisigActionScreen } from "./useMultisigActionScreen" +import { useTransactionReviewV2 } from "./useTransactionReviewV2" +import { parseTransferTokenCall } from "./utils/parseTransferTokenCall" +import { getPrettyRpcError } from "./utils/getPrettyRpcError" +import { ActionScreenErrorFooter } from "../transaction/ApproveTransactionScreen/ActionScreenErrorFooter" export interface TransactionActionScreenContainerV2Props extends ConfirmScreenProps { @@ -146,25 +134,37 @@ export const TransactionActionScreenContainerV2: FC< const loadingOrErrorState = useMemo(() => { if (error) { console.warn("error", error) - const message = getMessageFromTrpcError(error) return ( - - - Transaction failure predicted - - {message && ( - - {message} - - )} - + ) } if (!transactionReview) { return } return null - }, [error, transactionReview]) + }, [action.payload.transactions, error, transactionReview]) + + const customErrorFooter = useMemo(() => { + if (!error) { + return null + } + const message = getMessageFromTrpcError(error) + if (!message) { + return null + } + const rpcMessage = getPrettyRpcError(message) + const title = rpcMessage ? ( + + ) : ( + "Tx not executed" + ) + return + }, [error]) /** TODO: come back and refactor all this properly */ @@ -179,26 +179,29 @@ export const TransactionActionScreenContainerV2: FC< : false, ) // We only keep the last one as if there's more than one the first one is for the deployment of the account - const lastSimulation = txSimulationErrors?.[txSimulationErrors.length - 1] - if (!lastSimulation) { + const lastSimulationError = + txSimulationErrors?.[txSimulationErrors.length - 1] + if (!lastSimulationError) { return null } - const errorMessage = getMessageFromSimulationError(lastSimulation) + const errorMessage = getMessageFromSimulationError(lastSimulationError) + + const lastSimulationErrorOrMessage = + lastSimulationError.message || lastSimulationError.error + + const rpcError = getPrettyRpcError(lastSimulationErrorOrMessage) + + const label = rpcError ? rpcError : lastSimulationError.label + const message = rpcError ? lastSimulationErrorOrMessage : errorMessage return ( - - - - {" "} - - - - - - {errorMessage} - - + + } + errorMessage={message} + /> ) }, [transactionReview]) @@ -260,11 +263,6 @@ export const TransactionActionScreenContainerV2: FC< warningsWithoutUndefined.success && getHighestSeverity(warningsWithoutUndefined.data) - const { pendingTransactions: pendingUpgradeTransactions } = - useUpgradeAccountTransactions(selectedAccount) - - const txnsHasV3UpgradeTxn = useTxnsHasV3UpgradeCallback() - const isUpgradeTransaction = useMemo( () => isTransactionActionItem(action) && @@ -299,13 +297,7 @@ export const TransactionActionScreenContainerV2: FC< const transactionReviewFallback = useMemo( () => transactionReview?.isBackendDown && ( - + ), [transactionReview, action.payload.transactions], ) @@ -442,6 +434,8 @@ export const TransactionActionScreenContainerV2: FC< const footer = userClickedAddFunds ? ( + ) : customErrorFooter ? ( + customErrorFooter ) : ( {isHighRisk && } diff --git a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/AccountDetails.tsx b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/AccountDetails.tsx index 25e0df205..4061da889 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/AccountDetails.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/AccountDetails.tsx @@ -1,9 +1,9 @@ import { Flex } from "@chakra-ui/react" import { selectedAccountView } from "../../../../views/account" import { useView } from "../../../../views/implementation/react" -import { B3, L2 } from "@argent/ui" +import { B3, L2 } from "@argent/x-ui" import { useCurrentNetwork } from "../../../networks/hooks/useCurrentNetwork" -import { formatAddress } from "@argent/shared" +import { formatAddress } from "@argent/x-shared" export const AccountDetails = () => { const currentAccount = useView(selectedAccountView) @@ -11,14 +11,14 @@ export const AccountDetails = () => { return ( - {currentAccount?.name} + {currentAccount?.name} {currentAccount?.address && ( - + ({formatAddress(currentAccount.address)}) )} - {currentNetwork.name} + {currentNetwork.name} ) } diff --git a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/KnownIcon.tsx b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/KnownIcon.tsx index 49ef0615a..8e8627b7a 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/KnownIcon.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/KnownIcon.tsx @@ -1,6 +1,6 @@ import { BoxProps } from "@chakra-ui/react" import { IconWrapper } from "./IconWrapper" -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" export const KnownIcon = ({ iconKey, diff --git a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/UnknownDappIcon.tsx b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/UnknownDappIcon.tsx index 374a66a9b..550d823ef 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/UnknownDappIcon.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionIcon/UnknownDappIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { BoxProps } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionTitle.tsx b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionTitle.tsx index f8b640c17..bab83a0c9 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionTitle.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/TransactionHeader/TransactionTitle.tsx @@ -1,4 +1,4 @@ -import { H5, P4 } from "@argent/ui" +import { H5, P4 } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { KnownDappButtonWrapper } from "../../connectDapp/KnownDappButtonWrapper" @@ -15,7 +15,7 @@ export const TransactionTitle = ({
{title}
- + {subtitle} {dappHost && } diff --git a/packages/extension/src/ui/features/actions/transactionV2/TransactionReviewLabel.tsx b/packages/extension/src/ui/features/actions/transactionV2/TransactionReviewLabel.tsx index 900ca911d..9c35034d8 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/TransactionReviewLabel.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/TransactionReviewLabel.tsx @@ -3,9 +3,17 @@ import { FC } from "react" import { useView } from "../../../views/implementation/react" import { labelsFindFamily } from "../../../views/transactionReviews" -export const TransactionReviewLabel: FC<{ label?: string }> = ({ - label = "", -}) => { +export const TransactionReviewLabel: FC<{ + prefix?: string + label?: string + suffix?: string +}> = ({ prefix, label = "", suffix }) => { const labelString = useView(labelsFindFamily(label)) - return <>{labelString} + return ( + <> + {prefix} + {labelString} + {suffix} + + ) } diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewAction.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewAction.tsx index 32d637fa8..36dd0d388 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewAction.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewAction.tsx @@ -6,10 +6,10 @@ import { Flex, } from "@chakra-ui/react" import { FC } from "react" -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" const { AlertFillIcon } = icons -import { AccordionIconDropdown, P4 } from "@argent/ui" +import { AccordionIconDropdown, P4 } from "@argent/x-ui" import type { Action, Assessment, @@ -40,7 +40,10 @@ export const TransactionReviewAction: FC = ({ defaultIndex={defaultIndex} > - + diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewSignAction.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewSignAction.tsx index a2e8dbdbd..355a4bc0e 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewSignAction.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/action/TransactionReviewSignAction.tsx @@ -16,7 +16,7 @@ import { NestedAccordion, P4, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { typedData } from "starknet" import { JsonObject } from "type-fest" @@ -47,7 +47,7 @@ export const TransactionReviewSignAction: FC< isOpen={isOpen} onClose={onClose} /> - + Data to be signed diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/AddressProperty.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/AddressProperty.tsx new file mode 100644 index 000000000..55db26000 --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/AddressProperty.tsx @@ -0,0 +1,41 @@ +import { Flex } from "@chakra-ui/react" +import { useMemo } from "react" + +import type { Property } from "../../../../../../shared/transactionReview/schema" +import { PrettyAccountAddressArgentX } from "../../../../accounts/PrettyAccountAddressArgentX" +import { useCurrentNetwork } from "../../../../networks/hooks/useCurrentNetwork" +import { AddressActions } from "./ui/AddressActions" +import { AddressTooltip } from "./ui/AddressTooltip" + +export function AddressProperty( + property: Extract, +) { + const network = useCurrentNetwork() + const { addressName, address } = property + + const value = useMemo(() => { + if (addressName) { + return addressName + } + return ( + + ) + }, [address, addressName, network.id]) + + return ( + + + {value} + + ) +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/AmountProperty.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/AmountProperty.tsx new file mode 100644 index 000000000..5c3e28851 --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/AmountProperty.tsx @@ -0,0 +1,32 @@ +import { isUnlimitedAmount, prettifyTokenAmount } from "@argent/x-shared" +import { Flex, Text } from "@chakra-ui/react" + +import type { Property } from "../../../../../../shared/transactionReview/schema" +import { TokenIcon } from "../../../../accountTokens/TokenIcon" + +export function AmountProperty( + property: Extract, +) { + const { amount, token } = property + const value = prettifyTokenAmount({ + amount: amount, + decimals: token.decimals ?? 1 /** if nft 1 */, + symbol: token.symbol, + }) + let color = undefined + if (isUnlimitedAmount(amount)) { + color = "warning.500" + } + return ( + + + {value} + + ) +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/CallDataProperty.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/CallDataProperty.tsx new file mode 100644 index 000000000..765757c52 --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/CallDataProperty.tsx @@ -0,0 +1,33 @@ +import { Text, useDisclosure } from "@chakra-ui/react" + +import type { Property } from "../../../../../../shared/transactionReview/schema" +import { ModalDialogData } from "@argent/x-ui" + +export function CallDataProperty( + property: Extract, +) { + const { isOpen, onOpen, onClose } = useDisclosure() + const calldata = JSON.stringify(property.calldata, null, 2) + return ( + <> + + + {property.entrypoint} + + + ) +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/TextProperty.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TextProperty.tsx new file mode 100644 index 000000000..3838f344a --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TextProperty.tsx @@ -0,0 +1,5 @@ +import type { Property } from "../../../../../../shared/transactionReview/schema" + +export function TextProperty(property: Extract) { + return property.text +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/TimeStampProperty.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TimeStampProperty.tsx new file mode 100644 index 000000000..34e4280e1 --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TimeStampProperty.tsx @@ -0,0 +1,9 @@ +import type { Property } from "../../../../../../shared/transactionReview/schema" +import { formatDateTime } from "../../../../../services/dates" + +export function TimeStampProperty( + property: Extract, +) { + const value = formatDateTime(new Date(parseInt(property.value) * 1000)) + return value +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/TokenAddressProperty.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TokenAddressProperty.tsx new file mode 100644 index 000000000..3bf317abb --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TokenAddressProperty.tsx @@ -0,0 +1,31 @@ +import { Flex, Text } from "@chakra-ui/react" + +import type { Property } from "../../../../../../shared/transactionReview/schema" +import { TokenIcon } from "../../../../accountTokens/TokenIcon" +import { AddressActions } from "./ui/AddressActions" +import { AddressTooltip } from "./ui/AddressTooltip" + +export function TokenAddressProperty( + property: Extract, +) { + const { token } = property + return ( + + + + + + {token.symbol} + + + + ) +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperties.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperties.tsx index 28f4e39f8..2ddd4bfd7 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperties.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperties.tsx @@ -2,7 +2,7 @@ import { FC } from "react" import { Property } from "../../../../../../shared/transactionReview/schema" import { TransactionReviewProperty } from "./TransactionReviewProperty" -import { LabelValueStack } from "@argent/ui" +import { LabelValueStack } from "@argent/x-ui" interface TransactionReviewPropertiesProps { properties: Property[] diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperty.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperty.tsx index 69a8e1dc9..d4dd7364b 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperty.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/TransactionReviewProperty.tsx @@ -1,21 +1,14 @@ -import { formatTruncatedAddress, isUnlimitedAmount } from "@argent/shared" -import { ModalDialogData, icons, CopyTooltip, LabelValueRow } from "@argent/ui" -import { Button, Flex, Text, Tooltip, useDisclosure } from "@chakra-ui/react" -import { useCallback, useMemo } from "react" +import { LabelValueRow } from "@argent/x-ui" +import { useMemo } from "react" import type { Property } from "../../../../../../shared/transactionReview/schema" -import { TokenIcon } from "../../../../accountTokens/TokenIcon" -import { PrettyAccountAddressArgentX } from "../../../../accounts/PrettyAccountAddressArgentX" -import { useCurrentNetwork } from "../../../../networks/hooks/useCurrentNetwork" -import { - openBlockExplorerAddress, - useBlockExplorerTitle, -} from "../../../../../services/blockExplorer.service" -import { formatDateTime } from "../../../../../services/dates" -import { prettifyTokenAmount } from "../../../../../../shared/token/price" import { TransactionReviewLabel } from "../../TransactionReviewLabel" - -const { CopyIcon, ExpandIcon } = icons +import { AmountProperty } from "./AmountProperty" +import { AddressProperty } from "./AddressProperty" +import { CallDataProperty } from "./CallDataProperty" +import { TimeStampProperty } from "./TimeStampProperty" +import { TextProperty } from "./TextProperty" +import { TokenAddressProperty } from "./TokenAddressProperty" export function TransactionReviewProperty(property: Property) { const value = useMemo(() => { @@ -26,6 +19,8 @@ export function TransactionReviewProperty(property: Property) { return case "token_address": return TokenAddressProperty(property) + case "nft": + return TokenAddressProperty(property) case "calldata": return case "text": @@ -43,198 +38,3 @@ export function TransactionReviewProperty(property: Property) { /> ) } - -function AmountProperty(property: Extract) { - const { amount, token } = property - const value = prettifyTokenAmount({ - amount: amount, - decimals: token.decimals, - symbol: token.symbol, - }) - let color = undefined - if (isUnlimitedAmount(amount)) { - color = "warning.500" - } - return ( - - - {value} - - ) -} - -function AddressProperty(property: Extract) { - const network = useCurrentNetwork() - const blockExplorerTitle = useBlockExplorerTitle() - const { addressName, address } = property - const onOpen = useCallback( - () => void openBlockExplorerAddress(network, address), - [address, network], - ) - const value = useMemo(() => { - if (addressName) { - const tooltip = formatTruncatedAddress(address) - return ( - - - {addressName} - - - ) - } - return ( - - ) - }, [address, addressName, network.id, onOpen]) - - return ( - - - - - - - - - - {value} - - ) -} - -function TokenAddressProperty( - property: Extract, -) { - const { token } = property - return ( - - - {token.symbol} - - ) -} - -function CallDataProperty(property: Extract) { - const { isOpen, onOpen, onClose } = useDisclosure() - const calldata = JSON.stringify(property.calldata, null, 2) - return ( - - ) -} - -export function CallDataModal({ - calldata, - isOpen, - onClose, - onOpen, - label, - title, - alignRight = true, -}: { - calldata: string - label: string - title: string - isOpen: boolean - onClose: () => void - onOpen: () => void - alignRight?: boolean -}) { - return ( - - - - {label} - - - ) -} - -function TextProperty(property: Extract) { - return property.text -} - -function TimeStampProperty(property: Extract) { - const value = formatDateTime(new Date(parseInt(property.value) * 1000)) - return value -} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/AddressActions.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/AddressActions.tsx new file mode 100644 index 000000000..8346064ec --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/AddressActions.tsx @@ -0,0 +1,72 @@ +import { CopyTooltip, icons } from "@argent/x-ui" +import { Button, Flex, FlexProps, Tooltip } from "@chakra-ui/react" +import { FC, useCallback } from "react" + +import { + openBlockExplorerAddress, + useBlockExplorerTitle, +} from "../../../../../../services/blockExplorer.service" +import { useCurrentNetwork } from "../../../../../networks/hooks/useCurrentNetwork" + +const { CopyIcon, ExpandIcon } = icons + +interface AddressActionsProps extends FlexProps { + address: string +} + +export const AddressActions: FC = ({ + address, + ...rest +}) => { + const network = useCurrentNetwork() + const blockExplorerTitle = useBlockExplorerTitle() + const onOpen = useCallback( + () => void openBlockExplorerAddress(network, address), + [address, network], + ) + + return ( + { + e.stopPropagation() /** prevent click on containing button */ + }} + {...rest} + > + + + + + + + + ) +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/AddressTooltip.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/AddressTooltip.tsx new file mode 100644 index 000000000..2b58403f9 --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/AddressTooltip.tsx @@ -0,0 +1,38 @@ +import { formatTruncatedAddress } from "@argent/x-shared" +import { Text, Tooltip, TooltipProps } from "@chakra-ui/react" +import { FC, useCallback } from "react" + +import { openBlockExplorerAddress } from "../../../../../../services/blockExplorer.service" +import { useCurrentNetwork } from "../../../../../networks/hooks/useCurrentNetwork" + +interface AddressTooltipProps extends TooltipProps { + address: string +} + +export const AddressTooltip: FC = ({ + address, + children, + ...rest +}) => { + const network = useCurrentNetwork() + const onOpen = useCallback( + () => void openBlockExplorerAddress(network, address), + [address, network], + ) + const tooltip = formatTruncatedAddress(address) + + return ( + + + {children} + + + ) +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/CallDataModal.tsx b/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/CallDataModal.tsx new file mode 100644 index 000000000..3fb47a610 --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/action/properties/ui/CallDataModal.tsx @@ -0,0 +1,41 @@ +import { ModalDialogData } from "@argent/x-ui" +import { Button, Flex, Text } from "@chakra-ui/react" + +export function CallDataModal({ + calldata, + isOpen, + onClose, + onOpen, + label, + title, + alignRight = true, +}: { + calldata: string + label: string + title: string + isOpen: boolean + onClose: () => void + onOpen: () => void + alignRight?: boolean +}) { + return ( + + + + + ) +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/simulation/TransactionReviewSimulation.tsx b/packages/extension/src/ui/features/actions/transactionV2/simulation/TransactionReviewSimulation.tsx index 801f29edc..1ea631c3a 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/simulation/TransactionReviewSimulation.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/simulation/TransactionReviewSimulation.tsx @@ -1,6 +1,6 @@ import { FC } from "react" -import { B3, L1 } from "@argent/ui" +import { B3, L1 } from "@argent/x-ui" import { groupBy, isEmpty } from "lodash-es" import type { Simulation } from "../../../../../shared/transactionReview/schema" import { TransactionReviewSummary } from "./summary/TransactionReviewSummary" @@ -16,7 +16,7 @@ export const TransactionReviewSimulation: FC< if (isEmpty(simulation?.summary)) { return ( - + No balance change @@ -29,7 +29,7 @@ export const TransactionReviewSimulation: FC< {send && ( <> - Send + Send {send.map((summary, index) => ( - Receive + Receive {receive.map((summary, index) => ( @@ -77,7 +76,7 @@ function TokenSummary(summary: SimulationSummary) { {prefix} {displayAmount} - {usdValue && ${usdValue}} + {usdValue && ${usdValue}} ) diff --git a/packages/extension/src/ui/features/actions/transactionV2/simulation/summary/TransactionReviewSummaryStack.tsx b/packages/extension/src/ui/features/actions/transactionV2/simulation/summary/TransactionReviewSummaryStack.tsx index 2251e23df..57011f0c8 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/simulation/summary/TransactionReviewSummaryStack.tsx +++ b/packages/extension/src/ui/features/actions/transactionV2/simulation/summary/TransactionReviewSummaryStack.tsx @@ -8,7 +8,7 @@ export function TransactionReviewSummaryStack(props: FlexProps) { gap={3} p={3} rounded={"lg"} - bg="surface.elevated" + bg="surface-elevated" {...props} /> ) diff --git a/packages/extension/src/ui/features/actions/transactionV2/useTransactionReviewV2.ts b/packages/extension/src/ui/features/actions/transactionV2/useTransactionReviewV2.ts index 37ff9eaca..c15935f9c 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/useTransactionReviewV2.ts +++ b/packages/extension/src/ui/features/actions/transactionV2/useTransactionReviewV2.ts @@ -6,7 +6,7 @@ import { clientTransactionReviewService } from "../../../services/transactionRev import { Call } from "starknet" import { isArray, isEmpty } from "lodash-es" import { clientAccountService } from "../../../services/account" -import { Address } from "@argent/shared" +import { Address } from "@argent/x-shared" import { accountService } from "../../../../shared/account/service" import { BaseWalletAccount } from "../../../../shared/wallet.model" import { accountsEqual } from "../../../../shared/utils/accountsEqual" diff --git a/packages/extension/src/ui/features/actions/transactionV2/useTxnsHasV3Upgrade.ts b/packages/extension/src/ui/features/actions/transactionV2/useTxnsHasV3Upgrade.ts index c5f1d48f9..1f0b5e2e9 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/useTxnsHasV3Upgrade.ts +++ b/packages/extension/src/ui/features/actions/transactionV2/useTxnsHasV3Upgrade.ts @@ -1,6 +1,6 @@ import { useCallback } from "react" import { Transaction } from "../../../../shared/transactions" -import { nonNullable } from "@argent/shared" +import { nonNullable } from "@argent/x-shared" import { getV3UpgradeCall } from "../utils" export function useV3UpgradeFromTxnsCallback() { diff --git a/packages/extension/src/ui/features/actions/transactionV2/utils/getPrettyRpcError.test.ts b/packages/extension/src/ui/features/actions/transactionV2/utils/getPrettyRpcError.test.ts new file mode 100644 index 000000000..873ca88ae --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/utils/getPrettyRpcError.test.ts @@ -0,0 +1,51 @@ +import { getPrettyRpcError } from "./getPrettyRpcError" + +describe("getPrettyRpcError", () => { + describe("when valid", () => { + it("should return plain text reason", () => { + expect( + getPrettyRpcError( + "Failure reason: 0x496e73756666696369656e7420746f6b656e73207265636569766564 ('Insufficient tokens received').", + ), + ).toEqual("Insufficient tokens received") + + expect( + getPrettyRpcError( + `reverted: Error in the called contract (0x02f851d8206141e8133dbc778548be29f7d112cee9c6c8132d7f209817f5de3f):\nError at pc=0:15213:\nGot an exception while executing a hint: Custom Hint Error: Execution failed. Failure reason: 0x4e4654206973207374616b6564 ('NFT is staked').\nCairo traceback (most recent call last):\nUnknown location (pc=0:222)\nUnknown location (pc=0:4845)\nUnknown location (pc=0:10647)\n`, + ), + ).toEqual("NFT is staked") + + // How to reproduce: + // Go to your account on starkscan + // And trigger a “change_signer” just fill out the parameters with something like your address and 0 and 0 + expect( + getPrettyRpcError( + `reverted: Error in the called contract (0x011f5fc2a92ac03434a7937fe982f5e5293b65ad438a989c5b78fb8f04a12016):\nError at pc=0:15213:\nGot an exception while executing a hint: Custom Hint Error: Execution failed. Failure reason: 0x617267656e742f696e76616c69642d6f776e65722d736967 ('argent/invalid-owner-sig').\nCairo traceback (most recent call last):\nUnknown location (pc=0:222)\nUnknown location (pc=0:4845)\nUnknown location (pc=0:10647)\n`, + ), + ).toEqual("argent/invalid-owner-sig") + + // 1_ Go to Starkscan with your account + // 2 Trigger “Cancel escape” + expect( + getPrettyRpcError( + `reverted: Error in the called contract (0x011f5fc2a92ac03434a7937fe982f5e5293b65ad438a989c5b78fb8f04a12016):\nError at pc=0:15213:\nGot an exception while executing a hint: Custom Hint Error: Execution failed. Failure reason: 0x617267656e742f696e76616c69642d657363617065 ('argent/invalid-escape').\nCairo traceback (most recent call last):\nUnknown location (pc=0:222)\nUnknown location (pc=0:4845)\nUnknown location (pc=0:10647)\n`, + ), + ).toEqual("argent/invalid-escape") + }) + }) + describe("when invalid", () => { + it("should return undefined", () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(getPrettyRpcError()).toBeUndefined() + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(getPrettyRpcError(null)).toBeUndefined() + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(getPrettyRpcError([])).toBeUndefined() + expect(getPrettyRpcError("")).toBeUndefined() + expect(getPrettyRpcError(`0x123 ('')`)).toBeUndefined() + }) + }) +}) diff --git a/packages/extension/src/ui/features/actions/transactionV2/utils/getPrettyRpcError.ts b/packages/extension/src/ui/features/actions/transactionV2/utils/getPrettyRpcError.ts new file mode 100644 index 000000000..b1077c8dd --- /dev/null +++ b/packages/extension/src/ui/features/actions/transactionV2/utils/getPrettyRpcError.ts @@ -0,0 +1,14 @@ +import { isEmpty, isString } from "lodash-es" + +/** Failure reason: 0x496e73756666696369656e7420746f6b656e73207265636569766564 ('Insufficient tokens received'). */ +const rpcErrorRegex = /(0x[a-fA-F0-9]+)\s*\('(.*?)'\)/ + +export const getPrettyRpcError = (errorString?: string) => { + if (!isString(errorString)) { + return + } + const match = errorString.match(rpcErrorRegex) + if (match && !isEmpty(match[2])) { + return match[2] + } +} diff --git a/packages/extension/src/ui/features/actions/transactionV2/utils.test.ts b/packages/extension/src/ui/features/actions/transactionV2/utils/parseTransferTokenCall.test.ts similarity index 82% rename from packages/extension/src/ui/features/actions/transactionV2/utils.test.ts rename to packages/extension/src/ui/features/actions/transactionV2/utils/parseTransferTokenCall.test.ts index 278c01e6f..b4fb2c976 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/utils.test.ts +++ b/packages/extension/src/ui/features/actions/transactionV2/utils/parseTransferTokenCall.test.ts @@ -1,10 +1,10 @@ import { test } from "vitest" -import { parseTransferTokenCall } from "./utils" +import { parseTransferTokenCall } from "./parseTransferTokenCall" import { Call, uint256 } from "starknet" import { ETH_TOKEN_ADDRESS, STRK_TOKEN_ADDRESS, -} from "../../../../shared/network/constants" +} from "../../../../../shared/network/constants" test("parseTransferTokenCall", () => { const mockCall: Call = { diff --git a/packages/extension/src/ui/features/actions/transactionV2/utils.ts b/packages/extension/src/ui/features/actions/transactionV2/utils/parseTransferTokenCall.ts similarity index 93% rename from packages/extension/src/ui/features/actions/transactionV2/utils.ts rename to packages/extension/src/ui/features/actions/transactionV2/utils/parseTransferTokenCall.ts index eb7e05424..d8680e941 100644 --- a/packages/extension/src/ui/features/actions/transactionV2/utils.ts +++ b/packages/extension/src/ui/features/actions/transactionV2/utils/parseTransferTokenCall.ts @@ -1,4 +1,4 @@ -import { Address, addressSchema } from "@argent/shared" +import { Address, addressSchema } from "@argent/x-shared" import { isArray } from "lodash-es" import { Call, CallData, num, uint256 } from "starknet" diff --git a/packages/extension/src/ui/features/actions/useBestFeeToken.ts b/packages/extension/src/ui/features/actions/useBestFeeToken.ts index 45dfa7e21..dbef0ad7c 100644 --- a/packages/extension/src/ui/features/actions/useBestFeeToken.ts +++ b/packages/extension/src/ui/features/actions/useBestFeeToken.ts @@ -2,7 +2,7 @@ import { BaseWalletAccount } from "../../../shared/wallet.model" import { useView } from "../../views/implementation/react" import { useTokensInNetwork } from "../accountTokens/tokens.state" import { useAccount } from "../accounts/accounts.state" -import { TokenWithBalance, isEqualAddress } from "@argent/shared" +import { TokenWithBalance, isEqualAddress } from "@argent/x-shared" import { classHashSupportsTxV3, feeTokenNeedsTxV3Support, diff --git a/packages/extension/src/ui/features/actions/utils.test.ts b/packages/extension/src/ui/features/actions/utils.test.ts index 3ba67c12a..545ccb478 100644 --- a/packages/extension/src/ui/features/actions/utils.test.ts +++ b/packages/extension/src/ui/features/actions/utils.test.ts @@ -1,6 +1,5 @@ -import { Call, num } from "starknet" +import { Call } from "starknet" import { getV3UpgradeCall } from "./utils" -import { TXV3_ACCOUNT_CLASS_HASH } from "../../../shared/network/constants" describe("getV3UpgradeCall", () => { it("should return the first call that matches the condition", () => { diff --git a/packages/extension/src/ui/features/actions/warning/ConfirmationModal.tsx b/packages/extension/src/ui/features/actions/warning/ConfirmationModal.tsx index c0d2b8cd9..0838a2e53 100644 --- a/packages/extension/src/ui/features/actions/warning/ConfirmationModal.tsx +++ b/packages/extension/src/ui/features/actions/warning/ConfirmationModal.tsx @@ -1,4 +1,4 @@ -import { H5, P3 } from "@argent/ui" +import { H5, P3 } from "@argent/x-ui" import { Button, Modal, diff --git a/packages/extension/src/ui/features/actions/warning/ReviewFooter.tsx b/packages/extension/src/ui/features/actions/warning/ReviewFooter.tsx index c0a583873..dcd1b4e01 100644 --- a/packages/extension/src/ui/features/actions/warning/ReviewFooter.tsx +++ b/packages/extension/src/ui/features/actions/warning/ReviewFooter.tsx @@ -1,16 +1,16 @@ -import { P4 } from "@argent/ui" +import { P4 } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" export const ReviewFooter = () => { return ( - + Please review warnings before continuing diff --git a/packages/extension/src/ui/features/actions/warning/WarningBanner.tsx b/packages/extension/src/ui/features/actions/warning/WarningBanner.tsx index bc0d16b47..1d98b1cc7 100644 --- a/packages/extension/src/ui/features/actions/warning/WarningBanner.tsx +++ b/packages/extension/src/ui/features/actions/warning/WarningBanner.tsx @@ -1,7 +1,7 @@ import { Button, Flex, useDisclosure } from "@chakra-ui/react" import { Warning } from "../../../../shared/transactionReview/schema" import { riskToColorMap, riskToHeaderMap } from "./warningMap" -import { B2, L2 } from "@argent/ui" +import { B2, L2 } from "@argent/x-ui" import AlertFillIconWithHalo from "./AlertFillIconWithHalo" @@ -44,7 +44,7 @@ export const WarningBanner = ({ <> @@ -57,7 +57,7 @@ export const WarningBanner = ({ my={0.5} > {header} - {title} + {title} {highestSeverityWarning.severity !== "info" && ( diff --git a/packages/extension/src/ui/features/actions/warning/WarningModal.tsx b/packages/extension/src/ui/features/actions/warning/WarningModal.tsx index 7ea41d32c..e151fce62 100644 --- a/packages/extension/src/ui/features/actions/warning/WarningModal.tsx +++ b/packages/extension/src/ui/features/actions/warning/WarningModal.tsx @@ -1,4 +1,4 @@ -import { Button, icons, H6, B3, P4, L1 } from "@argent/ui" +import { Button, icons, H6, B3, P4, L1 } from "@argent/x-ui" import { Badge, Flex, diff --git a/packages/extension/src/ui/features/argentAccount/ArgentAccountBaseEmailScreen.tsx b/packages/extension/src/ui/features/argentAccount/ArgentAccountBaseEmailScreen.tsx index 92c5adfa6..0bef8d36b 100644 --- a/packages/extension/src/ui/features/argentAccount/ArgentAccountBaseEmailScreen.tsx +++ b/packages/extension/src/ui/features/argentAccount/ArgentAccountBaseEmailScreen.tsx @@ -9,7 +9,7 @@ import { NavigationContainer, icons, useToast, -} from "@argent/ui" +} from "@argent/x-ui" import { FC } from "react" import { useForm } from "react-hook-form" diff --git a/packages/extension/src/ui/features/argentAccount/ArgentAccountEmailScreen.tsx b/packages/extension/src/ui/features/argentAccount/ArgentAccountEmailScreen.tsx index 8ab870e28..065ec94bc 100644 --- a/packages/extension/src/ui/features/argentAccount/ArgentAccountEmailScreen.tsx +++ b/packages/extension/src/ui/features/argentAccount/ArgentAccountEmailScreen.tsx @@ -8,7 +8,6 @@ import { useRouteFlow, } from "../../routes" import { ArgentAccountBaseEmailScreen } from "../argentAccount/ArgentAccountBaseEmailScreen" -import { useShieldOnboardingTracking } from "../shield/useShieldTracking" export const ArgentAccountEmailScreen: FC = () => { const flow = useRouteFlow() @@ -16,22 +15,17 @@ export const ArgentAccountEmailScreen: FC = () => { const navigate = useNavigate() const returnTo = useReturnTo() - const { trackSuccess } = useShieldOnboardingTracking({ - stepId: "enterEmail", - }) - const onBack = useCallback(() => { navigate(returnTo ?? routes.accountTokens()) }, [navigate, returnTo]) const onEmailRequested = useCallback( (email: string) => { - void trackSuccess() if (accountAddress) { navigate(routes.shieldAccountOTP(accountAddress, email, flow)) } }, - [accountAddress, navigate, trackSuccess, flow], + [accountAddress, navigate, flow], ) return ( diff --git a/packages/extension/src/ui/features/argentAccount/ArgentAccountFeaturesList.tsx b/packages/extension/src/ui/features/argentAccount/ArgentAccountFeaturesList.tsx index 74d7c1eca..8f14083f4 100644 --- a/packages/extension/src/ui/features/argentAccount/ArgentAccountFeaturesList.tsx +++ b/packages/extension/src/ui/features/argentAccount/ArgentAccountFeaturesList.tsx @@ -1,4 +1,4 @@ -import { icons, H6 } from "@argent/ui" +import { icons, H6 } from "@argent/x-ui" import { FC } from "react" import { Flex, Text, Tooltip } from "@chakra-ui/react" diff --git a/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreen.tsx b/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreen.tsx index 9d98e1c69..40b756ca8 100644 --- a/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreen.tsx +++ b/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreen.tsx @@ -4,7 +4,7 @@ import { BarCloseButton, Input, H6, -} from "@argent/ui" +} from "@argent/x-ui" import { FC } from "react" import { Box, Button, Divider, Flex } from "@chakra-ui/react" import { ArgentAccountFeaturesList } from "./ArgentAccountFeaturesList" diff --git a/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreenContainer.tsx b/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreenContainer.tsx index b80aeb726..20fd247be 100644 --- a/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreenContainer.tsx +++ b/packages/extension/src/ui/features/argentAccount/ArgentAccountLoggedInScreenContainer.tsx @@ -7,7 +7,7 @@ import { ArgentAccountLoggedInScreen } from "./ArgentAccountLoggedInScreen" import { allAccountsWithGuardianView } from "../../views/account" import { useView } from "../../views/implementation/react" import { argentAccountService } from "../../services/argentAccount" -import { useToast } from "@argent/ui" +import { useToast } from "@argent/x-ui" import { useEmailPreferences } from "./hooks/useEmailPreferences" export const ArgentAccountLoggedInScreenContainer: FC = () => { diff --git a/packages/extension/src/ui/features/dev/DevUI.tsx b/packages/extension/src/ui/features/dev/DevUI.tsx index 7f3933a77..acc203240 100644 --- a/packages/extension/src/ui/features/dev/DevUI.tsx +++ b/packages/extension/src/ui/features/dev/DevUI.tsx @@ -9,7 +9,7 @@ import { } from "@chakra-ui/react" import { FC } from "react" -import { TabBarHeight } from "@argent/ui" +import { TabBarHeight } from "@argent/x-ui" import { useHardReload, useResetCache, diff --git a/packages/extension/src/ui/features/discover/AccountDiscoverScreen.tsx b/packages/extension/src/ui/features/discover/AccountDiscoverScreen.tsx index e54656e77..1f09c6245 100644 --- a/packages/extension/src/ui/features/discover/AccountDiscoverScreen.tsx +++ b/packages/extension/src/ui/features/discover/AccountDiscoverScreen.tsx @@ -1,4 +1,4 @@ -import { CellStack, Empty, H4, SpacerCell, icons } from "@argent/ui" +import { CellStack, Empty, H4, SpacerCell, icons } from "@argent/x-ui" import { Center } from "@chakra-ui/react" import { isEmpty } from "lodash-es" import { FC } from "react" diff --git a/packages/extension/src/ui/features/discover/ui/NewsItemCard.tsx b/packages/extension/src/ui/features/discover/ui/NewsItemCard.tsx index 4aeca9272..9b81be062 100644 --- a/packages/extension/src/ui/features/discover/ui/NewsItemCard.tsx +++ b/packages/extension/src/ui/features/discover/ui/NewsItemCard.tsx @@ -1,7 +1,7 @@ import { AspectRatio, Button, ButtonProps, Flex, Image } from "@chakra-ui/react" import { NewsItem } from "../../../../shared/discover/schema" import { FC } from "react" -import { H6, L2, P4 } from "@argent/ui" +import { H6, L2, P4 } from "@argent/x-ui" import { isEmpty } from "lodash-es" interface NewsItemCardProps extends ButtonProps { diff --git a/packages/extension/src/ui/features/discover/ui/NewsItemCardCollection.tsx b/packages/extension/src/ui/features/discover/ui/NewsItemCardCollection.tsx index 40b08f002..b010d389d 100644 --- a/packages/extension/src/ui/features/discover/ui/NewsItemCardCollection.tsx +++ b/packages/extension/src/ui/features/discover/ui/NewsItemCardCollection.tsx @@ -1,6 +1,6 @@ import { SimpleGrid } from "@chakra-ui/react" import { FC } from "react" -import { pluralise, daysBetween } from "@argent/shared" +import { pluralise, daysBetween } from "@argent/x-shared" import { NewsItem } from "../../../../shared/discover/schema" import { NewsItemCard } from "./NewsItemCard" diff --git a/packages/extension/src/ui/features/funding/FundingBridgeScreen.tsx b/packages/extension/src/ui/features/funding/FundingBridgeScreen.tsx index 58b993155..3f3936549 100644 --- a/packages/extension/src/ui/features/funding/FundingBridgeScreen.tsx +++ b/packages/extension/src/ui/features/funding/FundingBridgeScreen.tsx @@ -3,7 +3,7 @@ import { BarCloseButton, NavigationContainer, logos, -} from "@argent/ui" +} from "@argent/x-ui" import { FC } from "react" import { Navigate, useNavigate } from "react-router-dom" @@ -12,10 +12,9 @@ import { Option } from "../../components/Options" import { PageWrapper } from "../../components/Page" import { A } from "../../components/TrackingLink" import { routes } from "../../routes" -import { trackAddFundsService } from "../../services/analytics" import { selectedAccountView } from "../../views/account" import { useView } from "../../views/implementation/react" -import { isFeatureEnabled } from "@argent/shared" +import { isFeatureEnabled } from "@argent/x-shared" import { getLayerSwapUrl } from "./utils" import { Grid } from "@chakra-ui/react" @@ -54,11 +53,7 @@ export const FundingBridgeScreen: FC = () => { {bridgeUrl ? ( - + + + )} {BANXA_ENABLED && ( - + ) diff --git a/packages/extension/src/ui/features/funding/FundingScreen.tsx b/packages/extension/src/ui/features/funding/FundingScreen.tsx index 6e176eb92..f5c83d246 100644 --- a/packages/extension/src/ui/features/funding/FundingScreen.tsx +++ b/packages/extension/src/ui/features/funding/FundingScreen.tsx @@ -4,7 +4,7 @@ import { useToast, logos, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { FC } from "react" import { Link, Navigate, useLocation, useNavigate } from "react-router-dom" @@ -13,10 +13,9 @@ import { Option } from "../../components/Options" import { PageWrapper } from "../../components/Page" import { A } from "../../components/TrackingLink" import { routes } from "../../routes" -import { trackAddFundsService } from "../../services/analytics" import { selectedAccountView } from "../../views/account" import { useView } from "../../views/implementation/react" -import { isFeatureEnabled } from "@argent/shared" +import { isFeatureEnabled } from "@argent/x-shared" import { getLayerSwapUrl } from "./utils" import { FundingOnRampOption } from "./FundingOnRampOption" import { Grid } from "@chakra-ui/react" @@ -94,11 +93,7 @@ export const FundingScreen: FC = () => { /> {allowLayerswap && ( - + diff --git a/packages/extension/src/ui/features/multisig/MultisigSettingsWrapper.tsx b/packages/extension/src/ui/features/multisig/MultisigSettingsWrapper.tsx index b2f40dac0..7146b0736 100644 --- a/packages/extension/src/ui/features/multisig/MultisigSettingsWrapper.tsx +++ b/packages/extension/src/ui/features/multisig/MultisigSettingsWrapper.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, NavigationContainer } from "@argent/ui" +import { BarBackButton, NavigationContainer } from "@argent/x-ui" import { FC, PropsWithChildren, ReactNode, useCallback } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/multisig/MultisigTransactionConfirmationsScreen.tsx b/packages/extension/src/ui/features/multisig/MultisigTransactionConfirmationsScreen.tsx index d5aacb8ec..9148a6641 100644 --- a/packages/extension/src/ui/features/multisig/MultisigTransactionConfirmationsScreen.tsx +++ b/packages/extension/src/ui/features/multisig/MultisigTransactionConfirmationsScreen.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, H4, NavigationContainer, P3 } from "@argent/ui" +import { BarBackButton, H4, NavigationContainer, P3 } from "@argent/x-ui" import { Box, Divider } from "@chakra-ui/react" import { useMemo } from "react" @@ -15,10 +15,10 @@ import { useRouteAccount } from "../shield/useRouteAccount" import { useMultisig } from "./multisig.state" import { useMultisigPendingTransaction } from "./multisigTransactions.state" import { num } from "starknet" -import { isEqualAddress } from "@argent/shared" +import { isEqualAddress } from "@argent/x-shared" import { MultisigOwner } from "./MultisigOwner" import { useView } from "../../views/implementation/react" -import { creatorMultisigMetadataView } from "../../views/multisig" +import { publicKeyMultisigMetadataView } from "../../views/multisig" import { Navigate } from "react-router-dom" export const MultisigTransactionConfirmationsScreen = () => { @@ -30,7 +30,7 @@ export const MultisigTransactionConfirmationsScreen = () => { const encodedPubKey = useEncodedPublicKey(publicKey) const multisig = useMultisig(selectedAccount) - const multisigMetadata = useView(creatorMultisigMetadataView(multisig)) + const multisigMetadata = useView(publicKeyMultisigMetadataView(multisig)) const transactionTransformed = useMemo(() => { if (!pendingTransaction || !selectedAccount) { diff --git a/packages/extension/src/ui/features/multisig/NewMultisigScreen.tsx b/packages/extension/src/ui/features/multisig/NewMultisigScreen.tsx index 9c4e9d005..448a1b90a 100644 --- a/packages/extension/src/ui/features/multisig/NewMultisigScreen.tsx +++ b/packages/extension/src/ui/features/multisig/NewMultisigScreen.tsx @@ -1,4 +1,10 @@ -import { BarCloseButton, H6, NavigationContainer, P4, icons } from "@argent/ui" +import { + BarCloseButton, + H6, + NavigationContainer, + P4, + icons, +} from "@argent/x-ui" import { Center, Flex, Text } from "@chakra-ui/react" import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" @@ -49,7 +55,7 @@ export const NewMultisigScreen: FC = () => { goto: "multisig", networkId: switcherNetworkId, }) - chrome.tabs.create({ + void chrome.tabs.create({ url, }) navigate(routes.accounts()) @@ -85,7 +91,7 @@ export const NewMultisigScreen: FC = () => { gap={4} alignItems="center" border="1px solid" - borderColor="white30" + borderColor="white.30" mb={1} > @@ -105,7 +111,7 @@ export const NewMultisigScreen: FC = () => { alignItems="center" justifyContent="space-between" gap={3} - onClick={() => onClick(option.type)} + onClick={() => void onClick(option.type)} _hover={{ backgroundColor: "neutrals.700", "& > .icon-wrapper": { diff --git a/packages/extension/src/ui/features/multisig/PendingMultisigListItem.tsx b/packages/extension/src/ui/features/multisig/PendingMultisigListItem.tsx index a0a24bd8f..d7691a587 100644 --- a/packages/extension/src/ui/features/multisig/PendingMultisigListItem.tsx +++ b/packages/extension/src/ui/features/multisig/PendingMultisigListItem.tsx @@ -1,4 +1,4 @@ -import { H6, P4, icons, typographyStyles } from "@argent/ui" +import { H6, P4, icons, typographyStyles } from "@argent/x-ui" import { Circle, Flex, Text, chakra } from "@chakra-ui/react" import { FC } from "react" @@ -8,7 +8,7 @@ import { } from "../../components/CustomButtonCell" import { AccountAvatar } from "../accounts/AccountAvatar" import { getNetworkAccountImageUrl } from "../accounts/accounts.service" -import { formatTruncatedAddress } from "@argent/shared" +import { formatTruncatedAddress } from "@argent/x-shared" const { ViewIcon } = icons diff --git a/packages/extension/src/ui/features/multisig/PendingMultisigListScreenItem.tsx b/packages/extension/src/ui/features/multisig/PendingMultisigListScreenItem.tsx index 40ab00d2b..f0a01ad83 100644 --- a/packages/extension/src/ui/features/multisig/PendingMultisigListScreenItem.tsx +++ b/packages/extension/src/ui/features/multisig/PendingMultisigListScreenItem.tsx @@ -1,4 +1,4 @@ -import { Button, icons } from "@argent/ui" +import { Button, icons } from "@argent/x-ui" import { Circle, Flex } from "@chakra-ui/react" import { FC, MouseEvent, useCallback, useRef } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreen.tsx b/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreen.tsx index 2f0adb6f6..06e095699 100644 --- a/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreen.tsx +++ b/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreen.tsx @@ -1,10 +1,10 @@ -import { ButtonCell, CellStack, H6, P4, SpacerCell } from "@argent/ui" +import { ButtonCell, CellStack, H6, P4, SpacerCell } from "@argent/x-ui" import { Center, Flex, Image } from "@chakra-ui/react" import { FC, MouseEvent } from "react" import { getNetworkAccountImageUrl } from "../accounts/accounts.service" import { Multisig } from "./Multisig" -import { MultisigHideModal } from "./MultisigDeleteModal" +import { MultisigHideModal } from "./MultisigHideModal" export interface RemovedMultisigSettingsScreenProps { multisig: Multisig @@ -43,7 +43,7 @@ export const RemovedMultisigSettingsScreen: FC<
{accountName}
- + You were removed from this multisig
diff --git a/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreenContainer.tsx b/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreenContainer.tsx index 42de28070..66dba7e36 100644 --- a/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreenContainer.tsx +++ b/packages/extension/src/ui/features/multisig/RemovedMultisigSettingsScreenContainer.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, NavigationContainer } from "@argent/ui" +import { BarBackButton, NavigationContainer } from "@argent/x-ui" import { useDisclosure } from "@chakra-ui/react" import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/multisig/ReplaceOwnerForm.tsx b/packages/extension/src/ui/features/multisig/ReplaceOwnerForm.tsx index f6dbb50ee..b1ad2c671 100644 --- a/packages/extension/src/ui/features/multisig/ReplaceOwnerForm.tsx +++ b/packages/extension/src/ui/features/multisig/ReplaceOwnerForm.tsx @@ -1,4 +1,4 @@ -import { FieldError, P3 } from "@argent/ui" +import { FieldError, P3 } from "@argent/x-ui" import { Box, Flex, Input, InputGroup } from "@chakra-ui/react" import { useFormContext } from "react-hook-form" @@ -30,6 +30,16 @@ export const ReplaceOwnerForm = ({ New owner + + + { + vi.spyOn(baseMultisigModule, "getBaseMultisigAccounts").mockReturnValue( + Promise.resolve([]), + ) + vi.spyOn( + accountMessagingService, + "getPublicKeysBufferForMultisig", + ).mockReturnValue(Promise.resolve([])) +}) + +describe("CreateMultisigFormSchema", () => { + const validSchema = { + signerKeys: [ + { + key: "WboHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H", + name: "Owner 1", + }, + { + key: "AboHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H", + name: "Owner 2", + }, + { + key: "BboHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H", + }, + ], + confirmations: 1, + } + + it("validates valid schema", async () => { + const result = await FormSchema.safeParseAsync(validSchema) + expect(result.success).toBe(true) + }) + + it("validates invalid signerKeys", async () => { + const invalidSchema = JSON.parse(JSON.stringify(validSchema)) + invalidSchema.signerKeys.push({ key: "foo" }) + + const result = await FormSchema.safeParseAsync(invalidSchema) + expect(result.success).toBe(false) + + if (!result.success) { + expect(result.error).toBeInstanceOf(z.ZodError) + expect(result.error.errors[0].message).toBe("Incorrect signer pubkey") + } + }) + + it("validates duplicate signerKeys", async () => { + const invalidSchema = JSON.parse(JSON.stringify(validSchema)) + invalidSchema.signerKeys.push({ + key: "BboHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H", + }) + + const result = await FormSchema.safeParseAsync(invalidSchema) + expect(result.success).toBe(false) + + if (!result.success) { + expect(result.error).toBeInstanceOf(z.ZodError) + expect(result.error.errors[0].message).toBe( + "You cannot use the same key twice", + ) + } + }) + + it("validates duplicate name", async () => { + const invalidSchema = JSON.parse(JSON.stringify(validSchema)) + invalidSchema.signerKeys[2].name = "Owner 1" + const result = await FormSchema.safeParseAsync(invalidSchema) + expect(result.success).toBe(false) + + if (!result.success) { + expect(result.error).toBeInstanceOf(z.ZodError) + expect(result.error.errors[0].message).toBe( + "You cannot use the same name twice", + ) + } + }) + + it("validates invalid confirmations", async () => { + const invalidSchema = JSON.parse(JSON.stringify(validSchema)) + invalidSchema.confirmations = 6 + const result = await FormSchema.safeParseAsync(invalidSchema) + expect(result.success).toBe(false) + + if (!result.success) { + expect(result.error).toBeInstanceOf(z.ZodError) + expect(result.error.errors[0].message).toBe( + "Confirmations should be less than or equal to signer pubkeys", + ) + } + }) +}) + +describe("useCreateMultisigForm", () => { + const TOTAL_OWNERS = 3 + + const setup = ( + jsx: ReactElement>, + ) => { + return { + user: userEvent.setup(), + ...render(jsx), + } + } + + describe("create a component that has a form and uses useCreateMultisigForm hook", async () => { + const Component = () => { + const signerKey = "EroHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H" + + const { + register, + trigger, + formState: { errors }, + } = useCreateMultisigForm(signerKey) + + return ( +
void trigger("signerKeys")}> + Add owners + {Array.from({ length: TOTAL_OWNERS }).map((_, index) => { + return ( + + + + + + {errors.signerKeys?.[index]?.name && ( + + {errors.signerKeys?.[index]?.key?.message} + + )} + + + + + + + {errors.signerKeys?.[index]?.key && ( + + {errors.signerKeys?.[index]?.key?.message} + + )} + + + ) + })} + {errors.signerKeys && !Array.isArray(errors.signerKeys) && ( + + {errors.signerKeys.message} + + )} + +
+ ) + } + + it("validates the form and there are no errors", async () => { + const { user } = setup() + // test that the form is rendered + expect(screen.getByText("Add owners")).toBeInTheDocument() + expect(await screen.findByText("validate")).toBeInTheDocument() + + for (let i = 0; i < TOTAL_OWNERS; i++) { + await user.type(screen.getByLabelText(`input-name-${i}`), `Owner ${i}`) + await user.type( + screen.getByLabelText(`input-key-${i}`), + `${i}roHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H`, + ) + } + + await user.click(screen.getByRole("button")) + + expect( + screen.queryAllByLabelText("error-name-", { exact: false }), + ).toHaveLength(0) + + expect( + screen.queryAllByLabelText("error-key-", { exact: false }), + ).toHaveLength(0) + }) + + it("displays error invalid signer keys", async () => { + const { user } = setup() + // test that the form is rendered + expect(screen.getByText("Add owners")).toBeInTheDocument() + expect(await screen.findByText("validate")).toBeInTheDocument() + + for (let i = 0; i < TOTAL_OWNERS; i++) { + await user.type(screen.getByLabelText(`input-name-${i}`), `Owner ${i}`) + await user.type( + screen.getByLabelText(`input-key-${i}`), + `${i}roHR2jHcDb`, + ) + } + + await user.click(screen.getByRole("button")) + + expect( + screen.queryAllByLabelText("error-name-", { exact: false }), + ).toHaveLength(0) + + const keyErrors = screen.queryAllByLabelText("error-key-", { + exact: false, + }) + expect(keyErrors).toHaveLength(TOTAL_OWNERS) + Array.from({ length: TOTAL_OWNERS }).forEach((_, i) => { + expect(keyErrors[i]).toHaveTextContent("Incorrect signer pubkey") + }) + }) + + it("displays error duplicate signer keys", async () => { + const { user } = setup() + // test that the form is rendered + expect(screen.getByText("Add owners")).toBeInTheDocument() + expect(await screen.findByText("validate")).toBeInTheDocument() + + for (let i = 0; i < TOTAL_OWNERS; i++) { + await user.type(screen.getByLabelText(`input-name-${i}`), `Owner ${i}`) + await user.type( + screen.getByLabelText(`input-key-${i}`), + `WboHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H`, + ) + } + + await user.click(screen.getByRole("button")) + + expect( + screen.queryAllByLabelText("error-name-", { exact: false }), + ).toHaveLength(0) + expect( + screen.queryAllByLabelText("error-key-", { exact: false }), + ).toHaveLength(0) + + expect(await screen.findByLabelText("custom-error")).toHaveTextContent( + "You cannot use the same key twice", + ) + }) + + it("displays error duplicate signer names", async () => { + const { user } = setup() + // test that the form is rendered + expect(screen.getByText("Add owners")).toBeInTheDocument() + expect(await screen.findByText("validate")).toBeInTheDocument() + + for (let i = 0; i < TOTAL_OWNERS; i++) { + await user.type(screen.getByLabelText(`input-name-${i}`), `Owner`) + await user.type( + screen.getByLabelText(`input-key-${i}`), + `${i}roHR2jHcDboaEs6kfZcnbbA8UKLVmrs3KAbakj6r7H`, + ) + } + + await user.click(screen.getByRole("button")) + + expect( + screen.queryAllByLabelText("error-name-", { exact: false }), + ).toHaveLength(0) + expect( + screen.queryAllByLabelText("error-key-", { exact: false }), + ).toHaveLength(0) + + expect(await screen.findByLabelText("custom-error")).toHaveTextContent( + "You cannot use the same name twice", + ) + }) + }) +}) diff --git a/packages/extension/src/ui/features/multisig/hooks/useCreateMultisigForm.ts b/packages/extension/src/ui/features/multisig/hooks/useCreateMultisigForm.ts index 9cef041a2..7bc881700 100644 --- a/packages/extension/src/ui/features/multisig/hooks/useCreateMultisigForm.ts +++ b/packages/extension/src/ui/features/multisig/hooks/useCreateMultisigForm.ts @@ -3,7 +3,7 @@ import { useForm } from "react-hook-form" import { z } from "zod" import { accountMessagingService } from "../../../services/accountMessaging" import { getBaseMultisigAccounts } from "../../../../shared/multisig/utils/baseMultisig" -import { encodeBase58Array } from "@argent/shared" +import { encodeBase58Array } from "@argent/x-shared" import { pubkeySchema } from "../../../../shared/multisig/multisig.model" export const confirmationsSchema = z @@ -18,6 +18,7 @@ const getFormSchema = (accountSignerKey?: string, isNewMultisig = true) => signerKeys: z .object({ key: pubkeySchema, + name: z.string().optional(), }) .array() .min(isNewMultisig ? 0 : 1, "You need at least one signer") @@ -33,12 +34,25 @@ const getFormSchema = (accountSignerKey?: string, isNewMultisig = true) => { message: "You cannot use the same key twice", }, + ) + .refine( + (arr) => { + const nonEmptyNames = arr.map((item) => item.name).filter(Boolean) + const uniqueValues = new Set( + nonEmptyNames.map((name) => name?.toLowerCase()), + ) + return uniqueValues.size === nonEmptyNames.length + }, + { + message: "You cannot use the same name twice", + }, ), confirmations: confirmationsSchema, }) .refine( async (data) => { const baseMultisigs = await getBaseMultisigAccounts() + const bufferedPubKeys = await accountMessagingService.getPublicKeysBufferForMultisig( 0, @@ -70,6 +84,11 @@ export type FieldValuesCreateMultisigForm = z.infer< ReturnType > +export const CreateMultisigFormSchema = ( + accountSignerKey?: string, + isNewMultisig = true, +) => getFormSchema(accountSignerKey, isNewMultisig) + export const useCreateMultisigForm = (accountSignerKey?: string) => { return useForm({ resolver: zodResolver(getFormSchema(accountSignerKey), { diff --git a/packages/extension/src/ui/features/multisig/hooks/useReplaceOwnerForm.ts b/packages/extension/src/ui/features/multisig/hooks/useReplaceOwnerForm.ts index 5ceb4769d..20a4f70cc 100644 --- a/packages/extension/src/ui/features/multisig/hooks/useReplaceOwnerForm.ts +++ b/packages/extension/src/ui/features/multisig/hooks/useReplaceOwnerForm.ts @@ -5,6 +5,7 @@ import { pubkeySchema } from "../../../../shared/multisig/multisig.model" const FormSchema = z.object({ signerKey: pubkeySchema, + name: z.string().optional(), }) export type FieldValuesReplaceOwnerForm = z.infer diff --git a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcher.test.tsx b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcher.test.tsx index a1061b4c7..b8441efb2 100644 --- a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcher.test.tsx +++ b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcher.test.tsx @@ -2,8 +2,8 @@ import { Menu } from "@chakra-ui/react" import { render, screen, within } from "@testing-library/react" import userEvent from "@testing-library/user-event" -import { Network, NetworkStatus } from "../../../../shared/network" -import { statusMapping } from "../../../components/StatusIndicator" +import { Network, ColorStatus } from "../../../../shared/network" +import { networkStatusMapping } from "../../../components/StatusIndicator" import { NetworkSwitcherList } from "./NetworkSwitcherList" export const mockNetworks = [ @@ -28,13 +28,13 @@ export const mockNetworks = [ chainId: "chainId", status: "red", }, -] as (Network & { status: NetworkStatus })[] +] as (Network & { status: ColorStatus })[] const mockNetworkStatuses = { "1": "green", "2": "amber", "3": "red", -} as Partial> +} as Partial> const mockCurrentNetwork = mockNetworks[0] @@ -93,7 +93,7 @@ describe("NetworkSwitcherList", () => { const networkStatus = mockNetworkStatuses[id] const statusIndicator = screen.getByTestId( `status-indicator-${ - statusMapping[networkStatus as NetworkStatus].color + networkStatusMapping[networkStatus as ColorStatus].color }`, ) diff --git a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherButton.tsx b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherButton.tsx index 492d29e85..50920df25 100644 --- a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherButton.tsx +++ b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherButton.tsx @@ -1,12 +1,12 @@ import { Button, ButtonProps, MenuButton } from "@chakra-ui/react" import { FC } from "react" -import { Network, NetworkStatus } from "../../../../shared/network" +import { Network, ColorStatus } from "../../../../shared/network" import { StatusIndicator } from "../../../components/StatusIndicator" interface NetworkSwitcherButtonProps extends ButtonProps { disabled?: boolean - currentNetworkStatus: NetworkStatus + currentNetworkStatus: ColorStatus currentNetwork: Network } diff --git a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherContainer.tsx b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherContainer.tsx index e57ac11e0..e9045641d 100644 --- a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherContainer.tsx +++ b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherContainer.tsx @@ -4,14 +4,10 @@ import { Portal, usePrefersReducedMotion, } from "@chakra-ui/react" -import { FC, Fragment, useCallback, useEffect } from "react" -import { useLocation, useNavigate } from "react-router-dom" +import { FC, Fragment, useCallback } from "react" -import { NetworkStatus } from "../../../../shared/network" -import { routes } from "../../../routes" import { autoSelectAccountOnNetwork } from "../../accounts/switchAccount" import { useCurrentNetworkWithStatus } from "../hooks/useCurrentNetwork" -import { useNeedsToShowNetworkStatusWarning } from "../hooks/useNeedsToShowNetworkStatusWarning" import { useNetworksWithStatuses } from "../hooks/useNetworks" import { NetworkSwitcherButton } from "./NetworkSwitcherButton" import { @@ -19,8 +15,6 @@ import { NetworkSwitcherListProps, } from "./NetworkSwitcherList" -const valuesToShowNetwortWarning: Array = ["red", "amber"] - interface NetworkSwitcherProps extends ButtonProps { disabled?: boolean } @@ -29,24 +23,10 @@ export const NetworkSwitcherContainer: FC = ({ disabled, ...rest }) => { - const navigate = useNavigate() - const location = useLocation() const allNetworksWithStatuses = useNetworksWithStatuses() const currentNetwork = useCurrentNetworkWithStatus() - const [needsToShowNetworkStatusWarning] = useNeedsToShowNetworkStatusWarning() const currentNetworkStatus = currentNetwork?.status ?? "unknown" - useEffect(() => { - if ( - currentNetworkStatus && - valuesToShowNetwortWarning.includes(currentNetworkStatus) && - needsToShowNetworkStatusWarning - ) { - navigate(routes.networkWarning(location.pathname)) - } - // just trigger on network status change - }, [currentNetworkStatus]) // eslint-disable-line react-hooks/exhaustive-deps - const onChangeNetwork = useCallback(async (networkId: string) => { await autoSelectAccountOnNetwork(networkId) }, []) diff --git a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherList.tsx b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherList.tsx index 4afe482a6..1c36d948e 100644 --- a/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherList.tsx +++ b/packages/extension/src/ui/features/networks/NetworkSwitcher/NetworkSwitcherList.tsx @@ -1,13 +1,13 @@ -import { B3, L2 } from "@argent/ui" +import { B3, L2 } from "@argent/x-ui" import { Flex, MenuItem, MenuList, MenuListProps } from "@chakra-ui/react" import { FC } from "react" -import { Network, NetworkStatus } from "../../../../shared/network" +import { Network, ColorStatus } from "../../../../shared/network" import { StatusIndicator } from "../../../components/StatusIndicator" export interface NetworkSwitcherListProps extends MenuListProps { currentNetwork: Network - allNetworks: (Network & { status: NetworkStatus })[] + allNetworks: (Network & { status: ColorStatus })[] onChangeNetwork: (id: string) => void } diff --git a/packages/extension/src/ui/features/networks/NetworkWarningScreen/NetworkWarningScreen.tsx b/packages/extension/src/ui/features/networks/NetworkWarningScreen/NetworkWarningScreen.tsx index 7139e1487..f275b7a6d 100644 --- a/packages/extension/src/ui/features/networks/NetworkWarningScreen/NetworkWarningScreen.tsx +++ b/packages/extension/src/ui/features/networks/NetworkWarningScreen/NetworkWarningScreen.tsx @@ -1,4 +1,4 @@ -import { H3, P3, icons } from "@argent/ui" +import { H3, P3, icons } from "@argent/x-ui" import { Button, Center, Circle, Text } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/networks/hooks/useNeedsToShowNetworkStatusWarning.ts b/packages/extension/src/ui/features/networks/hooks/useNeedsToShowNetworkStatusWarning.ts index be9527020..54e7fb362 100644 --- a/packages/extension/src/ui/features/networks/hooks/useNeedsToShowNetworkStatusWarning.ts +++ b/packages/extension/src/ui/features/networks/hooks/useNeedsToShowNetworkStatusWarning.ts @@ -19,6 +19,7 @@ const useSeenNetworkStatus = create()( ), ) +/** Not used anymore. We used to show a banner when the network is slow */ export const useNeedsToShowNetworkStatusWarning = () => { const { lastSeen, updateLastSeen } = useSeenNetworkStatus() diff --git a/packages/extension/src/ui/features/onboarding/OnboardingFinishScreen.tsx b/packages/extension/src/ui/features/onboarding/OnboardingFinishScreen.tsx index 57351640d..0623ed670 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingFinishScreen.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingFinishScreen.tsx @@ -1,4 +1,4 @@ -import { icons, logos } from "@argent/ui" +import { icons, logos } from "@argent/x-ui" import { Circle, SimpleGrid } from "@chakra-ui/react" import { FC, ReactEventHandler } from "react" @@ -20,8 +20,8 @@ export const OnboardingFinishScreen: FC = ({ useOnboardingToastMessage() return ( } diff --git a/packages/extension/src/ui/features/onboarding/OnboardingFinishScreenContainer.tsx b/packages/extension/src/ui/features/onboarding/OnboardingFinishScreenContainer.tsx index 8c3c97035..abde19190 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingFinishScreenContainer.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingFinishScreenContainer.tsx @@ -4,12 +4,12 @@ import { FC, useCallback, useEffect } from "react" import { OnboardingFinishScreen } from "./OnboardingFinishScreen" import { lastLegalAgreementTimestampAtom } from "../legal/legalStorage" import { useAtom } from "jotai" +import { analyticsService } from "../../../shared/analytics" export const OnboardingFinishScreenContainer: FC = () => { - // const { trackSuccess } = useTimeSpentWithSuccessTracking( - // "onboardingStepFinished", - // { stepId: "finish" }, - // ) + useEffect(() => { + analyticsService.onboardingCompleted({ "account type": "standard" }) + }, []) const [, setLastLegalAgreementTimestamp] = useAtom( lastLegalAgreementTimestampAtom, diff --git a/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreen.tsx b/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreen.tsx index 84a46f5f0..3460d19b8 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreen.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreen.tsx @@ -8,7 +8,7 @@ import { AllowPromise } from "../../../shared/storage/types" import { ControlledInput } from "../../components/ControlledInput" import { OnboardingButton } from "./ui/OnboardingButton" import { OnboardingScreen } from "./ui/OnboardingScreen" -import { PasswordStrengthIndicator } from "@argent/ui" +import { PasswordStrengthIndicator } from "@argent/x-ui" const MIN_PASSWORD_LENGTH = 8 const setPasswordFormSchema = z @@ -37,6 +37,8 @@ export interface OnboardingPasswordScreenProps { } onSubmit: (password: string) => AllowPromise onBack?: MouseEventHandler + length?: number + currentIndex?: number } export const OnboardingPasswordScreen: FC = ({ @@ -44,6 +46,8 @@ export const OnboardingPasswordScreen: FC = ({ submitText, onBack, onSubmit, + length, + currentIndex, }) => { const { control, @@ -65,8 +69,8 @@ export const OnboardingPasswordScreen: FC = ({ errors.root?.message ? submitText?.retryAfterError ?? "Retry create wallet" : isSubmitting - ? submitText?.submitting ?? "Creating wallet…" - : submitText?.start ?? "Create wallet", + ? submitText?.submitting ?? "Creating wallet…" + : submitText?.start ?? "Create wallet", [isSubmitting, errors.root?.message, submitText], ) @@ -81,8 +85,8 @@ export const OnboardingPasswordScreen: FC = ({ return ( diff --git a/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreenContainer.tsx b/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreenContainer.tsx index 86159633e..f5161860f 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreenContainer.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingPasswordScreenContainer.tsx @@ -1,20 +1,14 @@ -import { useNavigateBack } from "@argent/ui" +import { useNavigateBack } from "@argent/x-ui" import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" import { defaultNetwork } from "../../../shared/network" import { routes } from "../../routes" import { clientAccountService } from "../../services/account" -import { analytics } from "../../services/analytics" import { OnboardingPasswordScreen } from "./OnboardingPasswordScreen" import { sessionService } from "../../services/session" export const OnboardingPasswordScreenContainer: FC = () => { - // const { trackSuccess } = useTimeSpentWithSuccessTracking( - // "onboardingStepFinished", - // { stepId: "newWalletPassword" }, - // ) - const navigate = useNavigate() const onBack = useNavigateBack() @@ -22,41 +16,18 @@ export const OnboardingPasswordScreenContainer: FC = () => { // we should still get rid of useAppState and any generic global state const networkId = defaultNetwork.id - // NOTE: I (@janek26) think we can get rid of the try/catch quite easily (see further comments), which would make this container a lot cleaner const handleDeploy = useCallback( async (password: string) => { - try { - await sessionService.startSession(password) - - const newAccount = await clientAccountService.create( - "standard", - networkId, - ) - - await clientAccountService.select(newAccount) + await sessionService.startSession(password) - // TBD: duplication of "createAccount" which comes from BG? - void analytics.track("createWallet", { - status: "success", - networkId: newAccount.networkId, - }) - // NOTE: this tracking call is legit, as it relies on information that's only accessable to the UI - // NOTE: we're not interested in the return of this promise, we should indicate that with void - // void trackSuccess() // TODO: temporary disabled + const newAccount = await clientAccountService.create( + "standard", + networkId, + ) - // NOTE: return the navigate promise, to make sure the form waits for it to finish - return navigate(routes.onboardingFinish.path, { replace: true }) - } catch (error: any) { - // TBD: duplication of "createAccount" which comes from BG? - void analytics.track("createWallet", { - status: "failure", - errorMessage: error.message, - networkId: networkId, - }) + await clientAccountService.select(newAccount) - // NOTE: by throwing the error in the submit, the form will handle that and show the retry button message to the user - throw error - } + return navigate(routes.onboardingFinish.path, { replace: true }) }, [navigate, networkId], ) diff --git a/packages/extension/src/ui/features/onboarding/OnboardingPrivacyScreen.tsx b/packages/extension/src/ui/features/onboarding/OnboardingPrivacyScreen.tsx new file mode 100644 index 000000000..b70a2341c --- /dev/null +++ b/packages/extension/src/ui/features/onboarding/OnboardingPrivacyScreen.tsx @@ -0,0 +1,76 @@ +import { P4, icons } from "@argent/x-ui" +import { Button, Flex, Link } from "@chakra-ui/react" +import { FC, MouseEventHandler } from "react" + +import { OnboardingScreen } from "./ui/OnboardingScreen" +import { ARGENT_X_LEGAL_PRIVACY_POLICY_URL } from "../../../shared/api/constants" + +const { TickIcon } = icons + +interface OnboardingStartScreenProps { + onAccept: MouseEventHandler + onRefuse: MouseEventHandler + onBack: () => void + length?: number +} + +export const PrivacyScreen: FC = ({ + onAccept, + onRefuse, + onBack, + length, +}) => { + return ( + + + + + Opt-out at any time via settings + + + + Send anonymized clicks and pageview events + + + + We never sell your data! + + + + Privacy Policy + + + + + + + ) +} diff --git a/packages/extension/src/ui/features/onboarding/OnboardingPrivacyScreenContainer.tsx b/packages/extension/src/ui/features/onboarding/OnboardingPrivacyScreenContainer.tsx new file mode 100644 index 000000000..e4ab7af0c --- /dev/null +++ b/packages/extension/src/ui/features/onboarding/OnboardingPrivacyScreenContainer.tsx @@ -0,0 +1,36 @@ +import { useNavigateBack } from "@argent/x-ui" +import { FC } from "react" +import { useNavigate, useParams } from "react-router-dom" + +import { routes } from "../../routes" +import { PrivacyScreen } from "./OnboardingPrivacyScreen" +import { clientAccountService } from "../../services/account" + +export const OnboardingPrivacyScreenContainer: FC = () => { + const navigate = useNavigate() + const onBack = useNavigateBack() + const { path } = useParams() + const navigateToNextScreen = () => { + if (path === "password") { + void navigate(routes.onboardingPassword()) + } else { + void navigate(routes.onboardingRestoreSeed()) + } + } + const handleRefuse = () => { + void clientAccountService.refuseTerms() + navigateToNextScreen() + } + const handleAccept = () => { + void clientAccountService.acceptTerms() + navigateToNextScreen() + } + return ( + + ) +} diff --git a/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreen.tsx b/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreen.tsx index d4eb88512..3df4eaee7 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreen.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreen.tsx @@ -1,4 +1,4 @@ -import { H6 } from "@argent/ui" +import { H6 } from "@argent/x-ui" import { Center, chakra } from "@chakra-ui/react" import { FC, MouseEventHandler, useCallback } from "react" import { useDropzone } from "react-dropzone" @@ -45,7 +45,7 @@ export const OnboardingRestoreBackupScreen: FC< p={8} bg={"black"} border={"2px dashed"} - borderColor={"white50"} + borderColor={"white.50"} rounded={"lg"} w={"full"} h={"256px"} diff --git a/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreenContainer.tsx b/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreenContainer.tsx index 9749d2043..a76f48890 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreenContainer.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingRestoreBackupScreenContainer.tsx @@ -1,5 +1,5 @@ // TBD: should we get rid of the whole file? We dont use files anymore since a long time as a backup method. Would this be part of the refactor to drop such parts of the app? As it changes functionality -import { useNavigateBack } from "@argent/ui" +import { useNavigateBack } from "@argent/x-ui" import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/onboarding/OnboardingRestorePasswordScreenContainer.tsx b/packages/extension/src/ui/features/onboarding/OnboardingRestorePasswordScreenContainer.tsx index 8f638cf84..97c9588d6 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingRestorePasswordScreenContainer.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingRestorePasswordScreenContainer.tsx @@ -1,4 +1,4 @@ -import { useNavigateBack, useToast } from "@argent/ui" +import { useNavigateBack, useToast } from "@argent/x-ui" import { FC, useCallback, useMemo } from "react" import { useNavigate } from "react-router-dom" @@ -98,6 +98,8 @@ export const OnboardingRestorePasswordScreenContainer: FC = () => { }} onSubmit={handleSubmit} onBack={onBack} + length={5} + currentIndex={3} /> ) } diff --git a/packages/extension/src/ui/features/onboarding/OnboardingRestoreSeedScreen.tsx b/packages/extension/src/ui/features/onboarding/OnboardingRestoreSeedScreen.tsx index 1f6414d51..8a4d227c6 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingRestoreSeedScreen.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingRestoreSeedScreen.tsx @@ -1,5 +1,5 @@ -import { seedphraseSchema } from "@argent/shared" -import { Alert, B3, FieldError, SeedInput, icons } from "@argent/ui" +import { seedphraseSchema } from "@argent/x-shared" +import { Alert, B3, FieldError, SeedInput, icons } from "@argent/x-ui" import { Flex, chakra } from "@chakra-ui/react" import { zodResolver } from "@hookform/resolvers/zod" import { FC, MouseEventHandler } from "react" @@ -47,8 +47,8 @@ export const OnboardingRestoreSeedScreen: FC< return ( { - // const { trackSuccess } = useTimeSpentWithSuccessTracking( - // "onboardingStepFinished", - // { stepId: "restoreSeedphrase" }, - // ) const customNavigate = useCustomNavigate() const onBack = useNavigateBack() const onRestore = useCallback( async (seedPhrase: string) => { - // seedPhrase was already validated in the OnboardingRestoreSeedScreen form and will be validated again in the BG - useSeedRecovery.setState({ seedPhrase }) // set to temorary state, so we can access it after the next screen - // void trackSuccess() // TODO: temporary disabled + useSeedRecovery.setState({ seedPhrase }) + await customNavigate(routes.onboardingRestorePassword()) }, [customNavigate], diff --git a/packages/extension/src/ui/features/onboarding/OnboardingStartScreen.tsx b/packages/extension/src/ui/features/onboarding/OnboardingStartScreen.tsx index 86a0f7b4e..a55128f51 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingStartScreen.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingStartScreen.tsx @@ -1,4 +1,4 @@ -import { P4, icons } from "@argent/ui" +import { P4, icons } from "@argent/x-ui" import { Circle, Flex, Link, SimpleGrid } from "@chakra-ui/react" import { FC, MouseEventHandler } from "react" @@ -24,7 +24,7 @@ export const OnboardingStartScreen: FC = ({ }) => { return ( = ({ alignItems={"center"} px={4} py={3} - bg={"surface.elevated"} + bg={"surface-elevated"} rounded={"lg"} w={"full"} > diff --git a/packages/extension/src/ui/features/onboarding/OnboardingStartScreenContainer.tsx b/packages/extension/src/ui/features/onboarding/OnboardingStartScreenContainer.tsx index 9a3fbc2db..9898e5f5f 100644 --- a/packages/extension/src/ui/features/onboarding/OnboardingStartScreenContainer.tsx +++ b/packages/extension/src/ui/features/onboarding/OnboardingStartScreenContainer.tsx @@ -2,25 +2,19 @@ import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" import { routes } from "../../routes" -// import { useTimeSpentWithSuccessTracking } from "../../services/analytics" import { OnboardingStartScreen } from "./OnboardingStartScreen" +import { analyticsService } from "../../../shared/analytics" export const OnboardingStartScreenContainer: FC = () => { - // const { trackSuccess } = useTimeSpentWithSuccessTracking( - // "onboardingStepFinished", - // { stepId: "welcome" }, - // ) - const navigate = useNavigate() const onCreate = useCallback(() => { - // void trackSuccess() - void navigate(routes.onboardingPassword()) + analyticsService.onboardingStarted() + void navigate(routes.onboardingPrivacy("password")) }, [navigate]) const onRestore = useCallback(() => { - // void trackSuccess() // NOTE: there is nothing different between restore and create, so we track the same event? - void navigate(routes.onboardingRestoreSeed()) + void navigate(routes.onboardingPrivacy("seedphrase")) }, [navigate]) return diff --git a/packages/extension/src/ui/features/onboarding/ui/OnboardingButton.tsx b/packages/extension/src/ui/features/onboarding/ui/OnboardingButton.tsx index b4c054ce4..a2472c8f8 100644 --- a/packages/extension/src/ui/features/onboarding/ui/OnboardingButton.tsx +++ b/packages/extension/src/ui/features/onboarding/ui/OnboardingButton.tsx @@ -1,4 +1,4 @@ -import { Button } from "@argent/ui" +import { Button } from "@argent/x-ui" import { ComponentProps, FC } from "react" export const OnboardingButton: FC> = (props) => { diff --git a/packages/extension/src/ui/features/onboarding/ui/OnboardingCheckbox.tsx b/packages/extension/src/ui/features/onboarding/ui/OnboardingCheckbox.tsx index def7968f7..32d657a64 100644 --- a/packages/extension/src/ui/features/onboarding/ui/OnboardingCheckbox.tsx +++ b/packages/extension/src/ui/features/onboarding/ui/OnboardingCheckbox.tsx @@ -1,4 +1,4 @@ -import { P3, icons } from "@argent/ui" +import { P3, icons } from "@argent/x-ui" import { Flex, FormLabel, diff --git a/packages/extension/src/ui/features/onboarding/ui/OnboardingRectButton.tsx b/packages/extension/src/ui/features/onboarding/ui/OnboardingRectButton.tsx index b35366b71..ec6754bdc 100644 --- a/packages/extension/src/ui/features/onboarding/ui/OnboardingRectButton.tsx +++ b/packages/extension/src/ui/features/onboarding/ui/OnboardingRectButton.tsx @@ -1,4 +1,4 @@ -import { Button } from "@argent/ui" +import { Button } from "@argent/x-ui" import { ComponentProps, FC } from "react" export const OnboardingRectButton: FC> = ( diff --git a/packages/extension/src/ui/features/onboarding/ui/OnboardingScreen.tsx b/packages/extension/src/ui/features/onboarding/ui/OnboardingScreen.tsx index 01263427f..b557084a4 100644 --- a/packages/extension/src/ui/features/onboarding/ui/OnboardingScreen.tsx +++ b/packages/extension/src/ui/features/onboarding/ui/OnboardingScreen.tsx @@ -1,4 +1,4 @@ -import { Button, H2, P3, icons, logos } from "@argent/ui" +import { Button, H2, P3, icons, logos } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { isNumber } from "lodash-es" import { FC, MouseEventHandler, PropsWithChildren, ReactNode } from "react" diff --git a/packages/extension/src/ui/features/onboarding/ui/OnboardingToastMessage.tsx b/packages/extension/src/ui/features/onboarding/ui/OnboardingToastMessage.tsx index 566676a3a..902eb9511 100644 --- a/packages/extension/src/ui/features/onboarding/ui/OnboardingToastMessage.tsx +++ b/packages/extension/src/ui/features/onboarding/ui/OnboardingToastMessage.tsx @@ -1,4 +1,4 @@ -import { H6, P3, icons, logos } from "@argent/ui" +import { H6, P3, icons, logos } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/provision/ProvisionAnnouncement.tsx b/packages/extension/src/ui/features/provision/ProvisionAnnouncement.tsx deleted file mode 100644 index 8049ef7f8..000000000 --- a/packages/extension/src/ui/features/provision/ProvisionAnnouncement.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { - BarCloseButton, - NavigationBar, - ScrollContainer, - H3, - P3, - Button, -} from "@argent/ui" -import { default as ProvisionLogo } from "./provisionAsset.svg" -import { Flex } from "@chakra-ui/react" - -import { provisionAnnouncementStore } from "../../services/provision/provision.state" -import { useNavigate } from "react-router-dom" -import { routes } from "../../routes" -import { WalletAccount } from "../../../shared/wallet.model" - -type ProvisionAnnouncementProps = { - account: WalletAccount -} - -export const ProvisionAnnouncement = ({ - account, -}: ProvisionAnnouncementProps) => { - const navigate = useNavigate() - - const onClose = () => { - void provisionAnnouncementStore.set({ - [account.address]: Date.now(), - }) - - navigate(routes.accountTokens()) - } - - const text = `Just claimed my STRK with @argenthq on Starknet 🚀` - // randomly 1 2 or 3 - const number = Math.ceil(Math.random() * 3) - const imageUrl = `https://static.argent.net/tweets/twitter_0${number}.html` - const encodedText = encodeURIComponent(text) - const encodedImageUrl = encodeURIComponent(imageUrl) - const twitterIntentURL = `https://twitter.com/intent/tweet?text=${encodedText}&url=${encodedImageUrl}` - - return ( - - } - mb={-9} - /> - - -

Congratulations!!

- - {account.name} has just received STRK tokens from the Starknet airdrop - -
- - - -
- ) -} diff --git a/packages/extension/src/ui/features/provision/provisionAsset.svg b/packages/extension/src/ui/features/provision/provisionAsset.svg deleted file mode 100644 index bf708974f..000000000 --- a/packages/extension/src/ui/features/provision/provisionAsset.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/extension/src/ui/features/recovery/CopySeedPhrase.tsx b/packages/extension/src/ui/features/recovery/CopySeedPhrase.tsx index e74e69751..83e4fb679 100644 --- a/packages/extension/src/ui/features/recovery/CopySeedPhrase.tsx +++ b/packages/extension/src/ui/features/recovery/CopySeedPhrase.tsx @@ -2,7 +2,7 @@ import { Button, Flex } from "@chakra-ui/react" import { FC, useEffect, useState } from "react" import CopyToClipboard from "react-copy-to-clipboard" -import { L2, icons } from "@argent/ui" +import { L2, icons } from "@argent/x-ui" const { AlertFillIcon } = icons diff --git a/packages/extension/src/ui/features/recovery/RecoverySetupScreen.tsx b/packages/extension/src/ui/features/recovery/RecoverySetupScreen.tsx index db73f9d7c..6ca307968 100644 --- a/packages/extension/src/ui/features/recovery/RecoverySetupScreen.tsx +++ b/packages/extension/src/ui/features/recovery/RecoverySetupScreen.tsx @@ -1,4 +1,4 @@ -import { BarCloseButton, NavigationContainer, icons } from "@argent/ui" +import { BarCloseButton, NavigationContainer, icons } from "@argent/x-ui" import { FC } from "react" import { Link, useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/recovery/SeedPhraseWithCopyButton.tsx b/packages/extension/src/ui/features/recovery/SeedPhraseWithCopyButton.tsx index e284f77ca..9ee141cb4 100644 --- a/packages/extension/src/ui/features/recovery/SeedPhraseWithCopyButton.tsx +++ b/packages/extension/src/ui/features/recovery/SeedPhraseWithCopyButton.tsx @@ -1,4 +1,4 @@ -import { P3 } from "@argent/ui" +import { P3 } from "@argent/x-ui" import { Divider, Flex } from "@chakra-ui/react" import { CopySeedPhrase } from "./CopySeedPhrase" import { SeedPhrase } from "./SeedPhrase" diff --git a/packages/extension/src/ui/features/recovery/SeedRecoverySetupScreen.tsx b/packages/extension/src/ui/features/recovery/SeedRecoverySetupScreen.tsx index bd1ba1675..b7c141f1b 100644 --- a/packages/extension/src/ui/features/recovery/SeedRecoverySetupScreen.tsx +++ b/packages/extension/src/ui/features/recovery/SeedRecoverySetupScreen.tsx @@ -4,7 +4,7 @@ import { NavigationContainer, P4, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { FC, useState } from "react" import { useNavigate } from "react-router-dom" import { useAtom } from "jotai" diff --git a/packages/extension/src/ui/features/recovery/ui/LoadingSeedWordBadge.tsx b/packages/extension/src/ui/features/recovery/ui/LoadingSeedWordBadge.tsx index 333f3be05..97633191b 100644 --- a/packages/extension/src/ui/features/recovery/ui/LoadingSeedWordBadge.tsx +++ b/packages/extension/src/ui/features/recovery/ui/LoadingSeedWordBadge.tsx @@ -1,31 +1,23 @@ -import { Box } from "@chakra-ui/react" -import { keyframes } from "@chakra-ui/react" +import { FlexProps, Skeleton } from "@chakra-ui/react" import { FC } from "react" -const pulseKeyframe = keyframes` -0% { - opacity: 1; -} -100% { - opacity: 0.2; -} -` +import { SeedWordBadge } from "./SeedWordBadge" -interface LoadingSeedWordBadgeProps { +interface LoadingSeedWordBadgeProps extends FlexProps { animationDelay?: number } -export const LoadingSeedWordBadge: FC< - LoadingSeedWordBadgeProps & { animationDelay: number } -> = ({ animationDelay = 0, ...props }) => { +export const LoadingSeedWordBadge: FC = ({ + animationDelay = 0, + ...rest +}) => { return ( - + +   + ) } diff --git a/packages/extension/src/ui/features/recovery/ui/SeedPhraseGrid.tsx b/packages/extension/src/ui/features/recovery/ui/SeedPhraseGrid.tsx index 7f43f7920..87f920db0 100644 --- a/packages/extension/src/ui/features/recovery/ui/SeedPhraseGrid.tsx +++ b/packages/extension/src/ui/features/recovery/ui/SeedPhraseGrid.tsx @@ -1,7 +1,7 @@ -import { B3 } from "@argent/ui" +import { B3 } from "@argent/x-ui" import { Box, Center, Flex } from "@chakra-ui/react" import { FC, PropsWithChildren, useState } from "react" -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" const { HideIcon } = icons export const SeedPhraseGrid: FC = ({ diff --git a/packages/extension/src/ui/features/recovery/ui/SeedWordBadge.tsx b/packages/extension/src/ui/features/recovery/ui/SeedWordBadge.tsx index c3010ca90..195462b7b 100644 --- a/packages/extension/src/ui/features/recovery/ui/SeedWordBadge.tsx +++ b/packages/extension/src/ui/features/recovery/ui/SeedWordBadge.tsx @@ -1,26 +1,20 @@ -import { Box } from "@chakra-ui/react" -import { FC, PropsWithChildren } from "react" +import { typographyStyles } from "@argent/x-ui" +import { FlexProps, Flex } from "@chakra-ui/react" +import { FC } from "react" -export const SeedWordBadge: FC = ({ - children, - ...props -}) => { +export const SeedWordBadge: FC = (props) => { return ( - - {children} - + /> ) } diff --git a/packages/extension/src/ui/features/recovery/ui/SeedWordBadgeNumber.tsx b/packages/extension/src/ui/features/recovery/ui/SeedWordBadgeNumber.tsx index a2598721d..460ae26c5 100644 --- a/packages/extension/src/ui/features/recovery/ui/SeedWordBadgeNumber.tsx +++ b/packages/extension/src/ui/features/recovery/ui/SeedWordBadgeNumber.tsx @@ -1,24 +1,6 @@ -import { Box } from "@chakra-ui/react" -import { FC, PropsWithChildren } from "react" +import { Box, BoxProps } from "@chakra-ui/react" +import { FC } from "react" -export const SeedWordBadgeNumber: FC = ({ - children, - ...props -}) => { - return ( - - {children} - - ) +export const SeedWordBadgeNumber: FC = (props) => { + return } diff --git a/packages/extension/src/ui/features/send/AccountListWithBalance.tsx b/packages/extension/src/ui/features/send/AccountListWithBalance.tsx index 39cc16df0..a449349d2 100644 --- a/packages/extension/src/ui/features/send/AccountListWithBalance.tsx +++ b/packages/extension/src/ui/features/send/AccountListWithBalance.tsx @@ -1,8 +1,8 @@ -import { CellStack } from "@argent/ui" +import { CellStack } from "@argent/x-ui" import { FC } from "react" import { WalletAccount } from "../../../shared/wallet.model" import { AccountListItemWithBalance } from "../accounts/AccountListItemWithBalance" -import { getAccountIdentifier } from "@argent/shared" +import { getAccountIdentifier } from "@argent/x-shared" interface AccountListWithBalanceProps { accounts: WalletAccount[] diff --git a/packages/extension/src/ui/features/send/NftInput.tsx b/packages/extension/src/ui/features/send/NftInput.tsx index f22a8446a..15aa9c15d 100644 --- a/packages/extension/src/ui/features/send/NftInput.tsx +++ b/packages/extension/src/ui/features/send/NftInput.tsx @@ -1,5 +1,5 @@ -import { Address, addressSchema, getNftPicture } from "@argent/shared" -import { H6, P4, icons } from "@argent/ui" +import { Address, addressSchema, getNftPicture } from "@argent/x-shared" +import { H6, P4, icons } from "@argent/x-ui" import { Circle, Flex, Image } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/send/SendAmountAndAssetNftScreenContainer.tsx b/packages/extension/src/ui/features/send/SendAmountAndAssetNftScreenContainer.tsx index 6495c6883..9980d71b8 100644 --- a/packages/extension/src/ui/features/send/SendAmountAndAssetNftScreenContainer.tsx +++ b/packages/extension/src/ui/features/send/SendAmountAndAssetNftScreenContainer.tsx @@ -1,4 +1,4 @@ -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/send/SendAmountAndAssetScreen.tsx b/packages/extension/src/ui/features/send/SendAmountAndAssetScreen.tsx index b41d82ea7..1eb2ee12d 100644 --- a/packages/extension/src/ui/features/send/SendAmountAndAssetScreen.tsx +++ b/packages/extension/src/ui/features/send/SendAmountAndAssetScreen.tsx @@ -6,7 +6,7 @@ import { HeaderCell, NavigationContainer, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, ReactNode } from "react" diff --git a/packages/extension/src/ui/features/send/SendAmountAndAssetTokenScreenContainer.tsx b/packages/extension/src/ui/features/send/SendAmountAndAssetTokenScreenContainer.tsx index 9da918225..3ff2e3a8e 100644 --- a/packages/extension/src/ui/features/send/SendAmountAndAssetTokenScreenContainer.tsx +++ b/packages/extension/src/ui/features/send/SendAmountAndAssetTokenScreenContainer.tsx @@ -4,18 +4,17 @@ import { nonNullable, parseAmount, transferCalldataSchema, -} from "@argent/shared" -import { FieldError } from "@argent/ui" + prettifyTokenNumber, + prettifyCurrencyValue, +} from "@argent/x-shared" +import { FieldError } from "@argent/x-ui" import { zodResolver } from "@hookform/resolvers/zod" import { FC, useCallback, useMemo } from "react" import { SubmitHandler, useForm } from "react-hook-form" import { useNavigate } from "react-router-dom" import { z } from "zod" -import { - prettifyCurrencyValue, - prettifyTokenBalance, -} from "../../../shared/token/price" +import { prettifyTokenBalance } from "../../../shared/token/prettifyTokenBalance" import type { Token } from "../../../shared/token/__new/types/token.model" import type { WalletAccount } from "../../../shared/wallet.model" import { useAutoFocusInputRef } from "../../hooks/useAutoFocusInputRef" @@ -38,9 +37,7 @@ import { clientStarknetAddressService } from "../../services/address" import { useMaxFeeEstimateForTransfer } from "../accountTokens/useMaxFeeForTransfer" import { useBestFeeToken } from "../actions/useBestFeeToken" import { formatUnits } from "ethers" -import { genericErrorSchema } from "../actions/feeEstimation/feeError" import { tokenBalanceForAccountAndTokenView } from "../../views/tokenBalances" -import { prettifyTokenNumber } from "../../../shared/utils/number" const formSchema = z.object({ amount: amountInputSchema, @@ -223,11 +220,6 @@ const GuardedSendAmountAndAssetTokenScreenContainer: FC< if (!maxFeeError) { return prettifyCurrencyValue(currencyValue) } - - const genericError = genericErrorSchema.safeParse(maxFeeError) - if (genericError.success) { - return {genericError.data.message} - } return Unable to estimate max }, [currencyValue, maxFeeError]) diff --git a/packages/extension/src/ui/features/send/SendAssetScreen.tsx b/packages/extension/src/ui/features/send/SendAssetScreen.tsx index bc5967ae8..dacc2ecb3 100644 --- a/packages/extension/src/ui/features/send/SendAssetScreen.tsx +++ b/packages/extension/src/ui/features/send/SendAssetScreen.tsx @@ -4,7 +4,7 @@ import { Empty, NavigationContainer, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Input, InputGroup, diff --git a/packages/extension/src/ui/features/send/SendCollectionNftsScreenContainer.tsx b/packages/extension/src/ui/features/send/SendCollectionNftsScreenContainer.tsx index 59ee986aa..6cf0b4c6e 100644 --- a/packages/extension/src/ui/features/send/SendCollectionNftsScreenContainer.tsx +++ b/packages/extension/src/ui/features/send/SendCollectionNftsScreenContainer.tsx @@ -1,5 +1,5 @@ -import { addressSchema } from "@argent/shared" -import { BarBackButton, BarCloseButton } from "@argent/ui" +import { addressSchema } from "@argent/x-shared" +import { BarBackButton, BarCloseButton } from "@argent/x-ui" import { FC } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/send/SendModalAddContactScreen.tsx b/packages/extension/src/ui/features/send/SendModalAddContactScreen.tsx index 02e379eda..7f4e556f6 100644 --- a/packages/extension/src/ui/features/send/SendModalAddContactScreen.tsx +++ b/packages/extension/src/ui/features/send/SendModalAddContactScreen.tsx @@ -1,4 +1,4 @@ -import { BarCloseButton } from "@argent/ui" +import { BarCloseButton } from "@argent/x-ui" import { DrawerProps } from "@chakra-ui/react" import { FC, Suspense } from "react" diff --git a/packages/extension/src/ui/features/send/SendRecipientScreen.tsx b/packages/extension/src/ui/features/send/SendRecipientScreen.tsx index debca3364..e97a8d37b 100644 --- a/packages/extension/src/ui/features/send/SendRecipientScreen.tsx +++ b/packages/extension/src/ui/features/send/SendRecipientScreen.tsx @@ -10,7 +10,7 @@ import { NavigationContainer, TextareaAutosize, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Flex, InputGroup, @@ -26,7 +26,7 @@ import { import { BaseSyntheticEvent, FC, ReactNode } from "react" import { FieldErrors, UseFormRegister } from "react-hook-form" -import { addressInputCharactersAndLengthSchema } from "@argent/shared" +import { addressInputCharactersAndLengthSchema } from "@argent/x-shared" import { isEmpty } from "lodash-es" import type { AddressBookContact } from "../../../shared/addressBook/type" import type { WalletAccount } from "../../../shared/wallet.model" diff --git a/packages/extension/src/ui/features/send/SendRecipientScreenContainer.tsx b/packages/extension/src/ui/features/send/SendRecipientScreenContainer.tsx index 377dd9e71..8449a9c07 100644 --- a/packages/extension/src/ui/features/send/SendRecipientScreenContainer.tsx +++ b/packages/extension/src/ui/features/send/SendRecipientScreenContainer.tsx @@ -3,7 +3,7 @@ import { addressOrDomainInputSchema, isStarknetDomainName, normalizeAddressOrDomain, -} from "@argent/shared" +} from "@argent/x-shared" import { useDisclosure } from "@chakra-ui/react" import { zodResolver } from "@hookform/resolvers/zod" import { FC, useCallback, useEffect, useMemo } from "react" @@ -199,13 +199,13 @@ export const SendRecipientScreenContainer: FC = () => { if (query !== "") { return } - /** ignore starknet id or invalid address */ if (!addressInputSchema.safeParse(queryPaste).success) { - return + /** submit and validate so the user will see error in the UI */ + return onQuerySubmit() } selectAddress(queryPaste) }, - [query, selectAddress], + [onQuerySubmit, query, selectAddress], ) if (!account) { diff --git a/packages/extension/src/ui/features/send/TokenAmountInput.tsx b/packages/extension/src/ui/features/send/TokenAmountInput.tsx index 11036a254..1fb3c73b7 100644 --- a/packages/extension/src/ui/features/send/TokenAmountInput.tsx +++ b/packages/extension/src/ui/features/send/TokenAmountInput.tsx @@ -1,4 +1,4 @@ -import { Button, L2, icons, typographyStyles } from "@argent/ui" +import { Button, L2, icons, typographyStyles } from "@argent/x-ui" import { Flex, InputProps, Spinner, chakra } from "@chakra-ui/react" import { ReactNode, forwardRef, useCallback, useMemo, useState } from "react" import Measure, { ContentRect } from "react-measure" @@ -86,7 +86,7 @@ const TokenAmountInput = forwardRef( w={"full"} bg={"transparent"} placeholder={"0"} - color={isInvalid ? "error.500" : "text.primary"} + color={isInvalid ? "error.500" : "text-primary"} _placeholder={{ color: "neutrals.500" }} _focus={{ outline: "none" }} value={value} diff --git a/packages/extension/src/ui/features/send/schema.test.ts b/packages/extension/src/ui/features/send/schema.test.ts index 17ba4669e..8ae0b3fdb 100644 --- a/packages/extension/src/ui/features/send/schema.test.ts +++ b/packages/extension/src/ui/features/send/schema.test.ts @@ -2,7 +2,7 @@ import { describe, expect, test } from "vitest" import { parseQuery, sendQuerySchema } from "./schema" import { stark } from "starknet" -import { addressSchema } from "@argent/shared" +import { addressSchema } from "@argent/x-shared" const mockTokenAddress = addressSchema.parse(stark.randomAddress()) diff --git a/packages/extension/src/ui/features/send/schema.ts b/packages/extension/src/ui/features/send/schema.ts index 8d49932af..7f9b35048 100644 --- a/packages/extension/src/ui/features/send/schema.ts +++ b/packages/extension/src/ui/features/send/schema.ts @@ -1,4 +1,4 @@ -import { addressOrDomainSchema, addressSchema } from "@argent/shared" +import { addressOrDomainSchema, addressSchema } from "@argent/x-shared" import { z } from "zod" import { useQuery } from "../../hooks/useQuery" diff --git a/packages/extension/src/ui/features/send/sendRecipientScreen.model.ts b/packages/extension/src/ui/features/send/sendRecipientScreen.model.ts index 0eacc0fc3..0e147859a 100644 --- a/packages/extension/src/ui/features/send/sendRecipientScreen.model.ts +++ b/packages/extension/src/ui/features/send/sendRecipientScreen.model.ts @@ -1,5 +1,5 @@ import { z } from "zod" -import { addressOrDomainInputSchema } from "@argent/shared" +import { addressOrDomainInputSchema } from "@argent/x-shared" export const formSchema = z.object({ query: addressOrDomainInputSchema, diff --git a/packages/extension/src/ui/features/send/useFilteredAccounts.ts b/packages/extension/src/ui/features/send/useFilteredAccounts.ts index 0c030ff62..2d1290604 100644 --- a/packages/extension/src/ui/features/send/useFilteredAccounts.ts +++ b/packages/extension/src/ui/features/send/useFilteredAccounts.ts @@ -1,4 +1,4 @@ -import { isEqualAddress, normalizeAddressOrDomain } from "@argent/shared" +import { isEqualAddress, normalizeAddressOrDomain } from "@argent/x-shared" import { useMemo } from "react" import { useAppState } from "../../app.state" diff --git a/packages/extension/src/ui/features/send/useFilteredContacts.ts b/packages/extension/src/ui/features/send/useFilteredContacts.ts index 847fa3bc7..9facd563b 100644 --- a/packages/extension/src/ui/features/send/useFilteredContacts.ts +++ b/packages/extension/src/ui/features/send/useFilteredContacts.ts @@ -1,4 +1,4 @@ -import { isEqualAddress, normalizeAddressOrDomain } from "@argent/shared" +import { isEqualAddress, normalizeAddressOrDomain } from "@argent/x-shared" import { useMemo } from "react" import { useAppState } from "../../app.state" diff --git a/packages/extension/src/ui/features/send/useGetAddressFromDomainName.ts b/packages/extension/src/ui/features/send/useGetAddressFromDomainName.ts index 1ab1f1c3c..a827ec40f 100644 --- a/packages/extension/src/ui/features/send/useGetAddressFromDomainName.ts +++ b/packages/extension/src/ui/features/send/useGetAddressFromDomainName.ts @@ -4,7 +4,7 @@ import { isStarknetDomainName, isValidAddress, useDebouncedValue, -} from "@argent/shared" +} from "@argent/x-shared" import useSWR from "swr" import { clientStarknetAddressService } from "../../services/address" diff --git a/packages/extension/src/ui/features/settings/SettingsScreen.tsx b/packages/extension/src/ui/features/settings/SettingsScreen.tsx index 8a15c318c..7c3a59014 100644 --- a/packages/extension/src/ui/features/settings/SettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/SettingsScreen.tsx @@ -6,7 +6,7 @@ import { NavigationContainerProps, SpacerCell, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Center, Flex } from "@chakra-ui/react" import { FC, ReactEventHandler } from "react" @@ -22,7 +22,7 @@ import { SettingsMenuItemLink, } from "./ui/SettingsMenuItem" import { SupportFooter } from "./ui/SupportFooter" -import { formatTruncatedString } from "@argent/shared" +import { formatTruncatedString } from "@argent/x-shared" const { LockIcon, diff --git a/packages/extension/src/ui/features/settings/account/AccountEditButtons.tsx b/packages/extension/src/ui/features/settings/account/AccountEditButtons.tsx index 4d6030178..b9e2d5c90 100644 --- a/packages/extension/src/ui/features/settings/account/AccountEditButtons.tsx +++ b/packages/extension/src/ui/features/settings/account/AccountEditButtons.tsx @@ -1,4 +1,4 @@ -import { ButtonCell, P4, SpacerCell, Switch, icons } from "@argent/ui" +import { ButtonCell, P4, SpacerCell, Switch, icons } from "@argent/x-ui" import { Spinner } from "@chakra-ui/react" import { useMemo } from "react" import { Link, useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/settings/account/AccountEditButtonsMultisig.tsx b/packages/extension/src/ui/features/settings/account/AccountEditButtonsMultisig.tsx index 7b8770c5c..ca9237612 100644 --- a/packages/extension/src/ui/features/settings/account/AccountEditButtonsMultisig.tsx +++ b/packages/extension/src/ui/features/settings/account/AccountEditButtonsMultisig.tsx @@ -1,4 +1,4 @@ -import { ButtonCell, H6, icons } from "@argent/ui" +import { ButtonCell, H6, icons } from "@argent/x-ui" import { Button, Flex } from "@chakra-ui/react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/settings/account/AccountEditName.tsx b/packages/extension/src/ui/features/settings/account/AccountEditName.tsx index 409313325..8f538e669 100644 --- a/packages/extension/src/ui/features/settings/account/AccountEditName.tsx +++ b/packages/extension/src/ui/features/settings/account/AccountEditName.tsx @@ -1,4 +1,4 @@ -import { Button, icons } from "@argent/ui" +import { Button, icons } from "@argent/x-ui" import { Input, InputGroup, diff --git a/packages/extension/src/ui/features/settings/account/AccountSettingsScreen.tsx b/packages/extension/src/ui/features/settings/account/AccountSettingsScreen.tsx index 860c0e1a5..78c722008 100644 --- a/packages/extension/src/ui/features/settings/account/AccountSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/account/AccountSettingsScreen.tsx @@ -3,7 +3,7 @@ import { CellStack, NavigationContainer, SpacerCell, -} from "@argent/ui" +} from "@argent/x-ui" import { Center, Flex, Image } from "@chakra-ui/react" import React, { FC, useCallback, useState } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/settings/account/ChangeAccountImplementationScreen.tsx b/packages/extension/src/ui/features/settings/account/ChangeAccountImplementationScreen.tsx index 67ef634c1..a5cfd199d 100644 --- a/packages/extension/src/ui/features/settings/account/ChangeAccountImplementationScreen.tsx +++ b/packages/extension/src/ui/features/settings/account/ChangeAccountImplementationScreen.tsx @@ -5,7 +5,7 @@ import { NavigationContainer, P4, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Box } from "@chakra-ui/react" import { filter, partition } from "lodash-es" import { FC } from "react" diff --git a/packages/extension/src/ui/features/settings/account/ExportPrivateKeyScreen.tsx b/packages/extension/src/ui/features/settings/account/ExportPrivateKeyScreen.tsx index fb3237659..7bf377c4c 100644 --- a/packages/extension/src/ui/features/settings/account/ExportPrivateKeyScreen.tsx +++ b/packages/extension/src/ui/features/settings/account/ExportPrivateKeyScreen.tsx @@ -1,22 +1,21 @@ import { BarBackButton, CellStack, - HeaderCell, L2, NavigationContainer, P3, icons, -} from "@argent/ui" -import { FC, ReactEventHandler, useEffect, useState } from "react" +} from "@argent/x-ui" +import { FC, ReactEventHandler, useState } from "react" import { Button, Center, Flex } from "@chakra-ui/react" import copy from "copy-to-clipboard" import { useRouteAccountAddress } from "../../../routes" import { usePrivateKey } from "../../accountTokens/usePrivateKey" -import { PasswordForm, PasswordFormProps } from "../../lock/PasswordForm" +import { PasswordFormProps } from "../../lock/PasswordForm" import { useCurrentNetwork } from "../../networks/hooks/useCurrentNetwork" -import { WarningRecoveryBanner } from "../ui/WarningRecoveryBanner" import { QrCode } from "../../../components/QrCode" +import { PasswordWarningForm } from "../ui/PasswordWarningForm" const { AlertFillIcon } = icons @@ -41,7 +40,14 @@ export const ExportPrivateKeyScreen: FC = ({ {passwordIsValid ? ( ) : ( - + )} ) @@ -105,36 +111,3 @@ function ExportPrivateKey({
) } - -function UnlockExportPrivateKey({ - verifyPassword, -}: Pick) { - return ( - - - Enter your password - - {(isDirty) => ( - <> - - - - )} - - - ) -} diff --git a/packages/extension/src/ui/features/settings/account/Implementation.tsx b/packages/extension/src/ui/features/settings/account/Implementation.tsx index 076dd53eb..dd04a6b8e 100644 --- a/packages/extension/src/ui/features/settings/account/Implementation.tsx +++ b/packages/extension/src/ui/features/settings/account/Implementation.tsx @@ -1,4 +1,4 @@ -import { H6, icons } from "@argent/ui" +import { H6, icons } from "@argent/x-ui" import { ArgentAccountType } from "../../../../shared/wallet.model" import { FC, ReactNode } from "react" import { AutoColumn } from "../../../components/Column" diff --git a/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreen.tsx b/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreen.tsx index ae51b0859..57d1cf3a4 100644 --- a/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreen.tsx +++ b/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreen.tsx @@ -10,11 +10,11 @@ import { Select, SelectOptions, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { addressInputCharactersAndLengthSchema, isStarknetDomainName, -} from "@argent/shared" +} from "@argent/x-shared" import { Button, Center, diff --git a/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreenContainer.tsx b/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreenContainer.tsx index 1063b97de..7a38fcd74 100644 --- a/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreenContainer.tsx +++ b/packages/extension/src/ui/features/settings/addressBook/AddressBookAddOrEditScreenContainer.tsx @@ -1,4 +1,4 @@ -import { NavigationContainerProps, SelectOptions } from "@argent/ui" +import { NavigationContainerProps, SelectOptions } from "@argent/x-ui" import { isFunction } from "lodash-es" import { FC, useMemo } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/settings/addressBook/AddressBookSettingsScreen.tsx b/packages/extension/src/ui/features/settings/addressBook/AddressBookSettingsScreen.tsx index 18943a5e6..a4ac12526 100644 --- a/packages/extension/src/ui/features/settings/addressBook/AddressBookSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/addressBook/AddressBookSettingsScreen.tsx @@ -7,7 +7,7 @@ import { Input, NavigationContainer, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { InputGroup, InputLeftElement } from "@chakra-ui/react" import { FC, useCallback, useMemo } from "react" import { useForm } from "react-hook-form" diff --git a/packages/extension/src/ui/features/settings/connectedDapps/DappConnectionsAccountListScreen.tsx b/packages/extension/src/ui/features/settings/connectedDapps/DappConnectionsAccountListScreen.tsx index 865fcae8d..f820bc89d 100644 --- a/packages/extension/src/ui/features/settings/connectedDapps/DappConnectionsAccountListScreen.tsx +++ b/packages/extension/src/ui/features/settings/connectedDapps/DappConnectionsAccountListScreen.tsx @@ -5,7 +5,7 @@ import { NavigationContainer, P3, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { PreAuthorization } from "../../../../shared/preAuthorization/schema" @@ -35,7 +35,7 @@ export const DappConnectionsAccountListScreen: FC< } title={"No connected dapps"} /> ) : ( - + One or more dapps are connected to these accounts: -
Connected dapps
+
Connected dapps
} - extendedDescription="ArgentX will use an RPC Provider (instead of the feeder gateway) to + extendedDescription="Argent X will use an RPC Provider (instead of the feeder gateway) to interact with Starknet." > Use RPC Provider diff --git a/packages/extension/src/ui/features/settings/developerSettings/betaFeatures/BetaFeaturesSettingsScreenContainer.tsx b/packages/extension/src/ui/features/settings/developerSettings/betaFeatures/BetaFeaturesSettingsScreenContainer.tsx index a44e2009f..d40b9ccdd 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/betaFeatures/BetaFeaturesSettingsScreenContainer.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/betaFeatures/BetaFeaturesSettingsScreenContainer.tsx @@ -1,6 +1,4 @@ import { FC } from "react" -import { useCurrentNetwork } from "../../../networks/hooks/useCurrentNetwork" -import { networkRepo } from "../../../../../shared/network/store" import { BetaFeaturesSettingsScreen } from "./BetaFeaturesSettingsScreen" export const BetaFeaturesSettingsScreenContainer: FC = () => { diff --git a/packages/extension/src/ui/features/settings/developerSettings/clearLocalStorage/ClearLocalStorageScreen.tsx b/packages/extension/src/ui/features/settings/developerSettings/clearLocalStorage/ClearLocalStorageScreen.tsx index 431cb7752..ddd98acba 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/clearLocalStorage/ClearLocalStorageScreen.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/clearLocalStorage/ClearLocalStorageScreen.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, H3, NavigationContainer, P3, icons } from "@argent/ui" +import { BarBackButton, H3, NavigationContainer, P3, icons } from "@argent/x-ui" import { Box, Button, Flex } from "@chakra-ui/react" import { FC } from "react" import { IconWrapper } from "../../../actions/transactionV2/TransactionHeader/TransactionIcon/IconWrapper" diff --git a/packages/extension/src/ui/features/settings/developerSettings/deploymentData/DeploymentDataScreen.tsx b/packages/extension/src/ui/features/settings/developerSettings/deploymentData/DeploymentDataScreen.tsx index 1f7ed1ec5..c16307256 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/deploymentData/DeploymentDataScreen.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/deploymentData/DeploymentDataScreen.tsx @@ -9,7 +9,7 @@ import { scrollbarStyle, BarBackButton, NavigationContainer, -} from "@argent/ui" +} from "@argent/x-ui" const { CopyIcon } = icons @@ -31,7 +31,7 @@ export const DeploymentDataScreen: FC = () => { = (props) => { + const { isOpen, onOpen, onClose } = useDisclosure() const navigate = useNavigate() const [expanded, setExpanded] = useState(false) const blockExplorerKey = useKeyValueStorage(settingsStore, "blockExplorerKey") const settingsBlockExplorer = defaultBlockExplorers[blockExplorerKey] - - const { prefer: preferredFeeToken } = useFeeTokenPreference() + const [userAcceptedRisk, setUserAcceptedRisk] = useState(false) const defaultNetwork = useMemo(() => { if (props.mode === "add") { @@ -51,7 +54,7 @@ export const NetworkSettingsFormScreenContainer: FC< accountClassHash: { standard: TXV1_ACCOUNT_CLASS_HASH, }, - possibleFeeTokenAddresses: [preferredFeeToken], // TODO: let the user add feetokens + possibleFeeTokenAddresses: [ETH_TOKEN_ADDRESS], // Default to ETH. User can change this if they want // should we add a default for this or use undefined? For better UX, its a good idea to have a default imo - Dhruv multicallAddress: MULTICALL_CONTRACT_ADDRESS, } @@ -79,6 +82,8 @@ export const NetworkSettingsFormScreenContainer: FC< resolver: zodResolver(networkSchema), }) + const { chainId } = watch() + useEffect(() => { const subscription = watch((value, { name, type }) => { if (props.mode === "add" && type === "change" && name === "name") { @@ -91,6 +96,12 @@ export const NetworkSettingsFormScreenContainer: FC< const onSubmit = async (network: Network) => { try { + if (mainnetChainIdSchema.safeParse(network.chainId).success) { + if (!userAcceptedRisk) { + onOpen() + return + } + } await networkService.add(network) const promises = network.possibleFeeTokenAddresses.map( @@ -131,15 +142,30 @@ export const NetworkSettingsFormScreenContainer: FC< } } + const onAcceptRisk = () => { + setUserAcceptedRisk(true) + onClose() + } + return ( - + <> + + + ) } diff --git a/packages/extension/src/ui/features/settings/developerSettings/manageNetworks/NetworkSettingsScreen.tsx b/packages/extension/src/ui/features/settings/developerSettings/manageNetworks/NetworkSettingsScreen.tsx index c698cac5f..230473c98 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/manageNetworks/NetworkSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/manageNetworks/NetworkSettingsScreen.tsx @@ -8,7 +8,7 @@ import { NavigationContainer, StickyGroup, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import type { Network } from "../../../../../shared/network" @@ -88,7 +88,7 @@ export const NetworkSettingsScreen: FC = ({ size={"2xs"} colorScheme="transparent" leftIcon={} - color="text.secondary" + color="text-secondary" > Restore default networks diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashInputActions.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashInputActions.tsx index 1624f3b4d..0cf2aba14 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashInputActions.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashInputActions.tsx @@ -1,4 +1,4 @@ -import { Button, H6, icons } from "@argent/ui" +import { Button, H6, icons } from "@argent/x-ui" import { Box, ScaleFade } from "@chakra-ui/react" import { FC, useCallback, useEffect, useRef, useState } from "react" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashOption.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashOption.tsx index eb1fc15df..54ddb449e 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashOption.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ClassHashOption.tsx @@ -1,9 +1,9 @@ -import { H6, P4 } from "@argent/ui" +import { H6, P4 } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC } from "react" import { Transaction } from "../../../../../shared/transactions" -import { formatTruncatedAddress } from "@argent/shared" +import { formatTruncatedAddress } from "@argent/x-shared" import { formatDateTimeBase } from "../../../../services/dates" import { AccountAvatar } from "../../../accounts/AccountAvatar" import { getNetworkAccountImageUrl } from "../../../accounts/accounts.service" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareOrDeployContractSuccessScreen.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareOrDeployContractSuccessScreen.tsx index a2e18f054..beedfad1c 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareOrDeployContractSuccessScreen.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareOrDeployContractSuccessScreen.tsx @@ -7,7 +7,7 @@ import { NavigationContainer, P3, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Box, Center, Flex } from "@chakra-ui/react" import { FC } from "react" @@ -52,7 +52,7 @@ export const DeclareOrDeployContractSuccessScreen: FC< backgroundColor="neutrals.800" borderRadius={8} textAlign={"center"} - color={"white50"} + color={"white.50"} p="4.5" overflowWrap="break-word" > @@ -70,9 +70,9 @@ export const DeclareOrDeployContractSuccessScreen: FC< mt="6" gap="1" size="3xs" - color={"white50"} + color={"white.50"} bg={"transparent"} - _hover={{ bg: "neutrals.700", color: "text.primary" }} + _hover={{ bg: "neutrals.700", color: "text-primary" }} > Copy diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractForm.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractForm.tsx index fdd38073f..ee62fa8c1 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractForm.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractForm.tsx @@ -1,11 +1,11 @@ -import { CellStack, ErrorMessage, P3, Select, SpacerCell } from "@argent/ui" +import { CellStack, ErrorMessage, P3, Select, SpacerCell } from "@argent/x-ui" import { isEmpty } from "lodash-es" import { FC, ReactNode, useCallback, useRef, useState } from "react" import { Controller, SubmitHandler, useForm } from "react-hook-form" import { CompiledSierraCasm, hash, isSierra } from "starknet6" import { chakra } from "@chakra-ui/react" -import { readFileAsString } from "@argent/shared" +import { readFileAsString } from "@argent/x-shared" import { useAppState } from "../../../../app.state" import { FileNameWithClassHash } from "./ui/ContractWithClassHash" import { FileInputButton } from "./ui/FileInputButton" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractScreen.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractScreen.tsx index f2efb4a30..669524bba 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractScreen.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeclareSmartContractScreen.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, Button, NavigationContainer } from "@argent/ui" +import { BarBackButton, Button, NavigationContainer } from "@argent/x-ui" import { FC } from "react" import { Flex } from "@chakra-ui/react" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractForm.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractForm.tsx index b02315cee..d67877fcb 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractForm.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractForm.tsx @@ -1,6 +1,12 @@ import { FC, ReactNode } from "react" -import { CellStack, ErrorMessage, Input, Select, SpacerCell } from "@argent/ui" +import { + CellStack, + ErrorMessage, + Input, + Select, + SpacerCell, +} from "@argent/x-ui" import { Box, chakra } from "@chakra-ui/react" import { isEmpty } from "lodash-es" import { diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParameters.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParameters.tsx index c0ac9d3e5..cb383e807 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParameters.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParameters.tsx @@ -1,4 +1,4 @@ -import { H6, Input, L2, Switch, TextareaAutosize, icons } from "@argent/ui" +import { H6, Input, L2, Switch, TextareaAutosize, icons } from "@argent/x-ui" import { Flex, FormControl, diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParametersContainer.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParametersContainer.tsx index 230c698ad..ccf7b0998 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParametersContainer.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractParametersContainer.tsx @@ -1,6 +1,6 @@ import { FC } from "react" -import { Alert, SpacerCell, icons } from "@argent/ui" +import { Alert, SpacerCell, icons } from "@argent/x-ui" import { useConstructorParams } from "./useConstructorParams" import { DeploySmartContractParameters } from "./DeploySmartContractParameters" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractScreen.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractScreen.tsx index 947b3e804..25ce24fa8 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractScreen.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/DeploySmartContractScreen.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, Button, NavigationContainer } from "@argent/ui" +import { BarBackButton, Button, NavigationContainer } from "@argent/x-ui" import { FC, useState } from "react" import { Flex } from "@chakra-ui/react" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SelectOptionAccount.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SelectOptionAccount.tsx index b12bd20bf..3d8cf51c5 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SelectOptionAccount.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SelectOptionAccount.tsx @@ -1,8 +1,8 @@ -import { H6, P4 } from "@argent/ui" +import { H6, P4 } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC } from "react" -import { formatTruncatedAddress } from "@argent/shared" +import { formatTruncatedAddress } from "@argent/x-shared" import { Account } from "../../../accounts/Account" interface SelectOptionAvatarProps { diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SmartContractDevelopmentScreen.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SmartContractDevelopmentScreen.tsx index 2e1f03bd9..183609841 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SmartContractDevelopmentScreen.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/SmartContractDevelopmentScreen.tsx @@ -4,7 +4,7 @@ import { Empty, NavigationBar, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { FC } from "react" import { routes } from "../../../../routes" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/ContractWithClassHash.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/ContractWithClassHash.tsx index e6fead657..f9adb530f 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/ContractWithClassHash.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/ContractWithClassHash.tsx @@ -1,4 +1,4 @@ -import { CopyTooltip, P3, P4, icons } from "@argent/ui" +import { CopyTooltip, P3, P4, icons } from "@argent/x-ui" import { Box, Flex } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/FileInputButton.tsx b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/FileInputButton.tsx index 550c26b93..af642bc73 100644 --- a/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/FileInputButton.tsx +++ b/packages/extension/src/ui/features/settings/developerSettings/smartContractDevelopment/ui/FileInputButton.tsx @@ -1,4 +1,4 @@ -import { Button, icons } from "@argent/ui" +import { Button, icons } from "@argent/x-ui" import { ButtonProps, Spinner } from "@chakra-ui/react" import { FC, useMemo } from "react" diff --git a/packages/extension/src/ui/features/settings/preferences/BlockExplorerSettingsScreen.tsx b/packages/extension/src/ui/features/settings/preferences/BlockExplorerSettingsScreen.tsx index 561d58b84..34564e80e 100644 --- a/packages/extension/src/ui/features/settings/preferences/BlockExplorerSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/preferences/BlockExplorerSettingsScreen.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, CellStack, NavigationContainer } from "@argent/ui" +import { BarBackButton, CellStack, NavigationContainer } from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { diff --git a/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreen.tsx b/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreen.tsx index 7634679a3..031ca36e7 100644 --- a/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreen.tsx @@ -4,7 +4,7 @@ import { CellStack, NavigationContainer, Switch, -} from "@argent/ui" +} from "@argent/x-ui" import { FC, ReactEventHandler } from "react" interface EmailNotificationsSettingsScreenProps { diff --git a/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreenContainer.tsx b/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreenContainer.tsx index a8a300146..3f431aa80 100644 --- a/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreenContainer.tsx +++ b/packages/extension/src/ui/features/settings/preferences/EmailNotificationsSettingsScreenContainer.tsx @@ -6,7 +6,7 @@ import { emailPreferencesSchema, } from "../../../../shared/argentAccount/schema" import { useEmailPreferences } from "../../argentAccount/hooks/useEmailPreferences" -import { useDebounce } from "@argent/shared" +import { useDebounce } from "@argent/x-shared" import { useNavigateReturnToOrBack } from "../../../hooks/useNavigateReturnTo" export const EmailNotificationsSettingsScreenContainer = () => { diff --git a/packages/extension/src/ui/features/settings/preferences/NftMarketplaceSettingsScreen.tsx b/packages/extension/src/ui/features/settings/preferences/NftMarketplaceSettingsScreen.tsx index 72d1fd8ef..f89b5ba0b 100644 --- a/packages/extension/src/ui/features/settings/preferences/NftMarketplaceSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/preferences/NftMarketplaceSettingsScreen.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, CellStack, NavigationContainer } from "@argent/ui" +import { BarBackButton, CellStack, NavigationContainer } from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { SettingsMenuItem } from "../ui/SettingsMenuItem" diff --git a/packages/extension/src/ui/features/settings/preferences/PreferencesSettings.tsx b/packages/extension/src/ui/features/settings/preferences/PreferencesSettings.tsx index 53850fbc9..0f54172ff 100644 --- a/packages/extension/src/ui/features/settings/preferences/PreferencesSettings.tsx +++ b/packages/extension/src/ui/features/settings/preferences/PreferencesSettings.tsx @@ -3,7 +3,7 @@ import { CellStack, NavigationContainer, Switch, -} from "@argent/ui" +} from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { NftMarketplace } from "../../../../shared/nft/marketplaces" @@ -42,7 +42,7 @@ export const PreferencesSettings: FC = ({ } > Change account implementation diff --git a/packages/extension/src/ui/features/settings/securityAndPrivacy/AutoLockTimerSettingsScreen.tsx b/packages/extension/src/ui/features/settings/securityAndPrivacy/AutoLockTimerSettingsScreen.tsx index de4715a14..4db7303e0 100644 --- a/packages/extension/src/ui/features/settings/securityAndPrivacy/AutoLockTimerSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/securityAndPrivacy/AutoLockTimerSettingsScreen.tsx @@ -1,4 +1,4 @@ -import { BarBackButton, CellStack, NavigationContainer } from "@argent/ui" +import { BarBackButton, CellStack, NavigationContainer } from "@argent/x-ui" import { FC, MouseEvent, ReactEventHandler } from "react" import { diff --git a/packages/extension/src/ui/features/settings/securityAndPrivacy/BeforeYouContinueScreen.tsx b/packages/extension/src/ui/features/settings/securityAndPrivacy/BeforeYouContinueScreen.tsx index af56e22bb..7fe4ab394 100644 --- a/packages/extension/src/ui/features/settings/securityAndPrivacy/BeforeYouContinueScreen.tsx +++ b/packages/extension/src/ui/features/settings/securityAndPrivacy/BeforeYouContinueScreen.tsx @@ -1,4 +1,4 @@ -import { Button, Warning } from "@argent/ui" +import { Button, Warning } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { useNavigate } from "react-router-dom" import { routes } from "../../../routes" diff --git a/packages/extension/src/ui/features/settings/securityAndPrivacy/SecurityAndPrivacySettingsScreen.tsx b/packages/extension/src/ui/features/settings/securityAndPrivacy/SecurityAndPrivacySettingsScreen.tsx index 54a23d8e0..7fd59b6cf 100644 --- a/packages/extension/src/ui/features/settings/securityAndPrivacy/SecurityAndPrivacySettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/securityAndPrivacy/SecurityAndPrivacySettingsScreen.tsx @@ -5,7 +5,7 @@ import { NavigationContainer, SpacerCell, Switch, -} from "@argent/ui" +} from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { ISettingsStorage } from "../../../../shared/settings/types" diff --git a/packages/extension/src/ui/features/settings/securityAndPrivacy/SeedSettingsScreen.tsx b/packages/extension/src/ui/features/settings/securityAndPrivacy/SeedSettingsScreen.tsx index a49b809a9..2fb25e357 100644 --- a/packages/extension/src/ui/features/settings/securityAndPrivacy/SeedSettingsScreen.tsx +++ b/packages/extension/src/ui/features/settings/securityAndPrivacy/SeedSettingsScreen.tsx @@ -1,17 +1,11 @@ -import { - BarBackButton, - Button, - CellStack, - HeaderCell, - NavigationContainer, -} from "@argent/ui" +import { BarBackButton, NavigationContainer } from "@argent/x-ui" import { FC, ReactEventHandler } from "react" import { Flex } from "@chakra-ui/react" -import { PasswordForm, PasswordFormProps } from "../../lock/PasswordForm" +import { PasswordFormProps } from "../../lock/PasswordForm" import { SeedPhraseWithCopyButton } from "../../recovery/SeedPhraseWithCopyButton" import { useSeedPhrase } from "../../recovery/hooks/useSeedPhrase" -import { WarningRecoveryBanner } from "../ui/WarningRecoveryBanner" +import { PasswordWarningForm } from "../ui/PasswordWarningForm" export interface SeedSettingsScreenProps extends Pick { @@ -34,7 +28,15 @@ export const SeedSettingsScreen: FC = ({ ) : ( - + )} ) @@ -44,36 +46,3 @@ function SeedPhraseWithCopyButtonContainer() { const seedPhrase = useSeedPhrase() return } - -function UnlockCopySeed({ - verifyPassword, -}: Pick) { - return ( - - - Enter your password - - {(isDirty) => ( - <> - - - - )} - - - ) -} diff --git a/packages/extension/src/ui/features/settings/ui/DapplandFooter.tsx b/packages/extension/src/ui/features/settings/ui/DapplandFooter.tsx index b0321edbd..6add7dcaa 100644 --- a/packages/extension/src/ui/features/settings/ui/DapplandFooter.tsx +++ b/packages/extension/src/ui/features/settings/ui/DapplandFooter.tsx @@ -1,4 +1,4 @@ -import { Button, P3 } from "@argent/ui" +import { Button, P3 } from "@argent/x-ui" import { SimpleGrid, VStack } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/settings/ui/PasswordWarningForm.tsx b/packages/extension/src/ui/features/settings/ui/PasswordWarningForm.tsx new file mode 100644 index 000000000..494a48564 --- /dev/null +++ b/packages/extension/src/ui/features/settings/ui/PasswordWarningForm.tsx @@ -0,0 +1,43 @@ +import { CellStack, HeaderCell, icons } from "@argent/x-ui" +import { FC } from "react" +import { Button, Flex, FlexProps } from "@chakra-ui/react" + +import { PasswordForm, PasswordFormProps } from "../../lock/PasswordForm" +import { + WarningRecoveryBanner, + WarningRecoveryBannerProps, +} from "./WarningRecoveryBanner" + +interface PasswordWarningFormProps + extends Pick, + WarningRecoveryBannerProps, + Omit {} + +export const PasswordWarningForm: FC = ({ + verifyPassword, + title, + reasons, + ...rest +}) => { + return ( + + + Enter your password + + {(isDirty) => ( + <> + + + + )} + + + ) +} diff --git a/packages/extension/src/ui/features/settings/ui/SettingsMenuItem.tsx b/packages/extension/src/ui/features/settings/ui/SettingsMenuItem.tsx index e39d3475e..1f259d5a4 100644 --- a/packages/extension/src/ui/features/settings/ui/SettingsMenuItem.tsx +++ b/packages/extension/src/ui/features/settings/ui/SettingsMenuItem.tsx @@ -1,4 +1,4 @@ -import { ButtonCell, P4, icons } from "@argent/ui" +import { ButtonCell, P4, icons } from "@argent/x-ui" import { Box, Button, ButtonProps, Flex, Text } from "@chakra-ui/react" import { FC, PropsWithChildren, ReactEventHandler } from "react" import { Link, LinkProps } from "react-router-dom" @@ -21,7 +21,7 @@ export const SettingsMenuItem: FC = ({ {title} - {subtitle && {subtitle}} + {subtitle && {subtitle}}
) diff --git a/packages/extension/src/ui/features/settings/ui/SettingsMenuItemLogo.tsx b/packages/extension/src/ui/features/settings/ui/SettingsMenuItemLogo.tsx index 2f22db099..03c4967ca 100644 --- a/packages/extension/src/ui/features/settings/ui/SettingsMenuItemLogo.tsx +++ b/packages/extension/src/ui/features/settings/ui/SettingsMenuItemLogo.tsx @@ -1,4 +1,4 @@ -import { logos } from "@argent/ui" +import { logos } from "@argent/x-ui" import { Center, CenterProps } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/settings/ui/SettingsNetworkListItem.tsx b/packages/extension/src/ui/features/settings/ui/SettingsNetworkListItem.tsx index 31f6148e7..0e7f0fb6c 100644 --- a/packages/extension/src/ui/features/settings/ui/SettingsNetworkListItem.tsx +++ b/packages/extension/src/ui/features/settings/ui/SettingsNetworkListItem.tsx @@ -1,4 +1,4 @@ -import { Button, H6, icons } from "@argent/ui" +import { Button, H6, icons } from "@argent/x-ui" import { FC } from "react" const { RemoveIcon } = icons diff --git a/packages/extension/src/ui/features/settings/ui/SettingsRadioIcon.tsx b/packages/extension/src/ui/features/settings/ui/SettingsRadioIcon.tsx index 03932cb3d..c07223dc8 100644 --- a/packages/extension/src/ui/features/settings/ui/SettingsRadioIcon.tsx +++ b/packages/extension/src/ui/features/settings/ui/SettingsRadioIcon.tsx @@ -1,4 +1,4 @@ -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" import { ComponentProps, FC } from "react" const { CheckboxActiveIcon, CheckboxDefaultIcon } = icons @@ -15,5 +15,5 @@ export const SettingsRadioIcon: FC = ({ if (checked) { return } - return + return } diff --git a/packages/extension/src/ui/features/settings/ui/SupportFooter.tsx b/packages/extension/src/ui/features/settings/ui/SupportFooter.tsx index 43e6170ae..c85848445 100644 --- a/packages/extension/src/ui/features/settings/ui/SupportFooter.tsx +++ b/packages/extension/src/ui/features/settings/ui/SupportFooter.tsx @@ -1,4 +1,4 @@ -import { Button, L2, P3, P4, icons, logos } from "@argent/ui" +import { Button, L2, P3, P4, icons, logos } from "@argent/x-ui" import { SimpleGrid, VStack, StackProps, Link, Flex } from "@chakra-ui/react" import { FC } from "react" @@ -35,7 +35,7 @@ const SupportFooter: FC = ({ rounded={"lg"} leftIcon={} href="https://support.argent.xyz/hc/en-us/categories/5767453283473-Argent-X" - title="Get ArgentX Support" + title="Get Argent X Support" target="_blank" > Help @@ -75,7 +75,7 @@ const SupportFooter: FC = ({ {privacyStatement && ( - + { +export interface WarningRecoveryBannerProps extends Omit { title: ReactNode reasons: ReactNode[] } @@ -25,7 +25,7 @@ export const WarningRecoveryBanner: FC = ({ borderRadius="xl" {...rest} > -
+
{title}
@@ -33,7 +33,7 @@ export const WarningRecoveryBanner: FC = ({ return ( - + {reason} diff --git a/packages/extension/src/ui/features/shield/ShieldAccountActionScreen.tsx b/packages/extension/src/ui/features/shield/ShieldAccountActionScreen.tsx index cf54eb711..8dca2ec8c 100644 --- a/packages/extension/src/ui/features/shield/ShieldAccountActionScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldAccountActionScreen.tsx @@ -1,4 +1,4 @@ -import { useToast } from "@argent/ui" +import { useToast } from "@argent/x-ui" import { FC, useCallback, useEffect, useState } from "react" import { useNavigate } from "react-router-dom" import { constants } from "starknet" @@ -9,7 +9,7 @@ import { routes } from "../../routes" import { ShieldBaseActionScreen } from "./ShieldBaseActionScreen" import { usePendingChangeGuardian } from "./usePendingChangingGuardian" import { useRouteAccount } from "./useRouteAccount" -import { useShieldOnboardingTracking } from "./useShieldTracking" + import { argentAccountService } from "../../services/argentAccount" import { accountMessagingService } from "../../services/accountMessaging" @@ -19,19 +19,14 @@ export const ShieldAccountActionScreen: FC = () => { const [isLoading, setIsLoading] = useState(false) const pendingChangeGuardian = usePendingChangeGuardian(account) const toast = useToast() - const hasGuardian = Boolean(account?.guardian) - - const { trackSuccess } = useShieldOnboardingTracking({ - stepId: hasGuardian ? "removeArgentShield" : "addArgentShield", - }) useEffect(() => { if (pendingChangeGuardian && account) { /** a guardian transaction for this account is now pending - move to finish */ - void trackSuccess() + navigate(routes.shieldAccountFinish(account?.address), { replace: true }) } - }, [account, navigate, pendingChangeGuardian, trackSuccess]) + }, [account, navigate, pendingChangeGuardian]) const onAddOrRemove = useCallback(async () => { if (!account) { diff --git a/packages/extension/src/ui/features/shield/ShieldAccountActivate.tsx b/packages/extension/src/ui/features/shield/ShieldAccountActivate.tsx index 838a761d5..a76e9ea26 100644 --- a/packages/extension/src/ui/features/shield/ShieldAccountActivate.tsx +++ b/packages/extension/src/ui/features/shield/ShieldAccountActivate.tsx @@ -1,4 +1,4 @@ -import { FlowHeader, icons } from "@argent/ui" +import { FlowHeader, icons } from "@argent/x-ui" import { Center, VStack } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/shield/ShieldAccountDeactivate.tsx b/packages/extension/src/ui/features/shield/ShieldAccountDeactivate.tsx index bac101c19..70914d459 100644 --- a/packages/extension/src/ui/features/shield/ShieldAccountDeactivate.tsx +++ b/packages/extension/src/ui/features/shield/ShieldAccountDeactivate.tsx @@ -1,4 +1,4 @@ -import { FlowHeader, icons } from "@argent/ui" +import { FlowHeader, icons } from "@argent/x-ui" import { Center, VStack } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/shield/ShieldAccountEmailScreen.tsx b/packages/extension/src/ui/features/shield/ShieldAccountEmailScreen.tsx index a3c505455..d9fed6775 100644 --- a/packages/extension/src/ui/features/shield/ShieldAccountEmailScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldAccountEmailScreen.tsx @@ -2,29 +2,23 @@ import { FC, useCallback } from "react" import { useNavigate } from "react-router-dom" import { routes, useRouteAccountAddress } from "../../routes" -import { useShieldOnboardingTracking } from "./useShieldTracking" import { ArgentAccountBaseEmailScreen } from "../argentAccount/ArgentAccountBaseEmailScreen" export const ShieldAccountEmailScreen: FC = () => { const accountAddress = useRouteAccountAddress() const navigate = useNavigate() - const { trackSuccess } = useShieldOnboardingTracking({ - stepId: "enterEmail", - }) - const onBack = useCallback(() => { navigate(routes.accountTokens()) }, [navigate]) const onEmailRequested = useCallback( (email: string) => { - void trackSuccess() if (accountAddress) { navigate(routes.shieldAccountOTP(accountAddress, email, "shield")) } }, - [accountAddress, navigate, trackSuccess], + [accountAddress, navigate], ) return ( diff --git a/packages/extension/src/ui/features/shield/ShieldAccountNotDeployed.tsx b/packages/extension/src/ui/features/shield/ShieldAccountNotDeployed.tsx index 2242a7e55..165223ad3 100644 --- a/packages/extension/src/ui/features/shield/ShieldAccountNotDeployed.tsx +++ b/packages/extension/src/ui/features/shield/ShieldAccountNotDeployed.tsx @@ -1,4 +1,4 @@ -import { FlowHeader, icons } from "@argent/ui" +import { FlowHeader, icons } from "@argent/x-ui" import { FC } from "react" const { ArgentShieldIcon } = icons interface ShieldAccountNotReadyProps { diff --git a/packages/extension/src/ui/features/shield/ShieldAccountOTPScreen.tsx b/packages/extension/src/ui/features/shield/ShieldAccountOTPScreen.tsx index 13dde1a5e..06e26df8b 100644 --- a/packages/extension/src/ui/features/shield/ShieldAccountOTPScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldAccountOTPScreen.tsx @@ -8,16 +8,12 @@ import { useRouteFlow, } from "../../routes" import { ShieldBaseOTPScreen } from "./ShieldBaseOTPScreen" -import { useShieldOnboardingTracking } from "./useShieldTracking" export const ShieldAccountOTPScreen: FC = () => { const accountAddress = useRouteAccountAddress() const email = useRouteEmailAddress() const navigate = useNavigate() const flow = useRouteFlow() - const { trackSuccess } = useShieldOnboardingTracking({ - stepId: "enterPasscode", - }) const onBack = useCallback(() => { navigate( @@ -33,7 +29,6 @@ export const ShieldAccountOTPScreen: FC = () => { }, [accountAddress, navigate, flow]) const onOTPConfirmed = useCallback(() => { - void trackSuccess() switch (flow) { case "shield": return navigate(routes.shieldAccountAction(accountAddress), { @@ -48,7 +43,7 @@ export const ShieldAccountOTPScreen: FC = () => { replace: true, }) } - }, [accountAddress, navigate, trackSuccess, flow]) + }, [accountAddress, navigate, flow]) if (!email) { return ( diff --git a/packages/extension/src/ui/features/shield/ShieldAccountStartScreen.tsx b/packages/extension/src/ui/features/shield/ShieldAccountStartScreen.tsx index a9b684cce..9d9e65d22 100644 --- a/packages/extension/src/ui/features/shield/ShieldAccountStartScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldAccountStartScreen.tsx @@ -5,7 +5,7 @@ import { NavigationContainer, icons, useToast, -} from "@argent/ui" +} from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC, useCallback, useState } from "react" import { useNavigate } from "react-router-dom" @@ -21,7 +21,6 @@ import { ShieldAccountActivate } from "./ShieldAccountActivate" import { ShieldAccountDeactivate } from "./ShieldAccountDeactivate" import { ShieldAccountNotReady } from "./ShieldAccountNotDeployed" import { useRouteAccount } from "./useRouteAccount" -import { useShieldOnboardingTracking } from "./useShieldTracking" import { useShieldVerifiedEmail } from "./useShieldVerifiedEmail" const { ArgentShieldIcon } = icons @@ -35,12 +34,7 @@ export const ShieldAccountStartScreen: FC = () => { const network = useCurrentNetwork() const needsUpgrade = useCheckUpgradeAvailable(account) - const { trackSuccess } = useShieldOnboardingTracking({ - stepId: "welcome", - }) - const onActivate = useCallback(async () => { - void trackSuccess() if (verifiedEmail) { try { setIsLoading(true) @@ -74,14 +68,7 @@ export const ShieldAccountStartScreen: FC = () => { } else { navigate(routes.argentAccountEmail(account?.address, "shield")) } - }, [ - account?.address, - account?.guardian, - navigate, - toast, - trackSuccess, - verifiedEmail, - ]) + }, [account?.address, account?.guardian, navigate, toast, verifiedEmail]) const isAvailable = network.id === ARGENT_SHIELD_NETWORK_ID diff --git a/packages/extension/src/ui/features/shield/ShieldBaseActionScreen.tsx b/packages/extension/src/ui/features/shield/ShieldBaseActionScreen.tsx index 411d2cf01..23c20d97d 100644 --- a/packages/extension/src/ui/features/shield/ShieldBaseActionScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldBaseActionScreen.tsx @@ -4,7 +4,7 @@ import { FlowHeader, NavigationContainer, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/shield/ShieldBaseFinishScreen.tsx b/packages/extension/src/ui/features/shield/ShieldBaseFinishScreen.tsx index 71afcea44..407e305ec 100644 --- a/packages/extension/src/ui/features/shield/ShieldBaseFinishScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldBaseFinishScreen.tsx @@ -4,7 +4,7 @@ import { FlowHeader, FlowHeaderProps, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Center } from "@chakra-ui/react" import { FC, useCallback } from "react" import { To, useNavigate } from "react-router-dom" @@ -13,7 +13,6 @@ import { ChangeGuardian, LiveAccountGuardianState, } from "./usePendingChangingGuardian" -import { useShieldOnboardingTracking } from "./useShieldTracking" const { ArgentShieldIcon, ArgentShieldDeactivateIcon, TickIcon, AlertIcon } = icons @@ -101,17 +100,9 @@ export const ShieldBaseFinishScreen: FC = ({ liveAccountGuardianState, }) - const { trackSuccess } = useShieldOnboardingTracking({ - stepId: - liveAccountGuardianState?.type === ChangeGuardian.ADDING - ? "addArgentShieldFinish" - : "removeArgentShieldFinish", - }) - const onFinish = useCallback(() => { - void trackSuccess() navigate(returnRoute) - }, [navigate, returnRoute, trackSuccess]) + }, [navigate, returnRoute]) return (
diff --git a/packages/extension/src/ui/features/shield/ShieldBaseOTPScreen.tsx b/packages/extension/src/ui/features/shield/ShieldBaseOTPScreen.tsx index 83e4ce0c1..3395e9a68 100644 --- a/packages/extension/src/ui/features/shield/ShieldBaseOTPScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldBaseOTPScreen.tsx @@ -6,7 +6,7 @@ import { NavigationContainer, icons, useToast, -} from "@argent/ui" +} from "@argent/x-ui" import { Center, HStack, PinInputField } from "@chakra-ui/react" import { FC, MouseEvent, useCallback, useRef, useState } from "react" import { useForm } from "react-hook-form" diff --git a/packages/extension/src/ui/features/shield/ShieldValidationErrorScreen.tsx b/packages/extension/src/ui/features/shield/ShieldValidationErrorScreen.tsx index f9819a117..4586bee84 100644 --- a/packages/extension/src/ui/features/shield/ShieldValidationErrorScreen.tsx +++ b/packages/extension/src/ui/features/shield/ShieldValidationErrorScreen.tsx @@ -5,12 +5,12 @@ import { FlowHeader, NavigationContainer, icons, -} from "@argent/ui" +} from "@argent/x-ui" import { Flex, Link } from "@chakra-ui/react" import { FC, useCallback } from "react" -import { ZENDESK_LINK } from "../userReview/ReviewFeedbackScreen" -import { useShieldTracking } from "./useShieldTracking" +import { ZENDESK_LINK } from "../userReview/constants" + import { SHIELD_EMAIL_VALIDATION_FAILURE_SCENARIO_1, SHIELD_EMAIL_VALIDATION_FAILURE_SCENARIO_2, @@ -28,17 +28,9 @@ export interface ShieldValidationErrorScreenProps { export const ShieldValidationErrorScreen: FC< ShieldValidationErrorScreenProps > = ({ onBack, error, onDone }) => { - const { trackSuccess } = useShieldTracking("argentShieldError", { - errorId: - error === SHIELD_EMAIL_VALIDATION_FAILURE_SCENARIO_2 - ? "emailNotMatch" - : "emailAlreadyInUseForOtherSeedphrase", - }) - const onDoneClick = useCallback(() => { - void trackSuccess() onDone() - }, [onDone, trackSuccess]) + }, [onDone]) const subtitle = error === SHIELD_EMAIL_VALIDATION_FAILURE_SCENARIO_1 ? ( diff --git a/packages/extension/src/ui/features/shield/WithArgentShieldVerified.tsx b/packages/extension/src/ui/features/shield/WithArgentShieldVerified.tsx index 412202370..699261fa0 100644 --- a/packages/extension/src/ui/features/shield/WithArgentShieldVerified.tsx +++ b/packages/extension/src/ui/features/shield/WithArgentShieldVerified.tsx @@ -1,4 +1,4 @@ -import { AlertDialog, useToast } from "@argent/ui" +import { AlertDialog, useToast } from "@argent/x-ui" import { Skeleton, VStack } from "@chakra-ui/react" import { useAtom } from "jotai" import { isArray } from "lodash-es" diff --git a/packages/extension/src/ui/features/shield/escape/EscapeBanner.tsx b/packages/extension/src/ui/features/shield/escape/EscapeBanner.tsx index a5a236088..9d3eda11f 100644 --- a/packages/extension/src/ui/features/shield/escape/EscapeBanner.tsx +++ b/packages/extension/src/ui/features/shield/escape/EscapeBanner.tsx @@ -1,4 +1,4 @@ -import { AlertButton, icons } from "@argent/ui" +import { AlertButton, icons } from "@argent/x-ui" import { Spinner } from "@chakra-ui/react" import { FC } from "react" import { useNavigate } from "react-router-dom" diff --git a/packages/extension/src/ui/features/shield/escape/EscapeGuardian.tsx b/packages/extension/src/ui/features/shield/escape/EscapeGuardian.tsx index 63c641eeb..f040d6c6a 100644 --- a/packages/extension/src/ui/features/shield/escape/EscapeGuardian.tsx +++ b/packages/extension/src/ui/features/shield/escape/EscapeGuardian.tsx @@ -1,8 +1,7 @@ -import { Button, FlowHeader, P4, icons } from "@argent/ui" +import { Button, FlowHeader, P4, icons } from "@argent/x-ui" import { Center, Flex, ListItem, OrderedList } from "@chakra-ui/react" import { FC } from "react" -import { analytics } from "../../../services/analytics" import { ESCAPE_GUARDIAN_LINK, ShieldExternalLinkButton, @@ -45,13 +44,7 @@ export const EscapeGuardian: FC = ({
{ - analytics.track("argentShieldEscapeScreenAction", { - escapeId: "escapeGuardian", - remainingTime: liveAccountEscape.activeFromNowMs, - action: "detailedInstructions", - }) - }} + onClick={() => undefined} href={ESCAPE_GUARDIAN_LINK} my={3} > diff --git a/packages/extension/src/ui/features/shield/escape/EscapeGuardianReady.tsx b/packages/extension/src/ui/features/shield/escape/EscapeGuardianReady.tsx index 90b68f4f9..a8ac5e11c 100644 --- a/packages/extension/src/ui/features/shield/escape/EscapeGuardianReady.tsx +++ b/packages/extension/src/ui/features/shield/escape/EscapeGuardianReady.tsx @@ -1,4 +1,4 @@ -import { Button, FlowHeader, P3, icons } from "@argent/ui" +import { Button, FlowHeader, P3, icons } from "@argent/x-ui" import { Flex } from "@chakra-ui/react" import { FC } from "react" diff --git a/packages/extension/src/ui/features/shield/escape/EscapeSigner.tsx b/packages/extension/src/ui/features/shield/escape/EscapeSigner.tsx index e4e8a47c3..309293615 100644 --- a/packages/extension/src/ui/features/shield/escape/EscapeSigner.tsx +++ b/packages/extension/src/ui/features/shield/escape/EscapeSigner.tsx @@ -1,10 +1,10 @@ -import { Button, FlowHeader, P4, icons } from "@argent/ui" +import { Button, FlowHeader, P4, icons } from "@argent/x-ui" import { Flex, VStack } from "@chakra-ui/react" import { FC } from "react" import { ESCAPE_SECURITY_PERIOD_DAYS } from "../../../../shared/account/details/escape.model" -import { analytics } from "../../../services/analytics" -import { ZENDESK_LINK } from "../../userReview/ReviewFeedbackScreen" + +import { ZENDESK_LINK } from "../../userReview/constants" import { ESCAPE_GUARDIAN_LINK, ShieldExternalLinkButton, @@ -45,13 +45,7 @@ export const EscapeSigner: FC = ({ {ESCAPE_SECURITY_PERIOD_DAYS} days. Check detailed instructions here: { - analytics.track("argentShieldEscapeScreenAction", { - escapeId: "escapeSigner", - remainingTime: liveAccountEscape.activeFromNowMs, - action: "detailedInstructions", - }) - }} + onClick={() => undefined} href={ESCAPE_GUARDIAN_LINK} my={3} > @@ -60,13 +54,7 @@ export const EscapeSigner: FC = ({ , - }, -} diff --git a/packages/storybook/src/ui/components/DetailAccordion.stories.tsx b/packages/storybook/src/ui/components/DetailAccordion.stories.tsx deleted file mode 100644 index 2479949f3..000000000 --- a/packages/storybook/src/ui/components/DetailAccordion.stories.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { - DetailAccordion, - DetailAccordionButton, - DetailAccordionHeader, - DetailAccordionItem, - DetailAccordionPanel, - DetailAccordionRow, -} from "@argent/ui" - -export default { - component: DetailAccordion, -} - -const Inner = () => ( - - - - - - - - - - - - - - - - - - - - - - - - - - -) - -export const WithHeader = () => ( - <> - Lorem ipsum dolor - - -) - -export const WithoutHeader = () => diff --git a/packages/storybook/src/ui/components/Empty.stories.tsx b/packages/storybook/src/ui/components/Empty.stories.tsx deleted file mode 100644 index e09516d38..000000000 --- a/packages/storybook/src/ui/components/Empty.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Empty, EmptyButton, icons } from "@argent/ui" - -const { AddIcon } = icons - -export default { - component: Empty, - parameters: { - layout: "fullscreen", - }, -} - -export const Default = { - args: {}, -} - -export const WithButton = { - args: { - children: }>Create account, - }, -} diff --git a/packages/storybook/src/ui/components/ErrorBoundary.stories.tsx b/packages/storybook/src/ui/components/ErrorBoundary.stories.tsx index 3d73b43be..54692220d 100644 --- a/packages/storybook/src/ui/components/ErrorBoundary.stories.tsx +++ b/packages/storybook/src/ui/components/ErrorBoundary.stories.tsx @@ -3,9 +3,6 @@ import ErrorBoundaryFallbackWithCopyError from "@argent-x/extension/src/ui/compo export default { component: ErrorBoundaryFallbackWithCopyError, - parameters: { - layout: "fullscreen", - }, } const error = new BaseError({ message: "Lorem ipsum" }) diff --git a/packages/storybook/src/ui/components/Input.stories.tsx b/packages/storybook/src/ui/components/Input.stories.tsx deleted file mode 100644 index 7799c976e..000000000 --- a/packages/storybook/src/ui/components/Input.stories.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { Input, icons, theme } from "@argent/ui" -import { - InputGroup, - InputLeftElement, - InputProps, - InputRightElement, - VStack, -} from "@chakra-ui/react" -import { getThemingArgTypes } from "@chakra-ui/storybook-addon" - -const { SearchIcon, QrIcon } = icons - -export default { - component: Input, - render: (props: InputProps) => ( - - - - - - - - - - - - - - - - - - - - ), - argTypes: { - isDisabled: { - control: "boolean", - defaultValue: false, - }, - isInvalid: { - control: "boolean", - defaultValue: false, - }, - ...getThemingArgTypes(theme, "Input"), - }, -} - -export const Default = { - args: { - placeholder: "Placeholder", - }, -} - -export const SM = { - args: { - ...Default.args, - size: "sm", - }, -} - -export const Filled = { - args: { - variant: "filled", - value: "Lorem ipsum dolor", - }, -} - -export const FilledIsInvalid = { - args: { - variant: "filled", - value: "Lorem ipsum dolor", - isInvalid: true, - }, -} - -export const Outline = { - args: { - variant: "outline", - value: "Lorem ipsum dolor", - }, -} - -export const OutlineIsInvalid = { - args: { - variant: "outline", - value: "Lorem ipsum dolor", - isInvalid: true, - }, -} diff --git a/packages/storybook/src/ui/components/List.stories.tsx b/packages/storybook/src/ui/components/List.stories.tsx deleted file mode 100644 index 59fa8b3de..000000000 --- a/packages/storybook/src/ui/components/List.stories.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { ListItem, OrderedList } from "@chakra-ui/react" - -export default { - component: OrderedList, -} - -export const Ordered = () => ( - - - Lorem ipsum dolor sit amet, consectetur adipisicing elit - - - Assumenda, quia temporibus eveniet a libero incidunt suscipit - - - Quidem, ipsam illum quis sed voluptatum quae eum fugit earum - - -) diff --git a/packages/storybook/src/ui/components/Menu.stories.tsx b/packages/storybook/src/ui/components/Menu.stories.tsx deleted file mode 100644 index 62e5d0be1..000000000 --- a/packages/storybook/src/ui/components/Menu.stories.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { icons } from "@argent/ui" -import { theme } from "@argent/ui" -import { Button, Menu, MenuButton, MenuItem, MenuList } from "@chakra-ui/react" -import { getThemingArgTypes } from "@chakra-ui/storybook-addon" -import { FC } from "react" - -const { DropdownDownIcon } = icons - -const networks = ["Mainnet", "Testnet", "Integration", "Localhost 5050"] -const selectedNetwork = networks[0] - -const MenuStory: FC = (props: any) => ( - - } {...props}> - {selectedNetwork} - - - {networks.map((n) => { - return ( - console.log("onClick", n)}> - {n} - - ) - })} - - -) - -export default { - component: MenuStory, - argTypes: { - ...getThemingArgTypes(theme, "Menu"), - }, -} - -export const Default = { - args: { - size: "2xs", - }, -} - -export const Disabled = { - args: { - ...Default.args, - isDisabled: true, - }, -} diff --git a/packages/storybook/src/ui/components/ModalDialog.stories.tsx b/packages/storybook/src/ui/components/ModalDialog.stories.tsx deleted file mode 100644 index 945554f55..000000000 --- a/packages/storybook/src/ui/components/ModalDialog.stories.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { ModalDialog, P4 } from "@argent/ui" -import { ComponentProps } from "react" - -export default { - component: ModalDialog, -} - -const Default = { - render: (props: ComponentProps) => { - return - }, -} - -export const Example = { - ...Default, - args: { - title: "Example", - children: ( - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lectus nisl, - diam iaculis porttitor., - - ), - }, - argTypes: { - onClose: { action: "onClose" }, - }, -} diff --git a/packages/storybook/src/ui/components/ModalDialogData.stories.tsx b/packages/storybook/src/ui/components/ModalDialogData.stories.tsx deleted file mode 100644 index 30a838dea..000000000 --- a/packages/storybook/src/ui/components/ModalDialogData.stories.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { ModalDialogData } from "@argent/ui" -import { ComponentProps } from "react" - -export default { - component: ModalDialogData, -} - -const Default = { - render: (props: ComponentProps) => { - return - }, -} - -const data = JSON.stringify( - [ - "0x07e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - "100000000000000", - "0", - ], - null, - 2, -) - -export const CallData = { - ...Default, - args: { - title: "Transaction call data", - data, - }, - argTypes: { - onClose: { action: "onClose" }, - }, -} diff --git a/packages/storybook/src/ui/components/NavigationContainer.stories.tsx b/packages/storybook/src/ui/components/NavigationContainer.stories.tsx deleted file mode 100644 index 6437c63cb..000000000 --- a/packages/storybook/src/ui/components/NavigationContainer.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { BarBackButton, NavigationContainer } from "@argent/ui" - -import { decorators } from "../../decorators/routerDecorators" - -export default { - component: NavigationContainer, - decorators, - parameters: { - layout: "fullscreen", - }, -} - -export const Default = { - args: { - title: "Title in here", - leftButton: , - }, -} diff --git a/packages/storybook/src/ui/components/NavigationContainerSkeleton.stories.tsx b/packages/storybook/src/ui/components/NavigationContainerSkeleton.stories.tsx deleted file mode 100644 index 9ca371b9b..000000000 --- a/packages/storybook/src/ui/components/NavigationContainerSkeleton.stories.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { NavigationContainerSkeleton } from "@argent/ui" - -export default { - component: NavigationContainerSkeleton, - parameters: { - layout: "fullscreen", - }, -} - -export const Default = { - args: {}, -} diff --git a/packages/storybook/src/ui/components/NestedAccordion.stories.tsx b/packages/storybook/src/ui/components/NestedAccordion.stories.tsx deleted file mode 100644 index dddeed182..000000000 --- a/packages/storybook/src/ui/components/NestedAccordion.stories.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { NestedAccordion } from "@argent/ui" -import { ComponentProps, FC } from "react" -import { - unframedSignature, - testDappSignature, - dappLandPayload, -} from "@argent-x/extension/src/ui/features/transactionReview/signature/fixtures" - -const Story: FC> = (props) => { - return -} - -export default { - component: Story, -} - -export const TestDapp = { - args: { - json: testDappSignature, - initiallyExpanded: true, - }, -} - -export const DappLand = { - args: { - json: dappLandPayload, - initiallyExpanded: true, - }, -} - -export const Unframed = { - args: { - json: unframedSignature, - initiallyExpanded: true, - }, -} - -export const Invalid = { - args: { - json: undefined, - initiallyExpanded: true, - }, -} diff --git a/packages/storybook/src/ui/components/NftDetails.stories.tsx b/packages/storybook/src/ui/components/NftDetails.stories.tsx deleted file mode 100644 index f6e6cc57a..000000000 --- a/packages/storybook/src/ui/components/NftDetails.stories.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { aspect } from "@argent-x/extension/src/ui/features/actions/__fixtures__" -import { DetailAccordion, DetailAccordionItem, NftDetails } from "@argent/ui" -import { ComponentProps } from "react" - -export default { - component: NftDetails, - render: (props: ComponentProps) => ( - - - - - - ), -} - -const { aggregatedData } = aspect -const dataIndex = 0 -const { amount, token, usdValue, safe } = aggregatedData[dataIndex] -const isDisabled = false - -export const Default = { - args: { - contractAddress: token.address, - tokenId: token.tokenId, - networkId: token.networkId, - dataIndex, - totalData: aggregatedData.length, - amount, - usdValue, - safe, - isDisabled, - }, -} diff --git a/packages/storybook/src/ui/components/Option.stories.tsx b/packages/storybook/src/ui/components/Option.stories.tsx index 351c89bef..0a72051c3 100644 --- a/packages/storybook/src/ui/components/Option.stories.tsx +++ b/packages/storybook/src/ui/components/Option.stories.tsx @@ -1,5 +1,5 @@ import { Option } from "@argent-x/extension/src/ui/components/Options" -import { icons } from "@argent/ui" +import { icons } from "@argent/x-ui" const { CardIcon } = icons diff --git a/packages/storybook/src/ui/components/PasswordStrengthIndicator.stories.tsx b/packages/storybook/src/ui/components/PasswordStrengthIndicator.stories.tsx deleted file mode 100644 index b590df959..000000000 --- a/packages/storybook/src/ui/components/PasswordStrengthIndicator.stories.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { PasswordStrengthIndicator } from "@argent/ui" -import { Box } from "@chakra-ui/react" -import { ComponentProps, FC, useState } from "react" - -export default { - component: PasswordStrengthIndicator, -} - -const Template: FC> = ( - props, -) => { - const [pwd, setPassword] = useState("") - return ( - - setPassword(e.target.value)} - placeholder="your password here" - style={{ - marginBottom: "1rem", - }} - /> - - - ) -} -export const Default = { - render: Template, - args: { - password: "someMoreSophisticatedPwd5", - }, -} diff --git a/packages/storybook/src/ui/components/PinInputField.stories.tsx b/packages/storybook/src/ui/components/PinInputField.stories.tsx deleted file mode 100644 index c1df6548d..000000000 --- a/packages/storybook/src/ui/components/PinInputField.stories.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { PinInput, PinInputField, theme } from "@argent/ui" -import { HStack } from "@chakra-ui/react" -import { getThemingArgTypes } from "@chakra-ui/storybook-addon" -import { ComponentProps } from "react" - -export default { - component: PinInput, - argTypes: { - isDisabled: { - control: "boolean", - defaultValue: false, - }, - isInvalid: { - control: "boolean", - defaultValue: false, - }, - ...getThemingArgTypes(theme, "PinInput"), - }, -} - -export const Default = { - render: (props: ComponentProps) => ( - - - - - - - - - - - ), - args: { - placeholder: "", - otp: true, - }, -} - -export const Filled = { - ...Default, - args: { - placeholder: "", - otp: true, - variant: "filled", - value: "1", - }, -} - -export const FilledIsInvalid = { - ...Default, - args: { - placeholder: "", - otp: true, - variant: "filled", - value: "2", - isInvalid: true, - }, -} - -export const Outline = { - ...Default, - args: { - placeholder: "", - otp: true, - variant: "outline", - value: "3", - }, -} - -export const OutlineIsInvalid = { - ...Default, - args: { - placeholder: "", - otp: true, - variant: "outline", - value: "4", - isInvalid: true, - }, -} diff --git a/packages/storybook/src/ui/components/PrettyAccountAddress.stories.tsx b/packages/storybook/src/ui/components/PrettyAccountAddress.stories.tsx deleted file mode 100644 index d84b9d6fb..000000000 --- a/packages/storybook/src/ui/components/PrettyAccountAddress.stories.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { PrettyAccountAddress } from "@argent/ui" - -export default { - component: PrettyAccountAddress, -} - -export const Default = { - args: { - accountAddress: - "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a", - networkId: "goerli-alpha", - }, -} - -export const ContactAddress = { - args: { - ...Default.args, - accountName: "Lorem ipsum", - }, -} - -export const FallbackAddress = { - args: { - ...Default.args, - fallbackValue: (accountAddreess: string) => - `Lorem ipsum ${accountAddreess}`, - }, -} diff --git a/packages/storybook/src/ui/components/Select.stories.tsx b/packages/storybook/src/ui/components/Select.stories.tsx deleted file mode 100644 index fc28f1dc9..000000000 --- a/packages/storybook/src/ui/components/Select.stories.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { H6, Select, icons } from "@argent/ui" -import { FC, useState } from "react" - -const { SendIcon } = icons - -const networks = ["Mainnet", "Testnet", "Integration", "Localhost 5050"] - -const options = networks.map((network, index) => ({ - label: network, - value: `network-${index}`, -})) - -const componentOptions = networks.map((network, index) => ({ - icon: , - label:
{network}
, - labelSelected: network, - value: `network-${index}`, -})) - -const SelectStory: FC = (props: any) => { - const [value, setValue] = useState() - const onChange = (newValue: string) => setValue(newValue) - return onChange(parseInt(e.target.value))} - /> - {onIncrease && ( - } - /> - )} - {onConfirm && ( - } - /> - )} -
- ) -} diff --git a/packages/ui/src/components/FlowHeader.tsx b/packages/ui/src/components/FlowHeader.tsx deleted file mode 100644 index 06a764783..000000000 --- a/packages/ui/src/components/FlowHeader.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { - Center, - CenterProps, - ChakraComponent, - Circle, - Spinner, -} from "@chakra-ui/react" -import { FC, ReactNode } from "react" - -import { TickIcon } from "./icons" -import { H4, P3 } from "./Typography" - -const variants = { - default: { - bg: "neutrals.700", - fg: "white", - }, - primary: { - bg: "primary.500", - fg: "neutrals.900", - }, - removed: { - bg: "error.900", - fg: "error.400", - }, - success: { - bg: "success.900", - fg: "success.500", - }, - warning: { - bg: "warning.500", - fg: "neutrals.900", - }, - danger: { - bg: "error.900", - fg: "error.400", - }, -} - -export type FlowHeaderVariant = keyof typeof variants - -export interface FlowHeaderProps extends Omit { - title: ReactNode - subtitle?: ReactNode - variant?: FlowHeaderVariant - size?: "md" | "lg" - icon?: ChakraComponent<"svg"> - isLoading?: boolean -} - -const FlowHeader: FC = ({ - title, - subtitle, - variant: variantKey = "default", - size = "md", - icon: Icon = TickIcon, - isLoading, - ...props -}) => { - const variant = variants[variantKey] - return ( -
- - {isLoading ? ( - - ) : ( - - )} - -

{title}

- {subtitle && ( - - {subtitle} - - )} -
- ) -} - -export { FlowHeader } diff --git a/packages/ui/src/components/Input.tsx b/packages/ui/src/components/Input.tsx deleted file mode 100644 index 496915b94..000000000 --- a/packages/ui/src/components/Input.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { inputAnatomy as parts } from "@chakra-ui/anatomy" -import { Input } from "@chakra-ui/react" -import { - createMultiStyleConfigHelpers, - defineStyle, -} from "@chakra-ui/styled-system" -import { mode } from "@chakra-ui/theme-tools" - -export { Input } - -const { definePartsStyle, defineMultiStyleConfig } = - createMultiStyleConfigHelpers(parts.keys) - -export const baseStyle = definePartsStyle({ - field: { - /** placeholder */ - }, -}) - -export const variantOutline = definePartsStyle((props) => { - return { - field: { - bg: mode("white", "black")(props), - border: "1px solid", - borderColor: "border", - _placeholder: { - color: mode("gray.200", "neutrals.500")(props), - }, - _hover: { - borderColor: mode("gray.100", "neutrals.600")(props), - }, - _invalid: { - borderColor: "error.500", - boxShadow: mode("inherit", "none")(props), - _hover: { - borderColor: mode("error.400", "error.600")(props), - }, - _focusVisible: { - borderColor: "error.500", - boxShadow: mode("outlineError", "none")(props), - }, - }, - _focusVisible: { - borderColor: mode("accent.500", "neutrals.400")(props), - boxShadow: mode("outlineAccent", "none")(props), - }, - }, - } -}) - -export const variantFilled = definePartsStyle((props) => { - return { - field: { - bg: mode("gray.50", "neutrals.800")(props), - border: "none", - _placeholder: { - color: mode("gray.300", "neutrals.400")(props), - }, - _hover: { - bg: mode("gray.100", "neutrals.700")(props), - }, - _invalid: { - boxShadow: "error", - _focusVisible: { - boxShadow: mode("outlineError", "error")(props), - }, - }, - _focusVisible: { - bg: mode("white", "neutrals.700")(props), - boxShadow: mode("outlineAccent", "none")(props), - }, - }, - } -}) - -export const variantFlat = definePartsStyle((props) => { - return { - field: { - bg: mode("gray.50", "neutrals.800")(props), - border: "none", - _placeholder: { - color: mode("gray.300", "neutrals.400")(props), - }, - _hover: { - bg: mode("gray.100", "neutrals.800")(props), - }, - _invalid: { - boxShadow: "error", - _focusVisible: { - boxShadow: mode("outlineError", "error")(props), - }, - }, - _focusVisible: { - bg: mode("white", "neutrals.800")(props), - boxShadow: mode("outlineAccent", "none")(props), - }, - }, - } -}) - -const variants = { - outline: variantOutline, - filled: variantFilled, - flat: variantFlat, -} - -export const size = { - md: defineStyle({ - px: "5", - py: "4.5", - fontSize: "base", - fontWeight: "semibold", - borderRadius: "lg", - minHeight: "14", - }), - sm: defineStyle({ - px: "3", - py: "3.5", - fontSize: "base", - fontWeight: "semibold", - borderRadius: "lg", - minHeight: "12", - h: "10" /** also defines the width of InputLeftElement and InputRightElement... */, - }), - pill: defineStyle({ - px: "4", - py: "1", - fontSize: "sm", - fontWeight: "semibold", - borderRadius: "full", - minHeight: "8", - textAlign: "right", - }), -} - -const sizes = { - md: definePartsStyle({ - field: size.md, - addon: size.md, - element: defineStyle({ - ...size.md, - px: undefined, - }), - }), - sm: definePartsStyle({ - field: size.sm, - addon: size.sm, - element: defineStyle({ - ...size.sm, - px: undefined, - }), - }), - pill: definePartsStyle({ - field: size.pill, - addon: size.pill, - element: defineStyle({ - ...size.pill, - px: undefined, - }), - }), -} - -export const inputTheme = defineMultiStyleConfig({ - baseStyle, - variants, - sizes, - defaultProps: { - size: "md", - variant: "outline", - }, -}) diff --git a/packages/ui/src/components/LabelValue.tsx b/packages/ui/src/components/LabelValue.tsx deleted file mode 100644 index 8f7fd28af..000000000 --- a/packages/ui/src/components/LabelValue.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Flex, FlexProps, Text, TextProps, Tooltip } from "@chakra-ui/react" -import { - ReactNode, - isValidElement, - useCallback, - useMemo, - useRef, - useState, -} from "react" -import { typographyStyles } from "." -import { isString } from "lodash-es" -import { formatAddress, formatFullAddress, isAddress } from "@argent/shared" - -export function LabelValueStack(props: FlexProps) { - return -} - -export function LabelValueRow({ - label, - value, -}: { - label: ReactNode - value?: ReactNode -}) { - const displayValue = useMemo(() => { - if (value === undefined) { - return null - } - if (isValidElement(value)) { - return value - } - if (isString(value) && isAddress(value)) { - return ( - - - {formatAddress(value)} - - - ) - } - - return ( - - ) - }, [value]) - - return ( - - - {label} - - {displayValue} - - ) -} - -/** Truncates text to one line. If overflowing displays full text as tooltip on hover */ - -export function LabelValueAutoTooltip({ - value, - ...rest -}: TextProps & { value: ReactNode }) { - const [hasOverflow, setHasOverflow] = useState(false) - const ref = useRef(null) - const setRef = useCallback((nextRef: HTMLDivElement | null) => { - ref.current = nextRef - if (ref?.current) { - const { scrollWidth, offsetWidth } = ref.current - setHasOverflow(scrollWidth > offsetWidth) - } - }, []) - return ( - - - {value} - - - ) -} diff --git a/packages/ui/src/components/List.tsx b/packages/ui/src/components/List.tsx deleted file mode 100644 index 7703429ae..000000000 --- a/packages/ui/src/components/List.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { listAnatomy as parts } from "@chakra-ui/anatomy" -import { createMultiStyleConfigHelpers } from "@chakra-ui/styled-system" - -import { typographyStyles } from "./Typography" - -const { definePartsStyle, defineMultiStyleConfig } = - createMultiStyleConfigHelpers(parts.keys) - -const variants = { - bordered: definePartsStyle(() => ({ - container: { - border: "1px solid", - borderColor: "neutrals.600", - rounded: "lg", - counterReset: "borderedList", - marginInlineStart: 0, - margin: 0, - ...typographyStyles.P4, - }, - item: { - display: "flex", - alignItems: "center", - py: 2, - px: 3, - gap: 3, - _notLast: { - borderBottom: "1px solid", - borderColor: "neutrals.700", - }, - "&::before": { - display: "flex", - content: "counter(borderedList)", - backgroundColor: "neutrals.700", - counterIncrement: "borderedList", - rounded: "full", - width: 6, - height: 6, - flexShrink: 0, - textAlign: "center", - alignItems: "center", - justifyContent: "center", - }, - }, - })), -} - -export const listTheme = defineMultiStyleConfig({ variants }) diff --git a/packages/ui/src/components/LoadingPulse.tsx b/packages/ui/src/components/LoadingPulse.tsx deleted file mode 100644 index 92807718c..000000000 --- a/packages/ui/src/components/LoadingPulse.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Box, BoxProps, keyframes } from "@chakra-ui/react" -import { FC } from "react" - -const PulseAnimation = keyframes` -0% { - opacity: 1; -} -50% { - opacity: 0.5; -} -100% { - opacity: 1; -} -` - -export interface LoadingPulseProps extends BoxProps { - isLoading?: boolean -} - -export const LoadingPulse: FC = ({ isLoading, ...rest }) => { - return ( - - ) -} diff --git a/packages/ui/src/components/Menu.tsx b/packages/ui/src/components/Menu.tsx deleted file mode 100644 index a458eb9e0..000000000 --- a/packages/ui/src/components/Menu.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { menuAnatomy } from "@chakra-ui/anatomy" -import { createMultiStyleConfigHelpers } from "@chakra-ui/react" - -const { definePartsStyle, defineMultiStyleConfig } = - createMultiStyleConfigHelpers(menuAnatomy.keys) - -const sizes = { - "2xs": definePartsStyle({ - button: { - minHeight: 8, - fontSize: "sm", - }, - item: { - minHeight: 8, - fontSize: "sm", - }, - }), -} - -const baseStyle = definePartsStyle({ - button: { - fontWeight: "bold", - }, - list: { - py: 0, - borderRadius: "xl", - border: "none", - bg: "neutrals.700", - overflow: "hidden", - boxShadow: "menu", - }, - item: { - p: 3, - fontWeight: "bold", - color: "neutrals.100", - _hover: { - color: "white", - bg: "neutrals.600", - }, - _focus: { - color: "white", - bg: "neutrals.600", - }, - ".chakra-menu__icon-wrapper": { - fontSize: "inherit", - }, - }, -}) - -export const menuTheme = defineMultiStyleConfig({ - baseStyle, - sizes, - defaultProps: { - size: "2xs", - }, -}) diff --git a/packages/ui/src/components/ModalDialog.tsx b/packages/ui/src/components/ModalDialog.tsx deleted file mode 100644 index db8a4bb76..000000000 --- a/packages/ui/src/components/ModalDialog.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { - Flex, - Modal, - ModalContent, - ModalOverlay, - ModalProps, - useModalContext, -} from "@chakra-ui/react" -import { FC } from "react" - -import { pxToRem } from "../theme/utilities/pxToRem" -import { Button } from "./Button" -import { H6 } from "./Typography" -import { CloseIcon } from "./icons" - -export const ModalCloseButton: FC = () => { - const { onClose } = useModalContext() - return ( - - ) -} - -export interface ModalDialogProps extends ModalProps { - title?: string -} - -/** - * Wraps Chakra Modal {@link https://chakra-ui.com/docs/components/modal} - * with a simpler API - */ - -export const ModalDialog: FC = ({ - title, - children, - ...rest -}) => { - return ( - - - - - {title &&
{title}
} - -
- {children} -
-
-
- ) -} diff --git a/packages/ui/src/components/ModalDialogData.tsx b/packages/ui/src/components/ModalDialogData.tsx deleted file mode 100644 index 65cd2d57a..000000000 --- a/packages/ui/src/components/ModalDialogData.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Flex } from "@chakra-ui/react" -import { FC } from "react" - -import { Button } from "./Button" -import { ModalDialog, ModalDialogProps } from "./ModalDialog" -import { P4 } from "./Typography" -import { CopyIcon } from "./icons" -import { CopyTooltip } from "./CopyTooltip" -import { scrollbarStyle } from "../theme" - -export interface ModalDialogDataProps - extends Omit { - data: string -} - -export const ModalDialogData: FC = ({ - data, - ...rest -}) => { - return ( - - - - {data} - - - - - - - ) -} diff --git a/packages/ui/src/components/MotionBox.tsx b/packages/ui/src/components/MotionBox.tsx deleted file mode 100644 index eb6b4265c..000000000 --- a/packages/ui/src/components/MotionBox.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { chakra, shouldForwardProp } from "@chakra-ui/react" -import { isValidMotionProp, motion } from "framer-motion" - -export const MotionBox = chakra(motion.div, { - shouldForwardProp: (prop) => - isValidMotionProp(prop) || shouldForwardProp(prop), -}) diff --git a/packages/ui/src/components/NavigationBar.tsx b/packages/ui/src/components/NavigationBar.tsx deleted file mode 100644 index 278778137..000000000 --- a/packages/ui/src/components/NavigationBar.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { - Button, - Center, - Fade, - Flex, - FlexProps, - SkeletonCircle, - SkeletonText, - chakra, -} from "@chakra-ui/react" -import { ComponentProps, FC, ReactNode } from "react" - -import { ScrollProps, useNavigateBack } from "../hooks" -import { AbsoluteFlex } from "./Absolute" -import * as icons from "./icons" -import { H6 } from "./Typography" - -const { AddIcon, CloseIcon, ArrowLeftIcon } = icons - -export const NavigationBarHeight = 14 - -const Container = chakra(Flex, { - baseStyle: { - alignItems: "center", - bottom: "initial", - h: NavigationBarHeight, - px: 3, - py: 2, - transitionProperty: "background", - transitionDuration: "fast", - flexShrink: 0, - zIndex: 1 /** shadow should appear over siblings regardless of DOM order */, - }, -}) - -const ButtonsContainer = chakra(AbsoluteFlex, { - baseStyle: { - alignItems: "center", - justifyContent: "space-between", - px: 3, - py: 2, - }, -}) - -const TitleContainer = chakra(AbsoluteFlex, { - baseStyle: { - alignItems: "center", - justifyContent: "center", - }, -}) - -export interface NavigationBarProps extends Omit { - isAbsolute?: boolean - leftButton?: ReactNode - title?: ReactNode - rightButton?: ReactNode - scroll?: ScrollProps - scrollContent?: ReactNode -} - -export const BarIconButton: FC> = ({ - children, - ...rest -}) => ( - -) - -export const BarBackButton: FC> = ( - props, -) => { - const onClick = useNavigateBack() - return ( - - - - ) -} - -export const BarCloseButton: FC> = ( - props, -) => { - const onClick = useNavigateBack() - return ( - - - - ) -} - -export const BarAddButton: FC> = ( - props, -) => { - return ( - - - - ) -} - -export const NavigationBar: FC = ({ - isAbsolute, - leftButton, - rightButton, - title, - scroll, - children, - scrollContent, - ...rest -}) => { - const scrollTop = scroll?.scrollTop ?? 0 - const isTransparent = scrollTop <= 16 - const showScrollContent = scrollTop > 90 - return ( - - {title && ( - -
- {title} -
-
- )} - - - {typeof scrollContent === "string" ? ( -
{scrollContent}
- ) : ( - <>{scrollContent} - )} -
-
- {(leftButton || rightButton) && ( - - {leftButton} - {rightButton && {rightButton}} - - )} - {children} -
- ) -} - -export const NavigationBarSkeleton: FC = () => { - return ( - -
- -
- -
- -
-
- ) -} diff --git a/packages/ui/src/components/NavigationContainer.tsx b/packages/ui/src/components/NavigationContainer.tsx deleted file mode 100644 index eee0ebdb3..000000000 --- a/packages/ui/src/components/NavigationContainer.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { FC, PropsWithChildren } from "react" - -import { useScroll } from "../hooks" -import { useScrollRestoration } from "../hooks/useScrollRestoration" -import { - NavigationBar, - NavigationBarProps, - NavigationBarSkeleton, -} from "./NavigationBar" -import { ScrollContainer } from "./ScrollContainer" - -type BaseNavigationContainerProps = Omit - -export interface NavigationContainerProps extends BaseNavigationContainerProps { - /** Unique id for persisting scroll position - if provided, scroll position will be restored when navigating 'back' to this component. See {@link useScrollRestoration} */ - scrollKey?: string -} - -interface ScrollRestorationNavigationContainerProps - extends BaseNavigationContainerProps { - scrollKey: string -} - -/** - * Combines {@link NavigationBar} and {@link ScrollContainer} and sets up the scroll interaction between them - */ - -export const NavigationContainer: FC = ({ - scrollKey, - ...rest -}) => { - if (scrollKey) { - return ( - - ) - } - return -} - -/** No `scrollKey`, no scroll restoration */ - -const BaseNavigationContainer: FC = ({ - children, - ...rest -}) => { - const { scrollRef, scroll } = useScroll() - return ( - <> - - {children} - - ) -} - -/** With scroll restoration */ - -const ScrollRestorationNavigationContainer: FC< - ScrollRestorationNavigationContainerProps -> = ({ scrollKey, children, ...rest }) => { - const { scrollRef, scroll } = useScrollRestoration(scrollKey) - return ( - <> - - {children} - - ) -} - -/** Skeleton */ - -export const NavigationContainerSkeleton: FC = ({ - children, -}) => { - return ( - <> - - <>{children} - - ) -} diff --git a/packages/ui/src/components/NestedAccordion.tsx b/packages/ui/src/components/NestedAccordion.tsx deleted file mode 100644 index 410e87cf4..000000000 --- a/packages/ui/src/components/NestedAccordion.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { - Accordion, - AccordionButton, - AccordionItem, - AccordionPanel, - AccordionProps, - Text, -} from "@chakra-ui/react" -import { - isArray, - isEmpty, - isObject, - isObjectLike, - lowerCase, - upperFirst, -} from "lodash-es" -import { FC } from "react" -import { JsonArray, JsonObject } from "type-fest" -import { AccordionIconDropdown, LabelValueRow, LabelValueStack } from "." - -interface NestedAccordionProps extends AccordionProps { - json: JsonObject | JsonArray - initiallyExpanded?: boolean -} - -export const NestedAccordion: FC = ({ - json, - initiallyExpanded, - ...rest -}) => { - if (!isObjectLike(json)) { - return null - } - const defaultIndex = initiallyExpanded ? 0 : undefined - return ( - - {Object.entries(json).map(([label, value], index) => { - const key = `${label}-${index}` - const displayLabel = upperFirst(lowerCase(label)) - - if ((isObject(value) || isArray(value)) && !isEmpty(value)) { - return ( - - - - {displayLabel} - - - - - - - - ) - } - - /** Show empty array as "–" rather than empty accordion */ - const displayValue = isArray(value) && isEmpty(value) ? "–" : `${value}` - - return ( - - ) - })} - - ) -} diff --git a/packages/ui/src/components/PasswordStrengthIndicator.tsx b/packages/ui/src/components/PasswordStrengthIndicator.tsx deleted file mode 100644 index 06900e42c..000000000 --- a/packages/ui/src/components/PasswordStrengthIndicator.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Flex } from "@chakra-ui/react" -import { zxcvbnOptions } from "@zxcvbn-ts/core" -import { FC } from "react" - -import { usePasswordStrength } from "../hooks/usePasswordStrength" -import { PasswordStrengthIndicatorBar } from "./PasswordStrengthIndicatorBar" - -interface PasswordStrengthIndicatorProps { - password: string - error?: string -} - -const PasswordStrengthIndicator: FC = ({ - password, - error, -}) => { - const indicator = usePasswordStrength(password, async () => { - // import zxcvbnEnPackage from "@zxcvbn-ts/language-en" - const zxcvbnEnPackage = await import("@zxcvbn-ts/language-en").then( - ({ default: x }) => x, - ) - // import zxcvbnCommonPackage from "@zxcvbn-ts/language-common" - const zxcvbnCommonPackage = await import("@zxcvbn-ts/language-common").then( - ({ default: x }) => x, - ) - - const options = { - dictionary: { - ...zxcvbnCommonPackage?.dictionary, - ...zxcvbnEnPackage?.dictionary, - }, - useLevenshteinDistance: true, // recommended - graphs: zxcvbnCommonPackage?.adjacencyGraphs, - translations: zxcvbnEnPackage?.translations, - } - - zxcvbnOptions.setOptions(options) - }) - - if (!password) { - return <> - } - - return ( - - {typeof indicator?.score === "number" ? ( - - ) : ( - - )} - - ) -} - -export { PasswordStrengthIndicator } diff --git a/packages/ui/src/components/PasswordStrengthIndicatorBar.tsx b/packages/ui/src/components/PasswordStrengthIndicatorBar.tsx deleted file mode 100644 index 2372cbed0..000000000 --- a/packages/ui/src/components/PasswordStrengthIndicatorBar.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from "react" -import { Box, Flex, Text } from "@chakra-ui/react" - -interface PasswordStrengthIndicatorBarProps { - progress: number - error?: string -} - -export const PasswordStrengthIndicatorBar: React.FC< - PasswordStrengthIndicatorBarProps -> = ({ progress, error }) => { - const colors = ["error.500", "warning.500", "accent.500", "success.500"] - const strengthLabels = [ - "Very weak password", - "Weak password", - "Strong password", - "Very strong password", - ] - - return ( - - - {colors.map((color, index) => ( - index ? color : "neutrals.800"} - ml={index !== 0 ? "4px" : "0"} - borderRadius="md" - /> - ))} - - {error ?? strengthLabels[progress - 1]} - - ) -} diff --git a/packages/ui/src/components/PinInput.tsx b/packages/ui/src/components/PinInput.tsx deleted file mode 100644 index 6aaee6e9b..000000000 --- a/packages/ui/src/components/PinInput.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { HStack, PinInput, PinInputField, chakra } from "@chakra-ui/react" -import { defineStyle, defineStyleConfig } from "@chakra-ui/styled-system" - -import { - baseStyle as inputBaseStyle, - size as inputSizes, - variantFilled, - variantFlat, - variantOutline, -} from "./Input" -import { typographyStyles } from "./Typography" - -export { PinInputField, PinInput } - -const baseStyle = defineStyle({ - ...inputBaseStyle, - textAlign: "center", -}) - -const variants = { - outline: defineStyle((props) => variantOutline(props).field), - filled: defineStyle((props) => variantFilled(props).field), - flat: defineStyle((props) => variantFlat(props).field), -} - -const sizes = { - ...inputSizes, - md: { - ...inputSizes.md, - ...typographyStyles.H3, - w: 12, - px: 0, - }, -} - -export const pinInputTheme = defineStyleConfig({ - baseStyle, - variants, - sizes, - defaultProps: { - size: "md", - variant: "outline", - }, -}) - -export const PinInputWrapper = chakra(HStack, { - baseStyle: { - gap: 2, - display: "flex", - }, -}) diff --git a/packages/ui/src/components/PreBox.tsx b/packages/ui/src/components/PreBox.tsx deleted file mode 100644 index d86a8af9d..000000000 --- a/packages/ui/src/components/PreBox.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { TextProps } from "@chakra-ui/react" -import { FC, useMemo } from "react" - -import { P4 } from "./Typography" - -export interface PreJsonStringifyProps extends TextProps { - json: Parameters[0] -} - -export const PreBoxJsonStringify: FC = ({ - json, - ...rest -}) => { - const stringified = useMemo(() => { - try { - return JSON.stringify(json, null, 2) - } catch (e) { - return String(e) - } - }, [json]) - return {stringified} -} - -export const PreBox: FC = (props) => { - return ( - - ) -} diff --git a/packages/ui/src/components/Progress.tsx b/packages/ui/src/components/Progress.tsx deleted file mode 100644 index 0abe57b7a..000000000 --- a/packages/ui/src/components/Progress.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Progress, defineStyleConfig } from "@chakra-ui/react" - -export { Progress } - -export const progressTheme = defineStyleConfig({ - baseStyle: () => { - return { - borderRadius: "lg", - filledTrack: { - bg: "primary.500", - }, - track: { - bg: "#803820", - }, - } - }, -}) diff --git a/packages/ui/src/components/RoundButton.tsx b/packages/ui/src/components/RoundButton.tsx deleted file mode 100644 index f2f8f7f17..000000000 --- a/packages/ui/src/components/RoundButton.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Button, ButtonProps, Circle } from "@chakra-ui/react" - -export const RoundButton = (props: ButtonProps) => { - return ( - - ) -} diff --git a/packages/ui/src/components/ScrollContainer.tsx b/packages/ui/src/components/ScrollContainer.tsx deleted file mode 100644 index 2b0fb71c1..000000000 --- a/packages/ui/src/components/ScrollContainer.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Flex, FlexProps, forwardRef } from "@chakra-ui/react" - -import { scrollbarStyle } from "../theme" - -export const ScrollContainer = forwardRef((props, ref) => { - return ( - - ) -}) -ScrollContainer.displayName = "ScrollContainer" diff --git a/packages/ui/src/components/SearchInput.tsx b/packages/ui/src/components/SearchInput.tsx deleted file mode 100644 index 0e855a393..000000000 --- a/packages/ui/src/components/SearchInput.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Box, InputElementProps, Text } from "@chakra-ui/react" -import { forwardRef } from "react" - -import { SearchIcon } from "./icons" -import { Input } from "./Input" - -const SearchInput = forwardRef( - ({ ...props }, ref) => { - return ( - - - - - - - ) - }, -) - -SearchInput.displayName = "SearchInput" - -export { SearchInput } diff --git a/packages/ui/src/components/SeedInput.tsx b/packages/ui/src/components/SeedInput.tsx deleted file mode 100644 index 2bac434c1..000000000 --- a/packages/ui/src/components/SeedInput.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { - Box, - Input, - InputGroup, - InputLeftAddon, - SimpleGrid, - SimpleGridProps, -} from "@chakra-ui/react" -import { wordlist } from "@scure/bip39/wordlists/english" -import { - FC, - SetStateAction, - useCallback, - useMemo, - useRef, - useState, -} from "react" -import { generateFakeWords } from "./generateFakeWords" - -interface SeedInputProps extends Omit { - length?: 12 - onChange?: (seed: string) => void -} - -export const SeedInput: FC = ({ - length = 12, - onChange, - ...rest -}) => { - const refInputs = useRef(new Array(length).fill(null)) - const [focusIndex, setFocusIndex] = useState(null) - const [seedInput, _setSeedInput] = useState([...Array(length)].map(() => "")) - const setSeedInput = useCallback( - (value: SetStateAction) => { - const seed = typeof value === "function" ? value(seedInput) : value - _setSeedInput(seed) - onChange?.(seed.join(" ")) - }, - [onChange, seedInput], - ) - - const fakeWords = useMemo(() => { - return generateFakeWords(wordlist, length) - }, [length]) - - return ( - - - {fakeWords.map((word, i) => ( - - ))} - - {seedInput.map((word, i) => ( - - - - {i + 1} - - - { - setFocusIndex(i) - // select all text on focus - e.target.select() - }} - onBlur={() => setFocusIndex(null)} - type={focusIndex === i ? "text" : "password"} - fontSize={focusIndex === i ? "sm" : "md"} - onPaste={(e) => { - e.preventDefault() - const pasted = e.clipboardData.getData("text") - // split by space or newline regex - const words = pasted.split(/\s+/).filter((s) => s) - - if (words.length === length) { - setSeedInput(words) - } - }} - ref={(el) => (refInputs.current[i] = el)} - onKeyDown={(e) => { - if (e.key === "Backspace" && word === "" && i > 0) { - // switch focus to previous input - e.preventDefault() - refInputs.current[i - 1]?.focus() - } - if (e.key === " " || e.key === "Enter") { - // switch focus to next input - e.preventDefault() - if (word !== "") { - refInputs.current[i + 1]?.focus() // if next input exists, focus it - } - } - }} - onChange={(e) => { - setSeedInput((prev) => [ - ...prev.slice(0, i), - e.target.value, - ...prev.slice(i + 1), - ]) - }} - /> - - ))} - - ) -} diff --git a/packages/ui/src/components/Select.tsx b/packages/ui/src/components/Select.tsx deleted file mode 100644 index 20a957a92..000000000 --- a/packages/ui/src/components/Select.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { - InputGroup, - InputRightElement, - Menu, - MenuButton, - MenuItem, - MenuList, - Text, -} from "@chakra-ui/react" -import { isString } from "lodash-es" -import { FC, ReactElement, ReactNode, useMemo } from "react" - -import { ChevronDownIcon } from "./icons" -import { Input } from "./Input" -import { H6 } from "./Typography" - -export interface SelectOption { - icon?: ReactElement - label: ReactNode - labelSelected?: string - value: string -} - -export type SelectOptions = SelectOption[] - -interface SelectProps { - emptyMessage?: string - isDisabled?: boolean - isInvalid?: boolean - label?: string - maxH?: string - name?: string - onChange: (e: string) => void - options: SelectOptions - placeholder: string - value: string -} - -const Select: FC = ({ - emptyMessage, - isDisabled, - isInvalid, - label, - maxH, - name, - onChange, - options, - placeholder, - value, -}) => { - const selectedOptionLabel = useMemo(() => { - const option = options.find((option) => option.value === value) - if (option && isString(option.label)) { - return option.label - } - }, [options, value]) - - const selectedOptionLabelSelected = useMemo(() => { - const option = options.find((option) => option.value === value) - return option?.labelSelected ?? option?.label - }, [options, value]) - - const hasLabel = Boolean(label) - - return ( - - - - - - {hasLabel &&
{selectedOptionLabelSelected ?? placeholder}
} - - - -
-
-
- - - {options.map(({ icon, label, value: optionValue }) => ( - onChange(optionValue)} - bgColor={optionValue === value ? "neutrals.600" : undefined} - data-group - > - {label} - - ))} - {emptyMessage && options?.length < 1 && ( - {emptyMessage} - )} - -
- ) -} - -export { Select } diff --git a/packages/ui/src/components/SplitProgress.tsx b/packages/ui/src/components/SplitProgress.tsx deleted file mode 100644 index 2e8e52b52..000000000 --- a/packages/ui/src/components/SplitProgress.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Box } from "@chakra-ui/react" - -export const SplitProgress = ({ - value, - max, -}: { - value: number - max: number -}) => { - const blockCount = Math.ceil(max) - const filledBlockCount = Math.ceil((value / max) * blockCount) - - const blocks = Array.from({ length: blockCount }).map((_, index) => ( - - )) - - return ( - - {blocks} - - ) -} diff --git a/packages/ui/src/components/StickyGroup.tsx b/packages/ui/src/components/StickyGroup.tsx deleted file mode 100644 index 200ed32d8..000000000 --- a/packages/ui/src/components/StickyGroup.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Box, chakra } from "@chakra-ui/react" - -export const StickyGroup = chakra(Box, { - baseStyle: { - position: "absolute", - display: "flex", - flexDirection: "column", - gap: 3, - bottom: 0, - left: 0, - right: 0, - background: - "linear-gradient(180deg, rgba(16, 16, 20, 0) 0%, #101014 66.54%)", - }, -}) diff --git a/packages/ui/src/components/Switch.tsx b/packages/ui/src/components/Switch.tsx deleted file mode 100644 index 3cda85a71..000000000 --- a/packages/ui/src/components/Switch.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { switchAnatomy as parts } from "@chakra-ui/anatomy" -import { Switch } from "@chakra-ui/react" -import { createMultiStyleConfigHelpers } from "@chakra-ui/styled-system" - -export { Switch } - -const { definePartsStyle, defineMultiStyleConfig } = - createMultiStyleConfigHelpers(parts.keys) - -const baseStyle = definePartsStyle({ - track: { - bg: "neutrals.600", - _checked: { - bg: "primary.500", - }, - }, -}) - -export const switchTheme = defineMultiStyleConfig({ - baseStyle, -}) diff --git a/packages/ui/src/components/TabBar.tsx b/packages/ui/src/components/TabBar.tsx deleted file mode 100644 index 93b459fd1..000000000 --- a/packages/ui/src/components/TabBar.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { - Center, - Circle, - ComponentWithAs, - Flex, - PropsOf, - chakra, -} from "@chakra-ui/react" -import { ReactNode } from "react" -import { NavLink } from "react-router-dom" - -export const TabBarHeight = 16 - -export const TabBar = chakra(Flex, { - baseStyle: { - top: "initial", - bottom: 0, - height: TabBarHeight, - color: "neutrals.600", - backgroundColor: "bg", - borderTop: "1px solid", - borderTopColor: "border", - boxShadow: "menu", - }, -}) - -export const TabContainer = chakra(Center, { - baseStyle: { - position: "relative", - display: "flex", - flex: "1", - alignItems: "center", - justifyContent: "center", - color: "neutrals.400", - "&.active": { - pointerEvents: "none", - }, - }, -}) - -export const TabIconContainer = chakra(Circle, { - baseStyle: { - fontSize: "2xl", - transitionProperty: "common", - transitionDuration: "fast", - ".active &": { - color: "white", - backgroundColor: "neutrals.600", - }, - _groupHover: { - color: "neutrals.100", - backgroundColor: "neutrals.700", - ".active &": { - backgroundColor: "red", - }, - }, - }, -}) - -export const TabBadge = chakra(Circle, { - baseStyle: { - position: "absolute", - left: "50%", - top: "50%", - backgroundColor: "skyBlue.500", - transform: - "translate(calc(var(--chakra-sizes-5)*-1),calc(var(--chakra-sizes-5)*-1))", - }, -}) - -export interface TabCustomProps { - icon: ReactNode - label?: string - badgeLabel?: string | number - badgeDescription?: string -} - -type TabComponent = ComponentWithAs<"div", TabCustomProps> -export type TabProps = PropsOf - -export const Tab: TabComponent = ({ - icon, - label, - badgeLabel, - badgeDescription, - as = NavLink, - ...rest -}) => { - const showBadgeLabel = Number(badgeLabel) > 0 - return ( - - {showBadgeLabel && } - {icon} - - ) -} diff --git a/packages/ui/src/components/Tabs.tsx b/packages/ui/src/components/Tabs.tsx deleted file mode 100644 index e2453fee1..000000000 --- a/packages/ui/src/components/Tabs.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { tabsAnatomy } from "@chakra-ui/anatomy" -import { createMultiStyleConfigHelpers } from "@chakra-ui/react" - -import { typographyStyles } from "." - -const { definePartsStyle, defineMultiStyleConfig } = - createMultiStyleConfigHelpers(tabsAnatomy.keys) - -const sizes = { - sm: definePartsStyle({ - tab: { - ...typographyStyles.L1, - py: "2", - px: "3", - }, - tabpanel: { - p: 0, - }, - }), -} - -const pill = definePartsStyle(() => { - return { - tab: { - color: "neutrals.300", - rounded: "full", - bg: "neutrals.800", - border: "1px solid", - borderColor: "transparent", - _hover: { - color: "neutrals.200", - bg: "neutrals.700", - }, - _selected: { - bg: "transparent", - borderColor: "white", - color: "white", - }, - }, - tablist: { - gap: 1, - }, - tabpanel: {}, - } -}) - -const variants = { - pill, -} - -export const tabsTheme = defineMultiStyleConfig({ - variants, - sizes, - defaultProps: { - size: "sm", - variant: "pill", - }, -}) diff --git a/packages/ui/src/components/TextWithAmount/index.test.tsx b/packages/ui/src/components/TextWithAmount/index.test.tsx deleted file mode 100644 index e4c78a663..000000000 --- a/packages/ui/src/components/TextWithAmount/index.test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { render } from "@testing-library/react" - -import TextWithAmount from "." - -describe("TextWithAmount", () => { - it("renders the child component with data-value attribute equal to the amount prop as a number", () => { - const amount = 42 - const { getByText } = render( - -

This is some text with an amount

-
, - ) - const childComponent = getByText("This is some text with an amount") - - expect(childComponent).toHaveAttribute("data-value", String(amount)) - }) - - it("renders the child component with data-value attribute equal to the amount prop as a string", () => { - const amount = "10000" - const { getByText } = render( - -

This is some text with an amount

-
, - ) - const childComponent = getByText("This is some text with an amount") - - expect(childComponent).toHaveAttribute("data-value", amount) - }) - - it("renders the child component with data-value attribute equal to the amount prop as a really large number", () => { - const amount = 1234567890 - const { getByText } = render( - -

This is some text with an amount

-
, - ) - const childComponent = getByText("This is some text with an amount") - - expect(childComponent).toHaveAttribute("data-value", String(amount)) - }) - - it("renders the child component with data-value attribute equal to the amount prop as a big number", () => { - const amount = 0xcdb221963ae56 - const { getByText } = render( - -

This is some text with an amount

-
, - ) - const childComponent = getByText("This is some text with an amount") - - expect(childComponent).toHaveAttribute( - "data-value", - String(0.003618639221861974), - ) - }) -}) diff --git a/packages/ui/src/components/TextWithAmount/index.tsx b/packages/ui/src/components/TextWithAmount/index.tsx deleted file mode 100644 index 3e9a6b6b2..000000000 --- a/packages/ui/src/components/TextWithAmount/index.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { bigDecimal } from "@argent/shared" -import { Children, ReactElement, cloneElement } from "react" -import { BigNumberish } from "starknet" - -export const TextWithAmount = ({ - amount, - decimals = 0, - children, -}: { - amount: BigNumberish - children: ReactElement - decimals?: number -}) => { - let dataValue - const element = Children.only(children) - - try { - const convertedAmount = BigInt(amount) - dataValue = bigDecimal.formatUnits({ value: convertedAmount, decimals }) - } catch (e) { - // ignore parsing error - } - - if (dataValue === undefined) { - return <>{children} - } - - return cloneElement(element, { - "data-value": dataValue, - }) -} - -export default TextWithAmount diff --git a/packages/ui/src/components/Textarea.tsx b/packages/ui/src/components/Textarea.tsx deleted file mode 100644 index 53780263a..000000000 --- a/packages/ui/src/components/Textarea.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Textarea, defineStyleConfig } from "@chakra-ui/react" -import { defineStyle } from "@chakra-ui/styled-system" -import { mode } from "@chakra-ui/theme-tools" - -export { Textarea } - -const baseStyle = defineStyle({ - transitionProperty: "common", - transitionDuration: "normal", -}) - -const variantOutline = defineStyle((props) => ({ - bg: mode("white", "black")(props), - border: "1px solid", - borderColor: "border", - _placeholder: { - color: mode("gray.200", "neutrals.500")(props), - }, - _hover: { - borderColor: mode("gray.100", "neutrals.600")(props), - }, - _invalid: { - borderColor: "error.500", - boxShadow: mode("inherit", "none")(props), - _hover: { - borderColor: mode("error.400", "error.600")(props), - }, - _focusVisible: { - borderColor: "error.500", - boxShadow: mode("outlineError", "none")(props), - }, - }, - _focusVisible: { - borderColor: mode("accent.500", "neutrals.400")(props), - boxShadow: mode("outlineAccent", "none")(props), - }, -})) - -const variantFilled = defineStyle((props) => ({ - bg: mode("gray.50", "neutrals.800")(props), - border: "none", - _placeholder: { - color: mode("gray.300", "neutrals.400")(props), - }, - _hover: { - bg: mode("gray.100", "neutrals.700")(props), - }, - _invalid: { - boxShadow: "error", - _focusVisible: { - boxShadow: mode("outlineError", "error")(props), - }, - }, - _focusVisible: { - bg: mode("white", "neutrals.700")(props), - boxShadow: mode("outlineAccent", "none")(props), - }, -})) - -const variants = { - outline: variantOutline, - filled: variantFilled, -} - -const sizes = { - md: { - px: "5", - py: "4.5", - fontSize: "base", - fontWeight: "semibold", - borderRadius: "lg", - minHeight: "14", - h: "initial", - }, - sm: defineStyle({ - px: "3", - py: "3.5", - fontSize: "base", - fontWeight: "semibold", - borderRadius: "lg", - minHeight: "12", - h: "10" /** also defines the width of InputLeftElement and InputRightElement... */, - }), -} - -export const textareaTheme = defineStyleConfig({ - baseStyle, - sizes, - variants, - defaultProps: { - size: "md", - variant: "outline", - }, -}) diff --git a/packages/ui/src/components/TextareaAutosize.tsx b/packages/ui/src/components/TextareaAutosize.tsx deleted file mode 100644 index 319f37eb5..000000000 --- a/packages/ui/src/components/TextareaAutosize.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Textarea, TextareaProps, useMergeRefs } from "@chakra-ui/react" -import { forwardRef, useEffect, useRef } from "react" - -const TextareaAutosize = forwardRef( - ({ value, ...rest }, ref) => { - const internalRef = useRef(null) - const refs = useMergeRefs(internalRef, ref) - - useEffect(() => { - if (internalRef.current) { - internalRef.current.style.height = "0" - const scrollHeight = internalRef.current.scrollHeight - internalRef.current.style.height = `${scrollHeight}px` - } - // hook updates height when value changes, but doesn't use its actual value - /* eslint-disable react-hooks/exhaustive-deps */ - }, [value]) - - return ( -